@valentia-ai-skills/framework 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 +103 -0
- package/bin/cli.js +482 -0
- package/package.json +42 -0
- package/scripts/postinstall.js +18 -0
- package/skills/global/api-design/SKILL.md +248 -0
- package/skills/global/api-design/tests/test-prompts.md +25 -0
- package/skills/global/code-standards/SKILL.md +245 -0
- package/skills/global/code-standards/tests/test-prompts.md +26 -0
- package/skills/global/deployment/SKILL.md +240 -0
- package/skills/global/deployment/tests/test-prompts.md +27 -0
- package/skills/global/documentation/SKILL.md +298 -0
- package/skills/global/documentation/tests/test-prompts.md +26 -0
- package/skills/global/git-workflow/SKILL.md +177 -0
- package/skills/global/git-workflow/tests/test-prompts.md +11 -0
- package/skills/global/security-baseline/SKILL.md +239 -0
- package/skills/global/security-baseline/tests/test-prompts.md +23 -0
- package/skills/global/testing-standards/SKILL.md +257 -0
- package/skills/global/testing-standards/tests/test-prompts.md +25 -0
- package/skills/onboarding/SKILL.md +110 -0
- package/skills/stack/devops/SKILL.md +220 -0
- package/skills/stack/devops/tests/test-prompts.md +29 -0
- package/skills/stack/node-backend/SKILL.md +304 -0
- package/skills/stack/node-backend/tests/test-prompts.md +27 -0
- package/skills/stack/python-backend/SKILL.md +304 -0
- package/skills/stack/python-backend/tests/test-prompts.md +27 -0
- package/skills/stack/react/SKILL.md +251 -0
- package/skills/stack/react/tests/test-prompts.md +26 -0
- package/skills/stack/react-native/SKILL.md +255 -0
- package/skills/stack/react-native/tests/test-prompts.md +26 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
## Test 1: Unit Test Writing
|
|
2
|
+
**Prompt**: "Write unit tests for a function that calculates order totals with discounts, tax, and shipping"
|
|
3
|
+
**Expected**:
|
|
4
|
+
- AAA pattern in each test
|
|
5
|
+
- "should ... when ..." naming
|
|
6
|
+
- Tests for: normal case, discount applied, free shipping threshold, zero items, negative values
|
|
7
|
+
- Mocks for any external dependencies
|
|
8
|
+
- Factory function for test orders
|
|
9
|
+
|
|
10
|
+
## Test 2: Integration Test
|
|
11
|
+
**Prompt**: "Write integration tests for a user registration API endpoint"
|
|
12
|
+
**Expected**:
|
|
13
|
+
- Full HTTP request/response cycle
|
|
14
|
+
- Test database setup and cleanup
|
|
15
|
+
- Happy path + validation errors + duplicate email
|
|
16
|
+
- Verifies database state after creation
|
|
17
|
+
- Proper status code assertions (201, 400, 409)
|
|
18
|
+
|
|
19
|
+
## Test 3: Test Refactoring
|
|
20
|
+
**Prompt**: "This test is fragile and hard to maintain: `it('test1', () => { const x = new UserService(db, cache, email, logger, config); ... })` — refactor it"
|
|
21
|
+
**Expected**:
|
|
22
|
+
- Descriptive test name with "should ... when ..."
|
|
23
|
+
- Factory function or beforeEach for setup
|
|
24
|
+
- Only mock what's needed for the specific test
|
|
25
|
+
- Clear AAA structure
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: onboarding
|
|
3
|
+
description: >
|
|
4
|
+
New developer onboarding for the AI Skills Framework. Use this skill when
|
|
5
|
+
a developer is new to the team, setting up their environment, asking about
|
|
6
|
+
conventions, or needs a walkthrough of how the AI-assisted development
|
|
7
|
+
workflow works. Triggers on: "new here", "just joined", "onboarding",
|
|
8
|
+
"getting started", "setup guide", "how does this work", "what are the rules",
|
|
9
|
+
"team conventions", "first task", or any indication the developer is
|
|
10
|
+
unfamiliar with the framework.
|
|
11
|
+
version: "1.0.0"
|
|
12
|
+
scope: global
|
|
13
|
+
author: Framework Admin
|
|
14
|
+
last_reviewed: 2026-03-19
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Developer Onboarding
|
|
18
|
+
|
|
19
|
+
## Overview
|
|
20
|
+
|
|
21
|
+
Welcome to the AI Skills Framework. This skill walks new developers through
|
|
22
|
+
the setup process and teaches them how AI-assisted development works in
|
|
23
|
+
this organization.
|
|
24
|
+
|
|
25
|
+
## What Is This Framework?
|
|
26
|
+
|
|
27
|
+
This organization uses AI agents (Claude Code and Claude.ai) to assist with
|
|
28
|
+
software development. Rather than each developer prompting AI independently,
|
|
29
|
+
we use **centralized Skills** — instruction sets that encode our coding standards,
|
|
30
|
+
security practices, and architectural patterns.
|
|
31
|
+
|
|
32
|
+
When you use Claude Code, it automatically reads these Skills and follows
|
|
33
|
+
our conventions. This means:
|
|
34
|
+
- Your code will be consistent with every other team
|
|
35
|
+
- Security best practices are built in
|
|
36
|
+
- You don't need to memorize all the conventions — the AI knows them
|
|
37
|
+
|
|
38
|
+
## Setup Checklist
|
|
39
|
+
|
|
40
|
+
### 1. Clone the Skills Repository
|
|
41
|
+
```bash
|
|
42
|
+
git clone git@github.com:YOUR_ORG/ai-skills-framework.git ~/ai-skills
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Install Claude Code
|
|
46
|
+
Follow the setup at https://docs.claude.com — install the CLI tool.
|
|
47
|
+
|
|
48
|
+
### 3. Configure Your Skill Path
|
|
49
|
+
In your project directory, create or edit `.claude/settings.json`:
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"permissions": {
|
|
53
|
+
"allow": ["Read ai-skills-framework/**"]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Point Claude Code's skill path to the cloned repository.
|
|
59
|
+
|
|
60
|
+
### 4. Know Your Team Config
|
|
61
|
+
Check `team-overrides/{your-team}/team-config.yaml` to see:
|
|
62
|
+
- Which skills are active for your team
|
|
63
|
+
- Any team-specific overrides or conventions
|
|
64
|
+
- Your team's stack and tooling preferences
|
|
65
|
+
|
|
66
|
+
### 5. Pull Skills Regularly
|
|
67
|
+
```bash
|
|
68
|
+
cd ~/ai-skills && git pull origin main
|
|
69
|
+
```
|
|
70
|
+
Skills are updated regularly. Pull at least weekly.
|
|
71
|
+
|
|
72
|
+
## How It Works Day-to-Day
|
|
73
|
+
|
|
74
|
+
1. **Start your task** — work in your project as normal
|
|
75
|
+
2. **Use Claude Code** — ask it to write code, review code, or help with tasks
|
|
76
|
+
3. **Skills apply automatically** — Claude reads the active skills and follows them
|
|
77
|
+
4. **Review the output** — verify the AI followed conventions (it usually will)
|
|
78
|
+
5. **Commit and PR** — follow the git-workflow skill for commits and PRs
|
|
79
|
+
|
|
80
|
+
## Your First AI-Assisted Task
|
|
81
|
+
|
|
82
|
+
For your first task, follow this process:
|
|
83
|
+
1. Pick a small, well-defined task (not a major feature)
|
|
84
|
+
2. Use Claude Code to help implement it
|
|
85
|
+
3. Review the output against the code-standards skill
|
|
86
|
+
4. Have your Team Lead review before merging
|
|
87
|
+
5. Share feedback — what worked, what didn't
|
|
88
|
+
|
|
89
|
+
## Key Skills to Read First
|
|
90
|
+
|
|
91
|
+
1. **code-standards** — Naming, structure, formatting (global/)
|
|
92
|
+
2. **git-workflow** — Branches, commits, PRs (global/)
|
|
93
|
+
3. **security-baseline** — Auth, validation, secrets (global/)
|
|
94
|
+
4. Your team's stack skill (stack/{your-stack}/)
|
|
95
|
+
|
|
96
|
+
## Getting Help
|
|
97
|
+
|
|
98
|
+
- **Skill not working?** → Open a GitHub Issue in the skills repo
|
|
99
|
+
- **Need a new skill?** → Use the "Skill Request" issue template
|
|
100
|
+
- **Framework questions?** → Ask your Team Lead or the Framework Admin
|
|
101
|
+
- **Want to contribute?** → Read CONTRIBUTING.md in the repo root
|
|
102
|
+
|
|
103
|
+
## Checklist
|
|
104
|
+
|
|
105
|
+
Verify your setup:
|
|
106
|
+
- [ ] Skills repo cloned locally
|
|
107
|
+
- [ ] Claude Code installed and configured
|
|
108
|
+
- [ ] Can identify your team's config file
|
|
109
|
+
- [ ] Have read code-standards, git-workflow, and security-baseline
|
|
110
|
+
- [ ] Completed first AI-assisted task with Team Lead review
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devops-patterns
|
|
3
|
+
description: >
|
|
4
|
+
Infrastructure and DevOps patterns for platform and infrastructure teams.
|
|
5
|
+
Use this skill whenever writing, reviewing, or designing infrastructure
|
|
6
|
+
configurations, monitoring, alerting, logging, or cloud resource management.
|
|
7
|
+
Triggers on: "Terraform", "CloudFormation", "Pulumi", "infrastructure as code",
|
|
8
|
+
"IaC", "Kubernetes", "k8s", "helm chart", "monitoring", "alerting",
|
|
9
|
+
"Prometheus", "Grafana", "Datadog", "CloudWatch", "load balancer", "autoscaling",
|
|
10
|
+
"VPC", "networking", "DNS", "SSL/TLS", "certificate", "backup", "disaster recovery",
|
|
11
|
+
"SLA", "SLO", "SLI", "observability", "tracing", "metrics". Applies to DevOps teams.
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
scope: stack
|
|
14
|
+
stack: devops
|
|
15
|
+
author: Framework Admin
|
|
16
|
+
last_reviewed: 2026-03-19
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# DevOps Patterns
|
|
20
|
+
|
|
21
|
+
## Overview
|
|
22
|
+
|
|
23
|
+
Infrastructure standards that ensure reliability, observability, and security
|
|
24
|
+
across all services. These patterns apply to whoever manages the platform —
|
|
25
|
+
whether a dedicated DevOps team or embedded platform engineers.
|
|
26
|
+
|
|
27
|
+
**Prerequisites**: `global/security-baseline` and `global/deployment` apply.
|
|
28
|
+
This skill adds infrastructure-specific patterns.
|
|
29
|
+
|
|
30
|
+
## 1. Infrastructure as Code (IaC)
|
|
31
|
+
|
|
32
|
+
### Rules
|
|
33
|
+
- ALL infrastructure must be defined in code — no manual console changes
|
|
34
|
+
- Use Terraform (preferred) or Pulumi for cloud resources
|
|
35
|
+
- Use Helm for Kubernetes manifests
|
|
36
|
+
- Store IaC in version control (separate repo or `infra/` directory)
|
|
37
|
+
- Plan before apply: always review `terraform plan` output
|
|
38
|
+
- State files stored remotely (S3 + DynamoDB lock, not local)
|
|
39
|
+
|
|
40
|
+
### Terraform Structure
|
|
41
|
+
```
|
|
42
|
+
infra/
|
|
43
|
+
modules/ # Reusable modules
|
|
44
|
+
database/
|
|
45
|
+
main.tf
|
|
46
|
+
variables.tf
|
|
47
|
+
outputs.tf
|
|
48
|
+
cache/
|
|
49
|
+
networking/
|
|
50
|
+
environments/ # Per-environment configs
|
|
51
|
+
staging/
|
|
52
|
+
main.tf # References modules
|
|
53
|
+
terraform.tfvars
|
|
54
|
+
production/
|
|
55
|
+
main.tf
|
|
56
|
+
terraform.tfvars
|
|
57
|
+
global/ # Shared resources (DNS, IAM)
|
|
58
|
+
main.tf
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Rules
|
|
62
|
+
- Separate state per environment (staging and production never share state)
|
|
63
|
+
- Tag all resources: `team`, `environment`, `service`, `managed-by=terraform`
|
|
64
|
+
- Use modules for any resource used by 2+ services
|
|
65
|
+
- Pin provider versions: `required_providers { aws = "~> 5.0" }`
|
|
66
|
+
|
|
67
|
+
## 2. Monitoring & Observability
|
|
68
|
+
|
|
69
|
+
### Three Pillars
|
|
70
|
+
|
|
71
|
+
| Pillar | Tool | What It Captures |
|
|
72
|
+
|--------|------|-----------------|
|
|
73
|
+
| Metrics | Prometheus / Datadog | Numeric measurements over time (latency, error rate, throughput) |
|
|
74
|
+
| Logs | ELK / CloudWatch / Loki | Structured event records |
|
|
75
|
+
| Traces | Jaeger / Datadog APM | Request flow across services |
|
|
76
|
+
|
|
77
|
+
### Required Metrics (Every Service)
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
# RED method — for every service endpoint:
|
|
81
|
+
- Rate: requests per second
|
|
82
|
+
- Errors: error rate (4xx, 5xx)
|
|
83
|
+
- Duration: response time (p50, p95, p99)
|
|
84
|
+
|
|
85
|
+
# USE method — for infrastructure:
|
|
86
|
+
- Utilization: CPU %, memory %, disk %
|
|
87
|
+
- Saturation: queue depth, thread pool usage
|
|
88
|
+
- Errors: hardware/system errors
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Standard Dashboard Layout
|
|
92
|
+
Every service dashboard must include:
|
|
93
|
+
1. **Request rate** — requests/sec over time
|
|
94
|
+
2. **Error rate** — 4xx and 5xx separately
|
|
95
|
+
3. **Latency** — p50, p95, p99 response times
|
|
96
|
+
4. **Saturation** — CPU, memory, connections
|
|
97
|
+
5. **Dependencies** — upstream service health
|
|
98
|
+
6. **Business metrics** — service-specific KPIs
|
|
99
|
+
|
|
100
|
+
## 3. Alerting
|
|
101
|
+
|
|
102
|
+
### Alert Severity Levels
|
|
103
|
+
|
|
104
|
+
| Level | Response Time | Examples |
|
|
105
|
+
|-------|--------------|---------|
|
|
106
|
+
| Critical (P1) | 5 minutes | Service down, data loss risk, security breach |
|
|
107
|
+
| Warning (P2) | 30 minutes | Error rate elevated, resource nearing limit |
|
|
108
|
+
| Info (P3) | Next business day | Disk usage growing, certificate expiring in 30 days |
|
|
109
|
+
|
|
110
|
+
### Rules
|
|
111
|
+
- Every alert must have a runbook link
|
|
112
|
+
- No alert without a clear action — if you can't act on it, it's not an alert
|
|
113
|
+
- Alert on symptoms (high error rate) not causes (CPU spike)
|
|
114
|
+
- Page only for P1 — Slack/email for P2/P3
|
|
115
|
+
- Review and tune alerts monthly — alert fatigue kills response quality
|
|
116
|
+
|
|
117
|
+
### Alert Template
|
|
118
|
+
```yaml
|
|
119
|
+
alert: HighErrorRate
|
|
120
|
+
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
|
|
121
|
+
for: 2m
|
|
122
|
+
labels:
|
|
123
|
+
severity: critical
|
|
124
|
+
team: "{{ $labels.team }}"
|
|
125
|
+
annotations:
|
|
126
|
+
summary: "High 5xx error rate on {{ $labels.service }}"
|
|
127
|
+
description: "Error rate is {{ $value | humanizePercentage }} (threshold: 5%)"
|
|
128
|
+
runbook: "https://wiki.company.com/runbooks/high-error-rate"
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 4. Service Level Objectives (SLOs)
|
|
132
|
+
|
|
133
|
+
Every production service defines:
|
|
134
|
+
|
|
135
|
+
| SLI (Indicator) | SLO (Objective) | Measurement |
|
|
136
|
+
|-----------------|-----------------|-------------|
|
|
137
|
+
| Availability | 99.9% (43 min downtime/month) | Successful requests / total requests |
|
|
138
|
+
| Latency | p99 < 500ms | 99% of requests complete in < 500ms |
|
|
139
|
+
| Throughput | Handles 1000 rps | Load test verified quarterly |
|
|
140
|
+
|
|
141
|
+
### Error Budget
|
|
142
|
+
- Error budget = 100% - SLO = 0.1% allowed failure
|
|
143
|
+
- If budget is exhausted: freeze feature work, focus on reliability
|
|
144
|
+
- Track budget monthly with the team
|
|
145
|
+
|
|
146
|
+
## 5. Kubernetes Standards
|
|
147
|
+
|
|
148
|
+
### Pod Configuration
|
|
149
|
+
```yaml
|
|
150
|
+
apiVersion: apps/v1
|
|
151
|
+
kind: Deployment
|
|
152
|
+
spec:
|
|
153
|
+
replicas: 3 # minimum 2 for HA
|
|
154
|
+
strategy:
|
|
155
|
+
type: RollingUpdate
|
|
156
|
+
rollingUpdate:
|
|
157
|
+
maxUnavailable: 1
|
|
158
|
+
maxSurge: 1
|
|
159
|
+
template:
|
|
160
|
+
spec:
|
|
161
|
+
containers:
|
|
162
|
+
- name: app
|
|
163
|
+
image: myapp:v1.2.3 # pinned tag, never :latest
|
|
164
|
+
resources:
|
|
165
|
+
requests:
|
|
166
|
+
cpu: 100m
|
|
167
|
+
memory: 256Mi
|
|
168
|
+
limits:
|
|
169
|
+
cpu: 500m
|
|
170
|
+
memory: 512Mi
|
|
171
|
+
livenessProbe:
|
|
172
|
+
httpGet:
|
|
173
|
+
path: /health
|
|
174
|
+
port: 3000
|
|
175
|
+
initialDelaySeconds: 10
|
|
176
|
+
periodSeconds: 15
|
|
177
|
+
readinessProbe:
|
|
178
|
+
httpGet:
|
|
179
|
+
path: /health
|
|
180
|
+
port: 3000
|
|
181
|
+
initialDelaySeconds: 5
|
|
182
|
+
periodSeconds: 5
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Rules
|
|
186
|
+
- Always set resource requests AND limits
|
|
187
|
+
- Always define liveness AND readiness probes
|
|
188
|
+
- Minimum 2 replicas for any production service
|
|
189
|
+
- Never use `:latest` tag — always pinned versions
|
|
190
|
+
- Use PodDisruptionBudget for critical services
|
|
191
|
+
- Secrets via Kubernetes Secrets or external secrets operator (never ConfigMaps)
|
|
192
|
+
|
|
193
|
+
## 6. Backup & Disaster Recovery
|
|
194
|
+
|
|
195
|
+
### Database Backups
|
|
196
|
+
- Automated daily backups with 30-day retention
|
|
197
|
+
- Weekly backup restore test (automated)
|
|
198
|
+
- Cross-region backup replication for production
|
|
199
|
+
- Recovery Point Objective (RPO): < 1 hour
|
|
200
|
+
- Recovery Time Objective (RTO): < 4 hours
|
|
201
|
+
|
|
202
|
+
### Rules
|
|
203
|
+
- Backups are tested regularly — untested backups are not backups
|
|
204
|
+
- Document the full restore procedure in the service runbook
|
|
205
|
+
- Encrypt backups at rest and in transit
|
|
206
|
+
- Backup retention: 30 days daily, 12 months monthly
|
|
207
|
+
|
|
208
|
+
## Checklist
|
|
209
|
+
|
|
210
|
+
Before deploying infrastructure changes:
|
|
211
|
+
- [ ] All infrastructure defined in code (no manual changes)
|
|
212
|
+
- [ ] Terraform plan reviewed before apply
|
|
213
|
+
- [ ] Resources tagged: team, environment, service, managed-by
|
|
214
|
+
- [ ] Monitoring dashboard with RED metrics in place
|
|
215
|
+
- [ ] Alerts configured with runbook links
|
|
216
|
+
- [ ] SLOs defined for the service
|
|
217
|
+
- [ ] K8s pods have resource limits, health probes, ≥ 2 replicas
|
|
218
|
+
- [ ] Backups configured and restore tested
|
|
219
|
+
- [ ] No :latest tags in any configuration
|
|
220
|
+
- [ ] Secrets in secrets manager (not plaintext in configs)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
## Test 1: Terraform Module
|
|
2
|
+
**Prompt**: "Create a Terraform module for a PostgreSQL RDS instance with read replicas, automated backups, and monitoring"
|
|
3
|
+
**Expected**:
|
|
4
|
+
- Module structure: main.tf, variables.tf, outputs.tf
|
|
5
|
+
- Resource tagging (team, environment, service, managed-by)
|
|
6
|
+
- Backup retention configured
|
|
7
|
+
- CloudWatch alarms for CPU, connections, storage
|
|
8
|
+
- Encryption at rest enabled
|
|
9
|
+
- Security group with restricted access
|
|
10
|
+
|
|
11
|
+
## Test 2: Kubernetes Deployment
|
|
12
|
+
**Prompt**: "Write a Kubernetes deployment manifest for a Node.js API with autoscaling, health checks, and resource limits"
|
|
13
|
+
**Expected**:
|
|
14
|
+
- Resource requests AND limits set
|
|
15
|
+
- Liveness AND readiness probes on /health
|
|
16
|
+
- Minimum 2 replicas
|
|
17
|
+
- Pinned image tag (not :latest)
|
|
18
|
+
- HPA for autoscaling
|
|
19
|
+
- RollingUpdate strategy
|
|
20
|
+
- PodDisruptionBudget
|
|
21
|
+
|
|
22
|
+
## Test 3: Monitoring Setup
|
|
23
|
+
**Prompt**: "Set up monitoring and alerting for a payment processing service"
|
|
24
|
+
**Expected**:
|
|
25
|
+
- RED metrics: rate, errors, duration
|
|
26
|
+
- Dashboard with required sections
|
|
27
|
+
- Alerts for: high error rate, high latency, service down
|
|
28
|
+
- Each alert has severity level and runbook link
|
|
29
|
+
- SLOs defined: availability, latency targets
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: node-backend-patterns
|
|
3
|
+
description: >
|
|
4
|
+
Node.js backend development patterns and conventions. Use this skill whenever
|
|
5
|
+
writing, reviewing, or designing Node.js backend services, APIs, middleware,
|
|
6
|
+
database access layers, queue consumers, or microservices. Triggers on:
|
|
7
|
+
"Express", "Fastify", "NestJS", "Koa", "Node.js backend", "middleware",
|
|
8
|
+
"controller", "service layer", "repository pattern", "database migration",
|
|
9
|
+
"Prisma", "TypeORM", "Drizzle", "Knex", "Redis", "queue", "worker",
|
|
10
|
+
"cron", "microservice", "health check", "graceful shutdown".
|
|
11
|
+
Applies to backend teams using Node.js/TypeScript.
|
|
12
|
+
version: "1.0.0"
|
|
13
|
+
scope: stack
|
|
14
|
+
stack: node-backend
|
|
15
|
+
author: Framework Admin
|
|
16
|
+
last_reviewed: 2026-03-19
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Node.js Backend Patterns
|
|
20
|
+
|
|
21
|
+
## Overview
|
|
22
|
+
|
|
23
|
+
Standardized backend architecture for Node.js services. These patterns ensure
|
|
24
|
+
every backend service is structured consistently, testable, and production-ready.
|
|
25
|
+
|
|
26
|
+
**Prerequisites**: `global/code-standards`, `global/security-baseline`, and
|
|
27
|
+
`global/api-design` all apply. This skill adds backend-specific patterns.
|
|
28
|
+
|
|
29
|
+
## 1. Service Architecture — Layered Pattern
|
|
30
|
+
|
|
31
|
+
Every backend service follows a 4-layer architecture:
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
┌──────────────────────────────┐
|
|
35
|
+
│ Routes / Controllers │ ← HTTP handling, validation, response formatting
|
|
36
|
+
├──────────────────────────────┤
|
|
37
|
+
│ Services │ ← Business logic, orchestration
|
|
38
|
+
├──────────────────────────────┤
|
|
39
|
+
│ Repositories / Data Access │ ← Database queries, cache, external APIs
|
|
40
|
+
├──────────────────────────────┤
|
|
41
|
+
│ Models / Types │ ← Data structures, validation schemas
|
|
42
|
+
└──────────────────────────────┘
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Rules
|
|
46
|
+
- Controllers handle HTTP — never contain business logic
|
|
47
|
+
- Services contain business logic — never touch HTTP request/response objects
|
|
48
|
+
- Repositories handle data access — never contain business logic
|
|
49
|
+
- Each layer only calls the layer directly below it
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
src/
|
|
53
|
+
routes/ # Express/Fastify route definitions
|
|
54
|
+
user-routes.ts
|
|
55
|
+
controllers/ # Request handling, validation, response
|
|
56
|
+
user-controller.ts
|
|
57
|
+
services/ # Business logic
|
|
58
|
+
user-service.ts
|
|
59
|
+
repositories/ # Database access
|
|
60
|
+
user-repository.ts
|
|
61
|
+
middleware/ # Auth, logging, error handling
|
|
62
|
+
auth-middleware.ts
|
|
63
|
+
error-handler.ts
|
|
64
|
+
models/ # Prisma/TypeORM models or Zod schemas
|
|
65
|
+
user-model.ts
|
|
66
|
+
config/ # Configuration loading
|
|
67
|
+
index.ts
|
|
68
|
+
database.ts
|
|
69
|
+
lib/ # Shared utilities (logger, cache client)
|
|
70
|
+
logger.ts
|
|
71
|
+
cache.ts
|
|
72
|
+
types/ # TypeScript type definitions
|
|
73
|
+
index.ts
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## 2. Dependency Injection
|
|
77
|
+
|
|
78
|
+
Services receive their dependencies through constructor injection:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// ✅ Good: Dependencies injected
|
|
82
|
+
class UserService {
|
|
83
|
+
constructor(
|
|
84
|
+
private userRepo: UserRepository,
|
|
85
|
+
private emailService: EmailService,
|
|
86
|
+
private logger: Logger,
|
|
87
|
+
) {}
|
|
88
|
+
|
|
89
|
+
async createUser(data: CreateUserInput): Promise<User> {
|
|
90
|
+
const user = await this.userRepo.create(data);
|
|
91
|
+
await this.emailService.sendWelcome(user.email);
|
|
92
|
+
this.logger.info("User created", { userId: user.id });
|
|
93
|
+
return user;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// ❌ Bad: Hard-coded dependencies
|
|
98
|
+
class UserService {
|
|
99
|
+
async createUser(data: CreateUserInput): Promise<User> {
|
|
100
|
+
const user = await prisma.user.create({ data }); // direct DB access
|
|
101
|
+
await sendgrid.send({ ... }); // direct service call
|
|
102
|
+
console.log("User created"); // no structured logging
|
|
103
|
+
return user;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Why
|
|
109
|
+
- Testable: inject mocks in tests
|
|
110
|
+
- Flexible: swap implementations without changing business logic
|
|
111
|
+
- Clear: dependencies are explicit, not hidden
|
|
112
|
+
|
|
113
|
+
## 3. Error Handling
|
|
114
|
+
|
|
115
|
+
### Custom Error Classes
|
|
116
|
+
```typescript
|
|
117
|
+
// Base application error
|
|
118
|
+
class AppError extends Error {
|
|
119
|
+
constructor(
|
|
120
|
+
message: string,
|
|
121
|
+
public statusCode: number,
|
|
122
|
+
public code: string,
|
|
123
|
+
public details?: unknown,
|
|
124
|
+
) {
|
|
125
|
+
super(message);
|
|
126
|
+
this.name = this.constructor.name;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Specific errors
|
|
131
|
+
class NotFoundError extends AppError {
|
|
132
|
+
constructor(resource: string, id: string) {
|
|
133
|
+
super(`${resource} with id ${id} not found`, 404, "NOT_FOUND");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
class ValidationError extends AppError {
|
|
138
|
+
constructor(details: Array<{ field: string; message: string }>) {
|
|
139
|
+
super("Validation failed", 400, "VALIDATION_ERROR", details);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
class ConflictError extends AppError {
|
|
144
|
+
constructor(message: string) {
|
|
145
|
+
super(message, 409, "CONFLICT");
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Global Error Handler (Express example)
|
|
151
|
+
```typescript
|
|
152
|
+
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
|
|
153
|
+
if (err instanceof AppError) {
|
|
154
|
+
return res.status(err.statusCode).json({
|
|
155
|
+
error: {
|
|
156
|
+
code: err.code,
|
|
157
|
+
message: err.message,
|
|
158
|
+
details: err.details,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Unexpected errors
|
|
164
|
+
logger.error("Unhandled error", { error: err.message, stack: err.stack });
|
|
165
|
+
return res.status(500).json({
|
|
166
|
+
error: {
|
|
167
|
+
code: "INTERNAL_ERROR",
|
|
168
|
+
message: "An unexpected error occurred",
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Rules
|
|
175
|
+
- Throw domain-specific errors from services
|
|
176
|
+
- Catch and format in the error handler middleware
|
|
177
|
+
- Never expose stack traces in production responses
|
|
178
|
+
- Always log unexpected errors with full context
|
|
179
|
+
|
|
180
|
+
## 4. Database Access
|
|
181
|
+
|
|
182
|
+
### Migration Rules
|
|
183
|
+
- Always use migrations for schema changes (never manual SQL)
|
|
184
|
+
- Migrations are forward-only in production
|
|
185
|
+
- Migration files have timestamps: `20260319_add_user_email_index`
|
|
186
|
+
- Test migrations against a copy of production data before deploying
|
|
187
|
+
|
|
188
|
+
### Query Patterns
|
|
189
|
+
```typescript
|
|
190
|
+
// Repository pattern — encapsulates all DB access
|
|
191
|
+
class UserRepository {
|
|
192
|
+
constructor(private db: PrismaClient) {}
|
|
193
|
+
|
|
194
|
+
async findById(id: string): Promise<User | null> {
|
|
195
|
+
return this.db.user.findUnique({ where: { id } });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async findByEmail(email: string): Promise<User | null> {
|
|
199
|
+
return this.db.user.findUnique({ where: { email } });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async create(data: CreateUserInput): Promise<User> {
|
|
203
|
+
return this.db.user.create({ data });
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async updateLastLogin(id: string): Promise<void> {
|
|
207
|
+
await this.db.user.update({
|
|
208
|
+
where: { id },
|
|
209
|
+
data: { lastLoginAt: new Date() },
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Rules
|
|
216
|
+
- All DB queries go through repositories — controllers never touch the DB
|
|
217
|
+
- Use transactions for multi-step operations
|
|
218
|
+
- Always set query timeouts
|
|
219
|
+
- Index columns used in WHERE and JOIN clauses
|
|
220
|
+
|
|
221
|
+
## 5. Configuration
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// config/index.ts — single source of truth
|
|
225
|
+
import { z } from "zod";
|
|
226
|
+
|
|
227
|
+
const configSchema = z.object({
|
|
228
|
+
NODE_ENV: z.enum(["development", "staging", "production"]),
|
|
229
|
+
PORT: z.coerce.number().default(3000),
|
|
230
|
+
DATABASE_URL: z.string().url(),
|
|
231
|
+
REDIS_URL: z.string().url(),
|
|
232
|
+
JWT_SECRET: z.string().min(32),
|
|
233
|
+
LOG_LEVEL: z.enum(["debug", "info", "warn", "error"]).default("info"),
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
export const config = configSchema.parse(process.env);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Rules
|
|
240
|
+
- Validate all env vars at startup — fail fast if missing
|
|
241
|
+
- Use Zod for config validation (same as request validation)
|
|
242
|
+
- Never use `process.env` directly in service code — only through the config module
|
|
243
|
+
- Different `.env.example` entries for each environment
|
|
244
|
+
|
|
245
|
+
## 6. Health Checks & Graceful Shutdown
|
|
246
|
+
|
|
247
|
+
Every service must implement:
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
// Health check endpoint
|
|
251
|
+
app.get("/health", async (req, res) => {
|
|
252
|
+
const checks = {
|
|
253
|
+
database: await checkDatabase(),
|
|
254
|
+
redis: await checkRedis(),
|
|
255
|
+
uptime: process.uptime(),
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const isHealthy = Object.values(checks).every(c => c !== false);
|
|
259
|
+
res.status(isHealthy ? 200 : 503).json({ status: isHealthy ? "ok" : "degraded", checks });
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
// Graceful shutdown
|
|
263
|
+
function gracefulShutdown(signal: string) {
|
|
264
|
+
logger.info(`Received ${signal}, shutting down gracefully...`);
|
|
265
|
+
|
|
266
|
+
server.close(async () => {
|
|
267
|
+
await prisma.$disconnect();
|
|
268
|
+
await redis.quit();
|
|
269
|
+
logger.info("Server shut down cleanly");
|
|
270
|
+
process.exit(0);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Force exit after 30 seconds
|
|
274
|
+
setTimeout(() => {
|
|
275
|
+
logger.error("Forced shutdown after timeout");
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}, 30_000);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
|
|
281
|
+
process.on("SIGINT", () => gracefulShutdown("SIGINT"));
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## 7. Logging
|
|
285
|
+
|
|
286
|
+
- Use structured logging (JSON format): `pino` or `winston`
|
|
287
|
+
- Always include: timestamp, level, message, request ID, service name
|
|
288
|
+
- Log at appropriate levels: debug (development only), info (normal operations),
|
|
289
|
+
warn (recoverable issues), error (failures requiring attention)
|
|
290
|
+
- Never log PII, passwords, tokens, or full request bodies in production
|
|
291
|
+
|
|
292
|
+
## Checklist
|
|
293
|
+
|
|
294
|
+
Before finalizing backend code:
|
|
295
|
+
- [ ] 4-layer architecture: routes → controllers → services → repositories
|
|
296
|
+
- [ ] Dependencies injected via constructor (testable)
|
|
297
|
+
- [ ] Custom error classes with proper status codes
|
|
298
|
+
- [ ] Global error handler catches all errors
|
|
299
|
+
- [ ] DB access through repositories only
|
|
300
|
+
- [ ] Config validated at startup with Zod
|
|
301
|
+
- [ ] Health check endpoint at /health
|
|
302
|
+
- [ ] Graceful shutdown handler
|
|
303
|
+
- [ ] Structured logging (no console.log in production)
|
|
304
|
+
- [ ] No PII in logs, no stack traces in responses
|