178 lines
6.5 KiB
Plaintext
178 lines
6.5 KiB
Plaintext
-- 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)
|
|
OpenProjectRequested(folder_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
|
|
--
|
|
-- data_path is the project folder: the directory that CONTAINS
|
|
-- meta/project.json. It is DISCOVERED from the project.json location at
|
|
-- load time and is never written into project.json itself — so the folder
|
|
-- can be moved/renamed freely. The current location is remembered only as a
|
|
-- machine-local pointer (a project registry under private_dir), never
|
|
-- embedded in the portable project. See DataPathNotPersistedInProjectJson.
|
|
public_dir: data_path
|
|
-- All user-owned, portable, webserver-bound content lives here, under
|
|
-- the project folder:
|
|
-- posts (.md), media + thumbnails, templates/, scripts/,
|
|
-- meta/ (project.json, categories.json, category-meta.json,
|
|
-- publishing.json), tags.json, menu.opml, and generated html/ output.
|
|
-- See PublicContentLivesInProjectFolder.
|
|
private_dir: String
|
|
-- The OS per-user app-data directory. Holds app-internal,
|
|
-- machine-specific, regenerable artifacts ONLY — never inside the repo
|
|
-- or the project folder:
|
|
-- the SQLite database, the per-project embeddings index
|
|
-- (projects/{id}/embeddings.usearch + .meta.json sidecar), the
|
|
-- downloaded embedding-model cache, the project registry, and
|
|
-- window/UI state.
|
|
-- OS-specific base (resolved via :filename.basedir, app name "bds"):
|
|
-- macOS: ~/Library/Application Support/bds (:user_config)
|
|
-- Linux: $XDG_CONFIG_HOME/bds (default ~/.config/bds)
|
|
-- Windows: %APPDATA%\\bds
|
|
-- See PrivateArtifactsLiveInOsAppDir.
|
|
}
|
|
|
|
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.public_dir
|
|
project.private_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
|
|
)
|
|
@guidance
|
|
-- data_path is the chosen project folder. CreateProject writes
|
|
-- meta/project.json into {data_path}/meta/ but never records data_path
|
|
-- inside it (DataPathNotPersistedInProjectJson). The default project's
|
|
-- folder is created at a per-user default content location on first
|
|
-- launch — never inside the application repo or private_dir.
|
|
}
|
|
|
|
rule DiscoverProjectDataPath {
|
|
-- Opening or loading a project folder deduces its data_path from the
|
|
-- on-disk location of meta/project.json rather than from any stored value,
|
|
-- keeping projects movable (DataPathNotPersistedInProjectJson).
|
|
when: OpenProjectRequested(folder_path)
|
|
-- folder_path contains meta/project.json
|
|
let project = Projects where data_path = folder_path
|
|
ensures: project.data_path = folder_path
|
|
}
|
|
|
|
invariant ProjectTemplatesDirectoryReservedForUserTemplates {
|
|
-- The project templates directory stores only user-managed templates.
|
|
-- Creating a project does not populate public_dir/templates with bundled defaults.
|
|
}
|
|
|
|
invariant PublicContentLivesInProjectFolder {
|
|
-- Every file the user owns or that must be served by the webserver lives
|
|
-- under public_dir (= the project folder containing meta/project.json):
|
|
-- posts, media + thumbnails, templates, scripts, the meta/ JSON files,
|
|
-- tags.json, menu.opml, and the generated html/ output. None of this
|
|
-- content is ever written to private_dir or into the application repo.
|
|
}
|
|
|
|
invariant PrivateArtifactsLiveInOsAppDir {
|
|
-- App-internal, machine-specific, regenerable artifacts — the SQLite
|
|
-- database, the per-project embeddings index and its sidecar, the
|
|
-- model cache, the project registry, and window/UI state — live ONLY
|
|
-- under private_dir (the OS per-user app-data directory). They are never
|
|
-- written into a project folder (public_dir) or into the application repo.
|
|
-- A regenerable artifact (e.g. the embeddings index) may be rebuilt from
|
|
-- the database when absent.
|
|
}
|
|
|
|
invariant DataPathNotPersistedInProjectJson {
|
|
-- meta/project.json never stores its own path or data_path. A project's
|
|
-- location is determined solely by where its meta/project.json file sits,
|
|
-- so the folder can be moved or renamed without editing any file. The app
|
|
-- remembers the current location as a machine-local pointer in private_dir.
|
|
}
|
|
|
|
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"
|
|
}
|