Architecture

Overview

Vigil is a prop firm compliance SaaS for traders. Users define their trading rules, connect their broker platforms, and Vigil uses AI to audit each trade against those rules. The app is built as a Next.js 16 static export deployed on Cloudflare Pages, with Supabase (PostgreSQL) as the database and auth layer. Server-side logic runs as Cloudflare Pages Functions (file-based routing under functions/api/). AI audits use OpenRouter (Kimi k2.5 model) for both single-agent and multi-agent analysis.

The product serves three user tiers: anonymous visitors (1 free audit/day), free authenticated users (3 audits/month), and Pro subscribers (50 audits/month via Stripe). Revenue comes from Stripe subscriptions with a Pro+ tier that unlocks multi-agent audits.

Stack

LayerTechnologyVersion
FrameworkNext.js16.2.1
RuntimeCloudflare Pages FunctionsWorkers runtime
LanguageTypeScript^5
UI LibraryReact19.2.4
StylingTailwind CSS v4^4
UI Componentsshadcn/ui (CVA + Radix via Base UI)^4.1.0
AnimationFramer Motion^12.38.0
ChartsRecharts^3.8.0
DatabaseSupabase (PostgreSQL)Hosted
AuthSupabase Auth (PKCE flow)@supabase/ssr ^0.9.0
PaymentsStripe^20.4.1
AIOpenRouter (Kimi k2.5)REST API
Email (transactional)ResendREST API
Email (newsletter)BeehiivREST API
Bot ProtectionCloudflare TurnstileWidget + server verify
AnalyticsPostHog^1.363.1
ValidationZod^4.3.6
TestingVitest + Testing Library^4.1.0
BuildWebpack (via NEXT_WEBPACK=1 flag)
DeployWrangler^4.76.0

Directory Structure

vigil/
  src/
    app/                      # Next.js App Router pages (static export)
      [firm]/[questionSlug]/  # Dynamic firm FAQ pages (pSEO)
      about/                  # About + methodology pages
      auth/callback/          # Supabase OAuth callback handler
      best/[category]/        # "Best prop firm for X" pSEO pages
      calculators/            # Cost calculators per firm
      changelog/              # Public changelog
      compare/                # Firm comparison tool (pSEO)
      corrections/            # Public corrections page
      dashboard/              # Authenticated dashboard area
        audit/                # AI trade audit interface
        connections/          # Broker connections management
        import/               # CSV trade import
        onboarding/           # New user onboarding wizard
        settings/             # Account settings + billing
        strategy/             # Strategy analysis page
      guides/                 # Educational guides
      import/[platform]/      # Platform-specific import pages
      learn/                  # Glossary / learn pages (pSEO)
      login/                  # Auth login page
      onboarding/             # Pre-auth onboarding flow
      pricing/                # Pricing page
      quiz/                   # Interactive quiz funnel
      r/                      # Shared results viewer
      reviews/                # Firm review pages (pSEO)
      rules/                  # Firm rules reference (pSEO)
      setup/                  # Platform setup guides
      stats/                  # Public stats page
      strategies/             # Strategy-firm combo pages (pSEO)
      switch-from/            # Competitor switch pages
      tools/                  # Free tools (strategy analyzer, simulators)
      trust/                  # Trust/safety score pages (pSEO)
    components/               # React components
      announcements/          # Announcement banner
      audit/                  # Audit UI (client, results, widget)
      auth/                   # Auth provider (Supabase session)
      broker/                 # Broker connection UI components
      dashboard/              # Dashboard panels and widgets
      home/                   # Homepage sections
      import/                 # CSV import UI
      quiz/                   # Quiz funnel components
      seo/                    # JSON-LD schema components
      simulator/              # Trailing drawdown simulator
      strategy/               # Strategy detail views
      strategy-analyzer/      # Chart screenshot analyzer
      trust/                  # Trust score animations
      ui/                     # shadcn/ui primitives (button, card, etc.)
    lib/                      # Shared business logic
      audit/                  # Audit cost tracking, schema, screenshot validation
      broker/                 # Broker auto-sync system
        adapters/             # Per-broker adapter implementations
        credentials.ts        # AES-256-GCM encryption/decryption
        oauth-state.ts        # HMAC-signed OAuth state parameter
        registry.ts           # Adapter registry (maps broker_type to adapter)
        sync.ts               # Sync orchestrator (fetch, dedup, insert)
        types.ts              # Domain types (BrokerAdapter, BrokerConnection, etc.)
      data/                   # Static data (firms, glossary, strategies, instruments)
      email/                  # Email template builder
      export/                 # CSV export generation
      import/                 # CSV parser + Supabase import
      quiz/                   # Quiz scoring + trader types
      rules/                  # Rule quality scoring (A-F grading)
      simulator/              # Drawdown simulation engine
      storage/                # Screenshot storage helpers
      posthog.ts              # PostHog analytics client
      referral.ts             # Referral link handling
      streak.ts               # Streak calculation logic
      stripe.ts               # Client-side Stripe checkout
      supabase.ts             # Supabase browser client singleton
      utm.ts                  # UTM parameter capture
  functions/
    api/                      # Cloudflare Pages Functions (server-side)
      _auth.ts                # Shared Supabase JWT verification
      _journal-core.ts        # Shared journal business logic (NLP, screenshots, logging)
      audit.ts                # Single-agent AI audit (POST)
      audit-multi.ts          # Multi-agent AI audit (POST, Pro+ only)
      broker/                 # Broker CRUD + sync endpoints
        callback.ts           # OAuth callback handler (GET)
        connect.ts            # Create broker connection (POST)
        disconnect.ts         # Remove broker connection (POST)
        status.ts             # List user's connections (GET)
        sync.ts               # Manual sync trigger (POST)
      cron/                   # Scheduled tasks (triggered by GitHub Actions)
        cleanup-screenshots.ts # Delete screenshots > 90 days
        reset-audits.ts       # Reset free audit quotas monthly
        sync-brokers.ts       # Auto-sync active broker connections
        weekly-digest.ts      # Weekly compliance email to Pro users
      delete-account.ts       # GDPR account deletion (POST)
      discord/webhook.ts      # Discord journal bot webhook
      email-capture.ts        # Email lead capture + Beehiiv (POST)
      email/inbound.ts        # SendGrid inbound email journal
      health.ts               # Health check (GET)
      journal/                # Journal platform linking
        link.ts               # Generate/check link codes (POST/GET)
        settings.ts           # Journal preferences (GET/PATCH)
      og-image.ts             # Dynamic OG image SVG (GET)
      rules/grade.ts          # Rule quality grading (POST)
      send-email.ts           # Transactional email via Resend (POST)
      strategy-analyze.ts     # Strategy extraction from screenshots (POST)
      strategy/
        generate-pine.ts      # Pine Script v5 generator (POST)
        import-backtest.ts    # Backtest CSV import (POST)
      stripe/                 # Stripe billing
        checkout.ts           # Create checkout session (POST)
        portal.ts             # Create billing portal session (POST)
        webhook.ts            # Stripe event handler (POST)
      telegram/webhook.ts     # Telegram journal bot webhook
      whatsapp/webhook.ts     # WhatsApp journal bot webhook
  supabase/
    config.toml               # Supabase local dev config
    migrations/               # 15 SQL migration files (see DATABASE_SCHEMA.md)
  scripts/                    # Utility scripts
    check-supabase-usage.ts   # Check Supabase usage metrics
    generate-icons.ts         # Generate favicon variants
    generate-og-image.ts      # Generate static OG image
    google-indexing.ts        # Google Indexing API batch submit
    llm-accuracy-test.ts      # LLM response accuracy testing
    ping-search-engines.sh    # Ping Google/Bing with sitemap
    setup-uptime.sh           # Configure Uptime Robot monitors
  public/                     # Static assets (favicons, firm logos, llms.txt, robots.txt)
  docs/                       # Project documentation + specs
  tests/                      # Test files

Key Flows

  1. 1.Client submits trade data + optional screenshot(s) + Turnstile token to POST /api/audit
  2. 2.Server verifies Turnstile token, validates trade data, checks monthly AI budget ($50 cap)
  3. 3.Server enforces per-user quota: anonymous (1/day via IP), free (3/month via free_audits_remaining), active subscriber (50/month)
  4. 4.Server builds a compliance audit prompt from: user's trading rules, prop firm rules, trade data, and screenshot instructions
  5. 5.Server calls OpenRouter (Kimi k2.5) with the prompt + optional Vision images
  6. 6.Server validates the JSON response against the audit schema (verdicts, compliance score, recommendation)
  7. 7.On validation failure, retries once with a correction prompt appended to the conversation
  8. 8.Server estimates cost from token usage, records quota usage, and returns the audit result
  1. 1.Same initial flow as single agent, but requires JWT auth + subscription_plan = 'pro_plus'
  2. 2.Runs 3 specialist agents in parallel: Technical Analyst (with screenshots), Risk Manager (data only), Rules Compliance Officer (data only)
  3. 3.Feeds all 3 reports into a 4th Debate Synthesizer agent that resolves contradictions and produces a unified audit
  4. 4.Returns the unified result with individual agent reports attached (~$0.12/audit vs $0.03 single-agent)
  1. 1.User connects a broker via POST /api/broker/connect -- credentials are AES-256-GCM encrypted before storage
  2. 2.For OAuth brokers (Tradovate, cTrader), returns a redirect URL with HMAC-signed state; callback at GET /api/broker/callback exchanges the code
  3. 3.For credential-based brokers (MetaTrader via MetaAPI, NinjaTrader, etc.), adapter.connect() verifies immediately
  4. 4.On successful connection, an initial sync is triggered fire-and-forget
  5. 5.A GitHub Actions cron triggers POST /api/cron/sync-brokers every 15 minutes
  6. 6.The cron endpoint queries active connections due for sync (oldest-first, batch of 10)
  7. 7.For each connection: decrypt credentials, call adapter.fetchTrades(since), deduplicate via external_id index + composite fallback, insert new trades with source_type = 'broker_sync'
  8. 8.On success: update last_sync_at, reset consecutive_errors, count total trades atomically
  9. 9.On failure: increment consecutive_errors; after 5 consecutive failures, status is set to error
  1. 1.User generates a link code via POST /api/journal/link (VGL-XXXX format, 10-minute TTL)
  2. 2.User sends the code to a bot on Telegram, Discord, WhatsApp, or via email
  3. 3.Platform webhook (/api/{platform}/webhook) receives the message, calls validateLinkCode() to bind the platform ID to the user's profile
  4. 4.Once linked, natural language trade messages are parsed by AI (parseTradeMessage() via OpenRouter)
  5. 5.Parsed trades are inserted via logTrade() which also upserts daily_tracking
  6. 6.Screenshots can be sent and are processed via Vision AI (parseTradeScreenshot())
  7. 7.Users can request daily summaries, weekly digests, and pre-trade checks via commands
  1. 1.Client calls POST /api/stripe/checkout (authenticated) to create a Checkout Session
  2. 2.Stripe redirects user to hosted checkout; on success, redirects back to /dashboard
  3. 3.POST /api/stripe/webhook receives events, verifies HMAC-SHA256 signature using Web Crypto API
  4. 4.checkout.session.completed -- links stripe_customer_id to user's profile, sets subscription_status = 'active'
  5. 5.customer.subscription.updated -- syncs plan name, status, period end date
  6. 6.customer.subscription.deleted -- sets status to cancelled
  7. 7.invoice.payment_failed -- sets status to past_due
  8. 8.invoice.paid -- confirms active status
  9. 9.Billing portal access via POST /api/stripe/portal using the stored stripe_customer_id

Configuration

FilePurpose
next.config.tsStatic export (output: 'export'), unoptimized images
wrangler.jsoncCloudflare Pages config (project: tradingaudit, nodejs_compat flag)
tsconfig.jsonTypeScript config, @/* path alias to ./src/*
postcss.config.mjsPostCSS with Tailwind v4
components.jsonshadcn/ui component config
vitest.config.tsVitest test runner config
open-next.config.tsOpenNext/Cloudflare adapter config
supabase/config.tomlSupabase local development config

Environment Variables

VariableLayerPurpose
NEXT_PUBLIC_SUPABASE_URLClientSupabase project URL
NEXT_PUBLIC_SUPABASE_ANON_KEYClientSupabase anonymous key (RLS-enforced)
SUPABASE_SERVICE_ROLE_KEYServerSupabase admin key (bypasses RLS)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYClientStripe public key
NEXT_PUBLIC_STRIPE_PRICE_ID_PROClientStripe Pro plan price ID
STRIPE_SECRET_KEYServerStripe API secret
STRIPE_WEBHOOK_SECRETServerStripe webhook signing secret
OPENROUTER_API_KEYServerOpenRouter API key for AI audits
OPENROUTER_BASE_URLServerOpenRouter base URL (default: https://openrouter.ai/api/v1)
OPENROUTER_MODELServerAI model (default: moonshot/kimi-k2.5)
NEXT_PUBLIC_TURNSTILE_SITE_KEYClientCloudflare Turnstile site key
TURNSTILE_SECRET_KEYServerCloudflare Turnstile secret
RESEND_API_KEYServerResend email API key
BEEHIIV_API_KEYServerBeehiiv newsletter API key
BEEHIIV_PUBLICATION_IDServerBeehiiv publication ID
NEXT_PUBLIC_POSTHOG_KEYClientPostHog project API key
NEXT_PUBLIC_POSTHOG_HOSTClientPostHog ingest URL
CRON_SECRETServerBearer token for cron endpoints
BROKER_ENCRYPTION_KEYServer256-bit hex key for AES-256-GCM credential encryption
TELEGRAM_BOT_TOKENServerTelegram Bot API token
DISCORD_PUBLIC_KEYServerDiscord application public key
DISCORD_BOT_TOKENServerDiscord bot token
WHATSAPP_TOKENServerWhatsApp Cloud API token
WHATSAPP_PHONE_NUMBER_IDServerWhatsApp phone number ID

Deployment

Build command: NEXT_WEBPACK=1 next build (outputs to out/)

Deploy command: wrangler pages deploy out --project-name tradingaudit

Combined: npm run cf:deploy

The build produces a fully static HTML/JS/CSS export in out/. Cloudflare Pages serves the static files and routes /api/* requests to the Pages Functions in functions/api/.

Cron jobs (screenshot cleanup, audit reset, broker sync, weekly digest) are triggered by GitHub Actions on a schedule, calling the respective /api/cron/* endpoints with a Bearer CRON_SECRET authorization header.

Key Design Decisions

  1. 1.Static export + Pages Functions -- No server-side rendering. All pages are statically generated at build time. Server logic runs only in Cloudflare Pages Functions, keeping the critical path fast and the hosting cost near zero.
  1. 1.Raw fetch against PostgREST -- Pages Functions cannot use the Supabase JS client (it requires Node.js). All database operations use raw fetch() against Supabase's PostgREST API with the service role key.
  1. 1.Adapter pattern for brokers -- Each broker integration implements the BrokerAdapter interface. Adding a new broker requires only creating an adapter file and registering it in the registry. The sync orchestrator is broker-agnostic.
  1. 1.AES-256-GCM credential encryption -- Broker credentials are encrypted client-side before storage. The encryption key is a server-side secret (BROKER_ENCRYPTION_KEY). Credentials are never stored in plaintext.
  1. 1.Graceful degradation everywhere -- Every server function falls back safely when optional services (Supabase, Turnstile, Resend, etc.) are not configured. This allows development and testing without all services running.
  1. 1.Multi-platform journal -- The _journal-core.ts module contains all journal business logic. Platform webhooks (Telegram, Discord, WhatsApp, Email) are thin adapters that delegate to the core module, preventing logic duplication.