5.7 KiB
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
- 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" - Restoration Procedure:
pg_restore -U postgres -h localhost -d jobsboard --clean --if-exists "/backups/jobsboard_target.dump" - Point-in-Time Recovery (PITR): Enable Write-Ahead Log (WAL) archiving in production cloud database providers (AWS RDS, Supabase, Neon, GCP Cloud SQL).