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