claudient 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.
Files changed (283) hide show
  1. package/.claude-plugin/plugin.json +42 -0
  2. package/CONTEXT.md +58 -0
  3. package/README.md +165 -0
  4. package/agents/build-resolvers/de/python-resolver.md +64 -0
  5. package/agents/build-resolvers/de/typescript-resolver.md +65 -0
  6. package/agents/build-resolvers/es/python-resolver.md +64 -0
  7. package/agents/build-resolvers/es/typescript-resolver.md +65 -0
  8. package/agents/build-resolvers/fr/python-resolver.md +64 -0
  9. package/agents/build-resolvers/fr/typescript-resolver.md +65 -0
  10. package/agents/build-resolvers/nl/python-resolver.md +64 -0
  11. package/agents/build-resolvers/nl/typescript-resolver.md +65 -0
  12. package/agents/build-resolvers/python-resolver.md +62 -0
  13. package/agents/build-resolvers/typescript-resolver.md +63 -0
  14. package/agents/core/architect.md +64 -0
  15. package/agents/core/code-reviewer.md +78 -0
  16. package/agents/core/de/architect.md +66 -0
  17. package/agents/core/de/code-reviewer.md +80 -0
  18. package/agents/core/de/planner.md +63 -0
  19. package/agents/core/de/security-reviewer.md +93 -0
  20. package/agents/core/es/architect.md +66 -0
  21. package/agents/core/es/code-reviewer.md +80 -0
  22. package/agents/core/es/planner.md +63 -0
  23. package/agents/core/es/security-reviewer.md +93 -0
  24. package/agents/core/fr/architect.md +66 -0
  25. package/agents/core/fr/code-reviewer.md +80 -0
  26. package/agents/core/fr/planner.md +63 -0
  27. package/agents/core/fr/security-reviewer.md +93 -0
  28. package/agents/core/nl/architect.md +66 -0
  29. package/agents/core/nl/code-reviewer.md +80 -0
  30. package/agents/core/nl/planner.md +63 -0
  31. package/agents/core/nl/security-reviewer.md +93 -0
  32. package/agents/core/planner.md +61 -0
  33. package/agents/core/security-reviewer.md +91 -0
  34. package/guides/agent-orchestration.md +231 -0
  35. package/guides/de/agent-orchestration.md +174 -0
  36. package/guides/de/getting-started.md +164 -0
  37. package/guides/de/hooks-cookbook.md +160 -0
  38. package/guides/de/memory-management.md +153 -0
  39. package/guides/de/security.md +180 -0
  40. package/guides/de/skill-authoring.md +214 -0
  41. package/guides/de/token-optimization.md +156 -0
  42. package/guides/es/agent-orchestration.md +174 -0
  43. package/guides/es/getting-started.md +164 -0
  44. package/guides/es/hooks-cookbook.md +160 -0
  45. package/guides/es/memory-management.md +153 -0
  46. package/guides/es/security.md +180 -0
  47. package/guides/es/skill-authoring.md +214 -0
  48. package/guides/es/token-optimization.md +156 -0
  49. package/guides/fr/agent-orchestration.md +174 -0
  50. package/guides/fr/getting-started.md +164 -0
  51. package/guides/fr/hooks-cookbook.md +227 -0
  52. package/guides/fr/memory-management.md +169 -0
  53. package/guides/fr/security.md +180 -0
  54. package/guides/fr/skill-authoring.md +214 -0
  55. package/guides/fr/token-optimization.md +158 -0
  56. package/guides/getting-started.md +164 -0
  57. package/guides/hooks-cookbook.md +423 -0
  58. package/guides/memory-management.md +192 -0
  59. package/guides/nl/agent-orchestration.md +174 -0
  60. package/guides/nl/getting-started.md +164 -0
  61. package/guides/nl/hooks-cookbook.md +160 -0
  62. package/guides/nl/memory-management.md +153 -0
  63. package/guides/nl/security.md +180 -0
  64. package/guides/nl/skill-authoring.md +214 -0
  65. package/guides/nl/token-optimization.md +156 -0
  66. package/guides/security.md +229 -0
  67. package/guides/skill-authoring.md +226 -0
  68. package/guides/token-optimization.md +169 -0
  69. package/hooks/lifecycle/cost-tracker.md +49 -0
  70. package/hooks/lifecycle/cost-tracker.sh +59 -0
  71. package/hooks/lifecycle/pre-compact-save.md +56 -0
  72. package/hooks/lifecycle/pre-compact-save.sh +37 -0
  73. package/hooks/lifecycle/session-start.md +50 -0
  74. package/hooks/lifecycle/session-start.sh +47 -0
  75. package/hooks/post-tool-use/audit-log.md +53 -0
  76. package/hooks/post-tool-use/audit-log.sh +53 -0
  77. package/hooks/post-tool-use/prettier.md +53 -0
  78. package/hooks/post-tool-use/prettier.sh +49 -0
  79. package/hooks/pre-tool-use/block-dangerous.md +48 -0
  80. package/hooks/pre-tool-use/block-dangerous.sh +76 -0
  81. package/hooks/pre-tool-use/git-push-confirm.md +46 -0
  82. package/hooks/pre-tool-use/git-push-confirm.sh +36 -0
  83. package/mcp/configs/github.json +11 -0
  84. package/mcp/configs/postgres.json +11 -0
  85. package/mcp/de/recommended-servers.md +170 -0
  86. package/mcp/es/recommended-servers.md +170 -0
  87. package/mcp/fr/recommended-servers.md +170 -0
  88. package/mcp/nl/recommended-servers.md +170 -0
  89. package/mcp/recommended-servers.md +168 -0
  90. package/package.json +45 -0
  91. package/prompts/project-starters/de/fastapi-project.md +62 -0
  92. package/prompts/project-starters/de/nextjs-project.md +82 -0
  93. package/prompts/project-starters/es/fastapi-project.md +62 -0
  94. package/prompts/project-starters/es/nextjs-project.md +82 -0
  95. package/prompts/project-starters/fastapi-project.md +60 -0
  96. package/prompts/project-starters/fr/fastapi-project.md +62 -0
  97. package/prompts/project-starters/fr/nextjs-project.md +82 -0
  98. package/prompts/project-starters/nextjs-project.md +80 -0
  99. package/prompts/project-starters/nl/fastapi-project.md +62 -0
  100. package/prompts/project-starters/nl/nextjs-project.md +82 -0
  101. package/prompts/system-prompts/ai-product.md +80 -0
  102. package/prompts/system-prompts/data-pipeline.md +76 -0
  103. package/prompts/system-prompts/de/ai-product.md +82 -0
  104. package/prompts/system-prompts/de/data-pipeline.md +78 -0
  105. package/prompts/system-prompts/de/saas-backend.md +71 -0
  106. package/prompts/system-prompts/es/ai-product.md +82 -0
  107. package/prompts/system-prompts/es/data-pipeline.md +78 -0
  108. package/prompts/system-prompts/es/saas-backend.md +71 -0
  109. package/prompts/system-prompts/fr/ai-product.md +82 -0
  110. package/prompts/system-prompts/fr/data-pipeline.md +78 -0
  111. package/prompts/system-prompts/fr/saas-backend.md +71 -0
  112. package/prompts/system-prompts/nl/ai-product.md +82 -0
  113. package/prompts/system-prompts/nl/data-pipeline.md +78 -0
  114. package/prompts/system-prompts/nl/saas-backend.md +71 -0
  115. package/prompts/system-prompts/saas-backend.md +69 -0
  116. package/prompts/task-specific/changelog.md +81 -0
  117. package/prompts/task-specific/de/changelog.md +83 -0
  118. package/prompts/task-specific/de/debugging.md +78 -0
  119. package/prompts/task-specific/de/pr-description.md +69 -0
  120. package/prompts/task-specific/debugging.md +76 -0
  121. package/prompts/task-specific/es/changelog.md +83 -0
  122. package/prompts/task-specific/es/debugging.md +78 -0
  123. package/prompts/task-specific/es/pr-description.md +69 -0
  124. package/prompts/task-specific/fr/changelog.md +83 -0
  125. package/prompts/task-specific/fr/debugging.md +78 -0
  126. package/prompts/task-specific/fr/pr-description.md +69 -0
  127. package/prompts/task-specific/nl/changelog.md +83 -0
  128. package/prompts/task-specific/nl/debugging.md +78 -0
  129. package/prompts/task-specific/nl/pr-description.md +69 -0
  130. package/prompts/task-specific/pr-description.md +67 -0
  131. package/rules/common/coding-style.md +45 -0
  132. package/rules/common/de/coding-style.md +47 -0
  133. package/rules/common/de/git.md +48 -0
  134. package/rules/common/de/performance.md +40 -0
  135. package/rules/common/de/security.md +45 -0
  136. package/rules/common/de/testing.md +45 -0
  137. package/rules/common/es/coding-style.md +47 -0
  138. package/rules/common/es/git.md +48 -0
  139. package/rules/common/es/performance.md +40 -0
  140. package/rules/common/es/security.md +45 -0
  141. package/rules/common/es/testing.md +45 -0
  142. package/rules/common/fr/coding-style.md +47 -0
  143. package/rules/common/fr/git.md +48 -0
  144. package/rules/common/fr/performance.md +40 -0
  145. package/rules/common/fr/security.md +45 -0
  146. package/rules/common/fr/testing.md +45 -0
  147. package/rules/common/git.md +46 -0
  148. package/rules/common/nl/coding-style.md +47 -0
  149. package/rules/common/nl/git.md +48 -0
  150. package/rules/common/nl/performance.md +40 -0
  151. package/rules/common/nl/security.md +45 -0
  152. package/rules/common/nl/testing.md +45 -0
  153. package/rules/common/performance.md +38 -0
  154. package/rules/common/security.md +43 -0
  155. package/rules/common/testing.md +43 -0
  156. package/rules/language-specific/de/go.md +48 -0
  157. package/rules/language-specific/de/python.md +38 -0
  158. package/rules/language-specific/de/typescript.md +51 -0
  159. package/rules/language-specific/es/go.md +48 -0
  160. package/rules/language-specific/es/python.md +38 -0
  161. package/rules/language-specific/es/typescript.md +51 -0
  162. package/rules/language-specific/fr/go.md +48 -0
  163. package/rules/language-specific/fr/python.md +38 -0
  164. package/rules/language-specific/fr/typescript.md +51 -0
  165. package/rules/language-specific/go.md +46 -0
  166. package/rules/language-specific/nl/go.md +48 -0
  167. package/rules/language-specific/nl/python.md +38 -0
  168. package/rules/language-specific/nl/typescript.md +51 -0
  169. package/rules/language-specific/python.md +36 -0
  170. package/rules/language-specific/typescript.md +49 -0
  171. package/scripts/cli.js +161 -0
  172. package/scripts/link-skills.sh +35 -0
  173. package/scripts/list-skills.sh +34 -0
  174. package/skills/ai-engineering/agent-construction.md +285 -0
  175. package/skills/ai-engineering/claude-api.md +248 -0
  176. package/skills/ai-engineering/de/agent-construction.md +287 -0
  177. package/skills/ai-engineering/de/claude-api.md +250 -0
  178. package/skills/ai-engineering/es/agent-construction.md +287 -0
  179. package/skills/ai-engineering/es/claude-api.md +250 -0
  180. package/skills/ai-engineering/fr/agent-construction.md +287 -0
  181. package/skills/ai-engineering/fr/claude-api.md +250 -0
  182. package/skills/ai-engineering/nl/agent-construction.md +287 -0
  183. package/skills/ai-engineering/nl/claude-api.md +250 -0
  184. package/skills/backend/dotnet/csharp.md +304 -0
  185. package/skills/backend/dotnet/de/csharp.md +306 -0
  186. package/skills/backend/dotnet/es/csharp.md +306 -0
  187. package/skills/backend/dotnet/fr/csharp.md +306 -0
  188. package/skills/backend/dotnet/nl/csharp.md +306 -0
  189. package/skills/backend/go/de/go.md +307 -0
  190. package/skills/backend/go/es/go.md +307 -0
  191. package/skills/backend/go/fr/go.md +307 -0
  192. package/skills/backend/go/go.md +305 -0
  193. package/skills/backend/go/nl/go.md +307 -0
  194. package/skills/backend/nodejs/de/nestjs.md +274 -0
  195. package/skills/backend/nodejs/de/nextjs.md +222 -0
  196. package/skills/backend/nodejs/es/nestjs.md +274 -0
  197. package/skills/backend/nodejs/es/nextjs.md +222 -0
  198. package/skills/backend/nodejs/fr/nestjs.md +274 -0
  199. package/skills/backend/nodejs/fr/nextjs.md +222 -0
  200. package/skills/backend/nodejs/nestjs.md +272 -0
  201. package/skills/backend/nodejs/nextjs.md +220 -0
  202. package/skills/backend/nodejs/nl/nestjs.md +274 -0
  203. package/skills/backend/nodejs/nl/nextjs.md +222 -0
  204. package/skills/backend/python/de/django.md +285 -0
  205. package/skills/backend/python/de/fastapi.md +244 -0
  206. package/skills/backend/python/django.md +283 -0
  207. package/skills/backend/python/es/django.md +285 -0
  208. package/skills/backend/python/es/fastapi.md +244 -0
  209. package/skills/backend/python/fastapi.md +242 -0
  210. package/skills/backend/python/fr/django.md +285 -0
  211. package/skills/backend/python/fr/fastapi.md +244 -0
  212. package/skills/backend/python/nl/django.md +285 -0
  213. package/skills/backend/python/nl/fastapi.md +244 -0
  214. package/skills/data-ml/dbt-data-pipelines.md +155 -0
  215. package/skills/data-ml/de/dbt-data-pipelines.md +157 -0
  216. package/skills/data-ml/de/pandas-polars.md +147 -0
  217. package/skills/data-ml/de/pytorch-tensorflow.md +171 -0
  218. package/skills/data-ml/es/dbt-data-pipelines.md +157 -0
  219. package/skills/data-ml/es/pandas-polars.md +147 -0
  220. package/skills/data-ml/es/pytorch-tensorflow.md +171 -0
  221. package/skills/data-ml/fr/dbt-data-pipelines.md +157 -0
  222. package/skills/data-ml/fr/pandas-polars.md +147 -0
  223. package/skills/data-ml/fr/pytorch-tensorflow.md +171 -0
  224. package/skills/data-ml/nl/dbt-data-pipelines.md +157 -0
  225. package/skills/data-ml/nl/pandas-polars.md +147 -0
  226. package/skills/data-ml/nl/pytorch-tensorflow.md +171 -0
  227. package/skills/data-ml/pandas-polars.md +145 -0
  228. package/skills/data-ml/pytorch-tensorflow.md +169 -0
  229. package/skills/database/de/graphql.md +181 -0
  230. package/skills/database/es/graphql.md +181 -0
  231. package/skills/database/fr/graphql.md +181 -0
  232. package/skills/database/graphql.md +179 -0
  233. package/skills/database/nl/graphql.md +181 -0
  234. package/skills/devops-infra/de/docker.md +133 -0
  235. package/skills/devops-infra/de/github-actions.md +179 -0
  236. package/skills/devops-infra/de/kubernetes.md +129 -0
  237. package/skills/devops-infra/de/terraform.md +130 -0
  238. package/skills/devops-infra/docker.md +131 -0
  239. package/skills/devops-infra/es/docker.md +133 -0
  240. package/skills/devops-infra/es/github-actions.md +179 -0
  241. package/skills/devops-infra/es/kubernetes.md +129 -0
  242. package/skills/devops-infra/es/terraform.md +130 -0
  243. package/skills/devops-infra/fr/docker.md +133 -0
  244. package/skills/devops-infra/fr/github-actions.md +179 -0
  245. package/skills/devops-infra/fr/kubernetes.md +129 -0
  246. package/skills/devops-infra/fr/terraform.md +130 -0
  247. package/skills/devops-infra/github-actions.md +177 -0
  248. package/skills/devops-infra/kubernetes.md +127 -0
  249. package/skills/devops-infra/nl/docker.md +133 -0
  250. package/skills/devops-infra/nl/github-actions.md +179 -0
  251. package/skills/devops-infra/nl/kubernetes.md +129 -0
  252. package/skills/devops-infra/nl/terraform.md +130 -0
  253. package/skills/devops-infra/terraform.md +128 -0
  254. package/skills/finance-payments/de/stripe.md +187 -0
  255. package/skills/finance-payments/es/stripe.md +187 -0
  256. package/skills/finance-payments/fr/stripe.md +187 -0
  257. package/skills/finance-payments/nl/stripe.md +187 -0
  258. package/skills/finance-payments/stripe.md +185 -0
  259. package/workflows/code-review.md +151 -0
  260. package/workflows/de/code-review.md +153 -0
  261. package/workflows/de/debugging-session.md +146 -0
  262. package/workflows/de/feature-development.md +155 -0
  263. package/workflows/de/new-project-bootstrap.md +175 -0
  264. package/workflows/de/refactor-safely.md +150 -0
  265. package/workflows/debugging-session.md +144 -0
  266. package/workflows/es/code-review.md +153 -0
  267. package/workflows/es/debugging-session.md +146 -0
  268. package/workflows/es/feature-development.md +155 -0
  269. package/workflows/es/new-project-bootstrap.md +175 -0
  270. package/workflows/es/refactor-safely.md +150 -0
  271. package/workflows/feature-development.md +153 -0
  272. package/workflows/fr/code-review.md +153 -0
  273. package/workflows/fr/debugging-session.md +146 -0
  274. package/workflows/fr/feature-development.md +155 -0
  275. package/workflows/fr/new-project-bootstrap.md +175 -0
  276. package/workflows/fr/refactor-safely.md +150 -0
  277. package/workflows/new-project-bootstrap.md +173 -0
  278. package/workflows/nl/code-review.md +153 -0
  279. package/workflows/nl/debugging-session.md +146 -0
  280. package/workflows/nl/feature-development.md +155 -0
  281. package/workflows/nl/new-project-bootstrap.md +175 -0
  282. package/workflows/nl/refactor-safely.md +150 -0
  283. package/workflows/refactor-safely.md +148 -0
@@ -0,0 +1,242 @@
1
+ # FastAPI Skill
2
+
3
+ ## When to activate
4
+ - Building a Python REST or async API with FastAPI
5
+ - Defining Pydantic request/response models
6
+ - Setting up dependency injection with `Depends`
7
+ - Writing async route handlers with SQLAlchemy or async DB drivers
8
+ - Adding middleware (CORS, auth, logging, rate limiting)
9
+ - Configuring background tasks or Celery workers
10
+ - Customizing OpenAPI docs (tags, descriptions, response schemas)
11
+ - Writing integration tests with `TestClient` or `AsyncClient`
12
+ - Structuring a multi-module FastAPI project
13
+
14
+ ## When NOT to use
15
+ - Django/DRF projects — use the Django skill
16
+ - Synchronous-only codebases where async overhead is not justified
17
+ - Simple scripts that don't need HTTP — use plain Python
18
+ - gRPC or GraphQL APIs — different transport and schema layer
19
+
20
+ ## Instructions
21
+
22
+ ### Project structure
23
+ ```
24
+ app/
25
+ ├── main.py # FastAPI app factory
26
+ ├── core/
27
+ │ ├── config.py # Settings via pydantic-settings
28
+ │ └── security.py # JWT, hashing utilities
29
+ ├── api/
30
+ │ ├── deps.py # Shared Depends() functions
31
+ │ └── v1/
32
+ │ ├── router.py # APIRouter aggregator
33
+ │ └── endpoints/
34
+ │ ├── users.py
35
+ │ └── items.py
36
+ ├── models/ # SQLAlchemy ORM models
37
+ ├── schemas/ # Pydantic request/response schemas
38
+ ├── crud/ # DB operation functions (not ORM, not HTTP)
39
+ └── db/
40
+ ├── session.py # AsyncSession factory
41
+ └── base.py # Declarative base import
42
+ ```
43
+
44
+ ### App factory
45
+ ```python
46
+ # main.py
47
+ from fastapi import FastAPI
48
+ from app.api.v1.router import api_router
49
+ from app.core.config import settings
50
+
51
+ def create_app() -> FastAPI:
52
+ app = FastAPI(
53
+ title=settings.PROJECT_NAME,
54
+ openapi_url=f"{settings.API_V1_STR}/openapi.json",
55
+ docs_url="/docs" if settings.ENVIRONMENT != "production" else None,
56
+ )
57
+ app.include_router(api_router, prefix=settings.API_V1_STR)
58
+ return app
59
+
60
+ app = create_app()
61
+ ```
62
+
63
+ ### Settings with pydantic-settings
64
+ ```python
65
+ # core/config.py
66
+ from pydantic_settings import BaseSettings
67
+
68
+ class Settings(BaseSettings):
69
+ PROJECT_NAME: str = "MyAPI"
70
+ API_V1_STR: str = "/api/v1"
71
+ DATABASE_URL: str
72
+ SECRET_KEY: str
73
+ ENVIRONMENT: str = "development"
74
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
75
+
76
+ class Config:
77
+ env_file = ".env"
78
+ case_sensitive = True
79
+
80
+ settings = Settings()
81
+ ```
82
+
83
+ ### Async SQLAlchemy session dependency
84
+ ```python
85
+ # db/session.py
86
+ from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
87
+
88
+ engine = create_async_engine(settings.DATABASE_URL, echo=False)
89
+ AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
90
+
91
+ # api/deps.py
92
+ async def get_db() -> AsyncIterator[AsyncSession]:
93
+ async with AsyncSessionLocal() as session:
94
+ try:
95
+ yield session
96
+ await session.commit()
97
+ except Exception:
98
+ await session.rollback()
99
+ raise
100
+ ```
101
+
102
+ ### Route handlers
103
+ ```python
104
+ # api/v1/endpoints/users.py
105
+ from fastapi import APIRouter, Depends, HTTPException, status
106
+ from sqlalchemy.ext.asyncio import AsyncSession
107
+ from app.api.deps import get_db, get_current_user
108
+ from app.crud import user as crud_user
109
+ from app.schemas.user import UserCreate, UserResponse
110
+
111
+ router = APIRouter(prefix="/users", tags=["users"])
112
+
113
+ @router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
114
+ async def create_user(
115
+ payload: UserCreate,
116
+ db: AsyncSession = Depends(get_db),
117
+ ) -> UserResponse:
118
+ if await crud_user.get_by_email(db, email=payload.email):
119
+ raise HTTPException(status_code=400, detail="Email already registered")
120
+ return await crud_user.create(db, obj_in=payload)
121
+ ```
122
+
123
+ ### Dependency injection for auth
124
+ ```python
125
+ # api/deps.py
126
+ from fastapi import Depends, HTTPException, status
127
+ from fastapi.security import OAuth2PasswordBearer
128
+ from jose import JWTError, jwt
129
+
130
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
131
+
132
+ async def get_current_user(
133
+ token: str = Depends(oauth2_scheme),
134
+ db: AsyncSession = Depends(get_db),
135
+ ) -> User:
136
+ try:
137
+ payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
138
+ user_id: str = payload.get("sub")
139
+ if user_id is None:
140
+ raise credentials_exception
141
+ except JWTError:
142
+ raise HTTPException(status_code=401, detail="Invalid credentials")
143
+ user = await crud_user.get(db, id=user_id)
144
+ if user is None:
145
+ raise HTTPException(status_code=404, detail="User not found")
146
+ return user
147
+ ```
148
+
149
+ ### Background tasks
150
+ ```python
151
+ # Use FastAPI's BackgroundTasks for lightweight fire-and-forget (no result needed)
152
+ @router.post("/send-email")
153
+ async def send_email_endpoint(
154
+ payload: EmailPayload,
155
+ background_tasks: BackgroundTasks,
156
+ ):
157
+ background_tasks.add_task(send_email, payload.to, payload.subject, payload.body)
158
+ return {"status": "queued"}
159
+
160
+ # Use Celery for: retries, result tracking, scheduling, cross-service tasks
161
+ ```
162
+
163
+ ### CORS middleware
164
+ ```python
165
+ from fastapi.middleware.cors import CORSMiddleware
166
+
167
+ app.add_middleware(
168
+ CORSMiddleware,
169
+ allow_origins=settings.ALLOWED_ORIGINS, # Never ["*"] in production
170
+ allow_credentials=True,
171
+ allow_methods=["*"],
172
+ allow_headers=["*"],
173
+ )
174
+ ```
175
+
176
+ ### Custom exception handlers
177
+ ```python
178
+ from fastapi.responses import JSONResponse
179
+
180
+ @app.exception_handler(ValueError)
181
+ async def value_error_handler(request: Request, exc: ValueError) -> JSONResponse:
182
+ return JSONResponse(status_code=422, content={"detail": str(exc)})
183
+ ```
184
+
185
+ ### Testing
186
+ ```python
187
+ # tests/conftest.py
188
+ import pytest
189
+ from httpx import AsyncClient, ASGITransport
190
+ from app.main import app
191
+
192
+ @pytest.fixture
193
+ async def client() -> AsyncIterator[AsyncClient]:
194
+ async with AsyncClient(
195
+ transport=ASGITransport(app=app), base_url="http://test"
196
+ ) as ac:
197
+ yield ac
198
+
199
+ # tests/test_users.py
200
+ @pytest.mark.asyncio
201
+ async def test_create_user(client: AsyncClient, db_session):
202
+ resp = await client.post("/api/v1/users/", json={"email": "a@b.com", "password": "secret"})
203
+ assert resp.status_code == 201
204
+ assert resp.json()["email"] == "a@b.com"
205
+ ```
206
+
207
+ ### Common Pydantic patterns
208
+ ```python
209
+ from pydantic import BaseModel, EmailStr, field_validator, model_validator
210
+
211
+ class UserCreate(BaseModel):
212
+ email: EmailStr
213
+ password: str
214
+
215
+ @field_validator("password")
216
+ @classmethod
217
+ def password_strength(cls, v: str) -> str:
218
+ if len(v) < 8:
219
+ raise ValueError("Password must be at least 8 characters")
220
+ return v
221
+
222
+ class UserResponse(BaseModel):
223
+ id: int
224
+ email: EmailStr
225
+
226
+ model_config = {"from_attributes": True} # replaces orm_mode = True
227
+ ```
228
+
229
+ ## Example
230
+
231
+ **User:** Build a FastAPI endpoint to create a blog post, authenticated with JWT, saving to PostgreSQL with SQLAlchemy async.
232
+
233
+ **Expected structure:**
234
+ - `schemas/post.py` — `PostCreate(BaseModel)`, `PostResponse(BaseModel)` with `from_attributes=True`
235
+ - `models/post.py` — `Post` ORM model with `id`, `title`, `body`, `author_id` (FK to User), `created_at`
236
+ - `crud/post.py` — `create(db, *, obj_in, author_id)` async function
237
+ - `api/v1/endpoints/posts.py` — `POST /posts/` with `Depends(get_current_user)` and `Depends(get_db)`
238
+ - `api/v1/router.py` — include posts router
239
+
240
+ ---
241
+
242
+ > **Work with us:** Claudient is backed by [Uitbreiden](https://uitbreiden.com/) — we build AI products and B2B solutions with developer communities. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,285 @@
1
+ > 🇫🇷 This is the French translation. [English version](../django.md).
2
+
3
+ # Compétence Django
4
+
5
+ ## Quand activer
6
+ - Construire un projet Django avec des modèles ORM, des migrations et des vues
7
+ - Configurer les sérialiseurs, viewsets et routers Django REST Framework (DRF)
8
+ - Rédiger des managers de modèles personnalisés ou des méthodes QuerySet
9
+ - Utiliser les signaux Django pour des effets secondaires découplés
10
+ - Configurer Celery pour les tâches async dans un projet Django
11
+ - Personnaliser l'admin Django
12
+ - Rédiger des tests avec `django.test.TestCase` ou `pytest-django`
13
+
14
+ ## Quand NE PAS utiliser
15
+ - APIs async en priorité — utiliser la compétence FastAPI à la place
16
+ - Microservices qui n'ont pas besoin de l'ORM ou de l'admin Django
17
+ - Scripts ou CLIs simples — Python simple ou Typer
18
+ - Si le projet utilise déjà FastAPI ou Flask
19
+
20
+ ## Instructions
21
+
22
+ ### Structure du projet
23
+ ```
24
+ project_name/
25
+ ├── manage.py
26
+ ├── config/
27
+ │ ├── settings/
28
+ │ │ ├── base.py
29
+ │ │ ├── development.py
30
+ │ │ └── production.py
31
+ │ ├── urls.py
32
+ │ └── wsgi.py
33
+ ├── apps/
34
+ │ └── users/
35
+ │ ├── models.py
36
+ │ ├── serializers.py
37
+ │ ├── views.py
38
+ │ ├── urls.py
39
+ │ ├── admin.py
40
+ │ ├── managers.py
41
+ │ └── tests/
42
+ └── requirements/
43
+ ├── base.txt
44
+ ├── development.txt
45
+ └── production.txt
46
+ ```
47
+
48
+ ### Séparation des paramètres
49
+ ```python
50
+ # config/settings/base.py
51
+ from pathlib import Path
52
+ BASE_DIR = Path(__file__).resolve().parent.parent.parent
53
+
54
+ INSTALLED_APPS = [
55
+ "django.contrib.admin",
56
+ "django.contrib.auth",
57
+ "django.contrib.contenttypes",
58
+ "rest_framework",
59
+ "apps.users",
60
+ ]
61
+
62
+ AUTH_USER_MODEL = "users.User" # Toujours définir un modèle utilisateur personnalisé dès le début
63
+
64
+ # config/settings/production.py
65
+ from .base import *
66
+ DEBUG = False
67
+ ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")
68
+ DATABASES = {"default": env.db("DATABASE_URL")}
69
+ ```
70
+
71
+ ### Modèle User personnalisé
72
+ ```python
73
+ # apps/users/models.py — à configurer avant la première migration, ne jamais changer ensuite
74
+ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
75
+ from django.db import models
76
+ from .managers import UserManager
77
+
78
+ class User(AbstractBaseUser, PermissionsMixin):
79
+ email = models.EmailField(unique=True)
80
+ is_staff = models.BooleanField(default=False)
81
+ is_active = models.BooleanField(default=True)
82
+ created_at = models.DateTimeField(auto_now_add=True)
83
+
84
+ USERNAME_FIELD = "email"
85
+ REQUIRED_FIELDS = []
86
+ objects = UserManager()
87
+ ```
88
+
89
+ ### Manager personnalisé
90
+ ```python
91
+ # apps/users/managers.py
92
+ from django.contrib.auth.base_user import BaseUserManager
93
+
94
+ class UserManager(BaseUserManager):
95
+ def create_user(self, email: str, password: str, **extra_fields):
96
+ if not email:
97
+ raise ValueError("Email is required")
98
+ email = self.normalize_email(email)
99
+ user = self.model(email=email, **extra_fields)
100
+ user.set_password(password)
101
+ user.save()
102
+ return user
103
+
104
+ def create_superuser(self, email: str, password: str, **extra_fields):
105
+ extra_fields.setdefault("is_staff", True)
106
+ extra_fields.setdefault("is_superuser", True)
107
+ return self.create_user(email, password, **extra_fields)
108
+
109
+ def active(self):
110
+ return self.get_queryset().filter(is_active=True)
111
+ ```
112
+
113
+ ### Sérialiseurs DRF
114
+ ```python
115
+ # apps/users/serializers.py
116
+ from rest_framework import serializers
117
+ from .models import User
118
+
119
+ class UserCreateSerializer(serializers.ModelSerializer):
120
+ password = serializers.CharField(write_only=True, min_length=8)
121
+
122
+ class Meta:
123
+ model = User
124
+ fields = ["id", "email", "password"]
125
+
126
+ def create(self, validated_data: dict) -> User:
127
+ return User.objects.create_user(**validated_data)
128
+
129
+ class UserSerializer(serializers.ModelSerializer):
130
+ class Meta:
131
+ model = User
132
+ fields = ["id", "email", "created_at"]
133
+ read_only_fields = ["id", "created_at"]
134
+ ```
135
+
136
+ ### ViewSets DRF
137
+ ```python
138
+ # apps/users/views.py
139
+ from rest_framework import viewsets, permissions, status
140
+ from rest_framework.decorators import action
141
+ from rest_framework.response import Response
142
+ from .models import User
143
+ from .serializers import UserSerializer, UserCreateSerializer
144
+
145
+ class UserViewSet(viewsets.ModelViewSet):
146
+ queryset = User.objects.active()
147
+ permission_classes = [permissions.IsAuthenticated]
148
+
149
+ def get_serializer_class(self):
150
+ if self.action == "create":
151
+ return UserCreateSerializer
152
+ return UserSerializer
153
+
154
+ def get_permissions(self):
155
+ if self.action == "create":
156
+ return [permissions.AllowAny()]
157
+ return super().get_permissions()
158
+
159
+ @action(detail=False, methods=["get"])
160
+ def me(self, request):
161
+ return Response(UserSerializer(request.user).data)
162
+ ```
163
+
164
+ ### Configuration du Router
165
+ ```python
166
+ # apps/users/urls.py
167
+ from rest_framework.routers import DefaultRouter
168
+ from .views import UserViewSet
169
+
170
+ router = DefaultRouter()
171
+ router.register("users", UserViewSet, basename="user")
172
+ urlpatterns = router.urls
173
+ ```
174
+
175
+ ### Signaux
176
+ ```python
177
+ # apps/users/signals.py — utiliser les signaux uniquement pour des effets secondaires vraiment découplés
178
+ from django.db.models.signals import post_save
179
+ from django.dispatch import receiver
180
+ from .models import User
181
+
182
+ @receiver(post_save, sender=User)
183
+ def send_welcome_email(sender, instance: User, created: bool, **kwargs):
184
+ if created:
185
+ send_email_task.delay(instance.email, "welcome")
186
+
187
+ # apps/users/apps.py
188
+ class UsersConfig(AppConfig):
189
+ name = "apps.users"
190
+ def ready(self):
191
+ import apps.users.signals # noqa: F401
192
+ ```
193
+
194
+ ### Celery
195
+ ```python
196
+ # config/celery.py
197
+ from celery import Celery
198
+ import os
199
+
200
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
201
+ app = Celery("project_name")
202
+ app.config_from_object("django.conf:settings", namespace="CELERY")
203
+ app.autodiscover_tasks()
204
+
205
+ # apps/users/tasks.py
206
+ from config.celery import app
207
+
208
+ @app.task(bind=True, max_retries=3)
209
+ def send_email_task(self, to_email: str, template: str):
210
+ try:
211
+ # envoyer l'email
212
+ pass
213
+ except Exception as exc:
214
+ raise self.retry(exc=exc, countdown=60)
215
+ ```
216
+
217
+ ### Personnalisation de l'admin
218
+ ```python
219
+ # apps/users/admin.py
220
+ from django.contrib import admin
221
+ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
222
+ from .models import User
223
+
224
+ @admin.register(User)
225
+ class UserAdmin(BaseUserAdmin):
226
+ list_display = ["email", "is_active", "is_staff", "created_at"]
227
+ list_filter = ["is_active", "is_staff"]
228
+ search_fields = ["email"]
229
+ ordering = ["-created_at"]
230
+ fieldsets = (
231
+ (None, {"fields": ("email", "password")}),
232
+ ("Permissions", {"fields": ("is_active", "is_staff", "is_superuser", "groups")}),
233
+ )
234
+ add_fieldsets = (
235
+ (None, {"fields": ("email", "password1", "password2")}),
236
+ )
237
+ ```
238
+
239
+ ### Optimisation des QuerySet
240
+ ```python
241
+ # Toujours select_related pour les champs FK, prefetch_related pour M2M/FK inverse
242
+ posts = Post.objects.select_related("author").prefetch_related("tags").filter(published=True)
243
+
244
+ # Utiliser only() ou defer() pour les grands modèles quand vous n'avez besoin que de champs spécifiques
245
+ emails = User.objects.filter(is_active=True).only("email")
246
+
247
+ # Utiliser values() pour les agrégations en lecture seule — évite la construction d'objets ORM
248
+ counts = Order.objects.values("status").annotate(count=Count("id"))
249
+ ```
250
+
251
+ ### Tests
252
+ ```python
253
+ # Style pytest-django
254
+ import pytest
255
+ from rest_framework.test import APIClient
256
+
257
+ @pytest.fixture
258
+ def api_client():
259
+ return APIClient()
260
+
261
+ @pytest.fixture
262
+ def authenticated_client(api_client, user):
263
+ api_client.force_authenticate(user=user)
264
+ return api_client
265
+
266
+ @pytest.mark.django_db
267
+ def test_create_user(api_client):
268
+ resp = api_client.post("/api/users/", {"email": "a@b.com", "password": "strongpass"})
269
+ assert resp.status_code == 201
270
+ assert resp.data["email"] == "a@b.com"
271
+ ```
272
+
273
+ ## Exemple
274
+
275
+ **Utilisateur :** Ajouter un modèle `Post` à un projet Django avec DRF, incluant des endpoints liste/création/récupération, des résultats paginés et un filtre par `published=True`.
276
+
277
+ **Sortie attendue :**
278
+ - `models.py` — `Post` avec `title`, `body`, `author` (FK vers User), `published`, `created_at`
279
+ - `serializers.py` — `PostSerializer` avec `author` en lecture seule (imbriqué), `title`/`body`/`published` modifiables
280
+ - `views.py` — `PostViewSet` avec `queryset` filtré à `published=True` pour les utilisateurs non authentifiés, permission `IsAuthenticatedOrReadOnly`, `PageNumberPagination`
281
+ - `urls.py` — router enregistré à `/api/posts/`
282
+
283
+ ---
284
+
285
+ > **Travaillez avec nous :** Claudient est soutenu par [Uitbreiden](https://uitbreiden.com/) — nous construisons des produits IA et des solutions B2B avec des communautés de développeurs. [uitbreiden.com](https://uitbreiden.com/)