diff --git a/README.md b/README.md index 481f970..cc64e60 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,17 @@ watch based on their region, streaming services, and preferences. External APIs populate a local catalog; browsing and filter changes will query WatchPulse's own data rather than calling upstream APIs. -The MVP provides region- and provider-aware discovery across five shared, -filterable sections: +The first-release UI provides region- and provider-aware discovery across four +shared, filterable sections: - Top 10 - New Releases - Recently Added -- Leaving Soon - Upcoming +The evidence-only Leaving Soon API remains available, but its UI section is +deferred until expiration ingestion is enabled. + See [AGENTS.md](AGENTS.md) for the current product requirements and [docs/architecture.md](docs/architecture.md) for the active architecture and implementation decisions. `AGENTS.md` remains the authoritative product brief. @@ -27,8 +29,7 @@ Documentation is split by responsibility: ## Project status -Version `v0.4` is released and `v0.5` frontend discovery is in progress. The repository currently -includes: +Version `v0.5` is the current release. The repository includes: - configurable TMDB discovery by region and provider; - full movie and TV metadata ingestion; @@ -52,14 +53,17 @@ includes: - scoped local title details with aggregated provider availability; - a responsive React frontend with region-aware provider selection and shared content type, genre, runtime, release-year, rating, and language filters; -- a filter-reactive Top 10 rail with reusable ranked poster cards and explicit - loading, empty, failure, and retry states; +- filter-reactive Top 10, New Releases, Recently Added, and Upcoming rails with + reusable poster cards and explicit loading, empty, failure, and retry states; +- local title search that respects the active region, providers, and filters; +- verified provider actions plus explicit outbound TMDB title-detail links; +- bounded broad and priority-based incremental TMDB enrichment planning; - unit tests that do not make live API calls. -Version `v0.4` adds a read-only FastAPI discovery backend, typed global filters, -parameterized local queries, catalog reference/freshness routes, all five -discovery sections, and scoped title details. See the -[v0.4 release notes](docs/releases/v0.4.md). +Version `v0.5` adds the complete local guest discovery interface, catalog +search, Upcoming lifecycle presentation, TMDB/provider navigation, and +intelligent enrichment planning. See the +[v0.5 release notes](docs/releases/v0.5.md). Add `STREAMING_AVAILABILITY_API_KEY` only when running live lifecycle ingestion; offline tests and warehouse builds do not require it. diff --git a/api/tests/test_discovery_integration.py b/api/tests/test_discovery_integration.py index 61d9735..3b46b53 100644 --- a/api/tests/test_discovery_integration.py +++ b/api/tests/test_discovery_integration.py @@ -343,7 +343,7 @@ def test_discovery_errors_are_validated_and_sanitized(tmp_path: Path) -> None: assert injection.status_code == 422 -def test_openapi_contains_the_complete_v04_contract(catalog_app: FastAPI) -> None: +def test_openapi_contains_the_complete_v05_contract(catalog_app: FastAPI) -> None: schema = _get(catalog_app, "/openapi.json").json() required_paths = { "/health", @@ -362,4 +362,4 @@ def test_openapi_contains_the_complete_v04_contract(catalog_app: FastAPI) -> Non } assert required_paths <= set(schema["paths"]) - assert schema["info"]["version"] == "0.4.0" + assert schema["info"]["version"] == "0.5.0" diff --git a/docs/releases/v0.5.md b/docs/releases/v0.5.md new file mode 100644 index 0000000..7b85030 --- /dev/null +++ b/docs/releases/v0.5.md @@ -0,0 +1,66 @@ +# WatchPulse v0.5 — Frontend Discovery + +Released: 2026-09-01 + +## Outcome + +WatchPulse now provides a complete local guest discovery experience. A user can +select Greece and their streaming services, apply shared filters, search the +catalog, and browse four deterministic discovery sections without triggering +TMDB or Streaming Availability requests from the browser. + +## Delivered + +- a responsive React 19, TypeScript, and Vite frontend; +- region-aware provider selection with browser-local guest preferences; +- shared content-type, genre, runtime, release-year, rating, and language + filters; +- filter-reactive Top 10, New Releases, Recently Added, and Upcoming rails; +- reusable title cards with posters, concise descriptions, genres, years, + ratings, lifecycle dates, and available series totals; +- local title/original-title search scoped by the active catalog filters; +- verified provider deep links when retained evidence supplies them; +- explicit TMDB navigation for richer title details; +- required TMDB attribution and JustWatch data attribution; +- targeted metadata/provider reconciliation for lifecycle-only titles; +- broad backfill and priority-based incremental TMDB enrichment planning with + dry runs, configurable caps, freshness windows, and resumable raw batches; +- source-aware catalog freshness shown in the visitor's local timezone. + +## Product decisions + +- WatchPulse remains a decision engine; TMDB is the canonical rich title-detail + destination for the first public release. +- Leaving Soon is not displayed until expiration evidence is ingested. No + departure date is inferred. +- Provider actions are shown only for verified HTTPS links. Missing links are + presented honestly rather than guessed. +- All browsing and filter interactions query the local serving database only. + +## Validation + +- 115 offline Python tests pass. +- 25 frontend tests pass with ESLint, TypeScript, and production builds. +- The warehouse build passes 222 dbt models/seeds/tests with zero errors. +- Commit and push hooks include secret detection, coverage, dbt validation, + formatting, linting, and protected-branch checks. +- A complete Netflix Greece discovery fetched all 471 TMDB pages in a bounded + discovery-only run without consuming Streaming Availability quota. + +## Known limitations + +- The UI currently targets Greece; the schema and API remain multi-region. +- Netflix Greece has complete discovery coverage in the retained local + development catalog. Other launch providers require equivalent full scans. +- Runtime, season/episode totals, and direct provider links remain nullable + until targeted or broad enrichment provides evidence. +- Streaming lifecycle automation remains manual. Production scheduling, + durable artifact delivery, monitoring, and deployment arrive in v0.6. +- Leaving Soon remains absent while `expiring` ingestion is disabled. +- Authentication and personalization are intentionally outside this release. + +## Next version + +v0.6 deploys WatchPulse privately under an owned domain with protected API +access, durable data delivery, scheduled ingestion, monitoring, and reproducible +operations. diff --git a/docs/roadmap.md b/docs/roadmap.md index a6313a6..e2f1db7 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -156,7 +156,7 @@ the [v0.4 release notes](releases/v0.4.md). Goal: deliver the complete deterministic user experience locally. -Current status: **release candidate (2026-09-01)**. React, TypeScript, and Vite are +Current status: **complete (2026-09-01)**. React, TypeScript, and Vite are selected in ADR-018. The first increment establishes the responsive application shell, typed local API client, catalog readiness state, explicit development CORS policy, frontend tests, and CI build validation. The second increment adds @@ -212,6 +212,11 @@ but is intentionally excluded from v0.5 because expiration ingestion is not enabled. The existing backend endpoint remains evidence-only and returns no guessed departures. +Exit criteria result: passed for the accepted four-section release scope. The +guest experience works end-to-end without login, all filters query only the +local WatchPulse API, desktop/mobile layouts are validated, and title details +lead explicitly to TMDB. See the [v0.5 release notes](releases/v0.5.md). + ## v0.6 — Automation and deployment Goal: make WatchPulse reproducible, observable, and publicly accessible. diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 5f850c0..4e8922e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -62,7 +62,7 @@ export default function App() { {state.kind === "ready" ? ( Updated {formatRefresh(state.status.freshness.latest_source_updated_at)} - ) : v0.5 preview} + ) : v0.5}