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,181 @@
1
+ > 🇩🇪 Dies ist die deutsche Übersetzung. [Englische Version](../graphql.md).
2
+
3
+ # GraphQL Skill
4
+
5
+ ## Wann aktivieren
6
+ - Ein GraphQL-Schema entwerfen (Types, Queries, Mutations, Subscriptions)
7
+ - Resolver in Node.js implementieren (Apollo Server, Pothos, GraphQL Yoga)
8
+ - Prisma mit einer GraphQL API einrichten
9
+ - GraphQL-Abfragen und Fragments für einen Frontend-Client schreiben
10
+ - Cursor-basierte oder Offset-Paginierung in GraphQL implementieren
11
+ - DataLoader zur N+1-Abfragevermeidung einrichten
12
+ - Authentifizierung und Autorisierung zu einer GraphQL API hinzufügen
13
+ - GraphQL-Performance oder N+1-Probleme debuggen
14
+
15
+ ## Wann NICHT verwenden
16
+ - REST APIs, bei denen GraphQL Komplexität ohne Vorteil hinzufügt (einfaches CRUD, Webhooks, Datei-Uploads)
17
+ - gRPC oder ereignisgesteuerte Systeme
18
+ - Fälle, in denen der Client immer die vollständige Antwort benötigt (GraphQL's Feldauswahl fügt keinen Wert hinzu)
19
+
20
+ ## Anweisungen
21
+
22
+ ### Schema-Designprinzipien
23
+ ```graphql
24
+ # Typnamen: PascalCase Substantive im Singular
25
+ # Feldnamen: camelCase
26
+ # Enums: SCREAMING_SNAKE_CASE-Werte
27
+
28
+ type Order {
29
+ id: ID!
30
+ status: OrderStatus!
31
+ customer: Customer! # Verschachtelter Typ — immer das Objekt zurückgeben, nicht nur die ID
32
+ items: [OrderItem!]! # Nicht-null-Liste von nicht-null-Elementen
33
+ totalAmount: Float!
34
+ createdAt: DateTime!
35
+ }
36
+
37
+ enum OrderStatus {
38
+ PENDING
39
+ COMPLETED
40
+ CANCELLED
41
+ }
42
+
43
+ # Queries: nullable für einzelnes Element zurückgeben (nicht gefunden = null), nicht-null für Listen
44
+ type Query {
45
+ order(id: ID!): Order # Nullable — null wenn nicht gefunden
46
+ orders(filter: OrderFilter): [Order!]! # Nicht-null-Liste
47
+ me: User # Nullable — null wenn nicht authentifiziert
48
+ }
49
+
50
+ # Mutations: immer das mutierte Objekt plus ein Fehler-Array zurückgeben
51
+ type Mutation {
52
+ createOrder(input: CreateOrderInput!): CreateOrderPayload!
53
+ }
54
+
55
+ type CreateOrderPayload {
56
+ order: Order # Null wenn Mutation fehlgeschlagen
57
+ errors: [UserError!]! # Leer wenn erfolgreich
58
+ }
59
+
60
+ type UserError {
61
+ field: String
62
+ message: String!
63
+ }
64
+ ```
65
+
66
+ ### N+1-Vermeidung mit DataLoader
67
+ ```typescript
68
+ import DataLoader from 'dataloader';
69
+
70
+ // Pro Request erstellen — niemals Singleton (Anfragedaten-Isolation)
71
+ export function createLoaders() {
72
+ return {
73
+ customerLoader: new DataLoader<string, Customer>(async (ids) => {
74
+ const customers = await db.customer.findMany({
75
+ where: { id: { in: [...ids] } }
76
+ });
77
+ // Muss in gleicher Reihenfolge wie ids zurückgeben
78
+ const customerMap = new Map(customers.map(c => [c.id, c]));
79
+ return ids.map(id => customerMap.get(id) ?? new Error(`Customer ${id} not found`));
80
+ }),
81
+ };
82
+ }
83
+
84
+ // Resolver — verwendet Loader, nicht direkten DB-Aufruf
85
+ const resolvers = {
86
+ Order: {
87
+ customer: (order, _, { loaders }) => loaders.customerLoader.load(order.customerId),
88
+ }
89
+ };
90
+ ```
91
+
92
+ ### Cursor-basierte Paginierung (gegenüber Offset bevorzugen)
93
+ ```graphql
94
+ type OrderConnection {
95
+ edges: [OrderEdge!]!
96
+ pageInfo: PageInfo!
97
+ totalCount: Int!
98
+ }
99
+
100
+ type OrderEdge {
101
+ node: Order!
102
+ cursor: String!
103
+ }
104
+
105
+ type PageInfo {
106
+ hasNextPage: Boolean!
107
+ hasPreviousPage: Boolean!
108
+ startCursor: String
109
+ endCursor: String
110
+ }
111
+
112
+ type Query {
113
+ orders(first: Int, after: String, last: Int, before: String): OrderConnection!
114
+ }
115
+ ```
116
+
117
+ ### Autorisierungsmuster
118
+ ```typescript
119
+ // Feldebenen-Autorisierung im Resolver
120
+ const resolvers = {
121
+ Query: {
122
+ adminStats: (_, __, { user }) => {
123
+ if (!user || user.role !== 'ADMIN') {
124
+ throw new GraphQLError('Unauthorized', {
125
+ extensions: { code: 'UNAUTHORIZED' }
126
+ });
127
+ }
128
+ return getAdminStats();
129
+ }
130
+ },
131
+ Order: {
132
+ // Objektebene: sensible Felder nur dem Besitzer der Bestellung zurückgeben
133
+ internalNotes: (order, _, { user }) => {
134
+ if (user?.id !== order.customerId && user?.role !== 'ADMIN') return null;
135
+ return order.internalNotes;
136
+ }
137
+ }
138
+ };
139
+ ```
140
+
141
+ ### Prisma + GraphQL-Muster
142
+ ```typescript
143
+ // Resolver mit Prisma — Über-Fetching vermeiden
144
+ const resolvers = {
145
+ Query: {
146
+ order: async (_, { id }, { prisma, user }) => {
147
+ const order = await prisma.order.findUnique({
148
+ where: { id },
149
+ select: {
150
+ id: true,
151
+ status: true,
152
+ customerId: true,
153
+ totalAmount: true,
154
+ createdAt: true,
155
+ // items NICHT hier auswählen — den items-Resolver damit umgehen
156
+ // mit DataLoader, um N+1 zu vermeiden
157
+ }
158
+ });
159
+ if (!order) return null;
160
+ if (order.customerId !== user?.id) throw new GraphQLError('Forbidden');
161
+ return order;
162
+ }
163
+ }
164
+ };
165
+ ```
166
+
167
+ ## Beispiel
168
+
169
+ **Benutzer:** Ein GraphQL-Schema und Resolver für eine einfache E-Commerce-API entwerfen — Produkte, Bestellungen und Kunden. Paginierung, DataLoader für Kunden und Mutation-Fehlerbehandlung einschließen.
170
+
171
+ **Erwartete Ausgabe:**
172
+ - Schema: `Product`, `Order`, `Customer`, `OrderConnection`, `UserError`-Typen
173
+ - `Query.orders` mit Cursor-Paginierung, die `OrderConnection` zurückgibt
174
+ - `Mutation.createOrder` gibt `CreateOrderPayload` mit Fehler-Array zurück
175
+ - `Order.customer`-Resolver verwendet DataLoader (keine direkte DB-Abfrage)
176
+ - `createLoaders()`-Funktion pro Request, batcht Kunden-Lookups nach ID
177
+ - Auth-Prüfung: nur authentifizierte Benutzer können ihre eigenen Bestellungen sehen
178
+
179
+ ---
180
+
181
+ > **Mit uns arbeiten:** Claudient wird von [Uitbreiden](https://uitbreiden.com/) unterstützt — wir bauen KI-Produkte und B2B-Lösungen mit Entwickler-Communities. GraphQL APIs oder KI-gestützte Datenschichten aufbauen? [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,181 @@
1
+ > 🇪🇸 Esta es la traducción en español. [Versión en inglés](../graphql.md).
2
+
3
+ # Skill de GraphQL
4
+
5
+ ## Cuándo activar
6
+ - Diseñar un esquema de GraphQL (tipos, queries, mutations, subscriptions)
7
+ - Implementar resolvers en Node.js (Apollo Server, Pothos, GraphQL Yoga)
8
+ - Configurar Prisma con una API de GraphQL
9
+ - Escribir queries y fragments de GraphQL para un cliente frontend
10
+ - Implementar paginación basada en cursor o por offset en GraphQL
11
+ - Configurar DataLoader para prevención de consultas N+1
12
+ - Agregar autenticación y autorización a una API de GraphQL
13
+ - Depurar rendimiento de GraphQL o problemas N+1
14
+
15
+ ## Cuándo NO usar
16
+ - APIs REST donde GraphQL añade complejidad sin beneficio (CRUD simple, webhooks, cargas de archivos)
17
+ - gRPC o sistemas orientados a eventos
18
+ - Casos donde el cliente siempre necesita la respuesta completa (la selección de campos de GraphQL no aporta valor)
19
+
20
+ ## Instrucciones
21
+
22
+ ### Principios de diseño de esquemas
23
+ ```graphql
24
+ # Nombres de tipos: PascalCase con sustantivos singulares
25
+ # Nombres de campos: camelCase
26
+ # Enums: valores SCREAMING_SNAKE_CASE
27
+
28
+ type Order {
29
+ id: ID!
30
+ status: OrderStatus!
31
+ customer: Customer! # Tipo anidado — siempre devolver el objeto, no solo el ID
32
+ items: [OrderItem!]! # Lista no nula de elementos no nulos
33
+ totalAmount: Float!
34
+ createdAt: DateTime!
35
+ }
36
+
37
+ enum OrderStatus {
38
+ PENDING
39
+ COMPLETED
40
+ CANCELLED
41
+ }
42
+
43
+ # Queries: devolver nullable para elemento individual (no encontrado = null), no nulo para listas
44
+ type Query {
45
+ order(id: ID!): Order # Nullable — null si no se encuentra
46
+ orders(filter: OrderFilter): [Order!]! # Lista no nula
47
+ me: User # Nullable — null si no está autenticado
48
+ }
49
+
50
+ # Mutations: siempre devolver el objeto mutado más un array de errores
51
+ type Mutation {
52
+ createOrder(input: CreateOrderInput!): CreateOrderPayload!
53
+ }
54
+
55
+ type CreateOrderPayload {
56
+ order: Order # Null si la mutation falló
57
+ errors: [UserError!]! # Vacío si fue exitoso
58
+ }
59
+
60
+ type UserError {
61
+ field: String
62
+ message: String!
63
+ }
64
+ ```
65
+
66
+ ### Prevención de N+1 con DataLoader
67
+ ```typescript
68
+ import DataLoader from 'dataloader';
69
+
70
+ // Crear por solicitud — nunca singleton (aislamiento de datos de solicitud)
71
+ export function createLoaders() {
72
+ return {
73
+ customerLoader: new DataLoader<string, Customer>(async (ids) => {
74
+ const customers = await db.customer.findMany({
75
+ where: { id: { in: [...ids] } }
76
+ });
77
+ // Debe devolver en el mismo orden que ids
78
+ const customerMap = new Map(customers.map(c => [c.id, c]));
79
+ return ids.map(id => customerMap.get(id) ?? new Error(`Customer ${id} not found`));
80
+ }),
81
+ };
82
+ }
83
+
84
+ // Resolver — usa el loader, no llamada directa a la BD
85
+ const resolvers = {
86
+ Order: {
87
+ customer: (order, _, { loaders }) => loaders.customerLoader.load(order.customerId),
88
+ }
89
+ };
90
+ ```
91
+
92
+ ### Paginación basada en cursor (preferida sobre offset)
93
+ ```graphql
94
+ type OrderConnection {
95
+ edges: [OrderEdge!]!
96
+ pageInfo: PageInfo!
97
+ totalCount: Int!
98
+ }
99
+
100
+ type OrderEdge {
101
+ node: Order!
102
+ cursor: String!
103
+ }
104
+
105
+ type PageInfo {
106
+ hasNextPage: Boolean!
107
+ hasPreviousPage: Boolean!
108
+ startCursor: String
109
+ endCursor: String
110
+ }
111
+
112
+ type Query {
113
+ orders(first: Int, after: String, last: Int, before: String): OrderConnection!
114
+ }
115
+ ```
116
+
117
+ ### Patrón de autorización
118
+ ```typescript
119
+ // Autorización a nivel de campo en el resolver
120
+ const resolvers = {
121
+ Query: {
122
+ adminStats: (_, __, { user }) => {
123
+ if (!user || user.role !== 'ADMIN') {
124
+ throw new GraphQLError('Unauthorized', {
125
+ extensions: { code: 'UNAUTHORIZED' }
126
+ });
127
+ }
128
+ return getAdminStats();
129
+ }
130
+ },
131
+ Order: {
132
+ // A nivel de objeto: solo devolver campos sensibles al propietario del pedido
133
+ internalNotes: (order, _, { user }) => {
134
+ if (user?.id !== order.customerId && user?.role !== 'ADMIN') return null;
135
+ return order.internalNotes;
136
+ }
137
+ }
138
+ };
139
+ ```
140
+
141
+ ### Patrón de Prisma + GraphQL
142
+ ```typescript
143
+ // Resolver usando Prisma — evitar over-fetching
144
+ const resolvers = {
145
+ Query: {
146
+ order: async (_, { id }, { prisma, user }) => {
147
+ const order = await prisma.order.findUnique({
148
+ where: { id },
149
+ select: {
150
+ id: true,
151
+ status: true,
152
+ customerId: true,
153
+ totalAmount: true,
154
+ createdAt: true,
155
+ // NO seleccionar items aquí — dejar que el resolver de items lo maneje
156
+ // con DataLoader para evitar N+1
157
+ }
158
+ });
159
+ if (!order) return null;
160
+ if (order.customerId !== user?.id) throw new GraphQLError('Forbidden');
161
+ return order;
162
+ }
163
+ }
164
+ };
165
+ ```
166
+
167
+ ## Ejemplo
168
+
169
+ **Usuario:** Diseñar un esquema de GraphQL y resolvers para una API de comercio electrónico simple — productos, pedidos y clientes. Incluir paginación, DataLoader para clientes y manejo de errores en mutations.
170
+
171
+ **Salida esperada:**
172
+ - Esquema: tipos `Product`, `Order`, `Customer`, `OrderConnection`, `UserError`
173
+ - `Query.orders` con paginación de cursor devolviendo `OrderConnection`
174
+ - `Mutation.createOrder` devolviendo `CreateOrderPayload` con array de errores
175
+ - Resolver `Order.customer` usando DataLoader (no consulta directa a la BD)
176
+ - Función `createLoaders()` por solicitud, agrupando búsquedas de clientes por ID
177
+ - Verificación de autenticación: solo los usuarios autenticados pueden ver sus propios pedidos
178
+
179
+ ---
180
+
181
+ > **Trabaja con nosotros:** Claudient está respaldado por [Uitbreiden](https://uitbreiden.com/) — construimos productos de IA y soluciones B2B con comunidades de desarrolladores. ¿Construyendo APIs GraphQL o capas de datos impulsadas por IA? [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,181 @@
1
+ > 🇫🇷 This is the French translation. [English version](../graphql.md).
2
+
3
+ # Compétence GraphQL
4
+
5
+ ## Quand activer
6
+ - Concevoir un schéma GraphQL (types, queries, mutations, subscriptions)
7
+ - Implémenter des resolvers en Node.js (Apollo Server, Pothos, GraphQL Yoga)
8
+ - Configurer Prisma avec une API GraphQL
9
+ - Rédiger des queries et fragments GraphQL pour un client frontend
10
+ - Implémenter une pagination cursor-based ou offset-based dans GraphQL
11
+ - Configurer DataLoader pour la prévention des requêtes N+1
12
+ - Ajouter l'authentification et l'autorisation à une API GraphQL
13
+ - Déboguer les performances GraphQL ou les problèmes N+1
14
+
15
+ ## Quand NE PAS utiliser
16
+ - APIs REST où GraphQL ajoute de la complexité sans bénéfice (CRUD simple, webhooks, upload de fichiers)
17
+ - gRPC ou systèmes event-driven
18
+ - Cas où le client a toujours besoin de la réponse complète (la sélection de champs de GraphQL n'apporte aucune valeur)
19
+
20
+ ## Instructions
21
+
22
+ ### Principes de conception du schéma
23
+ ```graphql
24
+ # Noms de types : noms singuliers en PascalCase
25
+ # Noms de champs : camelCase
26
+ # Valeurs d'enum : SCREAMING_SNAKE_CASE
27
+
28
+ type Order {
29
+ id: ID!
30
+ status: OrderStatus!
31
+ customer: Customer! # Type imbriqué — toujours retourner l'objet, pas juste l'ID
32
+ items: [OrderItem!]! # Liste non-null d'éléments non-null
33
+ totalAmount: Float!
34
+ createdAt: DateTime!
35
+ }
36
+
37
+ enum OrderStatus {
38
+ PENDING
39
+ COMPLETED
40
+ CANCELLED
41
+ }
42
+
43
+ # Queries : retourner nullable pour un seul élément (non trouvé = null), non-null pour les listes
44
+ type Query {
45
+ order(id: ID!): Order # Nullable — null si non trouvé
46
+ orders(filter: OrderFilter): [Order!]! # Liste non-null
47
+ me: User # Nullable — null si non authentifié
48
+ }
49
+
50
+ # Mutations : toujours retourner l'objet muté plus un tableau d'erreurs
51
+ type Mutation {
52
+ createOrder(input: CreateOrderInput!): CreateOrderPayload!
53
+ }
54
+
55
+ type CreateOrderPayload {
56
+ order: Order # Null si la mutation a échoué
57
+ errors: [UserError!]! # Vide si succès
58
+ }
59
+
60
+ type UserError {
61
+ field: String
62
+ message: String!
63
+ }
64
+ ```
65
+
66
+ ### Prévention N+1 avec DataLoader
67
+ ```typescript
68
+ import DataLoader from 'dataloader';
69
+
70
+ // Créer par requête — jamais singleton (isolation des données de requête)
71
+ export function createLoaders() {
72
+ return {
73
+ customerLoader: new DataLoader<string, Customer>(async (ids) => {
74
+ const customers = await db.customer.findMany({
75
+ where: { id: { in: [...ids] } }
76
+ });
77
+ // Doit retourner dans le même ordre que ids
78
+ const customerMap = new Map(customers.map(c => [c.id, c]));
79
+ return ids.map(id => customerMap.get(id) ?? new Error(`Customer ${id} not found`));
80
+ }),
81
+ };
82
+ }
83
+
84
+ // Resolver — utilise le loader, pas un appel DB direct
85
+ const resolvers = {
86
+ Order: {
87
+ customer: (order, _, { loaders }) => loaders.customerLoader.load(order.customerId),
88
+ }
89
+ };
90
+ ```
91
+
92
+ ### Pagination cursor-based (préférée à l'offset)
93
+ ```graphql
94
+ type OrderConnection {
95
+ edges: [OrderEdge!]!
96
+ pageInfo: PageInfo!
97
+ totalCount: Int!
98
+ }
99
+
100
+ type OrderEdge {
101
+ node: Order!
102
+ cursor: String!
103
+ }
104
+
105
+ type PageInfo {
106
+ hasNextPage: Boolean!
107
+ hasPreviousPage: Boolean!
108
+ startCursor: String
109
+ endCursor: String
110
+ }
111
+
112
+ type Query {
113
+ orders(first: Int, after: String, last: Int, before: String): OrderConnection!
114
+ }
115
+ ```
116
+
117
+ ### Pattern d'autorisation
118
+ ```typescript
119
+ // Autorisation au niveau du champ dans le resolver
120
+ const resolvers = {
121
+ Query: {
122
+ adminStats: (_, __, { user }) => {
123
+ if (!user || user.role !== 'ADMIN') {
124
+ throw new GraphQLError('Unauthorized', {
125
+ extensions: { code: 'UNAUTHORIZED' }
126
+ });
127
+ }
128
+ return getAdminStats();
129
+ }
130
+ },
131
+ Order: {
132
+ // Au niveau de l'objet : retourner les champs sensibles uniquement au propriétaire de la commande
133
+ internalNotes: (order, _, { user }) => {
134
+ if (user?.id !== order.customerId && user?.role !== 'ADMIN') return null;
135
+ return order.internalNotes;
136
+ }
137
+ }
138
+ };
139
+ ```
140
+
141
+ ### Pattern Prisma + GraphQL
142
+ ```typescript
143
+ // Resolver utilisant Prisma — éviter le sur-fetch
144
+ const resolvers = {
145
+ Query: {
146
+ order: async (_, { id }, { prisma, user }) => {
147
+ const order = await prisma.order.findUnique({
148
+ where: { id },
149
+ select: {
150
+ id: true,
151
+ status: true,
152
+ customerId: true,
153
+ totalAmount: true,
154
+ createdAt: true,
155
+ // Ne PAS sélectionner items ici — laisser le resolver items le gérer
156
+ // avec DataLoader pour éviter N+1
157
+ }
158
+ });
159
+ if (!order) return null;
160
+ if (order.customerId !== user?.id) throw new GraphQLError('Forbidden');
161
+ return order;
162
+ }
163
+ }
164
+ };
165
+ ```
166
+
167
+ ## Exemple
168
+
169
+ **Utilisateur :** Concevoir un schéma GraphQL et des resolvers pour une API e-commerce simple — produits, commandes et clients. Inclure la pagination, DataLoader pour les clients et la gestion des erreurs de mutation.
170
+
171
+ **Sortie attendue :**
172
+ - Schéma : types `Product`, `Order`, `Customer`, `OrderConnection`, `UserError`
173
+ - `Query.orders` avec pagination cursor retournant `OrderConnection`
174
+ - `Mutation.createOrder` retournant `CreateOrderPayload` avec tableau d'erreurs
175
+ - Resolver `Order.customer` utilisant DataLoader (pas de requête DB directe)
176
+ - Fonction `createLoaders()` par requête, regroupant les recherches de clients par ID
177
+ - Vérification d'auth : seuls les utilisateurs authentifiés peuvent voir leurs propres commandes
178
+
179
+ ---
180
+
181
+ > **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. Vous construisez des APIs GraphQL ou des couches de données alimentées par l'IA ? [uitbreiden.com](https://uitbreiden.com/)