Architecture Overview¶
!!! info "TL;DR" Next.js 15 + Supabase + Vercel. App Router with Server Actions. PostgreSQL with RLS. Realtime subscriptions. Modular monolith with domain prefixes.
High-Level Architecture¶
Canviq is a full-stack Next.js application deployed on Vercel with Supabase for backend services. The architecture follows a modular monolith pattern with clear domain boundaries.
┌─────────────────────────────────────────────────────────┐
│ Vercel Edge Network │
│ (Global CDN) │
└─────────────────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ Next.js 15 Application │
│ ┌──────────────────────────────────────────────────┐ │
│ │ App Router (src/app) │ │
│ │ ├── [locale]/ │ │
│ │ │ ├── Page Components (React 19) │ │
│ │ │ ├── Server Actions (mutations) │ │
│ │ │ └── Layout Components │ │
│ │ └── api/ │ │
│ │ └── Route Handlers (REST endpoints) │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Middleware │ │
│ │ ├── Auth validation (HMAC session cookies) │ │
│ │ ├── Locale routing (next-intl) │ │
│ │ └── Rate limiting │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ Supabase (Backend Services) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ PostgreSQL 15 │ │
│ │ ├── Row-level security (RLS) │ │
│ │ ├── Full-text search (tsvector) │ │
│ │ ├── Database triggers │ │
│ │ └── Materialized views │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Realtime │ │
│ │ ├── Postgres CDC │ │
│ │ └── WebSocket subscriptions │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Auth │ │
│ │ ├── User management │ │
│ │ ├── OAuth providers │ │
│ │ └── Session management │ │
│ └──────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Storage │ │
│ │ └── User avatars, attachments │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────┐
│ External Integrations │
│ ├── GitHub (issue creation) │
│ ├── Resend (email notifications) │
│ ├── Anthropic (sentiment analysis, NL parsing) │
│ ├── Inngest (workflow automation) │
│ └── Upstash Redis (rate limiting) │
└─────────────────────────────────────────────────────────┘
Key Design Decisions¶
1. Next.js App Router¶
Uses React Server Components by default. Benefits:
- Server-first rendering — Most components render on the server, reducing bundle size
- Streaming — Progressive page rendering for faster perceived load times
- Server Actions — Type-safe mutations without writing API routes
- Automatic code splitting — Each route is a separate chunk
Client components are used only for interactivity (forms, realtime updates, animations).
2. Supabase for Backend¶
Supabase provides PostgreSQL, Auth, Realtime, and Storage in a unified platform. Benefits:
- Managed infrastructure — No server maintenance
- RLS for security — Row-level security policies enforce authorization at the database level
- Realtime subscriptions — Live updates via PostgreSQL CDC
- Built-in Auth — OAuth, email/password, MFA support
- Self-hostable — Can migrate to self-hosted Supabase if needed
3. Standalone Deployment¶
This product is completely separate from the core Revoir website:
- Separate Vercel project — Independent deployments
- Separate Supabase project — Isolated database and auth
- Separate codebase — No shared code with core site
- Custom domain —
canviq.app(not a subdomain ofrevoir.app)
This isolation allows independent evolution and easier extraction as a standalone product.
4. Modular Monolith¶
The codebase is organized by domain with prefixed tables:
- Feedback domain —
submissions,votes,comments,follows - Survey domain —
survey_*tables (15+ tables) - Agent IAM domain —
agent_*tables - Workflow domain —
workflow_*tables
Each domain has its own:
- Database tables
- API routes (
api/submissions/,api/surveys/) - React components (
components/submissions/,components/surveys/) - Business logic (
lib/submissions.ts,lib/survey/)
This structure supports future extraction into microservices if needed, but avoids premature distribution complexity.
Data Flow¶
Read Path (Server Component)¶
- User requests page
- Next.js server component executes
- Component calls Supabase client (server variant)
- PostgreSQL query with RLS applied
- Data returned to component
- Component renders HTML
- HTML streamed to client
No client-side JavaScript needed for read-only pages.
Write Path (Server Action)¶
- User submits form
- Browser POSTs to Server Action endpoint
- Server Action validates input (Zod schema)
- Server Action calls Supabase client
- PostgreSQL mutation with RLS applied
- Database trigger updates denormalized counts
- Server Action returns result
- Client router refreshes page data
Realtime Path (Subscription)¶
- Client component subscribes to Realtime channel
- PostgreSQL CDC detects change
- Supabase Realtime broadcasts event
- Client receives event via WebSocket
- Client updates UI optimistically
Security Layers¶
1. Middleware¶
- Validates HMAC-signed session cookies
- Rejects forged or expired sessions
- Sets
x-user-idheader for downstream use
2. Row-Level Security (RLS)¶
Every table has RLS enabled. Policies enforce:
- Public read for submissions, categories, tags
- Authenticated write for votes, comments
- Admin-only access for moderation, analytics
- Agent API key validation for MCP tools
3. Server Actions¶
- Validate input with Zod schemas
- Never trust client-provided user IDs
- Re-authenticate using
auth()helper - Log security-relevant actions to audit log
4. Rate Limiting¶
- In-memory rate limiting for standard endpoints
- Distributed rate limiting (Upstash Redis) for MCP agents
- Per-user and per-IP limits
Deployment Pipeline¶
Git Push → GitHub
↓
GitHub Actions
├── Lint (ESLint)
├── Type check (tsc)
├── Unit tests (Vitest)
└── Build (next build)
↓
Vercel
├── Build Next.js app
├── Deploy to CDN
├── Run migrations (Supabase CLI)
└── Generate preview URL
↓
E2E Tests (Playwright on preview)
↓
Merge to main → Production deploy
Scalability Considerations¶
Current Scale (Launch)¶
- Expected load: 1,000 daily active users
- Peak: 100 concurrent users
- Database: 100,000 submissions, 1M votes, 500K comments
- Vercel serverless handles this easily
Growth Scale (Year 1)¶
- Expected load: 10,000 daily active users
- Peak: 1,000 concurrent users
- Database: 1M submissions, 10M votes, 5M comments
- May need Supabase Pro plan for connection pooling
Enterprise Scale (Year 2+)¶
- Expected load: 100,000+ daily active users
- Peak: 10,000+ concurrent users
- Consider:
- Read replicas for heavy queries
- Edge caching for static content
- Dedicated Supabase instance
- Background job workers for heavy operations
The modular monolith architecture supports gradual extraction of domains into separate services as scale demands.
What's Next¶
- System Overview — App Router, Server Actions, middleware
- Database Schema — Tables, RLS policies, indexes
- Authentication — Session cookies, API keys, scopes
- Realtime — Supabase Realtime subscriptions
- Internationalization — next-intl, JSONB translations