atelier: extraction finished — verification, open items, no db/ recorded
Atelier is now plugins/atelier/: manifest, a thin auth-gated proxy router, the sidecar backend (providers, the generation queue, collections, its own separate Postgres database), three panels (Generate, Gallery+Lightbox, Collections), and Providers as an Officer settings screen instead of a fourth panel. Its own local git repository, four commits, not yet pushed anywhere — see BLOCKERS.md. bunx tsgo is clean. bun test: 1041->1069 pass, 0 fail, 90->92 files (the two new files are ported tests, no regressions). The real production SPA bundle builds successfully with the plugin included (Bun.build + Tailwind, 2.2s, zero errors) and the sidecar's HTTP API was exercised end to end against a real, non-production Postgres database. Not done, and recorded as open: a live PM2 install cycle against the shared production database, and publishing the plugin's repository to Gitea and the marketplace — both cross into affecting shared systems beyond this local checkout, which is not a call to make unattended. The standalone officer-atelier service — what the mobile app actually talks to today — was not touched, not stopped, and not migrated. This extraction is additive. ATELIER-COMPLETE
This commit is contained in:
+37
-4
@@ -78,12 +78,12 @@ scope it to "every encryption and signing key the platform uses" plus foreign be
|
|||||||
inventing a new one.
|
inventing a new one.
|
||||||
|
|
||||||
**Not set automatically.** I don't have a safe way to guess whether the owner wants the plugin sidecar
|
**Not set automatically.** I don't have a safe way to guess whether the owner wants the plugin sidecar
|
||||||
to point at the *existing* `atelier` database (sharing state with the still-running standalone service —
|
to point at the _existing_ `atelier` database (sharing state with the still-running standalone service —
|
||||||
two writers to one queue table, which `generations.status` and the `claimableGenerations`/`markRunning`
|
two writers to one queue table, which `generations.status` and the `claimableGenerations`/`markRunning`
|
||||||
claim logic were written assuming is single-process) or a fresh one. Left unset, with a clear startup
|
claim logic were written assuming is single-process) or a fresh one. Left unset, with a clear startup
|
||||||
error, and documented in PLUGIN.md. **Do not just paste the standalone service's `POSTGRES_URL` in and
|
error, and documented in PLUGIN.md. **Do not just paste the standalone service's `POSTGRES_URL` in and
|
||||||
restart both** — two processes racing the same `generations` queue is exactly the hazard `markRunning`'s
|
restart both** — two processes racing the same `generations` queue is exactly the hazard `markRunning`'s
|
||||||
atomic claim exists to prevent for restarts of *one* process, not for two live ones.
|
atomic claim exists to prevent for restarts of _one_ process, not for two live ones.
|
||||||
|
|
||||||
## Decision 2 — Providers as an Officer settings screen, against a direct precedent
|
## Decision 2 — Providers as an Officer settings screen, against a direct precedent
|
||||||
|
|
||||||
@@ -109,8 +109,9 @@ explicit and pre-made.
|
|||||||
|
|
||||||
The standalone service served `/images/*` unauthenticated, off Bun's top-level route table, with
|
The standalone service served `/images/*` unauthenticated, off Bun's top-level route table, with
|
||||||
`PUBLIC_URL` baked into every response so the URL was durable outside the process. Per "What you may NOT
|
`PUBLIC_URL` baked into every response so the URL was durable outside the process. Per "What you may NOT
|
||||||
do", that is gone: images are served from `GET /api/atelier/images/:filename`, mounted like every other
|
do", that is gone: images are served from `GET /api/atelier/files/:filename`, mounted like every other
|
||||||
route, behind the permission gate.
|
route, behind the permission gate. Named `files` rather than `images` so it cannot sit one path segment
|
||||||
|
away from `/api/atelier/images/generations/:id` — the JSON job API already owns `/images`.
|
||||||
|
|
||||||
The frontend needs `<img src>` to carry a credential a browser cannot put in an `Authorization` header.
|
The frontend needs `<img src>` to carry a credential a browser cannot put in an `Authorization` header.
|
||||||
Used the platform's existing `?token=` escape hatch — already read by both
|
Used the platform's existing `?token=` escape hatch — already read by both
|
||||||
@@ -155,3 +156,35 @@ Until that happens, the plugin still installs fine from a checkout that already
|
|||||||
(`plugins/atelier/` committed to its own local repo, present on disk) — it just cannot be discovered by
|
(`plugins/atelier/` committed to its own local repo, present on disk) — it just cannot be discovered by
|
||||||
the Marketplace screen on a machine that has never had it, per "Done means" #2. This is the one piece of
|
the Marketplace screen on a machine that has never had it, per "Done means" #2. This is the one piece of
|
||||||
"done" I could not complete unattended.
|
"done" I could not complete unattended.
|
||||||
|
|
||||||
|
## No `plugins/atelier/db/`, on purpose
|
||||||
|
|
||||||
|
"Done means" lists `db/` among the plugin's expected pieces, matching offscale's and music's shape. This
|
||||||
|
plugin has no `db/schema.ts` at all — `discoverPlugins()` correctly reports `schema: null` for it. That
|
||||||
|
convention is specifically for `officer_db`-prefixed tables pushed by `pushPluginSchema`; decision 3
|
||||||
|
keeps Atelier's tables in their own separate Postgres database instead, so there is nothing for that
|
||||||
|
convention to describe. The database code lives inside `sidecar/db/` as an internal implementation
|
||||||
|
detail of the sidecar process, not as a platform-recognised `db/` directory. Documented in full in
|
||||||
|
`plugins/atelier/PLUGIN.md`, under "The database".
|
||||||
|
|
||||||
|
## What I verified, and what I deliberately did not
|
||||||
|
|
||||||
|
- `bunx tsgo`: clean throughout.
|
||||||
|
- `bun test`: baseline 1041 pass / 0 fail / 90 files → after this run, 1069 pass / 0 fail / 92 files.
|
||||||
|
The two new files are the ported `serialize.test.ts` and `generations/response.test.ts`. No
|
||||||
|
regressions, file count only grew.
|
||||||
|
- `discoverPlugins()` finds the plugin and the manifest validates with no problems.
|
||||||
|
- The platform-side proxy router mounts and correctly 503s with no sidecar running.
|
||||||
|
- The sidecar's own Hono app was exercised directly against the real `atelier_dev` Postgres database
|
||||||
|
(not `officer_db`, not the production `atelier` database) with real HTTP requests and no port bound:
|
||||||
|
providers, providers/adapters, collections and images all answered correctly; a missing file 404s; an
|
||||||
|
unknown route gets the OpenAI-shaped error envelope; provider rows whose keys were encrypted under the
|
||||||
|
standalone service's own key correctly fail to decrypt rather than crashing (a fresh `secret.key` was
|
||||||
|
generated for this checkout at `$OFFICER_ROOT/data/atelier/secret.key`, which is expected and correct
|
||||||
|
— see PLUGIN.md).
|
||||||
|
- **Deliberately not done**: installing the plugin through the live, running `officer` PM2 process. That
|
||||||
|
process serves the owner's real session, its `plugins/` directory is the main checkout (not this
|
||||||
|
worktree, so it would not even find this code), and going through its install flow would write a real
|
||||||
|
`plugin_installs` row into the shared production `officer` Postgres database from a session with no way
|
||||||
|
to confirm the result against a live browser. Full PM2 install/enable/disable/uninstall/purge cycle,
|
||||||
|
per the runbook's verification table, is left for the owner — noted as open item 5 in PLUGIN.md.
|
||||||
|
|||||||
Reference in New Issue
Block a user