π Current HTTP API and NiceGUI contract
The StoryMatrix service exposes a durable owner-scoped job boundary and a bounded NiceGUI console. This page describes the implemented contract as verified on 2026-08-03. Celery task IDs and filesystem paths are internal and are never public API.
π Exact public endpoints
| Method and path | Request / authorization | Response and behavior |
|---|---|---|
POST /stories | Bounded story-generation request; authenticated owner required when API-key mode is enabled | 202 Accepted; creates a durable owner-scoped generation job and returns public opaque story/job identifiers. |
GET /jobs | Authenticated owner | Lists that ownerβs durable jobs and public lifecycle fields. |
GET /jobs/{job_id} | Authenticated owner owning job_id | Returns the owned jobβs public state, timestamps, safe summary/error fields, and artifact references when available. |
POST /jobs/{job_id}/cancel | Authenticated owner owning active job_id | Requests cancellation and returns the updated durable job; queued jobs become terminally cancelled even if broker revocation fails. |
GET /jobs/{job_id}/artifacts/{artifact_id} | Authenticated owner authorized for the job/artifact | Downloads/serves the owned generated artifact through an authorized resource URL. |
HEAD /jobs/{job_id}/artifacts/{artifact_id} | Same artifact authorization as GET | Returns authorized artifact metadata headers without a response body. |
GET /health | Subject to the APIβs application-wide authorization/rate-limit dependency | Returns a generic liveness body without infrastructure details. |
GET /metrics | Protected endpoint | Prometheus metrics response. |
The old GET /stories/{job_id}/status Celery AsyncResult route does not exist in the current contract.
π¨ Public fields and hidden internals
Public story/job responses contain stable opaque identifiers, lifecycle state, timestamps, safe summaries/errors, and authorized artifact references/metadata as applicable. Artifact responses expose approved content type/extension and safe metadata, not storage locations.
The request model includes required prompt plus optional title, genre, style, language (default en), structure_type, background_music, and include_montage. POST /stories returns {"job": JobResponse}. JobResponse exposes id, story_id, status, result_summary, nullable error, created_at, updated_at, and artifacts. ArtifactResponse exposes id, filename, media_type, nullable size_bytes, and download_url; JobListResponse wraps jobs, and cancellation wraps the updated job in CancelResponse.
The API does not expose Celery task IDs, worker/backend identifiers, absolute or relative server paths, storage roots, or other orchestration internals. A public job_id is a durable resource identifier, not a Celery task ID.
include_montage defaults to true and is honoured by the worker: setting it to false skips final audio assembly, so the job still succeeds but produces no final mix and reports duration_seconds and file_size_bytes as null.
result_summary on a succeeded job carries title, story_summary, scenes_count, segments_count, tts_count, music_count, sfx_count, characters_count, image_count, duration_seconds, file_size_bytes, and generation_seconds. Values are scalar-only and pass a key allowlist, so no path, provider, task ID, or secret can appear. A metric that could not be measured is null rather than absent.
π Authentication and ownership
In API-key mode, a valid configured key maps to a deterministic opaque owner; invalid or missing keys are rejected. In auth-disabled local mode, the owner is local-api. Job listing, job reads, cancellation, and artifact access are owner-scoped. API-key ownership is not a multi-tenant product identity model; production identity and tenant administration remain deferred.
π¦ Quotas and rate limiting
Durable active-job and hourly-job quotas are admitted atomically per owner. A process rate limit also exists for request admission. Quota/rate-limit rejection is represented as a safe client error without leaking worker or filesystem details.
π Durable asynchronous generation
POST /stories persists a GenerationJob resource and dispatches internal worker execution. Job state is persisted in SQLite and is read through /jobs and /jobs/{job_id}. Cancellation is an explicit job command, not manipulation of a Celery result object. Celery remains an implementation mechanism behind the HTTP boundary.
The related GeneratedArtifact resources are also durable in SQLite. Their identifiers are opaque and deterministic, and their public references remain owner-authorized. The API contract does not promise production orchestration, multi-tenant identity, or a particular worker deployment.
π‘οΈ Artifact safety
Only approved artifact extensions and content types are accepted. Collection is confined to a job-specific subdirectory. The implementation checks true path containment and rejects symlinks, preventing path escape. Responses hide relative paths and never serialize arbitrary filesystem locations. Downloads require ownership authorization for the artifact.
π₯οΈ NiceGUI behavior
NiceGUI is a server-driven bounded console at /web (with / as the entry/link page). Runtime is 2.23.3, constrained by the project to >=2.23.3,<3. Signed app.storage.user stores a stable opaque owner, form state, display preferences, per-job settings snapshots, and the active job, backed by a configured or securely persisted signing secret. The UI submits through the durable application service shared with FastAPI; it does not directly invoke GenerateStoryUseCase.
The console offers a catalog-driven form covering every generation option the worker actually consumes, polls durable job state, recovers the active job after refresh, filters and paginates recent jobs, confirms cancellation before requesting it, renders a metric report plus grouped artifacts, and offers authorized downloads. Verified browser evidence on 2026-08-03 covered submit-to-success with a fully populated metric report, montage-disabled success rendering β for runtime and file size, queued cancellation, authorized download and inline streaming, a 390px no-overflow single column, a three-zone desktop layout, Ctrl+K command palette open/close, / typing safely inside the prompt, and density persistence across reload. There is no fake progress, raw Markdown/HTML rendering, SPA, WebSocket, or direct production orchestration.
The console also serves GET /web/media/{job_id}/{artifact_id} for inline audio and image preview. It is not part of the public API contract: it is owner-scoped through the signed NiceGUI session, resolves the artifact through the same get_artifact authorization used by the API, applies containment and symlink checks, supports HTTP range requests for audio seeking, and returns a bare 404 for every failure β including any request without a valid session owner.
Polling is the only progress transport. SSE is explicitly deferred.
π Service defaults and entry points
API and web hosts default to loopback (127.0.0.1). The API defaults to port 8000; the web console defaults to port 8080. Deployment exposure and production hardening are environment-specific and are not claimed here.
uv run storymatrix-apiuv run storymatrix-webβ οΈ Remaining limitations
The bounded local/service contract and browser-verified console journey are complete for the stated scope. Remaining limitations are explicit:
- production deployment, scaling, and operational worker topology are not claimed;
- multi-tenant product identity, tenant administration, and production authorization policy are deferred;
- SSE remains deferred; polling is the current and only progress transport;
- a richer SPA/editor remains deferred until a named product requirement or measured trigger; and
- deployment-specific controls such as CSRF/origin policy require an explicit production configuration.
See π₯οΈ YAGNI Frontend for the rationale, rich-client triggers, and clean-cutover rule.