# Frontend Architecture: Quark's Holo-Grid Ledger
> **Status**: Design Analysis — Pre-Implementation
> **Dependencies**: `reference/ENGINE.md`, `data-source/taxonomy.yaml`, `AGENTS.md`
> **Framework**: TanStack Start + TanStack Router (file-based routing)
---
## 1. Layout Topology
The application uses a fixed-viewport, three-column terminal layout defined in `__root.tsx`. The root shell is persistent — only the center column swaps content via ``.
```
┌────────────────────────────────────────────────────────────────────────────┐
│ [=] QUARK'S HOLO-GRID LEDGER // SUB-NET RECEPTOR STARDATE: 54201.3 │
│ BALANCE: 4,250.00 GPL │
├──────────────┬────────────────────────────────┬────────────────────────────┤
│ │ │ │
│ LEFT PANEL │ CENTER PANEL │ RIGHT PANEL │
│ col-span-3 │ col-span-6 │ col-span-3 │
│ │ │ │
│ Navigation │ │ Betslip │
│ Sidebar │ (route content) │ Sidecar │
│ │ │ │
│ 240px-ish │ flex-1 │ 280px-ish │
│ │ │ │
├──────────────┴────────────────────────────────┴────────────────────────────┤
│ SYSTEM RUNTIME: OK // CORE MODULES ACTIVE TANSTACK + VITE │
└────────────────────────────────────────────────────────────────────────────┘
```
### Responsive Breakpoints
```
DESKTOP (≥1280px): [col-3 Sidebar] [col-6 Main] [col-3 Betslip]
TABLET (768-1279): [col-2 Sidebar] [col-7 Main] [col-3 Betslip] (sidebar compressed)
MOBILE (<768): [Full-width Main] + bottom tab bar + slide-up betslip
```
On mobile, the sidebar collapses into a **bottom navigation bar** with 5 terminal command buttons, and the betslip becomes a pull-up sheet triggered from the bar.
```
┌────────────────────────────────────────┐
│ QUARK'S HOLO-GRID LEDGER 4,250 GPL │
├────────────────────────────────────────┤
│ │
│ MAIN CONTENT │
│ (full-width) │
│ │
│ │
├────────────────────────────────────────┤
│ GRID │ ALPHA │ BETA │ SLIP │ LEDGER │
│ ◈ │ α │ β │ ₲ │ ▤ │
└────────────────────────────────────────┘
```
---
## 2. Navigation Sidebar (Left Panel)
The sidebar is the primary navigation interface. It must feel like a hardware command console — numbered entries, hierarchical quadrant trees, and live status indicators.
### 2.1 Sidebar Sections
```
╔══════════════════════════════════╗
║ [ SYSTEM ARRAY ] Quadrants ║
╠══════════════════════════════════╣
║ ║
║ > GRID OVERVIEW [00] ║ ← Link to /
║ ║
║ ═══════════════════════════════ ║
║ > LIVE ENGAGEMENTS ║ ← Section header
║ ║
║ ▾ ALPHA QUADRANT [α] ║ ← Collapsible quadrant group
║ ├─ ◆SFC vs █BRG ●LIVE ║ ← Active match (link to /quadrants/{id})
║ │ 62% ████░░ 71% ║ ← Inline shield bars
║ ├─ ▼CRD vs ☼BAJ ●LIVE ║
║ │ 48% ███░░░ 55% ║
║ └─ ⚔KLG vs ◈ROM ○PRE ║ ← Pre-match (different indicator)
║ ║
║ ▸ BETA QUADRANT [β] ║ ← Collapsed quadrant
║ 2 active ║
║ ║
║ ▸ GAMMA QUADRANT [γ] ║
║ 1 active ║
║ ║
║ ▸ DELTA QUADRANT [δ] ║
║ 3 active ║
║ ║
║ ═══════════════════════════════ ║
║ > STATION ARCHIVES ║ ← Section header
║ ║
║ [01] Wager Ledger ║ ← Link to /ledger
║ [02] Faction Registry ║ ← Link to /registry/factions
║ [03] Venue Database ║ ← Link to /registry/venues
║ [04] Transmission Schedule ║ ← Link to /schedule
║ ║
╚══════════════════════════════════╝
```
### 2.2 Live Match Items
Each match in the sidebar should show at a glance:
- Faction glyphs and abbreviations (e.g., `◆SFC vs █BRG`)
- Match status indicator: `●LIVE` (pulsing green) / `○PRE` (amber) / `◉RES` (red)
- Compact shield capacity bars (optional, space permitting)
- Clicking navigates to `/quadrants/{sectorId}?quadrant=Alpha¤cy=Latinum`
### 2.3 Sidebar Data Source
The sidebar reads from the `sector:index:active` Valkey set via a **server function** that returns all active match summaries. It polls at the same 2s interval as match telemetry.
```tsx
// Server function: returns lightweight match summaries for sidebar
const getActiveMatchIndex = createServerFn({ method: 'GET' })
.handler(async () => {
const matchIds = await valkey.smembers('sector:index:active')
// For each match, read just the fields needed for sidebar rendering
// (id, name, quadrant, status, factions.home.abbreviation, factions.away.abbreviation,
// factions.home.shieldCapacity, factions.away.shieldCapacity)
return summaries
})
```
---
## 3. Route Map
### 3.1 File-Based Route Structure
```
src/routes/
├── __root.tsx # Shell layout (header, sidebar, betslip, footer)
├── index.tsx # Grid Overview / Dashboard
├── quadrants/
│ ├── index.tsx # Quadrant listing (all matches, filterable)
│ └── $sectorId.tsx # Live match detail (the main event page)
├── ledger/
│ ├── index.tsx # Wager Ledger overview (active + recent settled)
│ ├── active.tsx # Active/open wagers only
│ └── settled.tsx # Settled/graded wagers history
├── registry/
│ ├── factions.tsx # Faction directory (all teams)
│ ├── factions.$factionId.tsx # Faction detail (stats, form, history)
│ ├── venues.tsx # Venue directory (all sectors)
│ └── venues.$venueId.tsx # Venue detail (modifiers, match history)
└── schedule.tsx # Upcoming match schedule
```
### 3.2 Route Definitions with Validated Search Params
Every route enforces typed search params via Zod validators per AGENTS.md Rule A.
```tsx
// ─── / (Grid Overview Dashboard) ───
export const Route = createFileRoute('/')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(),
currency: z.enum(['Latinum', 'Credits']).default('Latinum'),
}),
})
// ─── /quadrants (Quadrant Match Listing) ───
export const Route = createFileRoute('/quadrants/')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(),
status: z.enum(['LIVE', 'PRE_MATCH', 'RESOLVING', 'all']).default('all'),
currency: z.enum(['Latinum', 'Credits']).default('Latinum'),
sort: z.enum(['shields', 'yield', 'newest', 'ending']).default('newest'),
}),
})
// ─── /quadrants/$sectorId (Live Match Detail) ───
export const Route = createFileRoute('/quadrants/$sectorId')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']),
currency: z.enum(['Latinum', 'Credits']).default('Latinum'),
marketCategory: z.enum(['primary', 'secondary', 'exotic', 'all']).default('all'),
}),
})
// ─── /ledger (Wager Ledger) ───
export const Route = createFileRoute('/ledger/')({
validateSearch: z.object({
status: z.enum(['active', 'settled', 'all']).default('all'),
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(),
currency: z.enum(['Latinum', 'Credits']).default('Latinum'),
page: z.number().default(1),
}),
})
// ─── /registry/factions (Faction Directory) ───
export const Route = createFileRoute('/registry/factions')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(),
type: z.enum(['aggressive', 'defensive', 'tactical', 'infiltrator', 'swarm']).optional(),
sort: z.enum(['name', 'attack', 'shield', 'evasion', 'winrate']).default('name'),
}),
})
// ─── /registry/venues (Venue Directory) ───
export const Route = createFileRoute('/registry/venues')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(),
sort: z.enum(['name', 'shield_mod', 'damage_mod', 'chaos']).default('name'),
}),
})
// ─── /schedule (Upcoming Matches) ───
export const Route = createFileRoute('/schedule')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']).optional(),
currency: z.enum(['Latinum', 'Credits']).default('Latinum'),
}),
})
```
---
## 4. Page Designs
### 4.1 Grid Overview Dashboard (`/`)
The landing page — a high-density terminal dashboard showing all active engagements at a glance.
```
┌──────────────────────────────────────────────────────────────────┐
│ [ CONSOLE TERMINAL ] Active Feeds │
├──────────────────────────────────────────────────────────────────┤
│ │
│ > SUBSPACE BROADCAST — LIVE ENGAGEMENTS ACROSS ALL QUADRANTS │
│ ════════════════════════════════════════════════════════════ │
│ │
│ ┌─── FILTER ─────────────────────────────────────────────────┐ │
│ │ [ALL] [α ALPHA] [β BETA] [γ GAMMA] [δ DELTA] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ SECTOR 001 — EARTH ORBITAL ARRAY ●LIVE α │ │
│ │ ◆ Starfleet Command 62% ████████░░░ VS │ │
│ │ █ Borg Collective 71% █████████░░ │ │
│ │ ────────────────────────────────────────────────── │ │
│ │ KY: 14.7 TW TICK: 42/90 ODDS: SFC 2.85 | BRG 1.48 │
│ │ ▸ 6 MARKETS OPEN [VIEW] → │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ THE BADLANDS — PLASMA STORM ZONE ●LIVE α │ │
│ │ ▼ Cardassian Union 48% ██████░░░░ VS │ │
│ │ ☼ Bajoran Militia 55% ███████░░░ │ │
│ │ ────────────────────────────────────────────────── │ │
│ │ KY: 8.2 TW TICK: 31/75 ODDS: CRD 2.10 | BAJ 1.72 │
│ │ ▸ 8 MARKETS OPEN [VIEW] → │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ NARENDRA III — HONOR'S EDGE ○PRE β │ │
│ │ ⚔ Klingon Empire VS │ │
│ │ ◈ Romulan Star Empire │ │
│ │ ────────────────────────────────────────────────── │ │
│ │ COMMENCING IN: 00:47 PRE-MATCH ODDS AVAILABLE │ │
│ │ ▸ 4 MARKETS OPEN [VIEW] → │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ LIVE TICKER ──────────────────────────────────────────┐ │
│ │ 14:32 Borg Adaptation triggered — Damage reduced 50% │ │
│ │ 14:30 Critical Hit! Starfleet deals 3× damage │ │
│ │ 14:28 Bajor: Prophet Intervention — Markets SUSPENDED │ │
│ │ 14:25 New match: Klingons vs Romulans @ Narendra III │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
**Key features:**
- Match summary cards with inline shield bars and headline odds
- Quadrant filter tabs (search param `?quadrant=alpha`)
- Live event ticker scrolling recent events from ALL active matches
- Pre-match cards show countdown timer instead of combat data
- Each card links to `/quadrants/$sectorId`
### 4.2 Match Detail Page (`/quadrants/$sectorId`)
The most important page — full live match view with all markets.
```
┌──────────────────────────────────────────────────────────────────┐
│ [ ENGAGEMENT MATRIX ] Wolf 359 — Memorial Perimeter │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ VERSUS ARENA ────────────────────────────────────────────┐ │
│ │ │ │
│ │ ◆ STARFLEET COMMAND █ BORG COLLECTIVE │ │
│ │ [SFC] [BRG] │ │
│ │ │ │
│ │ SHIELDS 62% ████████░░░ 71% █████████░░ SHIELDS │ │
│ │ ATTACK 58 99 ATTACK │ │
│ │ EVASION 40 12 EVASION │ │
│ │ │ │
│ │ ─────────── ✦ VS ✦ ────────── │ │
│ │ │ │
│ │ KINETIC YIELD: 14.7 TW TICK: 42 / 90 │ │
│ │ VENUE: Wolf 359 [debris-field, high-anomaly] │ │
│ │ SHIELD MOD: 0.95 DMG MOD: 1.10 EVA MOD: 0.80 │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ ACTIVE EFFECTS ──────────────────────────────────────────┐ │
│ │ ⚡ BORG ADAPTATION (BRG) — Incoming damage ×0.5 [3/5] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ FILTER ───────────────────────────────────────────────────┐ │
│ │ [ALL] [PRIMARY] [SECONDARY] [EXOTIC] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ MARKETS ─────────────────────────────────────────────────┐ │
│ │ │ │
│ │ COMBAT RESOLUTION — MONEYLINE [primary] │ │
│ │ ┌──────────────────────────┬───────────────────────────┐ │ │
│ │ │ ◆ Starfleet Victory │ █ Borg Assimilation │ │ │
│ │ │ [2.85] ▲ │ [1.48] ▼ │ │ │
│ │ └──────────────────────────┴───────────────────────────┘ │ │
│ │ │ │
│ │ FIRST SHIELD BREACH [primary] │ │
│ │ ┌──────────────────────────┬───────────────────────────┐ │ │
│ │ │ ◆ SFC Shields First │ █ BRG Shields First │ │ │
│ │ │ [1.65] ▼ │ [2.20] ▲ │ │ │
│ │ └──────────────────────────┴───────────────────────────┘ │ │
│ │ │ │
│ │ TOTAL KINETIC YIELD [primary] │ │
│ │ ┌──────────────────────────┬───────────────────────────┐ │ │
│ │ │ Over 8.5 TW │ Under 8.5 TW │ │ │
│ │ │ [1.35] ▼ │ [3.10] ▲ │ │ │
│ │ └──────────────────────────┴───────────────────────────┘ │ │
│ │ │ │
│ │ COMEBACK VICTORY [exotic] │ │
│ │ ┌──────────────────────────┬───────────────────────────┐ │ │
│ │ │ ◆ SFC 30+ Comeback │ █ BRG 30+ Comeback │ │ │
│ │ │ [5.50] │ [8.20] ▲ │ │ │
│ │ └──────────────────────────┴───────────────────────────┘ │ │
│ │ │ │
│ │ MUTUAL DESTRUCTION [exotic] │ │
│ │ ┌──────────────────────────┬───────────────────────────┐ │ │
│ │ │ Both Shields 0% │ Survivor │ │ │
│ │ │ [12.00] │ [1.05] │ │ │
│ │ └──────────────────────────┴───────────────────────────┘ │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ ENGAGEMENT LOG ──────────────────────────────────────────┐ │
│ │ [T42] ◆ Starfleet fires — HIT — 4.2% shield damage │ │
│ │ [T42] █ Borg fires — MISS — Evasion successful │ │
│ │ [T38] ⚡ EVENT: Borg Adaptation — Incoming dmg ×0.5 │ │
│ │ [T35] ◆ Starfleet fires — CRIT — 12.6% shield damage │ │
│ │ [T31] 🌀 EVENT: Debris Impact — BRG shields -12% │ │
│ │ [T28] █ Borg fires — HIT — 6.1% shield damage │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
**Key features:**
- Versus arena header with full faction stats, shield bars, and active effects
- Venue modifier display (so bettors understand the environment)
- Market category filter tabs (search param `?marketCategory=primary`)
- Each market selection is a clickable button that adds to betslip
- Price trend indicators (▲ up / ▼ down) with color coding
- Engagement log showing tick-by-tick combat events
- Market suspension overlay when `SUBSPACE INTERRUPTION` event fires
### 4.3 Betslip Sidecar (Right Panel — always visible)
The betslip is NOT a route — it's a persistent panel in the root layout, managed via React context or a lightweight client store.
```
╔══════════════════════════════════╗
║ [ WAGER SLIP ] Secure Link ║
╠══════════════════════════════════╣
║ ║
║ SELECTIONS (2) ║
║ ════════════════════════════ ║
║ ║
║ ┌────────────────────────────┐ ║
║ │ Wolf 359 — SFC vs BRG │ ║
║ │ ◆ Starfleet Victory │ ║
║ │ [2.85] [×] │ ║
║ │ STAKE: [___25.00___] GPL │ ║
║ │ RETURN: 71.25 GPL │ ║
║ └────────────────────────────┘ ║
║ ║
║ ┌────────────────────────────┐ ║
║ │ Badlands — CRD vs BAJ │ ║
║ │ Over 8.5 Terawatts │ ║
║ │ [1.85] [×] │ ║
║ │ STAKE: [___10.00___] GPL │ ║
║ │ RETURN: 18.50 GPL │ ║
║ └────────────────────────────┘ ║
║ ║
║ ═══════════════════════════════ ║
║ SINGLES TOTAL STAKE: 35.00 ║
║ POTENTIAL RETURN: 89.75 ║
║ ║
║ ─── ACCUMULATOR ────────────── ║
║ COMBINED ODDS: [5.27] ║
║ ACCA STAKE: [________] GPL ║
║ ACCA RETURN: 0.00 GPL ║
║ ║
║ ═══════════════════════════════ ║
║ ║
║ ┌────────────────────────────┐ ║
║ │ ▶ TRANSMIT WAGER ◀ │ ║
║ │ Rule of Acquisition #62 │ ║
║ └────────────────────────────┘ ║
║ ║
║ ─── RECENT TRANSMISSIONS ───── ║
║ ✓ SFC Victory @ 2.40 +36.00 ║
║ ✗ Over 8.5 TW @ 1.85 -10.00 ║
║ ○ BRG Victory @ 1.48 PENDING ║
║ ║
╚══════════════════════════════════╝
```
**Key features:**
- Selections added by clicking market buttons on any match page
- Individual stake inputs per selection (singles)
- Accumulator option with combined odds
- Live price updates — if odds change while in betslip, show old→new with flash
- Odds lock warning if price moves significantly
- Recent bet results at the bottom
- Persistent across route changes (React context, not URL state)
### 4.4 Wager Ledger (`/ledger`)
```
┌──────────────────────────────────────────────────────────────────┐
│ [ WAGER LEDGER ] Transaction Archive │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ FILTER ───────────────────────────────────────────────────┐ │
│ │ [ALL] [ACTIVE] [SETTLED] Quadrant: [ALL ▾] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ ACCOUNT SUMMARY ─────────────────────────────────────────┐ │
│ │ BALANCE: 4,250.00 GPL ACTIVE RISK: 285.00 GPL │ │
│ │ SESSION P/L: +127.50 GPL ▲ │ │
│ │ WIN RATE: 58% (14/24) AVG ODDS: 2.15 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ─── ACTIVE WAGERS ──────────────────────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ #W-0042 Wolf 359 — SFC vs BRG ●LIVE α │ │
│ │ Selection: ◆ Starfleet Victory │ │
│ │ Odds Taken: 2.85 Stake: 25.00 GPL │ │
│ │ Current Odds: 3.10 Potential: 71.25 GPL │ │
│ │ Status: OPEN — Shields: SFC 62% | BRG 71% │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ─── SETTLED WAGERS ─────────────────────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ #W-0039 Qo'noS Arena — KLG vs GRN ✓ WON β │ │
│ │ Selection: ⚔ Klingon Victory │ │
│ │ Odds: 1.65 Stake: 30.00 Return: 49.50 GPL +19.50 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ #W-0037 Badlands — CRD vs BAJ ✗ LOST α │ │
│ │ Selection: Over 8.5 TW │ │
│ │ Odds: 1.85 Stake: 10.00 Return: 0.00 GPL -10.00 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
### 4.5 Faction Registry (`/registry/factions`)
```
┌──────────────────────────────────────────────────────────────────┐
│ [ FACTION REGISTRY ] Combatant Database │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ FILTER ───────────────────────────────────────────────────┐ │
│ │ Quadrant: [ALL ▾] Type: [ALL ▾] Sort: [NAME ▾] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ GLYPH FACTION QDR TYPE SHD ATK EVA │
│ ═════ ═══════════════════ ═══ ═══════════ ═══ ═══ ═══ │
│ ◆ Starfleet Command α defensive 92 65 50 │
│ █ Borg Collective δ swarm 95 90 15 │
│ ⚔ Klingon Empire β aggressive 60 95 35 │
│ ◈ Romulan Star Empire β infiltrator 72 70 85 │
│ ◉ The Dominion γ swarm 75 88 40 │
│ ∞ Species 8472 δ aggressive 99 99 70 │
│ ... │
│ │
│ Click a faction row to view detailed profile → │
│ │
└──────────────────────────────────────────────────────────────────┘
```
Clicking a faction row navigates to `/registry/factions/$factionId`, which shows:
- Full tactical profile text
- Rivalry modifiers table
- Active matches this faction is in
- Recent match history (W/L record)
- Type advantage breakdown
### 4.6 Venue Database (`/registry/venues`)
```
┌──────────────────────────────────────────────────────────────────┐
│ [ VENUE DATABASE ] Sector Pool Registry │
├──────────────────────────────────────────────────────────────────┤
│ │
│ VENUE QDR SHD× DMG× EVA× ANOMALY │
│ ═══════════════════════ ════ ═════ ═════ ═════ ════════ │
│ Fluidic Space Rift δ 0.60 1.50 0.80 35% !!! │
│ The Badlands α 0.70 1.30 0.60 35% !!! │
│ Founders' Approach γ 0.85 1.10 0.60 40% !!! │
│ Qo'noS Arena β 0.80 1.25 0.95 8% │
│ Vulcan Defense Grid α 1.20 0.85 1.00 3% │
│ Nekrit Expanse δ 1.00 1.00 1.00 1% │
│ ... │
│ │
└──────────────────────────────────────────────────────────────────┘
```
### 4.7 Match Schedule (`/schedule`)
```
┌──────────────────────────────────────────────────────────────────┐
│ [ TRANSMISSION SCHEDULE ] Upcoming Engagements │
├──────────────────────────────────────────────────────────────────┤
│ │
│ ─── SCHEDULED (starting soon) ──────────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ T-47s Narendra III — Honor's Edge [β] │ │
│ │ ⚔ Klingon Empire vs ◈ Romulan Star Empire │ │
│ │ Rivalry: 1.30 — MARQUEE MATCHUP │ │
│ │ Pre-match odds available at T-60s │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ T-2m Gornar Orbit — Hegemony Arena [β] │ │
│ │ ▲ Gorn Hegemony vs ⊘ Orion Syndicate │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ─── RECENTLY SETTLED ───────────────────────────────────────── │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ SETTLED Vulcan Grid — T'Khasi Defense Grid [α] │ │
│ │ ◆ Starfleet Command 68% vs ₲ Ferengi 0% │ │
│ │ RESULT: Starfleet Victory — 72 ticks │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────┘
```
---
## 5. Component Architecture
Per AGENTS.md, route files contain only configuration. All visual markup lives in components.
### 5.1 Component Map
```
src/components/
├── ascii/ # Low-level visual primitives
│ ├── AsciiPanel.tsx # Bordered panel container (EXISTS)
│ ├── ShieldBar.tsx # Horizontal shield capacity bar
│ ├── PriceTag.tsx # Odds display with trend indicator
│ ├── StatusBadge.tsx # LIVE/PRE/RESOLVING/SETTLED indicator
│ ├── TerminalLine.tsx # Decorative separator line
│ ├── BlinkingCursor.tsx # Animated cursor for loading states
│ ├── TickProgress.tsx # Match progress bar (tick X / maxTicks)
│ └── GlyphIcon.tsx # Faction glyph renderer with color
│
├── panels/ # Domain feature views (large composites)
│ ├── NavigationMenu.tsx # Left sidebar navigation (EXISTS)
│ ├── BetslipSidecar.tsx # Right sidebar betslip
│ ├── MatchCard.tsx # Summary card for dashboard grid
│ ├── VersusArena.tsx # Full faction-vs-faction header
│ ├── MarketGrid.tsx # All markets for a match
│ ├── MarketSelection.tsx # Single clickable odds button
│ ├── EngagementLog.tsx # Scrolling event log for a match
│ ├── LiveTicker.tsx # Global event feed (dashboard)
│ ├── FactionTable.tsx # Sortable faction directory table
│ ├── VenueTable.tsx # Sortable venue directory table
│ ├── FactionProfile.tsx # Detailed faction stats view
│ ├── WagerCard.tsx # Single bet display (active or settled)
│ ├── AccountSummary.tsx # Balance, P/L, win rate stats
│ ├── ScheduleCard.tsx # Upcoming/settled match card
│ └── QuadrantFilterBar.tsx # Reusable quadrant filter tabs
│
└── providers/ # Client state providers
├── BetslipProvider.tsx # Betslip selection state (React Context)
└── CurrencyProvider.tsx # Active currency preference
```
### 5.2 Route → Component Mapping
Routes stay thin (AGENTS.md compliance). Heavy rendering delegates to panel components.
```tsx
// src/routes/quadrants/$sectorId.tsx — THIN ROUTE FILE
export const Route = createFileRoute('/quadrants/$sectorId')({
validateSearch: z.object({
quadrant: z.enum(['alpha', 'beta', 'gamma', 'delta']),
currency: z.enum(['Latinum', 'Credits']).default('Latinum'),
marketCategory: z.enum(['primary', 'secondary', 'exotic', 'all']).default('all'),
}),
loader: async ({ params }) => {
const snapshot = await getCachedSectorData({ input: params.sectorId })
return { snapshot }
},
component: MatchDetailView, // ← delegates to panel
})
// The actual MatchDetailView component lives in src/components/panels/
// It composes: VersusArena + MarketGrid + EngagementLog
```
---
## 6. Data Flow & Server Functions
### 6.1 Server Function Registry
```
src/server/
├── db/
│ └── valkeyConnector.ts # Valkey client instance
└── functions/
├── getActiveMatchIndex.ts # All active match summaries (sidebar)
├── getMatchTelemetry.ts # Full match state for detail page
├── getUpcomingSchedule.ts # Scheduled matches
├── getSettledMatches.ts # Recently settled results
├── getFactionRegistry.ts # Static faction data from taxonomy
├── getVenueRegistry.ts # Static venue data from taxonomy
└── submitWager.ts # Place a bet (write to Valkey)
```
### 6.2 Polling Strategy
| Data | Interval | Source | Route |
|------|----------|--------|-------|
| Active match index (sidebar) | 2s | `sector:index:active` | `__root.tsx` (always) |
| Match telemetry (detail page) | 2s | `sector:telemetry:{id}` | `/quadrants/$sectorId` |
| Match events (detail page) | 2s | `sector:events:{id}` | `/quadrants/$sectorId` |
| Dashboard match cards | 2s | All active telemetry | `/` |
| Schedule | 10s | `sector:schedule:upcoming` | `/schedule` |
| Faction/venue registry | Static | `taxonomy.yaml` (cached) | `/registry/*` |
| Betslip price updates | 2s | Individual market keys | `BetslipSidecar` |
### 6.3 SSR + Client Hydration Pattern
```tsx
// Pattern for all live data routes:
// 1. Loader runs on server — fetches initial snapshot from Valkey
loader: async ({ params }) => {
return await getCachedSectorData({ input: params.sectorId })
},
// 2. Component hydrates with loader data, then starts client polling
function MatchDetailView() {
const initialData = Route.useLoaderData()
const { data } = useQuery({
queryKey: ['telemetry', sectorId],
queryFn: () => getCachedSectorData({ input: sectorId }),
initialData, // SSR data used immediately
refetchInterval: 2000, // Client polls every 2s after hydration
})
}
```
---
## 7. Client State Management
Only two pieces of state live on the client (not URL, not server):
### 7.1 Betslip State (React Context)
```tsx
interface BetslipSelection {
matchId: string
matchName: string
marketId: string
selectionName: string
price: number // Price when added
currentPrice: number // Live price (updated by polling)
stake: number // User-entered stake
factionGlyph: string
}
interface BetslipState {
selections: BetslipSelection[]
addSelection: (sel: BetslipSelection) => void
removeSelection: (marketId: string) => void
updateStake: (marketId: string, stake: number) => void
clearAll: () => void
accumulatorStake: number
setAccumulatorStake: (stake: number) => void
}
```
### 7.2 Currency Preference
Currency is tracked in URL search params (`?currency=Latinum`) per AGENTS.md deterministic URL state rule — NOT in client state. The `CurrencyProvider` simply reads from the URL.
---
## 8. Route Transition Map
```mermaid
graph TD
ROOT["__root.tsx
(always rendered)"]
DASH["/ Dashboard
Grid Overview"]
QUAD_LIST["/quadrants
Filtered Match List"]
MATCH["/quadrants/$sectorId
Live Match Detail"]
LEDGER["/ledger
Wager Overview"]
ACTIVE["/ledger/active
Open Wagers"]
SETTLED["/ledger/settled
Settled History"]
FACTIONS["/registry/factions
All Factions"]
FACTION_D["/registry/factions/$id
Faction Profile"]
VENUES["/registry/venues
All Venues"]
VENUE_D["/registry/venues/$id
Venue Profile"]
SCHED["/schedule
Upcoming Matches"]
ROOT --> DASH
ROOT --> QUAD_LIST
ROOT --> MATCH
ROOT --> LEDGER
ROOT --> SCHED
ROOT --> FACTIONS
ROOT --> VENUES
DASH -->|"click match card"| MATCH
QUAD_LIST -->|"click match"| MATCH
SCHED -->|"click scheduled"| MATCH
LEDGER --> ACTIVE
LEDGER --> SETTLED
ACTIVE -->|"click match ref"| MATCH
FACTIONS --> FACTION_D
FACTION_D -->|"click active match"| MATCH
VENUES --> VENUE_D
VENUE_D -->|"click active match"| MATCH
MATCH -->|"click market selection"| BETSLIP["Betslip (context, not route)"]
style MATCH fill:#34d399,color:#000
style BETSLIP fill:#fbbf24,color:#000
style DASH fill:#38bdf8,color:#000
```