From f4e7d4e359dc226af7547c9f2c2348a846103235 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sat, 9 May 2026 22:40:54 +0200 Subject: [PATCH] feat: update README with enhanced feature descriptions and API documentation --- README.md | 88 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 92de895..effab9c 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,44 @@ # Movies Diary -A self-hosted, server-side rendered movie logging system. Built in Rust — no JavaScript, no SPA, just HTML forms and an RSS feed. Designed to run as a lightweight widget embedded on a personal site. +A self-hosted, server-side rendered movie logging system with a full REST API. Built in Rust — no JavaScript in the HTML interface, just HTML forms and an RSS feed. Designed to run as a lightweight widget embedded on a personal site or as a backend for third-party clients. ## Features -- Log movies with a TMDB/OMDb ID and a 0–5 rating +- Log movies with a TMDB/OMDb ID or manual title/year/director, with a 0–5 rating - Immutable append-only viewing ledger (tracks re-watches) - Background poster fetching and storage (local filesystem or S3-compatible) -- RSS/Atom feed for public subscription +- RSS/Atom feed for public subscription (global and per-user) - JWT authentication via cookie (HTML) or Bearer token (REST API) -- Zero JavaScript +- ActivityPub federation — follow/unfollow remote users on any compatible server, accept/reject/remove followers, pending follow request management +- CSV and JSON diary export (full round-trip: exported files can be re-imported via the TUI bulk import) +- REST API v1 (`/api/v1/`) with full feature parity with the HTML interface +- OpenAPI documentation at `/docs` (Swagger UI) and `/scalar` (Scalar) +- CSRF protection on all HTML form routes (double-submit cookie, defense-in-depth on top of `SameSite=Strict`) +- Per-IP rate limiting via token bucket (production-grade, backed by `axum-governor`) +- Terminal UI client (`crates/tui`) for logging reviews, bulk CSV import, and diary browsing ## Architecture Hexagonal (Ports & Adapters) with Domain-Driven Design: ``` -domain — pure types and trait definitions, no external deps -application — use cases / business logic orchestration -presentation — Axum HTTP router, wires all adapters together +domain — pure types and trait definitions, no external deps +application — use cases / business logic orchestration +presentation — Axum HTTP router, wires all adapters together adapters/ - auth — JWT issuance and validation (Argon2 passwords) - sqlite — SQLite repository via sqlx - metadata — OMDb HTTP client - poster-fetcher — downloads poster images - poster-storage — uploads posters to local filesystem or S3-compatible storage - template-askama — Askama HTML rendering - rss — RSS/Atom feed generation - event-publisher — async event channel for background poster sync + auth — JWT issuance and validation (Argon2 passwords) + sqlite — SQLite repository via sqlx + metadata — OMDb HTTP client + poster-fetcher — downloads poster images + poster-storage — uploads posters to local filesystem or S3-compatible storage + template-askama — Askama HTML rendering + rss — RSS/Atom feed generation + export — CSV and JSON diary serialization + event-publisher — async event channel for background poster sync + activitypub — ActivityPub federation (follow, inbox/outbox, actor) + activitypub-base — core ActivityPub types and repository traits +doc — OpenAPI spec assembly and Swagger UI / Scalar serving +tui — terminal UI client (ratatui) ``` ## Prerequisites @@ -39,7 +50,7 @@ adapters/ ## Environment Variables -A `.env.example` file is provided at the repo root — copy it to `.env` and fill in your values. Key variables: +A `.env.example` file is provided at the repo root — copy it to `.env` and fill in your values. ```env # Database @@ -51,6 +62,9 @@ JWT_SECRET=change-me # OMDb metadata OMDB_API_KEY=your-key +# Public base URL (used for ActivityPub actor URLs and canonical links) +BASE_URL=https://yourdomain.example.com + # Poster storage — pick one backend: # Option A: local filesystem (zero deps) @@ -64,9 +78,15 @@ POSTER_STORAGE_PATH=./posters # MINIO_REGION=minio # MINIO_ACCESS_KEY_ID=minioadmin # MINIO_SECRET_ACCESS_KEY=minioadmin -``` -See `.env.example` for optional variables (rate limiting, logging, host/port, etc.). +# Optional +HOST=0.0.0.0 +PORT=3000 +RATE_LIMIT=60 # requests per minute per IP (default: 60) +ALLOW_REGISTRATION=true # set to false to disable new sign-ups +SECURE_COOKIES=true # set when serving over HTTPS +RUST_LOG=presentation=info,tower_http=info +``` ## Run @@ -74,7 +94,24 @@ See `.env.example` for optional variables (rate limiting, logging, host/port, et cargo run -p presentation ``` -Server listens on `0.0.0.0:3000`. +Server listens on `0.0.0.0:3000` by default. + +## API + +All REST endpoints are under `/api/v1/`. Authentication uses `Authorization: Bearer ` obtained from `POST /api/v1/auth/login`. + +Interactive API documentation is available at runtime: + +- **Swagger UI** — `http://localhost:3000/docs` +- **Scalar** — `http://localhost:3000/scalar` + +## Terminal UI + +```bash +cargo run -p tui +``` + +Supports review logging, bulk CSV import (column order matches the export format), and diary browsing with review history. ## Test @@ -82,6 +119,19 @@ Server listens on `0.0.0.0:3000`. cargo test ``` +## Docker + +```bash +docker build -t movies-diary . +docker run -p 3000:3000 \ + -e DATABASE_URL=sqlite:///data/movies.db \ + -e JWT_SECRET=change-me \ + -e OMDB_API_KEY=your-key \ + -e BASE_URL=https://yourdomain.example.com \ + -v $(pwd)/data:/data \ + movies-diary +``` + ## License MIT License. See [LICENSE](LICENSE).