JB/DEPLOYMENT.md

5.7 KiB

JobsBoard Platform — Production Deployment & Operational Architecture Guide

1. System Topology Overview

                     [ Internet / CDN (Cloudflare) ]
                                    │
                         HTTPS / TLS Termination
                                    │
                                    ▼
                         [ Next.js Application ]
                    (Docker Container / Node.js 20+)
                                    │
        ┌───────────────────────────┼───────────────────────────┐
        ▼                           ▼                           ▼
[ PostgreSQL 16+ ]       [ Upstash / Redis ]         [ S3 / Cloudflare R2 ]
Primary Relational DB    Distributed Rate Limiting   Private Candidate Files
(Foreign Keys & BOLA)    & Session Revocations       (Pre-signed downloads)

2. Infrastructure System States

Subsystem State Implementation / Configuration Details
Relational Database ACTIVE AND VERIFIED PostgreSQL 16 container actively running on localhost:5432 (jobsboard-postgres). Schema synchronized with 76 production indexes, cascades, and constraints. All 1,425 jobs, 400 companies, 9 users, 1 resume, and active applications imported and verified.
Multi-Tenant Ownership ACTIVE AND VERIFIED Strict foreign-key relationship (job.postedById === user.id OR job.companyId === user.companyId). String matching eliminated; scraped jobs cannot be claimed or manipulated by employers.
Session Invalidation ACTIVE AND VERIFIED Dynamic DB rehydration in getAuthUser(). Suspended accounts (lockedUntil > now) are immediately denied access on next HTTP request regardless of unexpired JWT token.
Distributed Rate Limiting IMPLEMENTED BUT NOT CONFIGURED Unified IRateLimiter with DistributedRedisRateLimiter (atomic INCR + EXPIRE over Upstash REST). Automatically activates when UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN are set. Falls back to in-memory store with 10k key eviction cap.
Object Storage IMPLEMENTED BUT NOT CONFIGURED IObjectStorage abstraction in lib/storage.ts. Local adapter stores files with UUID keys and strict path traversal sanitization (../../../etc/passwd -> etcpasswd). Production S3/R2 adapter activates when STORAGE_ACCESS_KEY & STORAGE_SECRET_KEY are provided.
Background Processing DEVELOPMENT ONLY In-memory asynchronous queue (lib/queue.ts) with exponential backoff retries and dead-letter log handling. Suitable for non-blocking local email and notification dispatches. Requires BullMQ/SQS for persistent distributed workers.

3. Environment Variables Specification

Create .env.production in the deployment environment:

# Database Connection (PostgreSQL 16+)
DATABASE_URL="postgresql://username:password@db-host.internal:5432/jobsboard?schema=public&sslmode=require"

# NextAuth Authentication
NEXTAUTH_URL="https://jobsboard.yourdomain.com"
NEXTAUTH_SECRET="generate-strong-64-character-crypto-hex-secret"

# Node Environment
NODE_ENV="production"
PORT=3000

# Distributed Rate Limiting (Upstash / Redis REST API)
UPSTASH_REDIS_REST_URL="https://your-redis-instance.upstash.io"
UPSTASH_REDIS_REST_TOKEN="your-upstash-rest-token"

# Object Storage (AWS S3, Cloudflare R2, MinIO)
STORAGE_ENDPOINT="https://<account-id>.r2.cloudflarestorage.com"
STORAGE_BUCKET="jobsboard-private-assets"
STORAGE_ACCESS_KEY="your-storage-access-key"
STORAGE_SECRET_KEY="your-storage-secret-key"

# Automated Cron & Job Alert Security Secret
CRON_SECRET="generate-strong-random-bearer-token-for-alerts"

# Outbound Email Service (Resend / AWS SES)
RESEND_API_KEY="re_your_api_key_here"
EMAIL_FROM="JobsBoard Talent Alerts <notifications@jobsboard.yourdomain.com>"

4. Production Database Migration & Restoration

Step 1: Initialize Database Schema

npx prisma db push --schema=prisma/schema.postgresql.prisma

Step 2: Restore Core Dataset (If Migrating Existing SQLite dev.db)

DATABASE_URL="postgresql://user:password@host:5432/jobsboard?schema=public" node scripts/import-postgres-data.js

Step 3: Run E2E Database & Multi-Tenant Tests

npm run test:postgres

5. Failure Modes & Resilience Policy

Failure Condition System Impact Degraded Behavior & Safeguards
PostgreSQL Outage Critical /api/health returns 503 Service Unavailable. Database queries fail fast; sensitive operations reject rather than expose unauthenticated resources.
Redis / Rate Limiter Down Medium DistributedRedisRateLimiter automatically degrades to high-throughput local memory limiter (MemoryRateLimiter). Sensitive endpoints remain bounded by local 10k LRU memory table.
Object Storage Unreachable Medium Resume download fallback serves generated PDF stream on-the-fly via PDFKit. /api/health reports degraded storage status.
Queue Worker Crash Low In-memory queue logs dead-letter events for retry upon container restart.

6. Disaster Recovery & Backup Plan

  1. Daily Automated Snapshots:
    # Daily PostgreSQL Logical Backup
    pg_dump -U postgres -h localhost -d jobsboard --format=custom --file="/backups/jobsboard_$(date +%Y%m%d_%H%M%S).dump"
    
  2. Restoration Procedure:
    pg_restore -U postgres -h localhost -d jobsboard --clean --if-exists "/backups/jobsboard_target.dump"
    
  3. Point-in-Time Recovery (PITR): Enable Write-Ahead Log (WAL) archiving in production cloud database providers (AWS RDS, Supabase, Neon, GCP Cloud SQL).