Introduce timetracker/config.py with a single config() helper that resolves
settings from a fixed priority chain: NAME__FILE (opt-in secret) -> env var
-> .env -> settings.ini -> in-code default. Supports type casting
(bool/list/int/Path), file-based secrets with .strip(), and required_in_prod
validation.
Migrate settings.py off the previous ad-hoc idioms:
- DEBUG via config() (PROD kept as deprecated alias)
- SECRET_KEY required in prod, supports SECRET_KEY__FILE
- APP_URL derives ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS (kept separate,
each independently overridable); ALLOWED_HOSTS is now configurable
- TZ and DATA_DIR via config()
Fix DATA_DIR inconsistency: entrypoint.sh now reads DATA_DIR (was hardcoded)
so the bash bootstrap and Django agree on the database directory.
Document the container/entrypoint-only flags (PUID/PGID/
CREATE_DEFAULT_SUPERUSER/STAGING/LOAD_SAMPLE_DATA) as bash concerns.
Update deployment configs to set APP_URL (and DEBUG), add docs/configuration.md,
settings.ini.example, regrouped .env.example, CLAUDE.md, and tests.
https://claude.ai/code/session_01FFn8BiGrQpEJarC8xGse8s
CI installed pnpm with 'npm install -g pnpm', which pulls the latest
release and ignores the pnpm@10.33.0 pin in package.json's
packageManager field. This let CI drift to a different pnpm major than
the Docker image and local dev, the exact drift Corepack prevents.
Switch both the GitHub and Gitea build workflows to 'corepack enable',
matching the Dockerfile assets stage and the documented model where
local, CI, and Docker all follow the packageManager field.
https://claude.ai/code/session_01VWXYQxUPWdhoV4otwr6Cyk
Address issue #20 and the CI divergence between Gitea and GitHub.
Issue #20 (staging seeded from a prod snapshot):
- Read SECRET_KEY from the environment with the insecure dev key as
fallback, so each deployment can have its own key.
- Add a `scrub_staging` management command that clears django_session and
the django-q schedule/queue/results, removing copied prod sessions and
the inherited convert_prices() schedule.
- Run the scrub from entrypoint.sh when STAGING=true, and wire STAGING plus
a per-branch SECRET_KEY into the Gitea staging deploy.
CI parity (both systems kept, independent):
- Add the Node/pnpm/TypeScript build steps to the Gitea build workflow to
match the GitHub test job.
- Add a GitHub staging workflow that deploys per-branch ephemeral instances
to Fly.io (*.fly.dev) with a fresh database seeded from sample fixtures
and its own SECRET_KEY, never production data. Tears the app down on
branch delete and comments the URL on the open PR via github-script.
- Add fly.staging.toml and a LOAD_SAMPLE_DATA entrypoint hook for the
fresh-database public staging.
https://claude.ai/code/session_01KYjUcNjLfZ8Hq1GAC8J4oZ
Looks up the open PR for the pushed branch via the Gitea API using the
workflow token and posts the staging URL once (skips if the same
comment already exists).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The e2e tests launch chromium, but uv sync only installs the playwright
package, not the browser binaries, so CI failed with "Executable
doesn't exist" for the headless shell.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Branch pushes deploy a per-branch staging instance at
tracker-<slug>.home.arpa via the NAS act_runner; branch deletion tears
it down. build.yml ports the GitHub CI workflow so prod image builds
keep running on Gitea now that .gitea/workflows/ exists (Gitea ignores
.github/workflows/ when it does).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>