---
trigger: glob
globs: **/*.go
---

# Go + Fiber API

- Check `go.mod` for the Fiber major (`github.com/gofiber/fiber/v2` vs `/v3`) and use that version's handler signature and middleware import paths; v3 changed the context API.
- Fiber runs on fasthttp: values from `c.Params`, `c.Query`, `c.Body` and headers are only valid inside the handler. Copy them (`strings.Clone`, `utils.CopyString`, or `bytes.Clone`) before storing or passing to a goroutine.
- Layout: `cmd/api/main.go` builds config, DB and `app := fiber.New(fiber.Config{ErrorHandler: errorHandler})`; features in `internal/<feature>/{handler,service,repo}.go`.
- Parse input into a struct, then validate with `go-playground/validator`; return 400 with field errors. One central `ErrorHandler` maps domain errors to status codes and a consistent JSON shape.
- Pass `c.UserContext()` (v2) or the request context (v3) to services and DB calls so timeouts and cancellation work.
- Middleware: `recover`, `requestid`, logger, CORS with explicit origins, `limiter` on auth routes.
- Graceful shutdown: listen in a goroutine and call `app.ShutdownWithTimeout` on SIGINT/SIGTERM.
- Prefer `net/http` compatibility shims only at the edges; don't mix two routers.

## Tests
Use `app.Test(httptest.NewRequest(...))` for handler tests; table-driven cases with expected status and body.

## Done when
`go vet ./...`, `golangci-lint run` and `go test -race ./...` pass.
