Harden staging and bring GitHub/Gitea CI to parity

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
This commit is contained in:
Claude
2026-06-14 13:15:19 +00:00
parent 2c699eb976
commit 017e3a61a8
8 changed files with 230 additions and 1 deletions
+11
View File
@@ -19,6 +19,17 @@ jobs:
- name: Install dependencies
run: uv sync --frozen
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Install pnpm and JS dependencies
run: npm install -g pnpm && pnpm install --frozen-lockfile --ignore-scripts
- name: Build TypeScript
run: make ts
- name: Install Playwright browsers
run: uv run playwright install --with-deps chromium
+5
View File
@@ -19,6 +19,9 @@ jobs:
SLUG=$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/-+/-/g; s/^-//; s/-$//' | cut -c1-40)
echo "SLUG=${SLUG}" >> "$GITHUB_ENV"
echo "HOST=tracker-${SLUG}.home.arpa" >> "$GITHUB_ENV"
# Per-staging secret so each instance has its own key, decoupling it
# from prod even though the database is seeded from a prod snapshot.
echo "STAGING_SECRET_KEY=staging-${SLUG}-$(head -c16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')" >> "$GITHUB_ENV"
- name: Build image
run: docker build -t "timetracker:staging-${SLUG}" .
@@ -32,6 +35,8 @@ jobs:
-e PUID=1000 \
-e PGID=100 \
-e DATA_DIR=/home/timetracker/app/data \
-e STAGING=true \
-e "SECRET_KEY=${STAGING_SECRET_KEY}" \
-e "CSRF_TRUSTED_ORIGINS=https://${HOST}" \
-v "timetracker-staging-${SLUG}:/home/timetracker/app/data" \
-l "caddy=${HOST}" \