Project file lifecycle (#25) #71

Merged
crowmaki merged 2 commits from issue-25-project-file-lifecycle into main 2026-10-07 08:16:32 +00:00
Owner

Closes #25. Part of #24.

What

The tracer bullet for the app:

  • Cargo workspace at the repo root (crates/studio-core, src-tauri).
  • studio-core (no Tauri, no specta). ProjectSession creates, opens and closes .studio SQLite files:
    • fixed application_id; a non-studio file is refused
    • PRAGMA user_version migrations embedded in the core, run in one transaction after an online-backup copy to <name>.studio.bak-v<N>; a newer schema is refused and left untouched
    • WAL while open; a clean close checkpoints and switches to journal_mode=DELETE, leaving a single file at rest
    • <name>.studio.lock with PID and host, acquired atomically (temp file + hard link); stale same-host locks are taken over
    • sibling <name>.media/ folder, ULID keys, content-addressed BLAKE3 blob table with an unused-blob sweep on open
    • app-wide defaults in defaults.json (app config dir), copied into the project row and the lighting / reference_category_order tables at creation and never read again
    • aspect ratio settable and changeable from a fixed list
  • src-tauri: thin taurpc adapter with DTOs and a typed CommandError; bindings generated to src/lib/bindings.ts (cargo test -p ai-studio regenerates them). The session is closed cleanly on app exit.
  • UI: New / Open (*.studio pickers), shows the title, the aspect ratio (editable), the path, and a Close button.

Decisions to check

  • Aspect ratio list (not fixed by the spec): 16:9 (default), 1.85:1, 2.39:1, 4:3, 1:1, 9:16.
  • Default Lighting: Day, Night, Dawn/Dusk. Default slot category order: Keyframe, Atlas, Wardrobe mannequin, Location angle, Board, Prop.
  • Notation set, slug→Lighting table and Generation profile defaults are left to #43, #29 and #50, which own those tables.
  • Migration tests use a test-support feature that injects a migration list; that test file has required-features, so a plain cargo test skips it.

Known limitations

  • A lock written by another host is always refused; there is no override yet.
  • A small window remains between reading a stale lock and renaming it away.
  • No table references blobs yet, so the sweep currently deletes every blob on open (as specified). A "referenced blob survives" test comes with the first table that stores one.

Testing

  • cargo test --workspace --features studio-core/test-support: 26 passed (core: lifecycle 12, lock 4, migrations 5, blobs 2; adapter smoke 3).
  • cargo clippy --workspace --all-targets --features studio-core/test-support: clean.
  • bun run check: 0 errors, 0 warnings. bun run build succeeds.
  • Not done: the GUI has not been launched, so the native dialogs, the taurpc client at runtime and close-on-exit need a manual bun tauri dev check.
Closes #25. Part of #24. ## What The tracer bullet for the app: - **Cargo workspace** at the repo root (`crates/studio-core`, `src-tauri`). - **`studio-core`** (no Tauri, no specta). `ProjectSession` creates, opens and closes `.studio` SQLite files: - fixed `application_id`; a non-studio file is refused - `PRAGMA user_version` migrations embedded in the core, run in one transaction after an online-backup copy to `<name>.studio.bak-v<N>`; a newer schema is refused and left untouched - WAL while open; a clean close checkpoints and switches to `journal_mode=DELETE`, leaving a single file at rest - `<name>.studio.lock` with PID and host, acquired atomically (temp file + hard link); stale same-host locks are taken over - sibling `<name>.media/` folder, ULID keys, content-addressed BLAKE3 `blob` table with an unused-blob sweep on open - app-wide defaults in `defaults.json` (app config dir), copied into the `project` row and the `lighting` / `reference_category_order` tables at creation and never read again - aspect ratio settable and changeable from a fixed list - **`src-tauri`**: thin `taurpc` adapter with DTOs and a typed `CommandError`; bindings generated to `src/lib/bindings.ts` (`cargo test -p ai-studio` regenerates them). The session is closed cleanly on app exit. - **UI**: New / Open (`*.studio` pickers), shows the title, the aspect ratio (editable), the path, and a Close button. ## Decisions to check - Aspect ratio list (not fixed by the spec): 16:9 (default), 1.85:1, 2.39:1, 4:3, 1:1, 9:16. - Default Lighting: Day, Night, Dawn/Dusk. Default slot category order: Keyframe, Atlas, Wardrobe mannequin, Location angle, Board, Prop. - Notation set, slug→Lighting table and Generation profile defaults are left to #43, #29 and #50, which own those tables. - Migration tests use a `test-support` feature that injects a migration list; that test file has `required-features`, so a plain `cargo test` skips it. ## Known limitations - A lock written by another host is always refused; there is no override yet. - A small window remains between reading a stale lock and renaming it away. - No table references blobs yet, so the sweep currently deletes every blob on open (as specified). A "referenced blob survives" test comes with the first table that stores one. ## Testing - `cargo test --workspace --features studio-core/test-support`: 26 passed (core: lifecycle 12, lock 4, migrations 5, blobs 2; adapter smoke 3). - `cargo clippy --workspace --all-targets --features studio-core/test-support`: clean. - `bun run check`: 0 errors, 0 warnings. `bun run build` succeeds. - **Not done:** the GUI has not been launched, so the native dialogs, the taurpc client at runtime and close-on-exit need a manual `bun tauri dev` check.
Implements #25. Sets up a Cargo workspace with a Tauri-free studio-core
crate whose ProjectSession creates, opens and closes .studio SQLite files:
fixed application_id, user_version migrations run in one transaction after
a .bak-v<N> backup, refusal of newer schemas, WAL while open and a single
file at rest after close, an atomic PID/host lock file, a sibling .media
folder, a content-addressed BLAKE3 blob table swept on open, and app-wide
defaults copied in at creation.

src-tauri becomes a thin taurpc adapter with DTOs and a typed
CommandError; the SvelteKit page offers New/Open and shows the title and
an editable aspect ratio.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The app panicked at startup with "there is no reactor running" because
taurpc's router spawns onto Tokio when it is built. Also stop Vite from
watching the workspace target/ folder, which now sits at the repo root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign in to join this conversation.
No description provided.