Foundation for the user-accounts platform. Self-hosted PocketBase v0.39.6, version-pinned from the official release binary, schema-as-code so the collections auto-apply on boot and never drift from hand-clicking. Collections: users (auth, admin-only nsfwEnabled), profiles, watch_state, watchlist, prefs. Per-owner access rules traverse profile.user; nsfwEnabled is never client-writable (superuser-only). Relations cascadeDelete; unique indexes keep one resume/watchlist row per (profile,itemId) and one prefs per profile. Verified locally against v0.39.6: migration applies clean, and scripts/verify.py proves two users can't read/write each other's data and can't set their own nsfwEnabled (19/19 checks). Coolify deploy (domain/TLS, superuser, SMTP, backups) documented in README as the manual half. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
106 lines
5.1 KiB
Markdown
106 lines
5.1 KiB
Markdown
# myanime-backend
|
|
|
|
**PocketBase** backend for the myanime app — auth, database, realtime, file
|
|
storage and admin UI in a single Go binary. This is the foundation the account
|
|
features build on: cloud sync, codeless device sign-in, profiles, child
|
|
profiles, recommendations, and gated auto-update (epic
|
|
[#6](https://projects.petruzalekr.cz/richiexec/myanime-app/issues/6)).
|
|
|
|
- **No E2E.** TLS in transit + at-rest on disk. The server is deliberately
|
|
readable so recommendations, the admin `nsfwEnabled` flag, and painless
|
|
password reset all work.
|
|
- **Schema as code.** The collections live in [`pb_migrations/`](pb_migrations/)
|
|
and auto-apply on boot — never hand-click the schema in the admin UI, or the
|
|
next deploy will drift.
|
|
- **Version-pinned.** The [`Dockerfile`](Dockerfile) downloads the official
|
|
PocketBase **v0.39.6** static binary from GitHub releases (no third-party
|
|
image). Bump `PB_VERSION` there and in `docker-compose.yml` to upgrade.
|
|
|
|
## Data model
|
|
|
|
```
|
|
users ─┬─* profiles ─┬─* watch_state (resume points; 1 row per profile+item)
|
|
(auth)│ ├─* watchlist (1 row per profile+item)
|
|
│ └─1 prefs (playback/audio/subtitle blob)
|
|
└ nsfwEnabled (admin-only bool → gates adult vs clean build, issue #16)
|
|
```
|
|
|
|
| Collection | Type | Key fields |
|
|
|---------------|------|------------|
|
|
| `users` | auth | `username` (unique when set), `email`, `password`, **`nsfwEnabled`** (admin-only) |
|
|
| `profiles` | base | `user`→users, `name`, `avatar` (file), `isChild`, `pinHash` (hidden) |
|
|
| `watch_state` | base | `profile`→profiles, `itemId`, `itemType`, `position`, `duration`, `updatedAt` |
|
|
| `watchlist` | base | `profile`→profiles, `itemId`, `itemType`, `addedAt` |
|
|
| `prefs` | base | `profile`→profiles, `data` (json) |
|
|
|
|
**Access rules.** A user only ever reads/writes their own `users` row, their own
|
|
`profiles`, and rows whose `profile.user` is them. `nsfwEnabled` is never
|
|
accepted from a client (`@request.body.nsfwEnabled:isset = false` on create and
|
|
update) — only a **superuser** sets it, from the admin UI. Relations
|
|
`cascadeDelete`, so deleting a user removes their profiles and all child rows.
|
|
Unique indexes keep one resume/watchlist row per `(profile, itemId)` and one
|
|
`prefs` row per profile.
|
|
|
|
## Local run / verify
|
|
|
|
```bash
|
|
docker compose up --build # http://localhost:8090
|
|
# create the first superuser (one-time):
|
|
docker compose exec pocketbase pocketbase superuser upsert you@example.com 'a-strong-pass' --dir=/pb_data
|
|
# admin UI: http://localhost:8090/_/
|
|
```
|
|
|
|
The end-to-end access-rule check (two users can't see each other's data; a user
|
|
can't set their own `nsfwEnabled`; a superuser can) lives in
|
|
[`scripts/verify.py`](scripts/verify.py):
|
|
|
|
```bash
|
|
python scripts/verify.py # expects the server on :8090 + the superuser above
|
|
```
|
|
|
|
## Deploy on Coolify
|
|
|
|
The schema and image are automated; the steps below need your hands, Coolify
|
|
access and secrets (which never live in this repo).
|
|
|
|
1. **Push this repo** to a remote Coolify can reach (e.g. GitHub, like
|
|
`myanime-pair-server`).
|
|
2. **New Resource → Dockerfile application**, point it at this repo. It listens
|
|
on `8090`.
|
|
3. **Persistent storage:** add a volume mounted at **`/pb_data`** (DB + uploaded
|
|
files). Without this you lose data on redeploy.
|
|
4. **Domain + TLS:** set the domain to `pb.petruzalekr.cz`; Coolify/Traefik
|
|
provisions the Let's Encrypt cert and terminates TLS in front of the plain
|
|
`:8090`. Force-HTTPS on.
|
|
5. **Bootstrap the superuser** once, from the container terminal:
|
|
`pocketbase superuser upsert you@example.com 'a-strong-pass' --dir=/pb_data`
|
|
(or open the printed `/_/#/pbinstall/...` link on first boot). **Lock down**
|
|
the admin UI — strong password; the `_superusers` collection is the only way
|
|
in.
|
|
6. **SMTP** (admin UI → *Settings → Mail settings*): point at your SMTP host so
|
|
verification / password-reset emails send. Send the test email to confirm.
|
|
7. **Automated backups** (admin UI → *Settings → Backups*): enable the schedule
|
|
and, ideally, S3 off-site upload. Coolify volume backups are a second layer.
|
|
8. **App wiring** (later issues, not here): point the app's API base at
|
|
`https://pb.petruzalekr.cz`.
|
|
|
|
### Verify the deploy
|
|
|
|
- Admin UI reachable over **HTTPS** only; HTTP redirects up.
|
|
- Create a test user + profile + a couple of rows via admin or REST; confirm a
|
|
second user can't read them (run `scripts/verify.py` against the live URL by
|
|
editing `BASE`).
|
|
- Trigger a password-reset email and confirm delivery.
|
|
- Confirm a backup ran and can be downloaded/restored.
|
|
|
|
## Security
|
|
|
|
Account/session tokens and the addon plaintext-credential "tokens" are **never
|
|
logged or echoed** (see the app's `CLAUDE.md`). `pinHash` is a hidden field and
|
|
never leaves the API. `nsfwEnabled` is admin-only by rule, not just by UI.
|
|
|
|
## Upgrading PocketBase
|
|
|
|
Bump `PB_VERSION` in the `Dockerfile` (and the compose arg), rebuild, redeploy.
|
|
Check the PocketBase release notes for migration-API or schema changes first,
|
|
and test locally with `docker compose up --build` before deploying.
|