@plazmodium/odin 0.3.3-beta → 0.3.5-beta

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.
Files changed (133) hide show
  1. package/README.md +25 -10
  2. package/builtin/ODIN.md +1067 -0
  3. package/builtin/agent-definitions/README.md +170 -0
  4. package/builtin/agent-definitions/_shared-context.md +377 -0
  5. package/builtin/agent-definitions/architect.md +627 -0
  6. package/builtin/agent-definitions/builder.md +713 -0
  7. package/builtin/agent-definitions/discovery.md +293 -0
  8. package/builtin/agent-definitions/documenter.md +238 -0
  9. package/builtin/agent-definitions/guardian.md +1049 -0
  10. package/builtin/agent-definitions/integrator.md +189 -0
  11. package/builtin/agent-definitions/planning.md +236 -0
  12. package/builtin/agent-definitions/product.md +405 -0
  13. package/builtin/agent-definitions/release.md +205 -0
  14. package/builtin/agent-definitions/reviewer.md +447 -0
  15. package/builtin/agent-definitions/watcher.md +402 -0
  16. package/builtin/skills/api/graphql/SKILL.md +548 -0
  17. package/builtin/skills/api/grpc/SKILL.md +554 -0
  18. package/builtin/skills/api/rest-api/SKILL.md +469 -0
  19. package/builtin/skills/api/trpc/SKILL.md +503 -0
  20. package/builtin/skills/architecture/clean-architecture/SKILL.md +141 -0
  21. package/builtin/skills/architecture/domain-driven-design/SKILL.md +129 -0
  22. package/builtin/skills/architecture/event-driven/SKILL.md +145 -0
  23. package/builtin/skills/architecture/microservices/SKILL.md +143 -0
  24. package/builtin/skills/architecture/tla-precheck/SKILL.md +171 -0
  25. package/builtin/skills/backend/golang-gin/SKILL.md +141 -0
  26. package/builtin/skills/backend/nodejs-express/SKILL.md +277 -0
  27. package/builtin/skills/backend/nodejs-fastify/SKILL.md +152 -0
  28. package/builtin/skills/backend/python-django/SKILL.md +128 -0
  29. package/builtin/skills/backend/python-fastapi/SKILL.md +140 -0
  30. package/builtin/skills/database/mongodb/SKILL.md +132 -0
  31. package/builtin/skills/database/postgresql/SKILL.md +120 -0
  32. package/builtin/skills/database/prisma-orm/SKILL.md +366 -0
  33. package/builtin/skills/database/redis/SKILL.md +140 -0
  34. package/builtin/skills/database/supabase/SKILL.md +416 -0
  35. package/builtin/skills/devops/aws/SKILL.md +382 -0
  36. package/builtin/skills/devops/docker/SKILL.md +359 -0
  37. package/builtin/skills/devops/github-actions/SKILL.md +435 -0
  38. package/builtin/skills/devops/kubernetes/SKILL.md +459 -0
  39. package/builtin/skills/devops/terraform/SKILL.md +453 -0
  40. package/builtin/skills/frontend/alpine-dev/SKILL.md +27 -0
  41. package/builtin/skills/frontend/angular-dev/SKILL.md +28 -0
  42. package/builtin/skills/frontend/astro-dev/SKILL.md +28 -0
  43. package/builtin/skills/frontend/htmx-dev/SKILL.md +28 -0
  44. package/builtin/skills/frontend/nextjs-dev/SKILL.md +470 -0
  45. package/builtin/skills/frontend/react-patterns/SKILL.md +166 -0
  46. package/builtin/skills/frontend/svelte-dev/SKILL.md +28 -0
  47. package/builtin/skills/frontend/tailwindcss/SKILL.md +131 -0
  48. package/builtin/skills/frontend/vuejs-dev/SKILL.md +28 -0
  49. package/builtin/skills/generic-dev/SKILL.md +307 -0
  50. package/builtin/skills/testing/cypress/SKILL.md +372 -0
  51. package/builtin/skills/testing/jest/SKILL.md +176 -0
  52. package/builtin/skills/testing/playwright/SKILL.md +341 -0
  53. package/builtin/skills/testing/unit-tests-eval-sdd/SKILL.md +73 -0
  54. package/builtin/skills/testing/unit-tests-sdd/SKILL.md +83 -0
  55. package/builtin/skills/testing/vitest/SKILL.md +249 -0
  56. package/dist/adapters/skills/filesystem.d.ts +1 -0
  57. package/dist/adapters/skills/filesystem.d.ts.map +1 -1
  58. package/dist/adapters/skills/filesystem.js +6 -18
  59. package/dist/adapters/skills/filesystem.js.map +1 -1
  60. package/dist/adapters/skills/types.d.ts +1 -0
  61. package/dist/adapters/skills/types.d.ts.map +1 -1
  62. package/dist/adapters/workflow-state/in-memory.d.ts +10 -2
  63. package/dist/adapters/workflow-state/in-memory.d.ts.map +1 -1
  64. package/dist/adapters/workflow-state/in-memory.js +98 -5
  65. package/dist/adapters/workflow-state/in-memory.js.map +1 -1
  66. package/dist/adapters/workflow-state/supabase.d.ts +8 -2
  67. package/dist/adapters/workflow-state/supabase.d.ts.map +1 -1
  68. package/dist/adapters/workflow-state/supabase.js +204 -0
  69. package/dist/adapters/workflow-state/supabase.js.map +1 -1
  70. package/dist/adapters/workflow-state/types.d.ts +15 -1
  71. package/dist/adapters/workflow-state/types.d.ts.map +1 -1
  72. package/dist/builtin-assets.d.ts +8 -0
  73. package/dist/builtin-assets.d.ts.map +1 -0
  74. package/dist/builtin-assets.js +90 -0
  75. package/dist/builtin-assets.js.map +1 -0
  76. package/dist/domain/skill-draft-validation.d.ts +18 -0
  77. package/dist/domain/skill-draft-validation.d.ts.map +1 -0
  78. package/dist/domain/skill-draft-validation.js +100 -0
  79. package/dist/domain/skill-draft-validation.js.map +1 -0
  80. package/dist/domain/skill-proposals.d.ts +11 -0
  81. package/dist/domain/skill-proposals.d.ts.map +1 -0
  82. package/dist/domain/skill-proposals.js +103 -0
  83. package/dist/domain/skill-proposals.js.map +1 -0
  84. package/dist/init.js +69 -11
  85. package/dist/init.js.map +1 -1
  86. package/dist/schemas.d.ts +39 -1
  87. package/dist/schemas.d.ts.map +1 -1
  88. package/dist/schemas.js +30 -1
  89. package/dist/schemas.js.map +1 -1
  90. package/dist/server.js +38 -2
  91. package/dist/server.js.map +1 -1
  92. package/dist/tools/apply-migrations.d.ts +10 -0
  93. package/dist/tools/apply-migrations.d.ts.map +1 -1
  94. package/dist/tools/apply-migrations.js +10 -26
  95. package/dist/tools/apply-migrations.js.map +1 -1
  96. package/dist/tools/capture-learning.d.ts.map +1 -1
  97. package/dist/tools/capture-learning.js +14 -1
  98. package/dist/tools/capture-learning.js.map +1 -1
  99. package/dist/tools/get-skill-proposal-queue.d.ts +5 -0
  100. package/dist/tools/get-skill-proposal-queue.d.ts.map +1 -0
  101. package/dist/tools/get-skill-proposal-queue.js +21 -0
  102. package/dist/tools/get-skill-proposal-queue.js.map +1 -0
  103. package/dist/tools/get-skill-proposals.d.ts +4 -0
  104. package/dist/tools/get-skill-proposals.d.ts.map +1 -0
  105. package/dist/tools/get-skill-proposals.js +11 -0
  106. package/dist/tools/get-skill-proposals.js.map +1 -0
  107. package/dist/tools/prepare-phase-context.d.ts.map +1 -1
  108. package/dist/tools/prepare-phase-context.js +5 -0
  109. package/dist/tools/prepare-phase-context.js.map +1 -1
  110. package/dist/tools/publish-skill-proposal.d.ts +5 -0
  111. package/dist/tools/publish-skill-proposal.d.ts.map +1 -0
  112. package/dist/tools/publish-skill-proposal.js +57 -0
  113. package/dist/tools/publish-skill-proposal.js.map +1 -0
  114. package/dist/tools/record-skill-proposal-decision.d.ts +4 -0
  115. package/dist/tools/record-skill-proposal-decision.d.ts.map +1 -0
  116. package/dist/tools/record-skill-proposal-decision.js +22 -0
  117. package/dist/tools/record-skill-proposal-decision.js.map +1 -0
  118. package/dist/tools/record-skill-proposal-draft.d.ts +5 -0
  119. package/dist/tools/record-skill-proposal-draft.d.ts.map +1 -0
  120. package/dist/tools/record-skill-proposal-draft.js +65 -0
  121. package/dist/tools/record-skill-proposal-draft.js.map +1 -0
  122. package/dist/tools/sync-skill-proposal-candidates.d.ts +5 -0
  123. package/dist/tools/sync-skill-proposal-candidates.d.ts.map +1 -0
  124. package/dist/tools/sync-skill-proposal-candidates.js +20 -0
  125. package/dist/tools/sync-skill-proposal-candidates.js.map +1 -0
  126. package/dist/types.d.ts +41 -0
  127. package/dist/types.d.ts.map +1 -1
  128. package/dist/types.js +2 -0
  129. package/dist/types.js.map +1 -1
  130. package/migrations/009_skill_proposal_candidates.sql +124 -0
  131. package/migrations/010_skill_proposals.sql +36 -0
  132. package/migrations/README.md +6 -0
  133. package/package.json +5 -3
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: golang-gin
3
+ description: Gin HTTP web framework for building high-performance Go APIs
4
+ category: backend
5
+ version: "1.9+"
6
+ compatible_with:
7
+ - postgresql
8
+ - mongodb
9
+ - redis
10
+ - rest-api
11
+ - grpc
12
+ ---
13
+
14
+ # Go + Gin
15
+
16
+ ## Overview
17
+
18
+ Gin is a high-performance HTTP web framework for Go. It provides routing, middleware, JSON validation, and rendering with minimal overhead.
19
+
20
+ ## Project Structure
21
+
22
+ ```
23
+ cmd/
24
+ ├── server/
25
+ │ └── main.go # Entry point
26
+ internal/
27
+ ├── config/
28
+ │ └── config.go # Configuration loading
29
+ ├── handler/
30
+ │ ├── auth.go # Auth handlers
31
+ │ └── user.go # User handlers
32
+ ├── middleware/
33
+ │ ├── auth.go # JWT middleware
34
+ │ └── cors.go # CORS middleware
35
+ ├── model/
36
+ │ └── user.go # Domain models + DB structs
37
+ ├── repository/
38
+ │ └── user_repo.go # Database access
39
+ ├── service/
40
+ │ └── user_service.go # Business logic
41
+ └── router/
42
+ └── router.go # Route registration
43
+ ```
44
+
45
+ ## Core Patterns
46
+
47
+ ### Router Setup
48
+
49
+ ```go
50
+ func SetupRouter(userHandler *handler.UserHandler, authMW gin.HandlerFunc) *gin.Engine {
51
+ r := gin.Default()
52
+
53
+ r.Use(middleware.CORS())
54
+
55
+ api := r.Group("/api/v1")
56
+ {
57
+ auth := api.Group("/auth")
58
+ auth.POST("/login", userHandler.Login)
59
+ auth.POST("/register", userHandler.Register)
60
+
61
+ users := api.Group("/users")
62
+ users.Use(authMW)
63
+ users.GET("/:id", userHandler.GetByID)
64
+ users.PUT("/:id", userHandler.Update)
65
+ }
66
+
67
+ return r
68
+ }
69
+ ```
70
+
71
+ ### Handlers
72
+
73
+ ```go
74
+ type UserHandler struct {
75
+ service service.UserService
76
+ }
77
+
78
+ func (h *UserHandler) GetByID(c *gin.Context) {
79
+ id := c.Param("id")
80
+ user, err := h.service.GetByID(c.Request.Context(), id)
81
+ if err != nil {
82
+ c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
83
+ return
84
+ }
85
+ c.JSON(http.StatusOK, user)
86
+ }
87
+
88
+ // Request binding with validation
89
+ type CreateUserRequest struct {
90
+ Email string `json:"email" binding:"required,email"`
91
+ Password string `json:"password" binding:"required,min=8"`
92
+ Name string `json:"name" binding:"required,max=100"`
93
+ }
94
+
95
+ func (h *UserHandler) Register(c *gin.Context) {
96
+ var req CreateUserRequest
97
+ if err := c.ShouldBindJSON(&req); err != nil {
98
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
99
+ return
100
+ }
101
+ // ... create user
102
+ }
103
+ ```
104
+
105
+ ### Middleware
106
+
107
+ ```go
108
+ func AuthMiddleware(secret string) gin.HandlerFunc {
109
+ return func(c *gin.Context) {
110
+ token := c.GetHeader("Authorization")
111
+ if token == "" {
112
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing token"})
113
+ return
114
+ }
115
+ claims, err := validateJWT(strings.TrimPrefix(token, "Bearer "), secret)
116
+ if err != nil {
117
+ c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
118
+ return
119
+ }
120
+ c.Set("userID", claims.Subject)
121
+ c.Next()
122
+ }
123
+ }
124
+ ```
125
+
126
+ ## Best Practices
127
+
128
+ 1. **Use `internal/`** — prevents external packages from importing your business logic
129
+ 2. **Dependency injection** — pass dependencies via struct constructors, not globals
130
+ 3. **Context propagation** — always pass `c.Request.Context()` to service/repo layers
131
+ 4. **Graceful shutdown** — use `signal.NotifyContext` for clean shutdown
132
+ 5. **Error wrapping** — use `fmt.Errorf("...: %w", err)` for error chains
133
+ 6. **Structured logging** — use `slog` (Go 1.21+) or `zerolog`
134
+ 7. **Interface-based repos** — define interfaces in the consumer package, not the provider
135
+
136
+ ## Gotchas
137
+
138
+ - **Gin's `c.JSON` doesn't return** — always `return` after error responses
139
+ - **Binding validation tags** — `binding:"required"` only works with `ShouldBind*`
140
+ - **Goroutine safety** — don't share `gin.Context` across goroutines; copy needed values first
141
+ - **`c.Param` vs `c.Query`** — path params vs query strings are different methods
@@ -0,0 +1,277 @@
1
+ ---
2
+ name: nodejs-express
3
+ description: Node.js with Express.js framework expertise for building REST APIs, middleware patterns, and server-side applications
4
+ category: backend
5
+ version: "4.x"
6
+ compatible_with:
7
+ - postgresql
8
+ - prisma-orm
9
+ - supabase
10
+ - jest
11
+ - typescript
12
+ ---
13
+
14
+ # Node.js + Express Development
15
+
16
+ ## Overview
17
+
18
+ Express.js is a minimal, flexible Node.js web application framework providing robust features for building web and mobile applications.
19
+
20
+ ## Project Structure
21
+
22
+ ```
23
+ src/
24
+ ├── index.ts # Entry point
25
+ ├── app.ts # Express app setup
26
+ ├── routes/
27
+ │ ├── index.ts # Route aggregator
28
+ │ ├── auth.routes.ts # Auth endpoints
29
+ │ └── user.routes.ts # User endpoints
30
+ ├── controllers/
31
+ │ ├── auth.controller.ts
32
+ │ └── user.controller.ts
33
+ ├── services/
34
+ │ ├── auth.service.ts
35
+ │ └── user.service.ts
36
+ ├── middleware/
37
+ │ ├── auth.middleware.ts
38
+ │ ├── error.middleware.ts
39
+ │ └── validation.middleware.ts
40
+ ├── models/ # Database models
41
+ ├── utils/
42
+ │ └── asyncHandler.ts # Async error wrapper
43
+ └── types/
44
+ └── index.ts # TypeScript types
45
+ ```
46
+
47
+ ## Core Patterns
48
+
49
+ ### App Setup
50
+
51
+ ```typescript
52
+ // src/app.ts
53
+ import express from 'express';
54
+ import cors from 'cors';
55
+ import helmet from 'helmet';
56
+ import { errorHandler } from './middleware/error.middleware';
57
+ import routes from './routes';
58
+
59
+ const app = express();
60
+
61
+ // Security middleware
62
+ app.use(helmet());
63
+ app.use(cors());
64
+
65
+ // Body parsing
66
+ app.use(express.json());
67
+ app.use(express.urlencoded({ extended: true }));
68
+
69
+ // Routes
70
+ app.use('/api/v1', routes);
71
+
72
+ // Error handling (must be last)
73
+ app.use(errorHandler);
74
+
75
+ export default app;
76
+ ```
77
+
78
+ ### Async Handler Pattern
79
+
80
+ ```typescript
81
+ // src/utils/asyncHandler.ts
82
+ import { Request, Response, NextFunction } from 'express';
83
+
84
+ type AsyncFunction = (
85
+ req: Request,
86
+ res: Response,
87
+ next: NextFunction
88
+ ) => Promise<any>;
89
+
90
+ export const asyncHandler = (fn: AsyncFunction) => {
91
+ return (req: Request, res: Response, next: NextFunction) => {
92
+ Promise.resolve(fn(req, res, next)).catch(next);
93
+ };
94
+ };
95
+ ```
96
+
97
+ ### Controller Pattern
98
+
99
+ ```typescript
100
+ // src/controllers/user.controller.ts
101
+ import { Request, Response } from 'express';
102
+ import { asyncHandler } from '../utils/asyncHandler';
103
+ import * as userService from '../services/user.service';
104
+
105
+ export const getUsers = asyncHandler(async (req: Request, res: Response) => {
106
+ const users = await userService.findAll();
107
+ res.json({ success: true, data: users });
108
+ });
109
+
110
+ export const getUserById = asyncHandler(async (req: Request, res: Response) => {
111
+ const user = await userService.findById(req.params.id);
112
+ if (!user) {
113
+ res.status(404).json({ success: false, error: 'User not found' });
114
+ return;
115
+ }
116
+ res.json({ success: true, data: user });
117
+ });
118
+ ```
119
+
120
+ ### Route Definition
121
+
122
+ ```typescript
123
+ // src/routes/user.routes.ts
124
+ import { Router } from 'express';
125
+ import { getUsers, getUserById, createUser } from '../controllers/user.controller';
126
+ import { authenticate } from '../middleware/auth.middleware';
127
+ import { validate } from '../middleware/validation.middleware';
128
+ import { createUserSchema } from '../validators/user.validator';
129
+
130
+ const router = Router();
131
+
132
+ router.get('/', authenticate, getUsers);
133
+ router.get('/:id', authenticate, getUserById);
134
+ router.post('/', authenticate, validate(createUserSchema), createUser);
135
+
136
+ export default router;
137
+ ```
138
+
139
+ ### Error Handling Middleware
140
+
141
+ ```typescript
142
+ // src/middleware/error.middleware.ts
143
+ import { Request, Response, NextFunction } from 'express';
144
+
145
+ export class AppError extends Error {
146
+ constructor(
147
+ public statusCode: number,
148
+ public message: string,
149
+ public isOperational = true
150
+ ) {
151
+ super(message);
152
+ Object.setPrototypeOf(this, AppError.prototype);
153
+ }
154
+ }
155
+
156
+ export const errorHandler = (
157
+ err: Error,
158
+ req: Request,
159
+ res: Response,
160
+ next: NextFunction
161
+ ) => {
162
+ if (err instanceof AppError) {
163
+ return res.status(err.statusCode).json({
164
+ success: false,
165
+ error: err.message
166
+ });
167
+ }
168
+
169
+ console.error('Unexpected error:', err);
170
+ res.status(500).json({
171
+ success: false,
172
+ error: 'Internal server error'
173
+ });
174
+ };
175
+ ```
176
+
177
+ ### Auth Middleware
178
+
179
+ ```typescript
180
+ // src/middleware/auth.middleware.ts
181
+ import { Request, Response, NextFunction } from 'express';
182
+ import jwt from 'jsonwebtoken';
183
+ import { AppError } from './error.middleware';
184
+
185
+ export interface AuthRequest extends Request {
186
+ user?: { id: string; email: string };
187
+ }
188
+
189
+ export const authenticate = (
190
+ req: AuthRequest,
191
+ res: Response,
192
+ next: NextFunction
193
+ ) => {
194
+ const authHeader = req.headers.authorization;
195
+
196
+ if (!authHeader?.startsWith('Bearer ')) {
197
+ throw new AppError(401, 'No token provided');
198
+ }
199
+
200
+ const token = authHeader.split(' ')[1];
201
+
202
+ try {
203
+ const decoded = jwt.verify(token, process.env.JWT_SECRET!) as {
204
+ id: string;
205
+ email: string;
206
+ };
207
+ req.user = decoded;
208
+ next();
209
+ } catch {
210
+ throw new AppError(401, 'Invalid token');
211
+ }
212
+ };
213
+ ```
214
+
215
+ ## Best Practices
216
+
217
+ 1. **Always use asyncHandler** - Prevents unhandled promise rejections
218
+ 2. **Validate input** - Use Zod or Joi for request validation
219
+ 3. **Layer your code** - Routes → Controllers → Services → Models
220
+ 4. **Use TypeScript** - Type safety prevents runtime errors
221
+ 5. **Environment variables** - Never hardcode secrets
222
+ 6. **Error middleware last** - Must be registered after routes
223
+ 7. **Use HTTP status codes correctly** - 200, 201, 400, 401, 403, 404, 500
224
+
225
+ ## Common Response Format
226
+
227
+ ```typescript
228
+ // Success
229
+ { success: true, data: {...} }
230
+
231
+ // Error
232
+ { success: false, error: "Error message" }
233
+
234
+ // Paginated
235
+ {
236
+ success: true,
237
+ data: [...],
238
+ pagination: {
239
+ page: 1,
240
+ limit: 20,
241
+ total: 100,
242
+ totalPages: 5
243
+ }
244
+ }
245
+ ```
246
+
247
+ ## Gotchas & Pitfalls
248
+
249
+ - **Forgetting async error handling** - Always use asyncHandler or try-catch
250
+ - **Middleware order matters** - Auth before routes, error handler last
251
+ - **Not ending response** - Always call res.json(), res.send(), or next()
252
+ - **Memory leaks** - Clean up listeners, close DB connections on shutdown
253
+ - **CORS issues** - Configure cors() properly for your frontend domain
254
+
255
+ ## Integration Notes
256
+
257
+ ### With Prisma
258
+ ```typescript
259
+ import { PrismaClient } from '@prisma/client';
260
+ const prisma = new PrismaClient();
261
+
262
+ // In service
263
+ export const findAll = () => prisma.user.findMany();
264
+ ```
265
+
266
+ ### With Supabase
267
+ ```typescript
268
+ import { createClient } from '@supabase/supabase-js';
269
+ const supabase = createClient(SUPABASE_URL, SUPABASE_KEY);
270
+
271
+ // In service
272
+ export const findAll = async () => {
273
+ const { data, error } = await supabase.from('users').select('*');
274
+ if (error) throw new AppError(500, error.message);
275
+ return data;
276
+ };
277
+ ```
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: nodejs-fastify
3
+ description: Fastify framework for building high-performance Node.js APIs with schema-based validation
4
+ category: backend
5
+ version: "4.x"
6
+ compatible_with:
7
+ - postgresql
8
+ - prisma-orm
9
+ - mongodb
10
+ - redis
11
+ - rest-api
12
+ - typescript
13
+ ---
14
+
15
+ # Node.js + Fastify
16
+
17
+ ## Overview
18
+
19
+ Fastify is a high-performance Node.js web framework focused on developer experience and low overhead. It uses JSON Schema for request/response validation and serialization.
20
+
21
+ ## Project Structure
22
+
23
+ ```
24
+ src/
25
+ ├── app.ts # Fastify instance + plugin registration
26
+ ├── server.ts # Entry point (start server)
27
+ ├── plugins/
28
+ │ ├── auth.ts # Auth decorator/plugin
29
+ │ └── database.ts # DB connection plugin
30
+ ├── routes/
31
+ │ ├── auth/
32
+ │ │ ├── index.ts # Route registration
33
+ │ │ └── schema.ts # JSON schemas
34
+ │ └── users/
35
+ │ ├── index.ts
36
+ │ └── schema.ts
37
+ ├── services/
38
+ │ └── user.service.ts # Business logic
39
+ ├── types/
40
+ │ └── index.ts # TypeScript types
41
+ └── tests/
42
+ └── routes/
43
+ └── auth.test.ts
44
+ ```
45
+
46
+ ## Core Patterns
47
+
48
+ ### App Setup
49
+
50
+ ```typescript
51
+ import Fastify from 'fastify';
52
+
53
+ const app = Fastify({
54
+ logger: true,
55
+ ajv: { customOptions: { removeAdditional: 'all' } },
56
+ });
57
+
58
+ // Register plugins
59
+ await app.register(import('./plugins/database'));
60
+ await app.register(import('./plugins/auth'));
61
+
62
+ // Register routes
63
+ await app.register(import('./routes/auth'), { prefix: '/auth' });
64
+ await app.register(import('./routes/users'), { prefix: '/users' });
65
+
66
+ export default app;
67
+ ```
68
+
69
+ ### Routes with Schema Validation
70
+
71
+ ```typescript
72
+ import { FastifyPluginAsync } from 'fastify';
73
+
74
+ const userRoutes: FastifyPluginAsync = async (fastify) => {
75
+ fastify.get('/:id', {
76
+ schema: {
77
+ params: { type: 'object', properties: { id: { type: 'string', format: 'uuid' } }, required: ['id'] },
78
+ response: {
79
+ 200: {
80
+ type: 'object',
81
+ properties: {
82
+ id: { type: 'string' },
83
+ email: { type: 'string' },
84
+ name: { type: 'string' },
85
+ },
86
+ },
87
+ },
88
+ },
89
+ preHandler: [fastify.authenticate],
90
+ handler: async (request, reply) => {
91
+ const { id } = request.params as { id: string };
92
+ const user = await fastify.userService.getById(id);
93
+ if (!user) return reply.code(404).send({ error: 'Not found' });
94
+ return user;
95
+ },
96
+ });
97
+ };
98
+
99
+ export default userRoutes;
100
+ ```
101
+
102
+ ### Plugins (Decorators)
103
+
104
+ ```typescript
105
+ import fp from 'fastify-plugin';
106
+
107
+ export default fp(async (fastify) => {
108
+ const db = await connectToDatabase(fastify.config.DATABASE_URL);
109
+
110
+ fastify.decorate('db', db);
111
+ fastify.addHook('onClose', async () => { await db.close(); });
112
+ });
113
+
114
+ // Type augmentation
115
+ declare module 'fastify' {
116
+ interface FastifyInstance {
117
+ db: Database;
118
+ }
119
+ }
120
+ ```
121
+
122
+ ### Error Handling
123
+
124
+ ```typescript
125
+ app.setErrorHandler((error, request, reply) => {
126
+ request.log.error(error);
127
+
128
+ if (error.validation) {
129
+ return reply.code(400).send({ error: 'Validation failed', details: error.validation });
130
+ }
131
+
132
+ reply.code(error.statusCode ?? 500).send({
133
+ error: error.message || 'Internal Server Error',
134
+ });
135
+ });
136
+ ```
137
+
138
+ ## Best Practices
139
+
140
+ 1. **Schema-first** — define JSON Schema for all request/response; Fastify uses it for validation AND serialization (faster than manual serialization)
141
+ 2. **Encapsulation** — use plugins for encapsulated contexts; `fastify-plugin` for shared decorators
142
+ 3. **Type augmentation** — extend `FastifyInstance`/`FastifyRequest` for decorators
143
+ 4. **Autoload** — use `@fastify/autoload` to auto-register routes and plugins
144
+ 5. **Testing** — use `app.inject()` for integration tests (no real HTTP needed)
145
+ 6. **Hooks** — prefer `onRequest`/`preHandler` hooks over middleware for auth
146
+
147
+ ## Gotchas
148
+
149
+ - **Plugin encapsulation** — decorators are scoped to the plugin unless wrapped with `fastify-plugin`
150
+ - **Schema serialization** — response schemas strip undeclared properties (security feature, but surprising)
151
+ - **Async/await** — always return or `await`; unhandled promise rejections crash the server
152
+ - **Decorator timing** — decorators must be registered before routes that use them
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: python-django
3
+ description: Django web framework patterns for building full-stack Python applications with batteries included
4
+ category: backend
5
+ version: "5.x"
6
+ compatible_with:
7
+ - postgresql
8
+ - rest-api
9
+ ---
10
+
11
+ # Python Django
12
+
13
+ ## Overview
14
+
15
+ Django is a high-level Python web framework that follows the "batteries included" philosophy. It provides ORM, admin, auth, forms, and templating out of the box.
16
+
17
+ ## Project Structure
18
+
19
+ ```
20
+ project/
21
+ ├── manage.py
22
+ ├── config/
23
+ │ ├── settings/
24
+ │ │ ├── base.py # Shared settings
25
+ │ │ ├── development.py # Dev overrides
26
+ │ │ └── production.py # Prod overrides
27
+ │ ├── urls.py # Root URL conf
28
+ │ └── wsgi.py
29
+ ├── apps/
30
+ │ └── users/
31
+ │ ├── models.py # Database models
32
+ │ ├── views.py # View logic
33
+ │ ├── serializers.py # DRF serializers (if API)
34
+ │ ├── urls.py # App URL routes
35
+ │ ├── admin.py # Admin config
36
+ │ ├── services.py # Business logic
37
+ │ ├── tests/
38
+ │ │ ├── test_models.py
39
+ │ │ └── test_views.py
40
+ │ └── migrations/
41
+ └── requirements/
42
+ ├── base.txt
43
+ └── dev.txt
44
+ ```
45
+
46
+ ## Core Patterns
47
+
48
+ ### Models
49
+
50
+ ```python
51
+ from django.db import models
52
+ from django.contrib.auth.models import AbstractUser
53
+
54
+ class User(AbstractUser):
55
+ email = models.EmailField(unique=True)
56
+ bio = models.TextField(blank=True, default="")
57
+
58
+ USERNAME_FIELD = "email"
59
+ REQUIRED_FIELDS = ["username"]
60
+
61
+ class Meta:
62
+ ordering = ["-date_joined"]
63
+
64
+ def __str__(self):
65
+ return self.email
66
+ ```
67
+
68
+ ### Views (DRF)
69
+
70
+ ```python
71
+ from rest_framework import viewsets, permissions, status
72
+ from rest_framework.decorators import action
73
+ from rest_framework.response import Response
74
+
75
+ class UserViewSet(viewsets.ModelViewSet):
76
+ queryset = User.objects.all()
77
+ serializer_class = UserSerializer
78
+ permission_classes = [permissions.IsAuthenticated]
79
+
80
+ def get_queryset(self):
81
+ return self.queryset.filter(is_active=True)
82
+
83
+ @action(detail=False, methods=["get"])
84
+ def me(self, request):
85
+ serializer = self.get_serializer(request.user)
86
+ return Response(serializer.data)
87
+ ```
88
+
89
+ ### Services Layer
90
+
91
+ ```python
92
+ # apps/users/services.py — keep business logic out of views
93
+ class UserService:
94
+ @staticmethod
95
+ def create_user(email: str, password: str, **kwargs) -> User:
96
+ user = User.objects.create_user(email=email, password=password, **kwargs)
97
+ send_welcome_email.delay(user.id) # Celery task
98
+ return user
99
+ ```
100
+
101
+ ### Querysets
102
+
103
+ ```python
104
+ # Avoid N+1 queries
105
+ users = User.objects.select_related("profile").prefetch_related("groups").filter(is_active=True)
106
+
107
+ # Use F() and Q() for complex queries
108
+ from django.db.models import F, Q
109
+ Product.objects.filter(Q(stock__gt=0) | Q(preorder=True)).order_by(F("price").desc())
110
+ ```
111
+
112
+ ## Best Practices
113
+
114
+ 1. **Fat models, thin views** — or better: fat services, thin everything else
115
+ 2. **Custom User model** — always define one from the start (`AbstractUser`)
116
+ 3. **select_related / prefetch_related** — prevent N+1 queries
117
+ 4. **Migrations** — never edit auto-generated migrations; create new ones
118
+ 5. **Settings split** — separate base/dev/prod settings files
119
+ 6. **Signals sparingly** — prefer explicit service calls over implicit signals
120
+ 7. **Django REST Framework** — use for API projects; serializers for validation
121
+
122
+ ## Gotchas
123
+
124
+ - **Circular imports** — use string references in ForeignKey (`"app.Model"`)
125
+ - **Migration conflicts** — in team settings, use `--merge` to resolve
126
+ - **QuerySet laziness** — querysets aren't evaluated until iterated; chain freely
127
+ - **SECRET_KEY exposure** — never commit to VCS; use environment variables
128
+ - **Timezone handling** — always use `USE_TZ = True` and `django.utils.timezone`