How paulbabatuyi/double-entry-bank-go works
Purpose and Entry Point
This is a Go HTTP backend for a bank-style, double-entry ledger. It exposes registration, JWT-authenticated account operations, deposits, withdrawals, transfers, transaction history, and reconciliation. Process startup and dependency wiring originate in cmd/main.go; generated OpenAPI artifacts are in docs/docs.go and docs/swagger.yaml.
HTTP API Boundary
The API layer owns routing, request/response DTOs, validation, authentication middleware, authorization checks, and Swagger endpoint exposure. Public routes cover registration, login, health, and documentation; account and ledger routes require Bearer JWTs. Primary paths: internal/api/handler.go, internal/api/middleware.go, internal/api/dto.go.
Application and Ledger Domain
Ledger is the core business boundary for balance-changing commands. It converts deposits, withdrawals, and transfers into paired debit/credit entry writes, applies account ownership rules, and provides reconciliation/history-facing operations. The service, rather than handlers, owns transaction-level accounting invariants. Primary path: internal/service/ledger.go.
Transactional Persistence
The store layer bridges domain operations to PostgreSQL and coordinates SQL transactions. Monetary operations use serializable isolation, retry serialization failures (SQLSTATE 40001), and lock account rows before changing balances. Generated sqlc code executes typed queries; raw query definitions remain the source for regeneration. Paths: internal/db/store.go, postgres/queries/accounts.sql, postgres/sqlc/db.go.
Ledger Data Model and Integrity
PostgreSQL persists users, accounts, and single-sided entry rows. Each entry is debit-or-credit, while every business movement creates balanced opposing entries. Reconciliation derives balance from SUM(credit) - SUM(debit), making entries the accounting source of truth. Schema evolution is migration-driven. Paths: postgres/migrations/000002_create_accounts_table.up.sql, postgres/migrations/000003_create_entries_table.up.sql, postgres/queries/entries.sql.
Runtime and External Dependencies
The executable runs on Go 1.24+ with chi routing, JWT middleware, zerolog logging, and Swaggo/http-swagger documentation. PostgreSQL 16 is the required durable datastore. Docker supports local/full-stack execution and container startup; deployment configuration targets Render. Paths: Dockerfile, docker-compose.yml, render.yaml.
Primary Control Flow
A protected request passes router/auth middleware, then a handler maps HTTP input to service calls. The ledger service invokes the store’s retrying serializable transaction, which locks involved accounts, updates account state, and writes matching entry records atomically. Results flow back through API mappers/responses. Account history and reconciliation take read paths through typed SQL queries rather than trusting a client-supplied balance.
Main entry points: handler.go Router and handlers · db.go Generated typed queries · main.go Application startup · ledger.go Ledger service
Components 14
Runtime
- Application startup · Wires dependencies and starts the HTTP server.
cmd/main.go - Container runtime · Supports local and full-stack startup.
docker-compose.yml
HTTP API
- Router and handlers · Owns public and protected account and ledger endpoints.
internal/api/handler.go - JWT auth middleware · Protects account and ledger routes and applies authorization checks.
internal/api/middleware.go - Request and response DTOs · Validates and maps HTTP payloads.
internal/api/dto.go - Swagger documentation · Published API specification and Swagger endpoint content.
docs/swagger.yaml
Ledger Domain
- Ledger service · Enforces ownership and double-entry invariants for monetary commands.
internal/service/ledger.go
PostgreSQL Persistence
- Transactional store · Runs serializable transactions, retries serialization failures, and locks accounts.
internal/db/store.go - Generated typed queries · Executes typed SQL against PostgreSQL.
postgres/sqlc/db.go - Account queries
postgres/queries/accounts.sql - Entry and reconciliation queries · Provides entry history and derived balance reads.
postgres/queries/entries.sql - Accounts schema migration
postgres/migrations/000002_create_accounts_table.up.sql - Entries schema migration · Defines single-sided debit or credit ledger entries.
postgres/migrations/000003_create_entries_table.up.sql - PostgreSQL 16 · Persists users, accounts, and accounting entries.
Connections 16
- Container runtime → Application startup: runs
- Application startup → Router and handlers: registers routes
- Application startup → Swagger documentation: serves docs
- Router and handlers → JWT auth middleware: protected routes
- Router and handlers → Request and response DTOs: maps payloads
- Router and handlers → Ledger service: invokes commands and reads
- JWT auth middleware → Router and handlers: authenticated request
- Ledger service → Transactional store: atomic monetary operations
- Transactional store → Generated typed queries: executes typed queries
- Generated typed queries → Account queries: generated from
- Generated typed queries → Entry and reconciliation queries: generated from
- Generated typed queries → PostgreSQL 16: reads and writes
- Accounts schema migration → PostgreSQL 16: creates account tables
- Entries schema migration → PostgreSQL 16: creates entry tables
- Ledger service → Entry and reconciliation queries: history and reconciliation
- Transactional store → PostgreSQL 16: serializable transactions