users

package module
v0.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 26, 2026 License: MIT Imports: 2 Imported by: 0

README

go-users

go-users provides user management commands, queries, migrations, and scope controls that sit behind admin transports. Everything is transport agnostic and can be wired to HTTP, gRPC, jobs, or CLI pipelines.

Package map

  • service: builds the service façade and validates injected repositories.
  • command: lifecycle, invite, password reset, role, profile, preference, and activity handlers.
  • query: inventory, role, assignment, profile, preference, and activity read models.
  • preferences: resolver helpers for scoped preference trees.
  • scope: guard, policies, and resolver utilities.
  • registry: Bun helpers for registering SQL migrations and schema metadata.
  • activity: Bun repository, ActivitySink helpers, and fixtures for audit logging (see activity/README.md).
  • docs and examples: runnable references for transports, guards, and schema feeds.

Prerequisites

  • Go 1.23+.
  • A repository implementation for each interface located in pkg/types.
  • Access to a SQL database when using the bundled migrations (PostgreSQL or SQLite).

Quick start

  1. go get github.com/goliatone/go-users.
  2. Implement the interfaces in pkg/types or reuse the Bun repositories under activity, preferences, and registry.
  3. Provide a scope resolver and authorization policy if multitenancy is required.
  4. Wire activity by injecting an ActivitySink/ActivityRepository (Bun or custom) and use helpers (activity.BuildRecordFromActor or activity.BuildRecordFromUUID) to construct records; add a channel via activity.WithChannel and override scope/timestamps via activity.WithTenant, activity.WithOrg, or activity.WithOccurredAt when needed.
  5. Call service.New and expose the returned commands and queries through your transport.
  6. Run the SQL migrations under data/sql/migrations before serving traffic.
Wiring the service
package main

import (
	featuregate "github.com/goliatone/go-featuregate/gate"
	"github.com/goliatone/go-users/pkg/types"
	"github.com/goliatone/go-users/service"
)

type Dependencies struct {
	AuthRepo             types.AuthRepository
	InventoryRepo        types.UserInventoryRepository
	ActivityRepo         types.ActivityRepository
	ActivitySink         types.ActivitySink
	ProfileRepo          types.ProfileRepository
	PreferenceRepo       types.PreferenceRepository
	PreferenceResolver   service.PreferenceResolver
	RoleRegistry         types.RoleRegistry
	ScopeResolver        types.ScopeResolver
	AuthorizationPolicy  types.AuthorizationPolicy
	Hooks                types.Hooks
	Logger               types.Logger
	FeatureGate          featuregate.FeatureGate
}

func buildService(deps Dependencies) *service.Service {
	return service.New(service.Config{
		AuthRepository:       deps.AuthRepo,
		InventoryRepository:  deps.InventoryRepo,
		ActivityRepository:   deps.ActivityRepo,
		ActivitySink:         deps.ActivitySink,
		ProfileRepository:    deps.ProfileRepo,
		PreferenceRepository: deps.PreferenceRepo,
		RoleRegistry:         deps.RoleRegistry,
		PreferenceResolver:   deps.PreferenceResolver,
		ScopeResolver:        deps.ScopeResolver,
		AuthorizationPolicy:  deps.AuthorizationPolicy,
		Hooks:                deps.Hooks,
		Logger:               deps.Logger,
		FeatureGate:          deps.FeatureGate,
	})
}

Check service.Service.Ready or HealthCheck before wiring transports.

Commands

  • UserLifecycleTransition and BulkUserTransition: lifecycle state changes with policy enforcement.
  • UserInvite and UserPasswordReset: invite token and reset token workflows.
  • CreateRole, UpdateRole, DeleteRole: custom role CRUD with registry notifications.
  • AssignRole and UnassignRole: "actor-to-role" assignments, with guard checks.
  • ActivityLog: structured audit trails stored through the configured repository or sink.
  • ProfileUpsert, PreferenceUpsert, PreferenceDelete: profile and scoped preference management.

Every command runs through the scope guard before invoking repositories. Hooks fire after each command so transports can sync email, analytics, or caches.

Feature gates

go-users can defer invite, self-registration, and password reset flows to a feature gate. Inject any implementation of featuregate.FeatureGate via service.Config.FeatureGate. When FeatureGate is nil, all gated flows are treated as enabled.

Gated flows and keys:

  • users.inviteUserInvite (command.ErrInviteDisabled)
  • users.password_resetUserPasswordResetRequest (command.ErrPasswordResetDisabled)
  • featuregate.FeatureUsersSignup (users.signup) → UserRegistrationRequest (command.ErrSignupDisabled)

Scope handling: go-users resolves gates with the scope derived from types.ScopeFilter and (for password reset requests) the target user ID. If no scope identifiers are set, the gate falls back to context-based scope resolution. Gate errors are returned to the caller.

Queries

  • UserInventory: list, filter, and search users.
  • RoleList and RoleDetail: role registry lookups.
  • RoleAssignments: view assignments per role or user.
  • ActivityFeed and ActivityStats: feed and aggregate views backed by Bun repositories.
  • ProfileDetail and Preferences: scoped profile and preference snapshots.

Queries also rely on the guard to derive the effective scope passed to repositories.

Scope guard

  • Provide a types.ScopeResolver that understands tenant, workspace, or organization hints carried in the request.
  • Provide a types.AuthorizationPolicy that asserts whether the actor can operate in the requested scope.
  • Call service.ScopeGuard() when building HTTP or job adapters so the same guard instance drives controllers.
  • The guard runs before go-crud controllers inside crudguard.Adapter (see examples/web).

More details live in docs/MULTITENANCY.md and docs/WORKSPACES.md.

Storage and migrations

  • SQL definitions live under data/sql/migrations. Files are numbered and include .up.sql and .down.sql.
  • Register migrations through migrations.Register(fsys) and feed the returned filesystems to your runner.
  • Standalone installs should register auth bootstrap + auth extras (social accounts/identifiers) before core; go-auth installs should register core only.
  • migrations.TestMigrationsApplyToSQLite verifies that the SQL stack applies cleanly to SQLite.
  • Bun repositories under activity, preferences, and registry are thin wrappers around bun.DB and match the interfaces in pkg/types.
  • You can replace any repository with your own implementation as long as it satisfies the interface.
User tables

users stores core auth identities and lifecycle state. Use user_role for the built-in auth tier; use custom roles for app-specific capabilities.

  • id: TEXT primary key (UUID string).
  • user_role: core auth tier (guest, member, admin, owner).
  • first_name/last_name: required user display names.
  • username: unique login handle.
  • profile_picture: optional avatar URL.
  • email: unique login email.
  • phone_number: optional contact number.
  • password_hash: stored password hash (nullable for external providers).
  • metadata: JSON object for provider or app-specific attributes.
  • is_email_verified: email verification flag.
  • login_attempts/login_attempt_at: throttling and lockout tracking.
  • loggedin_at: last successful login timestamp.
  • reseted_at: last password reset timestamp.
  • status: lifecycle state (pending, active, suspended, disabled, archived).
  • suspended_at: suspension timestamp for audit.
  • created_at/updated_at, deleted_at: audit and soft delete timestamps.

password_reset tracks reset requests and their lifecycle.

  • id: TEXT primary key (UUID string).
  • user_id: user receiving the reset.
  • email: email used for the reset flow.
  • status: reset lifecycle (unknown, requested, expired, changed).
  • reseted_at: completion timestamp.
  • created_at/updated_at, deleted_at: audit and soft delete timestamps.
Activity tables

user_activity stores audit log entries and feed events.

  • id: TEXT primary key (UUID string).
  • user_id: target user (optional).
  • actor_id: actor who performed the action.
  • tenant_id/org_id: scope identifiers.
  • verb: action name (e.g. role.assigned).
  • object_type/object_id: optional object for the action.
  • channel: optional grouping (e.g. settings).
  • ip: optional actor IP address.
  • data: JSON payload with action-specific details.
  • created_at: event timestamp.
Activity metadata exposure (support roles)

The default activity access policy drops metadata for support roles. You can opt into explicit modes with activity.WithMetadataExposure:

  • MetadataExposeNone (default): no metadata returned.
  • MetadataExposeSanitized: metadata is returned after go-masker preprocessing (denylist rules).
  • MetadataExposeAll: raw metadata (intended for development/debug only).

Use WithPolicyMasker to change the masker used by sanitized mode or WithMetadataSanitizer for a custom transform.

Activity enrichment (optional)

Write-time enrichment stores stable display details in user_activity.data so the UI can render without read-time lookups. Reserved keys include actor_display, actor_email, object_display, object_deleted, session_id, enriched_at, and enricher_version.

Write-time modes:

  • none: no enrichment at write time.
  • wrapper: enrich via activity.EnrichedSink before persistence.
  • repo: enrich inside the repository Log hook.
  • hybrid: wrapper enriches app-specific metadata (like session_id), then the repo enriches actor/object fields.

Backfill job: use the cron command under command/activity_enrichment with Schedule (default 0 * * * *), BatchSize, and EnrichedAtCutoff to enrich legacy rows. Missing-key merges are safe to run repeatedly; add functional indexes on data->>'actor_display', data->>'object_display', and data->>'enriched_at' for Postgres.

See docs/ACTIVITY.md and docs/GUIDE_ACTIVITY.md for wiring details and rollout guidance.

Profile and preference tables

user_profiles stores profile attributes separate from core auth fields.

  • user_id: primary key and foreign key to users.
  • display_name: friendly name for UI.
  • avatar_url: profile avatar URL.
  • locale: locale code (e.g. en-US).
  • timezone: IANA timezone string.
  • bio: optional profile summary.
  • contact: JSON object for structured contact data.
  • metadata: JSON object for app-specific profile attributes.
  • tenant_id/org_id: scope identifiers.
  • created_at/updated_at, created_by/updated_by: audit fields.

user_preferences stores scoped preference values.

  • id: TEXT primary key (UUID string).
  • user_id: user receiving the preference.
  • tenant_id/org_id: scope identifiers.
  • scope_level: preference tier (system, tenant, org, user).
  • key: preference key (case insensitive).
  • value: JSON payload for the preference.
  • version: monotonically increasing version per key/scope.
  • created_at/updated_at, created_by/updated_by: audit fields.
Role registry tables

custom_roles stores role definitions scoped by tenant and org. Use name as the short display label, description as the longer admin facing explanation, and role_key as the stable machine key for grouping/filtering.

  • id: TEXT primary key (UUID string).
  • name: short display label shown in admin UIs, unique per scope.
  • description: longer help text for admins, not intended for filtering.
  • role_key: optional, stable key for app level grouping (e.g. editor).
  • permissions: JSON array of permission slugs.
  • metadata: JSON object for app specific attributes or UI hints.
  • is_system: marks built-in roles versus admin defined roles.
  • tenant_id/org_id: scope identifiers.
  • created_at/updated_at, created_by/updated_by: audit fields.

user_custom_roles stores role assignments within the same scope.

  • user_id: assigned user.
  • role_id: assigned role.
  • tenant_id/org_id: scope identifiers.
  • assigned_at/assigned_by: audit fields.

Examples

  • examples/commands: runs the service with in-memory repositories. go run ./examples/commands.
  • examples/internal/memory: shared fixtures for the sample binaries.
  • examples/web: Go Fiber admin site showing guard first controllers, schema registry feeds, and CRUD adapters.

Use the examples to confirm wiring and to capture request traces during development.

Activity helper usage

The activity helpers keep DI minimal (ActivitySink.Log(ctx, ActivityRecord)) and cover both request and background flows:

// From an HTTP request with go-auth middleware.
actor := &auth.ActorContext{
    ActorID:  adminID.String(),
    TenantID: tenantID.String(),
    Role:     "admin",
}
record, err := activity.BuildRecordFromActor(actor,
    "settings.updated",
    "settings",
    "global",
    map[string]any{"path": "ui.theme", "from": "light", "to": "dark"},
    activity.WithChannel("settings"),
)

// From a background worker with only an actor UUID.
record, err = activity.BuildRecordFromUUID(adminID,
    "export.completed",
    "export.job",
    jobID,
    map[string]any{"format": "csv", "count": 120},
    activity.WithTenant(tenantID),
    activity.WithOrg(orgID),
    activity.WithOccurredAt(startedAt),
)

if err != nil {
    return err
}
if err := svc.ActivitySink.Log(ctx, record); err != nil {
    return err
}

Options:

  • WithChannel for module level filtering.
  • WithTenant / WithOrg to set scope when not present on the actor context.
  • WithOccurredAt to override the default time.Now().UTC().

See activity/README.md for wiring tips and docs/ACTIVITY.md for verb/object conventions.

Development workflow

  • ./taskfile lint: runs go vet across the module.
  • ./taskfile test: runs go test ./....
  • ./taskfile migrate: exercises the SQLite migration test.
  • Standard go test ./... and golangci-lint setups also work if you prefer direct tool invocations.

Documentation index

  • docs/USER_MANAGEMENT_REPORT.md: design notes for the service surface.
  • docs/SERVICE_REFERENCE.md: detailed command and query inputs and outputs.
  • docs/ACTIVITY.md, docs/PROFILES_PREFERENCES.md, docs/WORKSPACES.md: feature specific guidance.
  • docs/EXAMPLES.md, docs/MULTITENANCY.md, docs/ROLE_REGISTRY.md: integration recipes.
  • MIGRATIONS.md: SQL execution guidance and versioning notes.
  • docs/RELEASE_NOTES.md: change history.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AuthBootstrapMigrationsFS embed.FS

AuthBootstrapMigrationsFS contains the minimum auth tables/columns needed to run go-users without go-auth (users, status, external IDs).

View Source
var AuthExtrasMigrationsFS embed.FS

AuthExtrasMigrationsFS contains optional auth tables used by go-users when running without go-auth (social_accounts, user_identifiers).

View Source
var CoreMigrationsFS embed.FS

CoreMigrationsFS contains go-users migrations that extend the auth users table (roles, activity, profiles/preferences, tokens). It omits auth bootstrap tables.

View Source
var MigrationsFS embed.FS

MigrationsFS contains SQL migrations for both PostgreSQL and SQLite.

The migrations are organized in a dialect-aware structure:

  • Root files (data/sql/migrations/*.sql) contain PostgreSQL migrations
  • SQLite overrides are in data/sql/migrations/sqlite/*.sql

The go-persistence-bun loader will automatically select the correct migrations based on the database dialect being used.

Usage:

import "io/fs"
import users "github.com/goliatone/go-users"
import persistence "github.com/goliatone/go-persistence-bun"

migrationsFS, _ := fs.Sub(users.GetCoreMigrationsFS(), "data/sql/migrations")
client.RegisterDialectMigrations(
    migrationsFS,
    persistence.WithDialectSourceLabel("."),
    persistence.WithValidationTargets("postgres", "sqlite"),
)

Functions

func GetAuthBootstrapMigrationsFS added in v0.12.0

func GetAuthBootstrapMigrationsFS() embed.FS

GetAuthBootstrapMigrationsFS exposes the auth bootstrap migrations.

func GetAuthExtrasMigrationsFS added in v0.12.0

func GetAuthExtrasMigrationsFS() embed.FS

GetAuthExtrasMigrationsFS exposes optional auth migrations for social identities.

func GetCoreMigrationsFS added in v0.12.0

func GetCoreMigrationsFS() embed.FS

GetCoreMigrationsFS exposes go-users core migrations (no users/password_reset).

func GetMigrationsFS

func GetMigrationsFS() embed.FS

GetMigrationsFS exposes the full migration tree (auth bootstrap + core). For dialect-aware registration, prefer GetCoreMigrationsFS and GetAuthBootstrapMigrationsFS so auth can be registered from the auth/ root.

Types

type Commands

type Commands = service.Commands

Re-export the service package entry point so consumers can do `users.New(...)` without importing internal wiring helpers.

type Config

type Config = service.Config

Re-export the service package entry point so consumers can do `users.New(...)` without importing internal wiring helpers.

type PreferenceResolver

type PreferenceResolver = service.PreferenceResolver

Re-export the service package entry point so consumers can do `users.New(...)` without importing internal wiring helpers.

type Queries

type Queries = service.Queries

Re-export the service package entry point so consumers can do `users.New(...)` without importing internal wiring helpers.

type Service

type Service = service.Service

Re-export the service package entry point so consumers can do `users.New(...)` without importing internal wiring helpers.

func New

func New(cfg Config) *Service

New constructs the go-users runtime using the provided configuration.

Directories

Path Synopsis
Package activity provides default persistence helpers for the go-users ActivitySink.
Package activity provides default persistence helpers for the go-users ActivitySink.
adapter
goauth
Package goauth provides adapters that wrap github.com/goliatone/go-auth repositories so they satisfy go-users interfaces without extra plumbing.
Package goauth provides adapters that wrap github.com/goliatone/go-auth repositories so they satisfy go-users interfaces without extra plumbing.
securelink
Package securelink provides adapters that wrap github.com/goliatone/go-urlkit/securelink managers so they satisfy go-users securelink interfaces without extra plumbing.
Package securelink provides adapters that wrap github.com/goliatone/go-urlkit/securelink managers so they satisfy go-users securelink interfaces without extra plumbing.
Package command provides a cron-friendly command for activity backfills.
Package command provides a cron-friendly command for activity backfills.
examples
admin command
commands command
pkg
Package preferences stores scoped user preference records and exposes helpers to resolve effective settings using go-options.
Package preferences stores scoped user preference records and exposes helpers to resolve effective settings using go-options.
Package profile exposes storage adapters for the user_profiles table.
Package profile exposes storage adapters for the user_profiles table.
Package query hosts read-side projections and DTO-friendly query helpers consumed by go-admin/go-cms dashboards.
Package query hosts read-side projections and DTO-friendly query helpers consumed by go-admin/go-cms dashboards.
Package registry contains interfaces and default implementations for the custom role registry.
Package registry contains interfaces and default implementations for the custom role registry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL