Containerize Crate and run it on k3s, with mycelium as the sole front door via OAuth2 proof-of-tap. Crate becomes a registered OAuth client.
Auth model
- Tag scan -> mycelium
OAUTH2 mapping -> https://<host>/auth/callback?code= -> crate-auth exchanges at /oauth/token (client_secret) -> validates JWT vs cached JWKS -> mints 30-day self-signed HMAC session cookie.
- No session -> decoy HTTP 502 page; silently listens for konami -> mints same self-signed session (personal backdoor, accepted).
- Traefik forwardAuth checks only the HMAC cookie; gating is network-only (offline PWA cache intentional).
Storage
- Synology NAS over NFS -> NFS-backed PV; nginx serves
/manifest.json, /audio, /artwork read-only.
Infra
- k3s + Traefik forwardAuth + cert-manager (Let's Encrypt). Hostname templated. Images -> public ghcr, built/pushed by GH Actions. mycelium already on-cluster.
Out of scope
- mycelium code changes; AWS tooling + terraform left intact (parallel path).
Acceptance criteria
Tier: swarm:med
Containerize Crate and run it on k3s, with mycelium as the sole front door via OAuth2 proof-of-tap. Crate becomes a registered OAuth client.
Auth model
OAUTH2mapping ->https://<host>/auth/callback?code=-> crate-auth exchanges at/oauth/token(client_secret) -> validates JWT vs cached JWKS -> mints 30-day self-signed HMAC session cookie.Storage
/manifest.json,/audio,/artworkread-only.Infra
Out of scope
Acceptance criteria
docker buildworks;npm run buildruns inside; nginx servesdist/on startTier: swarm:med