Skip to main content

Architecture

This guide describes the implementation in this checkout. The application profile records its purpose and ownership gaps; conventions define the rules for changing the design.

Components and boundaries​

The composition root runs one Go process containing HTTP and gRPC servers, a shared authentication service, persistence and cache adapters, an event router, and background workers.

The HTTP adapters and gRPC adapters translate transport requests into service inputs. HTTP exposes signup, login, token refresh, logout, and user management; gRPC exposes user management. The OpenAPI contracts and Protobuf contract define those interfaces.

The authentication service owns business operations, sessions, and token behavior. Feature domain/ packages hold service inputs and errors; models/ packages hold persistence models; repositories own database access. Dependency interfaces live beside their consumers.

Source map​

Use this map to find the owner of a behavior before editing it. Follow a request from its contract through the adapter, service, and repository; follow asynchronous effects through the outbox and subscriber.

ConcernSource ownerUse it to locate
Composition and lifecyclecmd/appDependency construction, registration, probes, and shutdown
API definitionsapi/openapi and api/protoHTTP and gRPC source contracts; generated output lives in api/gen/
Authentication behaviorinternal/authService operations, transport adapters, authorization, models, and repository
Shared transport behaviorinternal/apiServers, middleware, interceptors, validation, and error conversion
Persistence and migrationsinternal/database and migratePools, transaction context, engine-specific schema and seed data
Asynchronous effectsinternal/outbox and internal/eventsDurable message records, publishing, retries, and broker adapters
Cache and configurationinternal/cache and internal/configCache adapters, settings, defaults, and validation
Operational signalsinternal/metrics and infraMetric helpers, database observers, dashboard, and deployment configuration
Behavioral evidenceAdjacent *_test.go files and testsUnit cases, integration checks, resilience scenarios, and load scripts

Edit source contracts and consumer interfaces before using the generation workflow. Generated clients, handlers, and mocks describe the generated interface; their source definitions own changes to it.

Requests and persistence​

Services and worker handlers establish transaction boundaries through WithTransaction. They pass the resulting context to all participating repository calls so a business write and its required outbox message commit or roll back together.

Repositories use the primary database for writes and reads requiring immediate consistency. GetReadDB can use the configured replica where lag is acceptable; within a transaction it uses that transaction. Backend selection and persistence defaults are documented in configuration.

For signup and user creation, update, and deletion, the authentication service records the user change and its event in the same transaction. Login and logout record events on a best-effort basis after creating or revoking a session: an event write failure is logged and does not undo the successful authentication operation. These events therefore do not provide a complete audit guarantee for every operation.

Event delivery​

The outbox service stores pending messages in the application's SQL database. The publisher polls due messages, sends them through the event router, and records successful publication. Transient failures remain pending with a bounded exponential retry delay; permanent failures are marked failed.

Publication and the database update that marks a message processed are separate operations. A message can be delivered again if publication succeeds but that update does not commit. Consumers must handle duplicate delivery. The authentication subscriber records user history and deduplicates inserts by event ID in its repository.

The router applies consumer retries and dead-letter handling. Outbox publication retries and consumer retries are different stages: a processed outbox row establishes publication, while consumer completion must be observed separately. The default gochan backend runs in process and is not durable. The none backend accepts and discards publication. External broker options and provisioning settings are described in configuration.

Background work​

WorkerResponsibility
Outbox publisherPublish pending messages and record retry or completion state
Outbox cleanerRemove processed messages after retention; retain pending and failed messages
Authentication event subscriberTurn authentication events into user history records
Token usage updaterPersist buffered token usage information
Session cleanerRemove sessions according to the configured retention policy

The workers are implemented under outbox and authentication. Their polling, batch, timeout, and retention settings are defined in the configuration model.

Process lifecycle​

Startup loads and validates configuration, initializes dependencies, and applies migrations before serving requests. SQLite migrations use the application's database pool so an in-memory database survives migration initialization. MySQL and PostgreSQL migrations run against the primary before opening the application's pool.

The composition root registers event subscriptions before starting the router and the outbox publisher. It then starts HTTP and gRPC serving. Readiness includes database and cache checks; liveness tracks terminal serving and router failures. Broker connectivity and completion of individual messages are not readiness checks.

On a termination signal, the process cancels its application context, becomes unready, waits for probe propagation, and closes components within configured deadlines. A terminal server or router error fails liveness and readiness; the process relies on supervision for restart and still waits for a signal to enter shutdown. See operations for probes, shutdown settings, and failure investigation.

Evidence and open decisions​

These flows are described by the current source and exercised by authentication unit tests, outbox publisher tests, and integration tests. Follow the development workflow to run the relevant suites.

Application-specific business boundaries, capacity targets, availability objectives, and production topology are still undecided. Record required outcomes in requirements and significant choices in decisions; update this guide when they change the implementation.


Source: docs/handbook/architecture.md. Revision: 3841815ceb9e.