the extraction kept atelier's own postgres database, because the brief said to when the tables already had rows. the owner reversed it, and the reason is not tidiness: a plugin that behaves differently from every other plugin is a plugin nobody can reason about. the separate database meant a second connection string to set before install, a second thing to back up, a second thing to get wrong on a new machine, and failure modes no other plugin shares — none of it bought anything except avoiding a migration. four tables now: atelier_collections, atelier_collection_items, atelier_providers, atelier_generations. index and check constraint names carry the prefix too — those are global in postgres and are the one thing that would otherwise collide with another plugin. db/schema.ts re-exports the definitions rather than duplicating them: they stay beside the code that queries them in sidecar/db/, and that file exists to be found by gen-plugin-schemas. ATELIER_POSTGRES_URL is gone. db.ts reads OFFICERDEV_POSTGRES_URL ?? POSTGRES_URL, which the platform already sets. the standalone service's rows are NOT here and nothing depends on them being here — the old service is still running against the old database, untouched, and migrating is a separate watched step after this is proven on alpha.
74 lines
4.4 KiB
Markdown
74 lines
4.4 KiB
Markdown
# Atelier
|
|
|
|
Image generation for an Officer server: a provider-shaped API over OpenAI's image endpoints, storing
|
|
what it makes so every image has a durable reference — a gallery you can browse, collections you can
|
|
organise, and a job an agent can poll rather than block on.
|
|
|
|
Atelier was a standalone service before this plugin existed
|
|
(`~/officer-dev/dockers/officer-atelier`, still running as `officer-atelier`, still what the mobile app
|
|
talks to). This plugin is a fresh extraction into Officer, not a replacement for it yet — see
|
|
`PLUGIN.md` before assuming the two are interchangeable.
|
|
|
|
## What you get
|
|
|
|
- **Generate** — a prompt, a model, size/quality/background, and a job you watch settle. `n` images
|
|
become `n` independently-tracked rows, so one failure out of four does not discard the three that
|
|
worked.
|
|
- **Gallery** — everything generated, newest first, with a lightbox: pan, zoom about the cursor,
|
|
checkerboard/dark/light backdrops for telling a transparent background from an opaque one that only
|
|
looks it.
|
|
- **Collections** — named sets of images. A generation request can name one by name and it is created on
|
|
first use; the gallery and the lightbox can file an image into one after the fact.
|
|
- **A provider-shaped backend.** "OpenAI" is code, written once; a *provider* is a row — which model,
|
|
whose key, on or off — and several can share one adapter. Today OpenAI is the only adapter; the point
|
|
of the shape is that a second one is a new file, not a redesign.
|
|
- **An OpenAI-compatible job API**, for agents. `POST /api/atelier/images/generations` accepts OpenAI's
|
|
request body verbatim and answers `202` with a job id rather than blocking for the length of the
|
|
generation — the caller polls `GET /api/atelier/images/generations/:id`, optionally with `?wait=` to
|
|
long-poll instead of retrying in a loop.
|
|
|
|
## Requirements
|
|
|
|
- An Officer server, version 1.0.0 or later.
|
|
- A **separate Postgres database**, and its own environment variable: `OFFICERDEV_POSTGRES_URL`. Atelier's
|
|
tables (`generations`, `collections`, `collection_items`, `providers`) do not live in `officer_db` —
|
|
see `PLUGIN.md` for why, and set this before installing. There is no default.
|
|
- An OpenAI API key, set with `bun run secret:set atelier-openai-key`, or configured per-provider in
|
|
Settings → Integrations → Atelier, or (for an install that predates the secret store) as
|
|
`OPENAI_API_KEY` in `.env`.
|
|
|
|
## Install
|
|
|
|
From the Officer marketplace: find Atelier, install. That mounts `/api/atelier` and `/atelier`, starts
|
|
the `officer-atelier` sidecar under PM2, and connects it to whatever `OFFICERDEV_POSTGRES_URL` points at —
|
|
which has to already have the schema (the standalone repo's own `bun db:push` creates it; this plugin
|
|
does not run migrations against a database it does not own the schema of).
|
|
|
|
Uninstalling stops the sidecar and unmounts the route. **It never touches your database** — Atelier's
|
|
tables and rows are not this plugin's to drop, since it does not own the schema push for them either.
|
|
|
|
## Permissions
|
|
|
|
One permission, `atelier`, grantable per role at read or write.
|
|
|
|
- **Read** lets an account use Generate, browse the Gallery and Collections, and see which providers are
|
|
configured (never a key, in any form — not even masked).
|
|
- **Write** additionally lets an account add, edit or delete providers, including their API keys. A
|
|
provider's key authorises real spend on someone's OpenAI account, so treat write here the way you
|
|
would treat write on any billing-adjacent surface.
|
|
|
|
Providers is not a panel — it is a platform Settings screen (Settings → Integrations → Atelier), because
|
|
it is owner-level configuration rather than a working view. See `PLUGIN.md` for why.
|
|
|
|
## Limitations, honestly
|
|
|
|
- **Two Ateliers can exist at once.** This plugin and the standalone service are independent — installing
|
|
this one does not migrate the standalone one's data, stop it, or repoint the mobile app. See
|
|
`PLUGIN.md`.
|
|
- **No per-user data.** Every account with `read` sees the same gallery and the same collections — there
|
|
is no ownership model yet, the same simple shape offscale shipped with first.
|
|
- **The database is separate from `officer_db`**, which means Atelier's tables are not covered by
|
|
`bun db:push`, are not part of the platform's usual backup story unless you back up the second
|
|
database too, and need their own connection string. Migrating them in is real, tracked follow-up work
|
|
— see `PLUGIN.md`.
|