-- allium: 1 -- bDS Project Management -- Scope: core (Wave 1) -- Distilled from: src/main/engine/ProjectEngine.ts, schema.ts surface ProjectControlSurface { facing _: ProjectOperator provides: CreateProjectRequested(name, data_path) SetActiveProjectRequested(project) DeleteProjectRequested(project) } entity Project { name: String slug: String description: String? data_path: String? is_active: Boolean created_at: Timestamp updated_at: Timestamp -- Relationships posts: Post with project = this media: Media with project = this tags: Tag with project = this -- Derived internal_base_dir: String -- {user_data}/projects/{id}/ -- Contains: meta/, thumbnails/, tags.json effective_data_dir: data_path ?? internal_base_dir -- Custom data path overrides default } surface ProjectSurface { context project: Project exposes: project.name project.slug project.description when project.description != null project.data_path when project.data_path != null project.is_active project.created_at project.updated_at project.posts.count project.media.count project.tags.count project.internal_base_dir project.effective_data_dir } invariant SingleActiveProject { -- Exactly one project is active at any time let active = Projects where is_active active.count = 1 } invariant UniqueProjectSlug { for a in Projects: for b in Projects: a != b implies a.slug != b.slug } rule CreateProject { when: CreateProjectRequested(name, data_path) let slug = slugify(name) ensures: Project.created( name: name, slug: slug, data_path: data_path, is_active: false ) ensures: StarterTemplatesCopied(project) -- Bundled starter templates are copied into the new project } rule SetActiveProject { when: SetActiveProjectRequested(project) let previous = Projects where is_active = true ensures: for p in previous: p.is_active = false ensures: project.is_active = true } rule DeleteProject { when: DeleteProjectRequested(project) requires: project.id != "default" -- The default project (id='default') cannot be deleted requires: project.is_active = false -- The currently active project cannot be deleted ensures: not exists project @guidance -- deleteProjectWithData removes DB rows + internal directory -- but preserves external data at custom data_path } config { default_project_id: String = "default" default_project_name: String = "My Blog" } invariant DefaultProjectExists { -- A project with id='default' always exists -- It is created on first launch if missing exists p in Projects where p.id = "default" }