README: amber-backend, explicit deploys, and nsfwEnabled as legacy
- Retitled from myanime-backend. The Forgejo repo is amber-backend now; the old name redirects, and Coolify's source URL still uses it. - The deploy section said to push the repo to GitHub. It now describes the real Coolify app (uuid, domains, volume), says a push does not deploy it (every recorded deploy is an explicit call), gives the Deploy button and the API call, and the live checks (/api/health 200, /status 302). The first-time setup steps stay, with the git source step fixed for Forgejo. - nsfwEnabled no longer gates an adult versus clean build. There is one build: the manifest hook always serves clean, the releases rules dropped the flag (1793000000_releases_drop_adult_rule.js), whoami no longer returns it. The README now says so, and names its one remaining reader, the family web page's adult addon field and child-profile label. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c3635f0e7c
commit
ce9aa61bab
1 changed files with 79 additions and 23 deletions
102
README.md
102
README.md
|
|
@ -1,14 +1,17 @@
|
||||||
# myanime-backend
|
# amber-backend
|
||||||
|
|
||||||
**PocketBase** backend for the myanime app — auth, database, realtime, file
|
**PocketBase** backend for Amber: auth, database, realtime, file storage and admin
|
||||||
storage and admin UI in a single Go binary. This is the foundation the account
|
UI in a single Go binary. This is the foundation the account features build on:
|
||||||
features build on: cloud sync, codeless device sign-in, profiles, child
|
cloud sync, codeless device sign-in, profiles, child profiles, recommendations,
|
||||||
profiles, recommendations, and gated auto-update (epic
|
and gated auto-update (epic
|
||||||
[#6](https://projects.petruzalekr.cz/richiexec/myanime-app/issues/6)).
|
[#6](https://projects.petruzalekr.cz/richiexec/myanime-app/issues/6)).
|
||||||
|
|
||||||
|
The repo used to be called **myanime-backend**. On Forgejo it is now
|
||||||
|
`richiexec/amber-backend`; the old name still redirects to it, and Coolify's git
|
||||||
|
source still uses the old URL.
|
||||||
|
|
||||||
- **No E2E.** TLS in transit + at-rest on disk. The server is deliberately
|
- **No E2E.** TLS in transit + at-rest on disk. The server is deliberately
|
||||||
readable so recommendations, the admin `nsfwEnabled` flag, and painless
|
readable so recommendations and painless password reset work.
|
||||||
password reset all work.
|
|
||||||
- **Schema as code.** The collections live in [`pb_migrations/`](pb_migrations/)
|
- **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
|
and auto-apply on boot — never hand-click the schema in the admin UI, or the
|
||||||
next deploy will drift.
|
next deploy will drift.
|
||||||
|
|
@ -24,12 +27,12 @@ users ─┬─* profiles ─┬─* watch_state (resume points; 1 row per pro
|
||||||
│ ├─1 prefs (playback/audio/subtitle blob)
|
│ ├─1 prefs (playback/audio/subtitle blob)
|
||||||
│ └─1 addon_config (client-encrypted addon blob; ciphertext only)
|
│ └─1 addon_config (client-encrypted addon blob; ciphertext only)
|
||||||
├─* device_auth (codeless sign-in requests / approved devices, issue #12)
|
├─* device_auth (codeless sign-in requests / approved devices, issue #12)
|
||||||
└ nsfwEnabled (admin-only bool → gates adult vs clean build, issue #16)
|
└ nsfwEnabled (admin-only bool, legacy: see below)
|
||||||
```
|
```
|
||||||
|
|
||||||
| Collection | Type | Key fields |
|
| Collection | Type | Key fields |
|
||||||
|----------------|------|------------|
|
|----------------|------|------------|
|
||||||
| `users` | auth | `username` (unique when set), `email`, `password`, **`nsfwEnabled`** (admin-only) |
|
| `users` | auth | `username` (unique when set), `email`, `password`, **`nsfwEnabled`** (admin-only, legacy) |
|
||||||
| `profiles` | base | `user`→users, `name`, `avatar` (file), `isChild`, `pinHash` (hidden) |
|
| `profiles` | base | `user`→users, `name`, `avatar` (file), `isChild`, `pinHash` (hidden) |
|
||||||
| `watch_state` | base | `profile`→profiles, `itemId`, `itemType`, `position`, `duration`, `meta` (json), `updatedAt` (client), `updated` (server) |
|
| `watch_state` | base | `profile`→profiles, `itemId`, `itemType`, `position`, `duration`, `meta` (json), `updatedAt` (client), `updated` (server) |
|
||||||
| `watchlist` | base | `profile`→profiles, `itemId`, `itemType`, `meta` (json), `addedAt` (client), `updated` (server), `deletedAt` (tombstone) |
|
| `watchlist` | base | `profile`→profiles, `itemId`, `itemType`, `meta` (json), `addedAt` (client), `updated` (server), `deletedAt` (tombstone) |
|
||||||
|
|
@ -45,6 +48,28 @@ update) — only a **superuser** sets it, from the admin UI. Relations
|
||||||
Unique indexes keep one resume/watchlist row per `(profile, itemId)` and one
|
Unique indexes keep one resume/watchlist row per `(profile, itemId)` and one
|
||||||
`prefs`/`addon_config` row per profile.
|
`prefs`/`addon_config` row per profile.
|
||||||
|
|
||||||
|
### `nsfwEnabled` is legacy
|
||||||
|
|
||||||
|
There is **one Amber build**. The flag used to choose between an 18+ build and the
|
||||||
|
clean one; the 18+ section left Amber to become a separate app, and none of that
|
||||||
|
gating is left in this repo:
|
||||||
|
|
||||||
|
- `GET /api/update/manifest` (`pb_hooks/update.pb.js`) always serves variant
|
||||||
|
`clean`, whatever the flag says. The `variant` field stays in the response
|
||||||
|
because every installed Amber silently refuses a mismatch.
|
||||||
|
- The `releases` read rules no longer mention it
|
||||||
|
(`pb_migrations/1793000000_releases_drop_adult_rule.js`): any signed-in account
|
||||||
|
reads releases.
|
||||||
|
- `/api/amber/whoami` no longer returns it, and the status dashboard is gated on
|
||||||
|
superuser credentials, never on this flag.
|
||||||
|
- The Amber app neither reads nor sends it.
|
||||||
|
|
||||||
|
What remains: the field is still on `users`, still admin-only by rule, and has
|
||||||
|
exactly one reader, the family web page (`pb_public/index.html`). For an account
|
||||||
|
with the flag set, that page shows an adult addon URL field on the sources tab
|
||||||
|
(saved inside the encrypted addon config) and mentions 18+ in the child-profile
|
||||||
|
label. Nothing else reads it.
|
||||||
|
|
||||||
### Encrypted addon config (issue #20)
|
### Encrypted addon config (issue #20)
|
||||||
|
|
||||||
The `addon_config` blob is the one piece of account data that is **not** readable
|
The `addon_config` blob is the one piece of account data that is **not** readable
|
||||||
|
|
@ -131,20 +156,50 @@ nightly `trimClientLogs` cron through the superuser API and asserts none is left
|
||||||
PB_BIN=/path/to/pocketbase python scripts/test_client_logs_trim.py
|
PB_BIN=/path/to/pocketbase python scripts/test_client_logs_trim.py
|
||||||
```
|
```
|
||||||
|
|
||||||
## Deploy on Coolify
|
## Deploy
|
||||||
|
|
||||||
The schema and image are automated; the steps below need your hands, Coolify
|
Production is a Coolify "Dockerfile application" on `https://coolify.petruzalekr.cz`:
|
||||||
access and secrets (which never live in this repo).
|
app `amber-backend`, uuid `eu3wk4j0zf0uczhbew0m5c9p`, serving
|
||||||
|
`pb.petruzalekr.cz` and `amber.petruzalekr.cz` on port 8090, with a persistent
|
||||||
|
volume at `/pb_data`.
|
||||||
|
|
||||||
1. **Push this repo** to a remote Coolify can reach (e.g. GitHub, like
|
**A push does not deploy it.** Coolify's git source is
|
||||||
`myanime-pair-server`).
|
`https://projects.petruzalekr.cz/richiexec/myanime-backend.git` (the old name,
|
||||||
|
redirected to this repo), branch `main`, and nothing tells Coolify about a push.
|
||||||
|
It deploys only when someone asks: the app's **Deploy** button in Coolify, or
|
||||||
|
`GET /api/v1/deploy?uuid=eu3wk4j0zf0uczhbew0m5c9p` with the Coolify API token.
|
||||||
|
Every recorded deploy of it was such a call. Push first, then deploy; a push on
|
||||||
|
its own leaves the old build serving.
|
||||||
|
|
||||||
|
Migrations and hooks are baked into the image and apply when the new container
|
||||||
|
boots, so a schema or hook change reaches production only with a deploy.
|
||||||
|
|
||||||
|
A deploy is done when live requests show it, not when Coolify says `finished`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s https://pb.petruzalekr.cz/api/health # 200: the binary is up
|
||||||
|
curl -s -o /dev/null -w '%{http_code}\n' https://amber.petruzalekr.cz/status # 302: the hooks loaded
|
||||||
|
```
|
||||||
|
|
||||||
|
and then a request that shows the change itself. There is no commit endpoint, so
|
||||||
|
compare the commit on Coolify's deployment record with `origin/main`. How to wait
|
||||||
|
for a deploy, recover a wedged deployment queue and verify every service:
|
||||||
|
[`docs/runbooks/deploy.md` in amber-app](https://projects.petruzalekr.cz/richiexec/amber-app/src/branch/main/docs/runbooks/deploy.md).
|
||||||
|
|
||||||
|
### Setting it up from scratch
|
||||||
|
|
||||||
|
Only needed to rebuild the Coolify app. Secrets never live in this repo.
|
||||||
|
|
||||||
|
1. **Git source:** Coolify's "GitHub App" source cannot talk to Forgejo (it forces
|
||||||
|
`api.github.com`), so add the repo as a plain git source: its public HTTPS URL,
|
||||||
|
or SSH on Forgejo's port 22222.
|
||||||
2. **New Resource → Dockerfile application**, point it at this repo. It listens
|
2. **New Resource → Dockerfile application**, point it at this repo. It listens
|
||||||
on `8090`.
|
on `8090`.
|
||||||
3. **Persistent storage:** add a volume mounted at **`/pb_data`** (DB + uploaded
|
3. **Persistent storage:** add a volume mounted at **`/pb_data`** (DB + uploaded
|
||||||
files). Without this you lose data on redeploy.
|
files). Without this you lose data on redeploy.
|
||||||
4. **Domain + TLS:** set the domain to `pb.petruzalekr.cz`; Coolify/Traefik
|
4. **Domain + TLS:** set the domains to `pb.petruzalekr.cz` and
|
||||||
provisions the Let's Encrypt cert and terminates TLS in front of the plain
|
`amber.petruzalekr.cz`; Coolify/Traefik provisions the Let's Encrypt cert and
|
||||||
`:8090`. Force-HTTPS on.
|
terminates TLS in front of the plain `:8090`. Force-HTTPS on.
|
||||||
5. **Bootstrap the superuser** once, from the container terminal:
|
5. **Bootstrap the superuser** once, from the container terminal:
|
||||||
`pocketbase superuser upsert you@example.com 'a-strong-pass' --dir=/pb_data`
|
`pocketbase superuser upsert you@example.com 'a-strong-pass' --dir=/pb_data`
|
||||||
(or open the printed `/_/#/pbinstall/...` link on first boot). **Lock down**
|
(or open the printed `/_/#/pbinstall/...` link on first boot). **Lock down**
|
||||||
|
|
@ -154,10 +209,10 @@ access and secrets (which never live in this repo).
|
||||||
verification / password-reset emails send. Send the test email to confirm.
|
verification / password-reset emails send. Send the test email to confirm.
|
||||||
7. **Automated backups** (admin UI → *Settings → Backups*): enable the schedule
|
7. **Automated backups** (admin UI → *Settings → Backups*): enable the schedule
|
||||||
and, ideally, S3 off-site upload. Coolify volume backups are a second layer.
|
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
|
8. **App wiring:** the Amber app's PocketBase base URL defaults to
|
||||||
`https://pb.petruzalekr.cz`.
|
`https://pb.petruzalekr.cz` (`lib/core/config.dart` in amber-app).
|
||||||
|
|
||||||
### Verify the deploy
|
#### Verify a fresh setup
|
||||||
|
|
||||||
- Admin UI reachable over **HTTPS** only; HTTP redirects up.
|
- Admin UI reachable over **HTTPS** only; HTTP redirects up.
|
||||||
- Create a test user + profile + a couple of rows via admin or REST; confirm a
|
- Create a test user + profile + a couple of rows via admin or REST; confirm a
|
||||||
|
|
@ -174,6 +229,7 @@ never leaves the API. `nsfwEnabled` is admin-only by rule, not just by UI.
|
||||||
|
|
||||||
## Upgrading PocketBase
|
## Upgrading PocketBase
|
||||||
|
|
||||||
Bump `PB_VERSION` in the `Dockerfile` (and the compose arg), rebuild, redeploy.
|
Bump `PB_VERSION` in the `Dockerfile` (and the compose arg), then deploy
|
||||||
Check the PocketBase release notes for migration-API or schema changes first,
|
explicitly as described above (a push alone does not). Check the PocketBase
|
||||||
and test locally with `docker compose up --build` before deploying.
|
release notes for migration-API or schema changes first, and test locally with
|
||||||
|
`docker compose up --build` before deploying.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue