| 66 | } |
| 67 | |
| 68 | func (s *Store) CreateWorkspace(input models.WorkspaceCreate) (*models.Workspace, error) { |
| 69 | id := newID() |
| 70 | ts := now() |
| 71 | |
| 72 | slug := input.Slug |
| 73 | if slug == "" { |
| 74 | slug = slugify(input.Name) |
| 75 | } |
| 76 | |
| 77 | // Workspace slugs are globally unique (not scoped to a workspace |
| 78 | // like collection/item slugs), so we use a workspace-specific |
| 79 | // uniqueness check rather than the generic uniqueSlug helper. |
| 80 | finalSlug, err := s.uniqueWorkspaceSlug(slug) |
| 81 | if err != nil { |
| 82 | return nil, err |
| 83 | } |
| 84 | |
| 85 | settings := input.Settings |
| 86 | if settings == "" { |
| 87 | settings = "{}" |
| 88 | } |
| 89 | settings, err = models.NormalizeWorkspaceSettings(settings) |
| 90 | if err != nil { |
| 91 | return nil, fmt.Errorf("normalize workspace settings: %w", err) |
| 92 | } |
| 93 | if input.Context != nil { |
| 94 | settings, err = models.ApplyWorkspaceContext(settings, input.Context) |
| 95 | if err != nil { |
| 96 | return nil, fmt.Errorf("apply workspace context: %w", err) |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | _, err = s.db.Exec(s.q(` |
| 101 | INSERT INTO workspaces (id, name, slug, owner_id, description, settings, source, created_at, updated_at) |
| 102 | VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) |
| 103 | `), id, input.Name, finalSlug, input.OwnerID, input.Description, settings, input.Source, ts, ts) |
| 104 | if err != nil { |
| 105 | return nil, fmt.Errorf("insert workspace: %w", err) |
| 106 | } |
| 107 | |
| 108 | return s.GetWorkspaceBySlug(finalSlug) |
| 109 | } |
| 110 | |
| 111 | func (s *Store) uniqueWorkspaceSlug(baseSlug string) (string, error) { |
| 112 | slug := baseSlug |