@caddis/cli 0.0.0 → 0.1.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/LICENSE +21 -0
- package/README.md +150 -1
- package/bundles/antigravity-plugin/agents/code-reviewer.md +47 -0
- package/bundles/antigravity-plugin/agents/preflight.md +53 -0
- package/bundles/antigravity-plugin/guard_agy.py +338 -0
- package/bundles/antigravity-plugin/hooks.json +36 -0
- package/bundles/antigravity-plugin/mcp_config.json +8 -0
- package/bundles/antigravity-plugin/mcp_ping_server.py +55 -0
- package/bundles/antigravity-plugin/plugin.json +5 -0
- package/bundles/antigravity-plugin/session_end_agy.py +57 -0
- package/bundles/antigravity-plugin/skills/_registry.md +115 -0
- package/bundles/antigravity-plugin/skills/add-rules/SKILL.md +45 -0
- package/bundles/antigravity-plugin/skills/api-design/SKILL.md +249 -0
- package/bundles/antigravity-plugin/skills/backend-development/SKILL.md +305 -0
- package/bundles/antigravity-plugin/skills/best-practices/SKILL.md +500 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +263 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +326 -0
- package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +245 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/anti-patterns.md +571 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/before-after-examples.md +1114 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/best-practices-guide.md +513 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/common-workflows.md +692 -0
- package/bundles/antigravity-plugin/skills/best-practices/references/prompt-patterns.md +547 -0
- package/bundles/antigravity-plugin/skills/brainstorming/SKILL.md +57 -0
- package/bundles/antigravity-plugin/skills/ci-cd-pipeline/SKILL.md +315 -0
- package/bundles/antigravity-plugin/skills/code-documentation/SKILL.md +271 -0
- package/bundles/antigravity-plugin/skills/code-review/SKILL.md +122 -0
- package/bundles/antigravity-plugin/skills/codebase-audit/SKILL.md +204 -0
- package/bundles/antigravity-plugin/skills/context-curator/SKILL.md +157 -0
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +40 -0
- package/bundles/antigravity-plugin/skills/css-architecture/SKILL.md +305 -0
- package/bundles/antigravity-plugin/skills/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
- package/bundles/antigravity-plugin/skills/database-design/SKILL.md +177 -0
- package/bundles/antigravity-plugin/skills/db-diagram/SKILL.md +148 -0
- package/bundles/antigravity-plugin/skills/db-diagram/scripts/sql_to_graph.py +1212 -0
- package/bundles/antigravity-plugin/skills/digress/SKILL.md +61 -0
- package/bundles/antigravity-plugin/skills/draw-io/SKILL.md +162 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/aws-icons.md +677 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/layout-guidelines.md +142 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/troubleshooting.md +118 -0
- package/bundles/antigravity-plugin/skills/draw-io/references/workflows.md +103 -0
- package/bundles/antigravity-plugin/skills/draw-io/scripts/convert-drawio-to-png.sh +25 -0
- package/bundles/antigravity-plugin/skills/draw-io/scripts/find_aws_icon.py +79 -0
- package/bundles/antigravity-plugin/skills/error-handling/SKILL.md +260 -0
- package/bundles/antigravity-plugin/skills/excalidraw-db/SKILL.md +38 -0
- package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +300 -0
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +198 -0
- package/bundles/antigravity-plugin/skills/frontend-design/SKILL.md +193 -0
- package/bundles/antigravity-plugin/skills/frontend-design/references/my-tech-stack.md +127 -0
- package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +195 -0
- package/bundles/antigravity-plugin/skills/git-commit/SKILL.md +285 -0
- package/bundles/antigravity-plugin/skills/golden-plan/SKILL.md +577 -0
- package/bundles/antigravity-plugin/skills/handoff/SKILL.md +100 -0
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +114 -0
- package/bundles/antigravity-plugin/skills/javascript-typescript/SKILL.md +142 -0
- package/bundles/antigravity-plugin/skills/kb/SKILL.md +60 -0
- package/bundles/antigravity-plugin/skills/mermaid-db/SKILL.md +33 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/SKILL.md +236 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/advanced-features.md +556 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/architecture-diagrams.md +192 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/c4-diagrams.md +410 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/class-diagrams.md +361 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/erd-diagrams.md +510 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/flowcharts.md +450 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/sequence-diagrams.md +394 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/troubleshooting.md +335 -0
- package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/workflows.md +418 -0
- package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +68 -0
- package/bundles/antigravity-plugin/skills/mockup/SKILL.md +242 -0
- package/bundles/antigravity-plugin/skills/particle-art/SKILL.md +243 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/canvas-utils.ts +171 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/dot-field.template.tsx +203 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/flow-field.template.tsx +263 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/node-shape.template.tsx +261 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/shape-sampler.ts +281 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/stipple-morph.template.tsx +167 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/stipple.template.tsx +175 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/trail-ghost.template.tsx +266 -0
- package/bundles/antigravity-plugin/skills/particle-art/references/usage-examples.md +320 -0
- package/bundles/antigravity-plugin/skills/playwright/API_REFERENCE.md +653 -0
- package/bundles/antigravity-plugin/skills/playwright/SKILL.md +454 -0
- package/bundles/antigravity-plugin/skills/playwright/lib/helpers.js +441 -0
- package/bundles/antigravity-plugin/skills/playwright/package.json +26 -0
- package/bundles/antigravity-plugin/skills/playwright/run.js +228 -0
- package/bundles/antigravity-plugin/skills/prd/SKILL.md +107 -0
- package/bundles/antigravity-plugin/skills/preflight/SKILL.md +435 -0
- package/bundles/antigravity-plugin/skills/python/SKILL.md +388 -0
- package/bundles/antigravity-plugin/skills/react-best-practices/SKILL.md +269 -0
- package/bundles/antigravity-plugin/skills/react-dev/README.md +404 -0
- package/bundles/antigravity-plugin/skills/react-dev/SKILL.md +459 -0
- package/bundles/antigravity-plugin/skills/react-dev/examples/generic-components.md +579 -0
- package/bundles/antigravity-plugin/skills/react-dev/examples/server-components.md +579 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/event-handlers.md +574 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/hooks.md +456 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/react-19-patterns.md +638 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/react-router.md +1002 -0
- package/bundles/antigravity-plugin/skills/react-dev/references/tanstack-router.md +587 -0
- package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +486 -0
- package/bundles/antigravity-plugin/skills/resume/SKILL.md +36 -0
- package/bundles/antigravity-plugin/skills/security-review/SKILL.md +196 -0
- package/bundles/antigravity-plugin/skills/setup-project-ai/SKILL.md +61 -0
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +107 -0
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +103 -0
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +102 -0
- package/bundles/antigravity-plugin/skills/skill-creator/LICENSE.txt +202 -0
- package/bundles/antigravity-plugin/skills/skill-creator/SKILL.md +491 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/analyzer.md +274 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/comparator.md +202 -0
- package/bundles/antigravity-plugin/skills/skill-creator/agents/grader.md +223 -0
- package/bundles/antigravity-plugin/skills/skill-creator/assets/eval_review.html +146 -0
- package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/bundles/antigravity-plugin/skills/skill-creator/references/schemas.md +430 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/__init__.py +0 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/generate_report.py +326 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/improve_description.py +247 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/package_skill.py +136 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_eval.py +310 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_loop.py +328 -0
- package/bundles/antigravity-plugin/skills/skill-creator/scripts/utils.py +47 -0
- package/bundles/antigravity-plugin/skills/sql/SKILL.md +321 -0
- package/bundles/antigravity-plugin/skills/tdd/SKILL.md +37 -0
- package/bundles/antigravity-plugin/skills/tdd-workflow/SKILL.md +188 -0
- package/bundles/antigravity-plugin/skills/technical-writing/SKILL.md +286 -0
- package/bundles/antigravity-plugin/skills/test-strategy/SKILL.md +155 -0
- package/bundles/antigravity-plugin/skills/ui-brief/SKILL.md +84 -0
- package/bundles/antigravity-plugin/skills/ui-review/SKILL.md +176 -0
- package/bundles/antigravity-plugin/skills/ui-review/references/framework-fixes.md +471 -0
- package/bundles/antigravity-plugin/skills/ui-review/references/visual-checklist.md +236 -0
- package/bundles/antigravity-plugin/skills/usage-review/SKILL.md +77 -0
- package/bundles/antigravity-plugin/skills/use-model/SKILL.md +64 -0
- package/bundles/antigravity-plugin/skills/using-git-worktrees/SKILL.md +217 -0
- package/bundles/antigravity-plugin/skills/version/SKILL.md +18 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
- package/bundles/antigravity-plugin/skills/warm-editorial-ui/SKILL.md +732 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/LICENSE.txt +202 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/SKILL.md +97 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/console_logging.py +35 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/element_discovery.py +40 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/examples/static_html_automation.py +33 -0
- package/bundles/antigravity-plugin/skills/webapp-testing/scripts/with_server.py +106 -0
- package/bundles/antigravity-plugin/skills/windows-deployment/SKILL.md +880 -0
- package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +384 -0
- package/bundles/antigravity-plugin/statusline-command-agy.sh +91 -0
- package/bundles/antigravity-plugin/warm_start_agy.py +149 -0
- package/bundles/manifest.json +6 -0
- package/dist/cli.js +5363 -0
- package/package.json +61 -4
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: backend-development
|
|
3
|
+
description: Backend API design, database architecture, microservices patterns, and test-driven development. Use for designing APIs, database schemas, or backend system architecture.
|
|
4
|
+
source: wshobson/agents
|
|
5
|
+
license: MIT
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Backend Development
|
|
9
|
+
|
|
10
|
+
## API Design
|
|
11
|
+
|
|
12
|
+
### RESTful Conventions
|
|
13
|
+
```
|
|
14
|
+
GET /users # List users
|
|
15
|
+
POST /users # Create user
|
|
16
|
+
GET /users/:id # Get user
|
|
17
|
+
PUT /users/:id # Update user (full)
|
|
18
|
+
PATCH /users/:id # Update user (partial)
|
|
19
|
+
DELETE /users/:id # Delete user
|
|
20
|
+
|
|
21
|
+
GET /users/:id/posts # List user's posts
|
|
22
|
+
POST /users/:id/posts # Create post for user
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Response Format
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"data": { ... },
|
|
29
|
+
"meta": {
|
|
30
|
+
"page": 1,
|
|
31
|
+
"per_page": 20,
|
|
32
|
+
"total": 100
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Error Format
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"error": {
|
|
41
|
+
"code": "VALIDATION_ERROR",
|
|
42
|
+
"message": "Invalid input",
|
|
43
|
+
"details": [
|
|
44
|
+
{ "field": "email", "message": "Invalid format" }
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Database Patterns
|
|
51
|
+
|
|
52
|
+
### Schema Design
|
|
53
|
+
```sql
|
|
54
|
+
-- Use UUIDs for public IDs
|
|
55
|
+
CREATE TABLE users (
|
|
56
|
+
id SERIAL PRIMARY KEY,
|
|
57
|
+
public_id UUID DEFAULT gen_random_uuid() UNIQUE,
|
|
58
|
+
email VARCHAR(255) UNIQUE NOT NULL,
|
|
59
|
+
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
60
|
+
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
-- Soft deletes
|
|
64
|
+
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMPTZ;
|
|
65
|
+
|
|
66
|
+
-- Indexes
|
|
67
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
68
|
+
CREATE INDEX idx_users_created ON users(created_at DESC);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Query Patterns
|
|
72
|
+
```sql
|
|
73
|
+
-- Pagination with cursor
|
|
74
|
+
SELECT * FROM posts
|
|
75
|
+
WHERE created_at < $cursor
|
|
76
|
+
ORDER BY created_at DESC
|
|
77
|
+
LIMIT 20;
|
|
78
|
+
|
|
79
|
+
-- Efficient counting
|
|
80
|
+
SELECT reltuples::bigint AS estimate
|
|
81
|
+
FROM pg_class WHERE relname = 'users';
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Authentication
|
|
85
|
+
|
|
86
|
+
### JWT Pattern
|
|
87
|
+
```typescript
|
|
88
|
+
interface TokenPayload {
|
|
89
|
+
sub: string; // User ID
|
|
90
|
+
iat: number; // Issued at
|
|
91
|
+
exp: number; // Expiration
|
|
92
|
+
scope: string[]; // Permissions
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function verifyToken(token: string): TokenPayload {
|
|
96
|
+
return jwt.verify(token, SECRET) as TokenPayload;
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Middleware
|
|
101
|
+
```typescript
|
|
102
|
+
async function authenticate(req: Request, res: Response, next: Next) {
|
|
103
|
+
const token = req.headers.authorization?.replace('Bearer ', '');
|
|
104
|
+
if (!token) {
|
|
105
|
+
return res.status(401).json({ error: 'Unauthorized' });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
req.user = verifyToken(token);
|
|
110
|
+
next();
|
|
111
|
+
} catch {
|
|
112
|
+
res.status(401).json({ error: 'Invalid token' });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Caching Strategy
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Cache-aside pattern
|
|
121
|
+
async function getUser(id: string): Promise<User> {
|
|
122
|
+
const cached = await redis.get(`user:${id}`);
|
|
123
|
+
if (cached) return JSON.parse(cached);
|
|
124
|
+
|
|
125
|
+
const user = await db.users.findById(id);
|
|
126
|
+
await redis.setex(`user:${id}`, 3600, JSON.stringify(user));
|
|
127
|
+
return user;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Cache invalidation
|
|
131
|
+
async function updateUser(id: string, data: Partial<User>) {
|
|
132
|
+
await db.users.update(id, data);
|
|
133
|
+
await redis.del(`user:${id}`);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Architecture Patterns
|
|
138
|
+
|
|
139
|
+
### Repository Pattern
|
|
140
|
+
Abstract data access from business logic for testability and swappable backends.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
interface UserRepository {
|
|
144
|
+
findAll(filters?: UserFilters): Promise<User[]>
|
|
145
|
+
findById(id: string): Promise<User | null>
|
|
146
|
+
create(data: CreateUserDto): Promise<User>
|
|
147
|
+
update(id: string, data: UpdateUserDto): Promise<User>
|
|
148
|
+
delete(id: string): Promise<void>
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Service Layer Pattern
|
|
153
|
+
Separate business logic from data access and HTTP concerns.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
class UserService {
|
|
157
|
+
constructor(private userRepo: UserRepository) {}
|
|
158
|
+
|
|
159
|
+
async createUser(data: CreateUserDto): Promise<User> {
|
|
160
|
+
// Business logic: validation, enrichment, side effects
|
|
161
|
+
const existing = await this.userRepo.findByEmail(data.email);
|
|
162
|
+
if (existing) throw new ConflictError('Email already registered');
|
|
163
|
+
return this.userRepo.create(data);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### N+1 Query Prevention
|
|
169
|
+
```typescript
|
|
170
|
+
// Bad: N+1 queries
|
|
171
|
+
const posts = await getPosts();
|
|
172
|
+
for (const post of posts) {
|
|
173
|
+
post.author = await getUser(post.author_id); // N queries
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Good: Batch fetch
|
|
177
|
+
const posts = await getPosts();
|
|
178
|
+
const authorIds = posts.map(p => p.author_id);
|
|
179
|
+
const authors = await getUsers(authorIds); // 1 query
|
|
180
|
+
const authorMap = new Map(authors.map(a => [a.id, a]));
|
|
181
|
+
posts.forEach(post => { post.author = authorMap.get(post.author_id); });
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Rate Limiting
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// Library-based approach
|
|
188
|
+
const limiter = rateLimit({
|
|
189
|
+
windowMs: 60 * 1000, // 1 minute
|
|
190
|
+
max: 100, // 100 requests per window
|
|
191
|
+
keyGenerator: (req) => req.ip,
|
|
192
|
+
handler: (req, res) => {
|
|
193
|
+
res.status(429).json({ error: 'Too many requests' });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Error Handling
|
|
199
|
+
|
|
200
|
+
### Retry with Exponential Backoff
|
|
201
|
+
```typescript
|
|
202
|
+
async function fetchWithRetry<T>(
|
|
203
|
+
fn: () => Promise<T>,
|
|
204
|
+
maxRetries = 3
|
|
205
|
+
): Promise<T> {
|
|
206
|
+
let lastError: Error;
|
|
207
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
208
|
+
try {
|
|
209
|
+
return await fn();
|
|
210
|
+
} catch (error) {
|
|
211
|
+
lastError = error as Error;
|
|
212
|
+
if (i < maxRetries - 1) {
|
|
213
|
+
const delay = Math.pow(2, i) * 1000;
|
|
214
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
throw lastError!;
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Centralized Error Handler
|
|
223
|
+
```typescript
|
|
224
|
+
class ApiError extends Error {
|
|
225
|
+
constructor(public statusCode: number, message: string, public isOperational = true) {
|
|
226
|
+
super(message);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function errorHandler(error: unknown, req: Request): Response {
|
|
231
|
+
if (error instanceof ApiError) {
|
|
232
|
+
return json({ error: error.message }, { status: error.statusCode });
|
|
233
|
+
}
|
|
234
|
+
if (error instanceof z.ZodError) {
|
|
235
|
+
return json({ error: 'Validation failed', details: error.errors }, { status: 400 });
|
|
236
|
+
}
|
|
237
|
+
console.error('Unexpected error:', error);
|
|
238
|
+
return json({ error: 'Internal server error' }, { status: 500 });
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Role-Based Access Control
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
type Permission = 'read' | 'write' | 'delete' | 'admin';
|
|
246
|
+
|
|
247
|
+
const rolePermissions: Record<string, Permission[]> = {
|
|
248
|
+
admin: ['read', 'write', 'delete', 'admin'],
|
|
249
|
+
moderator: ['read', 'write', 'delete'],
|
|
250
|
+
user: ['read', 'write']
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
function hasPermission(user: { role: string }, permission: Permission): boolean {
|
|
254
|
+
return (rolePermissions[user.role] || []).includes(permission);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Background Jobs and Queues
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
class JobQueue<T> {
|
|
262
|
+
private queue: T[] = [];
|
|
263
|
+
private processing = false;
|
|
264
|
+
|
|
265
|
+
async add(job: T): Promise<void> {
|
|
266
|
+
this.queue.push(job);
|
|
267
|
+
if (!this.processing) this.process();
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private async process(): Promise<void> {
|
|
271
|
+
this.processing = true;
|
|
272
|
+
while (this.queue.length > 0) {
|
|
273
|
+
const job = this.queue.shift()!;
|
|
274
|
+
try { await this.execute(job); }
|
|
275
|
+
catch (error) { console.error('Job failed:', error); }
|
|
276
|
+
}
|
|
277
|
+
this.processing = false;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private async execute(job: T): Promise<void> { /* implementation */ }
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Observability
|
|
285
|
+
|
|
286
|
+
### Structured Logging
|
|
287
|
+
```typescript
|
|
288
|
+
class Logger {
|
|
289
|
+
log(level: 'info' | 'warn' | 'error', message: string, context?: Record<string, unknown>) {
|
|
290
|
+
console.log(JSON.stringify({
|
|
291
|
+
timestamp: new Date().toISOString(), level, message, ...context
|
|
292
|
+
}));
|
|
293
|
+
}
|
|
294
|
+
info(msg: string, ctx?: Record<string, unknown>) { this.log('info', msg, ctx); }
|
|
295
|
+
warn(msg: string, ctx?: Record<string, unknown>) { this.log('warn', msg, ctx); }
|
|
296
|
+
error(msg: string, err: Error, ctx?: Record<string, unknown>) {
|
|
297
|
+
this.log('error', msg, { ...ctx, error: err.message, stack: err.stack });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
### Health and Monitoring
|
|
303
|
+
- **Metrics**: Request latency, error rates, queue depths
|
|
304
|
+
- **Tracing**: Distributed tracing with correlation IDs
|
|
305
|
+
- **Health checks**: `/health` and `/ready` endpoints
|