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
- func Migrate(dsn string) error
- func New(ctx context.Context, cfg Config) (*pgRepository, error)
- type AutoFormStore
- type Config
- type DomainStore
- func (s *DomainStore) CreateDomain(ctx context.Context, d *service.Domain) (string, error)
- func (s *DomainStore) GetDomain(ctx context.Context, projectID, domainID string) (*service.Domain, error)
- func (s *DomainStore) GetDomainByName(ctx context.Context, projectID, domain string) (*service.Domain, error)
- func (s *DomainStore) ListDomainsByTenant(ctx context.Context, projectID, tenantID string) ([]*service.Domain, error)
- func (s *DomainStore) SetDomainStatus(ctx context.Context, projectID, domainID, status string, verifiedAtMs int64) error
- type InvitationStore
- func (s *InvitationStore) CreateInvitation(ctx context.Context, inv *service.TenantInvitation) (string, error)
- func (s *InvitationStore) GetInvitationByTokenHash(ctx context.Context, projectID, tokenHash string) (*service.TenantInvitation, error)
- func (s *InvitationStore) ListInvitationsForTenant(ctx context.Context, projectID, tenantID string) ([]*service.TenantInvitation, error)
- func (s *InvitationStore) SetInvitationStatus(ctx context.Context, projectID, invitationID, status string, ...) error
- type LoginPolicyStore
- type MembershipStore
- func (s *MembershipStore) GetMembership(ctx context.Context, projectID, tenantID, userID string) (*service.TenantMembership, error)
- func (s *MembershipStore) ListMembershipsForTenant(ctx context.Context, projectID, tenantID string) ([]*service.TenantMembership, error)
- func (s *MembershipStore) ListMembershipsForUser(ctx context.Context, projectID, userID string) ([]*service.TenantMembership, error)
- func (s *MembershipStore) RemoveMembership(ctx context.Context, projectID, tenantID, userID string) error
- func (s *MembershipStore) UpsertMembership(ctx context.Context, m *service.TenantMembership) (string, error)
- type Project
- type ProjectAuthDomain
- type ProjectCredential
- type ProjectStore
- func (s *ProjectStore) CreateProject(ctx context.Context, p *Project) (string, error)
- func (s *ProjectStore) CreateProjectAuthDomain(ctx context.Context, d *ProjectAuthDomain) (string, error)
- func (s *ProjectStore) CreateProjectCredential(ctx context.Context, c *ProjectCredential) (string, error)
- func (s *ProjectStore) EnsureAuthDomain(ctx context.Context, projectID, hostname string, isPrimary bool, ...) error
- func (s *ProjectStore) EnsureDefaultProject(ctx context.Context, projectID, storageScopeID, name string) (*Project, error)
- func (s *ProjectStore) GetProjectByAuthHostname(ctx context.Context, hostname string) (*Project, error)
- func (s *ProjectStore) GetProjectByID(ctx context.Context, projectID string) (*Project, error)
- func (s *ProjectStore) GetProjectByStorageScope(ctx context.Context, storageScopeID string) (*Project, error)
- func (s *ProjectStore) GetProjectCredentialByPublicID(ctx context.Context, publicID string) (*ProjectCredential, error)
- func (s *ProjectStore) ListProjectAuthDomains(ctx context.Context, projectID string) ([]*ProjectAuthDomain, error)
- func (s *ProjectStore) ResolveByCredential(ctx context.Context, publicID string) (*service.ResolvedProject, error)
- func (s *ProjectStore) ResolveByHostname(ctx context.Context, hostname string) (*service.ResolvedProject, error)
- func (s *ProjectStore) RevokeProjectCredential(ctx context.Context, credentialID string, atMs int64) error
- type TenantStore
- func (s *TenantStore) CreateTenant(ctx context.Context, t *service.Tenant) (string, error)
- func (s *TenantStore) GetTenant(ctx context.Context, projectID, tenantID string) (*service.Tenant, error)
- func (s *TenantStore) GetTenantByPrimaryDomain(ctx context.Context, projectID, domain string) (*service.Tenant, error)
- func (s *TenantStore) ListTenants(ctx context.Context, projectID string) ([]*service.Tenant, error)
- func (s *TenantStore) SetTenantStatus(ctx context.Context, projectID, tenantID, status string) error
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 Migrate ¶ added in v0.15.0
Migrate applies all pending schema migrations to the Postgres database at dsn, then returns. It is idempotent — a fully-migrated database is a no-op — and safe to run concurrently with other instances: the underlying runner holds a Postgres advisory lock for the duration, so exactly one caller applies the migrations and the rest wait, then no-op. It is the entry point behind the `identity migrate` deploy step (the explicit alternative to GATEWAY_POSTGRES_AUTO_MIGRATE).
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 AutoFormStore ¶ added in v0.17.0
type AutoFormStore struct {
// contains filtered or unexported fields
}
AutoFormStore turns a verified company-email signup into governance rows.
func NewAutoFormStore ¶ added in v0.17.0
func NewAutoFormStore(r *pgRepository) *AutoFormStore
NewAutoFormStore builds an auto-formation store sharing the repository's pool.
func (*AutoFormStore) EnsureTenantForDomain ¶ added in v0.17.0
func (s *AutoFormStore) EnsureTenantForDomain(ctx context.Context, projectID, domain, userID string) (string, error)
EnsureTenantForDomain idempotently ensures a latent Tenant + its email Domain exist for (projectID, domain) and records a domain-derived membership for userID. See the interface doc for the concurrency contract: tenant+domain are created in one transaction so a lost race leaves no orphan tenant.
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.
type DomainStore ¶ added in v0.17.0
type DomainStore struct {
// contains filtered or unexported fields
}
DomainStore persists Domains within a Project.
func NewDomainStore ¶ added in v0.17.0
func NewDomainStore(r *pgRepository) *DomainStore
NewDomainStore builds a domain store sharing the repository's pool.
func (*DomainStore) CreateDomain ¶ added in v0.17.0
CreateDomain inserts a domain. ProjectID, TenantID and Domain are required; a blank id is generated and written back. A duplicate (project_id, lower(domain)) surfaces service.ErrAlreadyExists.
func (*DomainStore) GetDomain ¶ added in v0.17.0
func (s *DomainStore) GetDomain(ctx context.Context, projectID, domainID string) (*service.Domain, error)
GetDomain returns the domain by id within a project, or (nil, nil).
func (*DomainStore) GetDomainByName ¶ added in v0.17.0
func (s *DomainStore) GetDomainByName(ctx context.Context, projectID, domain string) (*service.Domain, error)
GetDomainByName returns the domain row for a name (case-insensitive) within a project, or (nil, nil).
func (*DomainStore) ListDomainsByTenant ¶ added in v0.17.0
func (s *DomainStore) ListDomainsByTenant(ctx context.Context, projectID, tenantID string) ([]*service.Domain, error)
ListDomainsByTenant returns every domain bound to a tenant, newest first.
func (*DomainStore) SetDomainStatus ¶ added in v0.17.0
func (s *DomainStore) SetDomainStatus(ctx context.Context, projectID, domainID, status string, verifiedAtMs int64) error
SetDomainStatus transitions a domain's status and, when verifying, stamps verified_at_ms (0 defaults to now on a verify). Unknown ids are a no-op.
type InvitationStore ¶ added in v0.17.0
type InvitationStore struct {
// contains filtered or unexported fields
}
InvitationStore persists TenantInvitations within a Project.
func NewInvitationStore ¶ added in v0.17.0
func NewInvitationStore(r *pgRepository) *InvitationStore
NewInvitationStore builds a store sharing the repository's pool.
func (*InvitationStore) CreateInvitation ¶ added in v0.17.0
func (s *InvitationStore) CreateInvitation(ctx context.Context, inv *service.TenantInvitation) (string, error)
CreateInvitation atomically enforces one-open-invite: in a single transaction it revokes any existing pending invitation for the same (project, tenant, lower(email)) and inserts the new one. This is the authoritative enforcement (the partial unique index is defense-in-depth, and the memory/entdb drivers — should they ever gain invitations — must match these revoke-then-insert semantics).
func (*InvitationStore) GetInvitationByTokenHash ¶ added in v0.17.0
func (s *InvitationStore) GetInvitationByTokenHash(ctx context.Context, projectID, tokenHash string) (*service.TenantInvitation, error)
GetInvitationByTokenHash resolves an invitation by its hashed token within a project, or (nil, nil).
func (*InvitationStore) ListInvitationsForTenant ¶ added in v0.17.0
func (s *InvitationStore) ListInvitationsForTenant(ctx context.Context, projectID, tenantID string) ([]*service.TenantInvitation, error)
ListInvitationsForTenant returns every invitation in a tenant, newest first.
func (*InvitationStore) SetInvitationStatus ¶ added in v0.17.0
func (s *InvitationStore) SetInvitationStatus(ctx context.Context, projectID, invitationID, status string, acceptedAtMs int64) error
SetInvitationStatus transitions an invitation's status and, when accepting, stamps accepted_at_ms (0 defaults to now on accept). Unknown ids are a no-op.
type LoginPolicyStore ¶ added in v0.17.0
type LoginPolicyStore struct {
// contains filtered or unexported fields
}
LoginPolicyStore persists per-tenant login policies within a Project.
func NewLoginPolicyStore ¶ added in v0.17.0
func NewLoginPolicyStore(r *pgRepository) *LoginPolicyStore
NewLoginPolicyStore builds a store sharing the repository's pool.
func (*LoginPolicyStore) GetLoginPolicy ¶ added in v0.17.0
func (s *LoginPolicyStore) GetLoginPolicy(ctx context.Context, projectID, tenantID string) (*service.LoginPolicy, error)
GetLoginPolicy returns the policy for (projectID, tenantID), or (nil, nil) when none is set.
func (*LoginPolicyStore) UpsertLoginPolicy ¶ added in v0.17.0
func (s *LoginPolicyStore) UpsertLoginPolicy(ctx context.Context, p *service.LoginPolicy) (string, error)
UpsertLoginPolicy inserts or replaces the policy for (ProjectID, TenantID). On conflict it updates the policy fields and stamps updated_at_ms, leaving id and created_at_ms intact. Returns the id of the resulting row.
type MembershipStore ¶ added in v0.17.0
type MembershipStore struct {
// contains filtered or unexported fields
}
MembershipStore persists TenantMemberships within a Project.
func NewMembershipStore ¶ added in v0.17.0
func NewMembershipStore(r *pgRepository) *MembershipStore
NewMembershipStore builds a store sharing the repository's pool.
func (*MembershipStore) GetMembership ¶ added in v0.17.0
func (s *MembershipStore) GetMembership(ctx context.Context, projectID, tenantID, userID string) (*service.TenantMembership, error)
GetMembership returns the membership for (project, tenant, user), or (nil, nil).
func (*MembershipStore) ListMembershipsForTenant ¶ added in v0.17.0
func (s *MembershipStore) ListMembershipsForTenant(ctx context.Context, projectID, tenantID string) ([]*service.TenantMembership, error)
ListMembershipsForTenant returns every membership in a tenant, newest first.
func (*MembershipStore) ListMembershipsForUser ¶ added in v0.17.0
func (s *MembershipStore) ListMembershipsForUser(ctx context.Context, projectID, userID string) ([]*service.TenantMembership, error)
ListMembershipsForUser returns every membership a user holds across a project's tenants, newest first.
func (*MembershipStore) RemoveMembership ¶ added in v0.17.0
func (s *MembershipStore) RemoveMembership(ctx context.Context, projectID, tenantID, userID string) error
RemoveMembership deletes the membership for (project, tenant, user). Unknown rows are a no-op.
func (*MembershipStore) UpsertMembership ¶ added in v0.17.0
func (s *MembershipStore) UpsertMembership(ctx context.Context, m *service.TenantMembership) (string, error)
UpsertMembership inserts or, on a (project, tenant, user) conflict, updates source/role/status in place (keeping id + created_at_ms) and stamps updated_at_ms. Returns the surviving row id.
type Project ¶ added in v0.15.0
type Project struct {
ID string
StorageScopeID string
Name string
Status string // active | suspended
ConfigJSON string // JSON object; "" is normalised to "{}".
CreatedAtMs int64
UpdatedAtMs int64
}
Project is a control-plane registry row: one logical, control-plane isolation entity (a Firebase-style project) mapped onto exactly one physical storage scope (shard) via StorageScopeID.
type ProjectAuthDomain ¶ added in v0.15.0
type ProjectAuthDomain struct {
ID string
ProjectID string
Hostname string
IsPrimary bool
VerifiedAtMs int64
CreatedAtMs int64
}
ProjectAuthDomain is a per-project serving hostname. One host resolves to exactly one project (Hostname is globally unique, case-insensitive), so the Host header alone can resolve a project.
type ProjectCredential ¶ added in v0.15.0
type ProjectCredential struct {
ID string
ProjectID string
Kind string // publishable | secret | mtls
PublicID string
SecretHash string
Status string // active | revoked
CreatedAtMs int64
LastUsedAtMs int64
RevokedAtMs int64
}
ProjectCredential is a lookup key used to resolve a project on a request, by its globally-unique PublicID.
type ProjectStore ¶ added in v0.15.0
type ProjectStore struct {
// contains filtered or unexported fields
}
ProjectStore is the Postgres-backed, control-plane registry store. It is platform-global (not project/tenant-scoped) and shares its caller's connection pool.
func NewProjectStore ¶ added in v0.15.0
func NewProjectStore(r *pgRepository) *ProjectStore
NewProjectStore builds a control-plane store that shares the given repository's connection pool. The store must NOT be closed independently — closing the owning *pgRepository releases the pool for every derived store.
func (*ProjectStore) CreateProject ¶ added in v0.15.0
CreateProject inserts a project. StorageScopeID is required and globally unique; a duplicate surfaces service.ErrAlreadyExists. The id is caller-supplied (random hex when empty) so it is known without a RETURNING round-trip; the assigned id is written back to p.ID.
func (*ProjectStore) CreateProjectAuthDomain ¶ added in v0.15.0
func (s *ProjectStore) CreateProjectAuthDomain(ctx context.Context, d *ProjectAuthDomain) (string, error)
CreateProjectAuthDomain inserts a serving hostname for a project. Hostname is globally unique on lower(hostname) — a duplicate (in any case) surfaces service.ErrAlreadyExists. At most one is_primary domain is allowed per project (partial unique index); a second primary for the same project likewise surfaces service.ErrAlreadyExists. The id is caller-supplied (random hex when empty) and written back to d.ID.
func (*ProjectStore) CreateProjectCredential ¶ added in v0.15.0
func (s *ProjectStore) CreateProjectCredential(ctx context.Context, c *ProjectCredential) (string, error)
CreateProjectCredential inserts a lookup credential for a project. PublicID is required and globally unique; a duplicate surfaces service.ErrAlreadyExists. The id is caller-supplied (random hex when empty) and written back to c.ID.
func (*ProjectStore) EnsureAuthDomain ¶ added in v0.17.0
func (s *ProjectStore) EnsureAuthDomain(ctx context.Context, projectID, hostname string, isPrimary bool, verifiedAtMs int64) error
EnsureAuthDomain idempotently ensures hostname is a serving auth-domain of projectID. It is safe to call on every boot: if the hostname already exists it is a no-op when it belongs to projectID, and an error when it belongs to a DIFFERENT project (a misconfiguration the operator must resolve). verifiedAtMs marks the domain verified at seed time — used for deployer-owned domains, which need no DNS challenge. A concurrent creator is tolerated by re-reading the winner. Note: passing isPrimary=true when the project already has a different primary surfaces ErrAlreadyExists (the per-project primary partial-unique); changing the primary host is an explicit reconfiguration, not a silent re-seed.
func (*ProjectStore) EnsureDefaultProject ¶ added in v0.15.0
func (s *ProjectStore) EnsureDefaultProject(ctx context.Context, projectID, storageScopeID, name string) (*Project, error)
EnsureDefaultProject idempotently ensures the default Project exists, mapped onto the given storage scope (typically GATEWAY_DEFAULT_TENANT_ID). It is safe to call on every boot and from multiple instances at once: it returns the existing project when one is already present (looked up by id, then by storage scope), and otherwise creates it, tolerating a concurrent creator (an ErrAlreadyExists race is resolved by re-reading the row).
The default project is a logical control-plane entity that POINTS AT the storage scope via StorageScopeID — it is not the same value as the storage id, and the two must not be conflated.
If the storage scope is already mapped to a project (storage_scope_id is globally unique), that existing project is returned even when its id differs from projectID — the scope binding wins and no second project is created for the same scope.
func (*ProjectStore) GetProjectByAuthHostname ¶ added in v0.15.0
func (s *ProjectStore) GetProjectByAuthHostname(ctx context.Context, hostname string) (*Project, error)
GetProjectByAuthHostname resolves a project from a request's Host header. The hostname match is case-insensitive (lower(hostname)), matching the global unique index, so one host resolves to exactly one project. Returns (nil, nil) when no auth domain matches the host.
func (*ProjectStore) GetProjectByID ¶ added in v0.15.0
GetProjectByID returns the project with the given id, or (nil, nil) when no such project exists.
func (*ProjectStore) GetProjectByStorageScope ¶ added in v0.15.0
func (s *ProjectStore) GetProjectByStorageScope(ctx context.Context, storageScopeID string) (*Project, error)
GetProjectByStorageScope returns the single project mapped onto the given physical storage scope, or (nil, nil) when none is. storage_scope_id is globally unique, so this resolves at most one project.
func (*ProjectStore) GetProjectCredentialByPublicID ¶ added in v0.15.0
func (s *ProjectStore) GetProjectCredentialByPublicID(ctx context.Context, publicID string) (*ProjectCredential, error)
GetProjectCredentialByPublicID resolves a credential (and thus its owning project_id, kind and status) by its globally-unique public_id, or returns (nil, nil) when none matches. This is the key-based per-request project-resolution path.
func (*ProjectStore) ListProjectAuthDomains ¶ added in v0.15.0
func (s *ProjectStore) ListProjectAuthDomains(ctx context.Context, projectID string) ([]*ProjectAuthDomain, error)
ListProjectAuthDomains returns every auth domain for a project, ordered primary-first then by creation time, so callers can pick the link-building host deterministically. An unknown project yields an empty slice.
func (*ProjectStore) ResolveByCredential ¶ added in v0.16.0
func (s *ProjectStore) ResolveByCredential(ctx context.Context, publicID string) (*service.ResolvedProject, error)
ResolveByCredential resolves the active project an active credential public id belongs to. A revoked credential, a suspended project, an unknown id, or a blank id is a clean miss (nil, nil); only an infrastructure failure returns an error.
func (*ProjectStore) ResolveByHostname ¶ added in v0.16.0
func (s *ProjectStore) ResolveByHostname(ctx context.Context, hostname string) (*service.ResolvedProject, error)
ResolveByHostname resolves the active project a serving hostname maps onto (case-insensitive). An unmapped hostname, a suspended project, or a blank hostname is a clean miss (nil, nil).
func (*ProjectStore) RevokeProjectCredential ¶ added in v0.15.0
func (s *ProjectStore) RevokeProjectCredential(ctx context.Context, credentialID string, atMs int64) error
RevokeProjectCredential marks a credential revoked at atMs (defaulting to now when zero). Revoking is idempotent: an already-revoked or non-existent credential is a no-op that returns nil. A revoked credential no longer resolves a project for new requests, though the row is retained for audit.
type TenantStore ¶ added in v0.17.0
type TenantStore struct {
// contains filtered or unexported fields
}
TenantStore persists Tenants within a Project.
func NewTenantStore ¶ added in v0.17.0
func NewTenantStore(r *pgRepository) *TenantStore
NewTenantStore builds a tenant store sharing the repository's pool. Do not close it independently; closing the *pgRepository releases the pool.
func (*TenantStore) CreateTenant ¶ added in v0.17.0
CreateTenant inserts a tenant. ProjectID is required; a blank id is generated and written back to t.ID.
func (*TenantStore) GetTenant ¶ added in v0.17.0
func (s *TenantStore) GetTenant(ctx context.Context, projectID, tenantID string) (*service.Tenant, error)
GetTenant returns the tenant by id within a project, or (nil, nil).
func (*TenantStore) GetTenantByPrimaryDomain ¶ added in v0.17.0
func (s *TenantStore) GetTenantByPrimaryDomain(ctx context.Context, projectID, domain string) (*service.Tenant, error)
GetTenantByPrimaryDomain returns the tenant whose primary_domain equals domain (case-insensitive) within a project, or (nil, nil). A blank domain never matches.
func (*TenantStore) ListTenants ¶ added in v0.17.0
ListTenants returns every tenant in a project, newest first.
func (*TenantStore) SetTenantStatus ¶ added in v0.17.0
func (s *TenantStore) SetTenantStatus(ctx context.Context, projectID, tenantID, status string) error
SetTenantStatus transitions a tenant's status and stamps updated_at. Unknown ids are a no-op.
Source Files
¶
- config.go
- db.go
- doc.go
- email_change.go
- email_verification.go
- errors.go
- identity_verification.go
- invitation.go
- login_challenge.go
- login_policy_store.go
- membership_store.go
- migrate.go
- migrations.go
- oauth_identity.go
- oauth_one_time_code.go
- organization.go
- passkey.go
- password_reset.go
- passwordless.go
- phone.go
- project_resolver.go
- project_store.go
- qr_login.go
- recovery_code.go
- refresh_token.go
- repo.go
- session.go
- sweeper.go
- tenant_autoform.go
- tenant_store.go
- totp.go
- tracepool.go
- user.go