docs: expand README with detailed project documentation

This commit is contained in:
2026-06-21 02:19:25 +02:00
committed by Milas Holsting
parent b793566221
commit 8ebaac758c

197
README.md
View File

@@ -7,65 +7,186 @@
<p align="center"> <p align="center">
<img alt="Go" src="https://img.shields.io/badge/go-1.25-00ADD8?style=flat-square&logo=go" /> <img alt="Go" src="https://img.shields.io/badge/go-1.25-00ADD8?style=flat-square&logo=go" />
<img alt="SQLite" src="https://img.shields.io/badge/database-sqlite-003B57?style=flat-square&logo=sqlite" /> <img alt="SQLite" src="https://img.shields.io/badge/database-sqlite-003B57?style=flat-square&logo=sqlite" />
<img alt="Bun" src="https://img.shields.io/badge/runtime-bun-000000?style=flat-square&logo=bun" />
<img alt="Tailwind" src="https://img.shields.io/badge/tailwind-4-06D6D4?style=flat-square&logo=tailwindcss" /> <img alt="Tailwind" src="https://img.shields.io/badge/tailwind-4-06D6D4?style=flat-square&logo=tailwindcss" />
<img alt="HTMX" src="https://img.shields.io/badge/htmx-partial--updates-3366CC?style=flat-square" /> <img alt="HTMX" src="https://img.shields.io/badge/htmx-partial--updates-3366CC?style=flat-square" />
<img alt="License" src="https://img.shields.io/badge/license-MIT-green?style=flat-square" /> <img alt="License" src="https://img.shields.io/badge/license-MIT-green?style=flat-square" />
</p> </p>
MyAnimeList is a small self-hosted anime tracker and playback app. It keeps the catalog, watchlist, MyAnimeList is a self-hosted anime tracker, catalog browser, watchlist, and playback app built as a
progress tracking, and player in one place, backed by a single SQLite database and a single Go portfolio-grade full-stack project. It brings the parts of an anime discovery workflow that usually
server. 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.
Most of the UI is rendered on the server. HTMX handles lightweight updates like pagination and The project is intentionally built like a small real-world product instead of a throwaway demo. The
watchlist changes, while TypeScript is kept for the parts that need real browser state: the video backend is a Go application with feature-oriented modules, SQLite persistence, schema migrations,
player, search page, theme handling, and skip segment editor. The app also includes local users, API startup data fixes, provider clients, and tests around the parts that are easy to regress. The UI is
tokens, subtitle support, playlist rewriting, provider integrations, migrations, and startup data mostly server-rendered with Go templates and enhanced with HTMX where partial updates make sense.
fixes. TypeScript is reserved for browser-heavy behavior such as the video player, search interactions,
theme handling, progress updates, subtitles, skip segments, and carousel controls.
## Running ## Why This Exists
Requires [`mise`](https://mise.jdx.dev/), a C compiler for SQLite, and the tools managed in I made this project to explore what a focused, personal media app can look like when it is treated
`.mise.toml`. 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:
- 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
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 It Can Do
- 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`.
## Architecture
The repository is organized around product features and integration boundaries:
| Path | Purpose |
| --- | --- |
| `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. |
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.
## Technology Choices
- **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.
## Developer Experience
This project is set up around a small number of repeatable commands. The main workflow is:
```bash ```bash
mise install mise install
bun install bun install
just build 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`.
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:
```bash
go run ./cmd/user <username> <password> go run ./cmd/user <username> <password>
just dev
``` ```
The app starts on `http://localhost:3000` by default. Configuration comes from environment ## Quality Bar
variables, and a local `.env` file is loaded automatically. The most useful options are `PORT`,
`DATABASE_FILE`, `PLAYBACK_PROXY_SECRET`, `EPISODE_AVAILABILITY_MODE`, and
`ANIMESCHEDULE_API_TOKEN`.
## Development The codebase aims for a practical production style:
The codebase is split between Go feature packages, external integrations, server-rendered templates, - feature packages own their handlers, services, repositories, and module wiring;
and a small frontend asset pipeline. `cmd/server` starts the web app, `cmd/user` contains local - external provider behavior is isolated in `integrations`;
admin tools, `internal` holds the application modules, `integrations` holds provider clients, and - migrations are versioned and committed with the application code;
`templates`, `static`, and `dist` contain the UI. - 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.
The common development commands are in the `justfile`. ## Project Status
```bash This is a personal portfolio project and local-first application. It is still evolving, but the repo
just setup is structured to make future work straightforward: add migrations when the data model changes, keep
just dev provider-specific logic behind integration packages, prefer server-rendered flows by default, and use
just fmt TypeScript only where browser state is genuinely doing work.
just test
just lint-go
just lint-ts
just typecheck
just build
```
Run the full local check with: ## Community And Security
```bash Please read the project docs before contributing or using code from this repository:
just check
``` - [`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.
## License ## License
MIT. See [`LICENSE`](LICENSE). This project is released under the MIT License. See [`LICENSE`](LICENSE) for the full text.