@wipal/agent-team 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/.claude/rules/common/general-rules.md +141 -0
- package/.claude/rules/lessons/lessons.md +91 -0
- package/.claude/rules/role-rules/dev-fe-rules.md +146 -0
- package/.claude/rules/role-rules/sa-rules.md +226 -0
- package/.claude/skills/SKILL-INDEX.md +299 -0
- package/.claude/skills/community/security-validator/SKILL.md +392 -0
- package/.claude/skills/core/agent-creation/SKILL.md +338 -0
- package/.claude/skills/core/code-review/SKILL.md +154 -0
- package/.claude/skills/core/git-automation/SKILL.md +93 -0
- package/.claude/skills/core/retrospect-work/SKILL.md +172 -0
- package/.claude/skills/domain/architecture/adr-writing/SKILL.md +254 -0
- package/.claude/skills/domain/architecture/adr-writing/references/adr-best-practices.md +257 -0
- package/.claude/skills/domain/architecture/adr-writing/references/adr-examples.md +246 -0
- package/.claude/skills/domain/architecture/adr-writing/references/adr-template.md +160 -0
- package/.claude/skills/domain/architecture/architecture-patterns/SKILL.md +316 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/event-driven.md +393 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/microservices.md +315 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/monolith.md +321 -0
- package/.claude/skills/domain/architecture/architecture-patterns/references/serverless.md +457 -0
- package/.claude/skills/domain/architecture/performance-engineering/SKILL.md +227 -0
- package/.claude/skills/domain/architecture/performance-engineering/references/benchmarking.md +336 -0
- package/.claude/skills/domain/architecture/performance-engineering/references/caching-strategies.md +284 -0
- package/.claude/skills/domain/architecture/performance-engineering/references/optimization.md +298 -0
- package/.claude/skills/domain/architecture/security-architecture/SKILL.md +206 -0
- package/.claude/skills/domain/architecture/security-architecture/references/auth-patterns.md +209 -0
- package/.claude/skills/domain/architecture/security-architecture/references/compliance.md +246 -0
- package/.claude/skills/domain/architecture/security-architecture/references/threat-modeling.md +219 -0
- package/.claude/skills/domain/architecture/system-design/SKILL.md +227 -0
- package/.claude/skills/domain/architecture/system-design/references/distributed-systems.md +231 -0
- package/.claude/skills/domain/architecture/system-design/references/resilience.md +344 -0
- package/.claude/skills/domain/architecture/system-design/references/scalability.md +303 -0
- package/.claude/skills/domain/architecture/tech-selection/SKILL.md +192 -0
- package/.claude/skills/domain/architecture/tech-selection/references/build-vs-buy.md +258 -0
- package/.claude/skills/domain/architecture/tech-selection/references/evaluation-framework.md +203 -0
- package/.claude/skills/domain/architecture/tech-selection/references/tech-radar.md +257 -0
- package/.claude/skills/domain/backend/api-design/SKILL.md +121 -0
- package/.claude/skills/domain/backend/database-design/SKILL.md +156 -0
- package/.claude/skills/domain/backend/performance-be/SKILL.md +210 -0
- package/.claude/skills/domain/backend/security/SKILL.md +138 -0
- package/.claude/skills/domain/backend/testing-be/SKILL.md +203 -0
- package/.claude/skills/domain/devops/ci-cd/SKILL.md +188 -0
- package/.claude/skills/domain/devops/containerization/SKILL.md +177 -0
- package/.claude/skills/domain/devops/deployment/SKILL.md +198 -0
- package/.claude/skills/domain/devops/infrastructure-as-code/SKILL.md +178 -0
- package/.claude/skills/domain/devops/monitoring/SKILL.md +163 -0
- package/.claude/skills/domain/frontend/accessibility/SKILL.md +179 -0
- package/.claude/skills/domain/frontend/frontend-design/SKILL.md +138 -0
- package/.claude/skills/domain/frontend/performance-fe/SKILL.md +195 -0
- package/.claude/skills/domain/frontend/state-management/SKILL.md +190 -0
- package/.claude/skills/domain/frontend/testing-fe/SKILL.md +193 -0
- package/.claude/skills/domain/product/requirements-gathering/SKILL.md +136 -0
- package/.claude/skills/domain/product/roadmap-planning/SKILL.md +169 -0
- package/.claude/skills/domain/product/sprint-planning/SKILL.md +151 -0
- package/.claude/skills/domain/product/stakeholder-communication/SKILL.md +162 -0
- package/.claude/skills/domain/product/user-stories/SKILL.md +141 -0
- package/.claude/skills/domain/quality/bug-reporting/SKILL.md +150 -0
- package/.claude/skills/domain/quality/regression-testing/SKILL.md +178 -0
- package/.claude/skills/domain/quality/test-automation/SKILL.md +185 -0
- package/.claude/skills/domain/quality/test-planning/SKILL.md +177 -0
- package/.claude/skills/leadership/code-review-advanced/SKILL.md +167 -0
- package/.claude/skills/leadership/mentoring/SKILL.md +151 -0
- package/.claude/skills/leadership/technical-debt/SKILL.md +166 -0
- package/.claude/skills/leadership/technical-decision/SKILL.md +160 -0
- package/.claude/skills/security-reports/.gitkeep +0 -0
- package/.claude/skills/skills-registry.yaml +441 -0
- package/README.md +232 -0
- package/bin/agent-team.js +107 -0
- package/package.json +51 -0
- package/src/commands/add.js +227 -0
- package/src/commands/init.js +136 -0
- package/src/commands/list.js +66 -0
- package/src/commands/remove.js +71 -0
- package/src/commands/switch.js +53 -0
- package/src/index.js +11 -0
- package/src/interactive/prompts.js +153 -0
- package/src/server/api/agents.js +150 -0
- package/src/server/api/roles.js +97 -0
- package/src/server/api/skills.js +79 -0
- package/src/server/index.js +78 -0
- package/src/ui/agents.html +174 -0
- package/src/ui/css/styles.css +470 -0
- package/src/ui/index.html +107 -0
- package/src/ui/roles.html +371 -0
- package/src/ui/skills.html +332 -0
- package/src/utils/file-utils.js +193 -0
- package/src/utils/skill-resolver.js +594 -0
- package/src/utils/skill-scanner.js +154 -0
- package/templates/CLAUDE.md.tmpl +42 -0
- package/templates/knowledge.md.tmpl +31 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: api-design
|
|
3
|
+
description: |
|
|
4
|
+
RESTful API design patterns and best practices. Use when designing APIs,
|
|
5
|
+
creating endpoints, implementing authentication, versioning APIs, writing
|
|
6
|
+
API documentation, or when user mentions "API", "endpoint", "REST", "route",
|
|
7
|
+
"controller". Ensures consistent, intuitive, well-documented APIs.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
category: backend
|
|
10
|
+
tags:
|
|
11
|
+
- api
|
|
12
|
+
- rest
|
|
13
|
+
- http
|
|
14
|
+
- backend
|
|
15
|
+
depends_on:
|
|
16
|
+
- code-review
|
|
17
|
+
recommends:
|
|
18
|
+
- security
|
|
19
|
+
- database-design
|
|
20
|
+
used_by:
|
|
21
|
+
- security
|
|
22
|
+
- security-architecture
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Skill: API Design
|
|
26
|
+
|
|
27
|
+
## Core Principle
|
|
28
|
+
**APIs should be intuitive, consistent, and well-documented.** Developers should understand your API without reading docs.
|
|
29
|
+
|
|
30
|
+
## Hard Rules
|
|
31
|
+
|
|
32
|
+
1. **NEVER use verbs in URLs** - `/getUsers` → `/users`
|
|
33
|
+
2. **NEVER return HTML errors** - Always JSON
|
|
34
|
+
3. **ALWAYS use plural nouns** - `/users` not `/user`
|
|
35
|
+
4. **ALWAYS return consistent error format** - Same structure everywhere
|
|
36
|
+
5. **ALWAYS version APIs** - `/api/v1/...`
|
|
37
|
+
|
|
38
|
+
## HTTP Methods
|
|
39
|
+
|
|
40
|
+
| Method | Purpose | Idempotent |
|
|
41
|
+
|--------|---------|------------|
|
|
42
|
+
| GET | Retrieve | Yes |
|
|
43
|
+
| POST | Create | No |
|
|
44
|
+
| PUT | Replace | Yes |
|
|
45
|
+
| PATCH | Update | No |
|
|
46
|
+
| DELETE | Remove | Yes |
|
|
47
|
+
|
|
48
|
+
## Resource Naming
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
✅ GOOD:
|
|
52
|
+
GET /users
|
|
53
|
+
GET /users/{id}
|
|
54
|
+
POST /users
|
|
55
|
+
GET /users/{id}/orders
|
|
56
|
+
|
|
57
|
+
❌ BAD:
|
|
58
|
+
GET /getUsers
|
|
59
|
+
POST /createUser
|
|
60
|
+
GET /user-order/{id}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Status Codes
|
|
64
|
+
|
|
65
|
+
| Code | When |
|
|
66
|
+
|------|------|
|
|
67
|
+
| 200 | Success |
|
|
68
|
+
| 201 | Created |
|
|
69
|
+
| 204 | Deleted (no content) |
|
|
70
|
+
| 400 | Bad request |
|
|
71
|
+
| 401 | Unauthorized |
|
|
72
|
+
| 403 | Forbidden |
|
|
73
|
+
| 404 | Not found |
|
|
74
|
+
| 422 | Validation error |
|
|
75
|
+
| 500 | Server error |
|
|
76
|
+
|
|
77
|
+
## Error Response Format
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"error": {
|
|
82
|
+
"code": "VALIDATION_ERROR",
|
|
83
|
+
"message": "Validation failed",
|
|
84
|
+
"details": [
|
|
85
|
+
{ "field": "email", "message": "Invalid email" }
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Common Mistakes
|
|
92
|
+
|
|
93
|
+
| ❌ Mistake | ✅ Fix |
|
|
94
|
+
|------------|--------|
|
|
95
|
+
| `/getUsers` | `/users` with GET |
|
|
96
|
+
| No versioning | `/api/v1/users` |
|
|
97
|
+
| HTML errors | JSON error format |
|
|
98
|
+
| No pagination | `?page=1&limit=20` |
|
|
99
|
+
| Inconsistent naming | Stick to conventions |
|
|
100
|
+
|
|
101
|
+
## Pagination
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
{
|
|
105
|
+
"data": [...],
|
|
106
|
+
"pagination": {
|
|
107
|
+
"page": 1,
|
|
108
|
+
"limit": 20,
|
|
109
|
+
"total": 100
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Quick Checklist
|
|
115
|
+
|
|
116
|
+
- [ ] Uses nouns, not verbs
|
|
117
|
+
- [ ] Plural resource names
|
|
118
|
+
- [ ] Consistent error format
|
|
119
|
+
- [ ] API versioned
|
|
120
|
+
- [ ] Pagination for lists
|
|
121
|
+
- [ ] Proper status codes
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: database-design
|
|
3
|
+
description: |
|
|
4
|
+
Database schema design patterns and best practices. Use when designing
|
|
5
|
+
schemas, creating migrations, optimizing queries, adding indexes, or when
|
|
6
|
+
user mentions "database", "schema", "table", "migration", "index", "SQL",
|
|
7
|
+
"Prisma", "TypeORM". Ensures performant, maintainable data models.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
category: backend
|
|
10
|
+
tags:
|
|
11
|
+
- database
|
|
12
|
+
- sql
|
|
13
|
+
- schema
|
|
14
|
+
- optimization
|
|
15
|
+
depends_on:
|
|
16
|
+
- code-review
|
|
17
|
+
recommends:
|
|
18
|
+
- security
|
|
19
|
+
- performance-engineering
|
|
20
|
+
used_by:
|
|
21
|
+
- api-design
|
|
22
|
+
- security-architecture
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Skill: Database Design
|
|
26
|
+
|
|
27
|
+
## Core Principle
|
|
28
|
+
**Design for performance, maintainability, and data integrity.** A bad schema haunts you forever.
|
|
29
|
+
|
|
30
|
+
## Hard Rules
|
|
31
|
+
|
|
32
|
+
1. **NEVER use SELECT \*** - Specify columns explicitly
|
|
33
|
+
2. **NEVER store secrets unencrypted** - Encrypt PII
|
|
34
|
+
3. **ALWAYS use migrations** - No manual schema changes
|
|
35
|
+
4. **ALWAYS index foreign keys** - Join performance
|
|
36
|
+
5. **ALWAYS use appropriate data types** - Don't store numbers as strings
|
|
37
|
+
|
|
38
|
+
## Naming Conventions
|
|
39
|
+
|
|
40
|
+
```sql
|
|
41
|
+
-- Tables: snake_case, plural
|
|
42
|
+
users, orders, order_items
|
|
43
|
+
|
|
44
|
+
-- Columns: snake_case
|
|
45
|
+
user_id, created_at, is_active
|
|
46
|
+
|
|
47
|
+
-- Primary keys
|
|
48
|
+
id SERIAL PRIMARY KEY
|
|
49
|
+
-- or
|
|
50
|
+
user_id UUID PRIMARY KEY
|
|
51
|
+
|
|
52
|
+
-- Foreign keys: {table}_id
|
|
53
|
+
user_id REFERENCES users(id)
|
|
54
|
+
|
|
55
|
+
-- Indexes: idx_{table}_{columns}
|
|
56
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Index Strategy
|
|
60
|
+
|
|
61
|
+
### When to Index
|
|
62
|
+
- Primary keys (automatic)
|
|
63
|
+
- Foreign keys (always)
|
|
64
|
+
- WHERE clause columns
|
|
65
|
+
- ORDER BY columns
|
|
66
|
+
- JOIN conditions
|
|
67
|
+
|
|
68
|
+
### Index Types
|
|
69
|
+
|
|
70
|
+
| Type | Use Case |
|
|
71
|
+
|------|----------|
|
|
72
|
+
| B-tree | Default, equality/range |
|
|
73
|
+
| Unique | Email, username |
|
|
74
|
+
| Partial | `WHERE is_active = true` |
|
|
75
|
+
| Composite | Multi-column queries |
|
|
76
|
+
| GIN | JSONB, arrays, full-text |
|
|
77
|
+
|
|
78
|
+
## Common Mistakes
|
|
79
|
+
|
|
80
|
+
| ❌ Mistake | ✅ Fix |
|
|
81
|
+
|------------|--------|
|
|
82
|
+
| SELECT * | Specify columns |
|
|
83
|
+
| No migrations | Use migration tool |
|
|
84
|
+
| Missing FK indexes | `CREATE INDEX ON orders(user_id)` |
|
|
85
|
+
| N+1 queries | Use JOIN or include |
|
|
86
|
+
| Storing arrays as strings | Use proper array/JSONB |
|
|
87
|
+
|
|
88
|
+
## N+1 Query Fix
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// ❌ Bad: N+1 queries
|
|
92
|
+
for (const order of orders) {
|
|
93
|
+
order.items = await prisma.orderItem.findMany({
|
|
94
|
+
where: { orderId: order.id }
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ✅ Good: Use include
|
|
99
|
+
const orders = await prisma.order.findMany({
|
|
100
|
+
include: { items: true }
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Migration Template
|
|
105
|
+
|
|
106
|
+
```sql
|
|
107
|
+
-- Up: 20250226_create_users.sql
|
|
108
|
+
BEGIN;
|
|
109
|
+
|
|
110
|
+
CREATE TABLE users (
|
|
111
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
112
|
+
email VARCHAR(255) NOT NULL,
|
|
113
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
117
|
+
|
|
118
|
+
COMMIT;
|
|
119
|
+
|
|
120
|
+
-- Down: 20250226_create_users_down.sql
|
|
121
|
+
BEGIN;
|
|
122
|
+
DROP TABLE IF EXISTS users;
|
|
123
|
+
COMMIT;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Prisma Schema Example
|
|
127
|
+
|
|
128
|
+
```prisma
|
|
129
|
+
model User {
|
|
130
|
+
id String @id @default(uuid())
|
|
131
|
+
email String @unique
|
|
132
|
+
orders Order[]
|
|
133
|
+
createdAt DateTime @default(now()) @map("created_at")
|
|
134
|
+
|
|
135
|
+
@@map("users")
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
model Order {
|
|
139
|
+
id String @id @default(uuid())
|
|
140
|
+
userId String @map("user_id")
|
|
141
|
+
user User @relation(fields: [userId], references: [id])
|
|
142
|
+
items OrderItem[]
|
|
143
|
+
|
|
144
|
+
@@index([userId])
|
|
145
|
+
@@map("orders")
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Quick Checklist
|
|
150
|
+
|
|
151
|
+
- [ ] Uses migrations
|
|
152
|
+
- [ ] Foreign keys indexed
|
|
153
|
+
- [ ] Appropriate data types
|
|
154
|
+
- [ ] No SELECT *
|
|
155
|
+
- [ ] N+1 queries avoided
|
|
156
|
+
- [ ] Secrets encrypted
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: performance-be
|
|
3
|
+
description: |
|
|
4
|
+
Backend performance optimization patterns. Use when: optimizing database queries,
|
|
5
|
+
improving API response times, handling high load, or when user mentions "slow",
|
|
6
|
+
"performance", "optimize", "N+1", "caching", "latency". Fast backends = happy users.
|
|
7
|
+
version: 1.0.0
|
|
8
|
+
category: backend
|
|
9
|
+
tags:
|
|
10
|
+
- performance
|
|
11
|
+
- optimization
|
|
12
|
+
- caching
|
|
13
|
+
- database
|
|
14
|
+
depends_on:
|
|
15
|
+
- database-design
|
|
16
|
+
- api-design
|
|
17
|
+
recommends: []
|
|
18
|
+
used_by: []
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Skill: Performance BE
|
|
22
|
+
|
|
23
|
+
## Core Principle
|
|
24
|
+
**Measure before optimizing.** Profile, identify bottlenecks, then fix. Premature optimization is waste.
|
|
25
|
+
|
|
26
|
+
## Performance Metrics
|
|
27
|
+
|
|
28
|
+
| Metric | Target | What |
|
|
29
|
+
|--------|--------|------|
|
|
30
|
+
| **Response Time** | < 200ms | P95 latency |
|
|
31
|
+
| **Throughput** | 1000+ RPS | Requests per second |
|
|
32
|
+
| **Error Rate** | < 0.1% | Failed requests |
|
|
33
|
+
| **DB Query Time** | < 50ms | P95 query time |
|
|
34
|
+
|
|
35
|
+
## Hard Rules
|
|
36
|
+
|
|
37
|
+
1. **NEVER use SELECT \*** - Specify columns
|
|
38
|
+
2. **NEVER N+1 queries** - Use JOINs or includes
|
|
39
|
+
3. **ALWAYS index foreign keys** - Critical for joins
|
|
40
|
+
4. **ALWAYS paginate lists** - No unbounded queries
|
|
41
|
+
5. **ALWAYS cache expensive operations** - Within reason
|
|
42
|
+
|
|
43
|
+
## N+1 Query Fix
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// ❌ Bad: N+1 queries
|
|
47
|
+
async function getOrdersWithItems() {
|
|
48
|
+
const orders = await prisma.order.findMany();
|
|
49
|
+
|
|
50
|
+
for (const order of orders) {
|
|
51
|
+
order.items = await prisma.orderItem.findMany({
|
|
52
|
+
where: { orderId: order.id }
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return orders;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ✅ Good: Single query with include
|
|
60
|
+
async function getOrdersWithItems() {
|
|
61
|
+
return prisma.order.findMany({
|
|
62
|
+
include: { items: true }
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Database Optimization
|
|
68
|
+
|
|
69
|
+
### Indexing
|
|
70
|
+
|
|
71
|
+
```sql
|
|
72
|
+
-- Index foreign keys
|
|
73
|
+
CREATE INDEX idx_orders_user_id ON orders(user_id);
|
|
74
|
+
|
|
75
|
+
-- Composite index for common queries
|
|
76
|
+
CREATE INDEX idx_orders_status_created ON orders(status, created_at DESC);
|
|
77
|
+
|
|
78
|
+
-- Partial index for active records
|
|
79
|
+
CREATE INDEX idx_users_active ON users(email) WHERE is_active = true;
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Query Optimization
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// ❌ Bad: Unbounded query
|
|
86
|
+
const orders = await prisma.order.findMany();
|
|
87
|
+
|
|
88
|
+
// ✅ Good: Paginated
|
|
89
|
+
const orders = await prisma.order.findMany({
|
|
90
|
+
take: 20,
|
|
91
|
+
skip: (page - 1) * 20,
|
|
92
|
+
orderBy: { createdAt: 'desc' },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// ✅ Good: Select only needed fields
|
|
96
|
+
const users = await prisma.user.findMany({
|
|
97
|
+
select: { id: true, name: true, email: true },
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Caching Strategies
|
|
102
|
+
|
|
103
|
+
### Redis Patterns
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { Redis } from 'ioredis';
|
|
107
|
+
|
|
108
|
+
const redis = new Redis();
|
|
109
|
+
|
|
110
|
+
// Cache-aside pattern
|
|
111
|
+
async function getUser(id: string) {
|
|
112
|
+
// 1. Check cache
|
|
113
|
+
const cached = await redis.get(`user:${id}`);
|
|
114
|
+
if (cached) return JSON.parse(cached);
|
|
115
|
+
|
|
116
|
+
// 2. Fetch from DB
|
|
117
|
+
const user = await prisma.user.findUnique({ where: { id } });
|
|
118
|
+
|
|
119
|
+
// 3. Cache result
|
|
120
|
+
if (user) {
|
|
121
|
+
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return user;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Invalidate on update
|
|
128
|
+
async function updateUser(id: string, data: UpdateData) {
|
|
129
|
+
const user = await prisma.user.update({ where: { id }, data });
|
|
130
|
+
await redis.del(`user:${id}`);
|
|
131
|
+
return user;
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Cache Headers
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// Static assets
|
|
139
|
+
app.get('/static/*', (req, res) => {
|
|
140
|
+
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// API responses
|
|
144
|
+
app.get('/api/products', (req, res) => {
|
|
145
|
+
res.setHeader('Cache-Control', 'private, max-age=60, stale-while-revalidate=300');
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Common Mistakes
|
|
150
|
+
|
|
151
|
+
| ❌ Mistake | ✅ Fix |
|
|
152
|
+
|------------|--------|
|
|
153
|
+
| SELECT * | Specify columns |
|
|
154
|
+
| N+1 queries | Use JOIN/include |
|
|
155
|
+
| No pagination | Add limit/offset |
|
|
156
|
+
| Missing indexes | Index FKs, WHERE columns |
|
|
157
|
+
| No caching | Add Redis cache |
|
|
158
|
+
| Sync operations | Use async |
|
|
159
|
+
|
|
160
|
+
## Connection Pooling
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
// Prisma connection pool
|
|
164
|
+
const prisma = new PrismaClient({
|
|
165
|
+
datasources: {
|
|
166
|
+
db: {
|
|
167
|
+
url: process.env.DATABASE_URL,
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
// Connection pool settings
|
|
171
|
+
__internal: {
|
|
172
|
+
engine: {
|
|
173
|
+
connectionLimit: 10,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Performance Checklist
|
|
180
|
+
|
|
181
|
+
### Database
|
|
182
|
+
- [ ] Foreign keys indexed
|
|
183
|
+
- [ ] N+1 queries eliminated
|
|
184
|
+
- [ ] Queries use indexes (EXPLAIN ANALYZE)
|
|
185
|
+
- [ ] Pagination implemented
|
|
186
|
+
- [ ] Connection pooling configured
|
|
187
|
+
|
|
188
|
+
### API
|
|
189
|
+
- [ ] Response times < 200ms P95
|
|
190
|
+
- [ ] Caching implemented
|
|
191
|
+
- [ ] Compression enabled
|
|
192
|
+
- [ ] Rate limiting configured
|
|
193
|
+
|
|
194
|
+
### Monitoring
|
|
195
|
+
- [ ] P95/P99 latency tracked
|
|
196
|
+
- [ ] Slow query logging
|
|
197
|
+
- [ ] Error rate monitored
|
|
198
|
+
|
|
199
|
+
## Profiling
|
|
200
|
+
|
|
201
|
+
```sql
|
|
202
|
+
-- PostgreSQL query analysis
|
|
203
|
+
EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = '123';
|
|
204
|
+
|
|
205
|
+
-- Find slow queries
|
|
206
|
+
SELECT query, mean_exec_time
|
|
207
|
+
FROM pg_stat_statements
|
|
208
|
+
ORDER BY mean_exec_time DESC
|
|
209
|
+
LIMIT 10;
|
|
210
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security
|
|
3
|
+
description: |
|
|
4
|
+
Security best practices for backend development. Use when implementing
|
|
5
|
+
authentication, authorization, input validation, or when user mentions
|
|
6
|
+
"security", "auth", "JWT", "password", "encryption", "XSS", "SQL injection",
|
|
7
|
+
"OWASP", "vulnerability". Security is NOT optional - always apply these rules.
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
category: backend
|
|
10
|
+
tags:
|
|
11
|
+
- security
|
|
12
|
+
- authentication
|
|
13
|
+
- authorization
|
|
14
|
+
- owasp
|
|
15
|
+
depends_on:
|
|
16
|
+
- api-design
|
|
17
|
+
recommends:
|
|
18
|
+
- database-design
|
|
19
|
+
used_by:
|
|
20
|
+
- security-architecture
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Skill: Security
|
|
24
|
+
|
|
25
|
+
## Core Principle
|
|
26
|
+
**Security first. Never trust user input.** Every input is an attack vector.
|
|
27
|
+
|
|
28
|
+
## Hard Rules
|
|
29
|
+
|
|
30
|
+
1. **NEVER trust user input** - Validate everything
|
|
31
|
+
2. **NEVER store secrets in code** - Use environment variables
|
|
32
|
+
3. **NEVER use MD5/SHA1 for passwords** - Use bcrypt/argon2
|
|
33
|
+
4. **ALWAYS use parameterized queries** - Prevent SQL injection
|
|
34
|
+
5. **ALWAYS use HTTPS** - No exceptions in production
|
|
35
|
+
6. **ALWAYS log security events** - Auth failures, access denied
|
|
36
|
+
|
|
37
|
+
## OWASP Top 10 (Quick)
|
|
38
|
+
|
|
39
|
+
| # | Issue | Prevention |
|
|
40
|
+
|---|-------|------------|
|
|
41
|
+
| 1 | Broken Access Control | Check permissions |
|
|
42
|
+
| 2 | Crypto Failures | HTTPS, encrypt secrets |
|
|
43
|
+
| 3 | Injection | Parameterized queries |
|
|
44
|
+
| 4 | Insecure Design | Threat modeling |
|
|
45
|
+
| 5 | Misconfiguration | Harden defaults |
|
|
46
|
+
| 6 | Vulnerable Components | Update deps |
|
|
47
|
+
| 7 | Auth Failures | Strong auth |
|
|
48
|
+
| 8 | Data Integrity | Validate inputs |
|
|
49
|
+
| 9 | Logging Failures | Log security events |
|
|
50
|
+
| 10 | SSRF | Validate URLs |
|
|
51
|
+
|
|
52
|
+
## Authentication
|
|
53
|
+
|
|
54
|
+
### Password Handling
|
|
55
|
+
```typescript
|
|
56
|
+
import bcrypt from 'bcrypt';
|
|
57
|
+
|
|
58
|
+
// Hash password
|
|
59
|
+
const hash = await bcrypt.hash(password, 12);
|
|
60
|
+
|
|
61
|
+
// Verify password
|
|
62
|
+
const valid = await bcrypt.compare(password, hash);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### JWT Config
|
|
66
|
+
```typescript
|
|
67
|
+
const JWT_CONFIG = {
|
|
68
|
+
algorithm: 'RS256',
|
|
69
|
+
expiresIn: '15m', // Short access token
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Common Mistakes
|
|
74
|
+
|
|
75
|
+
| ❌ Mistake | ✅ Fix |
|
|
76
|
+
|------------|--------|
|
|
77
|
+
| `SELECT * FROM users WHERE id = ${id}` | Parameterized query |
|
|
78
|
+
| Storing passwords in plain text | bcrypt/argon2 |
|
|
79
|
+
| Hardcoded secrets | Environment variables |
|
|
80
|
+
| No rate limiting | Add rate limiter |
|
|
81
|
+
| Exposing internal errors | Generic error messages |
|
|
82
|
+
|
|
83
|
+
## SQL Injection Prevention
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
// ❌ Bad: SQL injection vulnerable
|
|
87
|
+
const query = `SELECT * FROM users WHERE id = ${userId}`;
|
|
88
|
+
|
|
89
|
+
// ✅ Good: Parameterized (Prisma)
|
|
90
|
+
const user = await prisma.user.findUnique({
|
|
91
|
+
where: { id: userId }
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ✅ Good: Parameterized (raw)
|
|
95
|
+
const result = await pool.query(
|
|
96
|
+
'SELECT * FROM users WHERE id = $1',
|
|
97
|
+
[userId]
|
|
98
|
+
);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Input Validation
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { z } from 'zod';
|
|
105
|
+
|
|
106
|
+
const schema = z.object({
|
|
107
|
+
email: z.string().email(),
|
|
108
|
+
password: z.string().min(8),
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const validate = (schema) => (req, res, next) => {
|
|
112
|
+
try {
|
|
113
|
+
req.body = schema.parse(req.body);
|
|
114
|
+
next();
|
|
115
|
+
} catch (e) {
|
|
116
|
+
res.status(400).json({ error: 'Validation failed' });
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Security Headers
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import helmet from 'helmet';
|
|
125
|
+
|
|
126
|
+
app.use(helmet());
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Quick Checklist
|
|
130
|
+
|
|
131
|
+
- [ ] Input validated
|
|
132
|
+
- [ ] Parameterized queries
|
|
133
|
+
- [ ] Passwords hashed
|
|
134
|
+
- [ ] HTTPS enabled
|
|
135
|
+
- [ ] Rate limiting
|
|
136
|
+
- [ ] Secrets in env vars
|
|
137
|
+
- [ ] Security headers
|
|
138
|
+
- [ ] Auth events logged
|