Adds a key-authenticated REST API at /api/v1 so another system can create
and manage quotes without going through the UI.
Endpoints cover quotes (list, create, read, update, delete, recalculate),
shots, assets and line items, plus read-only clients and rate cards.
POST /api/v1/quotes builds a whole priced quote -- client, shots, assets
and tasks -- in a single transaction. Routes are also mounted under
/api/v1/jobs, since a quote and a job are the same record here.
Keys are stored as SHA-256 with a display prefix, so the plaintext is
shown once at creation and is not recoverable. They carry read/write
scopes, can be revoked (effective on the next request), and record when
they were last used. Minting and revoking live in Settings and are
restricted to signed-in admins.
/api/v1 is exempt from the session proxy because it authenticates with a
bearer key rather than a cookie -- without this, every API call was
redirected to /login as a 307. It is not unprotected: each route handler
requires a live, unrevoked key with the right scope.
Shot numbering and shot-code construction move into lib/shot-codes.ts so
the UI and the API cannot drift. This also fixes numbering restarting at
0010 when a scene was entered in a different case to the stored one: the
lookup upper-cased the scene but the stored value was left as typed.
Unspecified currency and markup/tax/discount on an API-created quote fall
back to the studio's configured quote defaults.
Decimal fields are serialised as strings to preserve the exact precision
the app's decimal arithmetic maintains.
Note: this needs `prisma migrate deploy` for the new api_keys table.
Settings will error for admins until that runs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds a GET /api/csv/shots/[jobId] endpoint with two modes:
?detail=shots (default) - one row per shot, with rolled-up task
count, hours, days, subtotal and total.
?detail=tasks - one row per line item, adding artist role, rate
card, rates and the markup/discount/tax/total split.
Totals run through the existing calcLineItem/sumLineItems helpers so
they match the editor and the PDF. Amounts are emitted as plain 2dp
numbers with the currency named in the header, so spreadsheets can sum
them. Rows follow the editor's display order (grouped by episode or
shot group, Ungrouped last, then alphabetical by shot code) and the
group column header adapts to the job type.
Shotlist column headers deliberately match the CSV importer's aliases
so an export can be edited and re-imported. Free text is flattened to a
single line to keep one shot per row: the importer's parser splits on
newlines before handling quotes, so multi-line quoted fields would
otherwise corrupt a re-import.
Exposed as an "Export CSV" dropdown in the shots editor.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The CLI create-user scripts hit environment issues on the VPS (missing
ts-node, missing node_modules on the host). A /signup page sidesteps
that entirely since it runs inside the already-working Next.js server.
It's a one-time-use setup form: the server action refuses to run once
any user already exists, so it's safe to leave in place, though it can
be deleted after the first account is created.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>