forgehive 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +631 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +6265 -0
  4. package/dist/confirm.d.ts +1 -0
  5. package/dist/confirm.js +15 -0
  6. package/dist/fulfillment-catalog.d.ts +10 -0
  7. package/dist/fulfillment-catalog.js +119 -0
  8. package/dist/lookup-table.d.ts +16 -0
  9. package/dist/lookup-table.js +128 -0
  10. package/dist/rollback.d.ts +1 -0
  11. package/dist/rollback.js +9 -0
  12. package/dist/scanner.d.ts +2 -0
  13. package/dist/scanner.js +87 -0
  14. package/dist/types.d.ts +13 -0
  15. package/dist/types.js +1 -0
  16. package/dist/update.d.ts +7 -0
  17. package/dist/update.js +42 -0
  18. package/dist/writer.d.ts +3 -0
  19. package/dist/writer.js +63 -0
  20. package/forgehive/agents/eli.yaml +8 -0
  21. package/forgehive/agents/kai.yaml +8 -0
  22. package/forgehive/agents/nora.yaml +8 -0
  23. package/forgehive/agents/remy.yaml +8 -0
  24. package/forgehive/agents/sam.yaml +8 -0
  25. package/forgehive/agents/suki.yaml +8 -0
  26. package/forgehive/agents/vera.yaml +24 -0
  27. package/forgehive/agents/viktor.yaml +8 -0
  28. package/forgehive/commands/fh-hotfix.md +16 -0
  29. package/forgehive/commands/fh-review.md +16 -0
  30. package/forgehive/commands/fh-ship.md +18 -0
  31. package/forgehive/commands/fh-start-task.md +13 -0
  32. package/forgehive/hooks/guardrails.sh +17 -0
  33. package/forgehive/party/defaults.yaml +21 -0
  34. package/forgehive/skills/INDEX.yaml +64 -0
  35. package/forgehive/skills/expert/.gitkeep +0 -0
  36. package/forgehive/skills/expert/api-design.md +77 -0
  37. package/forgehive/skills/expert/auth-security.md +80 -0
  38. package/forgehive/skills/expert/clean-architecture.md +83 -0
  39. package/forgehive/skills/expert/code-review.md +81 -0
  40. package/forgehive/skills/expert/database-patterns.md +81 -0
  41. package/forgehive/skills/expert/error-handling.md +90 -0
  42. package/forgehive/skills/expert/gdpr-compliance.md +64 -0
  43. package/forgehive/skills/expert/git-conventions.md +84 -0
  44. package/forgehive/skills/expert/monorepo-patterns.md +91 -0
  45. package/forgehive/skills/expert/observability.md +98 -0
  46. package/forgehive/skills/expert/owasp-top10.md +153 -0
  47. package/forgehive/skills/expert/performance-patterns.md +79 -0
  48. package/forgehive/skills/expert/security-checklist.md +70 -0
  49. package/forgehive/skills/expert/testing-strategies.md +74 -0
  50. package/forgehive/skills/expert/typescript-patterns.md +62 -0
  51. package/forgehive/skills/templates/.gitkeep +0 -0
  52. package/forgehive/templates/claude-md.block.md +62 -0
  53. package/package.json +30 -0
@@ -0,0 +1,64 @@
1
+ # GDPR-Compliant Coding Patterns
2
+
3
+ ## Core Principles (Art. 5 GDPR)
4
+
5
+ | Principle | Implementation |
6
+ |-----------|---------------|
7
+ | Lawfulness, fairness, transparency | Consent records, privacy notices |
8
+ | Purpose limitation | Separate schemas per data use |
9
+ | Data minimisation | Collect only what's needed |
10
+ | Accuracy | Update mechanisms, validation |
11
+ | Storage limitation | Retention policies, automatic deletion |
12
+ | Integrity & confidentiality | Encryption, access control |
13
+ | Accountability | Audit logs |
14
+
15
+ ---
16
+
17
+ ## PII Data Classification
18
+
19
+ ```typescript
20
+ type PiiCategory =
21
+ | "DIRECT_IDENTIFIER" // name, email, NIN, passport
22
+ | "QUASI_IDENTIFIER" // DOB, postcode, gender
23
+ | "SENSITIVE_SPECIAL" // health, biometric, race, religion (Art. 9)
24
+ | "FINANCIAL" // IBAN, card numbers
25
+ | "BEHAVIORAL" // browsing history, location traces
26
+ | "NONE";
27
+ ```
28
+
29
+ ---
30
+
31
+ ## Right to Erasure (Art. 17)
32
+
33
+ ```typescript
34
+ export async function eraseUserData(db: Database, userId: string): Promise<void> {
35
+ // 1. Anonymize user record (don't delete if referenced by orders etc.)
36
+ await db.users.update({
37
+ where: { id: userId },
38
+ data: {
39
+ email: `deleted-${userId}@erasure.invalid`,
40
+ name: "Deleted User",
41
+ deletedAt: new Date(),
42
+ },
43
+ });
44
+ // 2. Delete personally identifiable child records
45
+ await db.addresses.deleteMany({ where: { userId } });
46
+ await db.sessions.deleteMany({ where: { userId } });
47
+ // 3. Log the erasure (keep audit trail even without PII)
48
+ await db.erasureLog.create({ data: { userId, erasedAt: new Date() } });
49
+ }
50
+ ```
51
+
52
+ ---
53
+
54
+ ## GDPR Checklist for New Features
55
+
56
+ - [ ] Lawful basis for processing defined
57
+ - [ ] Data minimised — only collect what's needed
58
+ - [ ] Retention period defined and enforced
59
+ - [ ] Data encrypted at rest (Art. 9 special categories)
60
+ - [ ] Access controls in place
61
+ - [ ] Processing documented in data register
62
+ - [ ] Erasure endpoint handles this data
63
+ - [ ] Privacy notice updated
64
+ - [ ] DPIA completed if high risk (Art. 35)
@@ -0,0 +1,84 @@
1
+ # Git Conventions
2
+
3
+ ## Commit Messages (Conventional Commits)
4
+
5
+ ```
6
+ <type>(<scope>): <short description>
7
+
8
+ [optional body — wrap at 72 chars]
9
+
10
+ [optional footer: BREAKING CHANGE, Closes #123]
11
+ ```
12
+
13
+ **Types:**
14
+
15
+ | Type | When |
16
+ |---|---|
17
+ | `feat` | New feature |
18
+ | `fix` | Bug fix |
19
+ | `chore` | Build, deps, config (no code change) |
20
+ | `refactor` | Code change without feature/fix |
21
+ | `test` | Adding/fixing tests |
22
+ | `docs` | Documentation only |
23
+ | `perf` | Performance improvement |
24
+ | `ci` | CI/CD changes |
25
+
26
+ **Rules:**
27
+ - Imperative mood: "add" not "added", "fix" not "fixes"
28
+ - No period at end of subject line
29
+ - Subject ≤ 72 chars
30
+ - Body explains WHY, not what (the diff shows what)
31
+
32
+ ## Branch Naming
33
+
34
+ ```
35
+ feat/user-authentication
36
+ fix/login-redirect-loop
37
+ chore/upgrade-dependencies
38
+ refactor/extract-auth-middleware
39
+ ```
40
+
41
+ ## Workflow
42
+
43
+ ```
44
+ main (protected)
45
+ └── feat/my-feature
46
+ ├── commit: feat: add login form
47
+ ├── commit: test: add login form tests
48
+ └── PR → squash merge to main
49
+ ```
50
+
51
+ - Work on feature branches — never directly on `main`
52
+ - Keep branches short-lived (days, not weeks)
53
+ - Squash merge for features, merge commit for releases
54
+
55
+ ## Good Commit Habits
56
+
57
+ - One logical change per commit (atomic)
58
+ - Green tests before committing
59
+ - `git add -p` for partial staging when you changed multiple things
60
+ - `git commit --fixup` for small corrections before push
61
+
62
+ ## PR Description Template
63
+
64
+ ```markdown
65
+ ## What
66
+ [1-2 sentences: what changed]
67
+
68
+ ## Why
69
+ [motivation, ticket link]
70
+
71
+ ## Test Plan
72
+ - [ ] Unit tests added/updated
73
+ - [ ] Smoke tested locally
74
+ ```
75
+
76
+ ## Anti-Patterns
77
+
78
+ | Avoid | Why |
79
+ |---|---|
80
+ | "WIP", "fix", "asdf" commits | Meaningless history |
81
+ | 1000-line commits | Hard to review, hard to bisect |
82
+ | `git push --force` on shared branches | Rewrites shared history |
83
+ | Committing generated files | Noise, conflicts |
84
+ | Committing secrets | Permanent in history |
@@ -0,0 +1,91 @@
1
+ # Monorepo Patterns
2
+
3
+ ## When to Use a Monorepo
4
+
5
+ Use when packages share code, have coordinated releases, or need atomic cross-package changes. Don't use just because you have multiple services — separate repos are fine for fully independent teams.
6
+
7
+ ## Structure
8
+
9
+ ```
10
+ packages/
11
+ core/ ← shared domain types, utilities
12
+ api/ ← backend service
13
+ web/ ← frontend app
14
+ cli/ ← command-line tool
15
+ apps/ ← deployable applications (thin, import from packages)
16
+ tools/ ← internal scripts, generators
17
+ package.json ← workspaces config
18
+ turbo.json ← build orchestration (if using Turborepo)
19
+ ```
20
+
21
+ ## Workspace Setup (npm/pnpm)
22
+
23
+ ```json
24
+ // root package.json
25
+ {
26
+ "workspaces": ["packages/*", "apps/*"],
27
+ "scripts": {
28
+ "build": "turbo build",
29
+ "test": "turbo test",
30
+ "lint": "turbo lint"
31
+ }
32
+ }
33
+ ```
34
+
35
+ ## Package Boundaries
36
+
37
+ ```typescript
38
+ // packages/core/index.ts — explicit public API
39
+ export type { User, Order, Money };
40
+ export { parseConfig } from "./config.ts";
41
+ // Don't export internal helpers
42
+
43
+ // packages/api/src/service.ts
44
+ import { User } from "@company/core"; // ✅ use workspace package
45
+ import { helper } from "../../../core/src/internal"; // ❌ bypass boundary
46
+ ```
47
+
48
+ ## Dependency Management
49
+
50
+ - Hoist shared dev dependencies to root
51
+ - Keep runtime deps in each package (visibility)
52
+ - Use `workspace:*` protocol for internal deps
53
+
54
+ ```json
55
+ // packages/api/package.json
56
+ {
57
+ "dependencies": {
58
+ "@company/core": "workspace:*",
59
+ "express": "^4.18"
60
+ }
61
+ }
62
+ ```
63
+
64
+ ## Build Order
65
+
66
+ Turborepo / Nx handle this with task graphs:
67
+ ```json
68
+ // turbo.json
69
+ {
70
+ "pipeline": {
71
+ "build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
72
+ "test": { "dependsOn": ["build"] }
73
+ }
74
+ }
75
+ ```
76
+
77
+ ## CI Strategy
78
+
79
+ - Cache build artifacts by content hash
80
+ - Run only affected packages on PR: `turbo run test --filter=[HEAD^1]`
81
+ - Full build on merge to main
82
+
83
+ ## Anti-Patterns
84
+
85
+ | Avoid | Why |
86
+ |---|---|
87
+ | Circular package dependencies | Build order impossible |
88
+ | Importing internal paths across packages | Bypasses public API |
89
+ | One giant `packages/shared` | Becomes a dumping ground |
90
+ | Versioning each package independently | Defeats coordination benefits |
91
+ | No build cache | CI takes 20min for every change |
@@ -0,0 +1,98 @@
1
+ # Observability
2
+
3
+ ## Three Pillars
4
+
5
+ | Pillar | What | Tool examples |
6
+ |---|---|---|
7
+ | Logs | What happened | Winston, Pino, Datadog |
8
+ | Metrics | How much / how fast | Prometheus, Datadog |
9
+ | Traces | Where time was spent | OpenTelemetry, Jaeger |
10
+
11
+ ## Structured Logging
12
+
13
+ ```typescript
14
+ // ✅ Structured — queryable, filterable
15
+ log.info("user.login", { userId, ip, duration_ms: 45, success: true });
16
+
17
+ // ❌ String interpolation — unsearchable
18
+ console.log(`User ${userId} logged in from ${ip} in 45ms`);
19
+ ```
20
+
21
+ **Log Levels:**
22
+
23
+ | Level | When |
24
+ |---|---|
25
+ | `error` | Something broke — requires action |
26
+ | `warn` | Unexpected but handled |
27
+ | `info` | Key business events (login, purchase, deploy) |
28
+ | `debug` | Detailed flow for troubleshooting (not in prod) |
29
+
30
+ **Never log:** passwords, tokens, PII, full request bodies with secrets.
31
+
32
+ ## Metrics to Track
33
+
34
+ **RED Method** (for services):
35
+ - **R**ate — requests per second
36
+ - **E**rrors — error rate (%)
37
+ - **D**uration — latency (p50, p95, p99)
38
+
39
+ **USE Method** (for infrastructure):
40
+ - **U**tilization — CPU/memory/disk %
41
+ - **S**aturation — queue depth, wait time
42
+ - **E**rrors — hardware/kernel errors
43
+
44
+ ## OpenTelemetry (Node.js)
45
+
46
+ ```typescript
47
+ import { trace } from "@opentelemetry/api";
48
+
49
+ const tracer = trace.getTracer("my-service");
50
+
51
+ async function processOrder(orderId: string) {
52
+ const span = tracer.startSpan("processOrder");
53
+ span.setAttribute("order.id", orderId);
54
+
55
+ try {
56
+ await doWork(orderId);
57
+ span.setStatus({ code: SpanStatusCode.OK });
58
+ } catch (err) {
59
+ span.recordException(err as Error);
60
+ span.setStatus({ code: SpanStatusCode.ERROR });
61
+ throw err;
62
+ } finally {
63
+ span.end();
64
+ }
65
+ }
66
+ ```
67
+
68
+ ## Alerting
69
+
70
+ - Alert on symptoms (high error rate, slow responses), not causes
71
+ - Every alert must have a runbook
72
+ - PagerDuty for P1/P2 (revenue impact, data loss risk)
73
+ - Slack for P3/P4 (degraded, not down)
74
+ - Alert fatigue = ignored alerts = missed incidents
75
+
76
+ ## Health Endpoints
77
+
78
+ ```typescript
79
+ // Liveness: is the process alive?
80
+ app.get("/health/live", (req, res) => res.json({ status: "ok" }));
81
+
82
+ // Readiness: can it serve traffic?
83
+ app.get("/health/ready", async (req, res) => {
84
+ const dbOk = await db.ping().then(() => true).catch(() => false);
85
+ if (!dbOk) return res.status(503).json({ status: "not ready", db: false });
86
+ res.json({ status: "ok", db: true });
87
+ });
88
+ ```
89
+
90
+ ## Anti-Patterns
91
+
92
+ | Avoid | Why |
93
+ |---|---|
94
+ | `console.log` in production | No structure, no log level, no context |
95
+ | Logging every function entry/exit | Noise drowns signal |
96
+ | Metrics without dashboards | Data no one looks at |
97
+ | Alerting on causes (`cpu > 80%`) | Noisy, doesn't map to user impact |
98
+ | No correlation IDs | Can't trace a request across services |
@@ -0,0 +1,153 @@
1
+ # OWASP Top 10 — Security Patterns for Node.js/TypeScript
2
+
3
+ ## Overview
4
+
5
+ This skill covers the OWASP Top 10 (2021) vulnerability categories with detection
6
+ patterns and remediation examples in TypeScript/Node.js.
7
+
8
+ ---
9
+
10
+ ## A01: Broken Access Control
11
+
12
+ **Risk:** Users can act outside their intended permissions.
13
+
14
+ **Detection patterns:**
15
+ - Missing authorization checks before database queries
16
+ - Direct object references using user-supplied IDs without ownership verification
17
+ - CORS misconfiguration allowing all origins
18
+
19
+ **Vulnerable:**
20
+ ```typescript
21
+ // ❌ No ownership check
22
+ app.get("/documents/:id", authenticate, async (req, res) => {
23
+ const doc = await db.documents.findById(req.params.id);
24
+ res.json(doc);
25
+ });
26
+ ```
27
+
28
+ **Secure:**
29
+ ```typescript
30
+ // ✅ Verify ownership
31
+ app.get("/documents/:id", authenticate, async (req, res) => {
32
+ const doc = await db.documents.findOne({
33
+ _id: req.params.id,
34
+ ownerId: req.user.id,
35
+ });
36
+ if (!doc) return res.status(404).json({ error: "Not found" });
37
+ res.json(doc);
38
+ });
39
+ ```
40
+
41
+ ---
42
+
43
+ ## A02: Cryptographic Failures
44
+
45
+ **Risk:** Sensitive data exposed due to weak or missing encryption.
46
+
47
+ **Detection patterns:**
48
+ - `MD5` or `SHA1` for password hashing
49
+ - Sensitive data in plaintext
50
+ - Weak JWT secrets
51
+
52
+ **Vulnerable:**
53
+ ```typescript
54
+ // ❌ MD5 not suitable for passwords
55
+ const hash = crypto.createHash("md5").update(password).digest("hex");
56
+ ```
57
+
58
+ **Secure:**
59
+ ```typescript
60
+ // ✅ Use bcrypt for passwords
61
+ import bcrypt from "bcrypt";
62
+ const hash = await bcrypt.hash(password, 12);
63
+ ```
64
+
65
+ ---
66
+
67
+ ## A03: Injection
68
+
69
+ **Risk:** Untrusted data sent to an interpreter as part of a command or query.
70
+
71
+ **Vulnerable:**
72
+ ```typescript
73
+ // ❌ SQL injection
74
+ const rows = await db.query(`SELECT * FROM users WHERE email = '${req.body.email}'`);
75
+ ```
76
+
77
+ **Secure:**
78
+ ```typescript
79
+ // ✅ Parameterized queries
80
+ const rows = await db.query("SELECT * FROM users WHERE email = $1", [req.body.email]);
81
+ ```
82
+
83
+ ---
84
+
85
+ ## A04: Insecure Design
86
+
87
+ **Checklist:**
88
+ - [ ] Threat model for sensitive flows
89
+ - [ ] Rate limiting on public endpoints
90
+ - [ ] Business logic validated server-side
91
+
92
+ ---
93
+
94
+ ## A05: Security Misconfiguration
95
+
96
+ **Secure Express setup:**
97
+ ```typescript
98
+ import helmet from "helmet";
99
+ app.use(helmet());
100
+ app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(",") ?? [] }));
101
+ ```
102
+
103
+ ---
104
+
105
+ ## A06: Vulnerable and Outdated Components
106
+
107
+ ```bash
108
+ npm audit
109
+ fh security deps
110
+ ```
111
+
112
+ ---
113
+
114
+ ## A07: Identification and Authentication Failures
115
+
116
+ **Secure JWT:**
117
+ ```typescript
118
+ const token = jwt.sign({ userId }, JWT_SECRET, { expiresIn: "15m" });
119
+ ```
120
+
121
+ ---
122
+
123
+ ## A08: Software and Data Integrity Failures
124
+
125
+ - Verify npm package integrity with `npm audit`
126
+ - Use lockfiles (`package-lock.json`)
127
+ - Pin dependencies in production
128
+
129
+ ---
130
+
131
+ ## A09: Security Logging and Monitoring Failures
132
+
133
+ ```typescript
134
+ // Log security events
135
+ fh security audit
136
+ ```
137
+
138
+ ---
139
+
140
+ ## A10: Server-Side Request Forgery (SSRF)
141
+
142
+ **Vulnerable:**
143
+ ```typescript
144
+ // ❌ Fetch user-controlled URL
145
+ const data = await fetch(req.body.url);
146
+ ```
147
+
148
+ **Secure:**
149
+ ```typescript
150
+ // ✅ Validate URL against allowlist
151
+ const allowed = new URL(req.body.url);
152
+ if (!ALLOWED_HOSTS.includes(allowed.hostname)) throw new Error("Blocked");
153
+ ```
@@ -0,0 +1,79 @@
1
+ # Performance Patterns
2
+
3
+ ## Measure First
4
+
5
+ Never optimize without data. Profile before you guess.
6
+
7
+ ```bash
8
+ # Node.js profiling
9
+ node --prof app.js
10
+ node --prof-process isolate-*.log
11
+
12
+ # Simple timing
13
+ console.time("operation");
14
+ await heavyOperation();
15
+ console.timeEnd("operation");
16
+ ```
17
+
18
+ ## Database
19
+
20
+ **The N+1 Problem:**
21
+ ```typescript
22
+ // ❌ N+1: 1 query for posts + N queries for authors
23
+ const posts = await db.posts.findMany();
24
+ for (const post of posts) {
25
+ post.author = await db.users.findById(post.authorId); // N queries
26
+ }
27
+
28
+ // ✅ 1 query with JOIN or 2 queries with batch load
29
+ const posts = await db.posts.findMany({ include: { author: true } });
30
+ ```
31
+
32
+ **Indexing:**
33
+ - Index foreign keys and columns used in WHERE, ORDER BY
34
+ - Composite indexes: column order matters (most selective first)
35
+ - Check `EXPLAIN ANALYZE` for slow queries
36
+
37
+ **Pagination:** Always paginate large result sets — never `SELECT *` without `LIMIT`.
38
+
39
+ ## Caching
40
+
41
+ ```typescript
42
+ // Cache expensive computations
43
+ const cache = new Map<string, { data: T; expires: number }>();
44
+
45
+ function cached<T>(key: string, ttlMs: number, fn: () => Promise<T>): Promise<T> {
46
+ const hit = cache.get(key);
47
+ if (hit && Date.now() < hit.expires) return Promise.resolve(hit.data);
48
+ return fn().then(data => { cache.set(key, { data, expires: Date.now() + ttlMs }); return data; });
49
+ }
50
+ ```
51
+
52
+ Cache at the right layer: HTTP (CDN/ETag), application (Redis), DB (query cache).
53
+
54
+ ## Async / Concurrency
55
+
56
+ ```typescript
57
+ // ❌ Sequential when parallel is possible
58
+ const user = await getUser(id);
59
+ const prefs = await getPrefs(id);
60
+
61
+ // ✅ Parallel
62
+ const [user, prefs] = await Promise.all([getUser(id), getPrefs(id)]);
63
+ ```
64
+
65
+ ## Bundle Size (Frontend)
66
+
67
+ - Code splitting: lazy-load routes and heavy components
68
+ - Tree shaking: named imports only (`import { fn } from "lib"`)
69
+ - Analyze: `npx source-map-explorer dist/*.js`
70
+
71
+ ## Anti-Patterns
72
+
73
+ | Avoid | Why |
74
+ |---|---|
75
+ | Premature optimization | Adds complexity for imaginary gains |
76
+ | Synchronous I/O in async context | Blocks event loop |
77
+ | Loading all records into memory | OOM on large datasets |
78
+ | Polling every 100ms | Use webhooks or SSE instead |
79
+ | Re-fetching uncached data on every render | Stale-while-revalidate pattern |
@@ -0,0 +1,70 @@
1
+ # Security Checklist
2
+
3
+ ## Input Validation (OWASP Top 10 — A03)
4
+
5
+ - [ ] Validate all input at the boundary (type, length, format, range)
6
+ - [ ] Use allowlist validation, not denylist
7
+ - [ ] Sanitize before storing, escape before rendering
8
+ - [ ] Never trust user-controlled data in SQL, shell commands, file paths
9
+
10
+ ```typescript
11
+ // Parameterized queries — never string interpolation
12
+ const user = await db.query("SELECT * FROM users WHERE id = $1", [userId]);
13
+
14
+ // Path traversal prevention
15
+ const safe = path.resolve(baseDir, userInput);
16
+ if (!safe.startsWith(baseDir)) throw new ForbiddenError();
17
+ ```
18
+
19
+ ## Authentication & Authorization
20
+
21
+ - [ ] Passwords: bcrypt/argon2 (never MD5/SHA1), min 12 chars
22
+ - [ ] Sessions: HttpOnly, Secure, SameSite=Strict cookies
23
+ - [ ] JWT: verify signature + expiry, short-lived access tokens
24
+ - [ ] Check authorization on every request — don't rely on UI hiding
25
+ - [ ] Rate limit auth endpoints (login, password reset, OTP)
26
+
27
+ ## Secrets Management
28
+
29
+ - [ ] Never hardcode secrets in source code
30
+ - [ ] Use env vars for config — never `.env` files in production
31
+ - [ ] Rotate secrets regularly; revoke on any exposure
32
+ - [ ] Secrets in logs? Redact them.
33
+
34
+ ```typescript
35
+ // ✅ Safe logging
36
+ log.info("request", { userId, endpoint }); // no token
37
+
38
+ // ❌ Never
39
+ log.info("auth", { token: req.headers.authorization });
40
+ ```
41
+
42
+ ## Dependencies
43
+
44
+ - [ ] `npm audit` before every release
45
+ - [ ] Pin major versions in production
46
+ - [ ] Review changelogs for security advisories when upgrading
47
+ - [ ] Remove unused dependencies
48
+
49
+ ## HTTP Security Headers
50
+
51
+ ```typescript
52
+ // Minimum set for web APIs
53
+ res.setHeader("X-Content-Type-Options", "nosniff");
54
+ res.setHeader("X-Frame-Options", "DENY");
55
+ res.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
56
+ res.setHeader("Content-Security-Policy", "default-src 'none'");
57
+ ```
58
+
59
+ ## Error Responses
60
+
61
+ - [ ] Never expose stack traces to clients
62
+ - [ ] Generic error messages in production (log details server-side)
63
+ - [ ] Consistent error format (don't leak internal structure)
64
+
65
+ ## Data
66
+
67
+ - [ ] Encrypt sensitive data at rest (PII, payment info)
68
+ - [ ] TLS everywhere in transit
69
+ - [ ] Minimal data collection — don't store what you don't need
70
+ - [ ] GDPR: deletion capability, data export capability