- R11: pin requirements.txt to the versions running in the image, so a rebuild
can't pull a breaking upstream release. Documented how to upgrade.
- R12: log rotation now also prunes job_runs rows older than 90 days (nulling
the manual_imports FK reference first), so the table doesn't grow without
bound. dedup/genre candidates are review state and left alone.
- U5: credential form shows non-secret fields (URLs, usernames, prefs) as plain
text so they can be verified while typing; only real secrets stay masked.
Dashboard IP card reworded from gluetun-specific to generic "Outbound IP".
- S9: enforce ALLOWED_EMAIL at the OIDC callback, before any user row or session
is created, instead of only on later requests.
Verified: pinned build resolves; prune deletes only old rows and keeps the
manual_imports record; credentials page renders text+password inputs; a
disallowed email gets 403 with no user row, an allowed one succeeds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- settings.py: pydantic-settings config for the two mount points
(MUSIC_DATA_DIR, ALEMBIC_CONFIG_DIR), OIDC client config, encryption key path
- db.py: SQLite engine with WAL mode, plain-SQL schema migration runner
(schema/*.sql, tracked by schema_version -- not the alembic migration tool)
- models.py: SQLAlchemy ORM models matching schema/0001_init.sql
- security/crypto.py: Fernet encrypt/decrypt for the secrets table
- security/oidc.py + routers/auth.py: Pocket ID OIDC login/callback/logout
- security/deps.py: require_auth dependency (redirect-to-login on no session)
- main.py: app factory, lifespan (init_db + beets WAL enable), session
middleware, minimal dashboard route
Verified boots end-to-end via TestClient: unauthenticated GET / redirects to
/auth/login, static files serve, and all 13 schema tables get created on
first run.
Moves all ~30 pipeline scripts, configs, and the vendored sldl binary into
this repo (source /opt/sldl left untouched). Removes all docker exec/docker
compose dependencies now that beets and sldl run in-process/as a subprocess
of this container instead of via soulbeet/on-demand sldl containers.
Replaces hardcoded host paths, Navidrome credentials, and Spotify credential
sourcing with env-var-driven paths and shared credential loaders. Adds
Dockerfile, entrypoint.sh, requirements.txt, docker-compose.snippet.yml, and
the initial app DB schema.