initial commit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
196
docs/superpowers/specs/2026-03-23-production-readiness-design.md
Normal file
196
docs/superpowers/specs/2026-03-23-production-readiness-design.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user