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,222 @@
1
+ > 🇳🇱 Dit is de Nederlandse vertaling. [Engelse versie](../nextjs.md).
2
+
3
+ # Next.js Skill
4
+
5
+ ## Wanneer te activeren
6
+ - Een Next.js-applicatie bouwen met de App Router
7
+ - Kiezen tussen Server Components en Client Components
8
+ - Server Actions schrijven voor formulierinzendingen en mutaties
9
+ - Route handlers instellen (API-endpoints in App Router)
10
+ - Authenticatie implementeren met NextAuth of een JWT-patroon
11
+ - Middleware configureren voor redirects en auth-guards
12
+ - Datafetching optimaliseren met React `cache()` en `unstable_cache`
13
+ - Parallelle routes, onderscheppende routes of routegroepen gebruiken
14
+
15
+ ## Wanneer NIET te gebruiken
16
+ - Pages Router-projecten — de patronen verschillen aanzienlijk
17
+ - Pure SPA's zonder server-rendering (gebruik Vite + React)
18
+ - NestJS of Express backends — gebruik de NestJS skill
19
+ - Statische sites zonder dynamische data (gebruik Astro)
20
+
21
+ ## Instructies
22
+
23
+ ### App Router-directorystructuur
24
+ ```
25
+ app/
26
+ ├── (auth)/ # Routegroep — geen URL-segment
27
+ │ ├── login/
28
+ │ │ └── page.tsx
29
+ │ └── layout.tsx # Auth-specifieke layout
30
+ ├── (dashboard)/
31
+ │ ├── dashboard/
32
+ │ │ ├── page.tsx # Server Component standaard
33
+ │ │ └── loading.tsx # Suspense-grens UI
34
+ │ └── layout.tsx
35
+ ├── api/
36
+ │ └── webhooks/
37
+ │ └── stripe/
38
+ │ └── route.ts # Route Handler
39
+ ├── layout.tsx # Root layout (vereist)
40
+ └── page.tsx # Startpagina
41
+ components/
42
+ ├── ui/ # Presentationeel (kan server of client zijn)
43
+ └── forms/ # Altijd client components (useState/events)
44
+ lib/
45
+ ├── auth.ts
46
+ ├── db.ts
47
+ └── actions/ # Server Actions
48
+ └── user.ts
49
+ ```
50
+
51
+ ### Server vs. Client Components
52
+ ```tsx
53
+ // Server Component (standaard) — draait op server, wordt nooit naar client gestuurd
54
+ // Kan: await fetch, DB lezen, omgevingsvariabelen benaderen
55
+ // Kan niet: useState, useEffect, browser API's, event handlers
56
+ export default async function UserProfile({ id }: { id: string }) {
57
+ const user = await db.user.findUnique({ where: { id } })
58
+ return <div>{user.name}</div>
59
+ }
60
+
61
+ // Client Component — voeg 'use client'-directive toe
62
+ 'use client'
63
+ import { useState } from 'react'
64
+
65
+ export function LikeButton({ initialCount }: { initialCount: number }) {
66
+ const [count, setCount] = useState(initialCount)
67
+ return <button onClick={() => setCount(c => c + 1)}>{count} likes</button>
68
+ }
69
+ ```
70
+
71
+ Regel: gebruik standaard Server Components. Voeg `'use client'` alleen toe wanneer je interactiviteit, browser API's of React hooks nodig hebt.
72
+
73
+ ### Datafetchingpatronen
74
+ ```tsx
75
+ // Server Component — directe async/await, geen useEffect, geen useState
76
+ export default async function PostList() {
77
+ const posts = await db.post.findMany({ where: { published: true } })
78
+ return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
79
+ }
80
+
81
+ // Deduplicatie — React cache() wikkelt een functie zodat meerdere components
82
+ // die het in één render aanroepen één fetch delen
83
+ import { cache } from 'react'
84
+ export const getUser = cache(async (id: string) => {
85
+ return db.user.findUnique({ where: { id } })
86
+ })
87
+
88
+ // Statische generatie met revalidatie
89
+ async function getProducts() {
90
+ const res = await fetch('https://api.example.com/products', {
91
+ next: { revalidate: 3600 }, // ISR — elke uur revalideren
92
+ })
93
+ return res.json()
94
+ }
95
+ ```
96
+
97
+ ### Server Actions
98
+ ```tsx
99
+ // lib/actions/user.ts
100
+ 'use server'
101
+ import { revalidatePath } from 'next/cache'
102
+ import { z } from 'zod'
103
+
104
+ const UpdateSchema = z.object({
105
+ name: z.string().min(1),
106
+ })
107
+
108
+ export async function updateUser(formData: FormData) {
109
+ const parsed = UpdateSchema.safeParse({ name: formData.get('name') })
110
+ if (!parsed.success) return { error: parsed.error.flatten() }
111
+
112
+ await db.user.update({ where: { id: getCurrentUserId() }, data: parsed.data })
113
+ revalidatePath('/dashboard/profile')
114
+ return { success: true }
115
+ }
116
+
117
+ // In een Server Component:
118
+ export default function ProfileForm({ user }: { user: User }) {
119
+ return (
120
+ <form action={updateUser}>
121
+ <input name="name" defaultValue={user.name} />
122
+ <button type="submit">Opslaan</button>
123
+ </form>
124
+ )
125
+ }
126
+ ```
127
+
128
+ ### Route Handlers
129
+ ```ts
130
+ // app/api/webhooks/stripe/route.ts
131
+ import { NextRequest, NextResponse } from 'next/server'
132
+ import Stripe from 'stripe'
133
+
134
+ export async function POST(req: NextRequest) {
135
+ const body = await req.text()
136
+ const sig = req.headers.get('stripe-signature')!
137
+
138
+ let event: Stripe.Event
139
+ try {
140
+ event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!)
141
+ } catch {
142
+ return NextResponse.json({ error: 'Invalid signature' }, { status: 400 })
143
+ }
144
+
145
+ if (event.type === 'checkout.session.completed') {
146
+ await handleCheckoutCompleted(event.data.object)
147
+ }
148
+
149
+ return NextResponse.json({ received: true })
150
+ }
151
+ ```
152
+
153
+ ### Middleware
154
+ ```ts
155
+ // middleware.ts (root-niveau)
156
+ import { NextResponse } from 'next/server'
157
+ import type { NextRequest } from 'next/server'
158
+
159
+ export function middleware(request: NextRequest) {
160
+ const token = request.cookies.get('auth-token')
161
+ if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
162
+ return NextResponse.redirect(new URL('/login', request.url))
163
+ }
164
+ return NextResponse.next()
165
+ }
166
+
167
+ export const config = {
168
+ matcher: ['/dashboard/:path*', '/api/protected/:path*'],
169
+ }
170
+ ```
171
+
172
+ ### Parallelle en onderscheppende routes
173
+ ```
174
+ app/
175
+ ├── @modal/ # Parallelle route — geeft naast hoofdinhoud weer
176
+ │ └── (.)photo/ # Onderscheppende route — onderschept /photo/[id]
177
+ │ └── [id]/
178
+ │ └── page.tsx
179
+ ├── photo/
180
+ │ └── [id]/
181
+ │ └── page.tsx
182
+ └── layout.tsx # Accepteert { children, modal } als props
183
+ ```
184
+
185
+ ### Fout- en laadgrenzen
186
+ ```tsx
187
+ // app/dashboard/loading.tsx — getoond tijdens Suspense
188
+ export default function Loading() {
189
+ return <DashboardSkeleton />
190
+ }
191
+
192
+ // app/dashboard/error.tsx — foutgrens voor dit segment
193
+ 'use client'
194
+ export default function Error({ error, reset }: { error: Error; reset: () => void }) {
195
+ return (
196
+ <div>
197
+ <p>{error.message}</p>
198
+ <button onClick={reset}>Opnieuw proberen</button>
199
+ </div>
200
+ )
201
+ }
202
+ ```
203
+
204
+ ### Omgevingsvariabelen
205
+ - `NEXT_PUBLIC_*` — blootgesteld aan de browser
206
+ - Alle andere — alleen server (nooit toegankelijk in Client Components)
207
+ - Importeer nooit een alleen-server omgevingsvariabele in een Client Component — het retourneert stilletjes `undefined`
208
+
209
+ ## Voorbeeld
210
+
211
+ **Gebruiker:** Voeg een gepagineerde blogberichtenpagina toe op `/blog` die ophaalt vanuit PostgreSQL, met een "Nieuw bericht"-modal die opent op `/blog/new` maar niet wegnavigeert van de berichtenlijst.
212
+
213
+ **Verwachte output:**
214
+ - `app/blog/page.tsx` — Server Component, haalt berichten op met `db.post.findMany`, geeft `<PostList>` + `<Link href="/blog/new">` weer
215
+ - `app/@modal/(.)blog/new/page.tsx` — Onderscheppende route die een `<NewPostModal>` Client Component toont
216
+ - `app/blog/new/page.tsx` — Volledige paginafallback voor directe navigatie
217
+ - `app/layout.tsx` — Bijgewerkt om `modal`-parallelle routesleuf te accepteren en naast `children` weer te geven
218
+ - `lib/actions/post.ts` — `createPost` Server Action met Zod-validatie + `revalidatePath('/blog')`
219
+
220
+ ---
221
+
222
+ > **Werk met ons:** Claudient wordt ondersteund door [Uitbreiden](https://uitbreiden.com/) — we bouwen AI-producten en B2B-oplossingen met ontwikkelaarsgemeenschappen. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,285 @@
1
+ > 🇩🇪 Dies ist die deutsche Übersetzung. [Englische Version](../django.md).
2
+
3
+ # Django Skill
4
+
5
+ ## Wann aktivieren
6
+ - Ein Django-Projekt mit ORM-Modellen, Migrationen und Views aufbauen
7
+ - Django REST Framework (DRF) Serializer, Viewsets und Router einrichten
8
+ - Benutzerdefinierte Modell-Manager oder QuerySet-Methoden schreiben
9
+ - Django-Signale für entkoppelte Nebeneffekte verwenden
10
+ - Celery für asynchrone Aufgaben in einem Django-Projekt einrichten
11
+ - Das Django-Admin anpassen
12
+ - Tests mit `django.test.TestCase` oder `pytest-django` schreiben
13
+
14
+ ## Wann NICHT verwenden
15
+ - Async-first APIs — stattdessen FastAPI Skill verwenden
16
+ - Microservices, die Django's ORM oder Admin nicht benötigen
17
+ - Einfache Skripte oder CLIs — einfaches Python oder Typer
18
+ - Wenn das Projekt bereits FastAPI oder Flask verwendet
19
+
20
+ ## Anweisungen
21
+
22
+ ### Projekt-Layout
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
+ ### Einstellungen aufteilen
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" # Immer von Anfang an ein benutzerdefiniertes User-Modell setzen
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
+ ### Benutzerdefiniertes User-Modell
72
+ ```python
73
+ # apps/users/models.py — vor der ersten Migration einrichten, danach nie mehr ändern
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
+ ### Benutzerdefinierter Manager
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
+ ### DRF-Serializer
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
+ ### DRF-ViewSets
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
+ ### Router-Setup
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
+ ### Signale
176
+ ```python
177
+ # apps/users/signals.py — Signale nur für wirklich entkoppelte Nebeneffekte verwenden
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
+ # E-Mail senden
212
+ pass
213
+ except Exception as exc:
214
+ raise self.retry(exc=exc, countdown=60)
215
+ ```
216
+
217
+ ### Admin-Anpassung
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
+ ### QuerySet-Optimierung
240
+ ```python
241
+ # Immer select_related für FK-Felder, prefetch_related für M2M/Reverse FK
242
+ posts = Post.objects.select_related("author").prefetch_related("tags").filter(published=True)
243
+
244
+ # only() oder defer() für große Modelle verwenden, wenn nur bestimmte Felder benötigt werden
245
+ emails = User.objects.filter(is_active=True).only("email")
246
+
247
+ # values() für schreibgeschützte Aggregationen verwenden — überspringt ORM-Objektkonstruktion
248
+ counts = Order.objects.values("status").annotate(count=Count("id"))
249
+ ```
250
+
251
+ ### Tests
252
+ ```python
253
+ # pytest-django-Stil
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
+ ## Beispiel
274
+
275
+ **Benutzer:** Ein `Post`-Modell zu einem Django-Projekt mit DRF hinzufügen, einschließlich Listen-/Erstell-/Abruf-Endpunkte, paginierte Ergebnisse und Filter nach `published=True`.
276
+
277
+ **Erwartete Ausgabe:**
278
+ - `models.py` — `Post` mit `title`, `body`, `author` (FK zu User), `published`, `created_at`
279
+ - `serializers.py` — `PostSerializer` mit schreibgeschütztem `author` (verschachtelt), beschreibbarem `title`/`body`/`published`
280
+ - `views.py` — `PostViewSet` mit `queryset` gefiltert auf `published=True` für nicht authentifizierte Benutzer, `IsAuthenticatedOrReadOnly`-Berechtigung, `PageNumberPagination`
281
+ - `urls.py` — Router registriert bei `/api/posts/`
282
+
283
+ ---
284
+
285
+ > **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/)