skillstore-cli 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/README.md +95 -0
- package/data/bundles/devflow-complete.json +19 -0
- package/data/free-skills/devflow-agile/manifest.json +19 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/retro.md +23 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/review.md +21 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/sprint.md +30 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile/standup.md +20 -0
- package/data/free-skills/devflow-agile/plugin/commands/agile.md +35 -0
- package/data/free-skills/devflow-agile/plugin/commands/devflow.md +42 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/SKILL.md +93 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/assets/sample-output.md +182 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/references/clean-architecture.md +361 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/references/clean-code-guide.md +207 -0
- package/data/free-skills/devflow-agile/plugin/skills/developer/references/debugging-methodology.md +191 -0
- package/data/free-skills/devflow-agile/template/agents/agile-coach.md +76 -0
- package/data/free-skills/devflow-agile/template/workflows/agile-sprint-workflow.md +81 -0
- package/data/free-skills/devflow-bootstrap/manifest.json +8 -0
- package/data/free-skills/devflow-bootstrap/plugin/commands/bootstrap/auto.md +31 -0
- package/data/free-skills/devflow-bootstrap/plugin/commands/bootstrap.md +38 -0
- package/data/free-skills/devflow-bootstrap/plugin/commands/devflow.md +20 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/SKILL.md +56 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/assets/sample-output.md +216 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/references/architecture-decisions.md +254 -0
- package/data/free-skills/devflow-bootstrap/plugin/skills/project-scaffold/references/stack-templates.md +400 -0
- package/data/free-skills/devflow-bootstrap/template/agents/bootstrap-specialist.md +56 -0
- package/data/free-skills/devflow-bootstrap/template/workflows/bootstrap-workflow.md +70 -0
- package/data/free-skills/devflow-docs/manifest.json +8 -0
- package/data/free-skills/devflow-docs/plugin/commands/devflow.md +20 -0
- package/data/free-skills/devflow-docs/plugin/commands/docs/generate.md +17 -0
- package/data/free-skills/devflow-docs/plugin/commands/docs/parse.md +19 -0
- package/data/free-skills/devflow-docs/plugin/commands/docs.md +26 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/SKILL.md +59 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/assets/sample-output.md +114 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/references/extraction-techniques.md +115 -0
- package/data/free-skills/devflow-docs/plugin/skills/pdf-processor/references/ocr-strategies.md +167 -0
- package/data/free-skills/devflow-docs/template/agents/docs-specialist.md +35 -0
- package/data/free-skills/devflow-docs/template/workflows/docs-workflow.md +70 -0
- package/data/free-skills/devflow-postproject/manifest.json +13 -0
- package/data/free-skills/devflow-postproject/plugin/commands/devflow.md +34 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject/handover.md +21 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject/retro.md +21 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject/support.md +21 -0
- package/data/free-skills/devflow-postproject/plugin/commands/postproject.md +32 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/SKILL.md +70 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/assets/sample-output.md +79 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/references/facilitation-techniques.md +178 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/references/lessons-learned-template.md +118 -0
- package/data/free-skills/devflow-postproject/plugin/skills/retrospective/references/retro-techniques.md +100 -0
- package/data/free-skills/devflow-postproject/template/agents/transition-manager.md +71 -0
- package/data/free-skills/devflow-postproject/template/workflows/transition-workflow.md +72 -0
- package/data/free-skills/devflow-presale/manifest.json +15 -0
- package/data/free-skills/devflow-presale/plugin/commands/devflow.md +47 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/analyze.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/estimate.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/price.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale/propose.md +30 -0
- package/data/free-skills/devflow-presale/plugin/commands/presale.md +42 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/SKILL.md +63 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/assets/sample-output.md +129 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/references/extraction-framework.md +140 -0
- package/data/free-skills/devflow-presale/plugin/skills/requirement-analysis/references/output-template.md +132 -0
- package/data/free-skills/devflow-presale/template/agents/presale-lead.md +83 -0
- package/data/free-skills/devflow-presale/template/agents/proposal-reviewer.md +63 -0
- package/data/free-skills/devflow-presale/template/workflows/presale-workflow.md +70 -0
- package/data/registry/categories.json +7 -0
- package/data/registry/packages.json +184 -0
- package/data/shared/framework/agents/brainstormer.md +74 -0
- package/data/shared/framework/agents/code-reviewer.md +87 -0
- package/data/shared/framework/agents/debugger.md +84 -0
- package/data/shared/framework/agents/docs-manager.md +55 -0
- package/data/shared/framework/agents/git-manager.md +59 -0
- package/data/shared/framework/agents/planner.md +68 -0
- package/data/shared/framework/agents/researcher.md +66 -0
- package/data/shared/framework/agents/tester.md +65 -0
- package/data/shared/framework/commands/cook/auto.md +27 -0
- package/data/shared/framework/commands/cook.md +45 -0
- package/data/shared/framework/commands/fix/ci.md +21 -0
- package/data/shared/framework/commands/fix/test.md +26 -0
- package/data/shared/framework/commands/fix/types.md +29 -0
- package/data/shared/framework/commands/fix.md +26 -0
- package/data/shared/framework/commands/git/cm.md +37 -0
- package/data/shared/framework/commands/git/pr.md +40 -0
- package/data/shared/framework/config/CLAUDE.md.template +26 -0
- package/data/shared/framework/config/settings.json +41 -0
- package/data/shared/framework/config/skillstore.config.json +29 -0
- package/data/shared/framework/hooks/discord-notify.sh +85 -0
- package/data/shared/framework/hooks/docs-sync.sh +53 -0
- package/data/shared/framework/hooks/modularization-hook.js +103 -0
- package/data/shared/framework/hooks/notification.js +94 -0
- package/data/shared/framework/hooks/quality-gate.js +109 -0
- package/data/shared/framework/hooks/scout-block.js +77 -0
- package/data/shared/framework/hooks/telegram-notify.sh +77 -0
- package/data/shared/framework/protocols/error-recovery.md +80 -0
- package/data/shared/framework/protocols/orchestration-protocol.md +112 -0
- package/data/shared/framework/quality/review-protocol.md +76 -0
- package/data/shared/framework/quality/verification-protocol.md +66 -0
- package/data/shared/framework/rules/development-rules.md +75 -0
- package/data/shared/framework/skills/backend-development/SKILL.md +77 -0
- package/data/shared/framework/skills/backend-development/assets/sample-output.md +175 -0
- package/data/shared/framework/skills/backend-development/references/advanced-patterns.md +180 -0
- package/data/shared/framework/skills/backend-development/references/api-design-guide.md +160 -0
- package/data/shared/framework/skills/backend-development/references/architecture-patterns.md +183 -0
- package/data/shared/framework/skills/backend-development/references/observability-resilience.md +155 -0
- package/data/shared/framework/skills/backend-development/references/troubleshooting.md +199 -0
- package/data/shared/framework/skills/codebase-analysis/SKILL.md +72 -0
- package/data/shared/framework/skills/codebase-analysis/assets/sample-output.md +263 -0
- package/data/shared/framework/skills/codebase-analysis/references/analysis-techniques.md +241 -0
- package/data/shared/framework/skills/codebase-analysis/references/dependency-mapping.md +280 -0
- package/data/shared/framework/skills/codebase-analysis/references/tech-debt-assessment.md +208 -0
- package/data/shared/framework/skills/databases/SKILL.md +72 -0
- package/data/shared/framework/skills/databases/assets/sample-output.md +212 -0
- package/data/shared/framework/skills/databases/references/advanced-data-patterns.md +259 -0
- package/data/shared/framework/skills/databases/references/query-optimization.md +214 -0
- package/data/shared/framework/skills/databases/references/schema-design.md +159 -0
- package/data/shared/framework/skills/databases/references/troubleshooting.md +214 -0
- package/data/shared/framework/skills/debugging-investigation/SKILL.md +84 -0
- package/data/shared/framework/skills/debugging-investigation/assets/sample-output.md +314 -0
- package/data/shared/framework/skills/debugging-investigation/references/systematic-debugging.md +197 -0
- package/data/shared/framework/skills/debugging-investigation/references/tool-specific-guides.md +202 -0
- package/data/shared/framework/skills/debugging-investigation/references/troubleshooting-patterns.md +196 -0
- package/data/shared/framework/skills/frontend-development/SKILL.md +67 -0
- package/data/shared/framework/skills/frontend-development/assets/sample-output.md +110 -0
- package/data/shared/framework/skills/frontend-development/references/component-patterns.md +112 -0
- package/data/shared/framework/skills/frontend-development/references/performance-guide.md +169 -0
- package/data/shared/framework/skills/frontend-development/references/routing-forms-realtime.md +374 -0
- package/data/shared/framework/skills/frontend-development/references/ssr-rsc-patterns.md +284 -0
- package/data/shared/framework/skills/frontend-development/references/troubleshooting.md +154 -0
- package/data/shared/framework/skills/mobile-development/SKILL.md +67 -0
- package/data/shared/framework/skills/mobile-development/assets/sample-output.md +382 -0
- package/data/shared/framework/skills/mobile-development/references/mobile-patterns.md +681 -0
- package/data/shared/framework/skills/mobile-development/references/mobile-performance.md +524 -0
- package/data/shared/framework/skills/mobile-development/references/troubleshooting.md +158 -0
- package/data/shared/framework/skills/security-audit/SKILL.md +83 -0
- package/data/shared/framework/skills/security-audit/assets/sample-output.md +451 -0
- package/data/shared/framework/skills/security-audit/references/owasp-checklist.md +580 -0
- package/data/shared/framework/skills/security-audit/references/secure-coding-patterns.md +433 -0
- package/data/shared/framework/skills/security-audit/references/vulnerability-remediation.md +331 -0
- package/data/shared/framework/skills/ui-generation/SKILL.md +70 -0
- package/data/shared/framework/skills/ui-generation/assets/sample-output.md +139 -0
- package/data/shared/framework/skills/ui-generation/references/accessibility-responsive.md +127 -0
- package/data/shared/framework/skills/ui-generation/references/compound-components.md +252 -0
- package/data/shared/framework/skills/ui-generation/references/generation-patterns.md +110 -0
- package/data/shared/framework/skills/ui-generation/references/storybook-design-system.md +278 -0
- package/data/shared/framework/skills/ui-generation/references/troubleshooting.md +198 -0
- package/data/shared/framework/workflows/documentation-management.md +58 -0
- package/data/shared/framework/workflows/primary-workflow.md +88 -0
- package/dist/commands/activate.d.ts +3 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +34 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/bundle.d.ts +3 -0
- package/dist/commands/bundle.d.ts.map +1 -0
- package/dist/commands/bundle.js +64 -0
- package/dist/commands/bundle.js.map +1 -0
- package/dist/commands/install.d.ts +3 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +99 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +37 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/search.d.ts +3 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +30 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +35 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +68 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/download/cache.d.ts +3 -0
- package/dist/download/cache.d.ts.map +1 -0
- package/dist/download/cache.js +18 -0
- package/dist/download/cache.js.map +1 -0
- package/dist/download/client.d.ts +2 -0
- package/dist/download/client.d.ts.map +1 -0
- package/dist/download/client.js +58 -0
- package/dist/download/client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/installer/file-copier.d.ts +6 -0
- package/dist/installer/file-copier.d.ts.map +1 -0
- package/dist/installer/file-copier.js +32 -0
- package/dist/installer/file-copier.js.map +1 -0
- package/dist/installer/plugin-installer.d.ts +12 -0
- package/dist/installer/plugin-installer.d.ts.map +1 -0
- package/dist/installer/plugin-installer.js +33 -0
- package/dist/installer/plugin-installer.js.map +1 -0
- package/dist/installer/template-installer.d.ts +12 -0
- package/dist/installer/template-installer.d.ts.map +1 -0
- package/dist/installer/template-installer.js +45 -0
- package/dist/installer/template-installer.js.map +1 -0
- package/dist/license/crypto.d.ts +16 -0
- package/dist/license/crypto.d.ts.map +1 -0
- package/dist/license/crypto.js +50 -0
- package/dist/license/crypto.js.map +1 -0
- package/dist/license/license-store.d.ts +19 -0
- package/dist/license/license-store.d.ts.map +1 -0
- package/dist/license/license-store.js +99 -0
- package/dist/license/license-store.js.map +1 -0
- package/dist/license/validator.d.ts +32 -0
- package/dist/license/validator.d.ts.map +1 -0
- package/dist/license/validator.js +81 -0
- package/dist/license/validator.js.map +1 -0
- package/dist/registry/loader.d.ts +30 -0
- package/dist/registry/loader.d.ts.map +1 -0
- package/dist/registry/loader.js +22 -0
- package/dist/registry/loader.js.map +1 -0
- package/dist/registry/search-engine.d.ts +9 -0
- package/dist/registry/search-engine.d.ts.map +1 -0
- package/dist/registry/search-engine.js +30 -0
- package/dist/registry/search-engine.js.map +1 -0
- package/dist/utils/config.d.ts +14 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +28 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +9 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +20 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +79 -0
- package/dist/utils/paths.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Sample Output: Task Management API Design
|
|
2
|
+
|
|
3
|
+
## Service Overview
|
|
4
|
+
|
|
5
|
+
A REST API for managing tasks within projects. Supports CRUD operations, assignment, status transitions, and filtering.
|
|
6
|
+
|
|
7
|
+
## Base URL
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
https://api.example.com/v1
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Authentication
|
|
14
|
+
|
|
15
|
+
All endpoints require a Bearer JWT token in the `Authorization` header:
|
|
16
|
+
```
|
|
17
|
+
Authorization: Bearer eyJhbGciOiJSUzI1NiIs...
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Endpoints
|
|
21
|
+
|
|
22
|
+
### 1. List Tasks
|
|
23
|
+
```
|
|
24
|
+
GET /projects/{projectId}/tasks?status=open&assignee=user-123&sort=-priority,created_at&page=1&per_page=25
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Response: 200 OK**
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"data": [
|
|
31
|
+
{
|
|
32
|
+
"id": "task-456",
|
|
33
|
+
"title": "Implement user authentication",
|
|
34
|
+
"description": "Add JWT-based auth with refresh tokens",
|
|
35
|
+
"status": "in_progress",
|
|
36
|
+
"priority": "high",
|
|
37
|
+
"assignee": { "id": "user-123", "name": "Nguyen Van A" },
|
|
38
|
+
"due_date": "2026-04-01",
|
|
39
|
+
"created_at": "2026-03-15T08:00:00Z",
|
|
40
|
+
"updated_at": "2026-03-18T14:30:00Z"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"meta": { "current_page": 1, "per_page": 25, "total_items": 42, "total_pages": 2 }
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 2. Create Task
|
|
48
|
+
```
|
|
49
|
+
POST /projects/{projectId}/tasks
|
|
50
|
+
Content-Type: application/json
|
|
51
|
+
|
|
52
|
+
{
|
|
53
|
+
"title": "Implement user authentication",
|
|
54
|
+
"description": "Add JWT-based auth with refresh tokens",
|
|
55
|
+
"priority": "high",
|
|
56
|
+
"assignee_id": "user-123",
|
|
57
|
+
"due_date": "2026-04-01"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Response: 201 Created**
|
|
62
|
+
```
|
|
63
|
+
Location: /v1/projects/proj-789/tasks/task-456
|
|
64
|
+
```
|
|
65
|
+
Returns the created task object.
|
|
66
|
+
|
|
67
|
+
**Validation Rules:**
|
|
68
|
+
- `title`: required, 1–200 characters
|
|
69
|
+
- `priority`: required, enum: `low`, `medium`, `high`, `critical`
|
|
70
|
+
- `assignee_id`: optional, must be a valid project member
|
|
71
|
+
- `due_date`: optional, must be today or future
|
|
72
|
+
|
|
73
|
+
### 3. Get Task
|
|
74
|
+
```
|
|
75
|
+
GET /projects/{projectId}/tasks/{taskId}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Response: 200 OK** — full task object with comments count and activity log.
|
|
79
|
+
|
|
80
|
+
**Response: 404 Not Found**
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"type": "https://api.example.com/errors/not-found",
|
|
84
|
+
"title": "Not Found",
|
|
85
|
+
"status": 404,
|
|
86
|
+
"detail": "Task 'task-999' not found in project 'proj-789'."
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 4. Update Task
|
|
91
|
+
```
|
|
92
|
+
PATCH /projects/{projectId}/tasks/{taskId}
|
|
93
|
+
Content-Type: application/json
|
|
94
|
+
|
|
95
|
+
{
|
|
96
|
+
"status": "done",
|
|
97
|
+
"priority": "medium"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Response: 200 OK** — returns updated task.
|
|
102
|
+
|
|
103
|
+
**Status Transition Rules:**
|
|
104
|
+
```
|
|
105
|
+
open → in_progress → in_review → done
|
|
106
|
+
→ blocked → in_progress
|
|
107
|
+
done → open (reopen)
|
|
108
|
+
```
|
|
109
|
+
Invalid transitions return 422.
|
|
110
|
+
|
|
111
|
+
### 5. Delete Task
|
|
112
|
+
```
|
|
113
|
+
DELETE /projects/{projectId}/tasks/{taskId}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Response: 204 No Content**
|
|
117
|
+
|
|
118
|
+
Only project admins can delete tasks. Returns 403 otherwise.
|
|
119
|
+
|
|
120
|
+
## Error Handling
|
|
121
|
+
|
|
122
|
+
### Validation Error (400)
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"type": "https://api.example.com/errors/validation-error",
|
|
126
|
+
"title": "Validation Error",
|
|
127
|
+
"status": 400,
|
|
128
|
+
"detail": "The request body contains invalid fields.",
|
|
129
|
+
"errors": [
|
|
130
|
+
{ "field": "title", "message": "Title is required" },
|
|
131
|
+
{ "field": "priority", "message": "Must be one of: low, medium, high, critical" }
|
|
132
|
+
],
|
|
133
|
+
"trace_id": "req-abc-123"
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Unauthorized (401)
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"type": "https://api.example.com/errors/unauthorized",
|
|
141
|
+
"title": "Unauthorized",
|
|
142
|
+
"status": 401,
|
|
143
|
+
"detail": "Access token is expired or invalid."
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Business Rule Violation (422)
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"type": "https://api.example.com/errors/invalid-transition",
|
|
151
|
+
"title": "Invalid Status Transition",
|
|
152
|
+
"status": 422,
|
|
153
|
+
"detail": "Cannot transition from 'open' to 'done'. Task must go through 'in_progress' first."
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Architecture
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
routes/tasks.ts → Route definitions, auth middleware
|
|
161
|
+
controllers/TaskCtrl.ts → Input validation, HTTP response
|
|
162
|
+
services/TaskService.ts → Business logic, status transitions
|
|
163
|
+
repos/TaskRepository.ts → Database queries (Knex/Kysely)
|
|
164
|
+
models/Task.ts → TypeScript interfaces
|
|
165
|
+
validators/task.ts → Zod schemas for request validation
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Rate Limits
|
|
169
|
+
|
|
170
|
+
| Endpoint | Limit |
|
|
171
|
+
|----------|-------|
|
|
172
|
+
| GET (list/read) | 100 req/min |
|
|
173
|
+
| POST/PATCH/DELETE | 30 req/min |
|
|
174
|
+
|
|
175
|
+
Returns `429` with `Retry-After` header when exceeded.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# Advanced Backend Patterns
|
|
2
|
+
|
|
3
|
+
## gRPC & Protocol Buffers
|
|
4
|
+
|
|
5
|
+
### Protobuf Schema Design
|
|
6
|
+
|
|
7
|
+
```protobuf
|
|
8
|
+
syntax = "proto3";
|
|
9
|
+
package orders.v1;
|
|
10
|
+
|
|
11
|
+
message Order {
|
|
12
|
+
string order_id = 1;
|
|
13
|
+
string customer_id = 2;
|
|
14
|
+
repeated LineItem items = 3;
|
|
15
|
+
OrderStatus status = 4;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
message LineItem {
|
|
19
|
+
string product_id = 1;
|
|
20
|
+
int32 quantity = 2;
|
|
21
|
+
int64 price_cents = 3; // Integer cents, never float for money
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
enum OrderStatus {
|
|
25
|
+
ORDER_STATUS_UNSPECIFIED = 0;
|
|
26
|
+
ORDER_STATUS_PENDING = 1;
|
|
27
|
+
ORDER_STATUS_CONFIRMED = 2;
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Schema rules:** Prefix enums with type name. Reserve removed field numbers (`reserved 6, 7;`). Use integers for money. Never reuse field numbers.
|
|
32
|
+
|
|
33
|
+
### Service Definitions & Streaming
|
|
34
|
+
|
|
35
|
+
```protobuf
|
|
36
|
+
service OrderService {
|
|
37
|
+
rpc GetOrder(GetOrderRequest) returns (Order); // Unary
|
|
38
|
+
rpc WatchOrderStatus(WatchRequest) returns (stream OrderEvent); // Server stream
|
|
39
|
+
rpc UploadLineItems(stream LineItem) returns (UploadSummary); // Client stream
|
|
40
|
+
rpc LiveOrderChat(stream ChatMessage) returns (stream ChatMessage); // Bidirectional
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- **Unary** — Standard CRUD, simple queries
|
|
45
|
+
- **Server stream** — Real-time feeds, progress updates, large result sets
|
|
46
|
+
- **Client stream** — File uploads, batch ingestion, telemetry
|
|
47
|
+
- **Bidirectional** — Chat, collaborative editing, live dashboards
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Webhooks
|
|
52
|
+
|
|
53
|
+
### Delivery with Retry & Idempotency
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
interface WebhookDelivery {
|
|
57
|
+
id: string; // Unique delivery ID
|
|
58
|
+
event_id: string; // Idempotency key
|
|
59
|
+
event_type: string;
|
|
60
|
+
payload: unknown;
|
|
61
|
+
signature: string; // HMAC-SHA256
|
|
62
|
+
timestamp: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function deliverWebhook(delivery: WebhookDelivery, endpoint: string) {
|
|
66
|
+
for (let attempt = 0; attempt <= 5; attempt++) {
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(endpoint, {
|
|
69
|
+
method: 'POST',
|
|
70
|
+
headers: {
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
'X-Webhook-Id': delivery.id,
|
|
73
|
+
'X-Webhook-Signature': delivery.signature,
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify(delivery.payload),
|
|
76
|
+
signal: AbortSignal.timeout(10_000),
|
|
77
|
+
});
|
|
78
|
+
if (res.ok || (res.status >= 400 && res.status < 500)) return;
|
|
79
|
+
} catch { /* network error */ }
|
|
80
|
+
const delay = Math.pow(2, attempt) * 1000 + Math.random() * 500;
|
|
81
|
+
await new Promise(r => setTimeout(r, delay));
|
|
82
|
+
}
|
|
83
|
+
await moveToDeadLetterQueue(delivery);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Signature Verification
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
91
|
+
|
|
92
|
+
function verifySignature(payload: string, signature: string, secret: string): boolean {
|
|
93
|
+
const expected = createHmac('sha256', secret).update(payload).digest('hex');
|
|
94
|
+
return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Use `timingSafeEqual` to prevent timing attacks. Reject payloads older than 5 minutes. Deduplicate using `event_id`.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Event Sourcing
|
|
103
|
+
|
|
104
|
+
### Event Store Design
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
EventStore table:
|
|
108
|
+
stream_id VARCHAR -- aggregate ID (e.g. "order-123")
|
|
109
|
+
version INTEGER -- monotonically increasing per stream
|
|
110
|
+
event_type VARCHAR -- e.g. "OrderPlaced", "ItemAdded"
|
|
111
|
+
payload JSONB -- event data
|
|
112
|
+
metadata JSONB -- correlation_id, causation_id, user_id
|
|
113
|
+
created_at TIMESTAMPTZ -- append-only, never updated
|
|
114
|
+
UNIQUE(stream_id, version) -- optimistic concurrency control
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- **Live projections** — Updated in real-time as events are appended
|
|
118
|
+
- **Catch-up projections** — Rebuild from event stream position 0
|
|
119
|
+
- **Snapshots** — Capture state every N events; on load, replay only events after snapshot
|
|
120
|
+
- **Replay** — Rebuild read models, debug with exact state reproduction, create new projections
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## CQRS
|
|
125
|
+
|
|
126
|
+
**Command side:** Receives writes, validates business rules, emits domain events. Returns success/failure only.
|
|
127
|
+
|
|
128
|
+
**Query side:** Maintains denormalized read models per use case. Updated async via event handlers.
|
|
129
|
+
|
|
130
|
+
**Eventual consistency handling:**
|
|
131
|
+
- Return `202 Accepted` with resource location for polling
|
|
132
|
+
- Read-your-writes: briefly read from write model after a command
|
|
133
|
+
- Include event version in responses so clients detect stale reads
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Message Queues
|
|
138
|
+
|
|
139
|
+
### RabbitMQ vs Kafka
|
|
140
|
+
|
|
141
|
+
| Criteria | RabbitMQ | Kafka |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| Pattern | Task queue, work distribution | Event log, stream processing |
|
|
144
|
+
| Ordering | Per-queue FIFO | Per-partition ordering |
|
|
145
|
+
| Retention | Removed after ack | Retained by time/size policy |
|
|
146
|
+
| Throughput | ~50K msg/s | ~1M+ msg/s |
|
|
147
|
+
| Replay | Not supported | From any offset |
|
|
148
|
+
| Best for | Job queues, RPC, routing | Event sourcing, analytics, CDC |
|
|
149
|
+
|
|
150
|
+
**Dead letter queues:** Messages failing N times move to DLQ. Monitor DLQ depth — growth signals a bug.
|
|
151
|
+
|
|
152
|
+
**Consumer groups (Kafka):** Each group gets every message. Within a group, partitions distribute across consumers. Max parallelism = partition count.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Saga Pattern (Distributed Transactions)
|
|
157
|
+
|
|
158
|
+
### Orchestration
|
|
159
|
+
|
|
160
|
+
A central coordinator directs steps and compensations:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
OrderSaga:
|
|
164
|
+
1. ReserveInventory → success → 2 | fail → END
|
|
165
|
+
2. ProcessPayment → success → 3 | fail → CompensateInventory → END
|
|
166
|
+
3. ShipOrder → success → END | fail → RefundPayment → CompensateInventory → END
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Choreography
|
|
170
|
+
|
|
171
|
+
Services react to events independently:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
OrderService → emits OrderPlaced
|
|
175
|
+
InventoryService → listens OrderPlaced → emits InventoryReserved
|
|
176
|
+
PaymentService → listens InventoryReserved → emits PaymentProcessed
|
|
177
|
+
ShippingService → listens PaymentProcessed → emits OrderShipped
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**Choose orchestration** for complex flows with many compensations. **Choose choreography** for simple flows (3-4 steps) with truly independent services.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# API Design Guide
|
|
2
|
+
|
|
3
|
+
## RESTful Design Principles
|
|
4
|
+
|
|
5
|
+
### Resource Naming
|
|
6
|
+
- Use nouns, not verbs: `/users` not `/getUsers`
|
|
7
|
+
- Use plural: `/tasks` not `/task`
|
|
8
|
+
- Nest for relationships: `/users/{id}/tasks`
|
|
9
|
+
- Keep URLs max 3 levels deep — beyond that, use query params or separate endpoints
|
|
10
|
+
- Use kebab-case: `/order-items` not `/orderItems`
|
|
11
|
+
|
|
12
|
+
### HTTP Methods
|
|
13
|
+
|
|
14
|
+
| Method | Purpose | Idempotent | Response |
|
|
15
|
+
|--------|---------|------------|----------|
|
|
16
|
+
| GET | Read resource(s) | Yes | 200 with body |
|
|
17
|
+
| POST | Create resource | No | 201 with Location header |
|
|
18
|
+
| PUT | Full replace | Yes | 200 with body |
|
|
19
|
+
| PATCH | Partial update | No* | 200 with body |
|
|
20
|
+
| DELETE | Remove resource | Yes | 204 no body |
|
|
21
|
+
|
|
22
|
+
### Status Codes — Use These
|
|
23
|
+
|
|
24
|
+
| Code | When |
|
|
25
|
+
|------|------|
|
|
26
|
+
| 200 | Successful read/update |
|
|
27
|
+
| 201 | Resource created |
|
|
28
|
+
| 204 | Successful delete (no body) |
|
|
29
|
+
| 400 | Validation error, malformed request |
|
|
30
|
+
| 401 | Not authenticated |
|
|
31
|
+
| 403 | Authenticated but not authorized |
|
|
32
|
+
| 404 | Resource not found |
|
|
33
|
+
| 409 | Conflict (duplicate, state violation) |
|
|
34
|
+
| 422 | Semantically invalid (understood but can't process) |
|
|
35
|
+
| 429 | Rate limit exceeded |
|
|
36
|
+
| 500 | Unhandled server error |
|
|
37
|
+
|
|
38
|
+
## API Versioning
|
|
39
|
+
|
|
40
|
+
| Strategy | Example | Pros | Cons |
|
|
41
|
+
|----------|---------|------|------|
|
|
42
|
+
| URL path | `/v1/users` | Simple, explicit, cacheable | URL pollution |
|
|
43
|
+
| Header | `Accept: application/vnd.api.v1+json` | Clean URLs | Harder to test |
|
|
44
|
+
| Query param | `/users?version=1` | Simple | Easy to forget |
|
|
45
|
+
|
|
46
|
+
**Recommendation**: URL path versioning (`/v1/`) for external APIs. It's the most discoverable and cache-friendly approach.
|
|
47
|
+
|
|
48
|
+
## Request/Response Patterns
|
|
49
|
+
|
|
50
|
+
### Pagination
|
|
51
|
+
```json
|
|
52
|
+
GET /tasks?page=2&per_page=25
|
|
53
|
+
|
|
54
|
+
{
|
|
55
|
+
"data": [...],
|
|
56
|
+
"meta": {
|
|
57
|
+
"current_page": 2,
|
|
58
|
+
"per_page": 25,
|
|
59
|
+
"total_items": 243,
|
|
60
|
+
"total_pages": 10
|
|
61
|
+
},
|
|
62
|
+
"links": {
|
|
63
|
+
"first": "/tasks?page=1&per_page=25",
|
|
64
|
+
"prev": "/tasks?page=1&per_page=25",
|
|
65
|
+
"next": "/tasks?page=3&per_page=25",
|
|
66
|
+
"last": "/tasks?page=10&per_page=25"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For large datasets, prefer cursor-based pagination:
|
|
72
|
+
```
|
|
73
|
+
GET /tasks?cursor=eyJpZCI6MTAwfQ&limit=25
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Filtering and Sorting
|
|
77
|
+
```
|
|
78
|
+
GET /tasks?status=open&priority=high&sort=-created_at,title
|
|
79
|
+
```
|
|
80
|
+
- Prefix `-` for descending sort
|
|
81
|
+
- Support multiple sort fields separated by commas
|
|
82
|
+
- Validate all filter fields — reject unknown params with 400
|
|
83
|
+
|
|
84
|
+
### Field Selection
|
|
85
|
+
```
|
|
86
|
+
GET /users/123?fields=id,name,email
|
|
87
|
+
```
|
|
88
|
+
Useful for mobile clients. Only implement if there's a real performance benefit.
|
|
89
|
+
|
|
90
|
+
## Error Response Format (RFC 7807)
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"type": "https://api.example.com/errors/validation-error",
|
|
95
|
+
"title": "Validation Error",
|
|
96
|
+
"status": 400,
|
|
97
|
+
"detail": "The request body contains invalid fields.",
|
|
98
|
+
"instance": "/tasks/123",
|
|
99
|
+
"errors": [
|
|
100
|
+
{ "field": "title", "message": "Title is required" },
|
|
101
|
+
{ "field": "due_date", "message": "Due date must be in the future" }
|
|
102
|
+
],
|
|
103
|
+
"trace_id": "abc-123-def"
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Key rules:
|
|
108
|
+
- Always include `status`, `title`, and `detail`
|
|
109
|
+
- Add `trace_id` for server errors (links to logs)
|
|
110
|
+
- Add `errors` array for validation errors with field-level detail
|
|
111
|
+
- Never expose stack traces or SQL in production
|
|
112
|
+
|
|
113
|
+
## Authentication Patterns
|
|
114
|
+
|
|
115
|
+
### JWT (JSON Web Tokens)
|
|
116
|
+
- Best for: stateless APIs, microservices, mobile apps
|
|
117
|
+
- Store access token in memory, refresh token in httpOnly cookie
|
|
118
|
+
- Short-lived access tokens (15 min), longer refresh tokens (7 days)
|
|
119
|
+
- Include minimal claims: `sub`, `role`, `exp` — NOT sensitive data
|
|
120
|
+
|
|
121
|
+
### OAuth2
|
|
122
|
+
- Best for: third-party integrations, SSO
|
|
123
|
+
- Use Authorization Code flow with PKCE for SPAs and mobile
|
|
124
|
+
- Never use Implicit flow (deprecated)
|
|
125
|
+
|
|
126
|
+
### API Keys
|
|
127
|
+
- Best for: server-to-server, webhooks, developer APIs
|
|
128
|
+
- Pass in header (`X-API-Key`), never in URL
|
|
129
|
+
- Implement key rotation without downtime
|
|
130
|
+
|
|
131
|
+
### Session-Based
|
|
132
|
+
- Best for: traditional web apps, server-rendered pages
|
|
133
|
+
- Store session in Redis/database, not in-memory
|
|
134
|
+
- Set `httpOnly`, `secure`, `sameSite=strict` on cookies
|
|
135
|
+
|
|
136
|
+
## Rate Limiting
|
|
137
|
+
|
|
138
|
+
- Return `429 Too Many Requests` with `Retry-After` header
|
|
139
|
+
- Use sliding window algorithm for fairness
|
|
140
|
+
- Different limits per tier: anonymous < authenticated < premium
|
|
141
|
+
- Include rate limit headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`
|
|
142
|
+
|
|
143
|
+
## GraphQL Considerations
|
|
144
|
+
|
|
145
|
+
### When to Use GraphQL
|
|
146
|
+
- Clients need flexible data fetching (mobile vs. web)
|
|
147
|
+
- Multiple data sources behind a single gateway
|
|
148
|
+
- Rapidly evolving frontend requirements
|
|
149
|
+
|
|
150
|
+
### When to Stick with REST
|
|
151
|
+
- Simple CRUD operations
|
|
152
|
+
- File upload/download heavy
|
|
153
|
+
- Caching is critical (REST caching is simpler)
|
|
154
|
+
- Team has no GraphQL experience
|
|
155
|
+
|
|
156
|
+
### Schema Design Tips
|
|
157
|
+
- Use `ID` type for identifiers, not `String` or `Int`
|
|
158
|
+
- Implement connections (cursor-based pagination) for lists
|
|
159
|
+
- Add `query complexity` limits to prevent abuse
|
|
160
|
+
- Use DataLoader to batch and deduplicate N+1 queries
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# Backend Architecture Patterns
|
|
2
|
+
|
|
3
|
+
## Layered Architecture
|
|
4
|
+
|
|
5
|
+
Standard three-layer structure. Each layer only calls the layer below it.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Controller (HTTP layer)
|
|
9
|
+
→ Validates input, calls service, returns HTTP response
|
|
10
|
+
→ Knows about: Request, Response, HTTP status codes
|
|
11
|
+
→ Does NOT contain business logic
|
|
12
|
+
|
|
13
|
+
Service (Business logic layer)
|
|
14
|
+
→ Implements business rules, orchestrates operations
|
|
15
|
+
→ Knows about: domain models, business rules
|
|
16
|
+
→ Does NOT know about HTTP or database implementation
|
|
17
|
+
|
|
18
|
+
Repository (Data access layer)
|
|
19
|
+
→ Handles database queries and persistence
|
|
20
|
+
→ Knows about: database, ORM, SQL
|
|
21
|
+
→ Returns domain models, not database rows
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Practical Example (Node.js/Express)
|
|
25
|
+
```typescript
|
|
26
|
+
// controller — HTTP concerns only
|
|
27
|
+
router.post('/tasks', auth, async (req, res) => {
|
|
28
|
+
const dto = validateCreateTask(req.body); // throws 400 on invalid
|
|
29
|
+
const task = await taskService.create(dto, req.user.id);
|
|
30
|
+
res.status(201).json(task);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// service — business logic
|
|
34
|
+
class TaskService {
|
|
35
|
+
async create(dto: CreateTaskDTO, userId: string): Promise<Task> {
|
|
36
|
+
const project = await this.projectRepo.findById(dto.projectId);
|
|
37
|
+
if (!project) throw new NotFoundError('Project');
|
|
38
|
+
if (!project.isActive) throw new BusinessError('Cannot add tasks to archived projects');
|
|
39
|
+
return this.taskRepo.create({ ...dto, createdBy: userId });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// repository — data access
|
|
44
|
+
class TaskRepository {
|
|
45
|
+
async create(data: TaskCreateData): Promise<Task> {
|
|
46
|
+
const row = await db('tasks').insert(data).returning('*');
|
|
47
|
+
return this.toModel(row[0]);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Clean Architecture Principles
|
|
53
|
+
|
|
54
|
+
- **Dependencies point inward**: outer layers depend on inner layers, never reverse
|
|
55
|
+
- **Domain entities** have zero dependencies on frameworks or databases
|
|
56
|
+
- **Use cases/services** contain application-specific business rules
|
|
57
|
+
- **Interfaces/ports** define contracts; implementations (adapters) are in outer layers
|
|
58
|
+
- **Practical tip**: You don't need full Clean Architecture for a CRUD API. Use it when business logic is complex enough to justify the abstraction.
|
|
59
|
+
|
|
60
|
+
## Middleware Patterns
|
|
61
|
+
|
|
62
|
+
Order matters. Apply middleware in this sequence:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
1. Request ID / Correlation ID → Generate or extract trace ID
|
|
66
|
+
2. Logging → Log request start
|
|
67
|
+
3. CORS → Handle preflight requests
|
|
68
|
+
4. Security headers → HSTS, CSP, X-Frame-Options
|
|
69
|
+
5. Rate limiting → Reject if over limit
|
|
70
|
+
6. Authentication → Verify token/session
|
|
71
|
+
7. Body parsing → Parse JSON/form data
|
|
72
|
+
8. Validation → Validate request body/params
|
|
73
|
+
9. Authorization → Check permissions
|
|
74
|
+
10. Route handler → Business logic
|
|
75
|
+
11. Error handler → Catch and format errors
|
|
76
|
+
12. Response logging → Log response status and duration
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Error Handling Middleware
|
|
80
|
+
```typescript
|
|
81
|
+
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
82
|
+
if (err instanceof AppError) {
|
|
83
|
+
logger.warn({ err, traceId: req.traceId });
|
|
84
|
+
return res.status(err.statusCode).json(err.toResponse());
|
|
85
|
+
}
|
|
86
|
+
logger.error({ err, traceId: req.traceId });
|
|
87
|
+
res.status(500).json({ title: 'Internal Server Error', trace_id: req.traceId });
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Dependency Injection
|
|
92
|
+
|
|
93
|
+
### Why
|
|
94
|
+
- Swap implementations (real DB → test mock)
|
|
95
|
+
- Control lifecycle (singleton vs. per-request)
|
|
96
|
+
- Make dependencies explicit (no hidden coupling)
|
|
97
|
+
|
|
98
|
+
### Simple Manual DI (good for most projects)
|
|
99
|
+
```typescript
|
|
100
|
+
// Compose at startup
|
|
101
|
+
const db = createDbConnection(config.database);
|
|
102
|
+
const userRepo = new UserRepository(db);
|
|
103
|
+
const authService = new AuthService(userRepo, config.jwt);
|
|
104
|
+
const userController = new UserController(authService);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### DI Container (for large projects)
|
|
108
|
+
Use a lightweight container like `tsyringe`, `awilix`, or `inversify` when you have 20+ services.
|
|
109
|
+
|
|
110
|
+
## Database Access Patterns
|
|
111
|
+
|
|
112
|
+
### Repository Pattern
|
|
113
|
+
- Abstract database operations behind an interface
|
|
114
|
+
- Each aggregate root gets its own repository
|
|
115
|
+
- Methods return domain objects, not raw rows
|
|
116
|
+
|
|
117
|
+
### Query Builder vs. ORM
|
|
118
|
+
| Approach | When | Examples |
|
|
119
|
+
|----------|------|----------|
|
|
120
|
+
| Raw SQL | Complex queries, performance-critical | pg, mysql2 |
|
|
121
|
+
| Query builder | Most CRUD apps, good balance | Knex, Kysely |
|
|
122
|
+
| Full ORM | Rapid development, simple schemas | Prisma, TypeORM, Sequelize |
|
|
123
|
+
|
|
124
|
+
**Recommendation**: Query builder (Knex/Kysely) for most ITO projects. Full control with less boilerplate than raw SQL.
|
|
125
|
+
|
|
126
|
+
## Background Jobs and Queues
|
|
127
|
+
|
|
128
|
+
### When to Use
|
|
129
|
+
- Email/SMS sending
|
|
130
|
+
- Report generation
|
|
131
|
+
- Data processing/ETL
|
|
132
|
+
- Webhook delivery with retries
|
|
133
|
+
|
|
134
|
+
### Implementation
|
|
135
|
+
- Use a job queue library (BullMQ for Node.js, Celery for Python, Sidekiq for Ruby)
|
|
136
|
+
- Store jobs in Redis or database
|
|
137
|
+
- Implement idempotency (same job processed twice = same result)
|
|
138
|
+
- Set up dead-letter queues for failed jobs
|
|
139
|
+
- Monitor queue depth and processing time
|
|
140
|
+
|
|
141
|
+
## Caching Strategies
|
|
142
|
+
|
|
143
|
+
| Strategy | Use Case | TTL |
|
|
144
|
+
|----------|----------|-----|
|
|
145
|
+
| In-memory (LRU) | Config, feature flags | App restart |
|
|
146
|
+
| Redis | Session, rate limits, API cache | 5 min – 24 hrs |
|
|
147
|
+
| CDN | Static assets, public API responses | 1 hr – 1 year |
|
|
148
|
+
| HTTP cache | Browser caching of API responses | Varies |
|
|
149
|
+
|
|
150
|
+
### Cache Invalidation Approaches
|
|
151
|
+
- **Time-based (TTL)**: simplest, good enough for most cases
|
|
152
|
+
- **Event-based**: invalidate on write (publish cache-clear event)
|
|
153
|
+
- **Cache-aside**: application manages cache reads/writes explicitly
|
|
154
|
+
|
|
155
|
+
**Rule of thumb**: Cache at the highest level possible (CDN > reverse proxy > application > database).
|
|
156
|
+
|
|
157
|
+
## Logging and Observability
|
|
158
|
+
|
|
159
|
+
### Structured Logging
|
|
160
|
+
```typescript
|
|
161
|
+
// Always use structured logging — never string concatenation
|
|
162
|
+
logger.info({ userId, action: 'task.created', taskId: task.id, duration: 45 });
|
|
163
|
+
// NOT: logger.info(`User ${userId} created task ${taskId}`);
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Correlation IDs
|
|
167
|
+
- Generate a unique ID per request (UUID v4)
|
|
168
|
+
- Pass it through all service calls (header: `X-Request-ID`)
|
|
169
|
+
- Include in every log entry and error response
|
|
170
|
+
- Enables tracing a request across services
|
|
171
|
+
|
|
172
|
+
### What to Log
|
|
173
|
+
| Level | When |
|
|
174
|
+
|-------|------|
|
|
175
|
+
| ERROR | Unhandled exceptions, failed external calls |
|
|
176
|
+
| WARN | Business rule violations, rate limits hit |
|
|
177
|
+
| INFO | Request start/end, key business events |
|
|
178
|
+
| DEBUG | Detailed flow (disable in production) |
|
|
179
|
+
|
|
180
|
+
### Health Checks
|
|
181
|
+
- `/health` — basic liveness (returns 200 if process is running)
|
|
182
|
+
- `/health/ready` — readiness (checks DB, Redis, external services)
|
|
183
|
+
- Used by load balancers and container orchestrators
|