Skip to main content

System Architecture

Echoes of the Past is built on a modern, serverless architecture that enables real-time AI-powered voice conversations with historical figures. The platform combines Next.js for the frontend, Supabase for backend services, and multiple AI providers for voice and intelligence capabilities.

Tech Stack

Frontend Framework

Next.js 15.3.2
React Framework
Server-side rendering, API routes, and static generation with React 19. Uses Turbopack for fast development builds.
TanStack Query
Data Fetching
Client-side state management and caching for server data with real-time updates.
Motion (Framer Motion)
Animation
Smooth UI animations and transitions for enhanced user experience.

Backend Infrastructure

Supabase
Backend Platform
PostgreSQL database, authentication, and real-time subscriptions via @supabase/ssr and @supabase/supabase-js.
Upstash Redis
Caching & Rate Limiting
Serverless Redis for rate limiting feedback generation (10 requests per day per user).
Next.js API Routes
Server Actions
Server-side business logic using Next.js 15 server actions with ‘use server’ directives.

AI & Voice Services

Vapi AI
Voice Conversation
Real-time voice interaction orchestration via @vapi-ai/web SDK. Handles speech-to-text, text-to-speech, and conversation flow.
ElevenLabs
Voice Synthesis
High-quality AI voice generation using @elevenlabs/elevenlabs-js for historical figure voice cloning.
OpenAI
Language Model
  • GPT-3.5 Turbo for real-time conversation (via Vapi)
  • GPT-4 Turbo for structured feedback generation with JSON mode

Architecture Diagram

The system follows a three-tier architecture:
┌─────────────────────────────────────────────────────────────┐
│                      Client Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Next.js    │  │  Vapi SDK    │  │ TanStack     │      │
│  │   Frontend   │  │  (WebRTC)    │  │ Query        │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│                   Application Layer                         │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │  Next.js API │  │    Server    │  │   Webhook    │      │
│  │    Routes    │  │   Actions    │  │   Handlers   │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│                     Service Layer                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐      │
│  │   Supabase   │  │  Upstash     │  │   AI APIs    │      │
│  │  PostgreSQL  │  │   Redis      │  │ (Vapi, EL,   │      │
│  │    + Auth    │  │              │  │  OpenAI)     │      │
│  └──────────────┘  └──────────────┘  └──────────────┘      │
└─────────────────────────────────────────────────────────────┘

Data Flow

Voice Conversation Flow

  1. Initiation: User selects a historical figure and starts a conversation
  2. Assistant Creation: Frontend creates a Vapi assistant with:
    • Character-specific system prompt from lib/prompt.ts
    • ElevenLabs voice ID from the character’s voiceId field
    • OpenAI GPT-3.5 Turbo for language processing
  3. Real-time Communication:
    • User speech → Vapi transcription → OpenAI processing → Response generation
    • AI response → ElevenLabs synthesis → Audio playback
  4. Message Tracking: All transcript messages stored in client state for feedback generation

Quiz Flow

  1. Quiz Generation: Server action creates quiz record in Supabase
  2. Question Delivery: Vapi assistant asks questions from quizQuestions table
  3. Scoring: Assistant tracks correct/incorrect answers in real-time
  4. Results: Final score displayed with feedback summary

Feedback Generation Flow

  1. Transcript Collection: Conversation messages accumulated during call
  2. Rate Limit Check: Redis checks user hasn’t exceeded 10 feedback requests per day
  3. AI Analysis: OpenAI GPT-4 Turbo analyzes transcript with structured prompt
  4. Structured Output: JSON response parsed with Zod schema validation
  5. Storage: Feedback saved to Supabase feedbacks table with category scores
// Rate limiting implementation
const rateLimit = await redis.incr(`feedback-rate-limit:${user.id}`)
if (rateLimit > 10) {
  return { error: 'Maximum feedback requests exceeded' }
}

Authentication & Authorization

  • Provider: Supabase Auth with cookie-based sessions
  • Client: Browser client created with createBrowserClient from @supabase/ssr
  • Server: Server client created with createServerClient using Next.js cookies
  • Row Level Security: Database policies enforce user access control

Environment Configuration

Required environment variables:
# Supabase
NEXT_PUBLIC_SUPABASE_URL
NEXT_PUBLIC_SUPABASE_ANON_KEY

# AI Services
NEXT_PUBLIC_VAPI_WEB_TOKEN
ELEVEN_LABS_API_KEY
OPENAI_API_KEY

# Redis
UPSTASH_REDIS_REST_URL
UPSTASH_REDIS_REST_TOKEN

# Webhooks (optional)
NEXT_PUBLIC_SERVER_URL

Type Safety

  • Database Types: Auto-generated TypeScript types from Supabase schema in database.types.ts
  • API Types: Vapi SDK types for assistant configuration and message handling
  • Validation: Zod schemas for runtime validation of AI-generated feedback
# Generate database types
npm run gen-types

Performance Optimizations

  • Server-Side Rendering: Initial page load with pre-rendered content
  • Data Caching: TanStack Query caches frequently accessed data
  • Redis Caching: Rate limit counters cached in serverless Redis
  • WebRTC: Direct peer-to-peer voice communication via Vapi
  • Turbopack: Fast development builds with incremental compilation

Scalability Considerations

  • Serverless Architecture: Auto-scaling Next.js API routes on Vercel
  • Database Connection Pooling: Supabase handles PostgreSQL connections
  • Edge Functions: Potential for edge deployment of API routes
  • Rate Limiting: Prevents abuse of expensive AI operations

Build docs developers (and LLMs) love