rhythm-backend/BACKEND_BLUEPRINT.md
Dmitri f00226a0d6
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 2m23s
logging
2026-04-19 19:09:13 +02:00

5.0 KiB

Go Backend Blueprint (Iteration Draft)

Chosen Stack

  • Framework: Gin
  • Migrations: Goose (SQL-only)
  • DB Access: SQLC (no ORM), package per bounded context
  • PostgreSQL Driver/Pool: pgx/v5 + pgxpool
  • Logging: Uber Zap (structured logs)
  • Health Probes: liveness/readiness endpoints
  • API Docs: OpenAPI (for frontend TypeScript type generation)
  • Deployment: Docker Compose on self-hosted hardware

Architecture Direction

Layering

  • cmd/api - application entrypoint and dependency wiring
  • internal/http - Gin router, handlers, middleware
  • internal/service - business logic + transaction boundaries
  • internal/db/<context> - SQLC-generated code by bounded context
  • internal/store - shared DB/Tx helpers
  • internal/auth - JWT validation + role guards
  • internal/config - env configuration loading
  • migrations/ - Goose SQL migration files
  • api/openapi/ - OpenAPI spec + generated artifacts

Transaction Strategy

  • Handlers stay thin.
  • Service layer owns DB transactions.
  • SQLC queries are called with either pool or tx using DBTX interfaces.
  • No transaction logic in handlers.

API and Runtime

API Shape

  • REST JSON API
  • Possible future WebSocket support for interactive features
  • Suggested versioning: /api/v1

Health Endpoints

  • GET /health/live - process is alive
  • GET /health/ready - DB ping succeeds (and optionally migration version check)

Logging

  • Zap JSON logs
  • Uber Zap logger will be initialized in cmd/api/main.go and injected into services/middleware (no global loggers).
  • Logs will be written directly to a file from the application, with log rotation implemented via lumberjack.
  • Correlation/request ID in middleware
  • Structured error logging from middleware and service boundaries

Database and Migrations

Goose

  • SQL-only migrations
  • Keep up/down migration scripts
  • Run on startup in non-prod optional, required in CI/CD/deploy step
  • Migrations are securely bundled into the binary using Go's embed.FS from a dedicated migrations package to isolate them from internal db logic.

SQLC

  • Generate one package per bounded context (similar to Spring repository modules)
  • Keep SQL in context directories (query.sql, models.sql style)
  • Service layer composes multiple repositories when needed

Work in Progress Snapshot

  • sqlc.yaml is now configured for PostgreSQL with schema from migrations/*.sql
  • First bounded context added: internal/db/users
  • Current users SQLC artifacts generated:
    • db.go, models.go, queries.sql.go, querier.go
  • Current SQLC generation options in use:
    • sql_package: pgx/v5
    • emit_interface: true (generated Querier interface)
    • emit_json_tags: false (can be revisited if API structs are returned directly)
  • Initial queries implemented for users: GetUser, CreateUser, DeleteUser
  • Goose startup migrations have been wired into cmd/api/main.go, utilizing the embed.FS strategy and logging via Zap adapter.
  • DB pool is successfully wired in cmd/api.
  • Environment-aware Zap logger is configured (development vs production).
  • Next Planned: Implement application-level file logging with rotation (using lumberjack), and build initial Gin API routes for health checks.

Testing Approach (Beginner-Friendly)

  • Unit tests for pure service logic (no DB)
  • Integration tests for SQLC repositories with real Postgres via Docker

DB Interface Testing (via SQLC Querier)

  • Treat generated SQLC interfaces (e.g. usersdb.Querier) as service dependencies
  • For service unit tests, provide a fake/mock implementation of Querier
  • Focus unit tests on business rules, branching, and error mapping (not SQL behavior)
  • Keep SQL correctness in integration tests against real Postgres
  • This split gives fast unit tests plus high-confidence DB integration coverage

Phase 2

  • HTTP handler tests with httptest
  • Auth middleware tests

Phase 3

  • Minimal end-to-end happy path tests

OpenAPI + Frontend Type Generation

  • Keep spec in repo at api/openapi/openapi.yaml
  • Generate frontend TypeScript types from OpenAPI (e.g. openapi-typescript)
  • Optionally serve Swagger UI from backend

Deployment

  • Docker Compose for app + postgres
  • Healthcheck in compose should target readiness endpoint
  • Env-based configuration (.env, .env.example)

Pending Decisions

  1. JWT signing:

    • HS256 shared secret (simple)
    • RS256 keypair (better long-term)
  2. Token model:

    • Access token only
    • Access + refresh token
  3. Initial roles:

    • USER / ADMIN
    • USER / MODERATOR / ADMIN
  4. OpenAPI workflow:

    • Contract-first (spec first)
    • Code-first annotations
  5. CORS policy:

    • Allowed frontend origins in dev/prod
  6. Schema strategy:

    • Single schema (public) confirmation
  7. Initial bounded contexts:

    • e.g. auth, users, rooms (or your domain names)

Iteration Notes

  • This file is intentionally a working draft.
  • We will refine decisions and turn this into a concrete implementation checklist.