Go backend: Gin + PostgreSQL (database/sql + pgx v5 stdlib) + Testcontainers.
make docker-run # start Postgres container
make docker-down # stop Postgres container
make watch # hot reload via Air → :8080
make run # run once (no reload)
make build # compile binary
make test # all tests (requires Docker)
make itest # integration tests only (requires Docker)cmd/api/main.go # entry point — wiring and graceful shutdown only
internal/
server/server.go # Server struct, NewServer(), http.Server timeouts
server/routes.go # RegisterRoutes(), CORS, all handlers as *Server methods
database/database.go # Service interface, New() singleton, all query methods
database/database_test.go # Testcontainers integration tests
docker-compose.yml # Postgres service (reads .env)
.env # env vars — never commit secrets
Makefile # all dev commands
Read the relevant doc before implementing. These are kept in sync with the code — prefer them over general Go or Gin knowledge when they conflict.
| Topic | File |
|---|---|
| DB connection, Service interface, query patterns | docs/database.md |
| Route registration, handler pattern, CORS | docs/routing.md |
| Testcontainers setup, TestMain, test patterns | docs/testing.md |
| Error handling, when log.Fatal is allowed | docs/error-handling.md |
| All environment variables and how they are loaded | docs/environment.md |
TDD is required. Write failing tests first, then implement.
All database and cache tests run against real instances via Testcontainers. Docker must be running.
make test # unit + integration (requires Docker)
make itest # integration only
go test ./internal/usecase/... -v # usecase unit tests (no Docker needed)
go test ./internal/transport/handlers/... -v # handler unit tests (no Docker needed)
go test ./internal/infrastructure/... -v # DB + cache integration tests (requires Docker)| Layer | Package | What is mocked |
|---|---|---|
usecase/ |
package usecase |
Repository interfaces (not the DB) |
transport/handlers/ |
package handlers |
Use case interfaces |
infrastructure/database/postgres/ |
package postgres |
Nothing — real DB via Testcontainers |
infrastructure/cache/redis/ |
package redis |
Nothing — real Redis via Testcontainers |
bootstrap/ |
package bootstrap |
Pinger interface; env vars via t.Setenv |
See backend/docs/testing.md for full patterns including TestMain, table-driven tests, and mock examples.
- New route → register in
RegisterRoutes(), handler as method on*Server - New DB query → add to
Serviceinterface, implement on*service, add integration test - Return errors up the stack — no
log.Fatal/os.Exitinsideinternal/(seedocs/error-handling.mdfor the two documented exceptions) - Parameterized queries only — never
fmt.SprintfSQL - Env vars loaded automatically via
godotenv/autoloadblank imports — no explicit call needed