┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │ │ │ │ │ │ Vercel │ │ Supabase │ │ External APIs │ │ (Frontend) │◄──►│ (Backend) │◄──►│ (Wallet Analysis)│ │ │ │ │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ │ │ │ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐ │ CDN │ │Database │ │ Railway │ │ Assets │ │Storage │ │ API │ └─────────┘ │Real-time│ └─────────┘ └─────────┘
Visit supabase.com and create a new project:
Organization: Your Organization Name: trenchr-production Database Password: [Generate strong password] Region: [Choose closest to users] Pricing Plan: Pro (recommended for production)
Run the following SQL scripts in order through the Supabase SQL Editor:
scripts/001-create-tables.sql
scripts/002-seed-sample-data.sql
scripts/003-add-username-constraint.sql
scripts/004-create-storage-bucket.sql
Site URL: https://your-domain.com Additional Redirect URLs: https://your-domain.com/auth/callback https://your-domain.com/dashboard Provider Settings: Email: Enabled Confirm email: Enabled Secure email change: Enabled
# Push to GitHub git add . git commit -m "Production ready" git push origin main # Verify Build npm run build npm run type-check
Import your project to Vercel:
Framework Preset: Next.js Root Directory: ./ Build Command: npm run build Output Directory: .next Install Command: npm install
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
// next.config.mjs const nextConfig = { async headers() { return [ { source: '/(.*)', headers: [ { key: 'Content-Security-Policy', value: ` default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline' *.vercel.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: *.supabase.co; connect-src 'self' *.supabase.co wss://*.supabase.co; `.replace(/\s{2,}/g, ' ').trim() } ] } ] } }
// middleware.ts import { NextResponse } from 'next/server' const rateLimitMap = new Map() export function middleware(request) { const ip = request.ip ?? '127.0.0.1' const limit = 100 // requests per hour // Rate limiting logic if (ipData.count >= limit) { return NextResponse.json( { error: 'Too many requests' }, { status: 429 } ) } return NextResponse.next() }
// app/layout.tsx import { Analytics } from '@vercel/analytics/react' export default function RootLayout({ children }) { return ( <html> <body> {children} <Analytics /> </body> </html> ) }
// app/api/health/route.ts export async function GET() { try { // Check database connection const { data, error } = await supabase .from('users') .select('count') .limit(1) return NextResponse.json({ status: 'healthy', timestamp: new Date().toISOString(), database: 'connected' }) } catch (error) { return NextResponse.json( { status: 'unhealthy', error: error.message }, { status: 500 } ) } }
Local Supabase instance
Hot reloading enabled
Preview deployments
Testing environment
Optimized builds
Analytics enabled