feat: admin articles grouped view, live stats, + bug fixes

Admin articles list:
- Group EN/DE language variants into a single row (grouped by url_path)
- Language chips (● EN/● DE) coloured by status: green=live, amber=scheduled, blue=draft
- Inline View ↗ (live only) and Edit buttons per variant — one-click access
- Filter by language switches back to flat single-row view
- Live HTMX polling of article counts while generation runs (every 3s, self-terminates)
- Table overflow fix: card gets overflow:hidden, table wrapped in overflow-x:auto scroll div

Bug fixes:
- X-Forwarded-Proto: pass $http_x_forwarded_proto through Nginx so Quart sees https
- pipeline_routes.py: fix relative import for analytics module (from .analytics → from ..analytics)
- Scheduled articles: redirect to parent path instead of 404 when not yet published
- city-cost-de: change priority_column from population to padel_venue_count
- Quote wizard step 4: make location_status required
- Article generation: use COUNT(*) instead of 501-sentinel hack for row counts
- Makefile: pin Tailwind v4.1.18, add dev/help targets, uv run python, .PHONY

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Deeman
2026-02-26 20:17:28 +01:00
parent ee488b6aca
commit 0fa2bf7c30
17 changed files with 270 additions and 335 deletions

View File

@@ -1,32 +1,58 @@
TAILWIND := ./bin/tailwindcss
TAILWIND_VERSION := v4.1.18
TAILWIND := ./bin/tailwindcss
SOPS_DOTENV := sops --input-type dotenv --output-type dotenv
.PHONY: help dev init-landing-seeds css-build css-watch \
secrets-decrypt-dev secrets-decrypt-prod \
secrets-edit-dev secrets-edit-prod
help:
@echo "Available targets:"
@echo " dev Start full dev environment (reset DB, migrate, seed, app + worker + CSS watcher)"
@echo " init-landing-seeds Create seed landing files for SQLMesh (run once after clone)"
@echo " css-build Build + minify Tailwind CSS"
@echo " css-watch Watch + rebuild Tailwind CSS"
@echo " secrets-decrypt-dev Decrypt .env.dev.sops → .env"
@echo " secrets-decrypt-prod Decrypt .env.prod.sops → .env"
@echo " secrets-edit-dev Edit .env.dev.sops in \$$EDITOR"
@echo " secrets-edit-prod Edit .env.prod.sops in \$$EDITOR"
# ── Dev environment ───────────────────────────────────────────────────────────
dev:
@./web/scripts/dev_run.sh
# ── Landing seeds ─────────────────────────────────────────────────────────────
# Create seed files for SQLMesh staging models that require at least one landing file.
# Run once after a fresh clone (data/ is gitignored so seeds are not in git).
init-landing-seeds:
@uv run python web/scripts/init_landing_seeds.py
# ── CSS ───────────────────────────────────────────────────────────────────────
bin/tailwindcss:
@mkdir -p bin
curl -sLo bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-linux-x64
curl -sLo bin/tailwindcss https://github.com/tailwindlabs/tailwindcss/releases/download/$(TAILWIND_VERSION)/tailwindcss-linux-x64
chmod +x bin/tailwindcss
# Create seed files for SQLMesh staging models that require at least one landing file.
# Run once after a fresh clone (data/ is gitignored so seeds are not in git).
init-landing-seeds:
@python3 web/scripts/init_landing_seeds.py
css-build: bin/tailwindcss
$(TAILWIND) -i web/src/padelnomics/static/css/input.css -o web/src/padelnomics/static/css/output.css --minify
css-watch: bin/tailwindcss
$(TAILWIND) -i web/src/padelnomics/static/css/input.css -o web/src/padelnomics/static/css/output.css --watch
# -- Secrets (SOPS + age) --
# ── Secrets (SOPS + age) ─────────────────────────────────────────────────────
# .env.*.sops files use dotenv format but sops can't infer from the extension,
# so we pass --input-type / --output-type explicitly.
SOPS_DOTENV := sops --input-type dotenv --output-type dotenv
secrets-decrypt-dev:
$(SOPS_DOTENV) --decrypt .env.dev.sops > .env
@echo "Decrypted .env.dev.sops → .env"
secrets-decrypt-prod:
$(SOPS_DOTENV) --decrypt .env.prod.sops > .env
@echo "Decrypted .env.prod.sops → .env"
secrets-edit-dev:
$(SOPS_DOTENV) .env.dev.sops