8.0 KiB
8.0 KiB
League Admin MVP Plan (Admin Acquisition)
Goal
Finish all league-management tools needed to attract and retain league admins by making three workflows fully functional, permission-correct, and data-backed:
- Schedule builder + publishing
- Roster + join requests + roles
- Results import + standings recompute
This plan prioritizes fixing auth/permissions and API contracts first, because they block all three workflows.
What we observed (current state)
Website gaps (data + correctness)
- Schedule UI assumes a rich race object but contract is effectively
unknown[]and usesDatemethods; this is unsafe and likely to break on real API responses. - Standings page uses real standings + memberships, but fills missing stats fields with placeholders (avgFinish, penaltyPoints, bonusPoints, racesStarted).
- League settings page checks admin via a membership cache, which can falsely deny access if cache isn’t hydrated.
- Stewarding data fetch is N+1: for each race, fetch protests + penalties, which won’t scale.
- Wallet page is explicitly demo/prototype: hardcoded season/account and static breakdown data; also not admin-gated.
API gaps (permissions + contract + admin tooling)
- Actor identity is inconsistent:
- Some operations take a performer/admin ID from request data.
- Some operations hardcode an admin ID.
- Some areas infer identity from session.
- Swagger/OpenAPI generation exists in code, but the committed OpenAPI artifact is stale/empty, so it cannot serve as a reliable contract source right now.
- League schedule endpoint exists, but it does not appear to deliver a typed, UI-ready schedule contract that the website expects.
- League admin tooling endpoints exist in fragments (join requests, memberships, config, wallet, protests), but are missing end-to-end admin workflows (schedule editing/publishing, results import flows, etc.) and consistent authorization.
Definition of Done (MVP-wide)
- Every admin action is authorized server-side based on the authenticated session identity (no client-supplied performer IDs; no hardcoded admin IDs).
- Website uses stable, generated types for API DTOs; no
unknown[]schedule data. - Admin can:
- Create and publish a season schedule (add/edit/remove races).
- Manage roster and join requests (approve/reject, roles, remove members; enforce capacity).
- Import results and see standings update per season.
- Performance guardrails:
- No N+1 requests for league stewarding over races; provide aggregate endpoint(s).
- Quality gates pass in implementation phase: lint, typecheck, tests.
Gap matrix (workflow → missing pieces)
1) Auth/Permissions (cross-cutting)
Missing / must improve:
- A single canonical “actor” model (session userId vs driverId mapping).
- Consistent admin/owner authorization checks for all league write operations.
- Removal of performer IDs from all public contracts.
Dependencies:
- Session endpoint exists; need to decide how driver identity is represented in session and how it’s resolved.
Deliverable:
- A short doc describing actor model and permission rules, then code changes that enforce them.
2) Schedule builder + publishing
Missing / must improve:
- Contract: schedule DTO must be typed and use ISO strings for dates; website parses to Date in view models.
- Admin endpoints: create/update/delete schedule races, associate to season, publish/unpublish.
- UI: schedule admin interface for managing races.
- Driver registration status: schedule should reflect registration per driver without relying on ad-hoc “isRegistered” fields.
Deliverable:
- Season-aware schedule read endpoint + schedule write endpoints + website schedule editor.
3) Roster + join requests + roles
Missing / must improve:
- Join requests list exists, but approval/rejection must be permission-correct and actor-derived.
- Role changes and member removal must be actor-derived.
- UI: admin roster page (requests inbox + members list + role controls + remove).
- Capacity/status enforcement at the API layer.
Deliverable:
- A single roster admin experience that matches API rules.
4) Results import + standings recompute
Missing / must improve:
- Results import UX in website (admin flow) and stable API contract(s) for import + recompute.
- Standings should be season-aware and include fields the UI currently fakes or omits.
- Ensure penalties/protests can affect standings where applicable.
Deliverable:
- Admin results import page + standings page backed by season-aware API.
5) Stewarding
Missing / must improve:
- Aggregate league stewarding endpoint (races + protests + penalties) to avoid N+1 behavior.
- Confirm admin-only access and correct actor inference for review/apply penalty.
Deliverable:
- Single endpoint powering stewarding page, plus minimal UI updates.
6) Wallet (scope decision required)
Recommendation:
- Keep wallet “demo-only” for MVP, but make it permission-correct and remove hardcoded season/account IDs.
- Replace static breakdown sections with values derived from the wallet endpoint, or hide them behind a “coming soon” section.
Deliverable:
- Admin-only wallet access + remove hardcoded values + clearly labeled non-MVP parts.
Proposed execution plan (implementation-ready)
Phase 0 — Contract & identity foundation (must be first)
- Define the actor model:
- What the session contains (userId, driverId, roles).
- How userId maps to driverId (1:1 or indirect).
- What “league admin” means and where it’s validated.
- Update all league write endpoints to infer actor from session and enforce permissions.
- Remove any hardcoded actor IDs in services.
- Make OpenAPI generation reliable and used as contract source.
Acceptance criteria:
- No API route accepts performer/admin IDs for authorization.
- OpenAPI doc contains real paths and is regeneratable in CI/local.
Phase 1 — Normalize DTOs + website type safety
- Fix website type generation flow so generated DTOs exist and match API.
- Fix schedule DTO contract:
- Race schedule entries use ISO strings.
- Website parses and derives isPast/isUpcoming deterministically.
- Registration state is returned explicitly or derived via a separate endpoint.
Acceptance criteria:
- No schedule-related
unknowncasts remain. - Schedule page renders with real API data and correct date handling.
Phase 2 — Admin schedule management
- Implement schedule CRUD endpoints for admins (season-scoped).
- Build schedule editor UI (create/edit/delete/publish).
- Ensure driver registration still works.
Acceptance criteria:
- Admin can publish a schedule and members see it immediately.
Phase 3 — Roster and join requests
- Ensure join request approve/reject is actor-derived and permission-checked.
- Provide endpoints for roster listing, role changes, and member removal.
- Build roster admin UI.
Acceptance criteria:
- Admin can manage roster end-to-end without passing performer IDs.
Phase 4 — Results import and standings
- Implement results import endpoints and recompute trigger behavior (manual + after import).
- Make standings season-aware and include additional fields needed by the UI (or simplify UI to match real data).
- Build results import UI and update standings UI accordingly.
Acceptance criteria:
- Import updates standings deterministically and is visible in UI.
Phase 5 — Stewarding performance + wallet cleanup
- Replace N+1 stewarding fetch with aggregate endpoint; update UI to use it.
- Wallet: admin-only gating; remove hardcoded season/account; hide or compute static sections.
Acceptance criteria:
- Stewarding loads in bounded requests.
- Wallet page does not contain hardcoded season/account IDs.
Phase 6 — Quality gates
- Run lint, typecheck, and tests until clean for all changes introduced.
Key decisions / assumptions (explicit)
- “Admin acquisition” MVP includes all three workflows and therefore requires solid permissions and contracts first.
- Wallet is not a blocker for admin acquisition but must not mislead; keep demo-only unless you want it fully MVP.