agentsclimarketplace

Gin architect

Skill ralvarezdev/ralvaskills/skills/frameworks/gin-architect

My personal, ever-growing collection of AI skills for OpenCode and Claude Code. Enforces strict clean architecture and professional standards.

Install
npx -y skills add ralvarezdev/ralvaskills --skill gin-architect

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Framework-specific delta on rest-api-architect — Gin 1.12 on Go 1.26. Feature layout, struct-tag validation, RFC 7807 errors, in-house JWT or external IdP, route groups for URL-prefix versioning, OpenAPI. Read rest-api-architect first for the cross-cutting REST conventions. Use when scaffolding or reviewing a Gin service.

SKILL.md

7.1 KB, as published. Nobody here has run it

Gin Architecture

Targets Gin 1.12 on Go 1.26. Companion to go-architect, rest-api-architect, and sql-architect. Implementation skeletons in RECIPES.md; pinned deps in STACK.md.

1. Project structure — feature-based

One folder per bounded context. Each feature owns its routes, service, repo, DTOs, and SQL files. Mirrors fastapi-architect so polyglot teams can navigate either side. Full tree in RECIPES.md.

  • handlers.go depends on service.go; never reaches into repo.go directly.
  • service.go is pure Go — no gin imports. Easy to unit-test without a fake *gin.Context.
  • dto.go holds wire types with json: and binding: (validator) tags. Never reuse domain structs as DTOs — that's how internal fields leak into the API.

2. Routing & versioning

URL-prefix versioning via route groups. One group per version, one sub-group per feature. Registration skeleton in RECIPES.md.

  • One Register(rg, deps) function per feature — keeps main.go thin.
  • Path params typed at parse time: id, err := uuid.Parse(c.Param("user_id")) — return 400 on parse failure.
  • Use gin.RouterGroup, not bare Engine.GET, so versioning + per-group middleware stays clean.

3. Request validation

Use struct tags with go-playground/validator (canonical per go-architect). Bind via c.ShouldBindJSON / c.ShouldBindUri / c.ShouldBindQuery — never c.MustBindWith (panics; we don't panic in handlers).

type CreateUserReq struct {
    Email    string `json:"email"    binding:"required,email"`
    Password string `json:"password" binding:"required,min=12"`
}
  • binding:"required" on every field that isn't truly optional.
  • Custom validators registered once at startup: validate.RegisterValidation("uuid_v7", isUUIDv7).
  • binding:"omitempty" on PATCH partial-update DTOs — let absent fields mean "leave unchanged."

4. Response shaping

  • Return DTOs, not domain types. c.JSON(200, dto.UserResponse{...}) — DTOs control what leaks.
  • json:"-" on any DTO field that should never serialize (passwords, internal IDs).
  • Status code with c.JSON(http.StatusCreated, ...) — explicit, not Gin's default 200.
  • Empty body uses c.Status(http.StatusNoContent), not c.JSON(204, nil) (sends null).

5. Dependency injection

Explicit constructors per go-architect §3. No globals, no init() magic. Dependencies live in a Deps struct wired in main.go. For larger graphs use uber-go/fx (canonical per go-architect); for services with <10 dependencies, hand-wired is clearer.

6. Lifespan & graceful shutdown

Open shared resources in main.go, never per-request. Close them on shutdown signal via signal.NotifyContext (Go 1.26 records which signal fired). Full skeleton in RECIPES.md.

  • ReadHeaderTimeout is mandatory — without it, Slowloris can pin connections forever.
  • Graceful shutdown timeout > longest expected request duration.

7. Authentication & authorization

Patterns (in-house JWT vs external IdP, Argon2id, JWT lifetimes, JWKS verification, switching criterion) live in rest-api-architect/AUTH_PATTERNS.md. Gin specifics:

  • Pattern A — in-house JWT via golang-jwt/jwt/v5 + argon2 from golang.org/x/crypto. Middleware skeleton in RECIPES.md.
  • Pattern B — external IdP: jwt.ParseWithClaims with a Keyfunc that resolves keys via a JWKS client. Cache JWKS in-process with TTL.
  • Authorization per route, never globalRequireScope(...) composed alongside AuthRequired(secret) on the route declaration (see RECIPES.md).

8. Error handling — RFC 7807 middleware

A central problem package emits application/problem+json (per rest-api-architect §7). Handlers either call problem.Render(c, p) directly or c.Error(err) and let the recovery middleware convert. Renderer in RECIPES.md.

  • One handler per domain-error family — map known sentinel errors to Problem types in a single switch.
  • gin.Recovery with a custom RecoveryHandler that emits a 500 Problem with correlation_id — never a stack trace.

9. Middleware order

Outermost first; order matters.

r := gin.New()  // not gin.Default — we set logging ourselves
r.Use(
    middleware.RequestID(),             // 1. assign correlation_id
    middleware.SLog(),                  // 2. structured access log
    gin.Recovery(),                     // 3. convert panics → 500 problem
    middleware.CORS(cfg.CORS),          // 4. preflight handling
    gzip.Gzip(gzip.DefaultCompression), // 5. response compression
)
  • Never gin.Default() in production — its logger writes unstructured text to stdout. Use slog (per go-architect).
  • Auth is per-route middleware, never global (see §7).
  • Recovery before CORS — a panic that bypasses CORS handler returns no headers; the browser shows a misleading CORS error.

10. Concurrency, not "background tasks"

Go has no FastAPI-style BackgroundTasks. To run work after the response, derive a new context.Context from context.Background() (request context is cancelled the moment the response writes), set a timeout, log errors. Anything serious (retryable, distributed, scheduled) belongs in a real task queue, not a goroutine.

11. Testing

httptest.NewRecorder + the engine directly — no real socket. Skeleton in RECIPES.md.

  • Test-DB strategy: mirror sql-architect — wrap each test in a rolled-back transaction, or use a per-test schema with golang-migrate.
  • Table-driven tests (per go-architect §9) for request validation paths — one row per (input, expected status, expected error type).

12. OpenAPI generation

  • Default: swaggo/swag// @ annotation comments above handlers; swag init generates docs/swagger.json and swagger.yaml. Predictable, mature.
  • For full OpenAPI 3.1 control: getkin/kin-openapi — write the spec in code; serve it; use it to validate requests at runtime. More work but no annotation noise.
  • CI snapshot-tests the spec (per rest-api-architect §15).
  • Internal endpoints excluded with // @Hidden (swag) or by not registering them in the spec route group.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.