Files
app/docs/superpowers/specs/2026-03-23-production-readiness-design.md
BOHA 4608494a3f initial commit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 08:46:51 +01:00

7.3 KiB

Production Readiness Audit — boha-app-ts

Date: 2026-03-23 Status: Approved Scope: Code hardening, security, validation, architecture refactor, testing, build preparation


Context

boha-app-ts is a TypeScript/Node.js migration of the PHP boha-app. Stack: Fastify backend, React frontend, Prisma ORM (MySQL), JWT + TOTP auth. The app will be deployed on an Ubuntu server alongside the existing PHP app, reusing the same MySQL database, nginx, and SSL setup.

This spec covers making the codebase production-ready. Deployment configuration (nginx, PM2, Ubuntu) is out of scope — this focuses purely on code quality, security, and build preparation.

Implementation Order

Sections must be executed in this order due to dependencies:

  1. Security Hardening — no dependencies, foundational
  2. Input Validation & TypeScript — no dependencies on (1), can overlap
  3. Service Layer Refactor — must complete before testing
  4. Testing — depends on services existing (tests target service layer)
  5. Production Build Preparation — last, especially migrations and graceful shutdown

1. Security Hardening

1.1 Secrets Management

  • Verify .env is in .gitignore and was never committed to git history
  • Create .env.example with placeholder values (no real secrets)
  • Document that production requires new JWT_SECRET and TOTP_ENCRYPTION_KEY
  • TOTP re-encryption script — see section 5.4 for implementation details

1.2 Rate Limiting

  • Global: 100 requests/min per IP (unchanged — sufficient for internal admin app)
  • Login endpoint (POST /api/admin/login): 20 requests/min per IP
  • All other endpoints: inherit global limit
  • Account lockout (5 failed attempts = 15 min lock) remains the primary brute-force defense
  • Rate limiting protects infrastructure, lockout protects accounts

1.3 Security Headers

Add to existing security middleware:

  • Content-Security-Policy — production only (dev mode needs relaxed policy for Vite HMR/eval)
    • Production: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'
    • Dev: no CSP (Vite injects scripts dynamically)
  • Permissions-Policy: camera=(), microphone=(), geolocation=()
  • Existing headers unchanged: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, HSTS (prod)

1.4 Request Body Limits

  • Global JSON body limit: 1MB via Fastify bodyLimit
  • Auth endpoints (login, refresh, TOTP): 10KB
  • Multipart (file uploads): 10MB (unchanged)

1.5 Timing-Safe Auth

  • When user not found during login, still run bcrypt.compare() against a dummy hash
  • Prevents timing-based username enumeration

2. Input Validation & TypeScript Strictness

2.1 Zod Validation

  • Install zod as dependency
  • Create validation schemas for all request bodies in src/schemas/
  • Schemas organized by domain: auth.schema.ts, users.schema.ts, offers.schema.ts, etc.
  • Replace all request.body as Record<string, unknown> with Zod parsing
  • Validation errors return 400 with field-level messages in Czech

2.2 TypeScript Strictness

  • Verify strict: true is already enabled in tsconfig.server.json
  • Eliminate remaining as Record<string, unknown> casts — replaced by Zod-inferred types
  • Remove any @ts-ignore or any usage
  • This step is effectively part of the Zod migration (2.1)

2.3 Error Response Consistency

  • All user-facing error messages in Czech
  • Every route uses error() / success() helpers
  • Proper HTTP status codes on all responses

3. Service Layer & Code Architecture

3.1 Service Extraction

Move business logic from route handlers into src/services/:

Service Responsibility
offers.service.ts CRUD, numbering, duplication
orders.service.ts CRUD, numbering, project creation
invoices.service.ts CRUD, stats, PDF data preparation
projects.service.ts CRUD, notes, numbering
users.service.ts CRUD, role assignment, password reset
attendance.service.ts Clock in/out, shift management
numbering.service.ts Shared number generation (orders + projects + offers)

Existing services (auth.ts, audit.ts) remain unchanged — already well structured.

3.2 Route Handler Pattern

After refactor, routes follow this pattern:

parse & validate input (Zod) → call service → return response

No business logic in route files.

3.3 Number Generation Consolidation

  • Move generateSharedNumber() from orders.ts into numbering.service.ts
  • Move offer MAX-based numbering into same service
  • Used by orders, projects, offers, and their next-number endpoints
  • The number_sequences table stays in the database — only the code location changes from src/utils/sequence.ts to src/services/numbering.service.ts

4. Testing

4.1 Stack

  • Vitest — test runner (compatible with existing Vite setup)
  • Supertest — HTTP integration testing
  • Real test database (no mocks)

4.2 Test Database Setup

  • Separate DATABASE_URL via .env.test pointing to a dedicated test database
  • Tests use transaction rollback for cleanup (each test runs in a transaction that rolls back)
  • Seed script for baseline test data (admin user, roles, permissions)

4.3 Test Coverage

Area Tests
Auth flow Login, TOTP verify, backup codes, token refresh, rotation, logout, lockout
Permissions Admin bypass, role-based access, forbidden responses
Number generation Offer, order, project shared sequence correctness
CRUD Create/read/update/delete for offers, orders, invoices
Edge cases Expired tokens, invalid TOTP, duplicate usernames, password validation

4.4 Not Testing

  • Frontend React components
  • Prisma query internals
  • Simple list/get endpoints with no business logic

4.5 Structure

src/__tests__/
  auth.test.ts
  permissions.test.ts
  offers.test.ts
  orders.test.ts
  invoices.test.ts
  numbering.test.ts

5. Production Build Preparation

5.1 Graceful Shutdown

  • Handle SIGTERM/SIGINT in server.ts
  • Close Fastify server (drain in-flight requests)
  • Disconnect Prisma client
  • Log shutdown events

5.2 Prisma Migration Strategy

  • Create baseline migration from existing schema using prisma migrate diff
  • All future schema changes go through versioned migration files
  • Never use db push in production

5.3 Environment Template

  • Create .env.example documenting all required variables with placeholder values
  • Mark which values must be regenerated for production (secrets)
  • Mark which values are deployment-specific (HOST, PORT, CORS_ORIGINS, NAS_PATH)

5.4 TOTP Re-encryption Script

  • Standalone script: scripts/rotate-totp-key.ts
  • Reads old key and new key from arguments
  • Decrypts all users.totp_secret with old key, re-encrypts with new key
  • Transaction-safe (all or nothing)
  • Dry-run mode for verification

5.5 Static File Serving

  • Production serves dist-client/ via @fastify/static (already a dependency)
  • Dev mode uses Vite middleware (already implemented)

5.6 Cleanup

  • Verify no unused dependencies in package.json
  • Ensure dist/ and dist-client/ are in .gitignore

Out of Scope

  • Nginx configuration
  • PM2 / process management setup
  • Ubuntu server provisioning
  • Frontend component refactoring
  • Database data migration from PHP app