Skip to content

Architecture

System Overview

graph TB
    subgraph "Cloudflare"
        CF_DNS[DNS + Proxy]
    end

    subgraph "Clerk"
        CLERK[Clerk Auth<br/>JWT Issuance]
    end

    subgraph "AWS eu-west-2"
        subgraph "CloudFront CDN"
            WEB_CF[Web CDN]
            ADMIN_CF[Admin CDN]
        end

        subgraph "API Gateway"
            APIGW[API Gateway V2<br/>api.getreggie.io]
        end

        subgraph "VPC (10.0.0.0/16)"
            subgraph "Private Subnets"
                API_FN["API Lambda (Node.js)<br/>Hono + Drizzle<br/>arm64, 1024 MB"]
                VAL_FN["Valuation Lambda<br/>LightGBM (Python)<br/>arm64, 1536 MB"]
                MIG_FN["Migrator Lambda<br/>Alembic (Python)<br/>x86_64, 512 MB"]
                RDS["Aurora Serverless v2<br/>PostgreSQL 17<br/>Encrypted at rest"]
            end
            NAT["EC2 NAT Instance<br/>~$4/mo per AZ"]
        end

        S3_WEB[S3 Web Assets]
        S3_ADMIN[S3 Admin Assets]
    end

    subgraph "Cloudflare R2"
        R2[R2 Storage<br/>Claim Documents]
    end

    CLERK -->|JWKS| API_FN
    CF_DNS --> WEB_CF
    CF_DNS --> ADMIN_CF
    CF_DNS --> APIGW
    WEB_CF --> S3_WEB
    ADMIN_CF --> S3_ADMIN
    APIGW --> API_FN
    API_FN --> RDS
    API_FN --> VAL_FN
    API_FN --> R2
    API_FN -->|Clerk, Stripe, DVLA| NAT
    VAL_FN --> RDS
    MIG_FN --> RDS

Service Architecture

Reggie uses a microservices architecture deployed as AWS Lambda functions, managed by SST v4.

graph LR
    subgraph "services/"
        API["api-ts/<br/>Node.js 22 (Hono)<br/>ZIP Lambda, arm64"]
        VAL["valuation/<br/>Python 3.11 (LightGBM)<br/>Container Lambda, arm64"]
        MIG["migrator/<br/>Python 3.11 (Alembic)<br/>Container Lambda, x86_64"]
        SCRAPER["scraper/<br/>Python 3.11<br/>Scheduled tasks"]
    end

    subgraph "packages/"
        SHARED["shared-python/<br/>Models, schemas, config"]
        APICLIENT["api-client/<br/>TypeScript types + client"]
        UI["ui/<br/>Shared React components"]
    end

    subgraph "apps/"
        WEB["web/<br/>Next.js 15 (public)"]
        ADMIN["admin/<br/>Next.js 15 (admin)"]
    end

    API --> SHARED
    VAL --> SHARED
    MIG --> SHARED
    SCRAPER --> SHARED
    WEB --> APICLIENT
    WEB --> UI
    ADMIN --> APICLIENT
    ADMIN --> UI

Components

Component Technology Runtime Purpose
API Hono (Node.js 22) Lambda ZIP, arm64 REST API, auth, CRUD, webhooks, presigned URLs
Valuation LightGBM (Python 3.11) Lambda Container, arm64 ML inference + rules engine
Migrator Alembic (Python 3.11) Lambda Container, x86_64 Database schema migrations
Scraper Python 3.11 Scheduled DVLA auctions, dealer listings
Web Next.js 15 CloudFront + Lambda Public plate search, valuations, offers
Admin Next.js 15 CloudFront + Lambda Claims management, admin dashboard
Database Aurora Serverless v2 PostgreSQL 17 Encrypted at rest, 0.5-4 ACU
Auth Clerk External SaaS JWT issuance, user management
Storage Cloudflare R2 EU region Claim documents (V5C uploads)
DNS Cloudflare Proxied DNS + CDN proxy

Request Flow

sequenceDiagram
    participant U as User/Agent
    participant CF as Cloudflare
    participant APIGW as API Gateway
    participant FN as API Lambda
    participant DB as Aurora PostgreSQL
    participant VAL as Valuation Lambda
    participant CLERK as Clerk JWKS

    U->>CF: GET /api/v1/plates/AB12CDE
    CF->>APIGW: Forward (proxied)
    APIGW->>FN: Invoke Lambda
    FN->>DB: Query plate data
    DB-->>FN: Plate record
    FN->>VAL: Invoke valuation
    VAL->>DB: Query market comparables
    DB-->>VAL: Market data
    VAL-->>FN: Valuation result
    FN-->>APIGW: JSON response
    APIGW-->>CF: Response
    CF-->>U: Plate data + valuation

Auth Model

Clerk issues JWTs to authenticated users. The API validates them using RS256 via Clerk's JWKS endpoint (cached for 1 hour).

sequenceDiagram
    participant U as User
    participant APP as Next.js App
    participant CLERK as Clerk
    participant API as API Lambda

    U->>APP: Sign in
    APP->>CLERK: Authenticate
    CLERK-->>APP: JWT (RS256)
    APP->>API: Request + Bearer token
    API->>CLERK: Fetch JWKS (cached 1hr)
    CLERK-->>API: Public keys
    API->>API: Verify JWT signature
    API-->>APP: Authenticated response

Auth dependencies: - get_current_user() -- require authenticated user - require_admin() -- require admin role - See ADR-001

Database Migration Flow

Migrations run automatically as part of CI/CD deployment:

sequenceDiagram
    participant CI as GitHub Actions
    participant SST as SST Deploy
    participant ECR as ECR Registry
    participant MIG as Migrator Lambda
    participant DB as Aurora PostgreSQL

    CI->>SST: sst deploy --stage production
    SST->>SST: Build + deploy all resources
    SST-->>CI: Deploy complete
    CI->>CI: docker build (migrator)
    CI->>ECR: Push image
    CI->>MIG: Update function code
    CI->>MIG: Invoke (empty payload)
    MIG->>MIG: alembic.command.upgrade("head")
    MIG->>DB: Apply migrations
    DB-->>MIG: Success
    MIG-->>CI: {"status": "success"}
    CI->>CI: Smoke test

Important: Code deploys before migrations run. Use expand-contract pattern for breaking schema changes. See Create a Migration.

Valuation System

70% ML (LightGBM) + 30% rules engine with adaptive weighting.

  • ML Model: Trained on 26,226 DVLA auction sales, 100+ engineered features
  • Rules Engine: Base price x length x pattern x word multipliers
  • Ensemble: Adaptive weighting based on training data availability per plate type
  • Current MAPE: 42.6% (Phase 3.6)

See Valuation deep-dive and ADR-002.

Agent-Native Design

API responses include structured data + natural language explanations so AI agents can interact as easily as humans. GET /api/v1/dev/info returns credentials programmatically in local dev.

Monorepo Structure

reggie/
  apps/
    web/                  # Next.js public app (port 3000)
    admin/                # Next.js admin app (port 3001)
  services/
    api-ts/               # Hono API (Node.js Lambda ZIP)
    valuation/            # ML inference (Python Lambda container)
    migrator/             # Alembic migrations (Python Lambda container)
    scraper/              # Web scraping (scheduled)
  packages/
    shared-python/        # Shared models, schemas, config, database
    api-client/           # TypeScript API client + generated types
    ui/                   # Shared UI components
  backend/
    alembic/              # Database migration files
    tests/                # Pytest test suite
    scripts/              # Analysis, training, import scripts
  docs/                   # Documentation (you are here)
  .github/                # CI/CD workflows
  .claude/                # AI agent configuration
  sst.config.ts           # Infrastructure definition

Key Files

Purpose Location
API Routes services/api-ts/src/routes/
API DB Connection services/api-ts/src/db/index.ts
Lambda Handler (API) services/api-ts/src/index.ts
Valuation Engine services/valuation/app/engine.py
Valuation Handler services/valuation/app/handler.py
Migrator Handler services/migrator/app/handler.py
Rules Engine packages/shared-python/shared/valuation_rules.py
Models packages/shared-python/shared/models/
Schemas packages/shared-python/shared/schemas/
Database Config packages/shared-python/shared/database.py
App Config packages/shared-python/shared/config.py
SST Config sst.config.ts