@martinffx/atelier 2.0.0 → 3.0.1

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 (81) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +94 -253
  3. package/package.json +1 -1
  4. package/skills/{spec-orchestrator → atelier-orchestrator}/SKILL.md +3 -3
  5. package/skills/atelier-setup/SKILL.md +80 -0
  6. package/skills/code-review/references/reviewers.md +3 -3
  7. package/skills/code-review/references/rq.md +6 -6
  8. package/skills/spec-brainstorm/SKILL.md +5 -5
  9. package/skills/spec-implement/SKILL.md +2 -3
  10. package/skills/spec-plan/SKILL.md +21 -29
  11. package/skills/spec-plan/references/plan_template.md +77 -0
  12. package/skills/python-architecture/SKILL.md +0 -148
  13. package/skills/python-architecture/references/data-modeling.md +0 -558
  14. package/skills/python-architecture/references/ddd.md +0 -569
  15. package/skills/python-architecture/references/functional-core.md +0 -337
  16. package/skills/python-build-tools/SKILL.md +0 -153
  17. package/skills/python-build-tools/references/basedpyright.md +0 -321
  18. package/skills/python-build-tools/references/ruff.md +0 -225
  19. package/skills/python-build-tools/references/uv.md +0 -257
  20. package/skills/python-fastapi/SKILL.md +0 -184
  21. package/skills/python-fastapi/references/api-design.md +0 -563
  22. package/skills/python-fastapi/references/dependencies.md +0 -479
  23. package/skills/python-fastapi/references/middleware.md +0 -475
  24. package/skills/python-fastapi/references/validation.md +0 -497
  25. package/skills/python-modern-python/SKILL.md +0 -201
  26. package/skills/python-modern-python/references/async.md +0 -76
  27. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  28. package/skills/python-modern-python/references/typing.md +0 -96
  29. package/skills/python-monorepo/SKILL.md +0 -146
  30. package/skills/python-monorepo/references/docker.md +0 -515
  31. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  32. package/skills/python-monorepo/references/workspace-config.md +0 -341
  33. package/skills/python-sqlalchemy/SKILL.md +0 -119
  34. package/skills/python-sqlalchemy/references/async.md +0 -51
  35. package/skills/python-sqlalchemy/references/models.md +0 -67
  36. package/skills/python-sqlalchemy/references/queries.md +0 -57
  37. package/skills/python-temporal/SKILL.md +0 -128
  38. package/skills/python-temporal/references/patterns.md +0 -87
  39. package/skills/python-temporal/references/testing.md +0 -54
  40. package/skills/python-testing/SKILL.md +0 -161
  41. package/skills/python-testing/references/boundaries.md +0 -449
  42. package/skills/python-testing/references/mocking.md +0 -449
  43. package/skills/python-testing/references/pytest.md +0 -524
  44. package/skills/typescript-api-design/SKILL.md +0 -396
  45. package/skills/typescript-api-design/references/error-responses.md +0 -469
  46. package/skills/typescript-build-tools/SKILL.md +0 -447
  47. package/skills/typescript-build-tools/references/biome.md +0 -436
  48. package/skills/typescript-build-tools/references/bun.md +0 -432
  49. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  50. package/skills/typescript-build-tools/references/vitest.md +0 -518
  51. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  52. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  53. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  54. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  55. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  56. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  57. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  58. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  59. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  60. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  61. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  62. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  63. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  64. package/skills/typescript-effect-ts/SKILL.md +0 -341
  65. package/skills/typescript-effect-ts/references/core.md +0 -412
  66. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  67. package/skills/typescript-effect-ts/references/resources.md +0 -476
  68. package/skills/typescript-effect-ts/references/schema.md +0 -536
  69. package/skills/typescript-effect-ts/references/services.md +0 -461
  70. package/skills/typescript-fastify/SKILL.md +0 -405
  71. package/skills/typescript-fastify/references/plugins.md +0 -329
  72. package/skills/typescript-fastify/references/typeid.md +0 -315
  73. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  74. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  75. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  76. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  77. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  78. package/skills/typescript-testing/SKILL.md +0 -353
  79. package/skills/typescript-testing/references/mocking.md +0 -675
  80. package/skills/typescript-testing/references/msw.md +0 -852
  81. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
@@ -1,479 +0,0 @@
1
- # Dependency Injection in FastAPI
2
-
3
- FastAPI's dependency injection system manages shared resources, authentication, database sessions, and cross-cutting concerns.
4
-
5
- ## Basic Dependencies
6
-
7
- ### Function Dependencies
8
-
9
- ```python
10
- from fastapi import Depends
11
-
12
- def get_db():
13
- """Simple dependency"""
14
- db = Database()
15
- try:
16
- yield db
17
- finally:
18
- db.close()
19
-
20
- @app.get("/users")
21
- def list_users(db: Database = Depends(get_db)):
22
- """db injected automatically"""
23
- return db.query(User).all()
24
- ```
25
-
26
- ### Class Dependencies
27
-
28
- ```python
29
- class DatabaseSession:
30
- def __init__(self):
31
- self.db = Database()
32
-
33
- def __enter__(self):
34
- return self.db
35
-
36
- def __exit__(self, *args):
37
- self.db.close()
38
-
39
- @app.get("/users")
40
- def list_users(db: Database = Depends(DatabaseSession)):
41
- return db.query(User).all()
42
- ```
43
-
44
- ## Nested Dependencies
45
-
46
- Dependencies can depend on other dependencies:
47
-
48
- ```python
49
- def get_db():
50
- db = Database()
51
- try:
52
- yield db
53
- finally:
54
- db.close()
55
-
56
- def get_user_repo(db: Database = Depends(get_db)):
57
- """Depends on get_db"""
58
- return UserRepository(db)
59
-
60
- @app.get("/users")
61
- def list_users(repo: UserRepository = Depends(get_user_repo)):
62
- """repo injected with db already provided"""
63
- return repo.find_all()
64
- ```
65
-
66
- ## Authentication Dependencies
67
-
68
- ### Token Extraction
69
-
70
- ```python
71
- from fastapi import Depends, HTTPException, Header
72
-
73
- def get_token(authorization: str = Header()):
74
- """Extract token from header"""
75
- if not authorization.startswith("Bearer "):
76
- raise HTTPException(status_code=401, detail="Invalid authorization header")
77
- return authorization[7:] # Remove "Bearer " prefix
78
-
79
- @app.get("/me")
80
- def get_current_user_profile(token: str = Depends(get_token)):
81
- user = decode_token(token)
82
- return user
83
- ```
84
-
85
- ### Current User Dependency
86
-
87
- ```python
88
- from fastapi import Depends, HTTPException
89
- from fastapi.security import HTTPBearer
90
-
91
- security = HTTPBearer()
92
-
93
- def get_current_user(
94
- credentials: HTTPAuthorizationCredentials = Depends(security),
95
- db: Database = Depends(get_db),
96
- ) -> User:
97
- """Get authenticated user"""
98
- token = credentials.credentials
99
-
100
- # Decode token
101
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
102
- user_id = payload.get("user_id")
103
-
104
- if not user_id:
105
- raise HTTPException(status_code=401, detail="Invalid token")
106
-
107
- # Get user from database
108
- user = db.query(User).filter(User.id == user_id).first()
109
- if not user:
110
- raise HTTPException(status_code=401, detail="User not found")
111
-
112
- return user
113
-
114
- @app.get("/me")
115
- def get_profile(current_user: User = Depends(get_current_user)):
116
- """current_user injected"""
117
- return current_user
118
- ```
119
-
120
- ### Optional Authentication
121
-
122
- ```python
123
- from typing import Optional
124
-
125
- def get_current_user_optional(
126
- credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
127
- ) -> User | None:
128
- """Optional authentication"""
129
- if not credentials:
130
- return None
131
-
132
- try:
133
- return decode_and_get_user(credentials.credentials)
134
- except:
135
- return None
136
-
137
- @app.get("/posts")
138
- def list_posts(current_user: User | None = Depends(get_current_user_optional)):
139
- """Works with or without authentication"""
140
- if current_user:
141
- return get_posts_for_user(current_user)
142
- return get_public_posts()
143
- ```
144
-
145
- ## Permission Dependencies
146
-
147
- ```python
148
- from enum import Enum
149
-
150
- class Permission(Enum):
151
- READ = "read"
152
- WRITE = "write"
153
- ADMIN = "admin"
154
-
155
- def require_permission(permission: Permission):
156
- """Factory function returning dependency"""
157
- def check_permission(current_user: User = Depends(get_current_user)):
158
- if permission not in current_user.permissions:
159
- raise HTTPException(status_code=403, detail="Permission denied")
160
- return current_user
161
- return check_permission
162
-
163
- # Usage
164
- @app.post("/users")
165
- def create_user(
166
- user: CreateUserRequest,
167
- current_user: User = Depends(require_permission(Permission.ADMIN)),
168
- ):
169
- """Requires ADMIN permission"""
170
- ...
171
-
172
- @app.get("/users")
173
- def list_users(
174
- current_user: User = Depends(require_permission(Permission.READ)),
175
- ):
176
- """Requires READ permission"""
177
- ...
178
- ```
179
-
180
- ## Database Session Management
181
-
182
- ### SQLAlchemy Session
183
-
184
- ```python
185
- from sqlalchemy.orm import Session, sessionmaker
186
-
187
- SessionLocal = sessionmaker(bind=engine)
188
-
189
- def get_db() -> Session:
190
- """Database session dependency"""
191
- db = SessionLocal()
192
- try:
193
- yield db
194
- finally:
195
- db.close()
196
-
197
- @app.get("/users")
198
- def list_users(db: Session = Depends(get_db)):
199
- return db.query(UserModel).all()
200
- ```
201
-
202
- ### With Transaction Management
203
-
204
- ```python
205
- from contextlib import contextmanager
206
-
207
- @contextmanager
208
- def get_db_with_transaction():
209
- """Database session with automatic transaction"""
210
- db = SessionLocal()
211
- try:
212
- yield db
213
- db.commit()
214
- except Exception:
215
- db.rollback()
216
- raise
217
- finally:
218
- db.close()
219
-
220
- @app.post("/users")
221
- def create_user(
222
- user: CreateUserRequest,
223
- db: Session = Depends(get_db_with_transaction),
224
- ):
225
- """Transaction automatically committed or rolled back"""
226
- new_user = UserModel(**user.model_dump())
227
- db.add(new_user)
228
- # Commit happens automatically on success
229
- return new_user
230
- ```
231
-
232
- ## Dependency Classes
233
-
234
- Classes can be dependencies:
235
-
236
- ```python
237
- from fastapi import Depends, HTTPException
238
-
239
- class UserService:
240
- def __init__(self, db: Session = Depends(get_db)):
241
- self.db = db
242
- self.repo = UserRepository(db)
243
-
244
- def get_user(self, user_id: int) -> User:
245
- user = self.repo.find_by_id(user_id)
246
- if not user:
247
- raise HTTPException(status_code=404, detail="User not found")
248
- return user
249
-
250
- def create_user(self, data: CreateUserRequest) -> User:
251
- user = User.from_request(data)
252
- return self.repo.save(user)
253
-
254
- @app.get("/users/{user_id}")
255
- def get_user(
256
- user_id: int,
257
- service: UserService = Depends(),
258
- ):
259
- """UserService injected with db already provided"""
260
- return service.get_user(user_id)
261
- ```
262
-
263
- ## Global Dependencies
264
-
265
- Apply dependencies to all routes:
266
-
267
- ```python
268
- app = FastAPI(dependencies=[Depends(get_current_user)])
269
-
270
- # All routes require authentication
271
- @app.get("/users")
272
- def list_users():
273
- ...
274
-
275
- @app.get("/products")
276
- def list_products():
277
- ...
278
- ```
279
-
280
- ### Router-level Dependencies
281
-
282
- ```python
283
- router = APIRouter(
284
- prefix="/admin",
285
- dependencies=[Depends(require_permission(Permission.ADMIN))],
286
- )
287
-
288
- # All routes in this router require ADMIN permission
289
- @router.get("/users")
290
- def list_all_users():
291
- ...
292
-
293
- @router.delete("/users/{user_id}")
294
- def delete_user(user_id: int):
295
- ...
296
- ```
297
-
298
- ## Caching Dependencies
299
-
300
- Use `use_cache=False` to disable dependency caching:
301
-
302
- ```python
303
- def get_timestamp():
304
- """Called once per request by default"""
305
- return datetime.now()
306
-
307
- @app.get("/time")
308
- def get_time(
309
- ts1: datetime = Depends(get_timestamp),
310
- ts2: datetime = Depends(get_timestamp),
311
- ):
312
- # ts1 and ts2 are the same (cached)
313
- return {"ts1": ts1, "ts2": ts2}
314
-
315
- @app.get("/time-no-cache")
316
- def get_time_no_cache(
317
- ts1: datetime = Depends(get_timestamp, use_cache=False),
318
- ts2: datetime = Depends(get_timestamp, use_cache=False),
319
- ):
320
- # ts1 and ts2 are different (not cached)
321
- return {"ts1": ts1, "ts2": ts2}
322
- ```
323
-
324
- ## Dependency Override (Testing)
325
-
326
- Override dependencies in tests:
327
-
328
- ```python
329
- from fastapi.testclient import TestClient
330
-
331
- def get_db_override():
332
- """Test database"""
333
- return TestDatabase()
334
-
335
- app.dependency_overrides[get_db] = get_db_override
336
-
337
- client = TestClient(app)
338
-
339
- # Tests use TestDatabase instead of real database
340
- response = client.get("/users")
341
- ```
342
-
343
- ## Query and Path Parameters as Dependencies
344
-
345
- ```python
346
- from fastapi import Query, Path
347
-
348
- def pagination(
349
- page: int = Query(default=1, ge=1),
350
- page_size: int = Query(default=10, ge=1, le=100),
351
- ):
352
- """Pagination dependency"""
353
- return {"skip": (page - 1) * page_size, "limit": page_size}
354
-
355
- @app.get("/users")
356
- def list_users(
357
- pagination: dict = Depends(pagination),
358
- db: Session = Depends(get_db),
359
- ):
360
- return db.query(User).offset(pagination["skip"]).limit(pagination["limit"]).all()
361
- ```
362
-
363
- ## Header Dependencies
364
-
365
- ```python
366
- def verify_api_key(x_api_key: str = Header()):
367
- """Verify API key from header"""
368
- if x_api_key != VALID_API_KEY:
369
- raise HTTPException(status_code=401, detail="Invalid API key")
370
- return x_api_key
371
-
372
- @app.get("/protected")
373
- def protected_route(api_key: str = Depends(verify_api_key)):
374
- return {"message": "Access granted"}
375
- ```
376
-
377
- ## Cookie Dependencies
378
-
379
- ```python
380
- from fastapi import Cookie
381
-
382
- def get_session(session_id: str | None = Cookie(default=None)):
383
- """Get session from cookie"""
384
- if not session_id:
385
- raise HTTPException(status_code=401, detail="No session")
386
- session = get_session_from_cache(session_id)
387
- if not session:
388
- raise HTTPException(status_code=401, detail="Invalid session")
389
- return session
390
-
391
- @app.get("/dashboard")
392
- def dashboard(session: Session = Depends(get_session)):
393
- return {"user": session.user}
394
- ```
395
-
396
- ## Application State Dependencies
397
-
398
- ```python
399
- from fastapi import Request
400
-
401
- def get_redis(request: Request):
402
- """Access app state"""
403
- return request.app.state.redis
404
-
405
- def get_cache(request: Request):
406
- return request.app.state.cache
407
-
408
- @app.get("/cached")
409
- def get_cached_data(
410
- cache = Depends(get_cache),
411
- redis = Depends(get_redis),
412
- ):
413
- ...
414
- ```
415
-
416
- ## Advanced Patterns
417
-
418
- ### Factory Dependencies
419
-
420
- ```python
421
- from typing import Type
422
-
423
- def create_repository(model: Type):
424
- """Factory for creating repository dependencies"""
425
- def get_repository(db: Session = Depends(get_db)):
426
- return Repository(db, model)
427
- return get_repository
428
-
429
- # Create specific repository dependencies
430
- get_user_repo = create_repository(UserModel)
431
- get_product_repo = create_repository(ProductModel)
432
-
433
- @app.get("/users")
434
- def list_users(repo = Depends(get_user_repo)):
435
- return repo.find_all()
436
- ```
437
-
438
- ### Async Dependencies
439
-
440
- ```python
441
- async def get_async_db():
442
- """Async dependency"""
443
- async with AsyncDatabase() as db:
444
- yield db
445
-
446
- @app.get("/users")
447
- async def list_users(db: AsyncDatabase = Depends(get_async_db)):
448
- return await db.query(User).all()
449
- ```
450
-
451
- ## Best Practices
452
-
453
- 1. **Use dependencies for shared resources**: Database, cache, external services
454
- 2. **Nest dependencies**: Build complex dependencies from simple ones
455
- 3. **Class dependencies for services**: Encapsulate business logic
456
- 4. **Factory functions for permissions**: Reusable permission checks
457
- 5. **Override in tests**: Swap real dependencies with test doubles
458
- 6. **Type hints are required**: FastAPI needs types for injection
459
- 7. **Use `yield` for cleanup**: Ensure resources are released
460
-
461
- ## Summary
462
-
463
- **Dependency types:**
464
- - Function dependencies (with `yield` for cleanup)
465
- - Class dependencies (automatic instantiation)
466
- - Nested dependencies (compose from simpler ones)
467
-
468
- **Common use cases:**
469
- - Database sessions
470
- - Authentication/authorization
471
- - Pagination parameters
472
- - External service clients
473
- - Caching
474
-
475
- **Advanced features:**
476
- - Factory functions (reusable patterns)
477
- - Router/app-level dependencies (global)
478
- - Dependency overrides (testing)
479
- - Async dependencies