Files
internet-id/docker-compose.yml
Copilot 14014cb784 Production hardening: Remove deprecations, optimize chain queries, enforce explicit configuration (#134)
* Initial plan

* Fix onLimitReached deprecation in rate-limit middleware

- Replace deprecated onLimitReached callback with inline logging in handler
- Update tests to verify logging happens in the rate limit handler
- Remove onLimitReached from exports as it's no longer a separate function

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Fix fromBlock: 0 in event queries for better performance

- Replace fromBlock: 0 with smart default (last 1M blocks)
- Add REGISTRY_START_BLOCK env var for configurable starting block
- Update make-proof.ts, verification-jobs.routes.ts, and verification-queue.service.ts
- Document new env variable in .env.example

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Remove hardcoded testnet RPC fallback for production safety

- Replace testnet fallbacks with proper error handling when RPC_URL is not configured
- Update registry.service.ts, blockchain.service.ts to throw errors if RPC_URL missing
- Update CLI scripts (verify.ts, register.ts, make-proof.ts) to fail fast without RPC_URL
- Update API routes to return 503 error when RPC_URL is not configured
- Update .env.example to emphasize RPC_URL is required

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Add documentation for dual Prisma generators and pin Redis version

- Add comprehensive comments in schema.prisma explaining dual generator setup
- Document why both generators are needed (API vs Next.js web app)
- Pin Redis version to 7.2-alpine in all docker-compose files for reproducibility
- Update docker-compose.yml, docker-compose.production.yml, and docker-compose.staging.yml

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Address code review feedback - add validation for REGISTRY_START_BLOCK

- Add proper validation for parseInt to handle NaN cases
- Ensure REGISTRY_START_BLOCK is validated before use
- Add comment explaining intentional empty catch block
- Prevents invalid block numbers from breaking event queries

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Refactor block range validation into shared utility function

- Create block-range.util.ts with getStartBlock helper
- Extract duplicated validation logic from make-proof.ts, verification-jobs.routes.ts, and verification-queue.service.ts
- Improves code maintainability and ensures consistent validation
- Add comprehensive JSDoc documentation

Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>

* Add comprehensive test coverage for block-range utility

- Create test/utils/block-range.util.test.ts following existing test patterns
- Test valid REGISTRY_START_BLOCK values (positive, zero, large numbers)
- Test invalid inputs (NaN, negative, empty string, whitespace)
- Test default fallback behavior (current block - 1M)
- Test edge cases (low block numbers, decimals, provider errors)
- 15 test cases covering all code paths and validation logic

Co-authored-by: PatrickFanella <61631520+PatrickFanella@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: onnwee <211922112+onnwee@users.noreply.github.com>
Co-authored-by: PatrickFanella <61631520+PatrickFanella@users.noreply.github.com>
2026-02-16 19:25:50 -06:00

150 lines
4.2 KiB
YAML

version: "3.9"
services:
# Nginx reverse proxy with SSL/TLS termination
nginx:
image: nginx:1.25-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./ops/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./ops/nginx/conf.d/default.conf.template:/etc/nginx/templates/default.conf.template:ro
- certbot_www:/var/www/certbot:ro
- certbot_conf:/etc/letsencrypt:ro
- nginx_logs:/var/log/nginx
environment:
- DOMAIN=${DOMAIN:-localhost}
- NGINX_ENVSUBST_OUTPUT_DIR=/etc/nginx/conf.d
depends_on:
- api
- web
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
interval: 30s
timeout: 5s
retries: 3
# Certbot for SSL certificate management
certbot:
image: certbot/certbot:latest
volumes:
- certbot_www:/var/www/certbot
- certbot_conf:/etc/letsencrypt
- certbot_logs:/var/log/letsencrypt
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --webroot --webroot-path=/var/www/certbot; sleep 12h & wait $${!}; done;'"
depends_on:
- nginx
restart: unless-stopped
# Express API server
api:
build:
context: .
dockerfile: Dockerfile.api
environment:
- NODE_ENV=${NODE_ENV:-production}
- DATABASE_URL=${DATABASE_URL}
- API_KEY=${API_KEY}
- RPC_URL=${RPC_URL}
- IPFS_API_URL=${IPFS_API_URL}
- WEB3_STORAGE_TOKEN=${WEB3_STORAGE_TOKEN}
- PINATA_JWT=${PINATA_JWT}
- REDIS_URL=${REDIS_URL}
expose:
- "3001"
depends_on:
- db
- redis
restart: unless-stopped
# Next.js web application
web:
build:
context: ./web
dockerfile: Dockerfile
environment:
- NODE_ENV=${NODE_ENV:-production}
- NEXT_PUBLIC_API_BASE=${NEXT_PUBLIC_API_BASE:-https://${DOMAIN}/api}
- NEXT_PUBLIC_SITE_BASE=${NEXT_PUBLIC_SITE_BASE:-https://${DOMAIN}}
- NEXTAUTH_URL=${NEXTAUTH_URL:-https://${DOMAIN}}
- NEXTAUTH_SECRET=${NEXTAUTH_SECRET}
- DATABASE_URL=${DATABASE_URL}
expose:
- "3000"
depends_on:
- db
- api
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER:-internetid}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-internetid}
POSTGRES_DB: ${POSTGRES_DB:-internetid}
# Enable WAL archiving for point-in-time recovery
command: >
postgres
-c wal_level=replica
-c archive_mode=on
-c archive_command='test ! -f /var/lib/postgresql/backups/wal_archive/%f && cp %p /var/lib/postgresql/backups/wal_archive/%f'
ports:
- "5432:5432"
volumes:
- db_data:/var/lib/postgresql/data
- backup_data:/var/lib/postgresql/backups
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 5s
timeout: 5s
retries: 5
# Redis for queue and caching
redis:
image: redis:7.2-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
# Backup service for automated database backups
backup:
image: postgres:16-alpine
environment:
POSTGRES_HOST: db
POSTGRES_PORT: 5432
POSTGRES_USER: ${POSTGRES_USER:-internetid}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-internetid}
POSTGRES_DB: ${POSTGRES_DB:-internetid}
BACKUP_DIR: /var/lib/postgresql/backups
RETENTION_DAYS: ${RETENTION_DAYS:-30}
S3_BUCKET: ${S3_BUCKET:-}
S3_REGION: ${S3_REGION:-us-east-1}
volumes:
- backup_data:/var/lib/postgresql/backups
- ./ops/backup:/opt/backup-scripts:ro
depends_on:
db:
condition: service_healthy
entrypoint: /bin/sh
# Run backup script on startup (for testing), in production use cron
command: -c "apk add --no-cache bash && while true; do /opt/backup-scripts/backup-database.sh full; sleep 86400; done"
restart: unless-stopped
volumes:
db_data:
backup_data:
redis_data:
certbot_www:
certbot_conf:
certbot_logs:
nginx_logs: