Skip to content

Raccoon Rocket Lab Architecture

This document describes the technical architecture of the Raccoon Rocket Lab sandbox application, a full-stack TypeScript project demonstrating modern development patterns with comprehensive testing and analysis tooling.

Overview

Raccoon Rocket Lab is a rocket flight simulator where users design rockets, launch them, and compete for high scores on a leaderboard. The application showcases patterns suitable for agentic software engineering workflows.

flowchart TB
    subgraph Client["Client (React 19)"]
        UI[UI Components]
        Hooks[Custom Hooks]
        Query[TanStack Query]
        Physics[Physics Simulation]
    end

    subgraph Server["Server (Hono)"]
        Routes[API Routes]
        Store[Store Layer]
        Validation[Zod Validation]
    end

    subgraph Database["SQLite"]
        Rockets[(rockets)]
        Flights[(flights)]
    end

    subgraph Shared["Shared Package"]
        Types[TypeScript Types]
        Schemas[Zod Schemas]
    end

    Client -->|HTTP /api/*| Server
    Server --> Database
    Client --> Shared
    Server --> Shared

Technology Stack

Layer Technology Version Purpose
Runtime Bun 1.3.7 Package manager, runtime, bundler
Frontend React 19.2.4 UI framework
Build Tool Vite 7.3.1 Dev server, production bundler
Data Fetching TanStack Query 5.90.20 Server state management
Backend Hono 4.11.7 Web framework
Validation Zod 4.3.6 Schema validation
Database SQLite Native Persistent storage
Unit Testing Vitest 4.0.18 Test runner
E2E Testing Playwright 1.58.0 Browser automation
Mutation Testing Stryker 9.4.0 Test quality analysis
Linting Biome 2.3.13 Formatting and linting
Dead Code Knip 5.82.1 Unused code detection
Orchestration Turborepo 2.7.6 Monorepo task runner

Additional Runtime Dependencies

Package Version Purpose
@hono/zod-validator ^0.7.6 Hono middleware for Zod schema validation
@tanstack/react-query-devtools ^5.91.2 Query debugging and inspection tools
@testing-library/react - React component testing utilities
@testing-library/dom - DOM testing utilities

Monorepo Structure

The project uses Turborepo with Bun workspaces for monorepo management.

flowchart TB
    subgraph Root["raccoon-rocket-lab/"]
        pkg[package.json]
        turbo[turbo.json]
        tsconfig[tsconfig.base.json]
    end

    subgraph Apps["apps/"]
        client["client/"]
        server["server/"]
    end

    subgraph Packages["packages/"]
        shared["shared/"]
    end

    Root --> Apps
    Root --> Packages

    client -->|workspace:*| shared
    server -->|workspace:*| shared

Directory Layout

sandbox/raccoon-rocket-lab/
├── apps/
│   ├── client/              # React frontend
│   │   ├── src/
│   │   │   ├── components/  # UI components
│   │   │   ├── hooks/       # State management
│   │   │   ├── lib/         # Utilities
│   │   │   ├── queries/     # TanStack Query configs
│   │   │   └── styles/      # CSS and styling
│   │   └── tests/
│   │       ├── e2e/         # End-to-end tests
│   │       ├── unit/        # Unit tests
│   │       └── infrastructure/  # Client infrastructure tests
│   └── server/              # Hono backend
│       └── src/
│           └── routes/      # API endpoints
├── packages/
│   └── shared/              # Shared types and schemas
├── specs/                   # Requirements and feature specifications
│   ├── requirements/        # Project requirements
│   └── features/            # Feature specifications
├── tests/                   # Root-level infrastructure tests
│   └── infrastructure/
│       ├── biome/           # Linting infrastructure tests
│       ├── deadcode/        # Dead code analysis tests
│       └── integration/     # Cross-package integration tests
├── turbo.json               # Build pipeline config
├── biome.json               # Linting config
├── knip.json                # Dead code config
└── Makefile                 # Development commands

Client Architecture

Component Hierarchy

The application has three main component groups:

flowchart TD
    App["App.tsx"]

    App --> RD["RocketDesigner"]
    App --> MC["MissionControl"]
    App --> LB["Leaderboard"]

    RD --> RP["RocketPreview"]
    RD --> SI["StabilityIndicator"]

    MC --> FV["FlightView"]
    MC --> SB["Scoreboard"]

Design Phase Components:

Component Purpose
RocketDesigner Main design interface with parameter controls
RocketPreview Visual rocket rendering
StabilityIndicator Shows stability rating
ParameterSlider Adjusts numeric values
ToggleButton Selects nose cone type

Flight Phase Components:

Component Purpose
MissionControl Flight observation container
ObservationWindow Viewport for flight animation
RaccoonCharacter Animated mascot
LaunchPad Countdown display
FlightView Flight trajectory visualization
Scoreboard Final score display

Unified View Pattern:

The UnifiedRocketView.tsx component consolidates both design and mission views into a single component, managing the transition between rocket design and flight observation phases. This pattern reduces code duplication and provides a consistent user experience across application states.

State Management

The client uses a combination of local React state and TanStack Query:

  • Local State - Rocket design parameters, flight simulation state
  • Server State - Leaderboard data via TanStack Query

Custom hooks encapsulate state logic:

Hook Purpose
useRocketDesign Manages rocket parameter state
useFlight Controls flight simulation lifecycle

Key Libraries

src/lib/
├── api.ts          # Fetch-based API client
├── queryClient.ts  # TanStack Query configuration
├── physics.ts      # Flight physics simulation
├── trajectory.ts   # Animation frame interpolation
├── stability.ts    # Stability calculations
└── scoring.ts      # Score computation

Server Architecture

API Endpoints

Method Endpoint Description
GET /api/health Server health check
POST /api/rockets Create rocket design
GET /api/rockets/:id Get specific rocket
GET /api/rockets List recent rockets
POST /api/flights Record flight result
GET /api/flights List recent flights
GET /api/leaderboard Get top scores

Database Schema

erDiagram
    rockets {
        text id PK "UUID"
        text name "nullable"
        real finSize
        integer finCount
        real fuelAmount
        text noseCone "pointed|rounded|blunt"
        real bodyDiameter
        real parachuteSize
        text createdAt "ISO timestamp"
        text updatedAt "ISO timestamp"
    }

    flights {
        text id PK "UUID"
        text rocketId FK
        text launchDate "ISO timestamp"
        real maxAltitude
        real maxVelocity
        real flightDuration
        text phases "JSON array"
        integer success "0|1"
        text notes "nullable"
        real score "nullable"
    }

    rockets ||--o{ flights : "has"

Store Layer

The store layer (src/store.ts) provides data access functions:

  • Pure functions for CRUD operations
  • SQLite prepared statements with parameter binding
  • Date serialization as ISO strings
  • JSON serialization for nested data (flight phases)

Shared Package

The shared package (packages/shared/) defines the contract between client and server.

Types

type NoseCone = "pointed" | "rounded" | "blunt"

type FlightPhase =
  | "pre-launch" | "ignition" | "powered-ascent"
  | "coast" | "apogee" | "descent" | "recovery"

interface RocketDesignInput {
  name?: string
  finSize: number
  finCount: number
  fuelAmount: number
  noseCone: NoseCone
  bodyDiameter: number
  parachuteSize: number
}

interface RocketDesign extends RocketDesignInput {
  id: string
  createdAt: string
  updatedAt: string
}

interface FlightResult {
  id: string
  rocketId: string
  launchDate: string
  maxAltitude: number
  maxVelocity: number
  flightDuration: number
  phases: FlightPhaseEvent[]
  success: boolean
  notes?: string
  score?: number
}

Zod Schemas

Zod schemas mirror the types for runtime validation on both client and server.

Data Flow

The client communicates with the server through a Vite proxy that forwards /api/* requests.

flowchart LR
    subgraph Browser
        Client["React App"]
    end

    subgraph Backend
        Server["Hono API"]
        DB[("SQLite")]
    end

    Client -->|"POST /api/rockets"| Server
    Client -->|"POST /api/flights"| Server
    Client -->|"GET /api/leaderboard"| Server
    Server <--> DB

Request Flow

  1. Design Phase - User adjusts rocket parameters, client calculates stability locally
  2. Launch Phase - Client runs physics simulation locally, generates flight data
  3. Save Rocket - POST /api/rockets with design parameters, server validates with Zod
  4. Save Flight - POST /api/flights with simulation results
  5. Leaderboard - GET /api/leaderboard fetches top scores via TanStack Query

Vite Proxy Configuration

The client proxies API requests to the backend. Environment variables provide flexibility for distributed deployments:

// vite.config.ts
export default defineConfig({
  server: {
    host: process.env.HOST || '0.0.0.0',
    port: parseInt(process.env.PORT || '35806'),
    proxy: {
      '/api': {
        target: process.env.VITE_API_PROXY_TARGET || 'http://localhost:35800',
        changeOrigin: true
      }
    }
  }
})
Environment Variable Default Purpose
HOST 0.0.0.0 Dev server bind address
PORT 35806 Dev server port
VITE_API_PROXY_TARGET http://localhost:35800 Backend API URL for proxy
PLAYWRIGHT_BASE_URL http://127.0.0.1:35806 E2E test target URL

Flight Simulation

State Machine

stateDiagram-v2
    [*] --> PreLaunch: Initialize
    PreLaunch --> Ignition: Start countdown
    Ignition --> PoweredAscent: Engine ignites
    PoweredAscent --> Coast: Fuel depleted
    Coast --> Apogee: Velocity = 0
    Apogee --> Descent: Gravity takes over
    Descent --> Recovery: Parachute deploys
    Recovery --> [*]: Landing

    note right of PoweredAscent: Thrust follows bell curve
    note right of Descent: Drag based on nose cone

Physics Engine

The physics simulation (src/lib/physics.ts) models:

Parameter Formula/Value
Gravity 9.81 m/s^2
Time step 0.1 seconds
Thrust curve Bell-shaped (sine wave)
Drag coefficient Pointed: 0.3, Rounded: 0.5, Blunt: 0.8

Stability Calculation

stability = 2 * (finSize/10) * (finCount/3) + 0.5 - (bodyDiameter-2)/3
Range Rating
< 1.0 Unstable
1.0 - 2.0 Stable
> 2.0 Overstable

Scoring System

Category Points Criteria
Altitude 0-50 Normalized to 2000m reference
Stability 0-25 Stable: 25, Overstable: 15, Unstable: 0
Landing 0-25 Penalty for high landing speed
Total 0-100

Testing Infrastructure

Unit Tests (Vitest)

Configuration in vitest.config.ts:

  • Environment: jsdom
  • Test patterns: src/**/*.{test,spec}.ts(x), tests/**/*.{test,spec}.ts(x)
  • Global assertions enabled
  • Setup file: tests/setup.ts
  • Infrastructure tests included from tests/infrastructure/
bun run test         # Run tests
bun run test:watch   # Watch mode

Infrastructure Tests

Root-level infrastructure tests validate tooling and cross-package integration:

Category Location Purpose
Biome tests/infrastructure/biome/ Linting configuration validation
Dead Code tests/infrastructure/deadcode/ Knip configuration validation
Integration tests/infrastructure/integration/ Cross-package dependency checks

E2E Tests (Playwright)

Configuration in playwright.config.ts:

  • Browser: Chromium
  • Test directory: tests/e2e
  • Base URL: http://127.0.0.1:35806 (configurable via PLAYWRIGHT_BASE_URL)
  • Automatic dev server startup (CI-aware with reuseExistingServer)
  • Trace retention on test failure for debugging
bun run test:e2e     # Run E2E tests

Mutation Testing (Stryker)

Configuration in stryker.config.mjs:

  • Mutates: src/lib/*.ts, src/hooks/useFlight.ts
  • Test runner: Vitest
  • Thresholds: High 80%, Low 60%, Break 64%
make mutation        # Run mutation testing

Reports generated at reports/mutation/mutation.html.

Static Analysis

Biome

Configuration in biome.json:

Setting Value
Indent 2 spaces
Line width 100 characters
Quotes Double
Semicolons Always
Trailing commas Yes
bun run lint         # Check issues
bun run lint:fix     # Auto-fix

Knip

Configuration in knip.json:

Detects unused:

  • Imports and exports
  • Dependencies
  • Files
make deadcode        # Run dead code analysis

Build System

Turborepo Pipeline

flowchart LR
    subgraph Build["build"]
        SB[shared:build]
        CB[client:build]
        SVB[server:build]
    end

    subgraph Test["test"]
        CT[client:test]
        SVT[server:test]
    end

    subgraph Lint["lint"]
        L[All workspaces]
    end

    SB --> CB
    SB --> SVB
    SB --> CT
    SB --> SVT
    SB --> L

Task definitions in turbo.json:

Task Dependencies Cache
build ^build Yes
dev - No (persistent)
test ^build Yes
lint ^build Yes
test:mutation ^build Yes
deadcode - Yes

Outputs

Build artifacts:

  • dist/** - Compiled JavaScript
  • TypeScript declarations (.d.ts)
  • Source maps

Docker Configuration

Development Containers

Service Port Image
client 35806 oven/bun:1.3
server 35800 oven/bun:1.3
playwright - mcr.microsoft.com/playwright

Health Checks

Services include health check configurations for orchestration reliability:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:35800/api/health"]
  interval: 5s
  timeout: 3s
  retries: 5

Test Environment

The docker-compose.test.yml orchestrates E2E testing:

  1. Server starts and exposes health endpoint
  2. Client waits for server health check (using depends_on with condition)
  3. Playwright container runs tests against client

Development Commands

From Repository Root

Command Description
make web Start client and server
make web-down Stop servers
make web-status Check if running
make test Run all tests
make mutation Run Stryker
make deadcode Run Knip

From sandbox/raccoon-rocket-lab/

Command Description
bun run dev Start dev servers
bun run build Build all packages
bun run test Run Vitest
bun run lint Run Biome
bun run test:e2e Run Playwright