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,244 @@
1
+ > 🇩🇪 Dies ist die deutsche Übersetzung. [Englische Version](../fastapi.md).
2
+
3
+ # FastAPI Skill
4
+
5
+ ## Wann aktivieren
6
+ - Eine Python REST- oder asynchrone API mit FastAPI bauen
7
+ - Pydantic-Anfrage-/Antwortmodelle definieren
8
+ - Dependency Injection mit `Depends` einrichten
9
+ - Asynchrone Route-Handler mit SQLAlchemy oder asynchronen DB-Treibern schreiben
10
+ - Middleware hinzufügen (CORS, Auth, Logging, Rate Limiting)
11
+ - Hintergrundaufgaben oder Celery-Worker konfigurieren
12
+ - OpenAPI-Docs anpassen (Tags, Beschreibungen, Antwort-Schemas)
13
+ - Integrationstests mit `TestClient` oder `AsyncClient` schreiben
14
+ - Ein Multi-Modul-FastAPI-Projekt strukturieren
15
+
16
+ ## Wann NICHT verwenden
17
+ - Django/DRF-Projekte — Django Skill verwenden
18
+ - Nur-synchrone Codebasen, bei denen Async-Overhead nicht gerechtfertigt ist
19
+ - Einfache Skripte, die kein HTTP benötigen — einfaches Python verwenden
20
+ - gRPC- oder GraphQL-APIs — anderer Transport und Schema-Layer
21
+
22
+ ## Anweisungen
23
+
24
+ ### Projektstruktur
25
+ ```
26
+ app/
27
+ ├── main.py # FastAPI App-Factory
28
+ ├── core/
29
+ │ ├── config.py # Einstellungen über pydantic-settings
30
+ │ └── security.py # JWT, Hashing-Utilities
31
+ ├── api/
32
+ │ ├── deps.py # Gemeinsame Depends()-Funktionen
33
+ │ └── v1/
34
+ │ ├── router.py # APIRouter-Aggregator
35
+ │ └── endpoints/
36
+ │ ├── users.py
37
+ │ └── items.py
38
+ ├── models/ # SQLAlchemy ORM-Modelle
39
+ ├── schemas/ # Pydantic Anfrage-/Antwort-Schemas
40
+ ├── crud/ # DB-Operationsfunktionen (kein ORM, kein HTTP)
41
+ └── db/
42
+ ├── session.py # AsyncSession-Factory
43
+ └── base.py # Deklarative Basis-Import
44
+ ```
45
+
46
+ ### App-Factory
47
+ ```python
48
+ # main.py
49
+ from fastapi import FastAPI
50
+ from app.api.v1.router import api_router
51
+ from app.core.config import settings
52
+
53
+ def create_app() -> FastAPI:
54
+ app = FastAPI(
55
+ title=settings.PROJECT_NAME,
56
+ openapi_url=f"{settings.API_V1_STR}/openapi.json",
57
+ docs_url="/docs" if settings.ENVIRONMENT != "production" else None,
58
+ )
59
+ app.include_router(api_router, prefix=settings.API_V1_STR)
60
+ return app
61
+
62
+ app = create_app()
63
+ ```
64
+
65
+ ### Einstellungen mit pydantic-settings
66
+ ```python
67
+ # core/config.py
68
+ from pydantic_settings import BaseSettings
69
+
70
+ class Settings(BaseSettings):
71
+ PROJECT_NAME: str = "MyAPI"
72
+ API_V1_STR: str = "/api/v1"
73
+ DATABASE_URL: str
74
+ SECRET_KEY: str
75
+ ENVIRONMENT: str = "development"
76
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
77
+
78
+ class Config:
79
+ env_file = ".env"
80
+ case_sensitive = True
81
+
82
+ settings = Settings()
83
+ ```
84
+
85
+ ### Asynchrone SQLAlchemy-Session-Abhängigkeit
86
+ ```python
87
+ # db/session.py
88
+ from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
89
+
90
+ engine = create_async_engine(settings.DATABASE_URL, echo=False)
91
+ AsyncSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
92
+
93
+ # api/deps.py
94
+ async def get_db() -> AsyncIterator[AsyncSession]:
95
+ async with AsyncSessionLocal() as session:
96
+ try:
97
+ yield session
98
+ await session.commit()
99
+ except Exception:
100
+ await session.rollback()
101
+ raise
102
+ ```
103
+
104
+ ### Route-Handler
105
+ ```python
106
+ # api/v1/endpoints/users.py
107
+ from fastapi import APIRouter, Depends, HTTPException, status
108
+ from sqlalchemy.ext.asyncio import AsyncSession
109
+ from app.api.deps import get_db, get_current_user
110
+ from app.crud import user as crud_user
111
+ from app.schemas.user import UserCreate, UserResponse
112
+
113
+ router = APIRouter(prefix="/users", tags=["users"])
114
+
115
+ @router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
116
+ async def create_user(
117
+ payload: UserCreate,
118
+ db: AsyncSession = Depends(get_db),
119
+ ) -> UserResponse:
120
+ if await crud_user.get_by_email(db, email=payload.email):
121
+ raise HTTPException(status_code=400, detail="Email already registered")
122
+ return await crud_user.create(db, obj_in=payload)
123
+ ```
124
+
125
+ ### Dependency Injection für Auth
126
+ ```python
127
+ # api/deps.py
128
+ from fastapi import Depends, HTTPException, status
129
+ from fastapi.security import OAuth2PasswordBearer
130
+ from jose import JWTError, jwt
131
+
132
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/token")
133
+
134
+ async def get_current_user(
135
+ token: str = Depends(oauth2_scheme),
136
+ db: AsyncSession = Depends(get_db),
137
+ ) -> User:
138
+ try:
139
+ payload = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
140
+ user_id: str = payload.get("sub")
141
+ if user_id is None:
142
+ raise credentials_exception
143
+ except JWTError:
144
+ raise HTTPException(status_code=401, detail="Invalid credentials")
145
+ user = await crud_user.get(db, id=user_id)
146
+ if user is None:
147
+ raise HTTPException(status_code=404, detail="User not found")
148
+ return user
149
+ ```
150
+
151
+ ### Hintergrundaufgaben
152
+ ```python
153
+ # FastAPI's BackgroundTasks für leichtgewichtiges Fire-and-Forget verwenden (kein Ergebnis benötigt)
154
+ @router.post("/send-email")
155
+ async def send_email_endpoint(
156
+ payload: EmailPayload,
157
+ background_tasks: BackgroundTasks,
158
+ ):
159
+ background_tasks.add_task(send_email, payload.to, payload.subject, payload.body)
160
+ return {"status": "queued"}
161
+
162
+ # Celery verwenden für: Wiederholungen, Ergebnisverfolgung, Planung, dienstübergreifende Aufgaben
163
+ ```
164
+
165
+ ### CORS-Middleware
166
+ ```python
167
+ from fastapi.middleware.cors import CORSMiddleware
168
+
169
+ app.add_middleware(
170
+ CORSMiddleware,
171
+ allow_origins=settings.ALLOWED_ORIGINS, # Niemals ["*"] in der Produktion
172
+ allow_credentials=True,
173
+ allow_methods=["*"],
174
+ allow_headers=["*"],
175
+ )
176
+ ```
177
+
178
+ ### Benutzerdefinierte Exception-Handler
179
+ ```python
180
+ from fastapi.responses import JSONResponse
181
+
182
+ @app.exception_handler(ValueError)
183
+ async def value_error_handler(request: Request, exc: ValueError) -> JSONResponse:
184
+ return JSONResponse(status_code=422, content={"detail": str(exc)})
185
+ ```
186
+
187
+ ### Tests
188
+ ```python
189
+ # tests/conftest.py
190
+ import pytest
191
+ from httpx import AsyncClient, ASGITransport
192
+ from app.main import app
193
+
194
+ @pytest.fixture
195
+ async def client() -> AsyncIterator[AsyncClient]:
196
+ async with AsyncClient(
197
+ transport=ASGITransport(app=app), base_url="http://test"
198
+ ) as ac:
199
+ yield ac
200
+
201
+ # tests/test_users.py
202
+ @pytest.mark.asyncio
203
+ async def test_create_user(client: AsyncClient, db_session):
204
+ resp = await client.post("/api/v1/users/", json={"email": "a@b.com", "password": "secret"})
205
+ assert resp.status_code == 201
206
+ assert resp.json()["email"] == "a@b.com"
207
+ ```
208
+
209
+ ### Häufige Pydantic-Muster
210
+ ```python
211
+ from pydantic import BaseModel, EmailStr, field_validator, model_validator
212
+
213
+ class UserCreate(BaseModel):
214
+ email: EmailStr
215
+ password: str
216
+
217
+ @field_validator("password")
218
+ @classmethod
219
+ def password_strength(cls, v: str) -> str:
220
+ if len(v) < 8:
221
+ raise ValueError("Password must be at least 8 characters")
222
+ return v
223
+
224
+ class UserResponse(BaseModel):
225
+ id: int
226
+ email: EmailStr
227
+
228
+ model_config = {"from_attributes": True} # ersetzt orm_mode = True
229
+ ```
230
+
231
+ ## Beispiel
232
+
233
+ **Benutzer:** Einen FastAPI-Endpunkt zum Erstellen eines Blog-Posts bauen, mit JWT authentifiziert und in PostgreSQL mit asynchronem SQLAlchemy gespeichert.
234
+
235
+ **Erwartete Struktur:**
236
+ - `schemas/post.py` — `PostCreate(BaseModel)`, `PostResponse(BaseModel)` mit `from_attributes=True`
237
+ - `models/post.py` — `Post` ORM-Modell mit `id`, `title`, `body`, `author_id` (FK zu User), `created_at`
238
+ - `crud/post.py` — `create(db, *, obj_in, author_id)` asynchrone Funktion
239
+ - `api/v1/endpoints/posts.py` — `POST /posts/` mit `Depends(get_current_user)` und `Depends(get_db)`
240
+ - `api/v1/router.py` — Posts-Router einschließen
241
+
242
+ ---
243
+
244
+ > **Mit uns arbeiten:** Claudient wird von [Uitbreiden](https://uitbreiden.com/) unterstützt — wir bauen KI-Produkte und B2B-Lösungen mit Entwickler-Communities. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,283 @@
1
+ # Django Skill
2
+
3
+ ## When to activate
4
+ - Building a Django project with ORM models, migrations, and views
5
+ - Setting up Django REST Framework (DRF) serializers, viewsets, and routers
6
+ - Writing custom model managers or QuerySet methods
7
+ - Using Django signals for decoupled side effects
8
+ - Setting up Celery for async tasks in a Django project
9
+ - Customizing the Django admin
10
+ - Writing tests with `django.test.TestCase` or `pytest-django`
11
+
12
+ ## When NOT to use
13
+ - Async-first APIs — use FastAPI skill instead
14
+ - Microservices that don't need Django's ORM or admin
15
+ - Simple scripts or CLIs — plain Python or Typer
16
+ - If the project already uses FastAPI or Flask
17
+
18
+ ## Instructions
19
+
20
+ ### Project layout
21
+ ```
22
+ project_name/
23
+ ├── manage.py
24
+ ├── config/
25
+ │ ├── settings/
26
+ │ │ ├── base.py
27
+ │ │ ├── development.py
28
+ │ │ └── production.py
29
+ │ ├── urls.py
30
+ │ └── wsgi.py
31
+ ├── apps/
32
+ │ └── users/
33
+ │ ├── models.py
34
+ │ ├── serializers.py
35
+ │ ├── views.py
36
+ │ ├── urls.py
37
+ │ ├── admin.py
38
+ │ ├── managers.py
39
+ │ └── tests/
40
+ └── requirements/
41
+ ├── base.txt
42
+ ├── development.txt
43
+ └── production.txt
44
+ ```
45
+
46
+ ### Settings split
47
+ ```python
48
+ # config/settings/base.py
49
+ from pathlib import Path
50
+ BASE_DIR = Path(__file__).resolve().parent.parent.parent
51
+
52
+ INSTALLED_APPS = [
53
+ "django.contrib.admin",
54
+ "django.contrib.auth",
55
+ "django.contrib.contenttypes",
56
+ "rest_framework",
57
+ "apps.users",
58
+ ]
59
+
60
+ AUTH_USER_MODEL = "users.User" # Always set a custom user model from day one
61
+
62
+ # config/settings/production.py
63
+ from .base import *
64
+ DEBUG = False
65
+ ALLOWED_HOSTS = env.list("ALLOWED_HOSTS")
66
+ DATABASES = {"default": env.db("DATABASE_URL")}
67
+ ```
68
+
69
+ ### Custom User model
70
+ ```python
71
+ # apps/users/models.py — set up before first migration, never change afterwards
72
+ from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
73
+ from django.db import models
74
+ from .managers import UserManager
75
+
76
+ class User(AbstractBaseUser, PermissionsMixin):
77
+ email = models.EmailField(unique=True)
78
+ is_staff = models.BooleanField(default=False)
79
+ is_active = models.BooleanField(default=True)
80
+ created_at = models.DateTimeField(auto_now_add=True)
81
+
82
+ USERNAME_FIELD = "email"
83
+ REQUIRED_FIELDS = []
84
+ objects = UserManager()
85
+ ```
86
+
87
+ ### Custom Manager
88
+ ```python
89
+ # apps/users/managers.py
90
+ from django.contrib.auth.base_user import BaseUserManager
91
+
92
+ class UserManager(BaseUserManager):
93
+ def create_user(self, email: str, password: str, **extra_fields):
94
+ if not email:
95
+ raise ValueError("Email is required")
96
+ email = self.normalize_email(email)
97
+ user = self.model(email=email, **extra_fields)
98
+ user.set_password(password)
99
+ user.save()
100
+ return user
101
+
102
+ def create_superuser(self, email: str, password: str, **extra_fields):
103
+ extra_fields.setdefault("is_staff", True)
104
+ extra_fields.setdefault("is_superuser", True)
105
+ return self.create_user(email, password, **extra_fields)
106
+
107
+ def active(self):
108
+ return self.get_queryset().filter(is_active=True)
109
+ ```
110
+
111
+ ### DRF Serializers
112
+ ```python
113
+ # apps/users/serializers.py
114
+ from rest_framework import serializers
115
+ from .models import User
116
+
117
+ class UserCreateSerializer(serializers.ModelSerializer):
118
+ password = serializers.CharField(write_only=True, min_length=8)
119
+
120
+ class Meta:
121
+ model = User
122
+ fields = ["id", "email", "password"]
123
+
124
+ def create(self, validated_data: dict) -> User:
125
+ return User.objects.create_user(**validated_data)
126
+
127
+ class UserSerializer(serializers.ModelSerializer):
128
+ class Meta:
129
+ model = User
130
+ fields = ["id", "email", "created_at"]
131
+ read_only_fields = ["id", "created_at"]
132
+ ```
133
+
134
+ ### DRF ViewSets
135
+ ```python
136
+ # apps/users/views.py
137
+ from rest_framework import viewsets, permissions, status
138
+ from rest_framework.decorators import action
139
+ from rest_framework.response import Response
140
+ from .models import User
141
+ from .serializers import UserSerializer, UserCreateSerializer
142
+
143
+ class UserViewSet(viewsets.ModelViewSet):
144
+ queryset = User.objects.active()
145
+ permission_classes = [permissions.IsAuthenticated]
146
+
147
+ def get_serializer_class(self):
148
+ if self.action == "create":
149
+ return UserCreateSerializer
150
+ return UserSerializer
151
+
152
+ def get_permissions(self):
153
+ if self.action == "create":
154
+ return [permissions.AllowAny()]
155
+ return super().get_permissions()
156
+
157
+ @action(detail=False, methods=["get"])
158
+ def me(self, request):
159
+ return Response(UserSerializer(request.user).data)
160
+ ```
161
+
162
+ ### Router setup
163
+ ```python
164
+ # apps/users/urls.py
165
+ from rest_framework.routers import DefaultRouter
166
+ from .views import UserViewSet
167
+
168
+ router = DefaultRouter()
169
+ router.register("users", UserViewSet, basename="user")
170
+ urlpatterns = router.urls
171
+ ```
172
+
173
+ ### Signals
174
+ ```python
175
+ # apps/users/signals.py — use signals for truly decoupled side effects only
176
+ from django.db.models.signals import post_save
177
+ from django.dispatch import receiver
178
+ from .models import User
179
+
180
+ @receiver(post_save, sender=User)
181
+ def send_welcome_email(sender, instance: User, created: bool, **kwargs):
182
+ if created:
183
+ send_email_task.delay(instance.email, "welcome")
184
+
185
+ # apps/users/apps.py
186
+ class UsersConfig(AppConfig):
187
+ name = "apps.users"
188
+ def ready(self):
189
+ import apps.users.signals # noqa: F401
190
+ ```
191
+
192
+ ### Celery
193
+ ```python
194
+ # config/celery.py
195
+ from celery import Celery
196
+ import os
197
+
198
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
199
+ app = Celery("project_name")
200
+ app.config_from_object("django.conf:settings", namespace="CELERY")
201
+ app.autodiscover_tasks()
202
+
203
+ # apps/users/tasks.py
204
+ from config.celery import app
205
+
206
+ @app.task(bind=True, max_retries=3)
207
+ def send_email_task(self, to_email: str, template: str):
208
+ try:
209
+ # send email
210
+ pass
211
+ except Exception as exc:
212
+ raise self.retry(exc=exc, countdown=60)
213
+ ```
214
+
215
+ ### Admin customization
216
+ ```python
217
+ # apps/users/admin.py
218
+ from django.contrib import admin
219
+ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
220
+ from .models import User
221
+
222
+ @admin.register(User)
223
+ class UserAdmin(BaseUserAdmin):
224
+ list_display = ["email", "is_active", "is_staff", "created_at"]
225
+ list_filter = ["is_active", "is_staff"]
226
+ search_fields = ["email"]
227
+ ordering = ["-created_at"]
228
+ fieldsets = (
229
+ (None, {"fields": ("email", "password")}),
230
+ ("Permissions", {"fields": ("is_active", "is_staff", "is_superuser", "groups")}),
231
+ )
232
+ add_fieldsets = (
233
+ (None, {"fields": ("email", "password1", "password2")}),
234
+ )
235
+ ```
236
+
237
+ ### QuerySet optimization
238
+ ```python
239
+ # Always select_related for FK fields, prefetch_related for M2M/reverse FK
240
+ posts = Post.objects.select_related("author").prefetch_related("tags").filter(published=True)
241
+
242
+ # Use only() or defer() for large models when you only need specific fields
243
+ emails = User.objects.filter(is_active=True).only("email")
244
+
245
+ # Use values() for read-only aggregations — skips ORM object construction
246
+ counts = Order.objects.values("status").annotate(count=Count("id"))
247
+ ```
248
+
249
+ ### Testing
250
+ ```python
251
+ # pytest-django style
252
+ import pytest
253
+ from rest_framework.test import APIClient
254
+
255
+ @pytest.fixture
256
+ def api_client():
257
+ return APIClient()
258
+
259
+ @pytest.fixture
260
+ def authenticated_client(api_client, user):
261
+ api_client.force_authenticate(user=user)
262
+ return api_client
263
+
264
+ @pytest.mark.django_db
265
+ def test_create_user(api_client):
266
+ resp = api_client.post("/api/users/", {"email": "a@b.com", "password": "strongpass"})
267
+ assert resp.status_code == 201
268
+ assert resp.data["email"] == "a@b.com"
269
+ ```
270
+
271
+ ## Example
272
+
273
+ **User:** Add a `Post` model to a Django project with DRF, including list/create/retrieve endpoints, paginated results, and filter by `published=True`.
274
+
275
+ **Expected output:**
276
+ - `models.py` — `Post` with `title`, `body`, `author` (FK to User), `published`, `created_at`
277
+ - `serializers.py` — `PostSerializer` with read-only `author` (nested), writable `title`/`body`/`published`
278
+ - `views.py` — `PostViewSet` with `queryset` filtered to `published=True` for unauthenticated users, `IsAuthenticatedOrReadOnly` permission, `PageNumberPagination`
279
+ - `urls.py` — router registered at `/api/posts/`
280
+
281
+ ---
282
+
283
+ > **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/)