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
+ > 🇪🇸 Esta es la traducción en español. [Versión en inglés](../nextjs.md).
2
+
3
+ # Skill de Next.js
4
+
5
+ ## Cuándo activar
6
+ - Construir una aplicación Next.js usando el App Router
7
+ - Decidir entre Server Components y Client Components
8
+ - Escribir Server Actions para envíos de formularios y mutations
9
+ - Configurar route handlers (endpoints de API en App Router)
10
+ - Implementar autenticación con NextAuth o un patrón JWT
11
+ - Configurar middleware para redirecciones y guardas de autenticación
12
+ - Optimizar la obtención de datos con `cache()` y `unstable_cache` de React
13
+ - Usar rutas paralelas, rutas interceptadas o grupos de rutas
14
+
15
+ ## Cuándo NO usar
16
+ - Proyectos con Pages Router — los patrones difieren significativamente
17
+ - SPAs puras sin renderizado en servidor (usar Vite + React)
18
+ - Backends NestJS o Express — usar el skill de NestJS
19
+ - Sitios estáticos sin datos dinámicos (usar Astro)
20
+
21
+ ## Instrucciones
22
+
23
+ ### Estructura de directorios del App Router
24
+ ```
25
+ app/
26
+ ├── (auth)/ # Grupo de rutas — sin segmento de URL
27
+ │ ├── login/
28
+ │ │ └── page.tsx
29
+ │ └── layout.tsx # Layout específico de autenticación
30
+ ├── (dashboard)/
31
+ │ ├── dashboard/
32
+ │ │ ├── page.tsx # Server Component por defecto
33
+ │ │ └── loading.tsx # UI del límite de Suspense
34
+ │ └── layout.tsx
35
+ ├── api/
36
+ │ └── webhooks/
37
+ │ └── stripe/
38
+ │ └── route.ts # Route Handler
39
+ ├── layout.tsx # Layout raíz (requerido)
40
+ └── page.tsx # Página de inicio
41
+ components/
42
+ ├── ui/ # Presentacional (puede ser server o client)
43
+ └── forms/ # Siempre Client Components (useState/eventos)
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 (por defecto) — se ejecuta en el servidor, nunca se envía al cliente
54
+ // Puede: await fetch, leer BD, acceder a variables de entorno
55
+ // No puede: useState, useEffect, APIs del navegador, manejadores de eventos
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 — agregar directiva 'use client'
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
+ Regla: por defecto usar Server Components. Agregar `'use client'` solo cuando se necesita interactividad, APIs del navegador o hooks de React.
72
+
73
+ ### Patrones de obtención de datos
74
+ ```tsx
75
+ // Server Component — async/await directo, sin useEffect, sin 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
+ // Deduplicación — React cache() envuelve una función para que múltiples componentes
82
+ // que la llamen en un render compartan una sola fetch
83
+ import { cache } from 'react'
84
+ export const getUser = cache(async (id: string) => {
85
+ return db.user.findUnique({ where: { id } })
86
+ })
87
+
88
+ // Generación estática con revalidación
89
+ async function getProducts() {
90
+ const res = await fetch('https://api.example.com/products', {
91
+ next: { revalidate: 3600 }, // ISR — revalidar cada hora
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
+ // En un 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">Save</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 (nivel raíz)
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
+ ### Rutas paralelas e interceptadas
173
+ ```
174
+ app/
175
+ ├── @modal/ # Ruta paralela — se renderiza junto al contenido principal
176
+ │ └── (.)photo/ # Ruta interceptada — intercepta /photo/[id]
177
+ │ └── [id]/
178
+ │ └── page.tsx
179
+ ├── photo/
180
+ │ └── [id]/
181
+ │ └── page.tsx
182
+ └── layout.tsx # Acepta { children, modal } como props
183
+ ```
184
+
185
+ ### Límites de error y carga
186
+ ```tsx
187
+ // app/dashboard/loading.tsx — mostrado durante Suspense
188
+ export default function Loading() {
189
+ return <DashboardSkeleton />
190
+ }
191
+
192
+ // app/dashboard/error.tsx — límite de error para este segmento
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}>Retry</button>
199
+ </div>
200
+ )
201
+ }
202
+ ```
203
+
204
+ ### Variables de entorno
205
+ - `NEXT_PUBLIC_*` — expuestas al navegador
206
+ - Todo lo demás — solo servidor (nunca accesible en Client Components)
207
+ - Nunca importes una variable de entorno solo del servidor dentro de un Client Component — devuelve `undefined` silenciosamente
208
+
209
+ ## Ejemplo
210
+
211
+ **Usuario:** Agregar una página de publicaciones de blog paginada en `/blog` que obtiene de PostgreSQL, con un modal "Nueva Publicación" que se abre en `/blog/new` pero no navega fuera de la lista de publicaciones.
212
+
213
+ **Salida esperada:**
214
+ - `app/blog/page.tsx` — Server Component, obtiene posts con `db.post.findMany`, renderiza `<PostList>` + `<Link href="/blog/new">`
215
+ - `app/@modal/(.)blog/new/page.tsx` — Ruta interceptada mostrando un Client Component `<NewPostModal>`
216
+ - `app/blog/new/page.tsx` — Fallback a página completa para navegación directa
217
+ - `app/layout.tsx` — Actualizado para aceptar el slot de ruta paralela `modal` y renderizarlo junto a `children`
218
+ - `lib/actions/post.ts` — Server Action `createPost` con validación Zod + `revalidatePath('/blog')`
219
+
220
+ ---
221
+
222
+ > **Trabaja con nosotros:** Claudient está respaldado por [Uitbreiden](https://uitbreiden.com/) — construimos productos de IA y soluciones B2B con comunidades de desarrolladores. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,274 @@
1
+ > 🇫🇷 This is the French translation. [English version](../nestjs.md).
2
+
3
+ # Compétence NestJS
4
+
5
+ ## Quand activer
6
+ - Construire une application NestJS (modules, controllers, services)
7
+ - Configurer des guards, interceptors, pipes et filtres d'exception
8
+ - Intégrer TypeORM ou Prisma avec NestJS
9
+ - Implémenter CQRS avec des commandes, requêtes et événements
10
+ - Configurer des microservices (transport TCP, Redis, RabbitMQ)
11
+ - Rédiger des tests unitaires et e2e avec Jest et Supertest
12
+ - Générer des docs OpenAPI avec `@nestjs/swagger`
13
+
14
+ ## Quand NE PAS utiliser
15
+ - Routes API Next.js ou Fastify standalone — framework différent
16
+ - Scripts Express simples — le surcoût NestJS n'est pas justifié
17
+ - Fonctions Lambda où le temps de cold start est critique
18
+
19
+ ## Instructions
20
+
21
+ ### Structure des modules
22
+ ```
23
+ src/
24
+ ├── app.module.ts # Module racine
25
+ ├── main.ts # Bootstrap
26
+ ├── common/
27
+ │ ├── decorators/
28
+ │ ├── filters/
29
+ │ ├── guards/
30
+ │ ├── interceptors/
31
+ │ └── pipes/
32
+ ├── config/
33
+ │ └── configuration.ts # Configuration du ConfigService
34
+ └── modules/
35
+ └── users/
36
+ ├── users.module.ts
37
+ ├── users.controller.ts
38
+ ├── users.service.ts
39
+ ├── dto/
40
+ │ ├── create-user.dto.ts
41
+ │ └── update-user.dto.ts
42
+ ├── entities/
43
+ │ └── user.entity.ts
44
+ └── users.service.spec.ts
45
+ ```
46
+
47
+ ### Bootstrap
48
+ ```ts
49
+ // main.ts
50
+ import { NestFactory } from '@nestjs/core'
51
+ import { AppModule } from './app.module'
52
+ import { ValidationPipe } from '@nestjs/common'
53
+ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'
54
+
55
+ async function bootstrap() {
56
+ const app = await NestFactory.create(AppModule)
57
+
58
+ app.useGlobalPipes(new ValidationPipe({
59
+ whitelist: true, // supprimer les champs inconnus
60
+ forbidNonWhitelisted: true,
61
+ transform: true, // auto-transformer les payloads en classes DTO
62
+ }))
63
+
64
+ const config = new DocumentBuilder()
65
+ .setTitle('API')
66
+ .setVersion('1.0')
67
+ .addBearerAuth()
68
+ .build()
69
+ SwaggerModule.setup('docs', app, SwaggerModule.createDocument(app, config))
70
+
71
+ await app.listen(3000)
72
+ }
73
+ bootstrap()
74
+ ```
75
+
76
+ ### Module, Controller, Service
77
+ ```ts
78
+ // users.module.ts
79
+ @Module({
80
+ imports: [TypeOrmModule.forFeature([User]), JwtModule.register({})],
81
+ controllers: [UsersController],
82
+ providers: [UsersService],
83
+ exports: [UsersService],
84
+ })
85
+ export class UsersModule {}
86
+
87
+ // users.controller.ts
88
+ @ApiTags('users')
89
+ @ApiBearerAuth()
90
+ @UseGuards(JwtAuthGuard)
91
+ @Controller('users')
92
+ export class UsersController {
93
+ constructor(private readonly usersService: UsersService) {}
94
+
95
+ @Post()
96
+ @HttpCode(HttpStatus.CREATED)
97
+ create(@Body() dto: CreateUserDto): Promise<UserResponseDto> {
98
+ return this.usersService.create(dto)
99
+ }
100
+
101
+ @Get(':id')
102
+ findOne(@Param('id', ParseUUIDPipe) id: string): Promise<UserResponseDto> {
103
+ return this.usersService.findOneOrFail(id)
104
+ }
105
+ }
106
+
107
+ // users.service.ts
108
+ @Injectable()
109
+ export class UsersService {
110
+ constructor(
111
+ @InjectRepository(User)
112
+ private readonly userRepo: Repository<User>,
113
+ ) {}
114
+
115
+ async create(dto: CreateUserDto): Promise<User> {
116
+ const exists = await this.userRepo.findOneBy({ email: dto.email })
117
+ if (exists) throw new ConflictException('Email already in use')
118
+ const user = this.userRepo.create({
119
+ ...dto,
120
+ password: await bcrypt.hash(dto.password, 10),
121
+ })
122
+ return this.userRepo.save(user)
123
+ }
124
+
125
+ async findOneOrFail(id: string): Promise<User> {
126
+ const user = await this.userRepo.findOneBy({ id })
127
+ if (!user) throw new NotFoundException(`User ${id} not found`)
128
+ return user
129
+ }
130
+ }
131
+ ```
132
+
133
+ ### DTOs avec class-validator
134
+ ```ts
135
+ // dto/create-user.dto.ts
136
+ import { IsEmail, IsString, MinLength, IsOptional } from 'class-validator'
137
+ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
138
+
139
+ export class CreateUserDto {
140
+ @ApiProperty({ example: 'user@example.com' })
141
+ @IsEmail()
142
+ email: string
143
+
144
+ @ApiProperty({ minLength: 8 })
145
+ @IsString()
146
+ @MinLength(8)
147
+ password: string
148
+
149
+ @ApiPropertyOptional()
150
+ @IsOptional()
151
+ @IsString()
152
+ name?: string
153
+ }
154
+ ```
155
+
156
+ ### Guards
157
+ ```ts
158
+ // common/guards/jwt-auth.guard.ts
159
+ @Injectable()
160
+ export class JwtAuthGuard extends AuthGuard('jwt') {
161
+ handleRequest<T>(err: Error, user: T, info: Error): T {
162
+ if (err || !user) {
163
+ throw err || new UnauthorizedException(info?.message)
164
+ }
165
+ return user
166
+ }
167
+ }
168
+
169
+ // common/guards/roles.guard.ts
170
+ @Injectable()
171
+ export class RolesGuard implements CanActivate {
172
+ constructor(private reflector: Reflector) {}
173
+
174
+ canActivate(context: ExecutionContext): boolean {
175
+ const roles = this.reflector.getAllAndOverride<Role[]>('roles', [
176
+ context.getHandler(),
177
+ context.getClass(),
178
+ ])
179
+ if (!roles) return true
180
+ const { user } = context.switchToHttp().getRequest()
181
+ return roles.some(role => user.roles?.includes(role))
182
+ }
183
+ }
184
+ ```
185
+
186
+ ### Interceptors
187
+ ```ts
188
+ // common/interceptors/transform.interceptor.ts
189
+ @Injectable()
190
+ export class TransformInterceptor<T>
191
+ implements NestInterceptor<T, { data: T; timestamp: string }>
192
+ {
193
+ intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
194
+ return next.handle().pipe(
195
+ map(data => ({ data, timestamp: new Date().toISOString() }))
196
+ )
197
+ }
198
+ }
199
+ ```
200
+
201
+ ### CQRS
202
+ ```ts
203
+ // Installer : @nestjs/cqrs
204
+
205
+ // commands/create-user.command.ts
206
+ export class CreateUserCommand {
207
+ constructor(public readonly dto: CreateUserDto) {}
208
+ }
209
+
210
+ // commands/create-user.handler.ts
211
+ @CommandHandler(CreateUserCommand)
212
+ export class CreateUserHandler implements ICommandHandler<CreateUserCommand> {
213
+ constructor(private readonly userRepo: UserRepository) {}
214
+
215
+ async execute(command: CreateUserCommand): Promise<User> {
216
+ const user = User.create(command.dto)
217
+ await this.userRepo.save(user)
218
+ return user
219
+ }
220
+ }
221
+
222
+ // Dans le service/controller :
223
+ const user = await this.commandBus.execute(new CreateUserCommand(dto))
224
+ ```
225
+
226
+ ### Tests
227
+ ```ts
228
+ // Test unitaire
229
+ describe('UsersService', () => {
230
+ let service: UsersService
231
+ let repo: jest.Mocked<Repository<User>>
232
+
233
+ beforeEach(async () => {
234
+ const module = await Test.createTestingModule({
235
+ providers: [
236
+ UsersService,
237
+ { provide: getRepositoryToken(User), useValue: createMockRepository() },
238
+ ],
239
+ }).compile()
240
+ service = module.get(UsersService)
241
+ repo = module.get(getRepositoryToken(User))
242
+ })
243
+
244
+ it('lève ConflictException pour un email en doublon', async () => {
245
+ repo.findOneBy.mockResolvedValue(existingUser)
246
+ await expect(service.create(dto)).rejects.toThrow(ConflictException)
247
+ })
248
+ })
249
+
250
+ // Test E2E
251
+ describe('POST /users', () => {
252
+ it('crée un utilisateur', () => {
253
+ return request(app.getHttpServer())
254
+ .post('/users')
255
+ .send({ email: 'a@b.com', password: 'password123' })
256
+ .expect(201)
257
+ })
258
+ })
259
+ ```
260
+
261
+ ## Exemple
262
+
263
+ **Utilisateur :** Ajouter un module `Products` à une application NestJS avec TypeORM, incluant des endpoints CRUD, une suppression réservée aux admins protégée par un `RolesGuard` et des docs OpenAPI.
264
+
265
+ **Sortie attendue :**
266
+ - `products.entity.ts` — entité TypeORM avec `id` (UUID), `name`, `price` (decimal), `stock`, `createdAt`
267
+ - `dto/create-product.dto.ts` — DTO class-validator avec décorateurs `@ApiProperty`
268
+ - `products.service.ts` — méthodes CRUD utilisant `Repository<Product>`, levant `NotFoundException` si manquant
269
+ - `products.controller.ts` — tous les endpoints CRUD, `@UseGuards(JwtAuthGuard, RolesGuard)` + `@Roles(Role.Admin)` sur `DELETE`
270
+ - `products.module.ts` — importe `TypeOrmModule.forFeature([Product])`
271
+
272
+ ---
273
+
274
+ > **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/)