Architecture
System design, data flows, component boundaries, and integration topology for this codebase.
️ Technology Stack
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 16 (App Router) | RSC, Server Actions, edge middleware |
| Language | TypeScript 6 (Strict) | Zero any, compile-time safety |
| Database | PostgreSQL 15 (Supabase) | 32 tables, RLS on every table |
| ORM | Drizzle ORM | Type-safe SQL, schema-driven |
| Auth | Supabase Auth | PKCE, OAuth, MFA, passkeys |
| Payments | Universal Adapter (5 providers) | Strategy pattern, env var swap |
| AI | Universal Adapter (4 providers) | Validated Gemini, OpenAI, Anthropic, DeepSeek factories |
| Embeddings | gemini-embedding-2 + pgvector | 3072-dim, cosine similarity RAG |
| Voice | Universal Adapter (2 providers) | ElevenLabs/Murf TTS; STT requires ElevenLabs |
| Universal Adapter (4 providers) | Validated SendGrid, Resend, Postmark, Brevo adapters | |
| Analytics | Universal Adapter (9 providers) | Consent-gated scripts/events with CSP allowlisting |
| Rate Limiting | Upstash Redis | Edge middleware, circuit breaker |
| Background | Universal Adapter (QStash / Trigger.dev) | Strategy pattern, swappable background jobs |
| Knowledge Graph | Graphify | AST parsed, 71.5x token reduction for AI Agents |
| Styling | Tailwind CSS v4 + shadcn/ui (57) | OKLCH, Glassmorphism 2.0 |
| Motion | motion/react (LazyMotion) | Spring physics, ~15KB vs ~100KB |
| i18n | next-intl | 3 languages, 14 sub-modules |
| Testing | Vitest + Playwright | 900 tests across 84 unit test files + E2E coverage |
| API | oRPC + OpenAPI 3.0.3 + Scalar | Type-safe RPC, interactive docs |
| Error Tracking | Sentry | PII and replay opt-in, GDPR-safe default |
Request Lifecycle
Every request passes through this pipeline:
Browser Request
↓
proxy.ts (Edge Middleware)
├── Route classification (public / auth / protected / super-admin / API)
├── Rate limiting (Upstash Redis, per-tier from lib/config/pricing.ts)
├── Circuit breaker (auto IP ban after 5 violations)
├── CSP nonce generation (per-request, strict-dynamic)
├── CSRF validation (HMAC-bound double-submit cookie + user binding)
├── Auth session refresh (Supabase token rotation)
├── MFA enforcement (AAL2 check via getAuthenticatorAssuranceLevel(), fail-closed)
├── Feature flag redirects (disabled modules → /dashboard)
├── Header injection (x-pathname, x-org-id, x-nonce, x-impersonating-*)
├── Signed impersonation context propagation (1hr auto-expiry + read-time profile revalidation)
├── Waitlist Gating: unapproved users deleted via super-admin client
├── Waitlist Metadata Sync: fullName → profile (first login)
└── CSRF cookie seeding/refresh for authenticated page requests
↓
Next.js App Router
├── Root layout (fonts, ThemeProvider, MotionProvider, NextIntlClientProvider, CSRFProvider)
├── Server Component (data fetching via Server Actions)
└── Client Component (interactive UI, motion animations)
↓
Server Actions (app/actions/)
├── 1. Auth check → requireUser() / verifyAdmin()
├── 2. Zod validation → schema.safeParse(input)
├── 3. Drizzle operation → db.select/insert/update/delete
└── 4. Cache invalidation → revalidatePath() + revalidateTag(..., "max")
↓
PostgreSQL (Supabase)
├── RLS policies enforce data isolation at query level
├── Drizzle ORM parameterizes all queries (SQL injection prevention)
└── Indexes optimized for RLS super-admin checks + common patternsPerformance Contracts
The current performance hardening uses stable production primitives, not experimental framework flags:
- Next.js config strips unstable keys after plugin composition; production builds must not depend on
experimental. - Pricing auth/billing reads execute in parallel and commit one derived billing-context state update.
- Drizzle reads use explicit projections to reduce payload size and avoid accidental over-fetching.
- Super-Admin webhook log reads clamp requested limits to 100 rows and project only fields needed by retry/list/detail views.
- Fixed-aspect
next/imageassets includestyle={{ width: "auto", height: "auto" }}to prevent ratio warnings and layout shifts. - Heavy client libraries remain behind dynamic import or provider-level lazy loading: Recharts via chart wrappers, support chat widget via
next/dynamic, and motion viaLazyMotion+domAnimation.
Directory Structure
app/
├── (marketing)/ # Public: landing, pricing, blog, contact, system, docs, API ref
├── (auth)/ # Login, signup, forgot/reset password, invite, verified
├── (protected)/ # Dashboard, billing, settings, super-admin, onboarding
│ ├── dashboard/
│ │ ├── analytics/ # Usage analytics (Recharts)
│ │ ├── billing/ # Subscriptions, invoices
│ │ ├── organizations/# Multi-tenant teams
│ │ ├── projects/ # Project CRUD
│ │ └── settings/ # Profile, security (MFA/passkeys), notifications, activity
│ └── super-admin/ # 17 super-admin module routes
└── api/
├── auth/callback/ # OAuth, magic link, password-reset code exchange
├── health/ # Minimal public liveness endpoint
├── rpc/[...path]/ # oRPC handler (type-safe API)
└── webhooks/ # Payment webhooks (stripe, polar, lemon-squeezy, dodo, creem)
components/
├── auth/ # Split-screen auth, MFA challenge, passkeys
├── dashboard/ # Sidebar, nav, charts, settings, org switcher
├── global/ # Header, footer, chat widget, theme toggle
├── marketing/ # Hero, features, pricing, testimonials
├── super-admin/ # 17 super-admin modules (Glassmorphism 2.0 logic)
├── support/ # Tickets, chat widget
└── ui/ # 57 shadcn/ui primitives (you own the code)
lib/
├── ai/ # Universal AI Adapter, providers/, RAG, intent, embeddings
├── rpc/ # oRPC routers, procedures, middleware
├── auth/ # Supabase client factory (server, client, super-admin), RBAC
├── config/ # App config, pricing, feature flags (single source of truth)
├── db/ # Drizzle client + schema/ (14 domain files)
├── email/ # Universal Email Adapter, templates, i18n content
├── invoices/ # PDF Invoice generation service
├── payments/ # Universal Payment Adapter (5 providers), types, utils
├── jobs/ # Universal Background Jobs (shared business logic)
├── qstash/ # QStash transport adapter for background jobs
├── trigger/ # Trigger.dev transport adapter for background jobs
├── realtime/ # Supabase Realtime broadcasting utilities
├── security/ # SSRF (ssrf.ts), crypto (crypto.ts), security alerts
├── seo/ # Metadata generators, JSON-LD schemas
├── validations/ # Shared Zod schemas
└── voice/ # Universal Voice Adapter (ElevenLabs, Murf AI)
locales/
├── frontend/ # UI: en.ts, es.ts, fr.ts (14 sub-modules each)
└── emails/ # Email content: en.ts, es.ts, fr.ts
.agents/
├── skills/ # 4 SKILL.md (backend, frontend, graphify, i18n)
└── workflows/ # 18 step-by-step playbooks
graphify-out/ # 🧠 Auto-generated AST knowledge graph for AIIntegration Architecture
Universal Payment Adapter
lib/payments/
├── types.ts # PaymentProvider interface contract
├── index.ts # Factory: getPaymentProvider() reads PAYMENT_PROVIDER env var
├── readiness.ts # Selected-provider env and paid-tier product readiness
├── utils.ts # mapProductNameToTier(), shared helpers
└── providers/
├── stripe.ts
├── polar.ts
├── lemon-squeezy.ts
├── dodo.ts
└── creem.tsPattern: Strategy. All providers implement PaymentProvider. App code calls getPaymentProvider() — never a specific provider. Switching = one env var change, zero code mods. getPaymentProviderReadiness() validates the selected provider's API key/access token, webhook secret, and active paid-tier price/product IDs for super-admin health without exposing secret values.
Paid product-name fallback: Providers that cannot resolve a tier from metadata or price/product IDs call mapProductNameToTier() in lib/payments/utils.ts. The helper matches configured paid tier IDs and display names first, maps config-driven highIntentAliases (e.g., business, agency, enterprise) to the correct paid tier, and falls back to the lowest paid tier for unknown paid provider names so completed one-time purchases are never downgraded to the default free tier. Each call emits a [mapProductNameToTier] warning so teams can replace string-based matching with metadata or configured IDs.
Webhook flow:
Provider sends webhook
↓
app/api/webhooks/[provider]/route.ts
↓
Read raw body + signature header(s)
↓
provider.handleWebhook(payload, signature) — HMAC-SHA256
↓
webhook_logs claim(provider, event_id) — success skip, active-processing skip, failed/stale retry
↓
syncSubscriptionToDb() / savePurchase() — provider-resource upsert/dedup + profiles.subscription_tier + subscriptions/purchasesFeatures:
- Token-Based Fulfillment: Secure, signed, short-lived download links for digital products.
- Same-Origin Redirects: Checkout success/cancel and portal return URLs are built with
lib/security/redirects.tsfromconfig.app.urlplus allowlisted paths. External redirect targets are rejected before provider session creation. - Provider Resource Idempotency:
subscriptions(provider, provider_subscription_id)andpurchases(provider, provider_payment_id)are unique when provider IDs are present, preventing duplicate entitlements after webhook retries or concurrent deliveries. - Billing Identity Parity: REST checkout, portal, cancel, and subscription routes use
getEffectiveUserId()so impersonated super-admin flows target the same account as Server Actions. - Fail-Closed Paid Deletion: Account deletion stops before local profile/auth/storage removal if immediate provider subscription cancellation, configured-bucket storage cleanup, or Auth deletion fails.
- Dynamic Usage Limits: Renders tier constraints (projects, team members, API requests, storage) directly from central pricing configs without hardcoded fallbacks.
- Upgrade Guard Hardening: Intelligently hides "Upgrade Plan" buttons exclusively for users already on the most expensive plan.
AI & RAG Pipeline
User message (text or voice)
↓
Language detection (getAIProvider().classifyIntent() — 100+ languages)
↓
Generate embedding (getEmbeddingProvider().generateEmbedding(), 3072 dims)
↓
pgvector cosine similarity → knowledge_base
↓
Top-K context injected into AI provider prompt
↓
getAIProvider().streamChat() responds (in detected language)
↓
[Optional] Voice Provider (ElevenLabs / Murf) TTS → speech; STT only when ElevenLabs is configured
↓
Response → chat widget (Web Audio API)Key properties:
- Lazy conversation creation — DB record on first message, not widget open
- Guest access — no auth required
- Message dedup — client-side + event IDs
- Provider gates — invalid
AI_PROVIDER/EMBEDDING_PROVIDERvalues fail closed before SDK construction
Email Adapter
lib/email/
├── index.ts # sendEmail() — validates EMAIL_PROVIDER and configured-key fallback
├── types.ts # EmailTemplateType (13 template names)
├── providers/
│ ├── sendgrid.ts # Native batch up to 1000
│ ├── resend.ts # Auto-chunks at 100
│ ├── postmark.ts # Official postmark SDK, auto-chunks at 500
│ └── brevo.ts # Sequential Promise.allSettled
└── templates/ # 13 i18n-ready templatesAnalytics Adapter
lib/analytics/
├── consent.ts # localStorage/cookie consent contract + app-local change event
├── index.ts # getAnalyticsAdapter() — SSR/feature/consent guard
├── types.ts # AnalyticsProvider (10 event helpers)
└── providers/ # 9 implementationsPII protection: trackSignup() excludes email. Client scripts mount through components/providers/analytics-provider.tsx only after explicit analytics consent. proxy.ts allowlists analytics connect-src endpoints for the configured providers; DataFast requires both NEXT_PUBLIC_DATAFAST_WEBSITE_ID and NEXT_PUBLIC_DATAFAST_DOMAIN.
️ Data Model
Entity Relationships
auth.users (Supabase-managed)
└── profiles (1:1)
├── subscriptions (1:many)
├── purchases (1:many)
├── invoices (1:many)
├── projects (1:many)
├── activity_logs (1:many)
├── ai_conversations (1:many)
│ └── ai_messages (1:many)
├── support_tickets (1:many)
│ └── ticket_replies (1:many)
├── api_keys (1:many)
│ └── api_usage_logs (1:many)
├── passkeys (1:many)
├── notification_preferences (1:1)
└── organizations (owner, 1:many)
└── org_members (many:many with profiles)
└── org_invitations (1:many)
Standalone:
├── posts ← blog_categories (many:1)
├── knowledge_base (RAG vectors)
├── generated_legal_docs
├── contact_submissions
├── waitlist
├── newsletter_subscribers
├── webhook_logs
├── webauthn_challenges
├── auth_events (append-only)
├── affiliates → referrals → affiliate_payouts
└── user_legal_consentsKey Design Decisions
| Decision | Rationale |
|---|---|
| UUID primary keys | Globally unique, no sequential enumeration |
timestamptz everywhere | Timezone-aware, no UTC bugs |
text not varchar | PostgreSQL treats identically; avoids arbitrary limits |
| Hard deletes + CASCADE | Simpler cleanup; retained deletion facts live in auth_events |
| JSONB for metadata | Flexible extension (goals, product_usage, line_items) |
| Barrel re-exports | Single import point; domain files keep schema organized |
Security Architecture
┌──────────────────────────────────────┐
│ Edge Layer │
│ Rate Limiting (Upstash Redis) │
│ Circuit Breaker (auto IP ban) │
│ CSP Nonce (per-request) │
│ CSRF (HMAC-bound double-submit) │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ Application Layer │
│ Auth Check (supabase.auth.getUser) │
│ MFA Enforcement (AAL2 check) │
│ Zod Input Validation │
│ Ownership Verification │
└──────────────┬───────────────────────┘
│
┌──────────────▼───────────────────────┐
│ Database Layer │
│ RLS on all 32 tables │
│ Drizzle parameterized queries │
│ FOR UPDATE row locks (credits) │
│ API Key SHA-256 hashing │
│ Composite indexes (20+) │
│ auth_events append-only logging │
└─────────────────────────────────────┘Full OWASP Top 10 (2025) compliance. See SECURITY_AUDIT.md · THREAT_MODEL.md · SUPPLY_CHAIN_SECURITY.md.
️ Configuration Architecture
Single source of truth:
lib/config.ts (barrel export)
├── lib/config/app.ts # App name, URL, feature flags, legal
├── lib/config/pricing.ts # PRICING_TIERS: prices, limits, credits, rate limits, provider IDs
└── lib/config/billing.ts # Billing model toggles (subs, lifetime, credits, seats, trials)Feature flags gate UI + server-side logic:
// UI
{isOrganizationsEnabled() && <OrgSwitcher />}
// Server
if (!isOrganizationsEnabled()) return { success: false, error: t("disabled") };21 helpers: isProjectsEnabled(), isOrganizationsEnabled(), isCreditsEnabled(), isSeatsEnabled(), isSubscriptionsEnabled(), isLifetimePurchasesEnabled(), isDigitalProductsEnabled(), isTrialEnabled(), isBlogEnabled(), isAiChatEnabled(), isVoiceEnabled(), isSTTEnabled(), isWaitlistEnabled(), isI18nEnabled(), isAnalyticsEnabled(), isStorageEnabled(), isEmailEnabled(), isAffiliatesEnabled(), isSupportTicketsEnabled(), isDocsEnabled(), isApiReferenceEnabled().
Copyright © 2026 Vibe44. Built with ❤️ by Scale with Alap.