┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ 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.sqlscripts/002-seed-sample-data.sqlscripts/003-add-username-constraint.sqlscripts/004-create-storage-bucket.sqlSite 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