170 lines
8.0 KiB
Markdown
170 lines
8.0 KiB
Markdown
# 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 uses `Date` methods; 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)
|
||
1. Every admin action is authorized server-side based on the authenticated session identity (no client-supplied performer IDs; no hardcoded admin IDs).
|
||
2. Website uses stable, generated types for API DTOs; no `unknown[]` schedule data.
|
||
3. 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.
|
||
4. Performance guardrails:
|
||
- No N+1 requests for league stewarding over races; provide aggregate endpoint(s).
|
||
5. 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 `unknown` casts 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.
|