Skip to content

feat(admin): safe operations, faster management and a problems-first dashboard - #51

Merged
jplacht merged 2 commits into
mainfrom
feat/admin-ops-dashboard
Sep 27, 2026
Merged

jplacht merged 2 commits into
mainfrom
feat/admin-ops-dashboard

Conversation

@jplacht

@jplacht jplacht commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Implements specs/2026-09-27-admin-ops-dashboard.md (workspace repo). Backend and admin only: no API, serializer or URL change, and there is no paired frontend PR.

What changes

Phase 1: safe

  • Bugs fixed:
    • Verification-code and snapshot search no longer 500.
    • The admin index no longer 500s when Redis is down.
    • FIO refresh uses .delay().
    • Dead code and the old KPI templates are removed.
    • The base_site.html override and the conflicting admin.site.* names are gone.
  • Destructive actions: GET-link deletes removed. "Delete all planets" is now a confirmation page, and the delete runs only on a CSRF-protected POST that carries the typed planet count.
  • Audit log: LogEntry can't be added, edited or deleted, history is on, and every custom action writes one LogEntry.
  • Secrets: the FIO key is masked (••••1234) and verification codes are never shown, including in __str__.
  • Queued work: every import, refresh and aggregate action enqueues a Celery task (gamedata_admin_import, gamedata_refresh_single_planet).
  • Read-only: FIO-sourced and derived models can't be added or edited in the admin.
  • Environment and settings: an environment badge, the admin path from ADMIN_URL, and the full brand theme ramps.
  • Stuck pending fix: a planet marked pending now holds a 1 h lease, so a dead worker no longer strands it.

Phase 2: manage

  • Grouped sidebar with command search, and a stuck-planet badge.
  • Automation admins: status labels, stuck and permanently-failed filters, and "Reset & retry".
  • User support page: badges, filters, plan and empire counts, actions, read-only inlines, and a header with FIO status.
  • User.date_joined.
  • Planning admins use autocomplete and never select JSON columns in lists or autocomplete.
  • CXPC and exchange analytics use InfinitePaginator and dropdown filters.
  • Summary strips on 8 list pages.

Phase 3: insight

  • Task health: Celery task_prerun/task_postrun receivers write per-task Redis hashes and daily counters. A Task health page shows each task as Paused, OK, Overdue or Failing, with a 14-day tracker.
  • AppStatistic: gains users_active_7d and signups.
  • Dashboard: cached for 60 s, with ?range=7|30|90|365 and ?refresh=1. Every card is isolated, so a failing card says "unavailable" instead of causing a 500. It shows:
    • health chips, each linking to exactly the rows it counts
    • headline tiles with sparklines and period change
    • engagement: active planners, plans edited, activation, shares created
    • growth and new-per-day charts
    • plans per user and feature adoption
    • top planets and top shared plans
    • task health, Postgres scoped to this database, Redis, and FIO webhooks

Deploy

  1. Run the migrations: user/0013, user/0014 (date_joined: added nullable, then given its default, so existing users are not backfilled) and analytics/0007.
  2. Restart web, worker and beat. The worker restart is needed to connect the task-health receivers.
  3. Optional env vars: ADMIN_URL (default admin/), ADMIN_AXIOM_URL (sidebar link), FRONTEND_URL ("view on site" for shared plans). Features hide when unset.

Verification

  • ruff check ✓, ruff format --check ✓, ty check ✓, pytest 499 passed (was 317), makemigrations --check: no changes.
  • e2e stack, checked in the browser:
    • All changelists return 200, plain and with search.
    • Stuck chip → exactly its rows → Reset & retry → OK, and the worker refresh ran.
    • Task health recorded by the real worker.
    • Delete-all confirmation: a GET deletes nothing.
    • With Redis stopped, the dashboard, strips and task health still return 200 and the affected cards say "unavailable".
    • No console errors.
  • Independent QA agent, two passes: PASS, all 25 acceptance criteria. The one blocking finding, a sidebar badge showing "None", is fixed and covered by a test.

Notes

  • A small override of Unfold's app_list_badge.html is needed because Unfold's lazy badge callback is always truthy.
  • Open follow-up: enable pg_stat_statements to get the slowest-queries card.

🤖 Generated with Claude Code

…dashboard

Safety: fix the admin 500s (verification code and snapshot search, Redis-down
index), drop destructive GET actions, make "Delete all planets" a typed-count
POST, make LogEntry immutable with history on, mask the FIO key and never show
verification codes, queue every import/refresh as a Celery task, make
FIO-sourced and derived models read-only, add an environment badge, the admin
path from settings and the full brand theme. Pending planets now hold a 1 h
lease, so a dead worker no longer strands them.

Management: sidebar and command search, automation status/filters and
"Reset & retry", a user support page, User.date_joined, autocomplete and no
JSON columns in planning lists, large-table pagination, and summary strips
and headers on the main pages.

Insight: task health from Celery signals (Redis), AppStatistic WAU and
signups, and a cached, fault-isolated dashboard: health chips, headline and
engagement tiles, growth and activity charts, feature adoption, top lists,
task health and infrastructure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@codacy-production

codacy-production Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 335 complexity · -4 duplication

Metric Results
Complexity 335
Duplication -4

View in Codacy

🟢 Coverage 94.38% diff coverage · +0.48% coverage variation

Metric Results
Coverage variation ✅ +0.48% coverage variation (-1.00%)
Diff coverage ✅ 94.38% diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (7207ec0) 3746 3520 93.97%
Head commit (b14f4a8) 4305 (+559) 4066 (+546) 94.45% (+0.48%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#51) 552 521 94.38%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

…ached-age assignment

Creating a user with an email queues a verification code through the user
signal; the test now patches that for its whole body, so it passes without a
reachable Celery broker (as in CI). The dashboard's cache age no longer
assigns inside a conditional expression (Codacy E0601).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jplacht
jplacht merged commit 2af4846 into main Sep 27, 2026
6 checks passed
@jplacht
jplacht deleted the feat/admin-ops-dashboard branch September 27, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant