# 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.
