# Go Backend Blueprint (Iteration Draft) ## IDEAS - instead of elastic search use ts vector and ts query to allow easy iseeu searching for smooth experience (pg vector?) ## Chosen Stack - **Framework:** Gin - **Dependency Injection:** Uber fx (runtime DI, Spring-like autowiring) - **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 fx DI wiring - `internal/http` - Gin Server provider, `router.go` for fx mapping - `internal/http/api/...` - Domain handlers structured by route hierarchy (e.g., `api/health`, `api/protected/users`) - `internal/service` - business logic + transaction boundaries - `internal/db/` - 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. ### Dependency Injection (fx) - Use `fx.Provide` to register constructors (config, logger, db pool, server, handlers). - Use `fx.Invoke` in `main.go` to orchestrate route mapping and application startup. - `internal/http/router.go` acts as the central route mapping orchestrator injected via `fx.Invoke`. - Each domain handler (`internal/http/api/*/handler.go`) receives its dependencies via constructor injection. - Lifecycle hooks (`fx.Lifecycle`) are used for graceful startup/shutdown of the HTTP server and DB pool. --- ## API and Runtime ### API Shape - REST JSON API - Possible future WebSocket support for interactive features - Suggested versioning: `/api/v1` ### Health Endpoints - `GET /api/health/live` - process is alive - `GET /api/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). - **fx DI wiring** is being introduced to replace manual dependency injection in `main.go`. HTTP layer will use domain handlers structured by route hierarchy (`internal/http/api/...`). - **Next Planned:** Implement fx providers for Gin server and DB pool, build `internal/http/server.go`, `internal/http/router.go`, and initial domain handlers (`health`, `auth`). --- ## Testing Approach (Beginner-Friendly) ### Phase 1 (Recommended Start) - 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.