@thierrynakoa/fire-flow 10.0.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.
- package/.claude-plugin/plugin.json +64 -0
- package/ARCHITECTURE-DIAGRAM.md +440 -0
- package/COMMAND-REFERENCE.md +172 -0
- package/DOMINION-FLOW-OVERVIEW.md +421 -0
- package/LICENSE +21 -0
- package/QUICK-START.md +351 -0
- package/README.md +398 -0
- package/TROUBLESHOOTING.md +264 -0
- package/agents/fire-codebase-mapper.md +484 -0
- package/agents/fire-debugger.md +535 -0
- package/agents/fire-executor.md +949 -0
- package/agents/fire-fact-checker.md +276 -0
- package/agents/fire-learncoding-explainer.md +237 -0
- package/agents/fire-learncoding-walker.md +147 -0
- package/agents/fire-planner.md +675 -0
- package/agents/fire-project-researcher.md +155 -0
- package/agents/fire-research-synthesizer.md +166 -0
- package/agents/fire-researcher.md +723 -0
- package/agents/fire-reviewer.md +499 -0
- package/agents/fire-roadmapper.md +203 -0
- package/agents/fire-verifier.md +880 -0
- package/bin/cli.js +208 -0
- package/commands/fire-0-orient.md +476 -0
- package/commands/fire-1-new.md +281 -0
- package/commands/fire-1a-discuss.md +455 -0
- package/commands/fire-2-plan.md +527 -0
- package/commands/fire-3-execute.md +1303 -0
- package/commands/fire-4-verify.md +845 -0
- package/commands/fire-5-handoff.md +515 -0
- package/commands/fire-6-resume.md +501 -0
- package/commands/fire-7-review.md +409 -0
- package/commands/fire-add-new-skill.md +598 -0
- package/commands/fire-analytics.md +499 -0
- package/commands/fire-assumptions.md +78 -0
- package/commands/fire-autonomous.md +528 -0
- package/commands/fire-brainstorm.md +413 -0
- package/commands/fire-complete-milestone.md +270 -0
- package/commands/fire-dashboard.md +375 -0
- package/commands/fire-debug.md +663 -0
- package/commands/fire-discover.md +616 -0
- package/commands/fire-double-check.md +460 -0
- package/commands/fire-execute-plan.md +182 -0
- package/commands/fire-learncoding.md +242 -0
- package/commands/fire-loop-resume.md +272 -0
- package/commands/fire-loop-stop.md +198 -0
- package/commands/fire-loop.md +1168 -0
- package/commands/fire-map-codebase.md +313 -0
- package/commands/fire-new-milestone.md +356 -0
- package/commands/fire-reflect.md +235 -0
- package/commands/fire-research.md +246 -0
- package/commands/fire-search.md +330 -0
- package/commands/fire-security-audit-repo.md +293 -0
- package/commands/fire-security-scan.md +484 -0
- package/commands/fire-session-summary.md +252 -0
- package/commands/fire-skills-diff.md +506 -0
- package/commands/fire-skills-history.md +388 -0
- package/commands/fire-skills-rollback.md +408 -0
- package/commands/fire-skills-sync.md +470 -0
- package/commands/fire-test.md +520 -0
- package/commands/fire-todos.md +335 -0
- package/commands/fire-transition.md +186 -0
- package/commands/fire-update.md +312 -0
- package/commands/fire-verify-uat.md +146 -0
- package/commands/fire-vuln-scan.md +493 -0
- package/hooks/hooks.json +16 -0
- package/hooks/run-hook.cmd +69 -0
- package/hooks/run-hook.sh +8 -0
- package/hooks/run-session-end.cmd +49 -0
- package/hooks/run-session-end.sh +7 -0
- package/hooks/session-end.sh +90 -0
- package/hooks/session-start.sh +111 -0
- package/package.json +52 -0
- package/plugin.json +7 -0
- package/references/auto-skill-extraction.md +136 -0
- package/references/behavioral-directives.md +365 -0
- package/references/blocker-tracking.md +155 -0
- package/references/checkpoints.md +165 -0
- package/references/circuit-breaker.md +410 -0
- package/references/context-engineering.md +587 -0
- package/references/decision-time-guidance.md +289 -0
- package/references/error-classification.md +326 -0
- package/references/execution-mode-intelligence.md +242 -0
- package/references/git-integration.md +217 -0
- package/references/honesty-protocols.md +304 -0
- package/references/integration-architecture.md +470 -0
- package/references/issue-to-pr-pipeline.md +150 -0
- package/references/metrics-and-trends.md +234 -0
- package/references/playwright-e2e-testing.md +326 -0
- package/references/questioning.md +125 -0
- package/references/research-improvements.md +110 -0
- package/references/skills-usage-guide.md +429 -0
- package/references/tdd.md +131 -0
- package/references/testing-enforcement.md +192 -0
- package/references/ui-brand.md +383 -0
- package/references/validation-checklist.md +456 -0
- package/references/verification-patterns.md +187 -0
- package/references/warrior-principles.md +173 -0
- package/skills-library/SKILLS-INDEX.md +588 -0
- package/skills-library/_general/frontend/html-visual-reports.md +292 -0
- package/skills-library/_general/methodology/debug-swarm-researcher-escape-hatch.md +240 -0
- package/skills-library/_general/methodology/learncoding-agentic-pattern.md +114 -0
- package/skills-library/_general/methodology/shell-autonomous-loop-fixplan.md +238 -0
- package/skills-library/basics/api-rest-basics.md +162 -0
- package/skills-library/basics/env-variables.md +96 -0
- package/skills-library/basics/error-handling-basics.md +125 -0
- package/skills-library/basics/git-commit-conventions.md +106 -0
- package/skills-library/basics/readme-template.md +108 -0
- package/skills-library/common-tasks/async-await-patterns.md +157 -0
- package/skills-library/common-tasks/auth-jwt-basics.md +164 -0
- package/skills-library/common-tasks/database-schema-design.md +166 -0
- package/skills-library/common-tasks/file-upload-basics.md +166 -0
- package/skills-library/common-tasks/form-validation.md +159 -0
- package/skills-library/debugging/FAILURE_TAXONOMY_CLASSIFICATION.md +117 -0
- package/skills-library/debugging/THREE_AGENT_HYPOTHESIS_DEBUGGING.md +86 -0
- package/skills-library/methodology/BREATH_BASED_PARALLEL_EXECUTION.md +678 -0
- package/skills-library/methodology/CONFIDENCE_GATED_EXECUTION.md +243 -0
- package/skills-library/methodology/EVIDENCE_BASED_VALIDATION.md +308 -0
- package/skills-library/methodology/MULTI_PERSPECTIVE_CODE_REVIEW.md +330 -0
- package/skills-library/methodology/PATH_VERIFICATION_GATE.md +211 -0
- package/skills-library/methodology/REFLEXION_MEMORY_PATTERN.md +183 -0
- package/skills-library/methodology/RESEARCH_BACKED_WORKFLOW_UPGRADE.md +263 -0
- package/skills-library/methodology/SABBATH_REST_PATTERN.md +267 -0
- package/skills-library/methodology/STONE_AND_SCAFFOLD.md +220 -0
- package/skills-library/performance/cache-augmented-generation.md +172 -0
- package/skills-library/quality-safety/debugging-steps.md +147 -0
- package/skills-library/quality-safety/deployment-checklist.md +155 -0
- package/skills-library/quality-safety/security-checklist.md +204 -0
- package/skills-library/quality-safety/testing-basics.md +180 -0
- package/skills-library/security/agent-security-scanner.md +445 -0
- package/skills-library/specialists/api-architecture/api-designer.md +49 -0
- package/skills-library/specialists/api-architecture/graphql-architect.md +49 -0
- package/skills-library/specialists/api-architecture/mcp-developer.md +51 -0
- package/skills-library/specialists/api-architecture/microservices-architect.md +50 -0
- package/skills-library/specialists/api-architecture/websocket-engineer.md +48 -0
- package/skills-library/specialists/backend/django-expert.md +52 -0
- package/skills-library/specialists/backend/fastapi-expert.md +52 -0
- package/skills-library/specialists/backend/laravel-specialist.md +52 -0
- package/skills-library/specialists/backend/nestjs-expert.md +51 -0
- package/skills-library/specialists/backend/rails-expert.md +53 -0
- package/skills-library/specialists/backend/spring-boot-engineer.md +56 -0
- package/skills-library/specialists/data-ml/fine-tuning-expert.md +48 -0
- package/skills-library/specialists/data-ml/ml-pipeline.md +47 -0
- package/skills-library/specialists/data-ml/pandas-pro.md +47 -0
- package/skills-library/specialists/data-ml/rag-architect.md +51 -0
- package/skills-library/specialists/data-ml/spark-engineer.md +47 -0
- package/skills-library/specialists/frontend/angular-architect.md +52 -0
- package/skills-library/specialists/frontend/flutter-expert.md +51 -0
- package/skills-library/specialists/frontend/nextjs-developer.md +54 -0
- package/skills-library/specialists/frontend/react-native-expert.md +50 -0
- package/skills-library/specialists/frontend/vue-expert.md +51 -0
- package/skills-library/specialists/infrastructure/chaos-engineer.md +74 -0
- package/skills-library/specialists/infrastructure/cloud-architect.md +70 -0
- package/skills-library/specialists/infrastructure/database-optimizer.md +64 -0
- package/skills-library/specialists/infrastructure/devops-engineer.md +70 -0
- package/skills-library/specialists/infrastructure/kubernetes-specialist.md +52 -0
- package/skills-library/specialists/infrastructure/monitoring-expert.md +70 -0
- package/skills-library/specialists/infrastructure/sre-engineer.md +70 -0
- package/skills-library/specialists/infrastructure/terraform-engineer.md +51 -0
- package/skills-library/specialists/languages/cpp-pro.md +74 -0
- package/skills-library/specialists/languages/csharp-developer.md +69 -0
- package/skills-library/specialists/languages/dotnet-core-expert.md +54 -0
- package/skills-library/specialists/languages/golang-pro.md +51 -0
- package/skills-library/specialists/languages/java-architect.md +49 -0
- package/skills-library/specialists/languages/javascript-pro.md +68 -0
- package/skills-library/specialists/languages/kotlin-specialist.md +68 -0
- package/skills-library/specialists/languages/php-pro.md +49 -0
- package/skills-library/specialists/languages/python-pro.md +52 -0
- package/skills-library/specialists/languages/react-expert.md +51 -0
- package/skills-library/specialists/languages/rust-engineer.md +50 -0
- package/skills-library/specialists/languages/sql-pro.md +56 -0
- package/skills-library/specialists/languages/swift-expert.md +69 -0
- package/skills-library/specialists/languages/typescript-pro.md +51 -0
- package/skills-library/specialists/platform/atlassian-mcp.md +52 -0
- package/skills-library/specialists/platform/embedded-systems.md +53 -0
- package/skills-library/specialists/platform/game-developer.md +53 -0
- package/skills-library/specialists/platform/salesforce-developer.md +53 -0
- package/skills-library/specialists/platform/shopify-expert.md +49 -0
- package/skills-library/specialists/platform/wordpress-pro.md +49 -0
- package/skills-library/specialists/quality/code-documenter.md +51 -0
- package/skills-library/specialists/quality/code-reviewer.md +67 -0
- package/skills-library/specialists/quality/debugging-wizard.md +51 -0
- package/skills-library/specialists/quality/fullstack-guardian.md +51 -0
- package/skills-library/specialists/quality/legacy-modernizer.md +50 -0
- package/skills-library/specialists/quality/playwright-expert.md +65 -0
- package/skills-library/specialists/quality/spec-miner.md +56 -0
- package/skills-library/specialists/quality/test-master.md +65 -0
- package/skills-library/specialists/security/secure-code-guardian.md +55 -0
- package/skills-library/specialists/security/security-reviewer.md +53 -0
- package/skills-library/specialists/workflow/architecture-designer.md +53 -0
- package/skills-library/specialists/workflow/cli-developer.md +70 -0
- package/skills-library/specialists/workflow/feature-forge.md +65 -0
- package/skills-library/specialists/workflow/prompt-engineer.md +54 -0
- package/skills-library/specialists/workflow/the-fool.md +62 -0
- package/templates/ASSUMPTIONS.md +125 -0
- package/templates/BLOCKERS.md +73 -0
- package/templates/DECISION_LOG.md +116 -0
- package/templates/UAT.md +96 -0
- package/templates/blueprint.md +94 -0
- package/templates/brainstorm.md +185 -0
- package/templates/conscience.md +92 -0
- package/templates/fire-handoff.md +159 -0
- package/templates/metrics.md +67 -0
- package/templates/phase-prompt.md +142 -0
- package/templates/record.md +131 -0
- package/templates/review-report.md +117 -0
- package/templates/skills-index.md +157 -0
- package/templates/verification.md +149 -0
- package/templates/vision.md +79 -0
- package/validation-config.yml +793 -0
- package/version.json +7 -0
- package/workflows/execute-phase.md +732 -0
- package/workflows/handoff-session.md +678 -0
- package/workflows/new-project.md +578 -0
- package/workflows/plan-phase.md +592 -0
- package/workflows/verify-phase.md +874 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Skill: Debugging Steps
|
|
2
|
+
|
|
3
|
+
**Category:** Quality & Safety
|
|
4
|
+
**Difficulty:** Beginner
|
|
5
|
+
**Applies to:** Every project
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Problem
|
|
10
|
+
|
|
11
|
+
Most developers debug by guessing — changing random things until it works. This wastes hours and often introduces new bugs. Systematic debugging finds the problem in minutes.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The 5-Step Method
|
|
16
|
+
|
|
17
|
+
### Step 1 — Read the Error Message
|
|
18
|
+
|
|
19
|
+
The error message tells you exactly what went wrong. Read the whole thing, including the stack trace.
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
TypeError: Cannot read properties of undefined (reading 'email')
|
|
23
|
+
at getUserEmail (routes/users.js:24:23)
|
|
24
|
+
at router.get (/routes/users.js:18:20)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This tells you:
|
|
28
|
+
- **What:** Trying to read `.email` from something that is `undefined`
|
|
29
|
+
- **Where:** `routes/users.js` line 24
|
|
30
|
+
- **How it got there:** Called from line 18
|
|
31
|
+
|
|
32
|
+
Go to line 24. `user` is `undefined` — the database returned no rows.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
### Step 2 — Reproduce it Reliably
|
|
37
|
+
|
|
38
|
+
Before fixing, make sure you can make the bug happen on purpose.
|
|
39
|
+
|
|
40
|
+
- What exact steps trigger it?
|
|
41
|
+
- Does it happen every time, or randomly?
|
|
42
|
+
- Does it happen in development but not production (or vice versa)?
|
|
43
|
+
|
|
44
|
+
A bug you can reproduce consistently is a bug you can fix.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Step 3 — Isolate Where It Breaks
|
|
49
|
+
|
|
50
|
+
Narrow down where in the code the problem starts. Use `console.log` to trace values:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
router.get('/users/:id', async (req, res) => {
|
|
54
|
+
console.log('1. Request received, id:', req.params.id);
|
|
55
|
+
|
|
56
|
+
const result = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
|
|
57
|
+
console.log('2. DB result:', result.rows);
|
|
58
|
+
|
|
59
|
+
const user = result.rows[0];
|
|
60
|
+
console.log('3. User:', user); // if undefined, the query returned nothing
|
|
61
|
+
|
|
62
|
+
res.json({ email: user.email }); // crashes if user is undefined
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Work from the outside in. Log at the start, then in the middle, then closer to the crash until you find where the data goes wrong.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
### Step 4 — Form a Hypothesis and Test It
|
|
71
|
+
|
|
72
|
+
Once you know where, make a specific prediction about why:
|
|
73
|
+
|
|
74
|
+
> "I think the user query returns nothing because the ID from the URL is a string, but the database expects an integer."
|
|
75
|
+
|
|
76
|
+
Test it:
|
|
77
|
+
```js
|
|
78
|
+
console.log(typeof req.params.id); // 'string' — confirmed!
|
|
79
|
+
// Fix: parseInt(req.params.id, 10)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
If your hypothesis is wrong, form a new one. Don't just try random fixes.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### Step 5 — Fix, Verify, and Clean Up
|
|
87
|
+
|
|
88
|
+
- Make the smallest change that fixes the problem
|
|
89
|
+
- Verify the original bug is gone
|
|
90
|
+
- Check that nothing else broke
|
|
91
|
+
- Remove all the `console.log` statements you added
|
|
92
|
+
- Write a test so it can't come back silently
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Common Bug Patterns and Their Fixes
|
|
97
|
+
|
|
98
|
+
| Symptom | Likely Cause | How to Check |
|
|
99
|
+
|---------|-------------|--------------|
|
|
100
|
+
| `undefined` where you expect an object | Database returned 0 rows | Log the query result |
|
|
101
|
+
| `Cannot read property of null` | Accessing a property before data loads | Check for null before accessing |
|
|
102
|
+
| Fetch returns HTML instead of JSON | API route not found (404) | Check the URL and router setup |
|
|
103
|
+
| Changes not showing up | Old code cached / wrong file edited | Hard refresh, check file path |
|
|
104
|
+
| Works locally, breaks in production | Missing env variable | Check production env config |
|
|
105
|
+
| CORS error in browser | Backend not allowing your frontend origin | Check CORS middleware |
|
|
106
|
+
| `jwt malformed` | Token corrupted or wrong format | Log the raw Authorization header |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## The Console is Your Friend
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
// Log an object clearly
|
|
114
|
+
console.log('user:', JSON.stringify(user, null, 2));
|
|
115
|
+
|
|
116
|
+
// Log with a timestamp
|
|
117
|
+
console.log(new Date().toISOString(), 'step reached');
|
|
118
|
+
|
|
119
|
+
// Log type and value
|
|
120
|
+
console.log('id type:', typeof id, 'value:', id);
|
|
121
|
+
|
|
122
|
+
// Trace where a function is called from
|
|
123
|
+
console.trace('Called from:');
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## When You've Been Stuck for 20 Minutes
|
|
129
|
+
|
|
130
|
+
1. **Explain the problem out loud** (rubber duck debugging) — saying it out loud often reveals the answer
|
|
131
|
+
2. **Take a 10-minute break** — your brain keeps working
|
|
132
|
+
3. **Search the exact error message** in quotes on Google or Stack Overflow
|
|
133
|
+
4. **Read the documentation** for the library you're using — check if your usage matches the examples
|
|
134
|
+
5. **Ask for help** — share the error, the code, and what you've already tried
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## What Not to Do
|
|
139
|
+
|
|
140
|
+
- Don't comment out code randomly hoping the bug disappears
|
|
141
|
+
- Don't change multiple things at once — you won't know what fixed it
|
|
142
|
+
- Don't ignore warnings in the console — they often point to the real problem
|
|
143
|
+
- Don't assume the library is broken — it's almost always your code
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
*Fire Flow Skills Library — MIT License*
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# Skill: Deployment Checklist
|
|
2
|
+
|
|
3
|
+
**Category:** Quality & Safety
|
|
4
|
+
**Difficulty:** Beginner
|
|
5
|
+
**Applies to:** Every web project going to production
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Before You Deploy — Run Through This List
|
|
10
|
+
|
|
11
|
+
Going live with something broken is worse than not going live at all. This checklist catches the most common deployment failures.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Environment & Secrets
|
|
16
|
+
|
|
17
|
+
- [ ] All secrets are in production environment variables (not in code)
|
|
18
|
+
- [ ] `NODE_ENV=production` is set
|
|
19
|
+
- [ ] Database URL points to the **production** database, not localhost
|
|
20
|
+
- [ ] JWT secret in production is different from your development secret
|
|
21
|
+
- [ ] No `.env` file is committed to git
|
|
22
|
+
- [ ] All required env variables are documented in `.env.example`
|
|
23
|
+
|
|
24
|
+
**How to verify:**
|
|
25
|
+
```bash
|
|
26
|
+
# List your production env vars (on Railway, Render, etc.)
|
|
27
|
+
# Or test locally with production values:
|
|
28
|
+
NODE_ENV=production node -e "console.log(process.env.DATABASE_URL)"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 2. Database
|
|
34
|
+
|
|
35
|
+
- [ ] All migrations have been run on the production database
|
|
36
|
+
- [ ] Production database has been backed up before this deployment
|
|
37
|
+
- [ ] Seed data (categories, default settings) is in place if needed
|
|
38
|
+
- [ ] Database indexes exist on frequently queried columns
|
|
39
|
+
- [ ] Connection pooling is configured for production load
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Run migrations
|
|
43
|
+
npm run db:migrate
|
|
44
|
+
|
|
45
|
+
# Verify tables exist
|
|
46
|
+
psql $DATABASE_URL -c "\dt"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 3. Code Quality
|
|
52
|
+
|
|
53
|
+
- [ ] All tests pass
|
|
54
|
+
- [ ] No `console.log` debug statements left in production code
|
|
55
|
+
- [ ] No hardcoded localhost URLs — use env variables for all service URLs
|
|
56
|
+
- [ ] Error handling is in place for all API routes
|
|
57
|
+
- [ ] `npm audit` shows no critical vulnerabilities
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm test
|
|
61
|
+
npm audit
|
|
62
|
+
grep -r "localhost" src/ --include="*.js" | grep -v ".env"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## 4. Security
|
|
68
|
+
|
|
69
|
+
- [ ] HTTPS is enabled (SSL certificate is valid)
|
|
70
|
+
- [ ] CORS is restricted to your production frontend domain
|
|
71
|
+
- [ ] Rate limiting is in place on auth endpoints
|
|
72
|
+
- [ ] Sensitive routes require authentication
|
|
73
|
+
- [ ] File uploads are validated and size-limited
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 5. Performance
|
|
78
|
+
|
|
79
|
+
- [ ] Images are compressed and sized appropriately
|
|
80
|
+
- [ ] Frontend assets are minified and bundled (run `npm run build`)
|
|
81
|
+
- [ ] Database queries use indexes where needed
|
|
82
|
+
- [ ] Caching is in place for data that doesn't change often (if applicable)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 6. Frontend Build
|
|
87
|
+
|
|
88
|
+
- [ ] Production build completed without errors (`npm run build`)
|
|
89
|
+
- [ ] Build output points to production API URL, not localhost
|
|
90
|
+
- [ ] 404 page exists and looks professional
|
|
91
|
+
- [ ] Favicon is set
|
|
92
|
+
- [ ] Page titles are set correctly (`<title>App Name</title>`)
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 7. Monitoring
|
|
97
|
+
|
|
98
|
+
- [ ] Error logging is in place (console.error at minimum)
|
|
99
|
+
- [ ] You know how to view production logs
|
|
100
|
+
- [ ] You have a way to be alerted if the app goes down
|
|
101
|
+
|
|
102
|
+
**Simple health check endpoint:**
|
|
103
|
+
```js
|
|
104
|
+
app.get('/api/health', (req, res) => {
|
|
105
|
+
res.json({ status: 'ok', timestamp: new Date().toISOString() });
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Set up an uptime monitor at [uptimerobot.com](https://uptimerobot.com) (free) to ping this every 5 minutes.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 8. Post-Deployment Smoke Test
|
|
114
|
+
|
|
115
|
+
After deploying, manually test these in the browser:
|
|
116
|
+
|
|
117
|
+
- [ ] Home page loads
|
|
118
|
+
- [ ] User can register
|
|
119
|
+
- [ ] User can log in
|
|
120
|
+
- [ ] Core feature works end-to-end
|
|
121
|
+
- [ ] Logout works
|
|
122
|
+
- [ ] No JavaScript errors in browser console (press F12)
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Rollback Plan
|
|
127
|
+
|
|
128
|
+
Before every deployment, know how to roll back:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Git: revert to previous commit
|
|
132
|
+
git revert HEAD
|
|
133
|
+
git push origin main
|
|
134
|
+
|
|
135
|
+
# Or: deploy the previous version manually
|
|
136
|
+
git checkout <previous-commit-hash>
|
|
137
|
+
git push origin main --force
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
If you changed the database schema, have a down migration ready.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Deployment Platforms (Beginner-Friendly)
|
|
145
|
+
|
|
146
|
+
| Platform | Best For | Free Tier |
|
|
147
|
+
|----------|---------|-----------|
|
|
148
|
+
| [Railway](https://railway.app) | Node.js + PostgreSQL together | Yes |
|
|
149
|
+
| [Render](https://render.com) | Web services + databases | Yes (sleeps after inactivity) |
|
|
150
|
+
| [Vercel](https://vercel.com) | Frontend + serverless functions | Yes |
|
|
151
|
+
| [Fly.io](https://fly.io) | Dockerized apps | Yes |
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
*Fire Flow Skills Library — MIT License*
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Skill: Security Checklist
|
|
2
|
+
|
|
3
|
+
**Category:** Quality & Safety
|
|
4
|
+
**Difficulty:** Beginner
|
|
5
|
+
**Applies to:** Every web project
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The 10 Most Common Security Mistakes
|
|
10
|
+
|
|
11
|
+
Based on the OWASP Top 10 — the industry-standard list of web vulnerabilities.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
### 1. SQL Injection
|
|
16
|
+
|
|
17
|
+
**What it is:** An attacker puts SQL code in your input fields to steal or destroy your data.
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
// VULNERABLE — never do this
|
|
21
|
+
const query = `SELECT * FROM users WHERE email = '${req.body.email}'`;
|
|
22
|
+
// Attacker sends: ' OR '1'='1 — returns ALL users
|
|
23
|
+
|
|
24
|
+
// SAFE — always use parameterized queries
|
|
25
|
+
const result = await db.query('SELECT * FROM users WHERE email = $1', [req.body.email]);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Rule:** Never build SQL strings by concatenating user input.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
### 2. Hardcoded Secrets
|
|
33
|
+
|
|
34
|
+
**What it is:** API keys, passwords, or tokens written directly in code and committed to git.
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
// WRONG
|
|
38
|
+
const stripe = require('stripe')('sk_live_abc123realkey');
|
|
39
|
+
|
|
40
|
+
// RIGHT
|
|
41
|
+
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Rule:** Every secret lives in `.env`. `.env` is in `.gitignore`. See [env-variables.md](../basics/env-variables.md).
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### 3. Missing Authentication on Routes
|
|
49
|
+
|
|
50
|
+
**What it is:** Forgetting to protect routes that should require login.
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// WRONG — anyone can delete any user
|
|
54
|
+
router.delete('/users/:id', async (req, res) => { ... });
|
|
55
|
+
|
|
56
|
+
// RIGHT
|
|
57
|
+
router.delete('/users/:id', requireAuth, async (req, res) => { ... });
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Rule:** Every route that reads private data or makes changes must have auth middleware.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### 4. Plain Text Passwords
|
|
65
|
+
|
|
66
|
+
**What it is:** Storing user passwords as plain text in the database. One breach = all accounts compromised.
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
// WRONG
|
|
70
|
+
await db.query('INSERT INTO users (password) VALUES ($1)', [password]);
|
|
71
|
+
|
|
72
|
+
// RIGHT — always hash with bcrypt
|
|
73
|
+
const hash = await bcrypt.hash(password, 12);
|
|
74
|
+
await db.query('INSERT INTO users (password_hash) VALUES ($1)', [hash]);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Rule:** Never store, log, or transmit plain text passwords. Hash with bcrypt.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### 5. No Input Validation
|
|
82
|
+
|
|
83
|
+
**What it is:** Trusting whatever the user sends without checking it.
|
|
84
|
+
|
|
85
|
+
```js
|
|
86
|
+
// WRONG — user could send a negative price, or a 10MB JSON body
|
|
87
|
+
app.post('/products', async (req, res) => {
|
|
88
|
+
await db.query('INSERT INTO products (price) VALUES ($1)', [req.body.price]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// RIGHT
|
|
92
|
+
app.use(express.json({ limit: '10kb' })); // limit body size
|
|
93
|
+
app.post('/products', async (req, res) => {
|
|
94
|
+
const price = parseFloat(req.body.price);
|
|
95
|
+
if (isNaN(price) || price < 0) return res.status(400).json({ error: 'Invalid price' });
|
|
96
|
+
await db.query('INSERT INTO products (price) VALUES ($1)', [price]);
|
|
97
|
+
});
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**Rule:** Validate every input on the server. See [form-validation.md](../common-tasks/form-validation.md).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### 6. Exposing Error Details to Users
|
|
105
|
+
|
|
106
|
+
**What it is:** Sending stack traces or database errors to the frontend, exposing your internal structure.
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
// WRONG
|
|
110
|
+
res.status(500).json({ error: err.stack }); // shows file paths, table names
|
|
111
|
+
|
|
112
|
+
// RIGHT
|
|
113
|
+
console.error(err); // log full error on server
|
|
114
|
+
res.status(500).json({ error: 'Something went wrong. Please try again.' });
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Rule:** Log errors on the server. Send only generic messages to the client.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
### 7. Missing HTTPS
|
|
122
|
+
|
|
123
|
+
**What it is:** Sending data over HTTP allows anyone on the network to read it (passwords, tokens, everything).
|
|
124
|
+
|
|
125
|
+
**Rule:** Always use HTTPS in production. Most hosting providers (Vercel, Railway, Render) do this automatically. For VPS, use Let's Encrypt (free SSL) via Certbot.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
### 8. CORS Misconfiguration
|
|
130
|
+
|
|
131
|
+
**What it is:** Allowing any website to call your API.
|
|
132
|
+
|
|
133
|
+
```js
|
|
134
|
+
// WRONG — allows any origin
|
|
135
|
+
app.use(cors());
|
|
136
|
+
|
|
137
|
+
// RIGHT — only allow your own frontend
|
|
138
|
+
app.use(cors({
|
|
139
|
+
origin: process.env.FRONTEND_URL, // e.g. 'https://myapp.com'
|
|
140
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
141
|
+
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
142
|
+
}));
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Rule:** Set CORS to your specific frontend domain in production.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### 9. Broken Access Control
|
|
150
|
+
|
|
151
|
+
**What it is:** A logged-in user can access or edit another user's data.
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
// WRONG — user can request any profile by changing the ID
|
|
155
|
+
router.get('/profile/:id', requireAuth, async (req, res) => {
|
|
156
|
+
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
|
|
157
|
+
res.json(user.rows[0]);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// RIGHT — only return the logged-in user's own data
|
|
161
|
+
router.get('/profile', requireAuth, async (req, res) => {
|
|
162
|
+
const user = await db.query('SELECT * FROM users WHERE id = $1', [req.user.userId]);
|
|
163
|
+
res.json(user.rows[0]);
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Rule:** When fetching user-specific data, always filter by the authenticated user's ID from the token — not from the URL.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### 10. Outdated Dependencies
|
|
172
|
+
|
|
173
|
+
**What it is:** Old packages often have known security vulnerabilities.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Check for vulnerabilities
|
|
177
|
+
npm audit
|
|
178
|
+
|
|
179
|
+
# Fix automatically (safe fixes only)
|
|
180
|
+
npm audit fix
|
|
181
|
+
|
|
182
|
+
# See outdated packages
|
|
183
|
+
npm outdated
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Rule:** Run `npm audit` before every deployment. Update dependencies regularly.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Quick Pre-Launch Checklist
|
|
191
|
+
|
|
192
|
+
- [ ] All secrets are in `.env`, not in code
|
|
193
|
+
- [ ] `.env` is in `.gitignore`
|
|
194
|
+
- [ ] All write routes require authentication
|
|
195
|
+
- [ ] Passwords are hashed with bcrypt
|
|
196
|
+
- [ ] All user input is validated on the server
|
|
197
|
+
- [ ] CORS is set to the production frontend domain
|
|
198
|
+
- [ ] HTTPS is enabled
|
|
199
|
+
- [ ] `npm audit` shows no critical vulnerabilities
|
|
200
|
+
- [ ] Error messages sent to users contain no internal details
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
*Fire Flow Skills Library — MIT License*
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Skill: Testing Basics
|
|
2
|
+
|
|
3
|
+
**Category:** Quality & Safety
|
|
4
|
+
**Difficulty:** Beginner
|
|
5
|
+
**Applies to:** Node.js (Jest), any language
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Why Test?
|
|
10
|
+
|
|
11
|
+
Tests catch bugs before your users do. They also let you change code confidently — if the tests still pass, you didn't break anything. Untested code is code you're afraid to touch.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Setup (Jest)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install --save-dev jest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
// package.json
|
|
23
|
+
{
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "jest",
|
|
26
|
+
"test:watch": "jest --watch"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## What to Test
|
|
34
|
+
|
|
35
|
+
**Test these:**
|
|
36
|
+
- Functions that calculate or transform data
|
|
37
|
+
- API endpoints (correct response, correct status code)
|
|
38
|
+
- Edge cases — what happens with empty input, null, zero, very large numbers
|
|
39
|
+
- Error paths — what happens when the database is down, or input is invalid
|
|
40
|
+
|
|
41
|
+
**Don't bother testing:**
|
|
42
|
+
- Third-party libraries (they have their own tests)
|
|
43
|
+
- Simple getters/setters with no logic
|
|
44
|
+
- Things that are just passing data through unchanged
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Pattern 1: Unit Test (Pure Function)
|
|
49
|
+
|
|
50
|
+
A unit test tests one function in isolation:
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
// utils/price.js
|
|
54
|
+
function applyDiscount(price, discountPercent) {
|
|
55
|
+
if (price < 0) throw new Error('Price cannot be negative');
|
|
56
|
+
if (discountPercent < 0 || discountPercent > 100) throw new Error('Invalid discount');
|
|
57
|
+
return price * (1 - discountPercent / 100);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = { applyDiscount };
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```js
|
|
64
|
+
// utils/price.test.js
|
|
65
|
+
const { applyDiscount } = require('./price');
|
|
66
|
+
|
|
67
|
+
describe('applyDiscount', () => {
|
|
68
|
+
test('applies 10% discount correctly', () => {
|
|
69
|
+
expect(applyDiscount(100, 10)).toBe(90);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('applies 0% discount (no change)', () => {
|
|
73
|
+
expect(applyDiscount(100, 0)).toBe(100);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('applies 100% discount (free)', () => {
|
|
77
|
+
expect(applyDiscount(100, 100)).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('throws on negative price', () => {
|
|
81
|
+
expect(() => applyDiscount(-10, 10)).toThrow('Price cannot be negative');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('throws on invalid discount over 100', () => {
|
|
85
|
+
expect(() => applyDiscount(100, 110)).toThrow('Invalid discount');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Run: `npm test`
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Pattern 2: API Test (Integration Test)
|
|
95
|
+
|
|
96
|
+
Test your actual routes with real HTTP requests:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npm install --save-dev supertest
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
```js
|
|
103
|
+
// routes/users.test.js
|
|
104
|
+
const request = require('supertest');
|
|
105
|
+
const app = require('../app');
|
|
106
|
+
|
|
107
|
+
describe('GET /api/users/:id', () => {
|
|
108
|
+
test('returns 200 and user for valid id', async () => {
|
|
109
|
+
const res = await request(app).get('/api/users/1');
|
|
110
|
+
expect(res.status).toBe(200);
|
|
111
|
+
expect(res.body).toHaveProperty('email');
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('returns 404 for non-existent user', async () => {
|
|
115
|
+
const res = await request(app).get('/api/users/99999');
|
|
116
|
+
expect(res.status).toBe(404);
|
|
117
|
+
expect(res.body).toHaveProperty('error');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('POST /api/users', () => {
|
|
122
|
+
test('returns 400 when email is missing', async () => {
|
|
123
|
+
const res = await request(app)
|
|
124
|
+
.post('/api/users')
|
|
125
|
+
.send({ name: 'Jane' }); // no email
|
|
126
|
+
expect(res.status).toBe(400);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## The AAA Pattern
|
|
134
|
+
|
|
135
|
+
Every test follows this structure:
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
test('description of what should happen', () => {
|
|
139
|
+
// Arrange — set up the data
|
|
140
|
+
const price = 100;
|
|
141
|
+
const discount = 20;
|
|
142
|
+
|
|
143
|
+
// Act — run the thing being tested
|
|
144
|
+
const result = applyDiscount(price, discount);
|
|
145
|
+
|
|
146
|
+
// Assert — verify the result
|
|
147
|
+
expect(result).toBe(80);
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Most Useful Jest Matchers
|
|
154
|
+
|
|
155
|
+
```js
|
|
156
|
+
expect(value).toBe(42) // strict equality (===)
|
|
157
|
+
expect(value).toEqual({ a: 1 }) // deep equality for objects
|
|
158
|
+
expect(value).toBeTruthy() // any truthy value
|
|
159
|
+
expect(value).toBeNull()
|
|
160
|
+
expect(value).toBeGreaterThan(0)
|
|
161
|
+
expect(array).toHaveLength(3)
|
|
162
|
+
expect(object).toHaveProperty('name')
|
|
163
|
+
expect(string).toContain('hello')
|
|
164
|
+
expect(fn).toThrow('message')
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Aim for This Coverage
|
|
170
|
+
|
|
171
|
+
| Layer | What to Test |
|
|
172
|
+
|-------|-------------|
|
|
173
|
+
| Utility functions | All branches, all edge cases |
|
|
174
|
+
| API endpoints | Happy path + main error cases |
|
|
175
|
+
| Auth middleware | Blocked with no token, blocked with bad token, passes with good token |
|
|
176
|
+
| Database queries | At least the shape of the returned data |
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
*Fire Flow Skills Library — MIT License*
|