From ce64efaf5f5d9acf97cef0664982582b460c0944 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Sun, 21 Jun 2026 02:25:14 +0200 Subject: [PATCH] docs: reorganize and trim README --- README.md | 282 +++++++++++++++++++++++++++--------------------------- 1 file changed, 143 insertions(+), 139 deletions(-) diff --git a/README.md b/README.md index fe1bea7..ceadf32 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,10 @@ MyAnimeList logo

+

+ A local-first anime catalog, watchlist, recommendation, and playback app. +

+

Go SQLite @@ -13,99 +17,93 @@ License

-MyAnimeList is a self-hosted anime tracker, catalog browser, watchlist, and playback app built as a -portfolio-grade full-stack project. It brings the parts of an anime discovery workflow that usually -live across several services into one local application: browsing titles, saving a watchlist, -tracking progress, continuing episodes, reading metadata, finding recommendations, and watching -through a browser player backed by provider integrations. +--- -The project is intentionally built like a small real-world product instead of a throwaway demo. The -backend is a Go application with feature-oriented modules, SQLite persistence, schema migrations, -startup data fixes, provider clients, and tests around the parts that are easy to regress. The UI is -mostly server-rendered with Go templates and enhanced with HTMX where partial updates make sense. -TypeScript is reserved for browser-heavy behavior such as the video player, search interactions, -theme handling, progress updates, subtitles, skip segments, and carousel controls. +MyAnimeList is a self-hosted media app for browsing anime, managing a watchlist, resuming episodes, +and playing streams through a browser-based player. It collects the parts of an anime workflow that +usually live across several products and keeps them in one small Go application backed by SQLite. -## Why This Exists +I built it as a portfolio project, but the goal was never to make a disposable demo. The interesting +part of the project is the product shape: server-rendered pages, a local database, provider +integrations, playback proxying, recommendations, migrations, tests, and a TypeScript player that +only appears where browser state actually earns its place. -I made this project to explore what a focused, personal media app can look like when it is treated -with the same care as a production product. Anime tracking is a good problem space because it touches -many practical engineering concerns without needing a large team or cloud platform: +> [!NOTE] +> This is a personal, local-first project. It is written to demonstrate product engineering choices, +> not to present itself as an official MyAnimeList client or a hosted streaming platform. -- local authentication and user-owned data -- catalog search, browse filters, details pages, and recommendations -- long-lived state such as watchlists, playback progress, and continue-watching rows -- server-rendered pages with small, deliberate frontend islands -- integration boundaries around external metadata and playback providers -- background refresh policies, cache behavior, migrations, and data repair jobs -- observability, request context, error handling, and testable service boundaries +## Contents -The goal is not to replace a commercial anime platform. The goal is to show how I think about product -engineering: keeping the architecture understandable, making features feel cohesive, choosing boring -tools where possible, and building enough operational structure that the app feels like it could keep -growing. +- [What This Project Is](#what-this-project-is) +- [What It Includes](#what-it-includes) +- [How It Is Built](#how-it-is-built) +- [Working Locally](#working-locally) +- [Repository Map](#repository-map) +- [Project Documents](#project-documents) -## What It Can Do +## What This Project Is -- Browse and search anime using external catalog data. -- View detail pages with metadata, synopsis, reviews, characters, statistics, related titles, themes, - and watch-order information. -- Maintain a local watchlist with status-oriented user state. -- Continue watching from stored playback progress. -- Play episodes through an HLS-capable web player. -- Rewrite playlists and proxy playback/subtitle requests through the server. -- Track progress, completion, episode navigation, quality, keyboard controls, and player state in - TypeScript. -- Support subtitles, subtitle caching, and VTT parsing. -- Manage skip segments and local skip-segment overrides. -- Generate personalized top picks from watchlist taste signals and recommendation data. -- Run SQLite migrations and one-off data fixes as the data model evolves. -- Create local users and run maintenance commands from `cmd/user`. +This project started from a simple idea: anime tracking becomes more interesting when catalog data, +personal progress, and playback live in the same interface. A user should be able to discover a +title, inspect its metadata, add it to a watchlist, watch an episode, come back later, and continue +from the right place without stitching that flow together manually. -## Architecture +That makes the app a useful playground for real application concerns. It has authentication, +long-lived user state, external APIs, background refresh behavior, migrations, data fixes, cache +boundaries, provider-specific code, and enough frontend complexity to justify TypeScript without +turning the whole product into a single-page app. -The repository is organized around product features and integration boundaries: +The project is also intentionally modest. It uses a single Go server and a SQLite database because +those choices make the system easy to run, inspect, and reason about. The architecture is more about +clear ownership than novelty: feature packages own their handlers and services, integrations stay at +the edges, and the UI is mostly rendered by the server. -| Path | Purpose | +## What It Includes + +| Area | What it does | | --- | --- | -| `cmd/server` | Application entry point for the web server. | -| `cmd/user` | Local admin and maintenance commands. | -| `internal/anime` | Catalog, details, browse, search, reviews, and recommendations wiring. | -| `internal/auth` | Local authentication, middleware, and user session behavior. | -| `internal/watchlist` | Watchlist handlers, service logic, and persistence access. | -| `internal/playback` | Playback state, progress, proxy tokens, skip segments, and watch data. | -| `internal/episodes` | Episode refresh and provider mapping logic. | -| `internal/database` | SQLite setup, migrations, and startup data fixes. | -| `internal/db` | Generated and helper database access code. | -| `integrations/jikan` | Jikan API client, rate limiting, query helpers, and catalog types. | -| `integrations/playback/allanime` | Playback provider client and extraction logic. | -| `templates` | Server-rendered pages and reusable Go template components. | -| `static` | TypeScript source for client-side interactions and player behavior. | -| `scripts` | Bun-powered development and maintenance scripts. | +| Catalog | Browse, search, and inspect anime metadata from external catalog sources. | +| Details | Render synopsis, reviews, characters, statistics, relations, themes, and watch-order data. | +| Watchlist | Store local user state for saved titles, statuses, and progress-driven flows. | +| Playback | Serve watch pages, proxy streams/subtitles, rewrite playlists, and track progress. | +| Player | Handle HLS playback, quality selection, subtitles, keyboard controls, episode navigation, and skip segments. | +| Recommendations | Generate personal top picks from watchlist signals and recommendation data. | +| Maintenance | Run migrations, startup fixes, local user commands, and data repair scripts. | -The application uses Go for the long-running server, domain services, provider clients, and data -access. SQLite keeps the app simple to run locally while still supporting real schema evolution -through migrations. Bun is used for the frontend toolchain, TypeScript checks, formatting, linting, -and small developer scripts. `mise` pins the tool versions so a fresh checkout can get to a working -environment quickly. +
+Implementation notes -## Technology Choices +The backend is written in Go with Gin for HTTP routing and Fx for module wiring. SQLite is used for +local persistence, with migrations and data fixes committed alongside the application. Templates are +rendered on the server, HTMX handles small partial updates, and TypeScript powers the interactive +parts of the browser experience. -- **Go** keeps the backend fast, explicit, and easy to ship as a single binary. -- **Gin** provides HTTP routing and middleware without hiding the request lifecycle. -- **Uber Fx** wires modules together in a way that keeps feature packages independent. -- **SQLite** makes the project self-contained and easy to run without external infrastructure. -- **Goose** manages migrations as the schema changes. -- **Go templates** keep most UI rendering close to the server data model. -- **HTMX** adds small partial updates without turning the app into a full SPA. -- **TypeScript** handles the browser behavior that benefits from strong client-side structure. -- **Tailwind CSS** provides a compact styling workflow. -- **Bun** runs the frontend build, lint, format, and script tasks. -- **mise** pins local tool versions for reproducible development. +The most stateful frontend code lives under `static/player`, where the app handles playback mode, +source loading, progress storage, subtitles, timelines, quality changes, keyboard shortcuts, skip +segments, episode completion, and thumbnail navigation. -## Developer Experience +
-This project is set up around a small number of repeatable commands. The main workflow is: +## How It Is Built + +The application is organized around product boundaries rather than framework layers. `internal/anime` +owns catalog-facing behavior, `internal/watchlist` owns saved user state, `internal/playback` owns +watch data and proxy behavior, and `integrations` contains provider clients. This keeps the core app +from depending directly on the details of a specific metadata or playback source. + +Server-rendered templates are the default because most pages are content-heavy and benefit from +simple request-response rendering. TypeScript is used where the browser has real ongoing state: +search interactions, theme handling, carousels, watchlist actions, toast messages, and especially +the video player. + +The result is a codebase that behaves like a small product rather than a tutorial project: it has a +repeatable toolchain, database evolution, local maintenance commands, focused tests, and a clear +split between app code and external integrations. + +## Working Locally + +The local workflow assumes [`mise`](https://mise.jdx.dev/) for tool versions and `just` for common +commands. ```bash mise install @@ -113,80 +111,86 @@ bun install just dev ``` -`just dev` runs the app through Air, which rebuilds the Go server and frontend assets when relevant -files change. The default server address is `http://localhost:3000`. +The development server runs on `http://localhost:3000` by default. `just dev` uses Air to rebuild the +Go server and frontend assets when relevant files change. -Configuration is read from environment variables, and a local `.env` file is loaded automatically. -Useful variables include: - -| Variable | Default | Purpose | -| --- | --- | --- | -| `PORT` | `3000` | HTTP port for the local server. | -| `DATABASE_FILE` | `mal.db` | SQLite database path. | -| `GIN_MODE` | release default | Gin runtime mode. | -| `MAL_CORS_ALLOW_ALL` | disabled | Allows any origin when set to `1`; useful only for local or proxy setups. | -| `PLAYBACK_PROXY_SECRET` | empty | Enables signed playback proxy tokens when set. | -| `EPISODE_AVAILABILITY_MODE` | `auto` | Episode availability strategy: `auto`, `legacy`, or `jikan`. | -| `MAL_JIKAN_TRACE` | disabled | Enables optional Jikan client tracing when truthy. | - -## Common Commands - -The project uses `just` as the command runner: - -| Command | Description | -| --- | --- | -| `just setup` | Install pinned tools with `mise` and install Bun dependencies. | -| `just dev` | Start the local development server with live rebuilds. | -| `just build` | Build the Go server, Tailwind CSS, and TypeScript assets. | -| `just test` | Run the Go test suite. | -| `just fmt` | Format Go code. | -| `bun run format` | Format TypeScript and related frontend files with `oxfmt`. | -| `just lint-go` | Run `golangci-lint` across Go packages. | -| `just lint-ts` | Run type-aware `oxlint` against the TypeScript source. | -| `just typecheck` | Run `tsc` without emitting files. | -| `just check` | Run linting, tests, typechecking, and a full build. | -| `just run` | Build and run the compiled server binary. | -| `just clean` | Remove generated build output. | -| `just new-data-fix name` | Scaffold a new data-fix file. | -| `just run-fixes` | Run registered data fixes through the user command. | -| `just fix-all` | Run the Bun maintenance script for data fixes. | - -To create a local user after setup: +Create a local user with: ```bash go run ./cmd/user ``` -## Quality Bar +### Commands -The codebase aims for a practical production style: +| Command | Use it for | +| --- | --- | +| `just setup` | Install pinned tools and Bun dependencies. | +| `just dev` | Run the app locally with live rebuilds. | +| `just build` | Build the Go binary, CSS, and TypeScript assets. | +| `just test` | Run the Go test suite. | +| `just check` | Run linting, tests, typechecking, and a full build. | +| `just lint-go` / `just lint-ts` | Run backend or frontend linting separately. | +| `just typecheck` | Run TypeScript without emitting files. | +| `just run` | Build and run the compiled server. | +| `just clean` | Remove generated build output. | -- feature packages own their handlers, services, repositories, and module wiring; -- external provider behavior is isolated in `integrations`; -- migrations are versioned and committed with the application code; -- template components use named props instead of implicit positional state; -- tests focus on database helpers, provider behavior, rendering helpers, recommendations, playback, - observability, and request handling; -- linting and typechecking are part of the normal local workflow; -- maintenance scripts are kept in the repo instead of living as undocumented one-off commands. +
+Configuration -## Project Status +Configuration is loaded from environment variables, and a local `.env` file is read automatically. -This is a personal portfolio project and local-first application. It is still evolving, but the repo -is structured to make future work straightforward: add migrations when the data model changes, keep -provider-specific logic behind integration packages, prefer server-rendered flows by default, and use -TypeScript only where browser state is genuinely doing work. +| Variable | Default | Purpose | +| --- | --- | --- | +| `PORT` | `3000` | HTTP port for the server. | +| `DATABASE_FILE` | `mal.db` | SQLite database path. | +| `GIN_MODE` | release default | Gin runtime mode. | +| `MAL_CORS_ALLOW_ALL` | disabled | Allows any origin when set to `1`; intended for local/proxy setups. | +| `PLAYBACK_PROXY_SECRET` | empty | Enables signed playback proxy tokens when set. | +| `EPISODE_AVAILABILITY_MODE` | `auto` | Episode availability strategy: `auto`, `legacy`, or `jikan`. | +| `MAL_JIKAN_TRACE` | disabled | Enables optional Jikan client tracing when truthy. | -## Community And Security +
-Please read the project docs before contributing or using code from this repository: +
+Maintenance commands -- [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) describes the expected standard for respectful - participation. -- [`SECURITY.md`](SECURITY.md) explains how to report security issues and how this project treats - sensitive playback, auth, and local data concerns. -- [`LICENSE`](LICENSE) contains the MIT license for this project. +| Command | Use it for | +| --- | --- | +| `just new-data-fix name` | Scaffold a new data-fix file. | +| `just run-fixes` | Run registered data fixes through `cmd/user`. | +| `just fix-all` | Run the Bun maintenance script for data fixes. | +| `bun run format` | Format TypeScript and related frontend files with `oxfmt`. | -## License +
-This project is released under the MIT License. See [`LICENSE`](LICENSE) for the full text. +## Repository Map + +| Path | Responsibility | +| --- | --- | +| `cmd/server` | Web server entry point. | +| `cmd/user` | Local user and maintenance commands. | +| `internal/anime` | Catalog, details, browse, search, reviews, and recommendations. | +| `internal/auth` | Authentication, middleware, and local user handling. | +| `internal/watchlist` | Watchlist handlers, service logic, and persistence. | +| `internal/playback` | Watch data, progress, proxy tokens, and skip segments. | +| `internal/episodes` | Episode refresh and provider mapping. | +| `internal/database` | SQLite setup, migrations, and startup data fixes. | +| `integrations/jikan` | Jikan API client and catalog types. | +| `integrations/playback/allanime` | Playback provider client and extraction logic. | +| `templates` | Server-rendered pages and reusable components. | +| `static` | TypeScript source for client-side behavior. | +| `scripts` | Bun-powered development and maintenance scripts. | + +## Project Documents + +This repository includes the usual project-level documents for public review and reuse: + +| Document | Purpose | +| --- | --- | +| [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) | Sets expectations for respectful project participation. | +| [`SECURITY.md`](SECURITY.md) | Explains how to report vulnerabilities and what is in scope. | +| [`LICENSE`](LICENSE) | MIT license terms. | + +--- + +Released under the [MIT License](LICENSE).