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,307 @@
1
+ > 🇩🇪 Dies ist die deutsche Übersetzung. [Englische Version](../go.md).
2
+
3
+ # Go Skill
4
+
5
+ ## Wann aktivieren
6
+ - Einen Go-HTTP-Service oder ein CLI-Tool bauen
7
+ - Ein Go-Projekt mit `cmd/`, `internal/`, `pkg/` strukturieren
8
+ - HTTP-Handler mit `net/http`, chi oder gin schreiben
9
+ - Interfaces, Einbettung und Kompositionsmuster implementieren
10
+ - Parallelen Code mit Goroutines, Channels und `sync`-Primitiven schreiben
11
+ - Fehlerbehandlung, -umschließung und Sentinel-Fehler
12
+ - Tabellengetriebene Tests schreiben
13
+
14
+ ## Wann NICHT verwenden
15
+ - Node.js-, Python- oder andere Sprachdienste — andere Ökosysteme
16
+ - Protobuf/gRPC-Dienste ohne vorherigen gRPC-Setup-Kontext
17
+ - Reine Skript-Aufgaben — Shell oder Python sind besser geeignet
18
+
19
+ ## Anweisungen
20
+
21
+ ### Projektlayout
22
+ ```
23
+ myapp/
24
+ ├── cmd/
25
+ │ └── server/
26
+ │ └── main.go # Einstiegspunkt — dünn, verbindet und startet nur
27
+ ├── internal/ # Private Pakete — nicht extern importierbar
28
+ │ ├── config/
29
+ │ ├── handler/
30
+ │ ├── service/
31
+ │ └── store/
32
+ ├── pkg/ # Öffentliche Pakete — von anderen Modulen importierbar
33
+ │ └── apierr/
34
+ ├── go.mod
35
+ └── go.sum
36
+ ```
37
+
38
+ ### main.go — nur Verkabelung
39
+ ```go
40
+ // cmd/server/main.go
41
+ package main
42
+
43
+ import (
44
+ "context"
45
+ "log/slog"
46
+ "net/http"
47
+ "os"
48
+ "os/signal"
49
+ "syscall"
50
+ "time"
51
+
52
+ "myapp/internal/config"
53
+ "myapp/internal/handler"
54
+ "myapp/internal/store"
55
+ )
56
+
57
+ func main() {
58
+ cfg := config.MustLoad()
59
+ db := store.MustConnect(cfg.DatabaseURL)
60
+ defer db.Close()
61
+
62
+ mux := handler.NewMux(db, cfg)
63
+
64
+ srv := &http.Server{
65
+ Addr: ":" + cfg.Port,
66
+ Handler: mux,
67
+ ReadTimeout: 10 * time.Second,
68
+ WriteTimeout: 30 * time.Second,
69
+ IdleTimeout: 60 * time.Second,
70
+ }
71
+
72
+ go func() {
73
+ slog.Info("server starting", "addr", srv.Addr)
74
+ if err := srv.ListenAndServe(); err != http.ErrServerClosed {
75
+ slog.Error("server error", "err", err)
76
+ os.Exit(1)
77
+ }
78
+ }()
79
+
80
+ quit := make(chan os.Signal, 1)
81
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
82
+ <-quit
83
+
84
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
85
+ defer cancel()
86
+ srv.Shutdown(ctx)
87
+ }
88
+ ```
89
+
90
+ ### Fehlerbehandlung
91
+ ```go
92
+ // Sentinel-Fehler für erwartete Bedingungen definieren
93
+ var (
94
+ ErrNotFound = errors.New("not found")
95
+ ErrDuplicate = errors.New("duplicate entry")
96
+ ErrForbidden = errors.New("forbidden")
97
+ )
98
+
99
+ // Fehler mit Kontext umschließen — %w verwenden, um das Entpacken zu erhalten
100
+ func (s *UserStore) GetByID(ctx context.Context, id string) (*User, error) {
101
+ var u User
102
+ err := s.db.QueryRowContext(ctx, `SELECT id, email FROM users WHERE id = $1`, id).
103
+ Scan(&u.ID, &u.Email)
104
+ if errors.Is(err, sql.ErrNoRows) {
105
+ return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
106
+ }
107
+ if err != nil {
108
+ return nil, fmt.Errorf("user store get: %w", err)
109
+ }
110
+ return &u, nil
111
+ }
112
+
113
+ // Aufrufer prüft Verhalten, nicht Nachrichtenstrings
114
+ user, err := store.GetByID(ctx, id)
115
+ if errors.Is(err, ErrNotFound) {
116
+ http.Error(w, "not found", http.StatusNotFound)
117
+ return
118
+ }
119
+ ```
120
+
121
+ ### HTTP-Handler mit chi
122
+ ```go
123
+ // internal/handler/users.go
124
+ type UserHandler struct {
125
+ svc UserService
126
+ }
127
+
128
+ func (h *UserHandler) Register(r chi.Router) {
129
+ r.Get("/users/{id}", h.GetUser)
130
+ r.Post("/users", h.CreateUser)
131
+ }
132
+
133
+ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
134
+ id := chi.URLParam(r, "id")
135
+ user, err := h.svc.GetUser(r.Context(), id)
136
+ if err != nil {
137
+ renderError(w, err)
138
+ return
139
+ }
140
+ renderJSON(w, http.StatusOK, user)
141
+ }
142
+
143
+ func renderJSON(w http.ResponseWriter, code int, v any) {
144
+ w.Header().Set("Content-Type", "application/json")
145
+ w.WriteHeader(code)
146
+ json.NewEncoder(w).Encode(v)
147
+ }
148
+
149
+ func renderError(w http.ResponseWriter, err error) {
150
+ switch {
151
+ case errors.Is(err, ErrNotFound):
152
+ http.Error(w, "not found", http.StatusNotFound)
153
+ case errors.Is(err, ErrForbidden):
154
+ http.Error(w, "forbidden", http.StatusForbidden)
155
+ default:
156
+ slog.Error("internal error", "err", err)
157
+ http.Error(w, "internal server error", http.StatusInternalServerError)
158
+ }
159
+ }
160
+ ```
161
+
162
+ ### Interfaces
163
+ ```go
164
+ // Interfaces dort definieren, wo sie verwendet werden (Verbraucherseite), nicht wo implementiert
165
+ // internal/handler/users.go
166
+ type UserService interface {
167
+ GetUser(ctx context.Context, id string) (*User, error)
168
+ CreateUser(ctx context.Context, req CreateUserRequest) (*User, error)
169
+ }
170
+
171
+ // Interfaces klein halten — 1-3 Methoden bevorzugen
172
+ // io.Reader, io.Writer sind die kanonischen Beispiele
173
+
174
+ // Einbettung für Komposition
175
+ type ReadWriter interface {
176
+ io.Reader
177
+ io.Writer
178
+ }
179
+ ```
180
+
181
+ ### Parallelitätsmuster
182
+ ```go
183
+ // Fan-out mit errgroup
184
+ import "golang.org/x/sync/errgroup"
185
+
186
+ func fetchAll(ctx context.Context, ids []string) ([]*User, error) {
187
+ g, ctx := errgroup.WithContext(ctx)
188
+ results := make([]*User, len(ids))
189
+
190
+ for i, id := range ids {
191
+ i, id := i, id // Schleifenvariablen erfassen
192
+ g.Go(func() error {
193
+ u, err := store.GetByID(ctx, id)
194
+ if err != nil {
195
+ return err
196
+ }
197
+ results[i] = u
198
+ return nil
199
+ })
200
+ }
201
+
202
+ if err := g.Wait(); err != nil {
203
+ return nil, err
204
+ }
205
+ return results, nil
206
+ }
207
+
208
+ // Worker-Pool
209
+ func processJobs(ctx context.Context, jobs <-chan Job) {
210
+ const workers = 10
211
+ var wg sync.WaitGroup
212
+ for range workers {
213
+ wg.Add(1)
214
+ go func() {
215
+ defer wg.Done()
216
+ for job := range jobs {
217
+ if err := process(ctx, job); err != nil {
218
+ slog.Error("job failed", "id", job.ID, "err", err)
219
+ }
220
+ }
221
+ }()
222
+ }
223
+ wg.Wait()
224
+ }
225
+ ```
226
+
227
+ ### Kontext-Weitergabe
228
+ ```go
229
+ // Kontext immer als erstes Argument weitergeben
230
+ func (s *Service) DoWork(ctx context.Context, id string) error {
231
+ // ctx an alle nachgelagerten Aufrufe weitergeben
232
+ user, err := s.store.GetByID(ctx, id)
233
+ if err != nil {
234
+ return err
235
+ }
236
+ return s.notifier.Send(ctx, user.Email)
237
+ }
238
+
239
+ // Anfragebezogene Werte im Kontext nur für übergreifende Belange speichern
240
+ // (Tracing-IDs, Auth-Info) — niemals für optionale Funktionsparameter
241
+ type contextKey string
242
+ const requestIDKey contextKey = "request_id"
243
+
244
+ func WithRequestID(ctx context.Context, id string) context.Context {
245
+ return context.WithValue(ctx, requestIDKey, id)
246
+ }
247
+ func GetRequestID(ctx context.Context) string {
248
+ id, _ := ctx.Value(requestIDKey).(string)
249
+ return id
250
+ }
251
+ ```
252
+
253
+ ### Tabellengetriebene Tests
254
+ ```go
255
+ func TestGetUser(t *testing.T) {
256
+ tests := []struct {
257
+ name string
258
+ id string
259
+ want *User
260
+ wantErr error
261
+ }{
262
+ {"found", "123", &User{ID: "123", Email: "a@b.com"}, nil},
263
+ {"not found", "999", nil, ErrNotFound},
264
+ {"empty id", "", nil, ErrNotFound},
265
+ }
266
+
267
+ for _, tt := range tests {
268
+ t.Run(tt.name, func(t *testing.T) {
269
+ svc := newTestService(t)
270
+ got, err := svc.GetUser(context.Background(), tt.id)
271
+ if !errors.Is(err, tt.wantErr) {
272
+ t.Fatalf("err = %v, want %v", err, tt.wantErr)
273
+ }
274
+ if diff := cmp.Diff(tt.want, got); diff != "" {
275
+ t.Errorf("mismatch (-want +got):\n%s", diff)
276
+ }
277
+ })
278
+ }
279
+ }
280
+ ```
281
+
282
+ ### Logging mit slog
283
+ ```go
284
+ // Strukturiertes Logging — niemals fmt.Println in Produktionscode
285
+ slog.Info("request completed", "method", r.Method, "path", r.URL.Path, "status", 200, "duration_ms", elapsed.Milliseconds())
286
+ slog.Error("db query failed", "query", "getUserByID", "err", err)
287
+
288
+ // JSON-Logger in main einrichten
289
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
290
+ Level: slog.LevelInfo,
291
+ }))
292
+ slog.SetDefault(logger)
293
+ ```
294
+
295
+ ## Beispiel
296
+
297
+ **Benutzer:** Eine Go-HTTP-API für eine To-Do-Liste bauen: Aufgaben erstellen, auflisten und abschließen. PostgreSQL-Backend, chi-Router, strukturiertes Logging, graceful Shutdown.
298
+
299
+ **Erwartete Ausgabe:**
300
+ - `cmd/server/main.go` — verbindet Store, Handler, startet Server mit graceful Shutdown
301
+ - `internal/store/task.go` — `TaskStore` mit `Create`, `List`, `Complete`-Methoden, die `database/sql` verwenden
302
+ - `internal/handler/tasks.go` — `TaskHandler` mit `Register(r chi.Router)`, JSON-Antworten
303
+ - `internal/handler/tasks_test.go` — tabellengetriebene Tests mit einem Mock-Store
304
+
305
+ ---
306
+
307
+ > **Mit uns arbeiten:** Claudient wird von [Uitbreiden](https://uitbreiden.com/) unterstützt — wir bauen KI-Produkte und B2B-Lösungen mit Entwickler-Communities. [uitbreiden.com](https://uitbreiden.com/)
@@ -0,0 +1,307 @@
1
+ > 🇪🇸 Esta es la traducción en español. [Versión en inglés](../go.md).
2
+
3
+ # Skill de Go
4
+
5
+ ## Cuándo activar
6
+ - Construir un servicio HTTP o herramienta CLI en Go
7
+ - Estructurar un proyecto Go con `cmd/`, `internal/`, `pkg/`
8
+ - Escribir manejadores HTTP con `net/http`, chi o gin
9
+ - Implementar interfaces, embedding y patrones de composición
10
+ - Escribir código concurrente con goroutines, canales y primitivas `sync`
11
+ - Manejo de errores, wrapping y errores centinela
12
+ - Escribir pruebas orientadas a tablas
13
+
14
+ ## Cuándo NO usar
15
+ - Servicios en Node.js, Python u otros lenguajes — ecosistemas diferentes
16
+ - Servicios Protobuf/gRPC sin contexto previo de configuración gRPC
17
+ - Tareas puras de scripting — shell o Python son mejores opciones
18
+
19
+ ## Instrucciones
20
+
21
+ ### Estructura del proyecto
22
+ ```
23
+ myapp/
24
+ ├── cmd/
25
+ │ └── server/
26
+ │ └── main.go # Punto de entrada — ligero, solo conecta e inicia
27
+ ├── internal/ # Paquetes privados — no importables externamente
28
+ │ ├── config/
29
+ │ ├── handler/
30
+ │ ├── service/
31
+ │ └── store/
32
+ ├── pkg/ # Paquetes públicos — importables por otros módulos
33
+ │ └── apierr/
34
+ ├── go.mod
35
+ └── go.sum
36
+ ```
37
+
38
+ ### main.go — solo conexión
39
+ ```go
40
+ // cmd/server/main.go
41
+ package main
42
+
43
+ import (
44
+ "context"
45
+ "log/slog"
46
+ "net/http"
47
+ "os"
48
+ "os/signal"
49
+ "syscall"
50
+ "time"
51
+
52
+ "myapp/internal/config"
53
+ "myapp/internal/handler"
54
+ "myapp/internal/store"
55
+ )
56
+
57
+ func main() {
58
+ cfg := config.MustLoad()
59
+ db := store.MustConnect(cfg.DatabaseURL)
60
+ defer db.Close()
61
+
62
+ mux := handler.NewMux(db, cfg)
63
+
64
+ srv := &http.Server{
65
+ Addr: ":" + cfg.Port,
66
+ Handler: mux,
67
+ ReadTimeout: 10 * time.Second,
68
+ WriteTimeout: 30 * time.Second,
69
+ IdleTimeout: 60 * time.Second,
70
+ }
71
+
72
+ go func() {
73
+ slog.Info("server starting", "addr", srv.Addr)
74
+ if err := srv.ListenAndServe(); err != http.ErrServerClosed {
75
+ slog.Error("server error", "err", err)
76
+ os.Exit(1)
77
+ }
78
+ }()
79
+
80
+ quit := make(chan os.Signal, 1)
81
+ signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
82
+ <-quit
83
+
84
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
85
+ defer cancel()
86
+ srv.Shutdown(ctx)
87
+ }
88
+ ```
89
+
90
+ ### Manejo de errores
91
+ ```go
92
+ // Definir errores centinela para condiciones esperadas
93
+ var (
94
+ ErrNotFound = errors.New("not found")
95
+ ErrDuplicate = errors.New("duplicate entry")
96
+ ErrForbidden = errors.New("forbidden")
97
+ )
98
+
99
+ // Envolver errores con contexto — usar %w para preservar el unwrapping
100
+ func (s *UserStore) GetByID(ctx context.Context, id string) (*User, error) {
101
+ var u User
102
+ err := s.db.QueryRowContext(ctx, `SELECT id, email FROM users WHERE id = $1`, id).
103
+ Scan(&u.ID, &u.Email)
104
+ if errors.Is(err, sql.ErrNoRows) {
105
+ return nil, fmt.Errorf("user %s: %w", id, ErrNotFound)
106
+ }
107
+ if err != nil {
108
+ return nil, fmt.Errorf("user store get: %w", err)
109
+ }
110
+ return &u, nil
111
+ }
112
+
113
+ // El llamador verifica el comportamiento, no los strings de mensaje
114
+ user, err := store.GetByID(ctx, id)
115
+ if errors.Is(err, ErrNotFound) {
116
+ http.Error(w, "not found", http.StatusNotFound)
117
+ return
118
+ }
119
+ ```
120
+
121
+ ### Manejadores HTTP con chi
122
+ ```go
123
+ // internal/handler/users.go
124
+ type UserHandler struct {
125
+ svc UserService
126
+ }
127
+
128
+ func (h *UserHandler) Register(r chi.Router) {
129
+ r.Get("/users/{id}", h.GetUser)
130
+ r.Post("/users", h.CreateUser)
131
+ }
132
+
133
+ func (h *UserHandler) GetUser(w http.ResponseWriter, r *http.Request) {
134
+ id := chi.URLParam(r, "id")
135
+ user, err := h.svc.GetUser(r.Context(), id)
136
+ if err != nil {
137
+ renderError(w, err)
138
+ return
139
+ }
140
+ renderJSON(w, http.StatusOK, user)
141
+ }
142
+
143
+ func renderJSON(w http.ResponseWriter, code int, v any) {
144
+ w.Header().Set("Content-Type", "application/json")
145
+ w.WriteHeader(code)
146
+ json.NewEncoder(w).Encode(v)
147
+ }
148
+
149
+ func renderError(w http.ResponseWriter, err error) {
150
+ switch {
151
+ case errors.Is(err, ErrNotFound):
152
+ http.Error(w, "not found", http.StatusNotFound)
153
+ case errors.Is(err, ErrForbidden):
154
+ http.Error(w, "forbidden", http.StatusForbidden)
155
+ default:
156
+ slog.Error("internal error", "err", err)
157
+ http.Error(w, "internal server error", http.StatusInternalServerError)
158
+ }
159
+ }
160
+ ```
161
+
162
+ ### Interfaces
163
+ ```go
164
+ // Definir interfaces donde se usan (lado consumidor), no donde se implementan
165
+ // internal/handler/users.go
166
+ type UserService interface {
167
+ GetUser(ctx context.Context, id string) (*User, error)
168
+ CreateUser(ctx context.Context, req CreateUserRequest) (*User, error)
169
+ }
170
+
171
+ // Mantener interfaces pequeñas — preferiblemente 1-3 métodos
172
+ // io.Reader, io.Writer son los ejemplos canónicos
173
+
174
+ // Embedding para composición
175
+ type ReadWriter interface {
176
+ io.Reader
177
+ io.Writer
178
+ }
179
+ ```
180
+
181
+ ### Patrones de concurrencia
182
+ ```go
183
+ // Fan-out con errgroup
184
+ import "golang.org/x/sync/errgroup"
185
+
186
+ func fetchAll(ctx context.Context, ids []string) ([]*User, error) {
187
+ g, ctx := errgroup.WithContext(ctx)
188
+ results := make([]*User, len(ids))
189
+
190
+ for i, id := range ids {
191
+ i, id := i, id // capturar variables del bucle
192
+ g.Go(func() error {
193
+ u, err := store.GetByID(ctx, id)
194
+ if err != nil {
195
+ return err
196
+ }
197
+ results[i] = u
198
+ return nil
199
+ })
200
+ }
201
+
202
+ if err := g.Wait(); err != nil {
203
+ return nil, err
204
+ }
205
+ return results, nil
206
+ }
207
+
208
+ // Pool de workers
209
+ func processJobs(ctx context.Context, jobs <-chan Job) {
210
+ const workers = 10
211
+ var wg sync.WaitGroup
212
+ for range workers {
213
+ wg.Add(1)
214
+ go func() {
215
+ defer wg.Done()
216
+ for job := range jobs {
217
+ if err := process(ctx, job); err != nil {
218
+ slog.Error("job failed", "id", job.ID, "err", err)
219
+ }
220
+ }
221
+ }()
222
+ }
223
+ wg.Wait()
224
+ }
225
+ ```
226
+
227
+ ### Propagación de contexto
228
+ ```go
229
+ // Siempre propaga el contexto como primer argumento
230
+ func (s *Service) DoWork(ctx context.Context, id string) error {
231
+ // Pasar ctx a todas las llamadas downstream
232
+ user, err := s.store.GetByID(ctx, id)
233
+ if err != nil {
234
+ return err
235
+ }
236
+ return s.notifier.Send(ctx, user.Email)
237
+ }
238
+
239
+ // Almacena valores con ámbito de solicitud en el contexto solo para preocupaciones transversales
240
+ // (IDs de trazado, info de autenticación) — nunca para parámetros de función opcionales
241
+ type contextKey string
242
+ const requestIDKey contextKey = "request_id"
243
+
244
+ func WithRequestID(ctx context.Context, id string) context.Context {
245
+ return context.WithValue(ctx, requestIDKey, id)
246
+ }
247
+ func GetRequestID(ctx context.Context) string {
248
+ id, _ := ctx.Value(requestIDKey).(string)
249
+ return id
250
+ }
251
+ ```
252
+
253
+ ### Pruebas orientadas a tablas
254
+ ```go
255
+ func TestGetUser(t *testing.T) {
256
+ tests := []struct {
257
+ name string
258
+ id string
259
+ want *User
260
+ wantErr error
261
+ }{
262
+ {"found", "123", &User{ID: "123", Email: "a@b.com"}, nil},
263
+ {"not found", "999", nil, ErrNotFound},
264
+ {"empty id", "", nil, ErrNotFound},
265
+ }
266
+
267
+ for _, tt := range tests {
268
+ t.Run(tt.name, func(t *testing.T) {
269
+ svc := newTestService(t)
270
+ got, err := svc.GetUser(context.Background(), tt.id)
271
+ if !errors.Is(err, tt.wantErr) {
272
+ t.Fatalf("err = %v, want %v", err, tt.wantErr)
273
+ }
274
+ if diff := cmp.Diff(tt.want, got); diff != "" {
275
+ t.Errorf("mismatch (-want +got):\n%s", diff)
276
+ }
277
+ })
278
+ }
279
+ }
280
+ ```
281
+
282
+ ### Logging con slog
283
+ ```go
284
+ // Logging estructurado — nunca fmt.Println en código de producción
285
+ slog.Info("request completed", "method", r.Method, "path", r.URL.Path, "status", 200, "duration_ms", elapsed.Milliseconds())
286
+ slog.Error("db query failed", "query", "getUserByID", "err", err)
287
+
288
+ // Configurar logger JSON en main
289
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
290
+ Level: slog.LevelInfo,
291
+ }))
292
+ slog.SetDefault(logger)
293
+ ```
294
+
295
+ ## Ejemplo
296
+
297
+ **Usuario:** Construir una API HTTP en Go para una lista de tareas: crear, listar y completar tareas. Backend PostgreSQL, router chi, logging estructurado, apagado graceful.
298
+
299
+ **Salida esperada:**
300
+ - `cmd/server/main.go` — conecta store, handler, inicia el servidor con apagado graceful
301
+ - `internal/store/task.go` — `TaskStore` con métodos `Create`, `List`, `Complete` usando `database/sql`
302
+ - `internal/handler/tasks.go` — `TaskHandler` con `Register(r chi.Router)`, respuestas JSON
303
+ - `internal/handler/tasks_test.go` — pruebas orientadas a tablas con un store mock
304
+
305
+ ---
306
+
307
+ > **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/)