devflow-kit 0.8.1 → 1.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/CHANGELOG.md +185 -29
- package/LICENSE +1 -1
- package/README.md +179 -308
- package/dist/cli.js +3 -1
- package/dist/commands/init.d.ts +21 -0
- package/dist/commands/init.js +311 -575
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.js +20 -0
- package/dist/commands/uninstall.d.ts +10 -0
- package/dist/commands/uninstall.js +351 -78
- package/dist/plugins.d.ts +46 -0
- package/dist/plugins.js +162 -0
- package/dist/utils/cli.d.ts +5 -0
- package/dist/utils/cli.js +14 -0
- package/dist/utils/installer.d.ts +41 -0
- package/dist/utils/installer.js +177 -0
- package/dist/utils/paths.d.ts +10 -0
- package/dist/utils/paths.js +23 -3
- package/dist/utils/post-install.d.ts +68 -0
- package/dist/utils/post-install.js +427 -0
- package/dist/utils/safe-delete-install.d.ts +22 -0
- package/dist/utils/safe-delete-install.js +156 -0
- package/dist/utils/safe-delete.d.ts +12 -0
- package/dist/utils/safe-delete.js +83 -0
- package/package.json +18 -8
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +7 -0
- package/plugins/devflow-audit-claude/README.md +46 -0
- package/plugins/devflow-audit-claude/agents/claude-md-auditor.md +134 -0
- package/plugins/devflow-audit-claude/commands/audit-claude.md +85 -0
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +31 -0
- package/plugins/devflow-code-review/README.md +73 -0
- package/plugins/devflow-code-review/agents/git.md +272 -0
- package/plugins/devflow-code-review/agents/reviewer.md +119 -0
- package/plugins/devflow-code-review/agents/synthesizer.md +204 -0
- package/plugins/devflow-code-review/commands/code-review-teams.md +262 -0
- package/plugins/devflow-code-review/commands/code-review.md +141 -0
- package/plugins/devflow-code-review/skills/accessibility/SKILL.md +229 -0
- package/plugins/devflow-code-review/skills/accessibility/references/detection.md +171 -0
- package/plugins/devflow-code-review/skills/accessibility/references/patterns.md +670 -0
- package/plugins/devflow-code-review/skills/accessibility/references/violations.md +419 -0
- package/plugins/devflow-code-review/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-code-review/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-code-review/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-code-review/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/SKILL.md +153 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/references/detection.md +337 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/references/patterns.md +873 -0
- package/plugins/devflow-code-review/skills/architecture-patterns/references/violations.md +575 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/SKILL.md +143 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/references/detection.md +264 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/references/patterns.md +487 -0
- package/plugins/devflow-code-review/skills/complexity-patterns/references/violations.md +361 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/SKILL.md +140 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/references/detection.md +207 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/references/patterns.md +202 -0
- package/plugins/devflow-code-review/skills/consistency-patterns/references/violations.md +213 -0
- package/plugins/devflow-code-review/skills/database-patterns/SKILL.md +134 -0
- package/plugins/devflow-code-review/skills/database-patterns/references/detection.md +208 -0
- package/plugins/devflow-code-review/skills/database-patterns/references/patterns.md +394 -0
- package/plugins/devflow-code-review/skills/database-patterns/references/violations.md +332 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/SKILL.md +141 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/references/detection.md +181 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/references/patterns.md +225 -0
- package/plugins/devflow-code-review/skills/dependencies-patterns/references/violations.md +247 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/SKILL.md +125 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/references/detection.md +190 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/references/patterns.md +189 -0
- package/plugins/devflow-code-review/skills/documentation-patterns/references/violations.md +163 -0
- package/plugins/devflow-code-review/skills/frontend-design/SKILL.md +254 -0
- package/plugins/devflow-code-review/skills/frontend-design/references/detection.md +184 -0
- package/plugins/devflow-code-review/skills/frontend-design/references/patterns.md +511 -0
- package/plugins/devflow-code-review/skills/frontend-design/references/violations.md +453 -0
- package/plugins/devflow-code-review/skills/performance-patterns/SKILL.md +154 -0
- package/plugins/devflow-code-review/skills/performance-patterns/references/detection.md +351 -0
- package/plugins/devflow-code-review/skills/performance-patterns/references/patterns.md +503 -0
- package/plugins/devflow-code-review/skills/performance-patterns/references/violations.md +354 -0
- package/plugins/devflow-code-review/skills/react/SKILL.md +276 -0
- package/plugins/devflow-code-review/skills/react/references/patterns.md +1331 -0
- package/plugins/devflow-code-review/skills/react/references/violations.md +565 -0
- package/plugins/devflow-code-review/skills/regression-patterns/SKILL.md +146 -0
- package/plugins/devflow-code-review/skills/regression-patterns/references/detection.md +237 -0
- package/plugins/devflow-code-review/skills/regression-patterns/references/patterns.md +226 -0
- package/plugins/devflow-code-review/skills/regression-patterns/references/violations.md +225 -0
- package/plugins/devflow-code-review/skills/review-methodology/SKILL.md +119 -0
- package/plugins/devflow-code-review/skills/review-methodology/references/patterns.md +186 -0
- package/plugins/devflow-code-review/skills/review-methodology/references/report-template.md +142 -0
- package/plugins/devflow-code-review/skills/review-methodology/references/violations.md +125 -0
- package/plugins/devflow-code-review/skills/security-patterns/SKILL.md +156 -0
- package/plugins/devflow-code-review/skills/security-patterns/references/detection.md +287 -0
- package/plugins/devflow-code-review/skills/security-patterns/references/patterns.md +507 -0
- package/plugins/devflow-code-review/skills/security-patterns/references/violations.md +237 -0
- package/plugins/devflow-code-review/skills/test-patterns/SKILL.md +183 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/detection.md +149 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/patterns.md +220 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/report-template.md +108 -0
- package/plugins/devflow-code-review/skills/test-patterns/references/violations.md +221 -0
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +27 -0
- package/plugins/devflow-core-skills/README.md +50 -0
- package/plugins/devflow-core-skills/skills/accessibility/SKILL.md +229 -0
- package/plugins/devflow-core-skills/skills/accessibility/references/detection.md +171 -0
- package/plugins/devflow-core-skills/skills/accessibility/references/patterns.md +670 -0
- package/plugins/devflow-core-skills/skills/accessibility/references/violations.md +419 -0
- package/plugins/devflow-core-skills/skills/core-patterns/SKILL.md +162 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/checklist.md +276 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/code-smell-violations.md +144 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/detection.md +303 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/patterns.md +576 -0
- package/plugins/devflow-core-skills/skills/core-patterns/references/violations.md +369 -0
- package/plugins/devflow-core-skills/skills/docs-framework/SKILL.md +134 -0
- package/plugins/devflow-core-skills/skills/docs-framework/references/patterns.md +346 -0
- package/plugins/devflow-core-skills/skills/docs-framework/references/violations.md +221 -0
- package/plugins/devflow-core-skills/skills/frontend-design/SKILL.md +254 -0
- package/plugins/devflow-core-skills/skills/frontend-design/references/detection.md +184 -0
- package/plugins/devflow-core-skills/skills/frontend-design/references/patterns.md +511 -0
- package/plugins/devflow-core-skills/skills/frontend-design/references/violations.md +453 -0
- package/plugins/devflow-core-skills/skills/git-safety/SKILL.md +122 -0
- package/plugins/devflow-core-skills/skills/git-safety/references/detection.md +290 -0
- package/plugins/devflow-core-skills/skills/git-safety/references/patterns.md +289 -0
- package/plugins/devflow-core-skills/skills/git-safety/references/violations.md +18 -0
- package/plugins/devflow-core-skills/skills/git-workflow/SKILL.md +158 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/commit-patterns.md +115 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/commit-violations.md +77 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/pr-patterns.md +127 -0
- package/plugins/devflow-core-skills/skills/git-workflow/references/pr-violations.md +96 -0
- package/plugins/devflow-core-skills/skills/github-patterns/SKILL.md +153 -0
- package/plugins/devflow-core-skills/skills/github-patterns/references/patterns.md +572 -0
- package/plugins/devflow-core-skills/skills/github-patterns/references/violations.md +298 -0
- package/plugins/devflow-core-skills/skills/input-validation/SKILL.md +148 -0
- package/plugins/devflow-core-skills/skills/input-validation/references/detection.md +283 -0
- package/plugins/devflow-core-skills/skills/input-validation/references/patterns.md +361 -0
- package/plugins/devflow-core-skills/skills/input-validation/references/violations.md +224 -0
- package/plugins/devflow-core-skills/skills/react/SKILL.md +276 -0
- package/plugins/devflow-core-skills/skills/react/references/patterns.md +1331 -0
- package/plugins/devflow-core-skills/skills/react/references/violations.md +565 -0
- package/plugins/devflow-core-skills/skills/test-patterns/SKILL.md +183 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/detection.md +149 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/patterns.md +220 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/report-template.md +108 -0
- package/plugins/devflow-core-skills/skills/test-patterns/references/violations.md +221 -0
- package/plugins/devflow-core-skills/skills/typescript/SKILL.md +176 -0
- package/plugins/devflow-core-skills/skills/typescript/references/patterns.md +1105 -0
- package/plugins/devflow-core-skills/skills/typescript/references/violations.md +433 -0
- package/plugins/devflow-debug/.claude-plugin/plugin.json +18 -0
- package/plugins/devflow-debug/README.md +65 -0
- package/plugins/devflow-debug/agents/git.md +272 -0
- package/plugins/devflow-debug/commands/debug-teams.md +231 -0
- package/plugins/devflow-debug/commands/debug.md +160 -0
- package/plugins/devflow-debug/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-debug/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-debug/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-debug/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-debug/skills/git-safety/SKILL.md +122 -0
- package/plugins/devflow-debug/skills/git-safety/references/detection.md +290 -0
- package/plugins/devflow-debug/skills/git-safety/references/patterns.md +289 -0
- package/plugins/devflow-debug/skills/git-safety/references/violations.md +18 -0
- package/plugins/devflow-implement/.claude-plugin/plugin.json +21 -0
- package/plugins/devflow-implement/README.md +71 -0
- package/plugins/devflow-implement/agents/coder.md +122 -0
- package/plugins/devflow-implement/agents/git.md +272 -0
- package/plugins/devflow-implement/agents/scrutinizer.md +80 -0
- package/plugins/devflow-implement/agents/shepherd.md +94 -0
- package/plugins/devflow-implement/agents/simplifier.md +62 -0
- package/plugins/devflow-implement/agents/skimmer.md +88 -0
- package/plugins/devflow-implement/agents/synthesizer.md +204 -0
- package/plugins/devflow-implement/agents/validator.md +86 -0
- package/plugins/devflow-implement/commands/implement-teams.md +608 -0
- package/plugins/devflow-implement/commands/implement.md +426 -0
- package/plugins/devflow-implement/skills/accessibility/SKILL.md +229 -0
- package/plugins/devflow-implement/skills/accessibility/references/detection.md +171 -0
- package/plugins/devflow-implement/skills/accessibility/references/patterns.md +670 -0
- package/plugins/devflow-implement/skills/accessibility/references/violations.md +419 -0
- package/plugins/devflow-implement/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-implement/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-implement/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-implement/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-implement/skills/frontend-design/SKILL.md +254 -0
- package/plugins/devflow-implement/skills/frontend-design/references/detection.md +184 -0
- package/plugins/devflow-implement/skills/frontend-design/references/patterns.md +511 -0
- package/plugins/devflow-implement/skills/frontend-design/references/violations.md +453 -0
- package/plugins/devflow-implement/skills/implementation-patterns/SKILL.md +162 -0
- package/plugins/devflow-implement/skills/implementation-patterns/references/patterns.md +1063 -0
- package/plugins/devflow-implement/skills/implementation-patterns/references/violations.md +483 -0
- package/plugins/devflow-implement/skills/self-review/SKILL.md +149 -0
- package/plugins/devflow-implement/skills/self-review/references/patterns.md +405 -0
- package/plugins/devflow-implement/skills/self-review/references/report-template.md +253 -0
- package/plugins/devflow-implement/skills/self-review/references/violations.md +308 -0
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +19 -0
- package/plugins/devflow-resolve/README.md +65 -0
- package/plugins/devflow-resolve/agents/git.md +272 -0
- package/plugins/devflow-resolve/agents/resolver.md +131 -0
- package/plugins/devflow-resolve/agents/simplifier.md +62 -0
- package/plugins/devflow-resolve/commands/resolve-teams.md +298 -0
- package/plugins/devflow-resolve/commands/resolve.md +237 -0
- package/plugins/devflow-resolve/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-resolve/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-resolve/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-resolve/skills/agent-teams/references/team-patterns.md +217 -0
- package/plugins/devflow-resolve/skills/implementation-patterns/SKILL.md +162 -0
- package/plugins/devflow-resolve/skills/implementation-patterns/references/patterns.md +1063 -0
- package/plugins/devflow-resolve/skills/implementation-patterns/references/violations.md +483 -0
- package/plugins/devflow-resolve/skills/security-patterns/SKILL.md +156 -0
- package/plugins/devflow-resolve/skills/security-patterns/references/detection.md +287 -0
- package/plugins/devflow-resolve/skills/security-patterns/references/patterns.md +507 -0
- package/plugins/devflow-resolve/skills/security-patterns/references/violations.md +237 -0
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +7 -0
- package/plugins/devflow-self-review/README.md +38 -0
- package/plugins/devflow-self-review/agents/scrutinizer.md +80 -0
- package/plugins/devflow-self-review/agents/simplifier.md +62 -0
- package/plugins/devflow-self-review/agents/validator.md +86 -0
- package/plugins/devflow-self-review/commands/self-review.md +126 -0
- package/plugins/devflow-self-review/skills/core-patterns/SKILL.md +162 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/checklist.md +276 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/code-smell-violations.md +144 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/detection.md +303 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/patterns.md +576 -0
- package/plugins/devflow-self-review/skills/core-patterns/references/violations.md +369 -0
- package/plugins/devflow-self-review/skills/self-review/SKILL.md +149 -0
- package/plugins/devflow-self-review/skills/self-review/references/patterns.md +405 -0
- package/plugins/devflow-self-review/skills/self-review/references/report-template.md +253 -0
- package/plugins/devflow-self-review/skills/self-review/references/violations.md +308 -0
- package/plugins/devflow-specify/.claude-plugin/plugin.json +15 -0
- package/plugins/devflow-specify/README.md +46 -0
- package/plugins/devflow-specify/agents/skimmer.md +88 -0
- package/plugins/devflow-specify/agents/synthesizer.md +204 -0
- package/plugins/devflow-specify/commands/specify-teams.md +314 -0
- package/plugins/devflow-specify/commands/specify.md +179 -0
- package/plugins/devflow-specify/skills/agent-teams/SKILL.md +124 -0
- package/plugins/devflow-specify/skills/agent-teams/references/cleanup.md +104 -0
- package/plugins/devflow-specify/skills/agent-teams/references/communication.md +122 -0
- package/plugins/devflow-specify/skills/agent-teams/references/team-patterns.md +217 -0
- package/scripts/hooks/background-memory-update.sh +167 -0
- package/scripts/hooks/pre-compact-memory.sh +81 -0
- package/scripts/hooks/session-start-memory.sh +84 -0
- package/scripts/hooks/stop-update-memory.sh +81 -0
- package/shared/agents/coder.md +122 -0
- package/shared/agents/git.md +272 -0
- package/shared/agents/resolver.md +131 -0
- package/shared/agents/reviewer.md +119 -0
- package/shared/agents/scrutinizer.md +80 -0
- package/shared/agents/shepherd.md +94 -0
- package/shared/agents/simplifier.md +62 -0
- package/shared/agents/skimmer.md +88 -0
- package/shared/agents/synthesizer.md +204 -0
- package/shared/agents/validator.md +86 -0
- package/shared/skills/accessibility/SKILL.md +229 -0
- package/shared/skills/accessibility/references/detection.md +171 -0
- package/shared/skills/accessibility/references/patterns.md +670 -0
- package/shared/skills/accessibility/references/violations.md +419 -0
- package/shared/skills/agent-teams/SKILL.md +124 -0
- package/shared/skills/agent-teams/references/cleanup.md +104 -0
- package/shared/skills/agent-teams/references/communication.md +122 -0
- package/shared/skills/agent-teams/references/team-patterns.md +217 -0
- package/shared/skills/architecture-patterns/SKILL.md +153 -0
- package/shared/skills/architecture-patterns/references/detection.md +337 -0
- package/shared/skills/architecture-patterns/references/patterns.md +873 -0
- package/shared/skills/architecture-patterns/references/violations.md +575 -0
- package/shared/skills/complexity-patterns/SKILL.md +143 -0
- package/shared/skills/complexity-patterns/references/detection.md +264 -0
- package/shared/skills/complexity-patterns/references/patterns.md +487 -0
- package/shared/skills/complexity-patterns/references/violations.md +361 -0
- package/shared/skills/consistency-patterns/SKILL.md +140 -0
- package/shared/skills/consistency-patterns/references/detection.md +207 -0
- package/shared/skills/consistency-patterns/references/patterns.md +202 -0
- package/shared/skills/consistency-patterns/references/violations.md +213 -0
- package/shared/skills/core-patterns/SKILL.md +162 -0
- package/shared/skills/core-patterns/references/checklist.md +276 -0
- package/shared/skills/core-patterns/references/code-smell-violations.md +144 -0
- package/shared/skills/core-patterns/references/detection.md +303 -0
- package/shared/skills/core-patterns/references/patterns.md +576 -0
- package/shared/skills/core-patterns/references/violations.md +369 -0
- package/shared/skills/database-patterns/SKILL.md +134 -0
- package/shared/skills/database-patterns/references/detection.md +208 -0
- package/shared/skills/database-patterns/references/patterns.md +394 -0
- package/shared/skills/database-patterns/references/violations.md +332 -0
- package/shared/skills/dependencies-patterns/SKILL.md +141 -0
- package/shared/skills/dependencies-patterns/references/detection.md +181 -0
- package/shared/skills/dependencies-patterns/references/patterns.md +225 -0
- package/shared/skills/dependencies-patterns/references/violations.md +247 -0
- package/shared/skills/docs-framework/SKILL.md +134 -0
- package/shared/skills/docs-framework/references/patterns.md +346 -0
- package/shared/skills/docs-framework/references/violations.md +221 -0
- package/shared/skills/documentation-patterns/SKILL.md +125 -0
- package/shared/skills/documentation-patterns/references/detection.md +190 -0
- package/shared/skills/documentation-patterns/references/patterns.md +189 -0
- package/shared/skills/documentation-patterns/references/violations.md +163 -0
- package/shared/skills/frontend-design/SKILL.md +254 -0
- package/shared/skills/frontend-design/references/detection.md +184 -0
- package/shared/skills/frontend-design/references/patterns.md +511 -0
- package/shared/skills/frontend-design/references/violations.md +453 -0
- package/shared/skills/git-safety/SKILL.md +122 -0
- package/shared/skills/git-safety/references/detection.md +290 -0
- package/shared/skills/git-safety/references/patterns.md +289 -0
- package/shared/skills/git-safety/references/violations.md +18 -0
- package/shared/skills/git-workflow/SKILL.md +158 -0
- package/shared/skills/git-workflow/references/commit-patterns.md +115 -0
- package/shared/skills/git-workflow/references/commit-violations.md +77 -0
- package/shared/skills/git-workflow/references/pr-patterns.md +127 -0
- package/shared/skills/git-workflow/references/pr-violations.md +96 -0
- package/shared/skills/github-patterns/SKILL.md +153 -0
- package/shared/skills/github-patterns/references/patterns.md +572 -0
- package/shared/skills/github-patterns/references/violations.md +298 -0
- package/shared/skills/implementation-patterns/SKILL.md +162 -0
- package/shared/skills/implementation-patterns/references/patterns.md +1063 -0
- package/shared/skills/implementation-patterns/references/violations.md +483 -0
- package/shared/skills/input-validation/SKILL.md +148 -0
- package/shared/skills/input-validation/references/detection.md +283 -0
- package/shared/skills/input-validation/references/patterns.md +361 -0
- package/shared/skills/input-validation/references/violations.md +224 -0
- package/shared/skills/performance-patterns/SKILL.md +154 -0
- package/shared/skills/performance-patterns/references/detection.md +351 -0
- package/shared/skills/performance-patterns/references/patterns.md +503 -0
- package/shared/skills/performance-patterns/references/violations.md +354 -0
- package/shared/skills/react/SKILL.md +276 -0
- package/shared/skills/react/references/patterns.md +1331 -0
- package/shared/skills/react/references/violations.md +565 -0
- package/shared/skills/regression-patterns/SKILL.md +146 -0
- package/shared/skills/regression-patterns/references/detection.md +237 -0
- package/shared/skills/regression-patterns/references/patterns.md +226 -0
- package/shared/skills/regression-patterns/references/violations.md +225 -0
- package/shared/skills/review-methodology/SKILL.md +119 -0
- package/shared/skills/review-methodology/references/patterns.md +186 -0
- package/shared/skills/review-methodology/references/report-template.md +142 -0
- package/shared/skills/review-methodology/references/violations.md +125 -0
- package/shared/skills/security-patterns/SKILL.md +156 -0
- package/shared/skills/security-patterns/references/detection.md +287 -0
- package/shared/skills/security-patterns/references/patterns.md +507 -0
- package/shared/skills/security-patterns/references/violations.md +237 -0
- package/shared/skills/self-review/SKILL.md +149 -0
- package/shared/skills/self-review/references/patterns.md +405 -0
- package/shared/skills/self-review/references/report-template.md +253 -0
- package/shared/skills/self-review/references/violations.md +308 -0
- package/shared/skills/test-patterns/SKILL.md +183 -0
- package/shared/skills/test-patterns/references/detection.md +149 -0
- package/shared/skills/test-patterns/references/patterns.md +220 -0
- package/shared/skills/test-patterns/references/report-template.md +108 -0
- package/shared/skills/test-patterns/references/violations.md +221 -0
- package/shared/skills/typescript/SKILL.md +176 -0
- package/shared/skills/typescript/references/patterns.md +1105 -0
- package/shared/skills/typescript/references/violations.md +433 -0
- package/src/templates/claudeignore.template +188 -0
- package/src/templates/managed-settings.json +146 -0
- package/src/templates/settings.json +59 -0
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/uninstall.d.ts.map +0 -1
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/utils/git.d.ts.map +0 -1
- package/dist/utils/git.js.map +0 -1
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js.map +0 -1
- package/src/claude/CLAUDE.md +0 -400
- package/src/claude/agents/devflow/audit-architecture.md +0 -132
- package/src/claude/agents/devflow/audit-complexity.md +0 -132
- package/src/claude/agents/devflow/audit-database.md +0 -132
- package/src/claude/agents/devflow/audit-dependencies.md +0 -132
- package/src/claude/agents/devflow/audit-documentation.md +0 -132
- package/src/claude/agents/devflow/audit-performance.md +0 -256
- package/src/claude/agents/devflow/audit-security.md +0 -259
- package/src/claude/agents/devflow/audit-tests.md +0 -132
- package/src/claude/agents/devflow/audit-typescript.md +0 -132
- package/src/claude/agents/devflow/brainstorm.md +0 -279
- package/src/claude/agents/devflow/catch-up.md +0 -345
- package/src/claude/agents/devflow/code-review.md +0 -307
- package/src/claude/agents/devflow/commit.md +0 -380
- package/src/claude/agents/devflow/debug.md +0 -476
- package/src/claude/agents/devflow/design.md +0 -491
- package/src/claude/agents/devflow/pr-comments.md +0 -285
- package/src/claude/agents/devflow/project-state.md +0 -419
- package/src/claude/agents/devflow/pull-request.md +0 -423
- package/src/claude/agents/devflow/release.md +0 -1137
- package/src/claude/agents/devflow/tech-debt.md +0 -338
- package/src/claude/commands/devflow/brainstorm.md +0 -68
- package/src/claude/commands/devflow/breakdown.md +0 -125
- package/src/claude/commands/devflow/catch-up.md +0 -29
- package/src/claude/commands/devflow/code-review.md +0 -237
- package/src/claude/commands/devflow/commit.md +0 -17
- package/src/claude/commands/devflow/debug.md +0 -56
- package/src/claude/commands/devflow/design.md +0 -82
- package/src/claude/commands/devflow/devlog.md +0 -408
- package/src/claude/commands/devflow/implement.md +0 -100
- package/src/claude/commands/devflow/plan.md +0 -223
- package/src/claude/commands/devflow/pull-request.md +0 -269
- package/src/claude/commands/devflow/release.md +0 -251
- package/src/claude/commands/devflow/resolve-comments.md +0 -583
- package/src/claude/scripts/statusline.sh +0 -47
- package/src/claude/settings.json +0 -6
- package/src/claude/skills/devflow/code-smell/SKILL.md +0 -428
- package/src/claude/skills/devflow/debug/SKILL.md +0 -119
- package/src/claude/skills/devflow/error-handling/SKILL.md +0 -597
- package/src/claude/skills/devflow/input-validation/SKILL.md +0 -514
- package/src/claude/skills/devflow/pattern-check/SKILL.md +0 -238
- package/src/claude/skills/devflow/research/SKILL.md +0 -138
- package/src/claude/skills/devflow/test-design/SKILL.md +0 -384
|
@@ -0,0 +1,1063 @@
|
|
|
1
|
+
# Implementation Correct Patterns
|
|
2
|
+
|
|
3
|
+
Extended correct patterns for implementation. Reference from main SKILL.md.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## CRUD Patterns
|
|
8
|
+
|
|
9
|
+
### Create Operation
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
// CORRECT: Validate -> Transform -> Persist -> Return
|
|
13
|
+
async function createUser(input: CreateUserInput): Promise<Result<User, CreateError>> {
|
|
14
|
+
// 1. Validate input
|
|
15
|
+
const validated = validateCreateUser(input);
|
|
16
|
+
if (!validated.ok) {
|
|
17
|
+
return Err({ type: 'validation', details: validated.error });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 2. Transform to domain entity
|
|
21
|
+
const user: User = {
|
|
22
|
+
id: generateId(),
|
|
23
|
+
...validated.value,
|
|
24
|
+
createdAt: new Date(),
|
|
25
|
+
updatedAt: new Date(),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// 3. Persist
|
|
29
|
+
const saved = await userRepository.save(user);
|
|
30
|
+
if (!saved.ok) {
|
|
31
|
+
return Err({ type: 'persistence', details: saved.error });
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// 4. Return created entity
|
|
35
|
+
return Ok(saved.value);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Read Operation (Single)
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// CORRECT: Fetch -> NotFound check -> Transform -> Return
|
|
43
|
+
async function getUser(id: UserId): Promise<Result<UserDTO, GetError>> {
|
|
44
|
+
// 1. Fetch from store
|
|
45
|
+
const user = await userRepository.findById(id);
|
|
46
|
+
|
|
47
|
+
// 2. Handle not found
|
|
48
|
+
if (!user.ok) {
|
|
49
|
+
return Err({ type: 'not_found', id });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 3. Transform to DTO (hide internal fields)
|
|
53
|
+
const dto = toUserDTO(user.value);
|
|
54
|
+
|
|
55
|
+
// 4. Return
|
|
56
|
+
return Ok(dto);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Read Operation (List)
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
// CORRECT: Parse filters -> Query -> Transform -> Paginate
|
|
64
|
+
async function listUsers(params: ListParams): Promise<Result<PaginatedResult<UserDTO>, ListError>> {
|
|
65
|
+
// 1. Parse and validate filters
|
|
66
|
+
const filters = parseFilters(params);
|
|
67
|
+
const pagination = parsePagination(params);
|
|
68
|
+
|
|
69
|
+
// 2. Query with filters
|
|
70
|
+
const result = await userRepository.findMany({
|
|
71
|
+
where: filters,
|
|
72
|
+
skip: pagination.offset,
|
|
73
|
+
take: pagination.limit,
|
|
74
|
+
orderBy: pagination.orderBy,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 3. Transform to DTOs
|
|
78
|
+
const items = result.items.map(toUserDTO);
|
|
79
|
+
|
|
80
|
+
// 4. Return paginated result
|
|
81
|
+
return Ok({
|
|
82
|
+
items,
|
|
83
|
+
total: result.total,
|
|
84
|
+
page: pagination.page,
|
|
85
|
+
pageSize: pagination.limit,
|
|
86
|
+
hasMore: result.total > pagination.offset + items.length,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Update Operation
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// CORRECT: Fetch existing -> Validate changes -> Merge -> Persist
|
|
95
|
+
async function updateUser(
|
|
96
|
+
id: UserId,
|
|
97
|
+
input: UpdateUserInput
|
|
98
|
+
): Promise<Result<User, UpdateError>> {
|
|
99
|
+
// 1. Fetch existing
|
|
100
|
+
const existing = await userRepository.findById(id);
|
|
101
|
+
if (!existing.ok) {
|
|
102
|
+
return Err({ type: 'not_found', id });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 2. Validate changes
|
|
106
|
+
const validated = validateUpdateUser(input, existing.value);
|
|
107
|
+
if (!validated.ok) {
|
|
108
|
+
return Err({ type: 'validation', details: validated.error });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 3. Merge changes (immutable update)
|
|
112
|
+
const updated: User = {
|
|
113
|
+
...existing.value,
|
|
114
|
+
...validated.value,
|
|
115
|
+
updatedAt: new Date(),
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// 4. Persist
|
|
119
|
+
const saved = await userRepository.save(updated);
|
|
120
|
+
if (!saved.ok) {
|
|
121
|
+
return Err({ type: 'persistence', details: saved.error });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return Ok(saved.value);
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Delete Operation
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// CORRECT: Check exists -> Check constraints -> Delete -> Confirm
|
|
132
|
+
async function deleteUser(id: UserId): Promise<Result<void, DeleteError>> {
|
|
133
|
+
// 1. Check exists
|
|
134
|
+
const existing = await userRepository.findById(id);
|
|
135
|
+
if (!existing.ok) {
|
|
136
|
+
return Err({ type: 'not_found', id });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 2. Check constraints (can this be deleted?)
|
|
140
|
+
const canDelete = await checkDeleteConstraints(existing.value);
|
|
141
|
+
if (!canDelete.ok) {
|
|
142
|
+
return Err({ type: 'constraint_violation', details: canDelete.error });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 3. Delete (soft delete preferred)
|
|
146
|
+
const deleted = await userRepository.softDelete(id);
|
|
147
|
+
if (!deleted.ok) {
|
|
148
|
+
return Err({ type: 'persistence', details: deleted.error });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 4. Confirm success
|
|
152
|
+
return Ok(undefined);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Repository Pattern
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// CORRECT: Abstract data access behind interface
|
|
160
|
+
interface UserRepository {
|
|
161
|
+
findById(id: UserId): Promise<Result<User, NotFoundError>>;
|
|
162
|
+
findByEmail(email: string): Promise<Result<User, NotFoundError>>;
|
|
163
|
+
findMany(query: UserQuery): Promise<PaginatedResult<User>>;
|
|
164
|
+
save(user: User): Promise<Result<User, PersistenceError>>;
|
|
165
|
+
delete(id: UserId): Promise<Result<void, PersistenceError>>;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Implementation
|
|
169
|
+
class PostgresUserRepository implements UserRepository {
|
|
170
|
+
constructor(private db: Database) {}
|
|
171
|
+
|
|
172
|
+
async findById(id: UserId): Promise<Result<User, NotFoundError>> {
|
|
173
|
+
const row = await this.db.query(
|
|
174
|
+
'SELECT * FROM users WHERE id = $1',
|
|
175
|
+
[id]
|
|
176
|
+
);
|
|
177
|
+
if (!row) {
|
|
178
|
+
return Err({ type: 'not_found', entity: 'User', id });
|
|
179
|
+
}
|
|
180
|
+
return Ok(rowToUser(row));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ... other methods
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Transaction Pattern
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// CORRECT: Start transaction -> Execute operations -> Commit or rollback
|
|
191
|
+
async function transferFunds(
|
|
192
|
+
from: AccountId,
|
|
193
|
+
to: AccountId,
|
|
194
|
+
amount: Money
|
|
195
|
+
): Promise<Result<Transfer, TransferError>> {
|
|
196
|
+
return db.transaction(async (tx) => {
|
|
197
|
+
// 1. Debit source account
|
|
198
|
+
const debit = await tx.accounts.debit(from, amount);
|
|
199
|
+
if (!debit.ok) {
|
|
200
|
+
return Err({ type: 'insufficient_funds', account: from });
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// 2. Credit destination account
|
|
204
|
+
const credit = await tx.accounts.credit(to, amount);
|
|
205
|
+
if (!credit.ok) {
|
|
206
|
+
return Err({ type: 'credit_failed', account: to });
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 3. Record transfer
|
|
210
|
+
const transfer = await tx.transfers.create({
|
|
211
|
+
from,
|
|
212
|
+
to,
|
|
213
|
+
amount,
|
|
214
|
+
timestamp: new Date(),
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
return Ok(transfer);
|
|
218
|
+
});
|
|
219
|
+
// Transaction auto-commits on success, auto-rollbacks on error
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## API Endpoint Patterns
|
|
226
|
+
|
|
227
|
+
### REST Endpoint Structure
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
// CORRECT: Parse request -> Validate auth -> Execute -> Format response
|
|
231
|
+
export async function handleGetUser(req: Request): Promise<Response> {
|
|
232
|
+
// 1. Parse request parameters
|
|
233
|
+
const id = parsePathParam(req, 'id');
|
|
234
|
+
if (!id.ok) {
|
|
235
|
+
return errorResponse(400, 'Invalid user ID');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 2. Validate authentication/authorization
|
|
239
|
+
const auth = await authenticate(req);
|
|
240
|
+
if (!auth.ok) {
|
|
241
|
+
return errorResponse(401, 'Unauthorized');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const canAccess = authorize(auth.value, 'users:read', id.value);
|
|
245
|
+
if (!canAccess) {
|
|
246
|
+
return errorResponse(403, 'Forbidden');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 3. Execute business logic
|
|
250
|
+
const result = await getUser(id.value);
|
|
251
|
+
if (!result.ok) {
|
|
252
|
+
return handleError(result.error);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 4. Format response
|
|
256
|
+
return jsonResponse(200, result.value);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Error Response Mapping
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// CORRECT: Map domain errors to HTTP responses
|
|
264
|
+
function handleError(error: DomainError): Response {
|
|
265
|
+
switch (error.type) {
|
|
266
|
+
case 'not_found':
|
|
267
|
+
return errorResponse(404, 'Resource not found');
|
|
268
|
+
case 'validation':
|
|
269
|
+
return errorResponse(400, 'Validation failed', error.details);
|
|
270
|
+
case 'conflict':
|
|
271
|
+
return errorResponse(409, 'Resource conflict');
|
|
272
|
+
case 'unauthorized':
|
|
273
|
+
return errorResponse(401, 'Unauthorized');
|
|
274
|
+
case 'forbidden':
|
|
275
|
+
return errorResponse(403, 'Forbidden');
|
|
276
|
+
default:
|
|
277
|
+
// Log unexpected errors, return generic message
|
|
278
|
+
logger.error('Unexpected error', { error });
|
|
279
|
+
return errorResponse(500, 'Internal server error');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Request Validation
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// CORRECT: Use schema validation at API boundary
|
|
288
|
+
import { z } from 'zod';
|
|
289
|
+
|
|
290
|
+
const CreateUserSchema = z.object({
|
|
291
|
+
email: z.string().email(),
|
|
292
|
+
name: z.string().min(1).max(100),
|
|
293
|
+
role: z.enum(['user', 'admin']).default('user'),
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
function parseCreateUserRequest(req: Request): Result<CreateUserInput, ValidationError> {
|
|
297
|
+
const parsed = CreateUserSchema.safeParse(req.body);
|
|
298
|
+
if (!parsed.success) {
|
|
299
|
+
return Err({
|
|
300
|
+
type: 'validation',
|
|
301
|
+
errors: parsed.error.errors.map(e => ({
|
|
302
|
+
field: e.path.join('.'),
|
|
303
|
+
message: e.message,
|
|
304
|
+
})),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return Ok(parsed.data);
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### POST Endpoint Example
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
// CORRECT: Full POST endpoint with validation and auth
|
|
315
|
+
export async function handleCreateUser(req: Request): Promise<Response> {
|
|
316
|
+
// 1. Parse and validate request body
|
|
317
|
+
const input = parseCreateUserRequest(req);
|
|
318
|
+
if (!input.ok) {
|
|
319
|
+
return errorResponse(400, 'Invalid request', input.error.errors);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// 2. Authenticate caller
|
|
323
|
+
const auth = await authenticate(req);
|
|
324
|
+
if (!auth.ok) {
|
|
325
|
+
return errorResponse(401, 'Unauthorized');
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// 3. Check authorization
|
|
329
|
+
if (!authorize(auth.value, 'users:create')) {
|
|
330
|
+
return errorResponse(403, 'Forbidden');
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// 4. Execute business logic
|
|
334
|
+
const result = await createUser(input.value);
|
|
335
|
+
if (!result.ok) {
|
|
336
|
+
return handleError(result.error);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// 5. Return created resource
|
|
340
|
+
return jsonResponse(201, result.value, {
|
|
341
|
+
Location: `/api/users/${result.value.id}`,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Response Helpers
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// CORRECT: Consistent response formatting
|
|
350
|
+
function jsonResponse<T>(status: number, data: T, headers?: Record<string, string>): Response {
|
|
351
|
+
return new Response(JSON.stringify(data), {
|
|
352
|
+
status,
|
|
353
|
+
headers: {
|
|
354
|
+
'Content-Type': 'application/json',
|
|
355
|
+
...headers,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function errorResponse(status: number, message: string, details?: unknown): Response {
|
|
361
|
+
return jsonResponse(status, {
|
|
362
|
+
error: message,
|
|
363
|
+
details,
|
|
364
|
+
timestamp: new Date().toISOString(),
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function emptyResponse(status: number): Response {
|
|
369
|
+
return new Response(null, { status });
|
|
370
|
+
}
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Event Handler Patterns
|
|
376
|
+
|
|
377
|
+
### Async Event Handler
|
|
378
|
+
|
|
379
|
+
```typescript
|
|
380
|
+
// CORRECT: Validate event -> Process -> Handle errors -> Acknowledge
|
|
381
|
+
async function handleUserCreated(event: UserCreatedEvent): Promise<void> {
|
|
382
|
+
const logger = createLogger({ eventId: event.id, type: event.type });
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
// 1. Validate event structure
|
|
386
|
+
const validated = validateEvent(event);
|
|
387
|
+
if (!validated.ok) {
|
|
388
|
+
logger.warn('Invalid event structure', { error: validated.error });
|
|
389
|
+
return; // Don't retry invalid events
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// 2. Process event (idempotent operations)
|
|
393
|
+
await sendWelcomeEmail(event.userId);
|
|
394
|
+
await createDefaultSettings(event.userId);
|
|
395
|
+
await notifyAdmins(event.userId);
|
|
396
|
+
|
|
397
|
+
// 3. Success
|
|
398
|
+
logger.info('Event processed successfully');
|
|
399
|
+
} catch (error) {
|
|
400
|
+
// 4. Handle errors
|
|
401
|
+
logger.error('Event processing failed', { error });
|
|
402
|
+
throw error; // Rethrow for retry
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Idempotent Processing
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// CORRECT: Check if already processed -> Process -> Mark complete
|
|
411
|
+
async function processOrderEvent(event: OrderEvent): Promise<void> {
|
|
412
|
+
// 1. Check idempotency key
|
|
413
|
+
const alreadyProcessed = await idempotencyStore.exists(event.id);
|
|
414
|
+
if (alreadyProcessed) {
|
|
415
|
+
logger.info('Event already processed, skipping', { eventId: event.id });
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// 2. Process within transaction
|
|
420
|
+
await db.transaction(async (tx) => {
|
|
421
|
+
await processOrder(tx, event.order);
|
|
422
|
+
await idempotencyStore.mark(tx, event.id);
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// 3. Event processed
|
|
426
|
+
logger.info('Order event processed', { orderId: event.order.id });
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Event with Retry Logic
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
// CORRECT: Exponential backoff retry
|
|
434
|
+
interface RetryConfig {
|
|
435
|
+
maxAttempts: number;
|
|
436
|
+
initialDelayMs: number;
|
|
437
|
+
maxDelayMs: number;
|
|
438
|
+
backoffMultiplier: number;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
async function handleEventWithRetry<T>(
|
|
442
|
+
event: T,
|
|
443
|
+
handler: (event: T) => Promise<void>,
|
|
444
|
+
config: RetryConfig
|
|
445
|
+
): Promise<void> {
|
|
446
|
+
let attempt = 0;
|
|
447
|
+
let delay = config.initialDelayMs;
|
|
448
|
+
|
|
449
|
+
while (attempt < config.maxAttempts) {
|
|
450
|
+
try {
|
|
451
|
+
await handler(event);
|
|
452
|
+
return; // Success
|
|
453
|
+
} catch (error) {
|
|
454
|
+
attempt++;
|
|
455
|
+
|
|
456
|
+
if (attempt >= config.maxAttempts) {
|
|
457
|
+
logger.error('Event processing failed after max retries', {
|
|
458
|
+
eventId: (event as any).id,
|
|
459
|
+
attempts: attempt,
|
|
460
|
+
error,
|
|
461
|
+
});
|
|
462
|
+
throw error;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
logger.warn('Event processing failed, retrying', {
|
|
466
|
+
eventId: (event as any).id,
|
|
467
|
+
attempt,
|
|
468
|
+
nextDelayMs: delay,
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
await sleep(delay);
|
|
472
|
+
delay = Math.min(delay * config.backoffMultiplier, config.maxDelayMs);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Dead Letter Queue Pattern
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
// CORRECT: Move failed events to DLQ for manual review
|
|
482
|
+
interface DeadLetterEvent<T> {
|
|
483
|
+
originalEvent: T;
|
|
484
|
+
error: string;
|
|
485
|
+
failedAt: Date;
|
|
486
|
+
attempts: number;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
async function handleWithDeadLetter<T>(
|
|
490
|
+
event: T,
|
|
491
|
+
handler: (event: T) => Promise<void>,
|
|
492
|
+
maxAttempts: number = 3
|
|
493
|
+
): Promise<void> {
|
|
494
|
+
try {
|
|
495
|
+
await handleEventWithRetry(event, handler, {
|
|
496
|
+
maxAttempts,
|
|
497
|
+
initialDelayMs: 1000,
|
|
498
|
+
maxDelayMs: 30000,
|
|
499
|
+
backoffMultiplier: 2,
|
|
500
|
+
});
|
|
501
|
+
} catch (error) {
|
|
502
|
+
// Send to dead letter queue
|
|
503
|
+
await deadLetterQueue.push({
|
|
504
|
+
originalEvent: event,
|
|
505
|
+
error: error.message,
|
|
506
|
+
failedAt: new Date(),
|
|
507
|
+
attempts: maxAttempts,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
logger.error('Event moved to dead letter queue', {
|
|
511
|
+
eventId: (event as any).id,
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Event Batching
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
// CORRECT: Process events in batches for efficiency
|
|
521
|
+
async function processBatch<T>(
|
|
522
|
+
events: T[],
|
|
523
|
+
processor: (event: T) => Promise<void>,
|
|
524
|
+
batchSize: number = 10
|
|
525
|
+
): Promise<{ success: number; failed: number }> {
|
|
526
|
+
let success = 0;
|
|
527
|
+
let failed = 0;
|
|
528
|
+
|
|
529
|
+
for (let i = 0; i < events.length; i += batchSize) {
|
|
530
|
+
const batch = events.slice(i, i + batchSize);
|
|
531
|
+
|
|
532
|
+
const results = await Promise.allSettled(
|
|
533
|
+
batch.map(event => processor(event))
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
for (const result of results) {
|
|
537
|
+
if (result.status === 'fulfilled') {
|
|
538
|
+
success++;
|
|
539
|
+
} else {
|
|
540
|
+
failed++;
|
|
541
|
+
logger.error('Batch item failed', { error: result.reason });
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return { success, failed };
|
|
547
|
+
}
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Pub/Sub Handler Registration
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
// CORRECT: Typed event bus with error handling
|
|
554
|
+
type EventHandler<T> = (event: T) => Promise<void>;
|
|
555
|
+
|
|
556
|
+
class EventBus {
|
|
557
|
+
private handlers = new Map<string, EventHandler<unknown>[]>();
|
|
558
|
+
|
|
559
|
+
subscribe<T>(eventType: string, handler: EventHandler<T>): void {
|
|
560
|
+
const existing = this.handlers.get(eventType) || [];
|
|
561
|
+
this.handlers.set(eventType, [...existing, handler as EventHandler<unknown>]);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async publish<T>(eventType: string, event: T): Promise<void> {
|
|
565
|
+
const handlers = this.handlers.get(eventType) || [];
|
|
566
|
+
|
|
567
|
+
await Promise.all(
|
|
568
|
+
handlers.map(handler =>
|
|
569
|
+
handler(event).catch(error => {
|
|
570
|
+
logger.error('Event handler failed', { eventType, error });
|
|
571
|
+
})
|
|
572
|
+
)
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// Usage
|
|
578
|
+
const eventBus = new EventBus();
|
|
579
|
+
eventBus.subscribe('user.created', handleUserCreated);
|
|
580
|
+
eventBus.subscribe('user.created', sendWelcomeEmail);
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## Configuration Patterns
|
|
586
|
+
|
|
587
|
+
### Environment Configuration
|
|
588
|
+
|
|
589
|
+
```typescript
|
|
590
|
+
// CORRECT: Define schema -> Load from env -> Validate -> Export frozen
|
|
591
|
+
import { z } from 'zod';
|
|
592
|
+
|
|
593
|
+
const ConfigSchema = z.object({
|
|
594
|
+
// Server
|
|
595
|
+
PORT: z.coerce.number().default(3000),
|
|
596
|
+
HOST: z.string().default('0.0.0.0'),
|
|
597
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
598
|
+
|
|
599
|
+
// Database
|
|
600
|
+
DATABASE_URL: z.string().url(),
|
|
601
|
+
DATABASE_POOL_SIZE: z.coerce.number().min(1).max(100).default(10),
|
|
602
|
+
|
|
603
|
+
// External services
|
|
604
|
+
API_KEY: z.string().min(1),
|
|
605
|
+
API_TIMEOUT_MS: z.coerce.number().default(5000),
|
|
606
|
+
|
|
607
|
+
// Feature flags
|
|
608
|
+
ENABLE_NEW_FEATURE: z.coerce.boolean().default(false),
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
type Config = z.infer<typeof ConfigSchema>;
|
|
612
|
+
|
|
613
|
+
function loadConfig(): Config {
|
|
614
|
+
const result = ConfigSchema.safeParse(process.env);
|
|
615
|
+
if (!result.success) {
|
|
616
|
+
console.error('Configuration validation failed:');
|
|
617
|
+
for (const error of result.error.errors) {
|
|
618
|
+
console.error(` ${error.path.join('.')}: ${error.message}`);
|
|
619
|
+
}
|
|
620
|
+
process.exit(1);
|
|
621
|
+
}
|
|
622
|
+
return Object.freeze(result.data);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export const config = loadConfig();
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
### Feature Flags
|
|
629
|
+
|
|
630
|
+
```typescript
|
|
631
|
+
// CORRECT: Centralized flags with typed access
|
|
632
|
+
interface FeatureFlags {
|
|
633
|
+
newCheckoutFlow: boolean;
|
|
634
|
+
betaFeatures: boolean;
|
|
635
|
+
debugMode: boolean;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
const defaultFlags: FeatureFlags = {
|
|
639
|
+
newCheckoutFlow: false,
|
|
640
|
+
betaFeatures: false,
|
|
641
|
+
debugMode: false,
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
function loadFeatureFlags(): FeatureFlags {
|
|
645
|
+
return {
|
|
646
|
+
newCheckoutFlow: config.ENABLE_NEW_CHECKOUT === true,
|
|
647
|
+
betaFeatures: config.ENABLE_BETA === true,
|
|
648
|
+
debugMode: config.NODE_ENV === 'development',
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
export const features = loadFeatureFlags();
|
|
653
|
+
|
|
654
|
+
// Usage
|
|
655
|
+
if (features.newCheckoutFlow) {
|
|
656
|
+
return newCheckoutProcess(cart);
|
|
657
|
+
} else {
|
|
658
|
+
return legacyCheckoutProcess(cart);
|
|
659
|
+
}
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
### Runtime Feature Flags
|
|
663
|
+
|
|
664
|
+
```typescript
|
|
665
|
+
// CORRECT: Dynamic flags that can change at runtime
|
|
666
|
+
interface FeatureFlagService {
|
|
667
|
+
isEnabled(flag: string, context?: FlagContext): Promise<boolean>;
|
|
668
|
+
getVariant(flag: string, context?: FlagContext): Promise<string | null>;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
interface FlagContext {
|
|
672
|
+
userId?: string;
|
|
673
|
+
region?: string;
|
|
674
|
+
percentile?: number;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
class FeatureFlagClient implements FeatureFlagService {
|
|
678
|
+
constructor(private source: FlagSource) {}
|
|
679
|
+
|
|
680
|
+
async isEnabled(flag: string, context?: FlagContext): Promise<boolean> {
|
|
681
|
+
const flagConfig = await this.source.getFlag(flag);
|
|
682
|
+
if (!flagConfig) return false;
|
|
683
|
+
|
|
684
|
+
// Percentage rollout
|
|
685
|
+
if (flagConfig.percentageEnabled !== undefined && context?.percentile) {
|
|
686
|
+
return context.percentile <= flagConfig.percentageEnabled;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// User targeting
|
|
690
|
+
if (flagConfig.enabledForUsers && context?.userId) {
|
|
691
|
+
return flagConfig.enabledForUsers.includes(context.userId);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return flagConfig.enabled;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
### Secrets Management
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
// CORRECT: Load secrets separately from config
|
|
703
|
+
interface Secrets {
|
|
704
|
+
databasePassword: string;
|
|
705
|
+
apiKey: string;
|
|
706
|
+
jwtSecret: string;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
async function loadSecrets(): Promise<Secrets> {
|
|
710
|
+
// In production, fetch from secret manager
|
|
711
|
+
if (config.NODE_ENV === 'production') {
|
|
712
|
+
return {
|
|
713
|
+
databasePassword: await secretManager.get('db-password'),
|
|
714
|
+
apiKey: await secretManager.get('api-key'),
|
|
715
|
+
jwtSecret: await secretManager.get('jwt-secret'),
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// In development, use environment variables
|
|
720
|
+
const SecretsSchema = z.object({
|
|
721
|
+
DATABASE_PASSWORD: z.string().min(1),
|
|
722
|
+
API_KEY: z.string().min(1),
|
|
723
|
+
JWT_SECRET: z.string().min(32),
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
const result = SecretsSchema.safeParse(process.env);
|
|
727
|
+
if (!result.success) {
|
|
728
|
+
throw new Error('Missing required secrets');
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
return {
|
|
732
|
+
databasePassword: result.data.DATABASE_PASSWORD,
|
|
733
|
+
apiKey: result.data.API_KEY,
|
|
734
|
+
jwtSecret: result.data.JWT_SECRET,
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
### Configuration Validation on Startup
|
|
740
|
+
|
|
741
|
+
```typescript
|
|
742
|
+
// CORRECT: Fail fast with clear error messages
|
|
743
|
+
async function validateConfiguration(): Promise<void> {
|
|
744
|
+
const errors: string[] = [];
|
|
745
|
+
|
|
746
|
+
// Check required services are reachable
|
|
747
|
+
try {
|
|
748
|
+
await db.ping();
|
|
749
|
+
} catch (error) {
|
|
750
|
+
errors.push(`Database connection failed: ${error.message}`);
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
await redis.ping();
|
|
755
|
+
} catch (error) {
|
|
756
|
+
errors.push(`Redis connection failed: ${error.message}`);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// Validate configuration values
|
|
760
|
+
if (config.PORT < 1 || config.PORT > 65535) {
|
|
761
|
+
errors.push(`Invalid PORT: ${config.PORT}`);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (config.NODE_ENV === 'production' && config.logLevel === 'debug') {
|
|
765
|
+
errors.push('Debug logging should not be enabled in production');
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (errors.length > 0) {
|
|
769
|
+
console.error('Configuration validation failed:');
|
|
770
|
+
errors.forEach(e => console.error(` - ${e}`));
|
|
771
|
+
process.exit(1);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// Call on startup
|
|
776
|
+
await validateConfiguration();
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
## Logging Patterns
|
|
782
|
+
|
|
783
|
+
### Structured Logging
|
|
784
|
+
|
|
785
|
+
```typescript
|
|
786
|
+
// CORRECT: Context -> Level -> Message -> Data
|
|
787
|
+
interface LogContext {
|
|
788
|
+
requestId?: string;
|
|
789
|
+
userId?: string;
|
|
790
|
+
operation?: string;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
function createLogger(context: LogContext) {
|
|
794
|
+
return {
|
|
795
|
+
info: (message: string, data?: object) =>
|
|
796
|
+
log('info', message, { ...context, ...data }),
|
|
797
|
+
warn: (message: string, data?: object) =>
|
|
798
|
+
log('warn', message, { ...context, ...data }),
|
|
799
|
+
error: (message: string, data?: object) =>
|
|
800
|
+
log('error', message, { ...context, ...data }),
|
|
801
|
+
debug: (message: string, data?: object) =>
|
|
802
|
+
log('debug', message, { ...context, ...data }),
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Usage
|
|
807
|
+
const logger = createLogger({ requestId: req.id, userId: user.id });
|
|
808
|
+
logger.info('Processing order', { orderId: order.id, items: order.items.length });
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### Operation Logging
|
|
812
|
+
|
|
813
|
+
```typescript
|
|
814
|
+
// CORRECT: Log start -> Execute -> Log result
|
|
815
|
+
async function withLogging<T>(
|
|
816
|
+
logger: Logger,
|
|
817
|
+
operation: string,
|
|
818
|
+
fn: () => Promise<T>
|
|
819
|
+
): Promise<T> {
|
|
820
|
+
const startTime = Date.now();
|
|
821
|
+
logger.info(`${operation} started`);
|
|
822
|
+
|
|
823
|
+
try {
|
|
824
|
+
const result = await fn();
|
|
825
|
+
const duration = Date.now() - startTime;
|
|
826
|
+
logger.info(`${operation} completed`, { durationMs: duration });
|
|
827
|
+
return result;
|
|
828
|
+
} catch (error) {
|
|
829
|
+
const duration = Date.now() - startTime;
|
|
830
|
+
logger.error(`${operation} failed`, { durationMs: duration, error });
|
|
831
|
+
throw error;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Usage
|
|
836
|
+
const user = await withLogging(logger, 'CreateUser', () => createUser(input));
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
### JSON Log Format
|
|
840
|
+
|
|
841
|
+
```typescript
|
|
842
|
+
// CORRECT: Production-ready JSON logging
|
|
843
|
+
interface LogEntry {
|
|
844
|
+
timestamp: string;
|
|
845
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
846
|
+
message: string;
|
|
847
|
+
service: string;
|
|
848
|
+
environment: string;
|
|
849
|
+
requestId?: string;
|
|
850
|
+
userId?: string;
|
|
851
|
+
durationMs?: number;
|
|
852
|
+
error?: {
|
|
853
|
+
name: string;
|
|
854
|
+
message: string;
|
|
855
|
+
stack?: string;
|
|
856
|
+
};
|
|
857
|
+
[key: string]: unknown;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
function log(level: LogEntry['level'], message: string, data: object = {}): void {
|
|
861
|
+
const entry: LogEntry = {
|
|
862
|
+
timestamp: new Date().toISOString(),
|
|
863
|
+
level,
|
|
864
|
+
message,
|
|
865
|
+
service: config.serviceName,
|
|
866
|
+
environment: config.NODE_ENV,
|
|
867
|
+
...data,
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
// In production, output JSON
|
|
871
|
+
if (config.NODE_ENV === 'production') {
|
|
872
|
+
console.log(JSON.stringify(entry));
|
|
873
|
+
} else {
|
|
874
|
+
// In development, pretty print
|
|
875
|
+
const color = { debug: '\x1b[34m', info: '\x1b[32m', warn: '\x1b[33m', error: '\x1b[31m' }[level];
|
|
876
|
+
console.log(`${color}[${level.toUpperCase()}]\x1b[0m ${message}`, data);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
```
|
|
880
|
+
|
|
881
|
+
### Request Logging Middleware
|
|
882
|
+
|
|
883
|
+
```typescript
|
|
884
|
+
// CORRECT: Log all HTTP requests with timing
|
|
885
|
+
function requestLogger(req: Request, res: Response, next: NextFunction): void {
|
|
886
|
+
const requestId = req.headers['x-request-id'] || generateId();
|
|
887
|
+
const startTime = Date.now();
|
|
888
|
+
|
|
889
|
+
// Attach request ID for tracing
|
|
890
|
+
req.requestId = requestId;
|
|
891
|
+
res.setHeader('x-request-id', requestId);
|
|
892
|
+
|
|
893
|
+
// Log on response finish
|
|
894
|
+
res.on('finish', () => {
|
|
895
|
+
const duration = Date.now() - startTime;
|
|
896
|
+
|
|
897
|
+
log(res.statusCode >= 400 ? 'error' : 'info', 'HTTP Request', {
|
|
898
|
+
requestId,
|
|
899
|
+
method: req.method,
|
|
900
|
+
path: req.path,
|
|
901
|
+
statusCode: res.statusCode,
|
|
902
|
+
durationMs: duration,
|
|
903
|
+
userAgent: req.headers['user-agent'],
|
|
904
|
+
ip: req.ip,
|
|
905
|
+
});
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
next();
|
|
909
|
+
}
|
|
910
|
+
```
|
|
911
|
+
|
|
912
|
+
### Error Logging
|
|
913
|
+
|
|
914
|
+
```typescript
|
|
915
|
+
// CORRECT: Log errors with full context
|
|
916
|
+
function logError(error: Error, context: object = {}): void {
|
|
917
|
+
log('error', error.message, {
|
|
918
|
+
...context,
|
|
919
|
+
error: {
|
|
920
|
+
name: error.name,
|
|
921
|
+
message: error.message,
|
|
922
|
+
stack: config.NODE_ENV !== 'production' ? error.stack : undefined,
|
|
923
|
+
},
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// CORRECT: Wrap async handlers with error logging
|
|
928
|
+
function withErrorLogging<T extends (...args: any[]) => Promise<any>>(
|
|
929
|
+
fn: T,
|
|
930
|
+
context: object = {}
|
|
931
|
+
): T {
|
|
932
|
+
return (async (...args: Parameters<T>) => {
|
|
933
|
+
try {
|
|
934
|
+
return await fn(...args);
|
|
935
|
+
} catch (error) {
|
|
936
|
+
logError(error as Error, context);
|
|
937
|
+
throw error;
|
|
938
|
+
}
|
|
939
|
+
}) as T;
|
|
940
|
+
}
|
|
941
|
+
```
|
|
942
|
+
|
|
943
|
+
### Audit Logging
|
|
944
|
+
|
|
945
|
+
```typescript
|
|
946
|
+
// CORRECT: Immutable audit trail for sensitive operations
|
|
947
|
+
interface AuditEntry {
|
|
948
|
+
timestamp: Date;
|
|
949
|
+
actor: string;
|
|
950
|
+
action: string;
|
|
951
|
+
resource: string;
|
|
952
|
+
resourceId: string;
|
|
953
|
+
changes?: {
|
|
954
|
+
before: unknown;
|
|
955
|
+
after: unknown;
|
|
956
|
+
};
|
|
957
|
+
result: 'success' | 'failure';
|
|
958
|
+
metadata?: object;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
async function audit(entry: Omit<AuditEntry, 'timestamp'>): Promise<void> {
|
|
962
|
+
const fullEntry: AuditEntry = {
|
|
963
|
+
...entry,
|
|
964
|
+
timestamp: new Date(),
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
// Write to immutable audit log (not regular logs)
|
|
968
|
+
await auditStore.append(fullEntry);
|
|
969
|
+
|
|
970
|
+
// Also log for operational visibility
|
|
971
|
+
log('info', 'Audit event', {
|
|
972
|
+
action: entry.action,
|
|
973
|
+
resource: entry.resource,
|
|
974
|
+
resourceId: entry.resourceId,
|
|
975
|
+
actor: entry.actor,
|
|
976
|
+
result: entry.result,
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
// Usage
|
|
981
|
+
await audit({
|
|
982
|
+
actor: userId,
|
|
983
|
+
action: 'user.update',
|
|
984
|
+
resource: 'user',
|
|
985
|
+
resourceId: targetUserId,
|
|
986
|
+
changes: { before: oldUser, after: newUser },
|
|
987
|
+
result: 'success',
|
|
988
|
+
});
|
|
989
|
+
```
|
|
990
|
+
|
|
991
|
+
### Performance Logging
|
|
992
|
+
|
|
993
|
+
```typescript
|
|
994
|
+
// CORRECT: Log slow operations
|
|
995
|
+
const SLOW_THRESHOLD_MS = 1000;
|
|
996
|
+
|
|
997
|
+
async function withPerformanceLogging<T>(
|
|
998
|
+
logger: Logger,
|
|
999
|
+
operation: string,
|
|
1000
|
+
fn: () => Promise<T>,
|
|
1001
|
+
threshold: number = SLOW_THRESHOLD_MS
|
|
1002
|
+
): Promise<T> {
|
|
1003
|
+
const start = performance.now();
|
|
1004
|
+
|
|
1005
|
+
try {
|
|
1006
|
+
const result = await fn();
|
|
1007
|
+
const duration = performance.now() - start;
|
|
1008
|
+
|
|
1009
|
+
if (duration > threshold) {
|
|
1010
|
+
logger.warn(`Slow operation: ${operation}`, {
|
|
1011
|
+
durationMs: Math.round(duration),
|
|
1012
|
+
threshold,
|
|
1013
|
+
});
|
|
1014
|
+
} else {
|
|
1015
|
+
logger.debug(`${operation} completed`, { durationMs: Math.round(duration) });
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
return result;
|
|
1019
|
+
} catch (error) {
|
|
1020
|
+
const duration = performance.now() - start;
|
|
1021
|
+
logger.error(`${operation} failed`, {
|
|
1022
|
+
durationMs: Math.round(duration),
|
|
1023
|
+
error: (error as Error).message,
|
|
1024
|
+
});
|
|
1025
|
+
throw error;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
### Correlation IDs
|
|
1031
|
+
|
|
1032
|
+
```typescript
|
|
1033
|
+
// CORRECT: Trace requests across services
|
|
1034
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
1035
|
+
|
|
1036
|
+
interface RequestContext {
|
|
1037
|
+
requestId: string;
|
|
1038
|
+
traceId: string;
|
|
1039
|
+
spanId: string;
|
|
1040
|
+
userId?: string;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
const contextStorage = new AsyncLocalStorage<RequestContext>();
|
|
1044
|
+
|
|
1045
|
+
function getContext(): RequestContext | undefined {
|
|
1046
|
+
return contextStorage.getStore();
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
function runWithContext<T>(context: RequestContext, fn: () => T): T {
|
|
1050
|
+
return contextStorage.run(context, fn);
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
// Logger automatically includes context
|
|
1054
|
+
function createContextAwareLogger() {
|
|
1055
|
+
return {
|
|
1056
|
+
info: (message: string, data?: object) => {
|
|
1057
|
+
const context = getContext();
|
|
1058
|
+
log('info', message, { ...context, ...data });
|
|
1059
|
+
},
|
|
1060
|
+
// ... other levels
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
```
|