Documentation
¶
Overview ¶
Package postgres provides a Postgres-backed implementation of service.Repository for the identity service.
This is an alternative to the EntDB-backed repository. The two are interchangeable from the AuthService's point of view: both implement the same service.Repository interface.
Why Postgres ¶
Postgres is well understood, ubiquitous in production environments, and ships with a mature ops toolkit (pg_dump, pg_basebackup, replicas, PITR via WAL archiving). It is the right default for teams that want to run identity without taking a dependency on the tenant-shard-db stack.
Driver choice ¶
The implementation uses pgx/v5 directly (not via database/sql). pgxpool.Pool gives us a tuneable connection pool; pgx is also faster than database/sql and exposes Postgres-specific features (LISTEN / NOTIFY, COPY, JSONB native typing) that we may want later.
Migrations ¶
Schema DDL lives under migrations/ and is applied via golang-migrate/migrate using the embed.FS source. By default New() does NOT run pending migrations on connect — production deploys run migrations out-of-band as a separate Job, so a rolling rollout never races two replicas to apply the same change. Set Config.AutoMigrate to true (or GATEWAY_POSTGRES_AUTO_MIGRATE=true) only for local dev and single-replica environments.
Multi-tenancy ¶
Every table carries a tenant_id text not null column and uniqueness constraints are scoped to (tenant_id, ...). A pgRepository instance is constructed with a single tenant_id and writes/reads only that tenant's rows.
Error mapping ¶
Postgres unique-violation errors (SQLSTATE 23505) are mapped to service.ErrAlreadyExists by errors.go::wrapPgErr. ErrNoRows is surfaced as a nil result (not an error), matching the existing in-memory and EntDB drivers.
Index ¶
Constants ¶
const DefaultConnTimeout = 5 * time.Second
DefaultConnTimeout is used when Config.ConnTimeout is zero.
const DefaultMaxConns int32 = 25
DefaultMaxConns is used when Config.MaxConns is zero.
Variables ¶
This section is empty.
Functions ¶
func New ¶
New constructs a Postgres-backed repository:
- Parse / validate cfg.
- Open a pgxpool with cfg.MaxConns, cfg.ConnTimeout.
- Optionally run pending migrations (cfg.AutoMigrate=true).
- Ping to fail fast on a misconfigured DSN.
The returned store implements both service.Repository and service.DB. The caller is responsible for keeping the *pgRepository alive for the lifetime of the service; pool resources are released by Close().
Types ¶
type Config ¶
type Config struct {
DSN string
MaxConns int32
ConnTimeout time.Duration
AutoMigrate bool
TenantID string
}
Config controls how the postgres repository connects to its database.
DSN is the libpq-style connection string, e.g.
postgres://user:pass@host:5432/dbname?sslmode=disable
MaxConns caps the underlying pgxpool. A zero value means "use the pgxpool default" (currently 4 + GOMAXPROCS-ish). 25 is the suggested default for an identity service node (see DefaultMaxConns).
ConnTimeout is the per-acquire timeout used when checking a connection out of the pool. It does NOT bound the total query time — callers are still responsible for passing a context with the appropriate deadline.
AutoMigrate controls whether New() applies pending schema migrations on first connect. In CI / dev / test we want true (the default); in strict production deploys teams may flip it to false and run `migrate ... up` from a deploy pipeline instead.
TenantID is the tenant whose rows this repository instance writes and reads. Multi-tenant deployments construct one repository per tenant; the most common single-tenant config plumbs cfg.DefaultTenantID straight through.
func ConfigFromEnv ¶
ConfigFromEnv reads Config values from GATEWAY_POSTGRES_* env vars. It is a convenience for callers that don't want to plumb each field through their own config struct. tenantID is passed in (rather than read from env) because identity already plumbs cfg.DefaultTenantID.