@eltonssouza/development-utility-kit 0.10.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 (131) hide show
  1. package/.claude/agents/README.md +24 -0
  2. package/.claude/agents/analyst.md +198 -0
  3. package/.claude/agents/backend-developer.md +126 -0
  4. package/.claude/agents/brain-keeper.md +229 -0
  5. package/.claude/agents/code-reviewer.md +181 -0
  6. package/.claude/agents/database-engineer.md +94 -0
  7. package/.claude/agents/devops-engineer.md +141 -0
  8. package/.claude/agents/frontend-developer.md +97 -0
  9. package/.claude/agents/gate-keeper.md +118 -0
  10. package/.claude/agents/migrator.md +291 -0
  11. package/.claude/agents/mobile-developer.md +80 -0
  12. package/.claude/agents/n8n-specialist.md +94 -0
  13. package/.claude/agents/product-owner.md +115 -0
  14. package/.claude/agents/qa-engineer.md +232 -0
  15. package/.claude/agents/release-engineer.md +204 -0
  16. package/.claude/agents/scaffold.md +87 -0
  17. package/.claude/agents/security-engineer.md +199 -0
  18. package/.claude/agents/sprint-runner.md +46 -0
  19. package/.claude/agents/stack-resolver.md +104 -0
  20. package/.claude/agents/tech-lead.md +182 -0
  21. package/.claude/agents/update-template.md +54 -0
  22. package/.claude/agents/ux-designer.md +118 -0
  23. package/.claude/hooks/flow-guard.js +261 -0
  24. package/.claude/hooks/flow-state.js +197 -0
  25. package/.claude/local/CLAUDE.md +71 -0
  26. package/.claude/settings.json +55 -0
  27. package/.claude/skills/README.md +331 -0
  28. package/.claude/skills/active-project/SKILL.md +131 -0
  29. package/.claude/skills/api-integration-test/SKILL.md +84 -0
  30. package/.claude/skills/auto-test-guard/SKILL.md +239 -0
  31. package/.claude/skills/auto-test-guard/resources/backend-tests.md +20 -0
  32. package/.claude/skills/auto-test-guard/resources/e2e-tests.md +24 -0
  33. package/.claude/skills/auto-test-guard/resources/execution-report.md +49 -0
  34. package/.claude/skills/auto-test-guard/resources/frontend-tests.md +18 -0
  35. package/.claude/skills/auto-test-guard/resources/initial-setup.md +108 -0
  36. package/.claude/skills/auto-test-guard/resources/run-suite.md +48 -0
  37. package/.claude/skills/auto-test-guard/resources/senior-gate.md +19 -0
  38. package/.claude/skills/brain-keeper/SKILL.md +62 -0
  39. package/.claude/skills/brain-keeper/obsidian/app.json +9 -0
  40. package/.claude/skills/brain-keeper/obsidian/appearance.json +4 -0
  41. package/.claude/skills/brain-keeper/obsidian/core-plugins.json +20 -0
  42. package/.claude/skills/brain-keeper/obsidian/daily-notes.json +5 -0
  43. package/.claude/skills/brain-keeper/obsidian/graph.json +32 -0
  44. package/.claude/skills/brain-keeper/obsidian/snippets/folder-colors.css +90 -0
  45. package/.claude/skills/brain-keeper/obsidian/templates.json +5 -0
  46. package/.claude/skills/brain-keeper/templates/README.md +51 -0
  47. package/.claude/skills/brain-keeper/templates/adr.md +40 -0
  48. package/.claude/skills/brain-keeper/templates/bug.md +35 -0
  49. package/.claude/skills/brain-keeper/templates/daily.md +38 -0
  50. package/.claude/skills/brain-keeper/templates/feature.md +62 -0
  51. package/.claude/skills/brain-keeper/templates/meeting.md +34 -0
  52. package/.claude/skills/brain-keeper/templates/tech-debt.md +21 -0
  53. package/.claude/skills/caveman/SKILL.md +189 -0
  54. package/.claude/skills/create-stack-pack/SKILL.md +281 -0
  55. package/.claude/skills/grill-me/SKILL.md +80 -0
  56. package/.claude/skills/pair-debug/SKILL.md +288 -0
  57. package/.claude/skills/prd-ready-check/SKILL.md +86 -0
  58. package/.claude/skills/project-manager/SKILL.md +334 -0
  59. package/.claude/skills/quality-standards/SKILL.md +203 -0
  60. package/.claude/skills/quick-feature/SKILL.md +266 -0
  61. package/.claude/skills/run-sprint/SKILL.md +41 -0
  62. package/.claude/skills/scaffold/SKILL.md +60 -0
  63. package/.claude/skills/stack-discovery/SKILL.md +161 -0
  64. package/.claude/skills/test-coverage-auditor/SKILL.md +87 -0
  65. package/.claude/skills/to-issues/SKILL.md +163 -0
  66. package/.claude/skills/to-prd/SKILL.md +130 -0
  67. package/.claude/skills/update-template/SKILL.md +256 -0
  68. package/.claude/stacks/CODEOWNERS +30 -0
  69. package/.claude/stacks/README.md +97 -0
  70. package/.claude/stacks/_template.md +116 -0
  71. package/.claude/stacks/dotnet/aspire-9.md +528 -0
  72. package/.claude/stacks/go/gin-1.10.md +570 -0
  73. package/.claude/stacks/java/spring-boot-3.md +376 -0
  74. package/.claude/stacks/java/spring-boot-4.md +438 -0
  75. package/.claude/stacks/node/express-5.md +538 -0
  76. package/.claude/stacks/python/django-5.md +483 -0
  77. package/.claude/stacks/python/fastapi-0.115.md +522 -0
  78. package/.claude/stacks/typescript/angular-18.md +420 -0
  79. package/.claude/stacks/typescript/angular-19.md +397 -0
  80. package/.claude/stacks/typescript/angular-21.md +494 -0
  81. package/CLAUDE.md +472 -0
  82. package/README.md +412 -0
  83. package/bin/cli.js +848 -0
  84. package/bin/lib/adr.js +146 -0
  85. package/bin/lib/backup.js +62 -0
  86. package/bin/lib/detect-stack.js +476 -0
  87. package/bin/lib/doctor.js +527 -0
  88. package/bin/lib/help.js +328 -0
  89. package/bin/lib/identity.js +108 -0
  90. package/bin/lib/lint-allowlist.json +15 -0
  91. package/bin/lib/lint.js +798 -0
  92. package/bin/lib/local-dir.js +68 -0
  93. package/bin/lib/manifest.js +236 -0
  94. package/bin/lib/sync-all.js +394 -0
  95. package/bin/lib/version-check.js +398 -0
  96. package/dashboard/db.js +321 -0
  97. package/dashboard/package.json +22 -0
  98. package/dashboard/public/app.js +853 -0
  99. package/dashboard/public/content/docs/agents-reference.en.md +911 -0
  100. package/dashboard/public/content/docs/architecture-overview.en.md +252 -0
  101. package/dashboard/public/content/docs/autonomy-matrix.en.md +186 -0
  102. package/dashboard/public/content/docs/cli-reference.en.md +538 -0
  103. package/dashboard/public/content/docs/git-flow.en.md +525 -0
  104. package/dashboard/public/content/docs/honcho-memory.en.md +394 -0
  105. package/dashboard/public/content/docs/hooks-reference.en.md +404 -0
  106. package/dashboard/public/content/docs/pipeline.en.md +414 -0
  107. package/dashboard/public/content/docs/plugins.en.md +289 -0
  108. package/dashboard/public/content/docs/quality-gate.en.md +315 -0
  109. package/dashboard/public/content/docs/skills-reference.en.md +484 -0
  110. package/dashboard/public/content/docs/stack-rules.en.md +362 -0
  111. package/dashboard/public/content/docs/troubleshooting.en.md +565 -0
  112. package/dashboard/public/content/manifest.json +114 -0
  113. package/dashboard/public/content/manual/backend.en.md +1053 -0
  114. package/dashboard/public/content/manual/existing-project.en.md +848 -0
  115. package/dashboard/public/content/manual/frontend.en.md +1008 -0
  116. package/dashboard/public/content/manual/fullstack.en.md +1459 -0
  117. package/dashboard/public/content/manual/mobile.en.md +837 -0
  118. package/dashboard/public/content/manual/quickstart.en.md +169 -0
  119. package/dashboard/public/index.html +217 -0
  120. package/dashboard/public/style.css +857 -0
  121. package/dashboard/public/vendor/marked.min.js +69 -0
  122. package/dashboard/rtk.js +143 -0
  123. package/dashboard/server-app.js +421 -0
  124. package/dashboard/server.js +104 -0
  125. package/dashboard/test/sprint1.test.js +406 -0
  126. package/dashboard/test/sprint2.test.js +571 -0
  127. package/dashboard/test/sprint3.test.js +560 -0
  128. package/package.json +33 -0
  129. package/scripts/hooks/subagent-telemetry.sh +14 -0
  130. package/scripts/hooks/telemetry-writer.js +250 -0
  131. package/scripts/latest-versions.json +56 -0
@@ -0,0 +1,570 @@
1
+ ---
2
+ stack: go/gin-1.10
3
+ versions_covered: "1.10.x — 1.12.x"
4
+ last_validated: 2026-05-28
5
+ validated_against: "reference pack — Go 1.23 + Gin 1.10 + GORM 1.25 + golang-migrate 4.18"
6
+ status: active
7
+ pack_owner: "@elton"
8
+ security_review: 2026-05-28
9
+ next_review_due: 2027-05-28
10
+ ---
11
+
12
+ # Go 1.23+ + Gin 1.10+
13
+
14
+ Canonical knowledge pack for Go HTTP services on Gin 1.10+. Gin is the right pick when the service is HTTP-heavy with middleware-friendly routing and modest dependency footprint. For projects targeting standard `net/http` + chi or echo, the patterns transfer with minor mechanical changes; this pack assumes Gin.
15
+
16
+ ## 1. When to use this pack
17
+
18
+ - Project declares `Primary stack: Go 1.23+ + Gin 1.10+` in `## Project Identity`.
19
+ - `go.mod` declares `go 1.23` (or newer) and a direct dependency on `github.com/gin-gonic/gin v1.10.x`.
20
+ - Service is API-first (REST), modest throughput target (Gin can handle 50k+ req/s with care; for extreme throughput consider `fasthttp` or hand-rolled `net/http`).
21
+ - For pure CLI / batch jobs without HTTP: do not use this pack — use a plain Go project with cobra/urfave-cli.
22
+ - For full-stack with server-rendered HTML: not Gin's strength; consider `templ` + chi or Buffalo.
23
+
24
+ ## 2. Stack baseline (what this pack assumes)
25
+
26
+ | Component | Version range | Notes |
27
+ |---|---|---|
28
+ | Go | 1.23 (min) / 1.24 (latest stable) | Generics maduros; iterators (range-over-func) na 1.23; toolchain directive in go.mod |
29
+ | Gin | 1.10.x — 1.12.x | Stable middleware API; HTTP/2 native; `gin.Context` is the canonical handler signature |
30
+ | ORM | GORM 1.25.x | OR `sqlc` (typed queries from SQL) for SQL purists |
31
+ | Migrations | golang-migrate 4.18.x | Pure-Go; embedded SQL files via `embed.FS` |
32
+ | Validation | `go-playground/validator` 10.x | Used by Gin's `c.ShouldBindJSON()`; struct tag-driven |
33
+ | Build | `go build` + Makefile | Module mode mandatory; `go mod tidy` in CI |
34
+ | Tests | `testing` stdlib + `testify` 1.10.x | `gomock` 0.5 for mocking; Testcontainers Go 0.34 for integration |
35
+ | Mutation | `go-mutesting` (community) | Target ≥70% on `domain/` + `application/` |
36
+ | Coverage | `go test -coverprofile=cov.out -covermode=atomic` | Target ≥85% lines (`go tool cover -func=cov.out`) |
37
+ | Static analysis | `golangci-lint` v1.61+ (or `v2.0+`) | Bundles 50+ linters; `revive`, `govet`, `staticcheck`, `gosec` |
38
+ | Security scan | `govulncheck` (golang.org/x/vuln) + `gosec` | `govulncheck ./...` checks CVE in code path; `gosec` scans code patterns |
39
+ | Observability | OpenTelemetry SDK + `otelgin` middleware | W3C Trace Context; auto-instruments HTTP, GORM, http.Client |
40
+ | HTTP client | `net/http` with `&http.Client{Timeout: 10*time.Second}` | NEVER `http.Get(url)` directly (no timeout = leaked goroutines) |
41
+ | Config | `kelseyhightower/envconfig` OR `spf13/viper` | env-driven; validated at startup |
42
+
43
+ ## 3. Project structure (DDD / hexagonal)
44
+
45
+ ```
46
+ service/
47
+ ├── go.mod
48
+ ├── go.sum
49
+ ├── Makefile
50
+ ├── cmd/
51
+ │ └── server/
52
+ │ └── main.go # bootstrap: cfg → DI graph → start gin
53
+ ├── internal/ # not importable by other modules
54
+ │ ├── domain/ # pure Go; no Gin, no GORM
55
+ │ │ ├── product/
56
+ │ │ │ ├── entity.go
57
+ │ │ │ ├── repository.go # interface
58
+ │ │ │ └── service.go # pure domain service
59
+ │ │ └── shared/
60
+ │ ├── application/ # use cases (1 method per type)
61
+ │ │ ├── product/
62
+ │ │ │ ├── create_product.go
63
+ │ │ │ └── list_products.go
64
+ │ │ └── shared/
65
+ │ ├── infrastructure/ # GORM, http.Client, AWS SDK, etc.
66
+ │ │ ├── db/
67
+ │ │ │ ├── gorm.go # *gorm.DB initializer
68
+ │ │ │ └── migration.go # golang-migrate runner
69
+ │ │ ├── product/
70
+ │ │ │ ├── model.go # GORM struct
71
+ │ │ │ └── repository.go # adapter for domain.Repository
72
+ │ │ └── http/
73
+ │ │ └── client.go # shared http.Client
74
+ │ ├── api/ # Gin routes + handlers + DTOs
75
+ │ │ ├── product/
76
+ │ │ │ ├── handler.go
77
+ │ │ │ ├── dto.go # request/response structs
78
+ │ │ │ └── router.go
79
+ │ │ └── shared/
80
+ │ │ ├── error_handler.go # RFC 9457 ProblemDetails
81
+ │ │ └── middleware.go
82
+ │ └── config/
83
+ │ └── config.go # envconfig struct
84
+ ├── migrations/ # SQL files for golang-migrate
85
+ │ ├── 000001_create_products.up.sql
86
+ │ └── 000001_create_products.down.sql
87
+ └── tests/
88
+ ├── unit/
89
+ ├── integration/
90
+ └── e2e/
91
+ ```
92
+
93
+ **Rule**: `internal/` makes the layers un-importable by other modules. `domain/` and `application/` contain **zero Gin and zero GORM imports** — pure Go testable without any infra. `infrastructure/` is the only place importing `gorm.io/...`. `api/` is the only place importing `gin-gonic/gin`.
94
+
95
+ ## 4. Code patterns
96
+
97
+ ### Domain entity (no GORM, no Gin)
98
+
99
+ ```go
100
+ // internal/domain/product/entity.go
101
+ package product
102
+
103
+ import (
104
+ "errors"
105
+ "time"
106
+ "github.com/google/uuid"
107
+ )
108
+
109
+ type Product struct {
110
+ ID uuid.UUID
111
+ Name string
112
+ Price int64 // cents — never float for money
113
+ Stock int
114
+ CreatedAt time.Time
115
+ }
116
+
117
+ func (p Product) Reserve(qty int) (Product, error) {
118
+ if qty <= 0 {
119
+ return Product{}, errors.New("qty must be positive")
120
+ }
121
+ if qty > p.Stock {
122
+ return Product{}, errors.New("insufficient stock")
123
+ }
124
+ p.Stock -= qty
125
+ return p, nil
126
+ }
127
+ ```
128
+
129
+ **Rule**: money in `int64` cents (or `decimal.Decimal` if shopspring/decimal is acceptable). NEVER `float64` for money — precision loss is real. Domain methods take and return value types; immutability by convention.
130
+
131
+ ### Domain port (interface) + infrastructure adapter
132
+
133
+ ```go
134
+ // internal/domain/product/repository.go
135
+ package product
136
+
137
+ import (
138
+ "context"
139
+ "github.com/google/uuid"
140
+ )
141
+
142
+ type Repository interface {
143
+ Get(ctx context.Context, id uuid.UUID) (*Product, error)
144
+ Save(ctx context.Context, p Product) error
145
+ }
146
+ ```
147
+
148
+ ```go
149
+ // internal/infrastructure/product/model.go
150
+ package product
151
+
152
+ import (
153
+ "time"
154
+ "github.com/google/uuid"
155
+ )
156
+
157
+ type ProductGORM struct {
158
+ ID uuid.UUID `gorm:"type:uuid;primaryKey"`
159
+ Name string `gorm:"size:120;index"`
160
+ Price int64
161
+ Stock int
162
+ CreatedAt time.Time
163
+ }
164
+
165
+ func (ProductGORM) TableName() string { return "products" }
166
+ ```
167
+
168
+ ```go
169
+ // internal/infrastructure/product/repository.go
170
+ package product
171
+
172
+ import (
173
+ "context"
174
+ "errors"
175
+ "github.com/google/uuid"
176
+ "gorm.io/gorm"
177
+ domain "service/internal/domain/product"
178
+ )
179
+
180
+ type GormRepository struct {
181
+ db *gorm.DB
182
+ }
183
+
184
+ func New(db *gorm.DB) *GormRepository {
185
+ return &GormRepository{db: db}
186
+ }
187
+
188
+ func (r *GormRepository) Get(ctx context.Context, id uuid.UUID) (*domain.Product, error) {
189
+ var row ProductGORM
190
+ if err := r.db.WithContext(ctx).First(&row, "id = ?", id).Error; err != nil {
191
+ if errors.Is(err, gorm.ErrRecordNotFound) {
192
+ return nil, nil
193
+ }
194
+ return nil, err
195
+ }
196
+ return toDomain(row), nil
197
+ }
198
+
199
+ func (r *GormRepository) Save(ctx context.Context, p domain.Product) error {
200
+ row := ProductGORM{
201
+ ID: p.ID, Name: p.Name, Price: p.Price, Stock: p.Stock, CreatedAt: p.CreatedAt,
202
+ }
203
+ return r.db.WithContext(ctx).Save(&row).Error
204
+ }
205
+
206
+ func toDomain(r ProductGORM) *domain.Product {
207
+ return &domain.Product{
208
+ ID: r.ID, Name: r.Name, Price: r.Price, Stock: r.Stock, CreatedAt: r.CreatedAt,
209
+ }
210
+ }
211
+ ```
212
+
213
+ **Rule**: domain `Repository` is an interface in `domain/`. Implementation in `infrastructure/`. Use cases depend on the interface. UUID primary key — never auto-increment for distributed systems.
214
+
215
+ ### Gin handler (thin)
216
+
217
+ ```go
218
+ // internal/api/product/dto.go
219
+ package product
220
+
221
+ import "time"
222
+
223
+ type CreateProductRequest struct {
224
+ Name string `json:"name" binding:"required,min=1,max=120"`
225
+ Price int64 `json:"price" binding:"required,gt=0"`
226
+ Stock int `json:"stock" binding:"gte=0"`
227
+ }
228
+
229
+ type ProductResponse struct {
230
+ ID string `json:"id"`
231
+ Name string `json:"name"`
232
+ Price int64 `json:"price"`
233
+ Stock int `json:"stock"`
234
+ CreatedAt time.Time `json:"created_at"`
235
+ }
236
+ ```
237
+
238
+ ```go
239
+ // internal/api/product/handler.go
240
+ package product
241
+
242
+ import (
243
+ "net/http"
244
+ "github.com/gin-gonic/gin"
245
+ "service/internal/application/product"
246
+ )
247
+
248
+ type Handler struct {
249
+ createUC *product.CreateProductUseCase
250
+ }
251
+
252
+ func NewHandler(uc *product.CreateProductUseCase) *Handler {
253
+ return &Handler{createUC: uc}
254
+ }
255
+
256
+ func (h *Handler) Create(c *gin.Context) {
257
+ var req CreateProductRequest
258
+ if err := c.ShouldBindJSON(&req); err != nil {
259
+ c.JSON(http.StatusBadRequest, gin.H{"detail": err.Error()})
260
+ return
261
+ }
262
+ p, err := h.createUC.Execute(c.Request.Context(), req.Name, req.Price, req.Stock)
263
+ if err != nil {
264
+ c.Error(err) // central error handler converts to ProblemDetails
265
+ return
266
+ }
267
+ c.JSON(http.StatusCreated, ProductResponse{
268
+ ID: p.ID.String(), Name: p.Name, Price: p.Price, Stock: p.Stock, CreatedAt: p.CreatedAt,
269
+ })
270
+ }
271
+ ```
272
+
273
+ **Rule**: handlers are thin — bind, validate (via `binding:` tags), call use case, serialize. Business logic stays in `application/`.
274
+
275
+ ### Router + middleware
276
+
277
+ ```go
278
+ // internal/api/product/router.go
279
+ package product
280
+
281
+ import "github.com/gin-gonic/gin"
282
+
283
+ func Register(r *gin.RouterGroup, h *Handler) {
284
+ products := r.Group("/products")
285
+ products.POST("", h.Create)
286
+ }
287
+ ```
288
+
289
+ ```go
290
+ // cmd/server/main.go
291
+ package main
292
+
293
+ import (
294
+ "github.com/gin-gonic/gin"
295
+ "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
296
+ // ... wire other deps
297
+ )
298
+
299
+ func main() {
300
+ cfg := loadConfig()
301
+ db := initDB(cfg)
302
+ runMigrations(db)
303
+
304
+ repo := productInfra.New(db)
305
+ createUC := productApp.NewCreateProductUseCase(repo)
306
+ handler := productAPI.NewHandler(createUC)
307
+
308
+ r := gin.New()
309
+ r.Use(gin.Recovery())
310
+ r.Use(otelgin.Middleware("products-service"))
311
+ r.Use(requestIDMiddleware())
312
+ r.Use(errorHandlerMiddleware()) // converts c.Error to RFC 9457
313
+ r.Use(rateLimiterMiddleware())
314
+
315
+ api := r.Group("/api/v1")
316
+ productAPI.Register(api, handler)
317
+
318
+ srv := &http.Server{
319
+ Addr: ":8080",
320
+ Handler: r,
321
+ ReadHeaderTimeout: 5 * time.Second,
322
+ WriteTimeout: 15 * time.Second,
323
+ IdleTimeout: 60 * time.Second,
324
+ }
325
+ log.Fatal(srv.ListenAndServe())
326
+ }
327
+ ```
328
+
329
+ **Rule**: use `http.Server` with explicit timeouts. Default `srv.ListenAndServe()` has no `ReadHeaderTimeout` — slowloris vulnerability. Always set.
330
+
331
+ ## 5. Testing
332
+
333
+ ### Unit (table-driven, idiomatic Go)
334
+
335
+ ```go
336
+ // internal/domain/product/entity_test.go
337
+ package product
338
+
339
+ import (
340
+ "testing"
341
+ "github.com/google/uuid"
342
+ )
343
+
344
+ func TestReserve(t *testing.T) {
345
+ tests := []struct {
346
+ name string
347
+ stock int
348
+ qty int
349
+ wantErr bool
350
+ }{
351
+ {"decreases stock", 10, 3, false},
352
+ {"refuses zero", 10, 0, true},
353
+ {"refuses excess", 10, 11, true},
354
+ }
355
+ for _, tt := range tests {
356
+ t.Run(tt.name, func(t *testing.T) {
357
+ p := Product{ID: uuid.New(), Stock: tt.stock}
358
+ _, err := p.Reserve(tt.qty)
359
+ if (err != nil) != tt.wantErr {
360
+ t.Errorf("got err=%v, wantErr=%v", err, tt.wantErr)
361
+ }
362
+ })
363
+ }
364
+ }
365
+ ```
366
+
367
+ ### Integration (Testcontainers + httptest)
368
+
369
+ ```go
370
+ // tests/integration/api_test.go
371
+ package integration
372
+
373
+ import (
374
+ "context"
375
+ "net/http/httptest"
376
+ "testing"
377
+ "github.com/stretchr/testify/require"
378
+ "github.com/testcontainers/testcontainers-go/modules/postgres"
379
+ )
380
+
381
+ func TestCreateProduct(t *testing.T) {
382
+ ctx := context.Background()
383
+ pg, err := postgres.Run(ctx, "postgres:16-alpine",
384
+ postgres.WithDatabase("test"),
385
+ postgres.WithUsername("test"),
386
+ postgres.WithPassword("test"),
387
+ )
388
+ require.NoError(t, err)
389
+ t.Cleanup(func() { pg.Terminate(ctx) })
390
+
391
+ // wire app with the postgres connection
392
+ r := buildRouter(t, pg)
393
+ ts := httptest.NewServer(r)
394
+ t.Cleanup(ts.Close)
395
+
396
+ // POST + assert response
397
+ // ...
398
+ }
399
+ ```
400
+
401
+ **Rule**: never SQLite for integration tests if prod is Postgres. Testcontainers Go is the standard.
402
+
403
+ ### Mutation
404
+
405
+ ```bash
406
+ go-mutesting --exec internal/domain/... internal/application/...
407
+ # Target: killed/total >= 70%
408
+ ```
409
+
410
+ ## 6. Build & run commands
411
+
412
+ ```bash
413
+ # Setup
414
+ go mod download
415
+ go mod tidy
416
+
417
+ # Run
418
+ go run ./cmd/server
419
+
420
+ # Build (with version info)
421
+ go build -ldflags "-X main.version=$(git rev-parse HEAD)" -o bin/server ./cmd/server
422
+
423
+ # Cross-compile (Linux from any OS)
424
+ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o bin/server-linux ./cmd/server
425
+
426
+ # Tests
427
+ go test ./... # all
428
+ go test -race ./... # data race detector (slow but mandatory in CI)
429
+ go test -coverprofile=cov.out -covermode=atomic ./...
430
+ go tool cover -func=cov.out | tail -1 # total coverage
431
+
432
+ # Lint
433
+ golangci-lint run ./...
434
+
435
+ # Security
436
+ govulncheck ./...
437
+ gosec ./...
438
+
439
+ # Migrations (golang-migrate)
440
+ migrate -path migrations -database "$DATABASE_URL" up
441
+ migrate -path migrations -database "$DATABASE_URL" down 1
442
+ migrate create -ext sql -dir migrations -seq create_products
443
+ ```
444
+
445
+ ## 7. Security (per ADR-007 + ADR-027 — MANDATORY section)
446
+
447
+ ### 7.1 Authentication & Authorization
448
+
449
+ - **JWT**: `github.com/golang-jwt/jwt/v5`. RS256 preferred; HS256 acceptable single-service. Set `Issuer`, `Audience`, `ExpiresAt` claims. Validate `kid` for rotation.
450
+ - **OAuth2**: `golang.org/x/oauth2` with provider-specific endpoints. PKCE for SPAs.
451
+ - **Password hashing**: `golang.org/x/crypto/bcrypt` with cost 12 minimum. NEVER plaintext, NEVER MD5/SHA1, NEVER unsalted SHA256.
452
+ - **API keys (internal)**: `crypto/rand` + `base64url`. Hash before storage (`sha256` is acceptable for non-user secrets).
453
+ - **Authorization**: middleware that parses JWT, populates `gin.Context` with user/roles, then per-route middleware checks role. Object-level checks inside the use case.
454
+
455
+ ### 7.2 CORS
456
+
457
+ ```go
458
+ import "github.com/gin-contrib/cors"
459
+
460
+ r.Use(cors.New(cors.Config{
461
+ AllowOrigins: []string{"https://app.example.com"}, // NEVER ["*"] in prod
462
+ AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
463
+ AllowHeaders: []string{"Authorization", "Content-Type"},
464
+ AllowCredentials: true,
465
+ MaxAge: 12 * time.Hour,
466
+ }))
467
+ ```
468
+
469
+ ### 7.3 Validation & input sanitization
470
+
471
+ - **SQL injection**: GORM parameterizes by default. NEVER `db.Raw(fmt.Sprintf("... %s ...", input))` — use `db.Raw("... ?", input)`.
472
+ - **`validator` tags**: `binding:"required,min=1,max=120"` on every request struct field. Custom validators registered at startup.
473
+ - **Path traversal**: `filepath.Clean` + check the resolved path is inside an allowlisted base before opening.
474
+ - **NoSQL injection (Mongo)**: use the typed bson builder, not `bson.M{}` dict concatenation with user input.
475
+
476
+ ### 7.4 Secrets management
477
+
478
+ - `envconfig` struct loaded at startup, validation via `validator` tags.
479
+ - `.env` gitignored; `env.example` committed.
480
+ - Prefer Secrets Manager (AWS / GCP / Vault) in prod over `.env`. `envconfig` doesn't read from there directly — wrap with a `secretsLoader` interface.
481
+
482
+ ### 7.5 Rate limiting
483
+
484
+ ```go
485
+ import "github.com/gin-contrib/limiter"
486
+
487
+ // 100 req/min/IP
488
+ r.Use(limiter.NewRateLimiter(limiter.Rate{
489
+ Period: time.Minute,
490
+ Limit: 100,
491
+ }))
492
+ ```
493
+
494
+ - `5/min` on `/login`, `/signup`, `/password-reset`. Use per-route group:
495
+
496
+ ```go
497
+ auth := r.Group("/auth", limiter.NewRateLimiter(...))
498
+ auth.POST("/login", h.Login)
499
+ ```
500
+
501
+ - Behind reverse proxy: trust `X-Forwarded-For` only from known proxy IPs.
502
+
503
+ ### 7.6 OWASP Top 10 mapping
504
+
505
+ | OWASP | Mitigation in Go + Gin |
506
+ |---|---|
507
+ | A01 Broken Access Control | JWT middleware + per-route role check; object-level check in use case; default-deny |
508
+ | A02 Cryptographic Failures | bcrypt cost 12; TLS at reverse proxy; HSTS via `c.Header("Strict-Transport-Security", ...)` in middleware |
509
+ | A03 Injection | GORM parameterization; `validator` tags on every struct; never `db.Raw` with f-strings |
510
+ | A04 Insecure Design | DDD layering (`domain/` no Gin/GORM); use case = single public method per type; ADRs document deviations |
511
+ | A05 Security Misconfiguration | `gin.SetMode(gin.ReleaseMode)` in prod; `Server.ReadHeaderTimeout` explicit; `cors` allowlist explicit |
512
+ | A06 Vulnerable Components | `govulncheck ./...` in CI; `dependabot` or `renovate` for `go.mod` bumps |
513
+ | A07 Auth Failures | rate-limit on auth endpoints; bcrypt with cost 12; account lock via Redis counter |
514
+ | A08 Data Integrity | `go mod verify`; `go.sum` committed; SBOM via `syft`/`cyclonedx-go` |
515
+ | A09 Logging Failures | Structured JSON via `slog` (stdlib 1.21+) or `zerolog`; correlation ID middleware; **NEVER** log request body raw (PII) |
516
+ | A10 SSRF | Centralized `http.Client` with allowlist of outbound hosts; reject private CIDRs (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.169.254`) by default |
517
+
518
+ ### 7.7 LGPD / GDPR / compliance specifics
519
+
520
+ - **PII tagging**: convention `// pii: true` in struct comments + a custom `golangci-lint` rule (`revive` config) to flag missing tags on string fields named `Email`, `CPF`, `Document`.
521
+ - **Soft delete**: `DeletedAt *time.Time` column + GORM `gorm.DeletedAt` type. NEVER hard delete user-owned data.
522
+ - **Data subject access**: `GET /api/v1/me/export` returns user data as JSON or zipped CSV.
523
+ - **Erasure**: `DELETE /api/v1/me` sets PII fields to anonymized values while preserving FKs.
524
+ - **Encryption at rest**: PostgreSQL TDE (cloud-managed) or column-level via `pgcrypto` + Go's `crypto/aes` for AES-256-GCM application-level.
525
+
526
+ ## 8. Anti-patterns (block in code-review)
527
+
528
+ | ❌ Bad | ✅ Good | Why |
529
+ |---|---|---|
530
+ | `http.Get(url)` directly | `client := &http.Client{Timeout: 10*time.Second}; client.Get(url)` | No timeout = leaked goroutines on slow upstream |
531
+ | `srv.ListenAndServe()` without timeouts | `&http.Server{ReadHeaderTimeout: 5*time.Second, ...}` | Slowloris attack works against default |
532
+ | `db.Raw(fmt.Sprintf("SELECT ... WHERE id = %s", id))` | `db.Raw("SELECT ... WHERE id = ?", id)` | SQL injection via concatenation |
533
+ | `gin.SetMode(gin.DebugMode)` in prod | `gin.SetMode(gin.ReleaseMode)` from env | Debug mode exposes routes + verbose errors |
534
+ | `float64` or `float32` for money | `int64` (cents) or `shopspring/decimal` | Float precision loss is real |
535
+ | `panic` inside handler not caught | `gin.Recovery()` middleware first in chain | Single bad request crashes the worker |
536
+ | Goroutine spawned in handler without `defer wg.Done()` | Explicit `errgroup.Group` with `ctx` propagation | Goroutine leaks on early return |
537
+ | GORM `AutoMigrate` in prod startup | `golang-migrate` with reviewed SQL files | Schema changes need explicit review |
538
+ | Catching `error` and ignoring with `_` | Always handle: `if err != nil { return err }` OR explicit comment why ignoring | Silent errors = silent bugs |
539
+ | Returning ORM struct directly from handler | DTO with `json:` tags; explicit conversion | API contract leaks data model |
540
+ | Hardcoded `time.Sleep` in tests | Channels + `time.After` for timeouts | Flaky tests on slow CI |
541
+ | `interface{}` (or `any`) when a concrete type fits | Generic `func F[T any](v T)` or concrete type | Type safety wins |
542
+
543
+ ## 9. Migration hints — Gin 1.9 → 1.10+
544
+
545
+ Breaking changes worth flagging when `migrator` agent runs Gin 1.9 → 1.10+:
546
+
547
+ - **Go 1.21 minimum** (Gin 1.10); 1.23 recommended for `slog` + generics improvements.
548
+ - **`Context.IsAborted()`** signature unchanged but rendered errors flow through `c.Error(...)` more strictly. Audit any custom error responses.
549
+ - **`gin.H`** is unchanged but consider replacing with typed `gin.H{}` returns by named response structs for OpenAPI compatibility.
550
+ - **`Routes()` method** on `Engine`: minor signature consolidation. Custom route enumerators may need adjustment.
551
+ - **HTTP/2** is enabled by default. If your service is behind a proxy doing HTTP/1.1 only, explicitly disable: `srv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler))`.
552
+ - **`testify`** mock vs `gomock`: if migrating away from `testify/mock`, `gomock` 0.5 has go-generate based generation that integrates better with new code.
553
+
554
+ Hand off to `migrator` with: current Gin version, current Go toolchain, list of custom middleware that touches `gin.Context` internals.
555
+
556
+ ## 10. References
557
+
558
+ - [Gin official docs](https://gin-gonic.com/docs/)
559
+ - [GORM 1.25 docs](https://gorm.io/docs/)
560
+ - [golang-migrate docs](https://github.com/golang-migrate/migrate/blob/master/GETTING_STARTED.md)
561
+ - [go-playground/validator](https://github.com/go-playground/validator)
562
+ - [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck)
563
+ - [gosec](https://github.com/securego/gosec)
564
+ - [Testcontainers Go](https://golang.testcontainers.org/)
565
+ - [OpenTelemetry Go](https://opentelemetry.io/docs/languages/go/)
566
+ - [OWASP Go Secure Coding Practices](https://github.com/OWASP/Go-SCP)
567
+ - ADR-007 (Senior+ gate thresholds — coverage ≥85%, mutation ≥70%)
568
+ - ADR-026 (Generic agents + stack packs architecture)
569
+ - ADR-027 (Pack governance — frontmatter + security mandatory + CODEOWNERS + annual review)
570
+ - ADR-029 (Canonical pack format — this document follows it)