Deployment Guide
This guide covers deploying Ecosyz to production environments.
🚀 Quick Deploy
Vercel (Recommended)
- Connect Repository
- Import project to Vercel
-
Connect GitHub repository
-
Environment Variables
# Database DATABASE_URL=postgresql://... # Supabase NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key SUPABASE_SERVICE_ROLE_KEY=your-service-key # Auth NEXTAUTH_SECRET=your-secret-key NEXTAUTH_URL=https://your-domain.vercel.app # External APIs YOUTUBE_API_KEY=your-youtube-key EMAILJS_SERVICE_ID=your-emailjs-id EMAILJS_TEMPLATE_ID=your-template-id EMAILJS_PUBLIC_KEY=your-public-key
-
Build Settings
- Build Command:
npm run build
orpnpm build
- Output Directory:
.next
-
Install Command:
npm install
orpnpm install
-
Deploy
- Push to main branch
- Vercel auto-deploys
- Check deployment logs
Manual Deployment
Prerequisites
- Node.js 18+
- PostgreSQL database
- Redis (optional, for caching)
- Domain name
Build Process
# Install dependencies
pnpm install
# Build application
pnpm build
# Start production server
pnpm start
🏗️ Infrastructure Setup
Database
Supabase (Recommended)
-
Create Project
-
Database Schema
-
Migrations
PostgreSQL (Self-hosted)
-- Create database
CREATE DATABASE ecosyz;
-- Create user
CREATE USER ecosyz_user WITH PASSWORD 'secure-password';
-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE ecosyz TO ecosyz_user;
File Storage
Supabase Storage
// Configure storage bucket
const { data, error } = await supabase.storage.createBucket('documents', {
public: false,
allowedMimeTypes: ['application/pdf', 'text/plain'],
fileSizeLimit: 10485760 // 10MB
});
AWS S3 (Alternative)
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
const s3Client = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
});
🔧 Environment Configuration
Environment Variables
Required Variables
# Database
DATABASE_URL=postgresql://user:password@host:5432/ecosyz
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-key
# Authentication
NEXTAUTH_SECRET=your-32-char-secret
NEXTAUTH_URL=https://your-domain.com
# External Services
YOUTUBE_API_KEY=AIzaSy...
EMAILJS_SERVICE_ID=service_...
EMAILJS_TEMPLATE_ID=template_...
EMAILJS_PUBLIC_KEY=public_...
# Redis (Optional)
REDIS_URL=redis://localhost:6379
Environment-Specific Config
// lib/config.ts
export const config = {
database: {
url: process.env.DATABASE_URL,
},
supabase: {
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
anonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
serviceKey: process.env.SUPABASE_SERVICE_ROLE_KEY,
},
auth: {
secret: process.env.NEXTAUTH_SECRET,
url: process.env.NEXTAUTH_URL,
},
isProduction: process.env.NODE_ENV === 'production',
isDevelopment: process.env.NODE_ENV === 'development',
};
📊 Monitoring & Analytics
Error Tracking
Sentry
// pages/_app.tsx or app/layout.tsx
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.SENTRY_DSN,
tracesSampleRate: 1.0,
});
Performance Monitoring
Vercel Analytics
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
);
}
Logging
Winston Logger
// lib/logger.ts
import winston from 'winston';
export const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' }),
],
});
🔒 Security
Security Headers
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin',
},
],
},
];
},
};
HTTPS Configuration
// next.config.js
module.exports = {
// Force HTTPS in production
...(process.env.NODE_ENV === 'production' && {
headers: [
{
source: '/(.*)',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
],
},
],
}),
};
🚀 CI/CD Pipeline
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Run tests
run: pnpm test
- name: Type check
run: pnpm type-check
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Build
run: pnpm build
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
📈 Scaling
Database Optimization
-- Add indexes for performance
CREATE INDEX CONCURRENTLY idx_resources_title ON resources USING gin(to_tsvector('english', title));
CREATE INDEX CONCURRENTLY idx_resources_created_at ON resources(created_at DESC);
-- Partition large tables
CREATE TABLE resources_y2024 PARTITION OF resources
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
Caching Strategy
// lib/cache.ts
import { Redis } from '@upstash/redis';
export const redis = new Redis({
url: process.env.REDIS_URL,
token: process.env.REDIS_TOKEN,
});
export const cache = {
async get(key: string) {
const data = await redis.get(key);
return data ? JSON.parse(data) : null;
},
async set(key: string, data: any, ttl = 3600) {
await redis.setex(key, ttl, JSON.stringify(data));
},
};
CDN Configuration
// next.config.js
module.exports = {
images: {
domains: ['your-cdn-domain.com'],
formats: ['image/webp', 'image/avif'],
},
};
🔄 Backup & Recovery
Database Backup
# Automated backup script
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
pg_dump $DATABASE_URL > backup_$DATE.sql
# Upload to cloud storage
aws s3 cp backup_$DATE.sql s3://your-backup-bucket/
Disaster Recovery
-
Database Recovery
-
Application Rollback
📋 Deployment Checklist
Pre-Deployment
- [ ] All tests pass
- [ ] Code linting passes
- [ ] Type checking passes
- [ ] Build succeeds locally
- [ ] Environment variables configured
- [ ] Database schema up to date
- [ ] Dependencies updated
Deployment
- [ ] Deploy to staging first
- [ ] Run smoke tests
- [ ] Monitor error rates
- [ ] Check performance metrics
- [ ] Verify critical user flows
Post-Deployment
- [ ] Update documentation
- [ ] Notify team
- [ ] Monitor for 24 hours
- [ ] Create release notes
- [ ] Plan next deployment
🆘 Troubleshooting
Common Issues
Build Failures
Database Connection Issues
// Check database connectivity
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
await prisma.$connect();
console.log('Database connected successfully');
Environment Variable Issues
# Check environment variables
printenv | grep NEXT_PUBLIC
# Validate Supabase connection
curl https://your-project.supabase.co/rest/v1/
For additional support, check the Contributing Guide or create an issue on GitHub.