Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/budgetron-org/budgetron/llms.txt

Use this file to discover all available pages before exploring further.

This guide covers production deployment best practices, security hardening, monitoring, and operational procedures for running Budgetron at scale.

Production Checklist

Before deploying to production:
  • Set strong, unique secrets for AUTH_SECRET, CRON_SECRET_TOKEN
  • Configure SSL/TLS certificates (HTTPS)
  • Set up database backups
  • Configure monitoring and alerting
  • Review and restrict network access
  • Enable database connection pooling
  • Set up log aggregation
  • Configure rate limiting
  • Test disaster recovery procedures
  • Document deployment and rollback procedures

Security Hardening

Environment Variables

Never commit secrets to version control. Use secure secret management:

Generate Strong Secrets

# AUTH_SECRET (32+ bytes)
openssl rand -base64 32

# CRON_SECRET_TOKEN (hex format)
openssl rand -hex 32

# CRON_SECRET_SLUG
openssl rand -hex 16

Secret Management

Docker Secrets (Docker Swarm):
echo "your-secret" | docker secret create auth_secret -
services:
  app:
    secrets:
      - auth_secret
    environment:
      AUTH_SECRET_FILE: /run/secrets/auth_secret

secrets:
  auth_secret:
    external: true
Kubernetes Secrets:
kubectl create secret generic budgetron-secrets \
  --from-literal=AUTH_SECRET=$(openssl rand -base64 32) \
  --from-literal=DB_URL="postgres://..."
HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault for enterprise deployments.

Database Security

Connection Security

Use SSL for database connections:
DB_URL="postgres://user:pass@host:5432/db?sslmode=require"
SSL modes:
  • require - Requires SSL, no certificate verification
  • verify-ca - Requires SSL, verifies CA
  • verify-full - Requires SSL, verifies CA and hostname

Network Isolation

Restrict database access:
# PostgreSQL pg_hba.conf
host    budgetron    budgetron    10.0.0.0/8    scram-sha-256
Use private networks or VPC for database connections.

Database User Permissions

Create a limited database user:
-- Create user with minimal privileges
CREATE USER budgetron_app WITH PASSWORD 'secure_password';
GRANT CONNECT ON DATABASE budgetron TO budgetron_app;
GRANT USAGE ON SCHEMA public TO budgetron_app;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO budgetron_app;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO budgetron_app;

-- For migrations, use separate user
CREATE USER budgetron_migrate WITH PASSWORD 'different_password';
GRANT ALL PRIVILEGES ON DATABASE budgetron TO budgetron_migrate;

Application Security

Run as Non-Root User

Modify Dockerfile:
# Add before CMD
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
RUN chown -R nextjs:nodejs /app
USER nextjs

Read-Only Filesystem

Run container with read-only root:
docker run --read-only \
  --tmpfs /tmp \
  --tmpfs /app/.next/cache \
  budgetron

Security Headers

Next.js automatically sets security headers. Verify in next.config.ts:
const nextConfig: NextConfig = {
  headers: async () => [
    {
      source: '/:path*',
      headers: [
        { key: 'X-DNS-Prefetch-Control', value: 'on' },
        { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
        { key: 'X-Content-Type-Options', value: 'nosniff' },
        { key: 'Referrer-Policy', value: 'origin-when-cross-origin' },
      ],
    },
  ],
}

Network Security

Firewall Configuration

Use UFW (Ubuntu):
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp   # SSH
sudo ufw allow 80/tcp   # HTTP
sudo ufw allow 443/tcp  # HTTPS
sudo ufw enable

Rate Limiting

Configure Nginx rate limiting:
http {
    limit_req_zone $binary_remote_addr zone=budgetron:10m rate=10r/s;
    
    server {
        location / {
            limit_req zone=budgetron burst=20 nodelay;
            proxy_pass http://localhost:3000;
        }
    }
}

DDoS Protection

Use Cloudflare or AWS WAF for DDoS protection and CDN caching.

High Availability

Load Balancing

Run multiple Budgetron instances behind a load balancer:
# docker-compose.yml
services:
  app:
    image: ghcr.io/budgetron-org/budgetron:latest
    deploy:
      replicas: 3
      restart_policy:
        condition: on-failure
    environment:
      DB_URL: ${DB_URL}
      # ... other env vars

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - app
Nginx upstream configuration:
upstream budgetron {
    least_conn;
    server app:3000 max_fails=3 fail_timeout=30s;
    server app:3000 max_fails=3 fail_timeout=30s;
    server app:3000 max_fails=3 fail_timeout=30s;
}

server {
    listen 80;
    location / {
        proxy_pass http://budgetron;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
    }
}

Database High Availability

PostgreSQL Replication

Set up primary-replica replication:
# Primary
postgresql.conf:
  wal_level = replica
  max_wal_senders = 3
  
pg_hba.conf:
  host replication replicator 10.0.0.0/8 scram-sha-256

Managed Database Services

Use managed PostgreSQL for automatic failover:
  • AWS RDS with Multi-AZ
  • Google Cloud SQL with high availability
  • Azure Database for PostgreSQL with read replicas
  • DigitalOcean Managed Databases

Health Checks

Implement comprehensive health checks:
// app/api/health/route.ts
import { db } from '@/server/db'
import { NextResponse } from 'next/server'

export async function GET() {
  try {
    // Check database connectivity
    await db.execute('SELECT 1')
    
    return NextResponse.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      database: 'connected',
    })
  } catch (error) {
    return NextResponse.json(
      {
        status: 'unhealthy',
        error: error.message,
      },
      { status: 503 }
    )
  }
}
Docker health check:
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => { \
    if (r.statusCode !== 200) process.exit(1); \
    let data = ''; \
    r.on('data', chunk => data += chunk); \
    r.on('end', () => { \
      const json = JSON.parse(data); \
      process.exit(json.status === 'healthy' ? 0 : 1); \
    }); \
  }).on('error', () => process.exit(1))"

Monitoring and Observability

Logging

Structured Logging

Budgetron logs to stdout/stderr. Use a log aggregation service: Docker Compose with Loki:
services:
  app:
    logging:
      driver: loki
      options:
        loki-url: "http://localhost:3100/loki/api/v1/push"
        loki-retries: 5
Centralized Logging Services:
  • Datadog
  • New Relic
  • Papertrail
  • Logtail
  • ELK Stack (Elasticsearch, Logstash, Kibana)

Log Rotation

For standalone deployments:
# /etc/logrotate.d/budgetron
/var/log/budgetron/*.log {
    daily
    rotate 30
    compress
    delaycompress
    notifempty
    create 0640 budgetron budgetron
    sharedscripts
    postrotate
        pm2 reloadLogs
    endscript
}

Metrics

Application Metrics

Integrate Prometheus metrics:
// lib/metrics.ts
import { Registry, Counter, Histogram } from 'prom-client'

export const register = new Registry()

export const httpRequestDuration = new Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status'],
  registers: [register],
})

export const httpRequestTotal = new Counter({
  name: 'http_requests_total',
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'route', 'status'],
  registers: [register],
})
// app/api/metrics/route.ts
import { register } from '@/lib/metrics'
import { NextResponse } from 'next/server'

export async function GET() {
  const metrics = await register.metrics()
  return new NextResponse(metrics, {
    headers: { 'Content-Type': register.contentType },
  })
}

Database Metrics

Monitor PostgreSQL:
-- Active connections
SELECT count(*) FROM pg_stat_activity WHERE datname = 'budgetron';

-- Database size
SELECT pg_size_pretty(pg_database_size('budgetron'));

-- Slow queries
SELECT query, calls, total_time, mean_time 
FROM pg_stat_statements 
ORDER BY mean_time DESC 
LIMIT 10;
Use monitoring tools:
  • pgAdmin
  • pganalyze
  • pg_stat_statements extension

Infrastructure Metrics

Prometheus + Grafana:
services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana
    ports:
      - "3001:3000"
    volumes:
      - grafana_data:/var/lib/grafana
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin

Alerting

Health Check Monitoring

Use uptime monitoring:
  • UptimeRobot (free tier available)
  • Pingdom
  • Better Uptime
  • StatusCake

Custom Alerts

Prometheus alerting rules:
groups:
  - name: budgetron
    rules:
      - alert: HighErrorRate
        expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"
          description: "Error rate is {{ $value }} errors/second"

      - alert: DatabaseConnectionFailed
        expr: up{job="postgres"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Database connection failed"

Backup and Recovery

Database Backups

Automated Backup Script

#!/bin/bash
# /usr/local/bin/backup-budgetron.sh

set -e

# Configuration
BACKUP_DIR="/var/backups/budgetron"
S3_BUCKET="s3://my-backups/budgetron"
DB_URL="postgres://user:pass@localhost:5432/budgetron"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/budgetron_$DATE.sql.gz"

# Create backup directory
mkdir -p $BACKUP_DIR

# Dump database
echo "Starting backup at $(date)"
pg_dump "$DB_URL" | gzip > "$BACKUP_FILE"

# Verify backup
if [ -f "$BACKUP_FILE" ] && [ $(stat -f%z "$BACKUP_FILE") -gt 1000 ]; then
    echo "Backup created successfully: $BACKUP_FILE"
else
    echo "ERROR: Backup failed or is too small"
    exit 1
fi

# Upload to S3 (optional)
if command -v aws &> /dev/null; then
    echo "Uploading to S3..."
    aws s3 cp "$BACKUP_FILE" "$S3_BUCKET/"
fi

# Remove old backups
find $BACKUP_DIR -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed at $(date)"
Make executable and schedule:
chmod +x /usr/local/bin/backup-budgetron.sh
sudo crontab -e
# Daily backup at 2 AM
0 2 * * * /usr/local/bin/backup-budgetron.sh >> /var/log/budgetron-backup.log 2>&1

Point-in-Time Recovery (PITR)

Enable WAL archiving in PostgreSQL:
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'test ! -f /mnt/wal_archive/%f && cp %p /mnt/wal_archive/%f'
archive_timeout = 3600

Application State Backup

Budgetron is stateless, but back up:
  • Environment variables (securely)
  • Custom configurations
  • SSL certificates

Disaster Recovery

Recovery Procedure

  1. Restore Database:
gunzip -c budgetron_20260305_020000.sql.gz | psql "$DB_URL"
  1. Deploy Application:
docker run -d \
  --name budgetron \
  --env-file .env \
  -p 3000:3000 \
  ghcr.io/budgetron-org/budgetron:latest
  1. Verify:
curl http://localhost:3000/api/health

Test Recovery

Regularly test your recovery procedure:
# Test restoration to a separate database
createdb budgetron_test
gunzip -c latest_backup.sql.gz | psql budgetron_test

# Verify data integrity
psql budgetron_test -c "SELECT COUNT(*) FROM transactions;"

Performance Optimization

Database Optimization

Connection Pooling

Budgetron uses Drizzle ORM with connection pooling. Configure pool size:
// For high-traffic deployments
import { drizzle } from 'drizzle-orm/node-postgres'
import { Pool } from 'pg'

const pool = new Pool({
  connectionString: process.env.DB_URL,
  max: 20,           // Maximum pool size
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
})

export const db = drizzle(pool)

Database Indexes

Ensure proper indexes exist:
-- Example: Index on user transactions
CREATE INDEX idx_transactions_user_date ON transactions(user_id, date DESC);
CREATE INDEX idx_transactions_category ON transactions(category_id);

Query Optimization

Monitor slow queries:
-- Enable pg_stat_statements
CREATE EXTENSION pg_stat_statements;

-- Find slow queries
SELECT 
  query,
  calls,
  total_exec_time,
  mean_exec_time,
  max_exec_time
FROM pg_stat_statements
WHERE mean_exec_time > 100  -- queries taking >100ms
ORDER BY mean_exec_time DESC
LIMIT 20;

Application Optimization

Caching

Next.js App Router includes built-in caching. Configure cache headers:
export const revalidate = 3600  // Revalidate every hour

CDN Integration

Use a CDN for static assets:
  • Cloudflare
  • AWS CloudFront
  • Vercel Edge Network

Resource Limits

Set container resource limits:
services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

Deployment Strategies

Blue-Green Deployment

# Deploy new version (green)
docker run -d --name budgetron-green \
  --env-file .env \
  -p 3001:3000 \
  ghcr.io/budgetron-org/budgetron:latest

# Test green deployment
curl http://localhost:3001/api/health

# Switch traffic (update load balancer)
# If successful, remove blue
docker stop budgetron-blue
docker rm budgetron-blue

Rolling Updates

With Docker Swarm or Kubernetes:
docker service update \
  --image ghcr.io/budgetron-org/budgetron:v0.2.0 \
  --update-parallelism 1 \
  --update-delay 30s \
  budgetron

Rollback Procedure

# Docker
docker stop budgetron
docker run -d --name budgetron \
  --env-file .env \
  -p 3000:3000 \
  ghcr.io/budgetron-org/budgetron:v0.1.0  # Previous version

# Kubernetes
kubectl rollout undo deployment/budgetron

Compliance and Auditing

Audit Logging

Log all authentication and sensitive operations:
import { logger } from '@/lib/logger'

// Log authentication events
logger.info('User login', {
  userId: user.id,
  ip: request.ip,
  timestamp: new Date().toISOString(),
})

Data Privacy

  • Implement GDPR data export/deletion
  • Encrypt sensitive data at rest
  • Use TLS 1.3 for data in transit
  • Regular security audits

Compliance Checklist

  • Data encryption (at rest and in transit)
  • User data export functionality
  • User data deletion functionality
  • Audit logging
  • Access controls
  • Regular backups
  • Incident response plan

Next Steps

Build docs developers (and LLMs) love