Files
Aurora-Core/docs/api.md
T
NixReaperandClaude Sonnet 5 892f78016c
CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
Add collection/franchise ingestion
Collections were bare stubs (name only) lazily created the moment a
movie's belongs_to_collection reference was seen. Adds a real
ingest_collection pipeline: TMDb's /collection/{id} for overview and
poster/backdrop artwork, plus ordered CollectionMovie membership --
linking only movies already ingested into Aurora, the same
never-fabricate-a-stub rule movie recommendations already follow.

get_or_create_collection now refreshes name/overview on an existing
stub instead of only creating, guarded so a bare movie-stub call
(overview=None) never clobbers real data a full ingestion already
filled in.

New POST /api/v1/admin/ingest/collection endpoint and
ingest_collection_task; GET /api/v1/collections/{id} needed no changes
since its read path (collection_service.py) already assembled the full
detail shape.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-05 08:37:27 -05:00

7.4 KiB

Aurora Core — API

Base path: /api/v1. Interactive OpenAPI docs are available at /docs in any environment where AURORA_API_DOCS_ENABLED=true (default; set to false to hide docs in production — section 32).

All responses are JSON, built from Pydantic response schemas (app/schemas/), never from serialized ORM objects (section 18). Errors use a consistent envelope:

{ "error": { "code": "movie_not_found", "message": "No such movie: aur_movie_..." } }

Health

Method Path Notes
GET /health and /api/v1/health Liveness only.
GET /ready and /api/v1/ready Checks PostgreSQL (always) and Redis (if REDIS_REQUIRED=true).
Method Path Notes
GET /api/v1/search?q=...&limit=10 Searches movies, series, people, collections, companies. limit (1-50) caps results per type.
GET /api/v1/search?q=the%20matrix

{
  "query": "the matrix",
  "movies": [ { "id": "aur_movie_...", "type": "movie", "title": "The Matrix", "release_date": "1999-03-30", "poster_path": "https://..." } ],
  "series": [],
  "people": [],
  "collections": [ { "id": "aur_collection_...", "name": "The Matrix Collection" } ],
  "companies": [],
  "total_results": 2
}

Movies

Method Path
GET /api/v1/movies/{aurora_id}
GET /api/v1/movies/{aurora_id}/credits
GET /api/v1/movies/{aurora_id}/images
GET /api/v1/movies/{aurora_id}/videos
GET /api/v1/movies/{aurora_id}/recommendations

GET /api/v1/movies/{aurora_id} (cached, see docs/architecture.md#caching):

{
  "id": "aur_movie_01m1q7p1c...",
  "type": "movie",
  "title": "The Matrix",
  "original_title": "The Matrix",
  "overview": "...",
  "tagline": "Welcome to the Real World",
  "status": "released",
  "original_language": "en",
  "release_date": "1999-03-30",
  "runtime": 136,
  "budget": 63000000,
  "revenue": 463517383,
  "popularity": 45.5,
  "vote_average": 8.2,
  "vote_count": 24000,
  "adult": false,
  "genres": [{ "id": "aur_genre_...", "name": "Action" }],
  "keywords": [{ "id": "aur_keyword_...", "name": "dystopia" }],
  "cast": [{ "id": "aur_credit_...", "person": { "id": "aur_person_...", "name": "Keanu Reeves", "profile_path": null }, "character": "Neo", "billing_order": 0 }],
  "crew": [{ "id": "aur_credit_...", "person": { "id": "aur_person_...", "name": "Lana Wachowski" }, "department": "Directing", "job": "Director" }],
  "companies": [{ "id": "aur_company_...", "name": "Village Roadshow Pictures", "company_type": "production_company" }],
  "collection": { "id": "aur_collection_...", "name": "The Matrix Collection" },
  "images": { "posters": [...], "backdrops": [...], "logos": [...] },
  "videos": [{ "id": "aur_vid_...", "type": "trailer", "site": "YouTube", "url": "https://www.youtube.com/watch?v=...", "is_official": true }],
  "external_ids": { "tmdb": "603", "imdb": "tt0133093" },
  "created_at": "...",
  "updated_at": "..."
}

GET /api/v1/movies/{aurora_id}/recommendations returns TMDb's ranked recommendations, but only the ones already ingested into Aurora — a recommendation pointing at a movie Aurora hasn't seen yet is silently dropped rather than fabricated as a stub (section 15), so this list can be sparse (or empty) for a young dataset and fills in as more movies get ingested:

{
  "id": "aur_movie_01m1q7p1c...",
  "recommendations": [
    { "id": "aur_movie_...", "type": "movie", "title": "The Matrix Reloaded", "release_date": "2003-05-15", "poster_path": "https://..." }
  ]
}

Series / Seasons / Episodes

Method Path
GET /api/v1/series/{aurora_id}
GET /api/v1/series/{aurora_id}/seasons
GET /api/v1/seasons/{aurora_id}
GET /api/v1/episodes/{aurora_id}

Series detail includes networks and companies as separate lists (a TV network and a production company are both Company rows distinguished by company_type — see docs/database.md), plus creators (series-level "Creator" credits) alongside cast/crew.

People

Method Path
GET /api/v1/people/{aurora_id}
GET /api/v1/people/{aurora_id}/credits (movie and series filmography; guest-star episode credits are aggregated to one row per series with episode_count, not one row per episode)

Collections / Companies

Method Path
GET /api/v1/collections/{aurora_id}
GET /api/v1/companies/{aurora_id}

Collection detail's movies list only includes movies already ingested into Aurora — POST /api/v1/admin/ingest/collection links a franchise's member movies purely by external-id lookup, the same never-fabricate-a-stub rule recommendations follows, so a franchise fills in as more of its movies get ingested rather than all at once.

Administrative (section 17: "separately protected")

Require header X-API-Key: <one of AURORA_ADMIN_API_KEYS>. Never exposed to public clients — mount behind a separate Traefik router/ACL in production if you want network-level isolation too.

Method Path Body Notes
POST /api/v1/admin/ingest/movie {"tmdb_id": "603"} Enqueues an arq job; returns {"job_id": "...", "status": "enqueued"} immediately (section 15: ingestion never runs inline in a request).
POST /api/v1/admin/ingest/person {"tmdb_id": "6384"} Same, for a person profile.
POST /api/v1/admin/ingest/series {"tmdb_id": "1396", "include_seasons": false} Ingests the series and season stubs (number, title, air date, poster) — no episodes yet. With include_seasons: true, also enqueues an ingest/season job for every season once the series finishes (opt-in: some shows have dozens of seasons, each a separate TMDb call).
POST /api/v1/admin/ingest/season {"tmdb_id": "1396", "season_number": 1} Ingests one season's full episode list. Requires the series to already be ingested (ingest/series first) — fails with a clear error otherwise.
POST /api/v1/admin/ingest/collection {"tmdb_id": "2344"} Ingests a franchise's own metadata (overview, poster/backdrop) and links its already-ingested member movies (see "Collections / Companies" above). Movie ingestion also lazily creates a bare name-only stub the first time it sees a belongs_to_collection reference — this is what actually fills it in.
GET /api/v1/admin/ingest/jobs/{job_id} — Poll job status: pending → running → succeeded/failed/retrying.

Errors

Status When
404 Entity not found, or the ID is well-formed but the wrong entity type (aur_person_... passed to /movies/{id})
422 Request validation failure (e.g. missing/invalid query params)
429 Rate limit exceeded (Retry-After header set)
401 Missing/invalid X-API-Key on an admin endpoint
503 Admin API called with AURORA_ADMIN_API_KEYS unset, or the job queue is unavailable

Known limitations

  • No pagination on list-shaped responses yet beyond search's limit (movie/series lists like recommendations return everything). Cursor-based pagination using the Aurora ID's inherent creation-order sort (see docs/database.md#aurora-ids-vs-primary-keys) is the natural next step.
  • /people/{id}/credits covers movies and series (episode guest-star credits rolled up per series). It does not yet expose a per-episode breakdown for those guest appearances (just the aggregate episode_count) — the individual episode Credit rows exist in the database if that's ever needed.