docs: rewrite README with prose focus and screenshot

This commit is contained in:
2026-05-25 20:19:28 +02:00
parent 246fa7439d
commit b6e06870aa
2 changed files with 26 additions and 97 deletions

123
README.md
View File

@@ -1,57 +1,42 @@
# MyAnimeList # MyAnimeList
<table align="center"> <p align="center">
<tr> <picture>
<td> <source media="(prefers-color-scheme: dark)" srcset="/static/assets/readme-logo-dark.svg" />
<picture> <img src="/static/assets/readme-logo-light.svg" alt="MyAnimeList logo" width="120" />
<source media="(prefers-color-scheme: dark)" srcset="/static/assets/readme-logo-dark.svg" /> </picture>
<img src="/static/assets/readme-logo-light.svg" alt="MyAnimeList logo" width="140" /> <br />
</picture> <em>My personal anime tracker, built because nothing else felt right.</em>
</td> </p>
<td>
<strong>MyAnimeList</strong><br />
My personal anime tracker, built because nothing else felt right.
</td>
</tr>
</table>
<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="Tailwind" src="https://img.shields.io/badge/tailwind-4-06B6D4?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" />
</p> </p>
--- <img alt="MyAnimeList home page screenshot" src="/static/assets/screenshot-home.png" width="800" />
## Why this project exists I was frustrated with every anime tracker I tried. Decent UI but awkward UX. Good features but missing the ones I actually use. So I built my own: search fast, get context fast, update your status fast, and move on.
I built this for myself. This project is personal first — I put it on GitHub because I like shipping in the open. It also doubles as proof that a small, server-rendered Go app can stay reliable even when upstream anime APIs are inconsistent.
I was frustrated with the UI and UX of every tracker I tried. Even when something looked decent, it still felt awkward to use day-to-day, or it was missing pieces I considered essential. I wanted one place that matched how I actually watch anime: search fast, get context fast, update status fast, and move on. - **Catalog browsing & seasonal discovery** — explore what's airing, filter by season
- **Quick search** — find anime, get mal links, open the detail page in seconds
So this project is personal first and public second. I put it on GitHub because I like shipping in the open, not because it was originally designed as a general-purpose product for everyone. - **Detail pages** — synopsis, stats, recommendations, related entries
- **Watchlist management** — track your progress across statuses
Technically, I also wanted to prove that a small, server-rendered Go app could stay reliable even when upstream anime APIs are inconsistent. A lot of this code exists because real APIs rate-limit, timeout, and occasionally fail at the worst possible moment. - **Continue watching** — pick up where you left off
- **In-app playback** — proxy-based video player
## What the application offers
For my own workflow, MyAnimeList combines catalog browsing, seasonal discovery, quick search, detail pages with recommendations and relations, watchlist management, continue-watching, and in-app playback in one server-rendered interface.
The interface is minimal and functional, featuring a dark theme and quick access to tracking tools.
## Technical approach ## Technical approach
The application is written in Go and rendered on the server with `html/template`, with SQLite as the primary datastore and `sqlc` for typed query generation. Styling uses Tailwind CSS v4. HTMX and small TypeScript modules handle incremental interactions, which keeps the interface responsive without moving the entire product into a heavy client-side architecture. Written in Go with server-rendered `html/template`, SQLite + `sqlc` for typed queries, Tailwind CSS v4 for styling, and HTMX backed by small TypeScript modules for incremental interactions.
The external anime data source is Jikan (`https://api.jikan.moe/v4`). Because reliability is a first-class concern, the client layer includes request pacing, bounded retries, backoff behavior, stale-cache fallback, and a persisted retry queue for failed fetches. Playback proxying uses uTLS to bypass Cloudflare protections. The external anime data source is [Jikan](https://api.jikan.moe/v4). The client layer handles request pacing, bounded retries, backoff, stale-cache fallback, and a persisted retry queue. Playback proxying uses uTLS to bypass Cloudflare. The system is built to degrade gracefully under `429` and `5xx` responses rather than fail hard.
Upstream APIs can fail transiently with `429` and `5xx` responses, so the app favors graceful degradation over hard failure. Cached values are used when fresh requests fail, retryable failures are persisted and replayed in a background worker, and relation synchronization is incremental so one bad fetch does not block the rest of the graph.
## Repository structure ## Repository structure
The codebase follows standard Go project layout conventions.
| Path | Purpose | | Path | Purpose |
| ----------------- | ------------------------------------------------ | | ----------------- | ------------------------------------------------ |
| `api/*` | Feature routes: anime, auth, playback, watchlist | | `api/*` | Feature routes: anime, auth, playback, watchlist |
@@ -63,74 +48,18 @@ The codebase follows standard Go project layout conventions.
| `migrations` | Schema evolution | | `migrations` | Schema evolution |
| `static` / `dist` | Frontend assets | | `static` / `dist` | Frontend assets |
## Getting started ## Running locally
Requires Go `1.25+`, Bun, and [just](https://github.com/casey/just) (`brew install just`). Requires Go `1.25+`, Bun, and [just](https://github.com/casey/just). Migrations run on startup. Configuration lives in environment variables — see `cmd/server/main.go` for the full list.
```bash ```bash
git clone https://github.com/mkelvers/mal.git && cd mal just dev
openssl rand -base32 32
PLAYBACK_PROXY_SECRET="your-32-char-secret" go run ./cmd/server
go run ./cmd/user <username> <password>
``` ```
The app runs at `http://localhost:3000`. ## Contributing
### Tasks Bug reports and pull requests are welcome. This is a personal project, so there is no strict roadmap or issue triage cycle. If something is broken or missing, open an issue or send a PR.
The justfile automates common tasks:
```bash
just fmt # format go code
just lint # go fmt && go vet
just test # run go tests
just build # build go binary + frontend
just check # lint, test, typecheck, build
just dev # build and run
just install-hooks # install pre-push hooks
```
### Docker
```bash
docker build -t mal .
docker run --rm -p 3000:3000 -e PLAYBACK_PROXY_SECRET="$(openssl rand -base32 32)" mal
# persistent data
docker run --rm -p 3000:3000 \
-e DATABASE_FILE=/app/data/mal.db \
-e PLAYBACK_PROXY_SECRET="your-secret" \
-v "$(pwd)/data:/app/data" \
mal
docker exec mal ./cmd/user <username> <password>
```
## Configuration
| Variable | Default | Description |
| ----------------------- | ------------------- | ----------------------------------------------------------- |
| `PORT` | `3000` | HTTP listen port |
| `DATABASE_FILE` | `mal.db` | SQLite database file path |
| `ENV` | _(empty)_ | Set to `production` to enable secure session cookies |
| `MIGRATIONS_DIR` | _(auto-discovered)_ | Optional explicit path to migration files |
| `PLAYBACK_PROXY_SECRET` | _(required)_ | HMAC secret for signed playback proxy tokens (min 32 chars) |
| `MAL_JIKAN_TRACE` | `false` | Log all Jikan cache/upstream timings when enabled |
## Testing
Run locally with `just check` or manually:
```bash
go test ./...
```
Migrations run automatically on startup.
## Security
Keep secrets out of version control, do not publish real credentials in documentation or screenshots, and report security issues privately before public disclosure.
## License ## License
This project is released under the MIT License. See `LICENSE` for details. MIT. See `LICENSE`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB