Spaces:
Sleeping
Download docs/architecture/API_CONTRACT_V1.md from phucsd/Oloka-Video-Dev: direct link, hf CLI and curl.
- Browser
- Download file 30.6 kB
-
https://huggingface.co/spaces/phucsd/Oloka-Video-Dev/resolve/main/docs/architecture/API_CONTRACT_V1.md
- Command line
-
hf download hf://spaces/phucsd/Oloka-Video-Dev/docs/architecture/API_CONTRACT_V1.md
-
curl -L -o API_CONTRACT_V1.md https://huggingface.co/spaces/phucsd/Oloka-Video-Dev/resolve/main/docs/architecture/API_CONTRACT_V1.md
API Contract V1
Status: capability map and transport contract. Slice 3C, Slice 3D, and the schema-v6 Phase 3E core are implemented, merged, and production-cutover complete; the Phase 3E.3 transactional-outbox runtime correction is not deployed until its later cutover verification. Phase 3F has not started.
Protocol conventions
- Product API paths are
/api/v1/**. Foundation probes remain/api/health,/api/ready, and/api/version. - JSON contracts are strict Zod schemas exported once from
packages/contracts; unknown keys fail with the canonical error envelope fromERROR_MODEL.md. - UUID resource IDs are opaque. Unauthorized private resources are indistinguishable from missing resources (
404 RESOURCE_NOT_FOUND). - All unsafe cookie-authenticated requests apply
AUTH_SESSION_CSRF.md. - First-admin bootstrap is part of the verified Google callback transaction and has no separate HTTP route. Admin role/status mutation enforces the last-active-admin guard; emergency recovery is operator maintenance only.
- Important mutations require exactly one
Idempotency-Keycontaining 1-128 ASCII characters fromA-Z a-z 0-9 . _ : -. Missing, empty, multiple, Unicode, whitespace, control, slash, backslash, quote, or oversized values are400 VALIDATION_ERROR. The server hashes the key and canonical semantic request; same key/same request replays the stored result and same key/different request is409 IDEMPOTENCY_CONFLICT. - Mutable resources expose an integer
versionand ETag. Updates requireIf-MatchorexpectedVersion; stale writes return409 VERSION_CONFLICTwith current safe version, never silently overwrite. - Lists use an opaque base64url cursor containing versioned canonical sort position, filter fingerprint, and ID tie-breaker. Default/max page sizes are 25/100. Sorting is deterministic; cursor/filter mismatch is
400 INVALID_CURSOR. - Times are ISO 8601 UTC strings at the HTTP boundary and epoch milliseconds in SQLite.
- IDs, not storage keys/paths/provider secrets, cross the API boundary.
Slice 3C Project projection
Owner Project responses expose only id, name, nullable description,
favorite, status, ISO-8601 UTC createdAt/updatedAt, and positive
version. They never expose owner columns, retention/purge internals, storage
keys, or filesystem paths. Owner routes return 404 RESOURCE_NOT_FOUND for a
different owner, including when the actor is an admin.
Slice 3C lists only active Projects at API-011 and only soft_deleted
Projects at API-062. Both use the authenticated opaque cursor contract and the
owner list order favorite DESC, updated_at DESC, id DESC. Slice 3C does not
implement purge scheduling/worker side effects despite the later-state schema
foundation.
Slice 3D Asset projection
Owner Asset responses expose only the resource/project IDs, normalized original filename, kind, declared/verified MIME, immutable byte size/checksum, bounded technical metadata, ingestion/lifecycle status, safe failure code, timestamps, and optimistic version. They never expose owner columns, storage/staging keys, filesystem paths, reconciliation state, or capability hashes. Upload responses expose the UploadSession ID, Asset ID, canonical received offset, declared length, lifecycle status, expiry, and recommended chunk size only.
Common errors
The stable code, status, retryability, message key, action, severity, and allowed
surface come only from ERROR_MODEL.md. Common mappings are
400 VALIDATION_ERROR/INVALID_CURSOR, 401 AUTHENTICATION_REQUIRED,
403 AUTHORIZATION_DENIED or an account-status code,
404 RESOURCE_NOT_FOUND, 409 RESOURCE_STATE_CONFLICT/VERSION_CONFLICT/
IDEMPOTENCY_CONFLICT, 413 PAYLOAD_TOO_LARGE,
415 UNSUPPORTED_MEDIA_TYPE, 416 RANGE_NOT_SATISFIABLE, typed 422 domain
codes, 429 QUOTA_EXCEEDED/RATE_LIMITED/PROVIDER_RATE_LIMITED, typed
502/503 provider or storage codes, and 500 INTERNAL_ERROR. Every response
contains safe code, localized messageKey, suggestedAction, retryable,
requestId, and optional allowlisted field details; never a stack or provider body.
Capability map
Legend: U authenticated user/owner, A administrator, P public/operator probe, O OIDC provider callback. Idem means Idempotency-Key required. Ver means optimistic version required. “Audit” names the success/denial class; security denials may be sampled/rate-limited.
| ID | Method and path | Actor; request -> response | Errors | Idempotency/concurrency | Audit; transaction/side effect |
|---|---|---|---|---|---|
| API-001 | GET /api/health |
P; none -> liveness/build | 500 | none/read-only | metric only; no tx |
| API-002 | GET /api/ready |
P/operator; none -> DB/storage/migration readiness without secrets | 503 | none/read-only | operational log; no write tx |
| API-003 | GET /api/version |
P; none -> build SHA/schema compatibility | 500 | cache-safe/read-only | metric only; no tx |
| API-004 | GET /api/v1/auth/google/start |
browser; safe same-origin return path -> Google redirect | 400,429,503 | one-use OAuth transaction | login-start; short security-state write |
| API-005 | GET /api/v1/auth/google/callback |
O/browser; code/state -> session cookie + validated return path; every failure -> fixed 303 /auth/error without query disclosure |
fixed safe redirect | state/nonce/PKCE one-use | login success/failure; provider denial consumes state; TX-01 |
| API-006 | GET /api/v1/auth/session |
U/pending member; none -> safe user status/session expiry | 401 | read-only | none; session last-seen coalesced |
| API-007 | GET /api/v1/auth/csrf |
U/pending member; none -> synchronizer token | 401 | no-store; per session | none; may rotate token in a guarded session write |
| API-008 | POST /api/v1/auth/logout |
U/pending member; CSRF -> 204 | 401,403 | repeat succeeds | logout; TX-03 |
| API-009 | GET /api/v1/auth/sessions |
U; cursor -> own safe session list | 401,400 | cursor/read-only | none |
| API-010 | POST /api/v1/auth/sessions/revoke-all |
U; CSRF/confirm -> revoked count + current-session policy result | 401,403 | Idem | session revoke-all; TX-03 |
| API-011 | GET /api/v1/projects |
U; cursor/status -> project summaries | 400,401 | cursor/read-only | none |
| API-012 | POST /api/v1/projects |
U; name/description -> project | 400,409 | Idem | project.create; TX-04 |
| API-013 | GET /api/v1/projects/:projectId |
U owner; ID -> project snapshot | 401,404 | ETag/read-only | none |
| API-014 | PATCH /api/v1/projects/:projectId |
U owner; rename/favorite + expected version -> updated project | 400,401,404,409 | Idem + Ver | project.update; TX-05 |
| API-015 | DELETE /api/v1/projects/:projectId |
U owner; expected version/confirm -> soft-deleted project | 401,404,409 | Idem + Ver | project.delete_requested; TX-06, later queues purge |
| API-016 | POST /api/v1/projects/:projectId/restore |
U owner; expected version -> active project when policy permits | 401,404,409 | Idem + Ver | project.restore; TX-06 |
| API-017 | POST /api/v1/projects/:projectId/uploads |
U owner; file metadata/size/checksum -> Asset + upload session | 400,404,409,413,415 | Idem; project Ver guard | upload.create; TX-07 |
| API-018 | HEAD /api/v1/uploads/:uploadId |
U owner; ID -> offset/length/status headers | 401,404,409 | read-only authoritative offset | none |
| API-019 | PATCH /api/v1/uploads/:uploadId |
U owner; offset + binary chunk -> new offset | 400,404,409,413,415 | offset/chunk checksum retry; Ver | upload.append metric; file then TX-08 |
| API-020 | POST /api/v1/uploads/:uploadId/complete |
U owner; optional checksum -> asset/job | 404,409,415,422 | Idem + upload Ver | upload.complete; TX-09 |
| API-021 | DELETE /api/v1/uploads/:uploadId |
U owner; ID -> 204 | 404 | repeat succeeds | upload.abort; TX-10 |
| API-022 | GET /api/v1/projects/:projectId/assets |
U owner; cursor/media type/upload time/ingestion/lifecycle/original-filename search -> assets | 400,404 | cursor/read-only | none |
| API-023 | GET /api/v1/assets/:assetId |
U owner; ID -> metadata/status | 401,404 | ETag/read-only | none |
| API-024 | POST /api/v1/assets/:assetId/retry-ingestion |
U owner; failed active Asset/version -> same Asset + new ingestion attempt | 404,409 | Idem + Ver | asset.ingestion_retry; TX-10-style admission |
| API-025 | DELETE /api/v1/assets/:assetId |
U owner; expected version -> soft-deleted lifecycle | 404,409 | Idem + Ver | asset.delete_requested; later TX-20 schedule |
| API-026 | GET /api/v1/assets/:assetId/content |
U owner; Range/conditional headers -> bytes | 404,416,503 | immutable ETag/read-only | access metric; authorized range stream |
| API-027 | POST /api/v1/assets/:assetId/delivery-capabilities |
U owner; operation -> short opaque capability | 404,409 | Idem; resource state guard | capability.issue; TX-23 |
| API-028 | GET /api/v1/projects/:projectId/compositions |
U owner; cursor/status -> version summaries | 400,404 | cursor/read-only | none |
| API-029 | POST /api/v1/projects/:projectId/compositions |
U owner; CompositionDocumentV1/parent/version -> immutable version | 400,404,409,422 | Idem + project Ver | composition.create; TX-11 |
| API-030 | GET /api/v1/compositions/:compositionVersionId |
U owner; ID -> canonical document/validation | 404 | immutable ETag | none |
| API-031 | POST /api/v1/compositions/:compositionVersionId/derive |
U owner; structured patch/edit intent -> new version | 400,404,409,422 | Idem + expected parent/project Ver | composition.derive; TX-11 |
| API-032 | POST /api/v1/compositions/:compositionVersionId/validate |
U owner; ID -> durable validation result | 404,409,422 | Idem; immutable input | composition.validate; bounded job or deterministic service |
| API-033 | POST /api/v1/projects/:projectId/generation-jobs |
U owner; brief/options/asset IDs -> Job | 400,404,409,422,503 | Idem + project Ver | generation.request; TX-12 |
| API-034 | POST /api/v1/compositions/:compositionVersionId/regenerate |
U owner; structured change brief/options -> Job | 400,404,409,422,503 | Idem; immutable source + project Ver | generation.regenerate; TX-12 |
| API-035 | POST /api/v1/compositions/:compositionVersionId/preview |
U owner; ID -> preview artifact/status | 404,409,422 | Idem; immutable version | preview.request/materialize; TX-12/TX-17 |
| API-036 | GET /api/v1/previews/:previewArtifactId |
U owner; ID -> artifact metadata/player bootstrap | 404,409,503 | immutable ETag/read-only | preview.access; authorized bootstrap |
| API-037 | GET /api/v1/previews/:previewArtifactId/content |
U owner or scoped capability; Range -> immutable artifact bytes | 404,416,503 | ETag/read-only | safe access metric; range stream |
| API-038 | POST /api/v1/compositions/:compositionVersionId/render-jobs |
U owner; output preset -> Job | 400,404,409,422,503 | Idem; immutable composition | render.request; TX-12 |
| API-039 | GET /api/v1/jobs |
U; cursor/type/status/project -> summaries | 400 | cursor/read-only | none |
| API-040 | GET /api/v1/jobs/:jobId |
U owner; ID -> durable snapshot | 404 | ETag/read-only | none |
| API-041 | GET /api/v1/jobs/:jobId/steps |
U owner; cursor -> safe step summaries | 400,404 | cursor/read-only | none |
| API-042 | GET /api/v1/jobs/:jobId/event-history |
U owner; cursor -> durable events | 400,404 | cursor/read-only | none |
| API-043 | GET /api/v1/jobs/:jobId/events |
U owner; Last-Event-ID -> SSE | 400,404,409 | durable replay; no mutation | connection metric; no tx beyond reads |
| API-044 | POST /api/v1/jobs/:jobId/cancel |
U owner; cancellable job/version -> snapshot | 404,409 | Idem + Ver | job.cancel_requested; TX-16 |
| API-045 | GET /api/v1/projects/:projectId/outputs |
U owner; cursor/state -> output summaries | 400,404 | cursor/read-only | none |
| API-046 | GET /api/v1/outputs/:outputId |
U owner; ID -> immutable evidence + lifecycle | 404 | ETag/read-only | none |
| API-047 | GET /api/v1/outputs/:outputId/content |
U owner/capability; Range -> video bytes | 404,416,503 | immutable ETag | output.download/stream metric; no write tx |
| API-048 | POST /api/v1/outputs/:outputId/delivery-capabilities |
U owner; download/stream -> opaque capability | 404,409 | Idem | capability.issue; TX-23 |
| API-049 | DELETE /api/v1/outputs/:outputId |
U owner; expected state version -> purge-scheduled | 404,409 | Idem + Ver | output.delete_requested; TX-20 |
| API-050 | GET /api/v1/settings/profile |
U; none -> safe profile/preferences | 401 | ETag/read-only | none |
| API-051 | PATCH /api/v1/settings/profile |
U; display/preferences/version -> profile | 400,409 | Idem + Ver | user.profile_update; short user tx |
| API-052 | GET /api/v1/settings/provider-status |
U; none -> enabled capability health (no reference names) | 401 | short cache/read-only | none |
| API-053 | GET /api/v1/admin/users |
A; cursor/status/search -> safe users | 400,403 | cursor/read-only | admin.read_users |
| API-054 | PATCH /api/v1/admin/users/:userId |
A; role/status/version -> user; reject last-active-admin lockout | 400,403,404,409 | Idem + Ver | admin.user_update; TX-02 |
| API-055 | GET /api/v1/admin/jobs |
A; cursor/type/status/lease -> redacted operational summaries | 400,403 | cursor/read-only | admin.read_jobs |
| API-056 | POST /api/v1/admin/jobs/:jobId/reconcile |
A; reason/version -> redacted reconciliation intent | 403,404,409 | Idem + Ver | admin.job_reconcile; TX-13/outbox |
| API-057 | GET /api/v1/admin/provider-credentials |
A; cursor -> reference names/status/health | 403 | cursor/read-only | admin.read_provider_refs |
| API-058 | PUT /api/v1/admin/provider-credentials/:referenceId |
A; provider/purpose/env-name/status/version -> reference | 400,403,409 | Idem + Ver | admin.provider_ref_update; never writes HF secret |
| API-059 | GET /api/v1/admin/audit-events |
A; cursor/actor/action/resource/time -> redacted events | 400,403 | cursor/read-only | admin.read_audit |
| API-060 | GET /api/v1/admin/operations |
A; none -> queue/lease/outbox/storage/backup health summary | 403,503 | read-only snapshot | admin.read_operations |
| API-062 | GET /api/v1/trash/projects |
U; cursor -> own soft-deleted/purge-scheduled Projects | 400,401 | cursor/read-only | none |
| API-063 | GET /api/v1/projects/:projectId/compositions/current |
U owner; project ID -> selected immutable version or null | 404 | project ETag/read-only | none |
| API-064 | POST /api/v1/outputs/:outputId/pin |
U owner; state version -> pinned state | 404,409 | Idem + Ver | output.pin; guarded output-state tx |
| API-065 | POST /api/v1/outputs/:outputId/unpin |
U owner; state version -> unpinned state | 404,409 | Idem + Ver | output.unpin; guarded output-state tx |
| API-066 | GET /api/v1/admin/users/pending |
A; cursor -> pending members | 400,403 | cursor/read-only | admin.read_pending_users |
| API-067 | POST /api/v1/admin/provider-credentials/:referenceId/health-check |
A; reference/version -> safe health result/job | 403,404,409,503 | Idem + Ver | admin.provider_health_check; bounded outbox/job intent |
| API-068 | GET /api/v1/admin/quota-policies |
A; cursor/scope -> versioned policies | 400,403 | cursor/read-only | admin.read_quota_policies |
| API-069 | POST /api/v1/admin/quota-policies |
A; scope/policy/effective interval -> new policy version | 400,403,409 | Idem + expected prior Ver | admin.quota_policy_create; quota/audit tx |
| API-070 | POST /api/v1/jobs/:jobId/retry |
U owner; retryable terminal job -> new Job | 404,409,503 | Idem; immutable original request | job.retry; TX-12, never reopens terminal row |
| API-071 | GET /api/v1/admin/jobs/:jobId |
A; ID -> redacted state/step/code/timestamps/lease diagnostics | 403,404 | ETag/read-only | admin.read_job_diagnostics; no owner SSE/content |
| API-072 | GET /api/v1/outputs/:outputId/download |
U owner or download-scoped capability; conditional request -> attachment bytes | 404,416,503 | immutable ETag/read-only | output.download metric; authorized Range stream |
Cursor shape
The opaque cursor encodes versioned canonical sort position, filter hash, and
UUID tie-breaker as base64url JSON plus HMAC-SHA256 under an HKDF-derived app
key. The implemented admin-user cursor is {v:1, sort:{createdAt,id}, filterHash} and binds normalized status/search. It never contains email,
display name, secret values, storage keys, provider operation IDs, or token
material. Invalid encoding/MAC/version/key/filter is 400 INVALID_CURSOR;
default/max page sizes are 25/100.
Contract ownership and evolution
Request, response, event, cursor, error, and composition schemas live in packages/contracts and are imported by both Fastify and React. API v1 additions are backward compatible; breaking shape/meaning requires a new API or schema version. OpenAPI may be generated from the canonical Zod contracts in Phase 3, but generated output is not a competing source of truth.
The capability map contains 72 sequential capabilities. Render cancellation and retry use only the generic Job commands; no parallel render-specific command routes exist. Owner-facing Project, CompositionVersion, Job history/status and SSE routes are owner-only. Administrators inspect Jobs only through the redacted admin list/detail/command surfaces, which exclude prompts, private bytes, storage paths/keys, raw provider payloads, and owner SSE.