Admin App — QA Plan
Access control
| Step | Expected |
|---|---|
Sign in as a Clerk user without platformRole = 'admin' | Every /admin/** request returns 403; UI shows “Platform admin access required”. |
Sign in as a Clerk user with platformRole = 'admin' | Resources load. |
| Demote an admin in Clerk while they have an open session | Access persists for up to 5 minutes (Redis TTL). Confirm and document. |
Manually delete platform-admin:<clerkId> from Redis | Next request re-fetches from Clerk and reflects the new role. |
Audit trail
| Step | Expected |
|---|---|
| Reset a user’s password | audit_logs row with action = 'user.reset_password', actor_clerk_id = caller, metadata.adminAction = true. |
| Refund a payment without a reason | API rejects with 400. |
| Refund a payment with reason | audit_logs carries metadata.reason. |
| Impersonate a user | Audit row carries metadata.impersonatedUserId; PostHog admin.impersonate event captured. |
Pages — smoke
| Page | Smoke check |
|---|---|
| Organizations list | Loads paginated; filter by tier returns matching rows. |
| Organization detail | Members, subscriptions, audit recent panel render. |
| Users list | Search by email returns the right user. |
| Payments | Filter by status: failed returns failed transactions. |
| Subscriptions | Sort by next_charge_date ascending. |
| Leads | Reassign a lead to an org; status changes. |
| Jobs | Filter by status / source; retry a failed import. |
| Audit Logs | Filter by actor, by resource, by metadata.agent = true. |
| Queues | Each BullMQ queue listed; pause + resume work. |
| System | Health pings return green. |
| Costs | Daily spend chart renders; export to CSV works. |
| Billing | Org with outstanding debt shows the debt total. |
| Platform Billing | MRR + tier distribution match the platform-billing service. |
| Observability | Recent agent traces visible; click-through to PostHog deep link works. |
| Actions | ”Rebuild cache” action returns success; an audit row appears. |
| Canonical Movements | Edit a canonical exercise; change persists. |
Negative / error paths
- API returns 500 on
/admin/organizations→ admin app surfaces an Ant Design error toast with the message and a copy-trace-id action. - API returns 401 (token expired) → Clerk refreshes the token; retry succeeds.
- API returns 403 on a previously-allowed user → admin app shows “Access revoked” and routes to
/login.
Performance
- Org list page should render < 1s on a warm cache; < 3s cold.
- Queues page polls every 10s — no thundering herd against the API on tab focus.
Localization
- Admin app is English-only. No i18n. Confirm Hebrew/Russian Clerk users see English UI without breaking.
Deploy
- Vercel preview deployments must not be indexable. Robots disallow + Vercel preview password gate.
- Production domain must not be reachable from the marketing site (avoid accidental leak via internal link).