> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openfinance-hackathon.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Deployment Strategies

> Production deployment options and strategies for Open Finance applications

# Production Deployment Strategies

Comprehensive guide to deploying Open Finance applications with modern cloud platforms, focusing on security, scalability, and cost optimization for hackathon teams and production environments.

<Info>
  **Third-Party Deployment Platforms**

  This guide covers **external hosting services** for deploying your hackathon project:

  * **Not provided** - Choose and set up your own deployment platform
  * **Free tiers available** - Great for hackathon demos and MVPs
  * **Your choice** - Use any platform you're comfortable with
  * **Not officially supported** - Platform-specific issues are outside hackathon support scope

  **Quick Start Recommendation**: Use Vercel (frontend) + Railway (backend) free tiers for fastest deployment with minimal configuration.
</Info>

## ⚡ Hackathon Quick Deploy (5-10 Minutes)

**For teams who need their demo live FAST:**

### Frontend: Vercel One-Click Deploy

**Perfect for**: React, Next.js, Vue.js applications

```bash theme={null}
# 1. Push your code to GitHub
git add .
git commit -m "Ready for deployment"
git push

# 2. Deploy to Vercel (one command)
npx vercel --prod
```

**That's it!** Your frontend is live. Vercel will give you a URL like `your-app.vercel.app`

### Backend: Railway Quick Deploy

**Perfect for**: Node.js, Python, databases

```bash theme={null}
# 1. Install Railway CLI
npm install -g @railway/cli

# 2. Login and deploy (2 commands)
railway login
railway up
```

**Done!** Your backend is deployed with a live URL.

### Database: Railway PostgreSQL

```bash theme={null}
# Add a database to your Railway project
railway add postgresql
```

**Environment variables are automatically configured** - no manual setup needed.

<Tip>
  **Pro Tip**: Deploy early in the hackathon (within first 6 hours) to catch any deployment issues before demo time. Test your live URLs to ensure everything works end-to-end.
</Tip>

***

## 📋 Detailed Platform Guide

For teams who want more control or have specific requirements:

## Platform Overview

### **Frontend Deployment Platforms**

<CardGroup cols={2}>
  <Card title="Vercel (Recommended)" icon="triangle">
    Zero-config deployments for React, Next.js, and static sites
  </Card>

  <Card title="Netlify" icon="netlify">
    JAMstack deployments with powerful serverless functions
  </Card>

  <Card title="AWS Amplify" icon="aws">
    Full-stack deployments with AWS integration
  </Card>

  <Card title="GitHub Pages" icon="github">
    Free static site hosting for documentation and demos
  </Card>
</CardGroup>

### **Backend Deployment Platforms**

<CardGroup cols={2}>
  <Card title="Railway (Recommended)" icon="train">
    Simple deployments for Node.js, Python, and databases
  </Card>

  <Card title="Render" icon="render">
    Free tier for web services and static sites
  </Card>

  <Card title="Heroku" icon="heroku">
    Classic PaaS with extensive add-on ecosystem
  </Card>

  <Card title="AWS/GCP/Azure" icon="cloud">
    Enterprise-grade cloud infrastructure
  </Card>
</CardGroup>

## Quick Deployment Guide

### Vercel Deployment

**Best For**: React, Next.js, Vue.js frontend applications

<Steps>
  <Step title="Install Vercel CLI">
    ```bash theme={null}
    npm i -g vercel
    ```
  </Step>

  <Step title="Login and Initialize">
    ```bash theme={null}
    # Login to Vercel
    vercel login

    # Deploy from project directory
    vercel

    # Follow prompts to configure project
    ```
  </Step>

  <Step title="Configure Environment Variables">
    ```bash theme={null}
    # Add production environment variables
    vercel env add NEXT_PUBLIC_API_URL production
    vercel env add OPENFINANCE_CLIENT_ID production

    # Redeploy with new environment
    vercel --prod
    ```
  </Step>

  <Step title="Custom Domain (Optional)">
    ```bash theme={null}
    # Add custom domain
    vercel domains add yourdomain.com

    # Assign to project
    vercel alias your-project.vercel.app yourdomain.com
    ```
  </Step>
</Steps>

**Vercel Configuration (`vercel.json`)**:

```json theme={null}
{
  "version": 2,
  "builds": [
    {
      "src": "package.json",
      "use": "@vercel/next"
    }
  ],
  "env": {
    "NEXT_PUBLIC_API_URL": "@api-url",
    "OPENFINANCE_CLIENT_ID": "@openfinance-client-id"
  },
  "functions": {
    "app/api/**/*.js": {
      "maxDuration": 30
    }
  },
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        {
          "key": "Access-Control-Allow-Origin",
          "value": "https://yourdomain.com"
        },
        {
          "key": "Access-Control-Allow-Methods",
          "value": "GET, POST, PUT, DELETE, OPTIONS"
        }
      ]
    }
  ]
}
```

### Railway Deployment

**Best For**: Node.js, Python, Go backend services with databases

<Steps>
  <Step title="Install Railway CLI">
    ```bash theme={null}
    npm install -g @railway/cli
    ```
  </Step>

  <Step title="Login and Initialize">
    ```bash theme={null}
    # Login to Railway
    railway login

    # Initialize project
    railway init

    # Link to existing project (optional)
    railway link [project-id]
    ```
  </Step>

  <Step title="Add Database (if needed)">
    ```bash theme={null}
    # Add PostgreSQL database
    railway add postgresql

    # Add Redis cache
    railway add redis

    # Add MySQL database
    railway add mysql
    ```
  </Step>

  <Step title="Configure Environment">
    ```bash theme={null}
    # Set environment variables
    railway variables set OPENFINANCE_CLIENT_ID=your_client_id
    railway variables set OPENFINANCE_CLIENT_SECRET=your_secret
    railway variables set NODE_ENV=production

    # Deploy application
    railway up
    ```
  </Step>
</Steps>

**Railway Configuration (`railway.json`)**:

```json theme={null}
{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "npm run build"
  },
  "deploy": {
    "startCommand": "npm start",
    "healthcheckPath": "/health",
    "healthcheckTimeout": 100,
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10
  }
}
```

## Full-Stack Deployment Examples

### React + Node.js + PostgreSQL

**Architecture**: Frontend (Vercel) + Backend (Railway) + Database (Railway PostgreSQL)

```bash theme={null}
# Frontend deployment (Vercel)
cd frontend
vercel --prod --env REACT_APP_API_URL=https://your-backend.railway.app

# Backend deployment (Railway)
cd ../backend
railway login
railway init
railway add postgresql
railway variables set DATABASE_URL=$RAILWAY_DATABASE_URL
railway variables set JWT_SECRET=your_jwt_secret
railway up
```

**Frontend Environment (`.env.production`)**:

```bash theme={null}
REACT_APP_API_URL=https://your-backend.railway.app
REACT_APP_WS_URL=wss://your-backend.railway.app
REACT_APP_OPENFINANCE_CLIENT_ID=your_client_id
```

**Backend Environment (Railway)**:

```bash theme={null}
NODE_ENV=production
DATABASE_URL=$RAILWAY_DATABASE_URL
OPENFINANCE_CLIENT_ID=your_client_id
OPENFINANCE_CLIENT_SECRET=your_secret
JWT_SECRET=your_jwt_secret
CORS_ORIGIN=https://your-frontend.vercel.app
```

### Next.js Full-Stack with Serverless

**Architecture**: Next.js (Vercel) + Serverless Functions + PlanetScale MySQL

```bash theme={null}
# Install dependencies
npm install @planetscale/database

# Deploy to Vercel with database
vercel --prod
```

**Next.js API Route (`pages/api/transactions.js`)**:

```javascript theme={null}
import { connect } from '@planetscale/database';

const config = {
  host: process.env.DATABASE_HOST,
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD
};

export default async function handler(req, res) {
  const conn = connect(config);

  try {
    if (req.method === 'GET') {
      const results = await conn.execute(
        'SELECT * FROM transactions WHERE user_id = ? ORDER BY date DESC LIMIT 20',
        [req.query.userId]
      );
      res.json(results.rows);
    } else if (req.method === 'POST') {
      const { amount, description, category } = req.body;
      await conn.execute(
        'INSERT INTO transactions (amount, description, category, user_id, date) VALUES (?, ?, ?, ?, NOW())',
        [amount, description, category, req.user.id]
      );
      res.json({ success: true });
    }
  } catch (error) {
    console.error('Database error:', error);
    res.status(500).json({ error: 'Database operation failed' });
  }
}
```

### Python FastAPI + PostgreSQL

**Architecture**: FastAPI (Render) + PostgreSQL (Render)

```bash theme={null}
# Deploy to Render
# Create render.yaml in project root
```

**Render Configuration (`render.yaml`)**:

```yaml theme={null}
databases:
  - name: openfinance-db
    databaseName: openfinance
    user: openfinance_user
    region: oregon

services:
  - type: web
    name: openfinance-api
    env: python
    buildCommand: "pip install -r requirements.txt"
    startCommand: "uvicorn main:app --host 0.0.0.0 --port $PORT"
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: openfinance-db
          property: connectionString
      - key: OPENFINANCE_CLIENT_ID
        value: your_client_id
      - key: OPENFINANCE_CLIENT_SECRET
        value: your_client_secret
```

**FastAPI Configuration (`main.py`)**:

```python theme={null}
from fastapi import FastAPI, Depends
from fastapi.middleware.cors import CORSMiddleware
import os

app = FastAPI(title="Open Finance API", version="1.0.0")

# CORS configuration
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "https://your-frontend.vercel.app",
        "http://localhost:3000"  # Development
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Database configuration
DATABASE_URL = os.getenv("DATABASE_URL")
if DATABASE_URL and DATABASE_URL.startswith("postgres://"):
    DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://", 1)

@app.get("/health")
async def health_check():
    return {"status": "healthy"}

@app.get("/")
async def root():
    return {"message": "Open Finance API"}
```

***

## 🏗️ Advanced Deployment Strategies

<Warning>
  **Advanced Topics - Beyond Hackathon Scope**

  The following sections cover production-grade deployment strategies that are **typically beyond hackathon needs**:

  * **Kubernetes**: Enterprise container orchestration (complex setup)
  * **Docker multi-stage builds**: Advanced containerization
  * **Custom infrastructure**: AWS/GCP/Azure manual configuration

  **For Hackathon**: Stick with the "Quick Deploy" section above unless your team has specific expertise in these areas. Judges value working demos over deployment complexity.
</Warning>

### Docker Containerization

**Multi-stage Dockerfile for Node.js**:

```dockerfile theme={null}
# Build stage
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# Production stage
FROM node:18-alpine AS production

WORKDIR /app

# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# Copy built application
COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder --chown=nextjs:nodejs /app/node_modules ./node_modules
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json

USER nextjs

EXPOSE 3000

ENV NODE_ENV=production
ENV PORT=3000

CMD ["npm", "start"]
```

**Docker Compose for Local Development**:

```yaml theme={null}
version: '3.8'

services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    environment:
      - REACT_APP_API_URL=http://localhost:8000
    depends_on:
      - backend

  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/openfinance
      - REDIS_URL=redis://redis:6379
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      POSTGRES_DB: openfinance
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:
```

### Kubernetes Deployment

**Kubernetes Manifests (`k8s/`)**:

```yaml theme={null}
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: openfinance-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: openfinance-api
  template:
    metadata:
      labels:
        app: openfinance-api
    spec:
      containers:
      - name: api
        image: your-registry/openfinance-api:latest
        ports:
        - containerPort: 8000
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: database-url
        - name: OPENFINANCE_CLIENT_SECRET
          valueFrom:
            secretKeyRef:
              name: app-secrets
              key: openfinance-secret
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        readinessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 30
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /health
            port: 8000
          initialDelaySeconds: 60
          periodSeconds: 30

---
apiVersion: v1
kind: Service
metadata:
  name: openfinance-api-service
spec:
  selector:
    app: openfinance-api
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8000
  type: LoadBalancer
```

## Security Best Practices

### Environment Variables Management

**Secure Environment Setup**:

```bash theme={null}
# Use environment-specific files
.env.local          # Local development (git-ignored)
.env.development    # Development environment
.env.staging        # Staging environment
.env.production     # Production environment (encrypted)

# Never commit secrets to git
echo ".env.local" >> .gitignore
echo ".env.production" >> .gitignore
```

**Environment Validation**:

```javascript theme={null}
// env-config.js
const requiredEnvVars = [
  'OPENFINANCE_CLIENT_ID',
  'OPENFINANCE_CLIENT_SECRET',
  'DATABASE_URL',
  'JWT_SECRET'
];

function validateEnvironment() {
  const missingVars = requiredEnvVars.filter(
    varName => !process.env[varName]
  );

  if (missingVars.length > 0) {
    console.error('Missing required environment variables:', missingVars);
    process.exit(1);
  }
}

validateEnvironment();
```

### SSL/TLS Configuration

**Nginx Reverse Proxy with SSL**:

```nginx theme={null}
server {
    listen 443 ssl http2;
    server_name api.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # Security headers
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_req zone=api burst=20 nodelay;

    location / {
        proxy_pass http://localhost:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # CORS headers
        add_header Access-Control-Allow-Origin "https://yourdomain.com";
        add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS";
        add_header Access-Control-Allow-Headers "Authorization, Content-Type";
    }
}
```

## Monitoring and Analytics

### Application Monitoring

**Health Check Endpoint**:

```javascript theme={null}
// health.js
const express = require('express');
const router = express.Router();

router.get('/health', async (req, res) => {
  const health = {
    status: 'healthy',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    environment: process.env.NODE_ENV
  };

  try {
    // Check database connection
    await db.query('SELECT 1');
    health.database = 'connected';

    // Check Redis connection
    await redis.ping();
    health.cache = 'connected';

    // Check external API
    const response = await fetch('https://api.openfinance.ae/health');
    health.openfinance_api = response.ok ? 'available' : 'unavailable';

    res.json(health);
  } catch (error) {
    health.status = 'unhealthy';
    health.error = error.message;
    res.status(500).json(health);
  }
});

module.exports = router;
```

**Logging Configuration**:

```javascript theme={null}
// logger.js
const winston = require('winston');

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  defaultMeta: { service: 'openfinance-api' },
  transports: [
    new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
    new winston.transports.File({ filename: 'logs/combined.log' })
  ]
});

if (process.env.NODE_ENV !== 'production') {
  logger.add(new winston.transports.Console({
    format: winston.format.simple()
  }));
}

module.exports = logger;
```

## Performance Optimization

### CDN and Caching

**Cloudflare Configuration**:

```javascript theme={null}
// cloudflare-worker.js
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)

  // Cache static assets for 1 year
  if (url.pathname.match(/\.(js|css|png|jpg|jpeg|gif|ico|svg)$/)) {
    const response = await fetch(request)
    const modifiedResponse = new Response(response.body, response)
    modifiedResponse.headers.set('Cache-Control', 'public, max-age=31536000')
    return modifiedResponse
  }

  // Cache API responses for 5 minutes
  if (url.pathname.startsWith('/api/')) {
    const cacheKey = request.url
    const cache = caches.default
    let response = await cache.match(cacheKey)

    if (!response) {
      response = await fetch(request)
      const modifiedResponse = new Response(response.body, response)
      modifiedResponse.headers.set('Cache-Control', 'public, max-age=300')
      event.waitUntil(cache.put(cacheKey, modifiedResponse.clone()))
      return modifiedResponse
    }

    return response
  }

  return fetch(request)
}
```

### Database Optimization

**Connection Pooling**:

```javascript theme={null}
// database.js
const { Pool } = require('pg');

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
  ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
  max: 20, // Maximum number of clients in the pool
  idleTimeoutMillis: 30000, // Close idle clients after 30 seconds
  connectionTimeoutMillis: 2000, // Return an error after 2 seconds if connection could not be established
});

// Optimized query with prepared statement
const getTransactions = async (userId, limit = 20, offset = 0) => {
  const query = `
    SELECT t.*, a.name as account_name
    FROM transactions t
    JOIN accounts a ON t.account_id = a.id
    WHERE a.user_id = $1
    ORDER BY t.date DESC
    LIMIT $2 OFFSET $3
  `;

  const result = await pool.query(query, [userId, limit, offset]);
  return result.rows;
};

module.exports = { pool, getTransactions };
```

## Cost Optimization

### Free Tier Combinations

**Budget-Friendly Stack**:

* **Frontend**: Vercel (Free: 100GB bandwidth, unlimited sites)
* **Backend**: Render (Free: 512MB RAM, sleeps after 15min inactivity)
* **Database**: PlanetScale (Free: 1 database, 1GB storage)
* **Cache**: Upstash Redis (Free: 10k requests/day)
* **Monitoring**: Better Stack (Free: 3 monitors)

**Estimated Monthly Cost**: \$0 for small hackathon projects

### Production Scaling Costs

**Medium-Scale Production**:

* **Frontend**: Vercel Pro (\$20/month)
* **Backend**: Railway Pro (\$20/month + usage)
* **Database**: Railway PostgreSQL (\$15/month)
* **CDN**: Cloudflare Pro (\$20/month)
* **Monitoring**: DataDog (\$15/month)

**Estimated Monthly Cost**: \$90-120 for production applications

## Troubleshooting Common Issues

### Deployment Failures

**Build Failures**:

```bash theme={null}
# Clear build cache
npm run clean
rm -rf node_modules package-lock.json
npm install

# Check build locally
npm run build

# Verify environment variables
vercel env ls
railway variables
```

**Memory Issues**:

```javascript theme={null}
// Optimize bundle size
// webpack.config.js
module.exports = {
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          reuseExistingChunk: true
        }
      }
    }
  }
};
```

<Warning>
  **Security Reminder**: Never commit API keys, secrets, or sensitive configuration to version control. Use environment variables and secure secret management.
</Warning>

<Tip>
  **Hackathon Strategy**: Start with free tiers (Vercel + Render/Railway) for rapid deployment, then upgrade to paid plans if your application gains traction.
</Tip>

## Quick Reference

### Deployment Checklist

* [ ] Environment variables configured
* [ ] Database migrations run
* [ ] SSL certificates configured
* [ ] Domain configured (if applicable)
* [ ] Health checks working
* [ ] Error monitoring setup
* [ ] Backup strategy in place
* [ ] Performance monitoring enabled

### Emergency Commands

```bash theme={null}
# Quick rollback (Vercel)
vercel rollback

# Check deployment logs (Railway)
railway logs

# Scale application (Heroku)
heroku ps:scale web=2

# Database backup (Railway)
railway run pg_dump $DATABASE_URL > backup.sql
```
