docs: sync README + architecture diagram with current codebase

This commit is contained in:
2026-07-10 21:56:16 +02:00
parent 1c81d7768c
commit 3dde0d13db
2 changed files with 14 additions and 9 deletions

View File

@@ -47,7 +47,7 @@ Open `http://localhost:3000`. The HTTP server and background worker start togeth
## Features ## Features
- Log movies with a TMDB/OMDb ID or manual title/year/director, with a 05 rating and optional watch medium (cinema, streaming, TV, physical media, download, media server) - Log movies with a TMDB/OMDb ID or manual title/year/director, with a 15 rating and optional watch medium (cinema, streaming, TV, physical media, download, media server)
- Edit reviews after the fact — update rating, comment, date, or watch medium via partial PATCH; each watch is still a separate record (re-watches tracked) - Edit reviews after the fact — update rating, comment, date, or watch medium via partial PATCH; each watch is still a separate record (re-watches tracked)
- Background poster fetching and storage (local filesystem or S3-compatible) - Background poster fetching and storage (local filesystem or S3-compatible)
- Movie enrichment via TMDb — full cast, crew, genres, keywords, runtime, budget/revenue, ratings; fetched automatically on movie discovery and refreshed every 30 days; exposed via `GET /api/v1/movies/{id}/profile` - Movie enrichment via TMDb — full cast, crew, genres, keywords, runtime, budget/revenue, ratings; fetched automatically on movie discovery and refreshed every 30 days; exposed via `GET /api/v1/movies/{id}/profile`
@@ -60,8 +60,9 @@ Open `http://localhost:3000`. The HTTP server and background worker start togeth
- Watchlist — add movies to watch later, per-user; federated watchlist entries visible for remote actors - Watchlist — add movies to watch later, per-user; federated watchlist entries visible for remote actors
- User profiles — display name, bio, avatar, banner, custom profile fields; editable via HTML settings page or REST API; account deletion broadcasts AP `Delete` actor activity; `alsoKnownAs` change triggers AP `Move` for account migration - User profiles — display name, bio, avatar, banner, custom profile fields; editable via HTML settings page or REST API; account deletion broadcasts AP `Delete` actor activity; `alsoKnownAs` change triggers AP `Move` for account migration
- Jellyfin/Plex auto-import — media server sends a webhook on playback stop, movies land in a watch queue; review and confirm with a rating to create diary entries; per-user webhook tokens with SHA-256 auth; setup UI at `/settings/integrations` - Jellyfin/Plex auto-import — media server sends a webhook on playback stop, movies land in a watch queue; review and confirm with a rating to create diary entries; per-user webhook tokens with SHA-256 auth; setup UI at `/settings/integrations`
- Annual Wrap-Up — Spotify Wrapped for movies: per-user and instance-wide year-in-review with stats (top directors, actors, genres, rating distribution, watch time, rewatches, budget analysis), shareable HTML page at `/wrapups/{user_id}/{year}`; admin-triggered or auto-generated in January - Annual Wrap-Up — Spotify Wrapped for movies: per-user and instance-wide year-in-review with stats (top directors, actors, genres, rating distribution, watch time, watch medium breakdown, rewatches, budget analysis); directors/actors filtered by minimum watch count for statistical relevance; shareable HTML page at `/wrapups/{user_id}/{year}`; admin-triggered or auto-generated in January
- Goals — set a "watch N movies in YEAR" target with a progress bar; progress computed from existing reviews (backwards compatible); per-user federation toggle in settings; displayed on profile (SPA: interactive with create/edit/delete, classic HTML: read-only glassmorphic card) - Goals — set a "watch N movies in YEAR" target with a progress bar; progress computed from existing reviews (backwards compatible); per-user federation toggle in settings; displayed on profile (SPA: interactive with create/edit/delete, classic HTML: read-only glassmorphic card)
- Profile trends — top directors, genre breakdown, rating distribution histogram, watch medium breakdown, monthly activity chart; all computed from the user's review history
- CSV and JSON diary export - CSV and JSON diary export
- File importer: upload CSV, TSV, JSON, or XLSX from any source (Letterboxd, IMDb, etc.), map columns to domain fields via a step-by-step wizard or REST API, save mapping profiles for repeat imports - File importer: upload CSV, TSV, JSON, or XLSX from any source (Letterboxd, IMDb, etc.), map columns to domain fields via a step-by-step wizard or REST API, save mapping profiles for repeat imports
- REST API v1 (`/api/v1/`) with full feature parity with the HTML interface - REST API v1 (`/api/v1/`) with full feature parity with the HTML interface
@@ -90,8 +91,8 @@ Hexagonal (Ports & Adapters) with Domain-Driven Design:
``` ```
api-types — shared REST API request/response DTOs (Serialize/Deserialize + utoipa schemas) + HtmlPageContext; used by presentation, tui, and template adapters api-types — shared REST API request/response DTOs (Serialize/Deserialize + utoipa schemas) + HtmlPageContext; used by presentation, tui, and template adapters
infra-wiring — shared infrastructure types (DbPool, EventBusBackend, AppConfig) used by both presentation and worker binaries infra-wiring — shared infrastructure types (DbPool, EventBusBackend, AppConfig) used by both presentation and worker binaries
domain — pure types and CQRS port traits (MovieCommand/MovieQuery, WatchEventCommand/WatchEventQuery, GoalCommand/GoalQuery, DiaryQuery, PersonCommand/PersonQuery, SearchCommand/SearchPort, ImageFetcher, RssFeedRenderer), no external deps except serde domain — pure types and CQRS port traits (MovieCommand/MovieQuery, WatchEventCommand/WatchEventQuery, GoalCommand/GoalQuery, DiaryQuery, PersonCommand/PersonQuery, SearchCommand/SearchPort, SocialCommand/SocialQuery, ImageFetcher, RssFeedRenderer), no external deps except serde
application — use cases (commands + queries), business logic orchestration; handlers delegate here for all domain logic application — use cases (commands + queries), business logic orchestration; handlers delegate here for all domain logic; modules: auth, diary, goals, import, integrations, movies, person, search, social, users, watchlist, wrapup
presentation — Axum HTTP router, OpenAPI spec assembly, Swagger UI + Scalar serving, composition root for the HTTP process presentation — Axum HTTP router, OpenAPI spec assembly, Swagger UI + Scalar serving, composition root for the HTTP process
worker — standalone worker binary (event consumer, poster sync, federation) worker — standalone worker binary (event consumer, poster sync, federation)
adapters/ adapters/
@@ -101,7 +102,7 @@ adapters/
postgres — PostgreSQL repository + connection factory postgres — PostgreSQL repository + connection factory
metadata — TMDB / OMDb HTTP client metadata — TMDB / OMDb HTTP client
poster-fetcher — downloads poster images poster-fetcher — downloads poster images
image-storage — stores images (posters + user avatars) on local filesystem or S3-compatible storage object-storage — stores images (posters + user avatars) on local filesystem or S3-compatible storage
poster-sync — event handler: triggers poster fetch+store on MovieDiscovered poster-sync — event handler: triggers poster fetch+store on MovieDiscovered
image-converter — optional background worker: converts stored images to AVIF or WebP; backfills existing images via a 24h periodic job image-converter — optional background worker: converts stored images to AVIF or WebP; backfills existing images via a 24h periodic job
tmdb-enrichment — TMDb HTTP client implementing MovieEnrichmentClient and PersonEnrichmentClient; event handlers (MovieEnrichmentHandler, PersonEnrichmentHandler) live in the application layer tmdb-enrichment — TMDb HTTP client implementing MovieEnrichmentClient and PersonEnrichmentClient; event handlers (MovieEnrichmentHandler, PersonEnrichmentHandler) live in the application layer
@@ -114,6 +115,7 @@ adapters/
event-payload — shared event serialization DTOs (used by all event bus adapters) event-payload — shared event serialization DTOs (used by all event bus adapters)
sqlite-event-queue — durable polling event queue backed by SQLite sqlite-event-queue — durable polling event queue backed by SQLite
postgres-event-queue — durable polling event queue backed by PostgreSQL postgres-event-queue — durable polling event queue backed by PostgreSQL
event-publisher — in-memory event channel (used in tests)
nats — NATS Core / JetStream event publisher and consumer nats — NATS Core / JetStream event publisher and consumer
event-publisher — in-memory event channel (used in tests) event-publisher — in-memory event channel (used in tests)
activitypub — ActivityPub federation adapter (follow, inbox/outbox, actor); delegates to k-ap for protocol internals activitypub — ActivityPub federation adapter (follow, inbox/outbox, actor); delegates to k-ap for protocol internals

View File

@@ -24,6 +24,7 @@ graph TB
UC_INTEGRATIONS["integrations<br/>webhooks, watch_queue,<br/>confirm, dismiss"] UC_INTEGRATIONS["integrations<br/>webhooks, watch_queue,<br/>confirm, dismiss"]
UC_SEARCH["search<br/>execute"] UC_SEARCH["search<br/>execute"]
UC_PERSON["person<br/>get, get_credits"] UC_PERSON["person<br/>get, get_credits"]
UC_SOCIAL["social<br/>follow, unfollow,<br/>accept, reject, block"]
end end
subgraph EventHandlers["Event Handlers"] subgraph EventHandlers["Event Handlers"]
EH_MOVIE["MovieEnrichmentHandler<br/><i>on MovieEnrichmentRequested</i>"] EH_MOVIE["MovieEnrichmentHandler<br/><i>on MovieEnrichmentRequested</i>"]
@@ -59,10 +60,10 @@ graph TB
M_SEARCH["SearchQuery,<br/>SearchResults"] M_SEARCH["SearchQuery,<br/>SearchResults"]
end end
subgraph Ports["Port Traits (Interfaces)"] subgraph Ports["Port Traits (Interfaces)"]
P_REPOS["MovieCommand / MovieQuery<br/>ReviewRepository<br/>DiaryQuery / StatsRepository<br/>UserRepository<br/>WatchlistRepository<br/>WatchEventCommand / WatchEventQuery<br/>WebhookTokenRepository<br/>ImportSessionRepository<br/>MovieProfileRepository<br/>WrapUpRepository<br/>GoalCommand / GoalQuery<br/>UserSettingsRepository<br/>MovieDeduplicator"] P_REPOS["MovieCommand / MovieQuery<br/>ReviewRepository<br/>DiaryQuery / StatsRepository<br/>UserRepository / UserProfileFieldsRepository<br/>WatchlistRepository<br/>WatchEventCommand / WatchEventQuery<br/>WebhookTokenRepository<br/>ImportSessionRepository / ImportProfileRepository<br/>MovieProfileRepository<br/>WrapUpRepository / WrapUpStatsQuery<br/>GoalCommand / GoalQuery<br/>UserSettingsRepository / RefreshSessionRepository<br/>MovieDeduplicator"]
P_SERVICES["AuthService<br/>MetadataClient<br/>PosterFetcherClient<br/>ImageFetcher<br/>ObjectStorage<br/>EventPublisher<br/>EventConsumer<br/>PasswordHasher<br/>DiaryExporter<br/>DocumentParser<br/>RssFeedRenderer"] P_SERVICES["AuthService<br/>MetadataClient / MovieEnrichmentClient<br/>PersonEnrichmentClient<br/>PosterFetcherClient<br/>ImageFetcher / ObjectStorage<br/>EventPublisher / EventConsumer<br/>PasswordHasher<br/>DiaryExporter / DocumentParser<br/>RssFeedRenderer / MediaServerParser"]
P_SEARCH["SearchPort<br/>SearchCommand<br/>PersonQuery<br/>PersonCommand"] P_SEARCH["SearchPort / SearchCommand<br/>PersonQuery / PersonCommand<br/>FederatedProfileQuery"]
P_FEDERATION["SocialQueryPort<br/>LocalApContentQuery<br/>RemoteWatchlistRepository<br/>RemoteGoalRepository"] P_FEDERATION["SocialCommand / SocialQuery<br/>FederationAdminQuery<br/>LocalApContentQuery<br/>RemoteWatchlistRepository<br/>RemoteGoalRepository"]
end end
subgraph DomainServices["Services (pure, no I/O)"] subgraph DomainServices["Services (pure, no I/O)"]
DS_WRAPUP["WrapUpAnalyzer<br/><i>build_report, compute_*</i>"] DS_WRAPUP["WrapUpAnalyzer<br/><i>build_report, compute_*</i>"]
@@ -92,7 +93,9 @@ graph TB
end end
subgraph Messaging["Messaging"] subgraph Messaging["Messaging"]
A_NATS["nats<br/><i>JetStream / Core</i>"] A_NATS["nats<br/><i>JetStream / Core</i>"]
A_SQLITE_QUEUE["sqlite-event-queue<br/><i>Polling, dead-letter</i>"]
A_PG_QUEUE["postgres-event-queue<br/><i>Polling, dead-letter</i>"] A_PG_QUEUE["postgres-event-queue<br/><i>Polling, dead-letter</i>"]
A_EVT_PUB["event-publisher<br/><i>In-memory (tests)</i>"]
A_PAYLOAD["event-payload<br/><i>Serde (de)serialization</i>"] A_PAYLOAD["event-payload<br/><i>Serde (de)serialization</i>"]
end end
subgraph External["External Services"] subgraph External["External Services"]