# Media Streamlining Plan: Driver Avatars, Team Logos, League Logos

## Goal
Create one clean, conflict-free way to represent and deliver:

- Driver avatars (defaults now; user uploads later)
- Team logos (seeded)
- League logos (seeded)

So that:

- Seeding never produces conflicting behavior across environments.
- The UI never has to guess whether a value is a file path, an API route, a generated asset, or an uploaded asset.
- There is exactly one place that decides the final image URL for each entity.

## What exists today (inventory, by responsibility)

### Driver avatars

Where they surface:

- Driver lists, driver leaderboards, race entry lists, dashboard summaries, and social/friend UI elements.
- API payloads sometimes include an avatar URL; other times the client constructs a URL from the driver id.
- There are multiple fallback strategies: empty string, null, or client-side default image.

Where they come from:

- A “default avatar set” of three files exists in the website public assets.
- There is also a server route that can generate an avatar image for a driver id.
- Some parts of the system treat driver avatar as a user-uploadable media setting.

Observed problems:

- Mixed meaning of the avatar field: sometimes it is an absolute URL, sometimes a relative path, sometimes a server route string.
- Multiple fallbacks implemented in multiple places leads to inconsistent UI and hard-to-debug “missing image” bugs.
- Multiple “demo/fake” avatar generators exist, creating divergent behavior between environments.

### Team logos

Where they surface:

- Team cards, team leaderboards, recruiting/featured team sections.
- Sometimes the UI uses `logoUrl` from the API payload; other times it falls back to a server route based on id.

Where they come from:

- A server route can generate a team logo image for a team id.
- Seed logic also “pre-seeds” team logos by writing route strings into an in-memory store.

Observed problems:

- Team “logoUrl” may be an actual URL, or it may be a placeholder, or it may be a server route string stored as data.
- Storing route strings as if they were media values creates conflicts when routes change.
- In some persistence modes the “seeded logo store” is not truly persisted, so bootstrapping may re-trigger reseeding or create inconsistent results.

### League logos

Where they surface:

- League cards, league headers, league pages.
- UI tends to call a client-side helper that builds a league-logo URL from id.

Where they come from:

- A server route can generate a league logo image for a league id.
- Seed logic also “pre-seeds” league logos by writing route strings into an in-memory store.

Observed problems:

- Same class of conflicts as team logos.
- There is no single authoritative rule for when a league has a “real” logo versus a generated one.

## Proposed streamlined model (single canonical representation)

### Canonical concept: Media Reference (not a URL)
Instead of treating stored values as “final URLs”, define a single canonical *media reference* for each entity image.

Media reference types:

- **System default**: a fixed asset shipped with the website (driver defaults: male/female/neutral).
- **Generated**: deterministically generated from an entity id and a seeded pseudo-random source (team/league logos).
- **Uploaded**: a user-uploaded object managed by the media subsystem.
- **None**: intentionally unset.

Key rule: **only one layer resolves media references into URLs**.

### URL resolution responsibilities

- **Backend** resolves *references* into *final URLs* for API payloads.
- **Backend** also serves the image bytes for generated assets and uploaded assets.
- **Frontend** treats received URLs as ready-to-render and does not invent additional fallbacks beyond a single last-resort placeholder.

## Seeding strategy (cleanest route)

### Teams and leagues: seeded via faker, but without storing URLs

Requirement: “seed team and league logos via faker”.

Clean approach:

- During seed, assign each team/league a **Generated** media reference.
- The generator uses faker with a seed derived from the entity id to produce a deterministic “logo identity” (colors, initials, shapes, etc.).
- The stored value is **only the reference** (type + seed key), not a route string and not a URL.
- When the UI needs to show the logo, it either receives a resolved URL in the API payload or uses a single, standardized media URL builder.

Benefits:

- Deterministic results: same team id always yields the same logo.
- No conflicts when URLs/routes change.
- No need to persist binary files for seeded logos.

### Drivers: seeded from the 3 default avatar images

Requirement: “seed driver logos from these defaults” and later “normally these would be user uploads”.

Clean approach:

- During seed, assign each driver a **System default** media reference selecting one of:
  - male-default-avatar
  - female-default-avatar
  - neutral-default-avatar
- Selection is deterministic (based on driver id) so reseeding does not change faces randomly.
- Later, if a user uploads an avatar, the reference switches to **Uploaded** and overrides the default.

Benefits:

- No dependency on generated avatars for baseline.
- No ambiguous meaning of the avatar field.

## Contract rules (what the UI can rely on)

### Field semantics

- Every API payload that includes a driver/team/league image should provide a **single resolved URL field** for that image.
- Resolved URL is either:
  - a valid URL string the UI can render immediately, or
  - null (meaning: show a generic placeholder).
- Never send empty strings.
- Never send “sometimes relative file path, sometimes server route” style mixed values.

### Fallback rules

- The backend resolver must guarantee a valid URL whenever it can (system default or generated).
- The frontend uses exactly one last-resort placeholder if it receives null.
- No per-component bespoke fallbacks.

## Streamlining work items (what changes where)

### 1) Centralize media reference resolution

Create one “media resolver” concept used by:

- API payload assembly for all places that include avatars/logos.
- Image-serving routes for generated assets and uploaded assets.

This resolver is the only place that knows:

- how to map media references to a concrete image URL
- what the fallback is when no uploaded media exists

### 2) Stop storing server route strings as data

Remove the pattern where seed logic writes values like “/api/media/.../logo” into an in-memory media store.

Replace it with:

- stored media references (generated/system-default/uploaded)
- consistent URL resolution at response time

### 3) Normalize route prefixes and caching behavior

- Choose one public URL shape for these images and apply it universally.
- Add consistent cache headers for generated assets (deterministic) so the browser and CDN can cache safely.

### 4) Align frontend consumption

- Ensure the UI always prefers the resolved URL from the API payload.
- Where the UI only has an id (e.g. very lightweight list items), use a single shared “URL builder” instead of ad-hoc string concatenation.
- Remove duplicate “if missing then fallback to …” logic sprinkled across components.

### 5) Align tests and demo fakes

- Eliminate competing fake avatar/logo generators.
- Ensure all test fixtures use the same deterministic rules as seed and runtime generation.
- Ensure snapshot/contract tests treat empty string as invalid and expect null instead.

### 6) Make bootstrapping/reseeding conflict-proof

- Reseed decision should be based on durable data correctness (presence of required entities) rather than transient “in-memory media store” state.
- Ensure “missing avatar/logo” checks are aligned with the new media reference model.

### 7) Migration and cleanup

- Define how existing seeded databases are handled:
  - either a one-time cleanup that rewrites old stored values into the new reference model, or
  - a documented wipe-and-reseed path for local/dev environments.
- Ensure the migration path eliminates stored route strings.

## Mermaid: Target flow

```mermaid
flowchart TD
  UI[Website UI] --> API[API payloads include resolved image URLs]
  API --> RES[Media resolver]
  RES --> UP[Uploaded media storage]
  RES --> GEN[Deterministic generator]
  RES --> DEF[System default assets]
  GEN --> IMG[Image response with cache headers]
  UP --> IMG
  DEF --> UI
  IMG --> UI
```

## Acceptance criteria

- Driver avatars always render with one of the three defaults unless an upload exists.
- Team and league logos always render deterministically in dev/test seed, without persisting URLs.
- No API payload returns empty string for avatar/logo.
- No UI component constructs its own bespoke fallback logic.
- No bootstrapping loop caused by “missing media” when media is generated or defaults are available.

