JB/DEPLOYMENT.md

113 lines
5.7 KiB
Markdown

# JobsBoard Platform — Production Deployment & Operational Architecture Guide
## 1. System Topology Overview
```text
[ 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:
```bash
# 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
```bash
npx prisma db push --schema=prisma/schema.postgresql.prisma
```
### Step 2: Restore Core Dataset (If Migrating Existing SQLite dev.db)
```bash
DATABASE_URL="postgresql://user:password@host:5432/jobsboard?schema=public" node scripts/import-postgres-data.js
```
### Step 3: Run E2E Database & Multi-Tenant Tests
```bash
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**:
```bash
# 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**:
```bash
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).