go-backend-fiber

>

sirmahdirahmani/go-backend-skills2 installsMITSynced Aug 22

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: go-backend-fiber
description: >
license: MIT
---

# Go Backend (Fiber v3 + pgx)

Defaults for a **modular monolith**: Fiber v3 HTTP API, PostgreSQL via `pgxpool` + hand-written SQL, Redis for cache/sessions. Follow these unless the project's existing code clearly does otherwise — **consistency with the codebase beats this skill.**

This skill is stack-specific (Fiber + pgx), not a universal Go style guide.

## First steps

1. Inspect the project layout, naming, and error style before writing code.
2. Check `go.mod` for Fiber / pgx versions (Fiber v3 ≠ v2 — see [references/fiber-v3.md](references/fiber-v3.md)).
3. Architecture / cross-domain / transactions → [references/architecture.md](references/architecture.md).
4. DB, money, state machines, tests, config → [references/patterns.md](references/patterns.md).
5. Migrations, Makefile, jobs, Docker → [references/tooling.md](references/tooling.md).

## Core rules

- **Module name ≠ directory name.** Read `go.mod`; don't invent import paths from the folder name.
- **Vertical slices, flat packages.** One domain = one flat package under `internal/domain/<name>/` (`handler.go`, `service.go`, `repository.go`, optional `model.go`, `interface.go`, `errors.go`, `request.go`, `response.go`). No `handler/` / `service/` / `repository/` subdirs. API versioning (e.g. `domain/v2/...`) is optional.
- **Sub-domains** are nested flat packages (e.g. `manager/orders`), each wired independently.
- **Upstream proxies** that only forward to another API live under `external/`, not under `internal/domain/`.
- **No cross-domain imports of internals.** Consumers define a tiny interface; the composition root injects an adapter. Never import another domain's repository or model.
- **Shared infra** lives as top-level packages under `internal/` (`response`, `request`, `middleware`, `migrate`, `pkg/...`, `dbtest`, `testutil`). Prefer that over inventing `internal/platform/` unless the project already uses it.
- **Manual DI** in one composition root (`cmd/api/main.go`). Constructors take interfaces defined at the **consumer** side.
- **State changes** use explicit transition rules + optimistic SQL (`UPDATE ... WHERE id=$1 AND owner=$2`; `RowsAffected()==0` → domain not-found / conflict).

## Money

**Store and compute money as `int64` minor units. Never `float64` for persisted or transacted amounts.**

- DB: `BIGINT`. Go: `int64` (nullable via your null type or `*int64`).
- Wire DTOs may expose a derived float **only** for a legacy display contract; never write that float back as truth.

## HTTP response envelope

Handlers must not call `c.Status(...).JSON(...)` ad hoc. Use a central `internal/response` (or equivalent):

| Helper | Purpose |
|--------|---------|
| `OK` / `Created` | Success body |
| `OKPaginated` | List + `{total,limit,offset}` (or your project's pagination shape — match existing) |
| `Error` | Known client errors |
| `InternalError(c, domain, err)` | Log structured detail; return generic `"internal error"` — **never leak Go errors** |

## Optional: opaque IDs on the wire

If the product encrypts row IDs (AES-GCM token instead of raw int64):

- Encrypt outbound `id` / `*_id` via response helpers.
- Decrypt inbound path/query/body tokens via a shared helper (e.g. `idparam`).
- Keep an explicit exception list for enum/code fields (`currency_id`, `status_id`, `role_id`, …) and nested enum objects.
- If the project does **not** encrypt IDs, skip this section entirely — don't add encryption "because the skill says so."

## Auth (typical pattern)

- JWT minted by the API for authenticated routes.
- Register / token-exchange endpoints are **public** (they mint the JWT).
- Validate the upstream identity provider on every register/exchange call when that is the product rule.
- Map conflicts clearly: already-exists → 409, not-found → 404.
- Prefer creating users only inside the auth flow, not a separate public `POST /users`.

## Database

- **pgxpool + raw SQL** on the HTTP path. Map `pgx.ErrNoRows` / unique violations to domain sentinels in the repository.
- **Avoid ORMs in API domains.** If a worker binary already uses GORM (or similar), confine it there — don't spread it into `cmd/api`.
- One writer pool per schema the API owns.

## Migrations

Prefer **app-level embedded** SQL migrations (`//go:embed` + `golang-migrate` / equivalent):

- Only the API process runs them (not workers), gated by config (`AUTO_MIGRATE` or similar).
- Failure is fatal at boot; "no change" is success.
- Append-only; never edit applied files.

## Testing

Preferred harness for this stack:

- Shared `dbtest` pool against a real Postgres + `WithTx` rollback (auto-skip when DB unreachable or `*_TEST_DB_SKIP=1`).
- Service tests: hand-written fakes on consumer interfaces — **testify `assert`/`require` only** (no `mock`/`suite`).
- Fiber helpers for context/AES-key unit tests when needed.

Do **not** default to testcontainers unless the project already standardized on them. Prefer the shared-pool + rollback pattern above.

## Style defaults

- Sentinels in `errors.go`; wrap with `%w`; one `writeErr` maps to HTTP.
- `log/slog` structured logging.
- `ctx context.Context` first on service/repo methods; Fiber v3: pass `c.RequestCtx()` into services.
- Validate at the handler edge; services enforce invariants.
- Never expose domain row structs as JSON — map through response DTOs.

## What NOT to do

- No ORM in the HTTP path by default.
- No ad-hoc `c.Status().JSON()` that bypasses the envelope.
- No `float64` money.
- No testify mock/suite.
- No business logic in handlers.
- No `init()` / package mutable state (tiny shared validator instance is the usual exception).
- No panics for expected failures; panic only on bad startup config.
- Don't add dependencies the stdlib already covers.

## References

- [architecture.md](references/architecture.md) — layout, import rules, composition root, cross-domain
- [patterns.md](references/patterns.md) — money, service/repo, state machine, errors, tests
- [fiber-v3.md](references/fiber-v3.md) — Fiber v3 pitfalls and route style
- [tooling.md](references/tooling.md) — migrations, Makefile, jobs, Docker

## Changelog

- **1.0.0 (2026-07-27)** — First publishable release: portable Fiber+pgx conventions; bridge-specific paths moved out of always-on rules; MIT license + metadata.

More Backend Frameworks skills

← All Backend Frameworks skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY