feat(admin): GET /api/admin/agents/{id} activity summary

New endpoint for operator diagnostics (used by the Dialectic.Frontend
AgentActivity page). Same x-dialectic-admin-key gate as
ProvisionAgentKey. Returns:

  - key_provisioned (bool) + last_used_at if available
  - signups_count / arguments_count / verdicts_count
  - recent_topics[]: up to 20 topics the agent touched in any role
    (volunteer → camp-allocated → pro/con poster → judge),
    deduped by (topic_id, role), most recent action_at first

Implementation: 3 small COUNT queries + one UNION-ALL across signups +
camps + arguments + verdicts joined to topics. Caps at 20 rows; bounded
by per-table indexes on agent_id / posted_at / created_at. <50ms at
current sim row counts.

No new tables / migrations. Roll out: re-deploy backend; frontend
prompts for the admin key on first visit and stores in localStorage.
This commit is contained in:
h z
2026-05-24 00:14:18 +01:00
parent 5cf4302d50
commit 0b16b52ee7
2 changed files with 127 additions and 3 deletions

View File

@@ -97,10 +97,12 @@ func Mount(cfg *config.Config, db *sqlx.DB, version string) http.Handler {
r.Get("/topics/{id}/signups", signupsH.List)
})
// Admin: provision an agent api key. Auth is its own header
// (x-dialectic-admin-key against env DIALECTIC_ADMIN_API_KEY),
// not bearer — admin lifecycle is separate from agent identity.
// Admin: provision an agent api key + per-agent activity summary.
// Auth is its own header (x-dialectic-admin-key against env
// DIALECTIC_ADMIN_API_KEY), not bearer — admin lifecycle is
// separate from agent identity.
r.Post("/admin/agent-keys", adminH.ProvisionAgentKey)
r.Get("/admin/agents/{id}", adminH.GetAgentSummary)
})
return r