schema

package
v0.0.15 Latest Latest
Warning

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

Go to latest
Published: Feb 11, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Index

Constants

View Source
const (
	DeviceCodeStatusPending    = "pending"
	DeviceCodeStatusAuthorized = "authorized"
	DeviceCodeStatusDenied     = "denied"
	DeviceCodeStatusExpired    = "expired"
	DeviceCodeStatusConsumed   = "consumed"
)

Device code status constants.

View Source
const (
	EnvironmentTypeDevelopment = "development"
	EnvironmentTypeProduction  = "production"
	EnvironmentTypeStaging     = "staging"
	EnvironmentTypePreview     = "preview"
	EnvironmentTypeTest        = "test"
)

Environment types.

View Source
const (
	EnvironmentStatusActive   = "active"
	EnvironmentStatusInactive = "inactive"
)

Environment status.

View Source
const (
	PromotionStatusPending    = "pending"
	PromotionStatusInProgress = "in_progress"
	PromotionStatusCompleted  = "completed"
	PromotionStatusFailed     = "failed"
)

Promotion status.

View Source
const (
	OrgMemberRoleOwner  = "owner"
	OrgMemberRoleAdmin  = "admin"
	OrgMemberRoleMember = "member"
)

Organization Member Roles.

View Source
const (
	OrgMemberStatusActive    = "active"
	OrgMemberStatusSuspended = "suspended"
	OrgMemberStatusPending   = "pending"
)

Organization Member Statuses.

View Source
const (
	OrgInvitationStatusPending   = "pending"
	OrgInvitationStatusAccepted  = "accepted"
	OrgInvitationStatusExpired   = "expired"
	OrgInvitationStatusCancelled = "cancelled"
	OrgInvitationStatusDeclined  = "declined"
)

Organization Invitation Statuses.

Variables

View Source
var ProviderDefaultScopes = map[string][]string{
	"google":    {"openid", "email", "profile"},
	"github":    {"user:email", "read:user"},
	"microsoft": {"openid", "email", "profile", "User.Read"},
	"apple":     {"name", "email"},
	"facebook":  {"email", "public_profile"},
	"discord":   {"identify", "email"},
	"twitter":   {"users.read", "tweet.read"},
	"linkedin":  {"openid", "profile", "email"},
	"spotify":   {"user-read-email", "user-read-private"},
	"twitch":    {"user:read:email"},
	"dropbox":   {"account_info.read"},
	"gitlab":    {"read_user", "openid", "email"},
	"line":      {"profile", "openid", "email"},
	"reddit":    {"identity"},
	"slack":     {"users:read", "users:read.email"},
	"bitbucket": {"account", "email"},
	"notion":    {},
}

ProviderDefaultScopes maps provider names to their default OAuth scopes.

View Source
var ProviderDisplayNames = map[string]string{
	"google":    "Google",
	"github":    "GitHub",
	"microsoft": "Microsoft",
	"apple":     "Apple",
	"facebook":  "Facebook",
	"discord":   "Discord",
	"twitter":   "Twitter / X",
	"linkedin":  "LinkedIn",
	"spotify":   "Spotify",
	"twitch":    "Twitch",
	"dropbox":   "Dropbox",
	"gitlab":    "GitLab",
	"line":      "LINE",
	"reddit":    "Reddit",
	"slack":     "Slack",
	"bitbucket": "Bitbucket",
	"notion":    "Notion",
}

ProviderDisplayNames maps provider names to human-readable display names.

View Source
var SupportedProviders = []string{
	"google",
	"github",
	"microsoft",
	"apple",
	"facebook",
	"discord",
	"twitter",
	"linkedin",
	"spotify",
	"twitch",
	"dropbox",
	"gitlab",
	"line",
	"reddit",
	"slack",
	"bitbucket",
	"notion",
}

SupportedProviders returns the list of all supported OAuth provider names.

Functions

func GetProviderDefaultScopes added in v0.0.3

func GetProviderDefaultScopes(name string) []string

GetProviderDefaultScopes returns the default scopes for a provider.

func GetProviderDisplayName added in v0.0.3

func GetProviderDisplayName(name string) string

GetProviderDisplayName returns the display name for a provider.

func IsValidOrgInvitationStatus

func IsValidOrgInvitationStatus(status string) bool

IsValidOrgInvitationStatus checks if an invitation status is valid.

func IsValidOrgMemberRole

func IsValidOrgMemberRole(role string) bool

IsValidOrgMemberRole checks if a role is valid.

func IsValidOrgMemberStatus

func IsValidOrgMemberStatus(status string) bool

IsValidOrgMemberStatus checks if a status is valid.

func IsValidProvider added in v0.0.3

func IsValidProvider(name string) bool

IsValidProvider checks if the given provider name is supported.

func ValidOrgInvitationStatuses

func ValidOrgInvitationStatuses() []string

ValidOrgInvitationStatuses returns the list of valid invitation statuses.

func ValidOrgMemberRoles

func ValidOrgMemberRoles() []string

ValidOrgMemberRoles returns the list of valid member roles.

func ValidOrgMemberStatuses

func ValidOrgMemberStatuses() []string

ValidOrgMemberStatuses returns the list of valid member statuses.

Types

type APIKey

type APIKey struct {
	AuditableModel
	bun.BaseModel `bun:"table:api_keys"`

	// 3-tier context (V2 architecture)
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`                    // Platform tenant
	EnvironmentID  xid.ID  `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"`            // Required: environment-scoped key
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"        json:"organizationID,omitempty"` // Optional: org-scoped key
	UserID         xid.ID  `bun:"user_id,notnull,type:varchar(20)"        json:"userID"`                   // User who created the key

	// Key identification
	Name        string `bun:"name,notnull"                  json:"name"`
	Description string `bun:"description"                   json:"description,omitempty"`
	Prefix      string `bun:"prefix,notnull,unique"         json:"prefix"`  // pk_test_xxx, sk_prod_xxx, rk_dev_xxx
	KeyType     string `bun:"key_type,notnull,default:'rk'" json:"keyType"` // pk/sk/rk
	KeyHash     string `bun:"key_hash,notnull"              json:"-"`       // Hashed key for verification

	// Permissions and scopes
	Scopes      []string          `bun:"scopes,type:jsonb"       json:"scopes"`                // ["read", "write", "admin"]
	Permissions map[string]string `bun:"permissions,type:jsonb"  json:"permissions"`           // Custom permissions
	RateLimit   int               `bun:"rate_limit,default:1000" json:"rate_limit"`            // Requests per hour
	AllowedIPs  []string          `bun:"allowed_ips,type:jsonb"  json:"allowed_ips,omitempty"` // IP whitelist (CIDR notation supported)

	// Status and expiration
	Active    bool       `bun:"active,notnull,default:true" json:"active"`
	ExpiresAt *time.Time `bun:"expires_at"                  json:"expires_at,omitempty"`

	// Usage tracking
	UsageCount int64      `bun:"usage_count,notnull,default:0" json:"usage_count"`
	LastUsedAt *time.Time `bun:"last_used_at"                  json:"last_used_at,omitempty"`
	LastUsedIP string     `bun:"last_used_ip"                  json:"last_used_ip,omitempty"`
	LastUsedUA string     `bun:"last_used_ua"                  json:"last_used_ua,omitempty"`

	// Metadata
	Metadata map[string]string `bun:"metadata,type:jsonb" json:"metadata,omitempty"`

	// RBAC Integration (Hybrid Approach)
	DelegateUserPermissions bool    `bun:"delegate_user_permissions,notnull,default:false" json:"delegateUserPermissions"`     // Inherit creator's permissions
	ImpersonateUserID       *xid.ID `bun:"impersonate_user_id,type:varchar(20)"            json:"impersonateUserID,omitempty"` // Act as specific user

	// RBAC Relationships
	Roles []*Role `bun:"m2m:apikey_roles,join:APIKey=Role" json:"-"` // Many-to-many with roles

	// Transient field - only populated during creation
	Key string `bun:"-" json:"key,omitempty"`
}

APIKey represents an API key for programmatic access Updated for V2 architecture: App → Environment → Organization.

func (*APIKey) BeforeAppendModel

func (a *APIKey) BeforeAppendModel(ctx context.Context, query bun.Query) error

BeforeAppendModel implements bun.BeforeAppendModelHook.

func (*APIKey) HasPermission

func (a *APIKey) HasPermission(permission string) bool

HasPermission checks if the API key has a specific permission.

func (*APIKey) HasScope

func (a *APIKey) HasScope(scope string) bool

HasScope checks if the API key has a specific scope.

func (*APIKey) IsExpired

func (a *APIKey) IsExpired() bool

IsExpired checks if the API key has expired.

func (*APIKey) IsIPAllowed

func (a *APIKey) IsIPAllowed(ip string) bool

IsIPAllowed checks if an IP address is in the allowed list Supports exact IP matching and CIDR notation.

type APIKeyRole

type APIKeyRole struct {
	bun.BaseModel `bun:"table:apikey_roles,alias:akr"`

	ID             xid.ID     `bun:"id,pk,type:varchar(20)"`
	APIKeyID       xid.ID     `bun:"api_key_id,notnull,type:varchar(20)"`
	RoleID         xid.ID     `bun:"role_id,notnull,type:varchar(20)"`
	OrganizationID *xid.ID    `bun:"organization_id,type:varchar(20)"` // Optional: org-scoped assignment
	CreatedAt      time.Time  `bun:"created_at,notnull"`
	CreatedBy      *xid.ID    `bun:"created_by,type:varchar(20)"`
	DeletedAt      *time.Time `bun:"deleted_at"`

	// Relations
	APIKey *APIKey `bun:"rel:belongs-to,join:api_key_id=id"`
	Role   *Role   `bun:"rel:belongs-to,join:role_id=id"`
}

APIKeyRole represents the many-to-many relationship between API keys and roles This enables API keys to leverage the RBAC system for structured permissions.

func (*APIKeyRole) BeforeAppendModel

func (ar *APIKeyRole) BeforeAppendModel(ctx context.Context, query bun.Query) error

BeforeAppendModel implements bun.BeforeAppendModelHook.

type Account

type Account struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:accounts,alias:a"`

	ID           xid.ID     `bun:"id,pk,type:varchar(20)"           json:"id"`
	AppID        xid.ID     `bun:"app_id,notnull,type:varchar(20)"  json:"appID"`
	UserID       xid.ID     `bun:"user_id,notnull,type:varchar(20)" json:"userID"`
	Provider     string     `bun:"provider,notnull"                 json:"provider"` // google, github, etc.
	ProviderID   string     `bun:"provider_id,notnull"              json:"providerID"`
	AccessToken  string     `bun:"access_token"                     json:"accessToken"`
	RefreshToken string     `bun:"refresh_token"                    json:"refreshToken"`
	ExpiresAt    *time.Time `bun:"expires_at"                       json:"expiresAt"`

	// Relations
	App  *App  `bun:"rel:belongs-to,join:app_id=id"`
	User *User `bun:"rel:belongs-to,join:user_id=id"`
}

Account represents OAuth accounts.

type AccountLockout

type AccountLockout struct {
	bun.BaseModel `bun:"table:account_lockouts,alias:al"`

	ID          xid.ID    `bun:"type:varchar(20),pk"                                json:"id"`
	UserID      xid.ID    `bun:"type:varchar(20),notnull"                           json:"user_id"`
	LockedUntil time.Time `bun:"type:timestamptz,notnull"                           json:"locked_until"`
	Reason      string    `bun:"type:varchar(255)"                                  json:"reason"`
	CreatedAt   time.Time `bun:"type:timestamptz,notnull,default:current_timestamp" json:"created_at"`
}

AccountLockout tracks locked user accounts due to failed login attempts.

type App

type App struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:apps,alias:a"`

	ID         xid.ID         `bun:"id,pk,type:varchar(20)"    json:"id"`
	Name       string         `bun:"name,notnull"              json:"name"`
	Slug       string         `bun:"slug,notnull,unique"       json:"slug"`
	Metadata   map[string]any `bun:"metadata,type:jsonb"       json:"metadata"`
	IsPlatform bool           `bun:"is_platform,default:false" json:"isPlatform"` // Identifies the single platform app

	// Relations
	Members []Member `bun:"rel:has-many,join:id=app_id" json:"members,omitempty"`
	Teams   []Team   `bun:"rel:has-many,join:id=app_id" json:"teams,omitempty"`
}

App represents the app table (formerly Organization - platform-level tenant).

type AuditEvent

type AuditEvent struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:audit_events,alias:ae"`

	ID             xid.ID  `bun:"id,pk,type:varchar(20)"           json:"id"`
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"  json:"appID"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)" json:"organizationID,omitempty"` // User-created organization (optional)
	EnvironmentID  *xid.ID `bun:"environment_id,type:varchar(20)"  json:"environmentID"`            // Environment scoping
	UserID         *xid.ID `bun:"user_id,type:varchar(20)"         json:"userID"`
	Action         string  `bun:"action,notnull"                   json:"action"`
	Resource       string  `bun:"resource,notnull"                 json:"resource"`
	Source         string  `bun:"source,notnull,default:'system'"  json:"source"` // Audit source: system, application, plugin
	IPAddress      string  `bun:"ip_address"                       json:"ipAddress"`
	UserAgent      string  `bun:"user_agent"                       json:"userAgent"`
	Metadata       string  `bun:"metadata"                         json:"metadata"`

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
}

AuditEvent represents the audit_events table.

type AuditableModel

type AuditableModel struct {
	ID        xid.ID     `bun:"id,pk,type:varchar(20)"                                json:"id"`
	CreatedAt time.Time  `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	CreatedBy xid.ID     `bun:"created_by,nullzero"                                   json:"createdBy"`
	UpdatedAt time.Time  `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updatedAt"`
	UpdatedBy xid.ID     `bun:"updated_by,nullzero"                                   json:"updatedBy"`
	DeletedAt *time.Time `bun:"deleted_at,nullzero"                                   json:"deletedAt,omitempty"`
	Version   int        `bun:"version,default:1"                                     json:"version"`
}

func (*AuditableModel) BeforeAppendModel

func (u *AuditableModel) BeforeAppendModel(ctx context.Context, query bun.Query) error

type AuthorizationCode

type AuthorizationCode struct {
	AuditableModel
	bun.BaseModel `bun:"table:authorization_codes"`

	// Context fields
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`
	EnvironmentID  xid.ID  `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"        json:"organizationID,omitempty"` // Optional org context
	SessionID      *xid.ID `bun:"session_id,type:varchar(20)"             json:"sessionID,omitempty"`      // Link to user session

	// OAuth2/OIDC fields
	Code                string `bun:"code,unique,notnull"              json:"code"`                          // The authorization code
	ClientID            string `bun:"client_id,notnull"                json:"clientID"`                      // OAuth client ID
	UserID              xid.ID `bun:"user_id,notnull,type:varchar(20)" json:"userID"`                        // User who authorized
	RedirectURI         string `bun:"redirect_uri,notnull"             json:"redirectURI"`                   // Redirect URI used in auth request
	Scope               string `bun:"scope,notnull"                    json:"scope"`                         // Requested scopes
	State               string `bun:"state"                            json:"state,omitempty"`               // State parameter from auth request
	Nonce               string `bun:"nonce"                            json:"nonce,omitempty"`               // Nonce for OIDC
	CodeChallenge       string `bun:"code_challenge"                   json:"codeChallenge,omitempty"`       // PKCE code challenge
	CodeChallengeMethod string `bun:"code_challenge_method"            json:"codeChallengeMethod,omitempty"` // PKCE challenge method (S256, plain)

	// Consent tracking
	ConsentGranted bool   `bun:"consent_granted,default:false" json:"consentGranted"`
	ConsentScopes  string `bun:"consent_scopes"                json:"consentScopes,omitempty"` // Scopes user consented to

	// Authentication context
	AuthTime time.Time `bun:"auth_time,notnull" json:"authTime"` // When user authenticated (for max_age checks)

	// Lifecycle
	ExpiresAt time.Time  `bun:"expires_at,notnull"         json:"expiresAt"` // Code expiration (typically 10 minutes)
	Used      bool       `bun:"used,notnull,default:false" json:"used"`
	UsedAt    *time.Time `bun:"used_at"                    json:"usedAt,omitempty"`

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	Session      *Session      `bun:"rel:belongs-to,join:session_id=id"`
}

AuthorizationCode represents an OAuth2/OIDC authorization code.

func (*AuthorizationCode) IsExpired

func (ac *AuthorizationCode) IsExpired() bool

IsExpired checks if the authorization code has expired.

func (*AuthorizationCode) IsValid

func (ac *AuthorizationCode) IsValid() bool

IsValid checks if the authorization code is valid (not expired and not used).

type BackupCode

type BackupCode struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:twofa_backup_codes,alias:tbc"`

	ID       xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID    xid.ID     `bun:"app_id,notnull,type:varchar(20)"`
	UserID   xid.ID     `bun:"user_id,notnull,type:varchar(20)"`
	CodeHash string     `bun:"code_hash,notnull"`
	UsedAt   *time.Time `bun:"used_at"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

BackupCode stores recovery codes for 2FA.

type Delivery

type Delivery struct {
	bun.BaseModel `bun:"table:webhook_deliveries,alias:wd"`

	ID              xid.ID     `bun:"id,pk,type:varchar(20)"                                json:"id"`
	WebhookID       xid.ID     `bun:"webhook_id,notnull,type:varchar(20)"                   json:"webhook_id"`
	EventID         xid.ID     `bun:"event_id,notnull,type:varchar(20)"                     json:"event_id"`
	URL             string     `bun:"url,notnull"                                           json:"url"`
	HTTPMethod      string     `bun:"http_method,notnull,default:'POST'"                    json:"http_method"`
	Headers         []byte     `bun:"headers,type:jsonb"                                    json:"headers,omitempty"`
	Body            []byte     `bun:"body"                                                  json:"body,omitempty"`
	Status          string     `bun:"status,notnull"                                        json:"status"`
	StatusCode      *int       `bun:"status_code"                                           json:"status_code,omitempty"`
	ResponseHeaders []byte     `bun:"response_headers,type:jsonb"                           json:"response_headers,omitempty"`
	ResponseBody    []byte     `bun:"response_body"                                         json:"response_body,omitempty"`
	Error           *string    `bun:"error"                                                 json:"error,omitempty"`
	AttemptNumber   int        `bun:"attempt_number,notnull,default:1"                      json:"attempt_number"`
	NextRetryAt     *time.Time `bun:"next_retry_at"                                         json:"next_retry_at,omitempty"`
	DeliveredAt     *time.Time `bun:"delivered_at"                                          json:"delivered_at,omitempty"`
	CreatedAt       time.Time  `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
	UpdatedAt       time.Time  `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`

	// Relations
	Webhook *Webhook `bun:"rel:belongs-to,join:webhook_id=id" json:"webhook,omitempty"`
	Event   *Event   `bun:"rel:belongs-to,join:event_id=id"   json:"event,omitempty"`
}

Delivery represents a webhook delivery attempt.

type Device

type Device struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:devices,alias:d"`

	ID          xid.ID    `bun:"id,pk,type:varchar(20)"           json:"id"`
	AppID       xid.ID    `bun:"app_id,notnull,type:varchar(20)"  json:"appID"`
	UserID      xid.ID    `bun:"user_id,notnull,type:varchar(20)" json:"userID"`
	Fingerprint string    `bun:"fingerprint,notnull,unique"       json:"fingerprint"`
	UserAgent   string    `bun:"user_agent"                       json:"userAgent"`
	IPAddress   string    `bun:"ip_address"                       json:"ipAddress"`
	LastActive  time.Time `bun:"last_active,notnull"              json:"lastActive"`

	// Relations
	App  *App  `bun:"rel:belongs-to,join:app_id=id"`
	User *User `bun:"rel:belongs-to,join:user_id=id"`
}

Device represents the devices table.

type DeviceCode added in v0.0.15

type DeviceCode struct {
	AuditableModel
	bun.BaseModel `bun:"table:device_codes"`

	// Context fields
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`
	EnvironmentID  xid.ID  `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"        json:"organizationID,omitempty"` // Optional org context

	// OAuth client
	ClientID string `bun:"client_id,notnull" json:"clientID"` // OAuth client ID

	// Device Flow Fields (RFC 8628)
	DeviceCode      string    `bun:"device_code,unique,notnull" json:"deviceCode"`      // Long random string (URL-safe)
	UserCode        string    `bun:"user_code,unique,notnull"   json:"userCode"`        // Short human-typable code (e.g., "WDJB-MJHT")
	VerificationURI string    `bun:"verification_uri,notnull"   json:"verificationURI"` // Where user goes to authorize
	ExpiresAt       time.Time `bun:"expires_at,notnull"         json:"expiresAt"`       // Code expiration
	Interval        int       `bun:"interval,notnull,default:5" json:"interval"`        // Polling interval in seconds
	Scope           string    `bun:"scope"                      json:"scope,omitempty"` // Requested scopes

	// Authorization State
	Status    string  `bun:"status,notnull,default:'pending'" json:"status"`              // pending, authorized, denied, expired, consumed
	UserID    *xid.ID `bun:"user_id,type:varchar(20)"         json:"userID,omitempty"`    // Set when user authorizes
	SessionID *xid.ID `bun:"session_id,type:varchar(20)"      json:"sessionID,omitempty"` // Set when user authorizes

	// PKCE Support (optional but recommended)
	CodeChallenge       string `bun:"code_challenge"        json:"codeChallenge,omitempty"`       // PKCE code challenge
	CodeChallengeMethod string `bun:"code_challenge_method" json:"codeChallengeMethod,omitempty"` // PKCE challenge method (S256, plain)

	// Rate Limiting
	PollCount    int        `bun:"poll_count,notnull,default:0" json:"pollCount"`
	LastPolledAt *time.Time `bun:"last_polled_at"               json:"lastPolledAt,omitempty"`

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	User         *User         `bun:"rel:belongs-to,join:user_id=id"`
	Session      *Session      `bun:"rel:belongs-to,join:session_id=id"`
}

DeviceCode represents an OAuth 2.0 device authorization code (RFC 8628).

func (*DeviceCode) CanPoll added in v0.0.15

func (dc *DeviceCode) CanPoll() bool

CanPoll checks if the device can poll for this code.

func (*DeviceCode) FormattedUserCode added in v0.0.15

func (dc *DeviceCode) FormattedUserCode() string

FormattedUserCode returns the user code in a display-friendly format (e.g., "BCDF-GHJK").

func (*DeviceCode) IsAuthorized added in v0.0.15

func (dc *DeviceCode) IsAuthorized() bool

IsAuthorized checks if the device code has been authorized by the user.

func (*DeviceCode) IsExpired added in v0.0.15

func (dc *DeviceCode) IsExpired() bool

IsExpired checks if the device code has expired.

func (*DeviceCode) IsPending added in v0.0.15

func (dc *DeviceCode) IsPending() bool

IsPending checks if the device code is awaiting user authorization.

func (*DeviceCode) ShouldSlowDown added in v0.0.15

func (dc *DeviceCode) ShouldSlowDown() bool

ShouldSlowDown checks if the device is polling too frequently.

type EmailOTP

type EmailOTP struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:email_otps,alias:eotp"`

	ID        xid.ID    `bun:"id,pk,type:varchar(20)"          json:"id"`
	AppID     xid.ID    `bun:"app_id,notnull,type:varchar(20)" json:"appID"`
	Email     string    `bun:"email,notnull"                   json:"email"`
	OTP       string    `bun:"otp,notnull"                     json:"otp"`
	ExpiresAt time.Time `bun:"expires_at,notnull"              json:"expiresAt"`
	Attempts  int       `bun:"attempts,notnull,default:0"      json:"attempts"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

EmailOTP stores OTP codes for email-based authentication.

type Environment

type Environment struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:environments,alias:env"`

	ID        xid.ID         `bun:"id,pk,type:varchar(20)"           json:"id"`
	AppID     xid.ID         `bun:"app_id,notnull,type:varchar(20)"  json:"appID"` // Foreign key to App
	Name      string         `bun:"name,notnull"                     json:"name"`
	Slug      string         `bun:"slug,notnull"                     json:"slug"`      // dev, prod, staging
	Type      string         `bun:"type,notnull"                     json:"type"`      // development, production, staging, preview
	Status    string         `bun:"status,notnull,default:'active'"  json:"status"`    // active, inactive
	Config    map[string]any `bun:"config,type:jsonb"                json:"config"`    // Environment-specific configuration
	IsDefault bool           `bun:"is_default,notnull,default:false" json:"isDefault"` // Is this the default environment for the app

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

Environment represents an isolated data context within an App (dev, prod, staging, etc.)

func (*Environment) CanDelete

func (e *Environment) CanDelete() bool

CanDelete checks if this environment can be deleted.

func (*Environment) IsDevelopment

func (e *Environment) IsDevelopment() bool

IsDevelopment checks if this is a development environment.

func (*Environment) IsProduction

func (e *Environment) IsProduction() bool

IsProduction checks if this is a production environment.

type EnvironmentPromotion

type EnvironmentPromotion struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:environment_promotions,alias:ep"`

	ID           xid.ID     `bun:"id,pk,type:varchar(20)"                 json:"id"`
	AppID        xid.ID     `bun:"app_id,notnull,type:varchar(20)"        json:"appID"`
	SourceEnvID  xid.ID     `bun:"source_env_id,notnull,type:varchar(20)" json:"sourceEnvId"`
	TargetEnvID  xid.ID     `bun:"target_env_id,notnull,type:varchar(20)" json:"targetEnvId"`
	PromotedBy   xid.ID     `bun:"promoted_by,notnull,type:varchar(20)"   json:"promotedBy"`  // User who performed promotion
	IncludeData  bool       `bun:"include_data,notnull,default:false"     json:"includeData"` // Whether to copy data or just schema
	Status       string     `bun:"status,notnull"                         json:"status"`      // pending, in_progress, completed, failed
	ErrorMessage string     `bun:"error_message"                          json:"errorMessage"`
	CompletedAt  *time.Time `bun:"completed_at"                           json:"completedAt"`

	// Relations
	App       *App         `bun:"rel:belongs-to,join:app_id=id"`
	SourceEnv *Environment `bun:"rel:belongs-to,join:source_env_id=id"`
	TargetEnv *Environment `bun:"rel:belongs-to,join:target_env_id=id"`
}

EnvironmentPromotion represents a promotion from one environment to another.

type Event

type Event struct {
	bun.BaseModel `bun:"table:webhook_events,alias:we"`

	ID            xid.ID         `bun:"id,pk,type:varchar(20)"                                 json:"id"`
	AppID         xid.ID         `bun:"app_id,notnull,type:varchar(20)"                        json:"app_id"`
	EnvironmentID xid.ID         `bun:"environment_id,notnull,type:varchar(20)"                json:"environment_id"`
	Type          string         `bun:"type,notnull"                                           json:"type"`
	Data          map[string]any `bun:"data,type:jsonb"                                        json:"data"`
	UserID        *xid.ID        `bun:"user_id,type:varchar(20)"                               json:"user_id,omitempty"`
	SessionID     *xid.ID        `bun:"session_id,type:varchar(20)"                            json:"session_id,omitempty"`
	IPAddress     string         `bun:"ip_address"                                             json:"ip_address,omitempty"`
	UserAgent     string         `bun:"user_agent"                                             json:"user_agent,omitempty"`
	OccurredAt    time.Time      `bun:"occurred_at,nullzero,notnull,default:current_timestamp" json:"occurred_at"`
	CreatedAt     time.Time      `bun:"created_at,nullzero,notnull,default:current_timestamp"  json:"created_at"`
}

Event represents a webhook event.

type FailedLoginAttempt

type FailedLoginAttempt struct {
	bun.BaseModel `bun:"table:failed_login_attempts,alias:fla"`

	ID        xid.ID    `bun:"type:varchar(20),pk"                                json:"id"`
	Username  string    `bun:"type:varchar(255),notnull"                          json:"username"`
	AppID     xid.ID    `bun:"type:varchar(20),notnull"                           json:"app_id"`
	IP        string    `bun:"type:varchar(45)"                                   json:"ip"`
	UserAgent string    `bun:"type:text"                                          json:"user_agent"`
	AttemptAt time.Time `bun:"type:timestamptz,notnull,default:current_timestamp" json:"attempt_at"`
}

FailedLoginAttempt records failed login attempts for account lockout functionality.

type FormField

type FormField struct {
	ID          string         `json:"id"`
	Type        string         `json:"type"` // text, email, password, select, checkbox, etc.
	Label       string         `json:"label"`
	Placeholder string         `json:"placeholder"`
	Required    bool           `json:"required"`
	Validation  map[string]any `json:"validation"`
	Options     []string       `json:"options,omitempty"` // For select fields
	Metadata    map[string]any `json:"metadata,omitempty"`
}

FormField represents a single form field configuration.

type FormSchema

type FormSchema struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:form_schemas,alias:fs"`

	ID          xid.ID         `bun:"id,pk,type:varchar(20)"          json:"id"`
	AppID       xid.ID         `bun:"app_id,notnull,type:varchar(20)" json:"appID"` // App-scoped form schemas
	Type        string         `bun:"type,notnull"                    json:"type"`  // signup, signin, profile, etc.
	Name        string         `bun:"name,notnull"                    json:"name"`
	Description string         `bun:"description"                     json:"description"`
	Schema      map[string]any `bun:"schema,type:jsonb,notnull"       json:"schema"`
	IsActive    bool           `bun:"is_active,notnull,default:true"  json:"isActive"`
	Version     int            `bun:"version,notnull,default:1"       json:"version"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

FormSchema represents app-specific form configurations.

type FormSubmission

type FormSubmission struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:form_submissions,alias:fsub"`

	ID           xid.ID         `bun:"id,pk,type:varchar(20)"                  json:"id"`
	FormSchemaID xid.ID         `bun:"form_schema_id,notnull,type:varchar(20)" json:"formSchemaId"`
	UserID       *xid.ID        `bun:"user_id,type:varchar(20)"                json:"userId"` // Optional for anonymous submissions
	SessionID    *xid.ID        `bun:"session_id,type:varchar(20)"             json:"sessionId"`
	Data         map[string]any `bun:"data,type:jsonb,notnull"                 json:"data"`
	IPAddress    string         `bun:"ip_address"                              json:"ipAddress"`
	UserAgent    string         `bun:"user_agent"                              json:"userAgent"`
	Status       string         `bun:"status,notnull,default:'submitted'"      json:"status"` // submitted, processed, failed

	// Relations
	FormSchema *FormSchema `bun:"rel:belongs-to,join:form_schema_id=id"`
	User       *User       `bun:"rel:belongs-to,join:user_id=id"`
	Session    *Session    `bun:"rel:belongs-to,join:session_id=id"`
}

FormSubmission represents a form submission.

type IDModel

type IDModel struct {
	ID xid.ID `bun:"id,pk,type:varchar(20)" json:"id"`
}

type IdentityVerification

type IdentityVerification struct {
	AuditableModel
	bun.BaseModel `bun:"table:identity_verifications,alias:iv"`

	ID string `bun:"id,pk,type:varchar(255)" json:"id"`

	// V2 Multi-tenant context (App → Environment → Organization)
	AppID          string  `bun:"app_id,notnull,type:varchar(20)"          json:"appId"`
	EnvironmentID  *string `bun:"environment_id,type:varchar(20)"          json:"environmentId,omitempty"`
	OrganizationID string  `bun:"organization_id,notnull,type:varchar(20)" json:"organizationId"`
	UserID         string  `bun:"user_id,notnull,type:varchar(20)"         json:"userId"`

	// Provider information
	Provider        string `bun:"provider,notnull,type:varchar(50)"   json:"provider"` // onfido, jumio, stripe_identity
	ProviderCheckID string `bun:"provider_check_id,type:varchar(255)" json:"providerCheckId"`

	// Verification type and status
	VerificationType string `bun:"verification_type,notnull,type:varchar(50)" json:"verificationType"` // document, liveness, age, aml
	Status           string `bun:"status,notnull,type:varchar(50)"            json:"status"`           // pending, in_progress, completed, failed, expired

	// Document information (if applicable)
	DocumentType    string `bun:"document_type,type:varchar(50)"    json:"documentType,omitempty"`    // passport, drivers_license, national_id
	DocumentNumber  string `bun:"document_number,type:varchar(255)" json:"documentNumber,omitempty"`  // Encrypted
	DocumentCountry string `bun:"document_country,type:varchar(2)"  json:"documentCountry,omitempty"` // ISO 3166-1 alpha-2

	// Verification results
	IsVerified      bool   `bun:"is_verified,default:false"   json:"isVerified"`
	RiskScore       int    `bun:"risk_score,type:int"         json:"riskScore,omitempty"`       // 0-100, higher is riskier
	RiskLevel       string `bun:"risk_level,type:varchar(20)" json:"riskLevel,omitempty"`       // low, medium, high
	ConfidenceScore int    `bun:"confidence_score,type:int"   json:"confidenceScore,omitempty"` // 0-100

	// Personal information extracted
	FirstName   string     `bun:"first_name,type:varchar(255)" json:"firstName,omitempty"`
	LastName    string     `bun:"last_name,type:varchar(255)"  json:"lastName,omitempty"`
	DateOfBirth *time.Time `bun:"date_of_birth,type:date"      json:"dateOfBirth,omitempty"`
	Age         int        `bun:"age,type:int"                 json:"age,omitempty"`
	Gender      string     `bun:"gender,type:varchar(20)"      json:"gender,omitempty"`
	Nationality string     `bun:"nationality,type:varchar(2)"  json:"nationality,omitempty"` // ISO 3166-1 alpha-2

	// AML/Sanctions screening results
	IsOnSanctionsList bool   `bun:"is_on_sanctions_list,default:false" json:"isOnSanctionsList"`
	IsPEP             bool   `bun:"is_pep,default:false"               json:"isPep"` // Politically Exposed Person
	SanctionsDetails  string `bun:"sanctions_details,type:text"        json:"sanctionsDetails,omitempty"`

	// Liveness detection
	LivenessScore int  `bun:"liveness_score,type:int" json:"livenessScore,omitempty"` // 0-100
	IsLive        bool `bun:"is_live,default:false"   json:"isLive"`

	// Rejection/failure information
	RejectionReasons []string `bun:"rejection_reasons,type:jsonb" json:"rejectionReasons,omitempty"`
	FailureReason    string   `bun:"failure_reason,type:text"     json:"failureReason,omitempty"`

	// Metadata
	Metadata     map[string]any `bun:"metadata,type:jsonb"         json:"metadata,omitempty"`
	ProviderData map[string]any `bun:"provider_data,type:jsonb"    json:"providerData,omitempty"` // Raw provider response
	IPAddress    string         `bun:"ip_address,type:varchar(45)" json:"ipAddress,omitempty"`
	UserAgent    string         `bun:"user_agent,type:text"        json:"userAgent,omitempty"`

	// Expiry and validity
	ExpiresAt  *time.Time `bun:"expires_at,type:timestamptz"  json:"expiresAt,omitempty"`
	VerifiedAt *time.Time `bun:"verified_at,type:timestamptz" json:"verifiedAt,omitempty"`

	// Webhook tracking
	WebhookDeliveryStatus string     `bun:"webhook_delivery_status,type:varchar(50)" json:"webhookDeliveryStatus,omitempty"`
	WebhookDeliveredAt    *time.Time `bun:"webhook_delivered_at,type:timestamptz"    json:"webhookDeliveredAt,omitempty"`

	// Relations
	User         *User         `bun:"rel:belongs-to,join:user_id=id"         json:"user,omitempty"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"`
}

IdentityVerification represents a KYC verification attempt.

type IdentityVerificationDocument

type IdentityVerificationDocument struct {
	bun.BaseModel `bun:"table:identity_verification_documents,alias:ivd"`

	ID             string `bun:"id,pk,type:varchar(255)"                   json:"id"`
	VerificationID string `bun:"verification_id,notnull,type:varchar(255)" json:"verificationId"`

	// V2 Multi-tenant context (inherited from parent verification)
	AppID          string  `bun:"app_id,notnull,type:varchar(20)"          json:"appId"`
	EnvironmentID  *string `bun:"environment_id,type:varchar(20)"          json:"environmentId,omitempty"`
	OrganizationID string  `bun:"organization_id,notnull,type:varchar(20)" json:"organizationId"`

	// Document details
	DocumentSide string `bun:"document_side,type:varchar(20)" json:"documentSide"` // front, back, selfie
	FileURL      string `bun:"file_url,type:text"             json:"fileUrl"`      // Encrypted storage URL
	FileHash     string `bun:"file_hash,type:varchar(64)"     json:"fileHash"`     // SHA-256 for integrity
	MimeType     string `bun:"mime_type,type:varchar(100)"    json:"mimeType"`
	FileSize     int64  `bun:"file_size,type:bigint"          json:"fileSize"`

	// Processing status
	ProcessingStatus string `bun:"processing_status,type:varchar(50)" json:"processingStatus"` // pending, processing, processed, failed

	// Extracted data
	ExtractedData map[string]any `bun:"extracted_data,type:jsonb" json:"extractedData,omitempty"`

	// Retention policy
	RetainUntil *time.Time `bun:"retain_until,type:timestamptz" json:"retainUntil,omitempty"`
	DeletedAt   *time.Time `bun:"deleted_at,type:timestamptz"   json:"deletedAt,omitempty"`

	CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updatedAt"`

	// Relations
	Verification *IdentityVerification `bun:"rel:belongs-to,join:verification_id=id" json:"verification,omitempty"`
}

IdentityVerificationDocument represents uploaded documents for verification.

type IdentityVerificationSession

type IdentityVerificationSession struct {
	bun.BaseModel `bun:"table:identity_verification_sessions,alias:ivs"`

	ID string `bun:"id,pk,type:varchar(255)" json:"id"`

	// V2 Multi-tenant context (App → Environment → Organization)
	AppID          string  `bun:"app_id,notnull,type:varchar(20)"          json:"appId"`
	EnvironmentID  *string `bun:"environment_id,type:varchar(20)"          json:"environmentId,omitempty"`
	OrganizationID string  `bun:"organization_id,notnull,type:varchar(20)" json:"organizationId"`
	UserID         string  `bun:"user_id,notnull,type:varchar(20)"         json:"userId"`

	// Session details
	Provider     string `bun:"provider,notnull,type:varchar(50)" json:"provider"`
	SessionURL   string `bun:"session_url,type:text"             json:"sessionUrl"`   // URL for user to complete verification
	SessionToken string `bun:"session_token,type:varchar(255)"   json:"sessionToken"` // Encrypted

	// Configuration
	RequiredChecks []string       `bun:"required_checks,type:jsonb" json:"requiredChecks"` // [document, liveness, aml]
	Config         map[string]any `bun:"config,type:jsonb"          json:"config,omitempty"`

	// Status tracking
	Status      string     `bun:"status,notnull,type:varchar(50)"     json:"status"` // created, started, completed, abandoned, expired
	CompletedAt *time.Time `bun:"completed_at,type:timestamptz"       json:"completedAt,omitempty"`
	ExpiresAt   time.Time  `bun:"expires_at,notnull,type:timestamptz" json:"expiresAt"`

	// Callback URLs
	SuccessURL string `bun:"success_url,type:text" json:"successUrl,omitempty"`
	CancelURL  string `bun:"cancel_url,type:text"  json:"cancelUrl,omitempty"`

	// Tracking
	IPAddress string `bun:"ip_address,type:varchar(45)" json:"ipAddress,omitempty"`
	UserAgent string `bun:"user_agent,type:text"        json:"userAgent,omitempty"`

	CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updatedAt"`

	// Relations
	User         *User         `bun:"rel:belongs-to,join:user_id=id"         json:"user,omitempty"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"`
}

IdentityVerificationSession represents a verification session/flow.

type ImpersonationAuditEvent

type ImpersonationAuditEvent struct {
	bun.BaseModel `bun:"table:impersonation_audit,alias:ia"`

	ID              xid.ID            `bun:"id,pk,type:varchar(20)"                       json:"id"`
	ImpersonationID xid.ID            `bun:"impersonation_id,notnull,type:varchar(20)"    json:"impersonationID"`
	AppID           xid.ID            `bun:"app_id,notnull,type:varchar(20)"              json:"appID"`                    // Platform app (required)
	EnvironmentID   *xid.ID           `bun:"environment_id,type:varchar(20)"              json:"environmentID,omitempty"`  // Environment (optional)
	OrganizationID  *xid.ID           `bun:"organization_id,type:varchar(20)"             json:"organizationID,omitempty"` // User-created organization (optional)
	EventType       string            `bun:"event_type,notnull,type:varchar(50)"          json:"eventType"`                // started, ended, action_performed, expired
	Action          string            `bun:"action,type:varchar(100)"                     json:"action,omitempty"`         // Specific action performed during impersonation
	Resource        string            `bun:"resource,type:varchar(255)"                   json:"resource,omitempty"`       // Resource accessed
	IPAddress       string            `bun:"ip_address,type:varchar(45)"                  json:"ipAddress"`
	UserAgent       string            `bun:"user_agent,type:text"                         json:"userAgent"`
	Details         map[string]string `bun:"details,type:jsonb"                           json:"details,omitempty"`
	CreatedAt       time.Time         `bun:"created_at,notnull,default:current_timestamp" json:"createdAt"`

	// Relationships
	ImpersonationSession *ImpersonationSession `bun:"rel:belongs-to,join:impersonation_id=id" json:"impersonationSession,omitempty"`
	App                  *App                  `bun:"rel:belongs-to,join:app_id=id"           json:"app,omitempty"`
	Environment          *Environment          `bun:"rel:belongs-to,join:environment_id=id"   json:"environment,omitempty"`
	Organization         *Organization         `bun:"rel:belongs-to,join:organization_id=id"  json:"organization,omitempty"`
}

ImpersonationAuditEvent represents a detailed audit log for impersonation events Updated for V2 architecture: App → Environment → Organization.

type ImpersonationSession

type ImpersonationSession struct {
	AuditableModel
	bun.BaseModel `bun:"table:impersonation_sessions,alias:is"`

	// Core fields
	AppID           xid.ID  `bun:"app_id,notnull,type:varchar(20)"          json:"appID"`                     // Platform app (required)
	EnvironmentID   *xid.ID `bun:"environment_id,type:varchar(20)"          json:"environmentID,omitempty"`   // Environment (optional)
	OrganizationID  *xid.ID `bun:"organization_id,type:varchar(20)"         json:"organizationID,omitempty"`  // User-created organization (optional)
	ImpersonatorID  xid.ID  `bun:"impersonator_id,notnull,type:varchar(20)" json:"impersonatorID"`            // Admin who is impersonating
	TargetUserID    xid.ID  `bun:"target_user_id,notnull,type:varchar(20)"  json:"targetUserID"`              // User being impersonated
	OriginalSession *xid.ID `bun:"original_session,type:varchar(20)"        json:"originalSession,omitempty"` // Admin's original session
	NewSessionID    *xid.ID `bun:"new_session_id,type:varchar(20)"          json:"newSessionID,omitempty"`    // New session for impersonation
	SessionToken    string  `bun:"session_token,type:text"                  json:"-"`                         // Session token for revocation (not exposed in JSON)

	// Metadata
	Reason       string            `bun:"reason,type:text"                json:"reason"`                  // Required: ticket/reason for impersonation
	IPAddress    string            `bun:"ip_address,type:varchar(45)"     json:"ip_address"`              // Admin's IP
	UserAgent    string            `bun:"user_agent,type:text"            json:"user_agent"`              // Admin's user agent
	Metadata     map[string]string `bun:"metadata,type:jsonb"             json:"metadata,omitempty"`      // Additional context
	TicketNumber string            `bun:"ticket_number,type:varchar(100)" json:"ticket_number,omitempty"` // Support ticket reference

	// Status and lifecycle
	Active    bool       `bun:"active,notnull,default:true" json:"active"`               // Currently active
	ExpiresAt time.Time  `bun:"expires_at,notnull"          json:"expires_at"`           // Auto-logout time
	EndedAt   *time.Time `bun:"ended_at"                    json:"ended_at,omitempty"`   // When impersonation ended
	EndReason string     `bun:"end_reason,type:varchar(50)" json:"end_reason,omitempty"` // manual, timeout, error

	// Relationships (for joins)
	Impersonator *User         `bun:"rel:belongs-to,join:impersonator_id=id" json:"impersonator,omitempty"`
	TargetUser   *User         `bun:"rel:belongs-to,join:target_user_id=id"  json:"targetUser,omitempty"`
	App          *App          `bun:"rel:belongs-to,join:app_id=id"          json:"app,omitempty"`          // Platform app
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"  json:"environment,omitempty"`  // Environment (optional)
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"` // User-created org (optional)
}

ImpersonationSession represents an admin impersonating a user Updated for V2 architecture: App → Environment → Organization.

func (*ImpersonationSession) IsActive

func (i *ImpersonationSession) IsActive() bool

IsActive checks if the impersonation session is currently active.

func (*ImpersonationSession) IsExpired

func (i *ImpersonationSession) IsExpired() bool

IsExpired checks if the impersonation session has expired.

type Invitation

type Invitation struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:invitations,alias:inv"`

	ID         xid.ID           `bun:"id,pk,type:varchar(20)"              json:"id"`
	AppID      xid.ID           `bun:"app_id,notnull,type:varchar(20)"     json:"appID"`
	Email      string           `bun:"email,notnull"                       json:"email"`
	Role       MemberRole       `bun:"role,notnull"                        json:"role"`
	InviterID  xid.ID           `bun:"inviter_id,notnull,type:varchar(20)" json:"inviterID"`
	Token      string           `bun:"token,notnull,unique"                json:"token"`
	ExpiresAt  time.Time        `bun:"expires_at,notnull"                  json:"expiresAt"`
	AcceptedAt *time.Time       `bun:"accepted_at"                         json:"acceptedAt"`
	Status     InvitationStatus `bun:"status,notnull"                      json:"status"`
	Metadata   map[string]any   `bun:"metadata,type:jsonb"                 json:"metadata"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id" json:"app,omitempty"`
}

Invitation represents the app invitation table.

type InvitationStatus

type InvitationStatus string

InvitationStatus represents the status of an invitation.

const (
	InvitationStatusPending   InvitationStatus = "pending"
	InvitationStatusAccepted  InvitationStatus = "accepted"
	InvitationStatusExpired   InvitationStatus = "expired"
	InvitationStatusCancelled InvitationStatus = "cancelled"
	InvitationStatusDeclined  InvitationStatus = "declined"
)

func (InvitationStatus) IsValid

func (s InvitationStatus) IsValid() bool

IsValid checks if the status is valid.

func (InvitationStatus) String

func (s InvitationStatus) String() string

String returns the string representation.

type JSONMap

type JSONMap map[string]any

JSONMap is a helper type for storing JSON data.

func (*JSONMap) Scan

func (j *JSONMap) Scan(value any) error

Scan implements sql.Scanner for JSONMap.

func (JSONMap) Value

func (j JSONMap) Value() (driver.Value, error)

Value implements driver.Valuer for JSONMap.

type JWTKey

type JWTKey struct {
	AuditableModel
	bun.BaseModel `bun:"table:jwt_keys"`

	// App context
	AppID         xid.ID `bun:"app_id,notnull,type:varchar(20)"       json:"appID"`
	IsPlatformKey bool   `bun:"is_platform_key,notnull,default:false" json:"isPlatformKey"`

	// Key identification
	KeyID     string `bun:"key_id,notnull"    json:"keyID"`           // Kid for JWKS (unique per app)
	Algorithm string `bun:"algorithm,notnull" json:"algorithm"`       // EdDSA, RS256, etc.
	KeyType   string `bun:"key_type,notnull"  json:"keyType"`         // OKP, RSA
	Curve     string `bun:"curve"             json:"curve,omitempty"` // Ed25519, P-256, etc.

	// Key material (encrypted)
	PrivateKey []byte `bun:"private_key,notnull" json:"-"`         // Encrypted private key
	PublicKey  []byte `bun:"public_key,notnull"  json:"publicKey"` // Public key for JWKS

	// Key status
	Active    bool       `bun:"active,notnull,default:true" json:"active"`
	ExpiresAt *time.Time `bun:"expires_at"                  json:"expiresAt,omitempty"`

	// Usage tracking
	UsageCount int64      `bun:"usage_count,notnull,default:0" json:"usageCount"`
	LastUsedAt *time.Time `bun:"last_used_at"                  json:"lastUsedAt,omitempty"`

	// Metadata
	Name        string            `bun:"name"                json:"name,omitempty"`
	Description string            `bun:"description"         json:"description,omitempty"`
	Metadata    map[string]string `bun:"metadata,type:jsonb" json:"metadata,omitempty"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

JWTKey represents a JWT signing key.

func (*JWTKey) BeforeAppendModel

func (k *JWTKey) BeforeAppendModel(ctx context.Context, query bun.Query) error

BeforeAppendModel implements bun.BeforeAppendModelHook.

type MFAAttempt

type MFAAttempt struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_attempts,alias:mfa"`

	ID            xid.ID  `bun:"id,pk,type:varchar(20)"`
	AppID         xid.ID  `bun:"app_id,notnull,type:varchar(20)"` // App context
	UserID        xid.ID  `bun:"user_id,notnull,type:varchar(20)"`
	FactorID      *xid.ID `bun:"factor_id,type:varchar(20)"`
	ChallengeID   *xid.ID `bun:"challenge_id,type:varchar(20)"`
	Type          string  `bun:"type,notnull"` // Factor type
	Success       bool    `bun:"success,notnull"`
	FailureReason string  `bun:"failure_reason"`
	IPAddress     string  `bun:"ip_address"`
	UserAgent     string  `bun:"user_agent"`
	Metadata      JSONMap `bun:"metadata,type:jsonb"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFAAttempt tracks verification attempts for rate limiting and security.

type MFABypass

type MFABypass struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_bypasses,alias:mfb"`

	ID        xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID     xid.ID     `bun:"app_id,notnull,type:varchar(20)"` // App context
	UserID    xid.ID     `bun:"user_id,notnull,type:varchar(20)"`
	GrantedBy xid.ID     `bun:"granted_by,notnull,type:varchar(20)"` // Admin who granted bypass
	Reason    string     `bun:"reason,notnull"`
	ExpiresAt time.Time  `bun:"expires_at,notnull"`
	RevokedAt *time.Time `bun:"revoked_at"`
	RevokedBy *xid.ID    `bun:"revoked_by,type:varchar(20)"`
	Metadata  JSONMap    `bun:"metadata,type:jsonb"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFABypass represents temporary MFA bypass granted by admins.

type MFAChallenge

type MFAChallenge struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_challenges,alias:mfc"`

	ID          xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID       xid.ID     `bun:"app_id,notnull,type:varchar(20)"`     // App context
	SessionID   xid.ID     `bun:"session_id,notnull,type:varchar(20)"` // Links to MFA session
	UserID      xid.ID     `bun:"user_id,notnull,type:varchar(20)"`
	FactorID    xid.ID     `bun:"factor_id,notnull,type:varchar(20)"`
	Type        string     `bun:"type,notnull"`   // Factor type
	Status      string     `bun:"status,notnull"` // pending, verified, failed, expired
	CodeHash    string     `bun:"code_hash"`      // Hashed verification code
	Metadata    JSONMap    `bun:"metadata,type:jsonb"`
	Attempts    int        `bun:"attempts,notnull,default:0"`
	MaxAttempts int        `bun:"max_attempts,notnull,default:3"`
	IPAddress   string     `bun:"ip_address"`
	UserAgent   string     `bun:"user_agent"`
	ExpiresAt   time.Time  `bun:"expires_at,notnull"`
	VerifiedAt  *time.Time `bun:"verified_at"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFAChallenge stores active MFA verification challenges.

type MFAFactor

type MFAFactor struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_factors,alias:mff"`

	ID             xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID          xid.ID     `bun:"app_id,notnull,type:varchar(20)"` // App context (required)
	UserID         xid.ID     `bun:"user_id,notnull,type:varchar(20)"`
	OrganizationID *xid.ID    `bun:"organization_id,type:varchar(20)"` // User-created org (optional)
	Type           string     `bun:"type,notnull"`                     // totp, sms, email, webauthn, backup, etc.
	Status         string     `bun:"status,notnull"`                   // pending, active, disabled, revoked
	Priority       string     `bun:"priority,notnull"`                 // primary, backup, optional
	Name           string     `bun:"name"`                             // User-friendly name
	Secret         string     `bun:"secret"`                           // Encrypted factor secret
	Metadata       JSONMap    `bun:"metadata,type:jsonb"`              // Factor-specific metadata
	LastUsedAt     *time.Time `bun:"last_used_at"`
	VerifiedAt     *time.Time `bun:"verified_at"`
	ExpiresAt      *time.Time `bun:"expires_at"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFAFactor stores enrolled authentication factors for users.

type MFAPolicy

type MFAPolicy struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_policies,alias:mfp"`

	ID                     xid.ID      `bun:"id,pk,type:varchar(20)"`
	AppID                  xid.ID      `bun:"app_id,notnull,type:varchar(20)"`  // App context
	OrganizationID         *xid.ID     `bun:"organization_id,type:varchar(20)"` // User-created org (optional)
	Enabled                bool        `bun:"enabled,notnull,default:true"`
	RequiredFactorCount    int         `bun:"required_factor_count,notnull,default:1"`
	AllowedFactorTypes     StringArray `bun:"allowed_factor_types,type:text[]"`
	RequiredFactorTypes    StringArray `bun:"required_factor_types,type:text[]"`
	GracePeriodDays        int         `bun:"grace_period_days,notnull,default:7"`
	TrustedDeviceDays      int         `bun:"trusted_device_days,notnull,default:30"`
	StepUpRequired         bool        `bun:"step_up_required,notnull,default:false"`
	AdaptiveMFAEnabled     bool        `bun:"adaptive_mfa_enabled,notnull,default:false"`
	MaxFailedAttempts      int         `bun:"max_failed_attempts,notnull,default:5"`
	LockoutDurationMinutes int         `bun:"lockout_duration_minutes,notnull,default:30"`
	Metadata               JSONMap     `bun:"metadata,type:jsonb"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFAPolicy defines organization-level MFA requirements.

type MFARiskAssessment

type MFARiskAssessment struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_risk_assessments,alias:mra"`

	ID          xid.ID      `bun:"id,pk,type:varchar(20)"`
	AppID       xid.ID      `bun:"app_id,notnull,type:varchar(20)"` // App context
	UserID      xid.ID      `bun:"user_id,notnull,type:varchar(20)"`
	SessionID   *xid.ID     `bun:"session_id,type:varchar(20)"`
	RiskLevel   string      `bun:"risk_level,notnull"`      // low, medium, high, critical
	RiskScore   float64     `bun:"risk_score,notnull"`      // 0-100
	Factors     StringArray `bun:"factors,type:text[]"`     // Risk factors identified
	Recommended StringArray `bun:"recommended,type:text[]"` // Recommended factor types
	IPAddress   string      `bun:"ip_address"`
	UserAgent   string      `bun:"user_agent"`
	Location    string      `bun:"location"` // Geographic location
	Metadata    JSONMap     `bun:"metadata,type:jsonb"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFARiskAssessment stores risk assessment results.

type MFASession

type MFASession struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_sessions,alias:mfs"`

	ID              xid.ID      `bun:"id,pk,type:varchar(20)"`
	AppID           xid.ID      `bun:"app_id,notnull,type:varchar(20)"` // App context
	UserID          xid.ID      `bun:"user_id,notnull,type:varchar(20)"`
	SessionToken    string      `bun:"session_token,unique,notnull"`
	FactorsRequired int         `bun:"factors_required,notnull"`
	FactorsVerified int         `bun:"factors_verified,notnull,default:0"`
	VerifiedFactors StringArray `bun:"verified_factors,type:text[]"` // Array of factor IDs
	RiskLevel       string      `bun:"risk_level"`                   // low, medium, high, critical
	RiskScore       float64     `bun:"risk_score"`                   // 0-100
	Context         string      `bun:"context"`                      // login, transaction, step-up
	IPAddress       string      `bun:"ip_address"`
	UserAgent       string      `bun:"user_agent"`
	Metadata        JSONMap     `bun:"metadata,type:jsonb"`
	ExpiresAt       time.Time   `bun:"expires_at,notnull"`
	CompletedAt     *time.Time  `bun:"completed_at"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFASession represents an MFA verification session.

type MFATrustedDevice

type MFATrustedDevice struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:mfa_trusted_devices,alias:mtd"`

	ID         xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID      xid.ID     `bun:"app_id,notnull,type:varchar(20)"` // App context
	UserID     xid.ID     `bun:"user_id,notnull,type:varchar(20)"`
	DeviceID   string     `bun:"device_id,notnull"`   // Fingerprint/identifier
	Name       string     `bun:"name"`                // User-friendly name
	Metadata   JSONMap    `bun:"metadata,type:jsonb"` // Device info
	IPAddress  string     `bun:"ip_address"`
	UserAgent  string     `bun:"user_agent"`
	LastUsedAt *time.Time `bun:"last_used_at"`
	ExpiresAt  time.Time  `bun:"expires_at,notnull"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MFATrustedDevice stores trusted devices that can skip MFA.

type MagicLink struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:magic_links,alias:ml"`

	ID             xid.ID    `bun:"id,pk,type:varchar(20)"           json:"id"`
	Email          string    `bun:"email,notnull"                    json:"email"`
	Token          string    `bun:"token,notnull"                    json:"token"`
	AppID          xid.ID    `bun:"app_id,notnull,type:varchar(20)"  json:"appID"`                    // Platform app (required)
	OrganizationID *xid.ID   `bun:"organization_id,type:varchar(20)" json:"organizationID,omitempty"` // User-created org (optional)
	EnvironmentID  *xid.ID   `bun:"environment_id,type:varchar(20)"  json:"environmentID,omitempty"`  // Optional environment context
	ExpiresAt      time.Time `bun:"expires_at,notnull"               json:"expiresAt"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

MagicLink stores passwordless email tokens Updated for V2 architecture: App → Environment → Organization.

type Member

type Member struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:members,alias:m"`

	ID       xid.ID       `bun:"id,pk,type:varchar(20)"                               json:"id"`
	AppID    xid.ID       `bun:"app_id,notnull,type:varchar(20)"                      json:"appID"` // App context
	UserID   xid.ID       `bun:"user_id,notnull,type:varchar(20)"                     json:"userID"`
	Role     MemberRole   `bun:"role,nullzero"                                        json:"role"`
	Status   MemberStatus `bun:"status,notnull,default:'active'"                      json:"status"`
	JoinedAt time.Time    `bun:"joined_at,nullzero,notnull,default:current_timestamp" json:"joinedAt"` // when the member joined

	// Relations
	App   *App   `bun:"rel:belongs-to,join:app_id=id"     json:"app,omitempty"`
	User  *User  `bun:"rel:belongs-to,join:user_id=id"    json:"user,omitempty"`
	Teams []Team `bun:"m2m:team_members,join:Member=Team" json:"teams,omitempty"`
}

Member represents the app member table.

type MemberRole

type MemberRole string

MemberRole represents the role of a member in an app.

const (
	MemberRoleOwner  MemberRole = "owner"
	MemberRoleAdmin  MemberRole = "admin"
	MemberRoleMember MemberRole = "member"
)

func (MemberRole) IsValid

func (r MemberRole) IsValid() bool

IsValid checks if the role is valid.

func (MemberRole) String

func (r MemberRole) String() string

String returns the string representation.

type MemberStatus

type MemberStatus string

MemberStatus represents the status of a member.

const (
	MemberStatusActive    MemberStatus = "active"
	MemberStatusSuspended MemberStatus = "suspended"
	MemberStatusPending   MemberStatus = "pending"
)

func (MemberStatus) IsValid

func (s MemberStatus) IsValid() bool

IsValid checks if the status is valid.

func (MemberStatus) String

func (s MemberStatus) String() string

String returns the string representation.

type Notification

type Notification struct {
	bun.BaseModel `bun:"table:notifications,alias:n"`

	ID          xid.ID         `bun:"id,pk,type:varchar(20)"                                json:"id"`
	AppID       xid.ID         `bun:"app_id,notnull,type:varchar(20)"                       json:"appId"`
	TemplateID  *xid.ID        `bun:"template_id,type:varchar(20)"                          json:"templateId,omitempty"`
	Type        string         `bun:"type,notnull"                                          json:"type"`
	Recipient   string         `bun:"recipient,notnull"                                     json:"recipient"`
	Subject     string         `bun:"subject"                                               json:"subject,omitempty"`
	Body        string         `bun:"body,notnull"                                          json:"body"`
	Status      string         `bun:"status,notnull"                                        json:"status"`
	Error       string         `bun:"error"                                                 json:"error,omitempty"`
	ProviderID  string         `bun:"provider_id"                                           json:"providerId,omitempty"`
	Metadata    map[string]any `bun:"metadata,type:jsonb"                                   json:"metadata,omitempty"`
	SentAt      *time.Time     `bun:"sent_at"                                               json:"sentAt,omitempty"`
	DeliveredAt *time.Time     `bun:"delivered_at"                                          json:"deliveredAt,omitempty"`
	CreatedAt   time.Time      `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt   time.Time      `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updatedAt"`

	// Relations
	Template *NotificationTemplate `bun:"rel:belongs-to,join:template_id=id" json:"template,omitempty"`
}

Notification represents a notification instance in the database.

type NotificationAnalytics

type NotificationAnalytics struct {
	bun.BaseModel `bun:"table:notification_analytics,alias:na"`

	ID             xid.ID         `bun:"id,pk,type:varchar(20)"                                json:"id"`
	NotificationID xid.ID         `bun:"notification_id,notnull,type:varchar(20)"              json:"notificationId"`
	TemplateID     *xid.ID        `bun:"template_id,type:varchar(20)"                          json:"templateId,omitempty"`
	AppID          xid.ID         `bun:"app_id,notnull,type:varchar(20)"                       json:"appId"`
	OrganizationID *xid.ID        `bun:"organization_id,type:varchar(20)"                      json:"organizationId,omitempty"`
	Event          string         `bun:"event,notnull"                                         json:"event"`               // sent, delivered, opened, clicked, converted, bounced, complained
	EventData      map[string]any `bun:"event_data,type:jsonb"                                 json:"eventData,omitempty"` // Additional event-specific data (e.g., link clicked, conversion value)
	UserAgent      string         `bun:"user_agent"                                            json:"userAgent,omitempty"`
	IPAddress      string         `bun:"ip_address"                                            json:"ipAddress,omitempty"`
	Metadata       map[string]any `bun:"metadata,type:jsonb"                                   json:"metadata,omitempty"`
	CreatedAt      time.Time      `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`

	// Relations
	Notification *Notification         `bun:"rel:belongs-to,join:notification_id=id" json:"notification,omitempty"`
	Template     *NotificationTemplate `bun:"rel:belongs-to,join:template_id=id"     json:"template,omitempty"`
	App          *App                  `bun:"rel:belongs-to,join:app_id=id"          json:"app,omitempty"`
	Organization *Organization         `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"`
}

NotificationAnalytics represents a single analytics event for a notification.

type NotificationEvent

type NotificationEvent string

NotificationEvent represents the type of analytics event.

const (
	NotificationEventSent       NotificationEvent = "sent"       // Notification sent
	NotificationEventDelivered  NotificationEvent = "delivered"  // Provider confirmed delivery
	NotificationEventOpened     NotificationEvent = "opened"     // Recipient opened (email tracking pixel)
	NotificationEventClicked    NotificationEvent = "clicked"    // Recipient clicked link (tracked URL)
	NotificationEventConverted  NotificationEvent = "converted"  // Recipient completed desired action
	NotificationEventBounced    NotificationEvent = "bounced"    // Delivery failed permanently
	NotificationEventComplained NotificationEvent = "complained" // Recipient marked as spam
	NotificationEventFailed     NotificationEvent = "failed"     // General failure
)

type NotificationProvider

type NotificationProvider struct {
	bun.BaseModel `bun:"table:notification_providers,alias:np"`

	ID             xid.ID         `bun:"id,pk,type:varchar(20)"                                json:"id"`
	AppID          xid.ID         `bun:"app_id,notnull,type:varchar(20)"                       json:"appId"`
	OrganizationID *xid.ID        `bun:"organization_id,type:varchar(20)"                      json:"organizationId,omitempty"` // Nullable for app-level providers
	ProviderType   string         `bun:"provider_type,notnull"                                 json:"providerType"`             // email, sms, push
	ProviderName   string         `bun:"provider_name,notnull"                                 json:"providerName"`             // smtp, sendgrid, twilio, etc.
	Config         map[string]any `bun:"config,type:jsonb,notnull"                             json:"config"`                   // Encrypted provider configuration
	IsActive       bool           `bun:"is_active,notnull,default:true"                        json:"isActive"`
	IsDefault      bool           `bun:"is_default,notnull,default:false"                      json:"isDefault"` // Default provider for this type
	Metadata       map[string]any `bun:"metadata,type:jsonb"                                   json:"metadata,omitempty"`
	CreatedAt      time.Time      `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt      time.Time      `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updatedAt"`
	DeletedAt      *time.Time     `bun:"deleted_at,soft_delete,nullzero"                       json:"-"`

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"          json:"app,omitempty"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"`
}

NotificationProvider represents a notification provider configuration in the database Providers can be configured at app-level or organization-level.

type NotificationQueue added in v0.0.7

type NotificationQueue struct {
	bun.BaseModel `bun:"table:notification_queue,alias:nq"`

	ID    xid.ID `bun:"id,pk,type:varchar(20)"          json:"id"`
	AppID xid.ID `bun:"app_id,notnull,type:varchar(20)" json:"appId"`

	// Notification details
	Type        string `bun:"type,notnull"      json:"type"`                  // email, sms, push
	Priority    string `bun:"priority,notnull"  json:"priority"`              // critical, high, normal, low
	Recipient   string `bun:"recipient,notnull" json:"recipient"`             // Email address or phone number
	Subject     string `bun:"subject"           json:"subject,omitempty"`     // Email subject
	Body        string `bun:"body"              json:"body,omitempty"`        // Direct body content
	TemplateKey string `bun:"template_key"      json:"templateKey,omitempty"` // Template key if using template

	// Payload for retry (JSON serialized request)
	Payload []byte `bun:"payload,type:bytea" json:"payload,omitempty"`

	// Retry state
	Attempts    int                     `bun:"attempts,notnull,default:0"       json:"attempts"`
	MaxAttempts int                     `bun:"max_attempts,notnull,default:3"   json:"maxAttempts"`
	LastError   string                  `bun:"last_error"                       json:"lastError,omitempty"`
	Status      NotificationQueueStatus `bun:"status,notnull,default:'pending'" json:"status"`
	NextRetryAt *time.Time              `bun:"next_retry_at"                    json:"nextRetryAt,omitempty"`
	ProcessedAt *time.Time              `bun:"processed_at"                     json:"processedAt,omitempty"`

	// Audit fields
	CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updatedAt"`
}

NotificationQueue represents a notification queued for retry in the database.

type NotificationQueueStats added in v0.0.7

type NotificationQueueStats struct {
	PendingCount    int64 `json:"pendingCount"`
	ProcessingCount int64 `json:"processingCount"`
	SucceededCount  int64 `json:"succeededCount"`
	FailedCount     int64 `json:"failedCount"`
	TotalCount      int64 `json:"totalCount"`
}

NotificationQueueStats holds aggregate statistics for the notification queue.

type NotificationQueueStatus added in v0.0.7

type NotificationQueueStatus string

NotificationQueueStatus represents the status of a queued notification.

const (
	NotificationQueueStatusPending    NotificationQueueStatus = "pending"
	NotificationQueueStatusProcessing NotificationQueueStatus = "processing"
	NotificationQueueStatusSucceeded  NotificationQueueStatus = "succeeded"
	NotificationQueueStatusFailed     NotificationQueueStatus = "failed"
)

type NotificationTemplate

type NotificationTemplate struct {
	bun.BaseModel `bun:"table:notification_templates,alias:nt"`

	ID             xid.ID         `bun:"id,pk,type:varchar(20)"            json:"id"`
	AppID          xid.ID         `bun:"app_id,notnull,type:varchar(20)"   json:"appId"`
	OrganizationID *xid.ID        `bun:"organization_id,type:varchar(20)"  json:"organizationId,omitempty"` // Nullable for app-level templates
	TemplateKey    string         `bun:"template_key,notnull"              json:"templateKey"`              // e.g., "auth.welcome", "auth.mfa_code"
	Name           string         `bun:"name,notnull"                      json:"name"`
	Type           string         `bun:"type,notnull"                      json:"type"`
	Language       string         `bun:"language,notnull,default:'en'"     json:"language"`
	Subject        string         `bun:"subject"                           json:"subject,omitempty"`
	Body           string         `bun:"body,notnull"                      json:"body"`
	Variables      []string       `bun:"variables,array"                   json:"variables"`
	Metadata       map[string]any `bun:"metadata,type:jsonb"               json:"metadata,omitempty"`
	Active         bool           `bun:"active,notnull,default:true"       json:"active"`
	IsDefault      bool           `bun:"is_default,notnull,default:false"  json:"isDefault"`   // Is this a default template
	IsModified     bool           `bun:"is_modified,notnull,default:false" json:"isModified"`  // Has it been modified from default
	DefaultHash    string         `bun:"default_hash"                      json:"defaultHash"` // Hash of default content for comparison

	// Versioning fields
	Version  int     `bun:"version,notnull,default:1"  json:"version"`            // Current version number
	ParentID *xid.ID `bun:"parent_id,type:varchar(20)" json:"parentId,omitempty"` // ID of template this was cloned from

	// A/B Testing fields
	ABTestGroup   string `bun:"ab_test_group"                         json:"abTestGroup,omitempty"` // Group identifier for variants
	ABTestEnabled bool   `bun:"ab_test_enabled,notnull,default:false" json:"abTestEnabled"`         // Is this variant active in A/B test
	ABTestWeight  int    `bun:"ab_test_weight,notnull,default:100"    json:"abTestWeight"`          // Weight for variant selection (0-100)

	// Analytics fields
	SendCount       int64 `bun:"send_count,notnull,default:0"       json:"sendCount"`       // Total sends
	OpenCount       int64 `bun:"open_count,notnull,default:0"       json:"openCount"`       // Total opens
	ClickCount      int64 `bun:"click_count,notnull,default:0"      json:"clickCount"`      // Total clicks
	ConversionCount int64 `bun:"conversion_count,notnull,default:0" json:"conversionCount"` // Total conversions

	CreatedAt time.Time  `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt time.Time  `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updatedAt"`
	DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero"                       json:"-"`
}

NotificationTemplate represents a notification template in the database.

type NotificationTemplateVersion

type NotificationTemplateVersion struct {
	bun.BaseModel `bun:"table:notification_template_versions,alias:ntv"`

	ID         xid.ID         `bun:"id,pk,type:varchar(20)"                                json:"id"`
	TemplateID xid.ID         `bun:"template_id,notnull,type:varchar(20)"                  json:"templateId"`
	Version    int            `bun:"version,notnull"                                       json:"version"` // Version number
	Subject    string         `bun:"subject"                                               json:"subject,omitempty"`
	Body       string         `bun:"body,notnull"                                          json:"body"`
	Variables  []string       `bun:"variables,array"                                       json:"variables"`
	Changes    string         `bun:"changes"                                               json:"changes,omitempty"`   // Description of what changed
	ChangedBy  *xid.ID        `bun:"changed_by,type:varchar(20)"                           json:"changedBy,omitempty"` // User who made the change
	Metadata   map[string]any `bun:"metadata,type:jsonb"                                   json:"metadata,omitempty"`
	CreatedAt  time.Time      `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	RestoredAt *time.Time     `bun:"restored_at"                                           json:"restoredAt,omitempty"` // When this version was restored (if ever)

	// Relations
	Template *NotificationTemplate `bun:"rel:belongs-to,join:template_id=id" json:"template,omitempty"`
	User     *User                 `bun:"rel:belongs-to,join:changed_by=id"  json:"user,omitempty"`
}

NotificationTemplateVersion represents a version snapshot of a notification template.

type NotificationTest

type NotificationTest struct {
	bun.BaseModel `bun:"table:notification_tests,alias:ntest"`

	ID             xid.ID         `bun:"id,pk,type:varchar(20)"                                json:"id"`
	TemplateID     xid.ID         `bun:"template_id,notnull,type:varchar(20)"                  json:"templateId"`
	AppID          xid.ID         `bun:"app_id,notnull,type:varchar(20)"                       json:"appId"`
	OrganizationID *xid.ID        `bun:"organization_id,type:varchar(20)"                      json:"organizationId,omitempty"`
	TestType       string         `bun:"test_type,notnull"                                     json:"testType"`            // preview, send, bulk
	Recipients     []string       `bun:"recipients,array"                                      json:"recipients"`          // Test recipient(s)
	Variables      map[string]any `bun:"variables,type:jsonb"                                  json:"variables,omitempty"` // Test variables
	Results        map[string]any `bun:"results,type:jsonb"                                    json:"results,omitempty"`   // Test results (success/failure for each recipient)
	Status         string         `bun:"status,notnull,default:'pending'"                      json:"status"`              // pending, running, completed, failed, partial
	Error          string         `bun:"error"                                                 json:"error,omitempty"`     // Error message if failed
	SuccessCount   int            `bun:"success_count,notnull,default:0"                       json:"successCount"`
	FailureCount   int            `bun:"failure_count,notnull,default:0"                       json:"failureCount"`
	CreatedBy      *xid.ID        `bun:"created_by,type:varchar(20)"                           json:"createdBy,omitempty"` // User who initiated the test
	Metadata       map[string]any `bun:"metadata,type:jsonb"                                   json:"metadata,omitempty"`
	CreatedAt      time.Time      `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	CompletedAt    *time.Time     `bun:"completed_at"                                          json:"completedAt,omitempty"`

	// Relations
	Template     *NotificationTemplate `bun:"rel:belongs-to,join:template_id=id"     json:"template,omitempty"`
	App          *App                  `bun:"rel:belongs-to,join:app_id=id"          json:"app,omitempty"`
	Organization *Organization         `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"`
	User         *User                 `bun:"rel:belongs-to,join:created_by=id"      json:"user,omitempty"`
}

NotificationTest represents a test execution for notification templates.

type NotificationTestStatus

type NotificationTestStatus string

NotificationTestStatus represents the test execution status.

const (
	NotificationTestStatusPending   NotificationTestStatus = "pending"   // Test queued
	NotificationTestStatusRunning   NotificationTestStatus = "running"   // Test in progress
	NotificationTestStatusCompleted NotificationTestStatus = "completed" // Test completed successfully
	NotificationTestStatusFailed    NotificationTestStatus = "failed"    // Test failed
	NotificationTestStatusPartial   NotificationTestStatus = "partial"   // Some tests succeeded, some failed
)

type NotificationTestType

type NotificationTestType string

NotificationTestType represents the type of test being performed.

const (
	NotificationTestTypePreview NotificationTestType = "preview" // Template preview/render test
	NotificationTestTypeSend    NotificationTestType = "send"    // Single test send
	NotificationTestTypeBulk    NotificationTestType = "bulk"    // Bulk test with multiple recipients
)

type OAuthClient

type OAuthClient struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:oauth_clients,alias:oc"`

	ID             xid.ID  `bun:"id,pk,type:varchar(20)"                  json:"id"`
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`
	EnvironmentID  xid.ID  `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"        json:"organizationID,omitempty"` // null = app-level
	Name           string  `bun:"name,notnull"                            json:"name"`
	ClientID       string  `bun:"client_id,notnull,unique"                json:"clientID"`
	ClientSecret   string  `bun:"client_secret,notnull"                   json:"-"`

	// OAuth2/OIDC Configuration
	RedirectURI            string   `bun:"redirect_uri,notnull"                        json:"redirectURI"` // Legacy single URI, kept for backward compatibility
	RedirectURIs           []string `bun:"redirect_uris,array,type:text[]"             json:"redirectURIs"`
	PostLogoutRedirectURIs []string `bun:"post_logout_redirect_uris,array,type:text[]" json:"postLogoutRedirectURIs,omitempty"`
	GrantTypes             []string `bun:"grant_types,array,type:text[]"               json:"grantTypes"`    // Default: ["authorization_code", "refresh_token"] - set in application code
	ResponseTypes          []string `bun:"response_types,array,type:text[]"            json:"responseTypes"` // Default: ["code"] - set in application code
	AllowedScopes          []string `bun:"allowed_scopes,array,type:text[]"            json:"allowedScopes,omitempty"`

	// Client Authentication & Security
	TokenEndpointAuthMethod string `bun:"token_endpoint_auth_method,default:'client_secret_basic'" json:"tokenEndpointAuthMethod"` // client_secret_basic, client_secret_post, none
	ApplicationType         string `bun:"application_type,default:'web'"                           json:"applicationType"`         // web, native, spa
	RequirePKCE             bool   `bun:"require_pkce,default:false"                               json:"requirePKCE"`
	RequireConsent          bool   `bun:"require_consent,default:true"                             json:"requireConsent"`
	TrustedClient           bool   `bun:"trusted_client,default:false"                             json:"trustedClient"`

	// Client Metadata (RFC 7591)
	LogoURI   string   `bun:"logo_uri"                   json:"logoURI,omitempty"`
	PolicyURI string   `bun:"policy_uri"                 json:"policyURI,omitempty"`
	TosURI    string   `bun:"tos_uri"                    json:"tosURI,omitempty"`
	Contacts  []string `bun:"contacts,array,type:text[]" json:"contacts,omitempty"`

	// Flexible metadata storage
	Metadata map[string]any `bun:"metadata,type:jsonb" json:"metadata,omitempty"`

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
}

OAuthClient stores registered OAuth/OIDC clients.

type OAuthConsent

type OAuthConsent struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:oauth_consents,alias:oc"`

	ID             xid.ID  `bun:"id,pk,type:varchar(20)"                  json:"id"`
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`
	EnvironmentID  xid.ID  `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"        json:"organizationID,omitempty"` // Optional org context
	UserID         xid.ID  `bun:"user_id,notnull,type:varchar(20)"        json:"userID"`
	ClientID       string  `bun:"client_id,notnull"                       json:"clientID"`

	// Consent details
	Scopes    []string   `bun:"scopes,array,type:text[],notnull" json:"scopes"`              // Granted scopes
	ExpiresAt *time.Time `bun:"expires_at"                       json:"expiresAt,omitempty"` // Optional consent expiration

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	User         *User         `bun:"rel:belongs-to,join:user_id=id"`
}

OAuthConsent stores persistent user consent decisions for OAuth clients.

func (*OAuthConsent) HasScope

func (oc *OAuthConsent) HasScope(scope string) bool

HasScope checks if a specific scope was granted.

func (*OAuthConsent) IsExpired

func (oc *OAuthConsent) IsExpired() bool

IsExpired checks if the consent has expired.

func (*OAuthConsent) IsValid

func (oc *OAuthConsent) IsValid() bool

IsValid checks if the consent is still valid.

type OAuthToken

type OAuthToken struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:oauth_tokens,alias:ot"`

	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`
	EnvironmentID  xid.ID  `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"        json:"organizationID,omitempty"` // Optional org context
	SessionID      *xid.ID `bun:"session_id,type:varchar(20)"             json:"sessionID,omitempty"`      // Linked session for lifecycle management

	// Token fields
	AccessToken  string `bun:"access_token,unique,notnull"         json:"-"`          // The access token
	RefreshToken string `bun:"refresh_token,unique"                json:"-"`          // Optional refresh token
	IDToken      string `bun:"id_token"                            json:"-"`          // OIDC ID token
	TokenType    string `bun:"token_type,notnull,default:'Bearer'" json:"tokenType"`  // Token type (Bearer)
	TokenClass   string `bun:"token_class,default:'access_token'"  json:"tokenClass"` // access_token, refresh_token, id_token
	ClientID     string `bun:"client_id,notnull"                   json:"clientID"`   // OAuth client ID
	UserID       xid.ID `bun:"user_id,notnull,type:varchar(20)"    json:"userID"`     // User who owns the token
	Scope        string `bun:"scope,notnull"                       json:"scope"`      // Granted scopes

	// JWT Claims
	JTI       string     `bun:"jti,unique"                 json:"jti,omitempty"`       // JWT ID for token revocation by ID
	Issuer    string     `bun:"issuer"                     json:"issuer,omitempty"`    // Token issuer
	Audience  []string   `bun:"audience,array,type:text[]" json:"audience,omitempty"`  // Token audience (aud claim)
	NotBefore *time.Time `bun:"not_before"                 json:"notBefore,omitempty"` // Token validity start time (nbf claim)

	// Authentication context
	AuthTime *time.Time `bun:"auth_time"             json:"authTime,omitempty"` // When user authenticated
	ACR      string     `bun:"acr"                   json:"acr,omitempty"`      // Authentication context class reference
	AMR      []string   `bun:"amr,array,type:text[]" json:"amr,omitempty"`      // Authentication methods references

	// Lifecycle
	ExpiresAt        time.Time  `bun:"expires_at,notnull"            json:"expiresAt"`                  // Token expiration
	RefreshExpiresAt *time.Time `bun:"refresh_expires_at"            json:"refreshExpiresAt,omitempty"` // Refresh token expiration
	Revoked          bool       `bun:"revoked,notnull,default:false" json:"revoked"`                    // Whether token is revoked
	RevokedAt        *time.Time `bun:"revoked_at"                    json:"revokedAt,omitempty"`        // When token was revoked

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	Session      *Session      `bun:"rel:belongs-to,join:session_id=id"`
}

OAuthToken represents an OAuth2/OIDC access token.

func (*OAuthToken) IsExpired

func (ot *OAuthToken) IsExpired() bool

IsExpired checks if the access token has expired.

func (*OAuthToken) IsRefreshValid

func (ot *OAuthToken) IsRefreshValid() bool

IsRefreshValid checks if the refresh token is valid.

func (*OAuthToken) IsValid

func (ot *OAuthToken) IsValid() bool

IsValid checks if the access token is valid (not expired and not revoked).

type OTPCode

type OTPCode struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:twofa_otpcodes,alias:toc"`

	ID        xid.ID    `bun:"id,pk,type:varchar(20)"`
	AppID     xid.ID    `bun:"app_id,notnull,type:varchar(20)"`
	UserID    xid.ID    `bun:"user_id,notnull,type:varchar(20)"`
	CodeHash  string    `bun:"code_hash,notnull"`
	ExpiresAt time.Time `bun:"expires_at,notnull"`
	Attempts  int       `bun:"attempts,notnull,default:0"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

OTPCode stores one-time codes for OTP-based 2FA.

type Organization

type Organization struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:organizations,alias:uo"`

	ID            xid.ID         `bun:"id,pk,type:varchar(20)"                  json:"id"`
	AppID         xid.ID         `bun:"app_id,notnull,type:varchar(20)"         json:"appID"`
	EnvironmentID xid.ID         `bun:"environment_id,notnull,type:varchar(20)" json:"environmentID"` // Foreign key to Environment
	Name          string         `bun:"name,notnull"                            json:"name"`
	Slug          string         `bun:"slug,notnull"                            json:"slug"` // Unique within app+environment
	Metadata      map[string]any `bun:"metadata,type:jsonb"                     json:"metadata"`
	CreatedBy     xid.ID         `bun:"created_by,notnull,type:varchar(20)"     json:"createdBy"`

	// Relations
	App         *App         `bun:"rel:belongs-to,join:app_id=id"         json:"app"`
	Environment *Environment `bun:"rel:belongs-to,join:environment_id=id" json:"environment"`
}

Organization represents user-created organizations (Clerk-style workspaces) within an environment.

type OrganizationInvitation

type OrganizationInvitation struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:organization_invitations,alias:uoi"`

	ID             xid.ID     `bun:"id,pk,type:varchar(20)"                   json:"id"`
	OrganizationID xid.ID     `bun:"organization_id,notnull,type:varchar(20)" json:"organizationID"`
	Email          string     `bun:"email,notnull"                            json:"email"`
	Role           string     `bun:"role,notnull"                             json:"role"`
	InviterID      xid.ID     `bun:"inviter_id,notnull,type:varchar(20)"      json:"inviterID"`
	Token          string     `bun:"token,notnull,unique"                     json:"token"`
	ExpiresAt      time.Time  `bun:"expires_at,notnull"                       json:"expiresAt"`
	AcceptedAt     *time.Time `bun:"accepted_at"                              json:"acceptedAt"`
	Status         string     `bun:"status,notnull"                           json:"status"` // pending, accepted, expired, cancelled

	// Relations
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization"`
}

OrganizationInvitation represents invitations to user-created organizations.

type OrganizationMember

type OrganizationMember struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:organization_members,alias:uom"`

	ID             xid.ID    `bun:"id,pk,type:varchar(20)"                               json:"id"`
	OrganizationID xid.ID    `bun:"organization_id,notnull,type:varchar(20)"             json:"organizationID"`
	UserID         xid.ID    `bun:"user_id,notnull,type:varchar(20)"                     json:"userID"`
	Role           string    `bun:"role,notnull"                                         json:"role"`   // owner, admin, member
	Status         string    `bun:"status,notnull,default:'active'"                      json:"status"` // active, suspended, pending
	JoinedAt       time.Time `bun:"joined_at,nullzero,notnull,default:current_timestamp" json:"joinedAt"`

	// Relations
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization"`
	User         *User         `bun:"rel:belongs-to,join:user_id=id"         json:"user"`
}

OrganizationMember represents membership in user-created organizations.

type OrganizationTeam

type OrganizationTeam struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:organization_teams,alias:uot"`

	ID             xid.ID         `bun:"id,pk,type:varchar(20)"                   json:"id"`
	OrganizationID xid.ID         `bun:"organization_id,notnull,type:varchar(20)" json:"organizationID"`
	Name           string         `bun:"name,notnull"                             json:"name"`
	Description    string         `bun:"description"                              json:"description"`
	Metadata       map[string]any `bun:"metadata,type:jsonb"                      json:"metadata"`

	// Provisioning tracking
	ProvisionedBy *string `bun:"provisioned_by,type:varchar(50)" json:"provisionedBy,omitempty"` // e.g., "scim"
	ExternalID    *string `bun:"external_id,type:varchar(255)"   json:"externalID,omitempty"`    // External system ID

	// Relations
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization"`
}

OrganizationTeam represents teams within user-created organizations.

type OrganizationTeamMember

type OrganizationTeamMember struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:organization_team_members,alias:uotm"`

	ID       xid.ID    `bun:"id,pk,type:varchar(20)"                               json:"id"`
	TeamID   xid.ID    `bun:"team_id,notnull,type:varchar(20)"                     json:"teamID"`
	MemberID xid.ID    `bun:"member_id,notnull,type:varchar(20)"                   json:"memberID"` // References OrganizationMember
	JoinedAt time.Time `bun:"joined_at,nullzero,notnull,default:current_timestamp" json:"joinedAt"`

	// Provisioning tracking
	ProvisionedBy *string `bun:"provisioned_by,type:varchar(50)" json:"provisionedBy,omitempty"` // e.g., "scim"

	// Relations
	Team   *OrganizationTeam   `bun:"rel:belongs-to,join:team_id=id"   json:"team"`
	Member *OrganizationMember `bun:"rel:belongs-to,join:member_id=id" json:"member"`
}

OrganizationTeamMember represents team membership within user-created organizations.

type Passkey

type Passkey struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:passkeys,alias:pk"`

	ID           xid.ID `bun:"id,pk,type:varchar(20)"           json:"id"`
	UserID       xid.ID `bun:"user_id,notnull,type:varchar(20)" json:"userId"`
	CredentialID string `bun:"credential_id,notnull,unique"     json:"credentialId"`

	// WebAuthn cryptographic fields
	PublicKey []byte `bun:"public_key,notnull"   json:"-"`                // COSE encoded public key
	AAGUID    []byte `bun:"aaguid"               json:"aaguid,omitempty"` // Authenticator AAGUID
	SignCount uint32 `bun:"sign_count,default:0" json:"signCount"`        // Counter for replay attack detection

	// Authenticator metadata
	AuthenticatorType string `bun:"authenticator_type" json:"authenticatorType,omitempty"` // "platform" or "cross-platform"

	// User-friendly naming for device management
	Name string `bun:"name" json:"name,omitempty"`

	// Resident key / discoverable credential support
	IsResidentKey bool `bun:"is_resident_key,default:false" json:"isResidentKey"`

	// Usage tracking
	LastUsedAt *time.Time `bun:"last_used_at" json:"lastUsedAt,omitempty"`

	// Multi-tenant scoping (App → Environment → Organization)
	AppID              xid.ID  `bun:"app_id,notnull,type:varchar(20)"       json:"appId"`                        // Platform app (required)
	UserOrganizationID *xid.ID `bun:"user_organization_id,type:varchar(20)" json:"userOrganizationId,omitempty"` // User-created org (optional)
}

Passkey stores WebAuthn/FIDO2 credentials Updated for V2 architecture: App → Environment → Organization Now includes full WebAuthn fields for production-ready implementation.

type PasswordHistory

type PasswordHistory struct {
	bun.BaseModel `bun:"table:password_histories,alias:ph"`

	ID           xid.ID    `bun:"type:varchar(20),pk"                                json:"id"`
	UserID       xid.ID    `bun:"type:varchar(20),notnull"                           json:"user_id"`
	PasswordHash string    `bun:"type:text,notnull"                                  json:"password_hash"`
	CreatedAt    time.Time `bun:"type:timestamptz,notnull,default:current_timestamp" json:"created_at"`
}

PasswordHistory tracks user password history to prevent password reuse.

type Permission

type Permission struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:permissions,alias:perm"`

	ID             xid.ID  `bun:"id,pk,type:varchar(20)"           json:"id"`
	AppID          *xid.ID `bun:"app_id,type:varchar(20)"          json:"appID"`          // App-scoped permissions
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)" json:"organizationID"` // Org-scoped permissions (NULL = app-level)
	Name           string  `bun:"name,notnull"                     json:"name"`
	Description    string  `bun:"description"                      json:"description"`
	IsCustom       bool    `bun:"is_custom,notnull,default:false"  json:"isCustom"` // Distinguishes custom from pre-defined permissions
	Category       string  `bun:"category"                         json:"category"` // Groups permissions: "users", "settings", "content", etc.

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	Roles        []Role        `bun:"m2m:role_permissions,join:Permission=Role"`
}

Permission table.

type PhoneVerification

type PhoneVerification struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:phone_verifications,alias:pver"`

	ID                 xid.ID    `bun:"id,pk,type:varchar(20)"                json:"id"`
	Phone              string    `bun:"phone,notnull"                         json:"phone"`
	Code               string    `bun:"code,notnull"                          json:"code"`
	AppID              xid.ID    `bun:"app_id,notnull,type:varchar(20)"       json:"appId"`                        // Platform app (required)
	UserOrganizationID *xid.ID   `bun:"user_organization_id,type:varchar(20)" json:"userOrganizationId,omitempty"` // User-created org (optional)
	ExpiresAt          time.Time `bun:"expires_at,notnull"                    json:"expiresAt"`
	Attempts           int       `bun:"attempts,notnull,default:0"            json:"attempts"`
}

PhoneVerification stores SMS verification codes Updated for V2 architecture: App → Environment → Organization.

type Policy

type Policy struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:policies,alias:pol"`

	ID         xid.ID `bun:"id,pk,type:varchar(20)"`
	Expression string `bun:"expression,notnull"`
}

Policy stores RBAC policy expressions.

type Role

type Role struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:roles,alias:r"`

	ID             xid.ID  `bun:"id,pk,type:varchar(20)"`
	AppID          *xid.ID `bun:"app_id,type:varchar(20)"`          // App-scoped roles
	EnvironmentID  *xid.ID `bun:"environment_id,type:varchar(20)"`  // Environment-scoped roles
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"` // Org-scoped roles (NULL = app-level template)
	Name           string  `bun:"name,notnull"`                     // Slug/identifier (e.g., "workspace_owner")
	DisplayName    string  `bun:"display_name,notnull"`             // Human-readable name (e.g., "Workspace Owner")
	Description    string  `bun:"description"`
	IsTemplate     bool    `bun:"is_template,notnull,default:false"`   // Marks roles as templates for cloning
	IsOwnerRole    bool    `bun:"is_owner_role,notnull,default:false"` // Marks the default owner role for new orgs
	TemplateID     *xid.ID `bun:"template_id,type:varchar(20)"`        // Tracks which template this role was cloned from

	// Relations
	App          *App          `bun:"rel:belongs-to,join:app_id=id"`
	Environment  *Environment  `bun:"rel:belongs-to,join:environment_id=id"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id"`
	Template     *Role         `bun:"rel:belongs-to,join:template_id=id"`
	Permissions  []Permission  `bun:"m2m:role_permissions,join:Role=Permission"`
}

Role table.

func (*Role) BeforeAppendModel added in v0.0.5

func (r *Role) BeforeAppendModel(ctx context.Context, query bun.Query) error

BeforeAppendModel is called before inserting or updating a role This ensures critical validation happens at the database layer.

type RolePermission

type RolePermission struct {
	bun.BaseModel `bun:"table:role_permissions,alias:rp"`

	ID           xid.ID    `bun:"id,pk,type:varchar(20)"`
	RoleID       xid.ID    `bun:"role_id,notnull,type:varchar(20)"`
	PermissionID xid.ID    `bun:"permission_id,notnull,type:varchar(20)"`
	CreatedAt    time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp"`
	UpdatedAt    time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp"`

	// Relations
	Role       *Role       `bun:"rel:belongs-to,join:role_id=id"`
	Permission *Permission `bun:"rel:belongs-to,join:permission_id=id"`
}

RolePermission represents the many-to-many relationship between roles and permissions.

type SSOProvider

type SSOProvider struct {
	bun.BaseModel `bun:"table:sso_providers"`

	ID        xid.ID `bun:",pk"`
	CreatedAt time.Time
	UpdatedAt time.Time

	// Multi-tenant scoping: App → Environment → Organization
	AppID          xid.ID  `bun:",notnull"`  // Platform tenant (required)
	EnvironmentID  xid.ID  `bun:",notnull"`  // Environment within app (required)
	OrganizationID *xid.ID `bun:",nullzero"` // End-user workspace (optional for app-level providers)

	ProviderID string `bun:",notnull"` // e.g., "okta-saml" or "google-oidc"
	Type       string `bun:",notnull"` // "saml" or "oidc"
	Domain     string // org domain match for auto-discovery

	// Attribute mapping from SSO assertions to user fields
	// Maps user field names to SSO attribute names
	// Example: {"email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"}
	AttributeMapping map[string]string `bun:"type:jsonb"`

	// SAML configuration
	SAMLEntryPoint string // IdP SSO URL
	SAMLIssuer     string // IdP Entity ID
	SAMLCert       string // IdP signing certificate (PEM format)

	// OIDC configuration
	OIDCClientID     string // OAuth2 client ID
	OIDCClientSecret string // OAuth2 client secret
	OIDCIssuer       string // OIDC issuer URL (e.g., https://idp.example.com)
	OIDCRedirectURI  string // Callback URL for this provider
}

SSOProvider stores SSO provider configuration with multi-tenant scoping.

type SecurityEvent

type SecurityEvent struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:security_events,alias:se"`

	ID        xid.ID  `bun:"id,pk,type:varchar(20)"`
	AppID     xid.ID  `bun:"app_id,notnull,type:varchar(20)"`
	UserID    *xid.ID `bun:"user_id,type:varchar(20)"`
	Type      string  `bun:"type,notnull"`
	IPAddress string  `bun:"ip_address"`
	UserAgent string  `bun:"user_agent"`
	Geo       string  `bun:"geo"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

SecurityEvent represents the security_events table.

type Session

type Session struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:sessions,alias:s"`

	ID    xid.ID `bun:"id,pk,type:varchar(20)"`
	Token string `bun:"token,notnull,unique"`

	// App-centric context
	AppID          xid.ID  `bun:"app_id,notnull,type:varchar(20)"`
	EnvironmentID  *xid.ID `bun:"environment_id,type:varchar(20)"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)"`

	UserID    xid.ID    `bun:"user_id,notnull,type:varchar(20)"`
	ExpiresAt time.Time `bun:"expires_at,notnull"`
	IPAddress string    `bun:"ip_address"`
	UserAgent string    `bun:"user_agent"`

	// Refresh token support (Option 3)
	RefreshToken          *string    `bun:"refresh_token,unique"`     // Long-lived refresh token
	RefreshTokenExpiresAt *time.Time `bun:"refresh_token_expires_at"` // Refresh token expiry
	LastRefreshedAt       *time.Time `bun:"last_refreshed_at"`        // When was access token last refreshed

	// Relations
	User *User `bun:"rel:belongs-to,join:user_id=id"`
}

Session represents the session table.

type SocialAccount

type SocialAccount struct {
	bun.BaseModel `bun:"table:social_accounts"`

	ID        xid.ID    `bun:",pk"`
	CreatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`
	UpdatedAt time.Time `bun:",nullzero,notnull,default:current_timestamp"`

	// User relationship
	UserID             xid.ID  `bun:",notnull"`
	User               *User   `bun:"rel:belongs-to,join:user_id=id"`
	AppID              xid.ID  `bun:"app_id,notnull"`                        // Platform app (required)
	UserOrganizationID *xid.ID `bun:"user_organization_id,type:varchar(20)"` // User-created org (optional)

	// Provider information
	Provider   string `bun:",notnull"` // google, github, microsoft, etc.
	ProviderID string `bun:",notnull"` // Provider's unique user ID
	Email      string `bun:""`         // Email from provider (may differ from user.Email)
	Name       string `bun:""`         // Display name from provider
	Avatar     string `bun:""`         // Profile picture URL

	// OAuth tokens
	AccessToken      string     `bun:",notnull"`                  // Current access token
	RefreshToken     string     `bun:""`                          // Refresh token (if provided)
	TokenType        string     `bun:",notnull,default:'Bearer'"` // Token type
	ExpiresAt        *time.Time `bun:""`                          // Access token expiration
	RefreshExpiresAt *time.Time `bun:""`                          // Refresh token expiration
	Scope            string     `bun:""`                          // Granted scopes (comma-separated)

	// ID Token (for OIDC providers)
	IDToken string `bun:"type:text"` // Full ID token JWT

	// Provider-specific data (JSON)
	RawUserInfo string `bun:"type:jsonb"` // Raw user profile from provider

	// Account status
	Revoked   bool       `bun:",notnull,default:false"` // Whether tokens were revoked
	RevokedAt *time.Time `bun:""`                       // When account was disconnected
}

SocialAccount links a user to an OAuth provider account.

func (*SocialAccount) IsRefreshTokenValid

func (sa *SocialAccount) IsRefreshTokenValid() bool

IsRefreshTokenValid checks if refresh token is valid.

func (*SocialAccount) IsTokenExpired

func (sa *SocialAccount) IsTokenExpired() bool

IsTokenExpired checks if the access token has expired.

func (*SocialAccount) NeedsRefresh

func (sa *SocialAccount) NeedsRefresh() bool

NeedsRefresh checks if the access token needs refreshing.

type SocialProviderConfig added in v0.0.3

type SocialProviderConfig struct {
	bun.BaseModel `bun:"table:social_provider_configs,alias:spc"`

	ID        xid.ID    `bun:"id,pk,type:varchar(20)"                                json:"id"`
	CreatedAt time.Time `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt time.Time `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updatedAt"`

	// Multi-tenant scoping: App → Environment
	AppID         xid.ID `bun:"app_id,notnull,type:varchar(20)"         json:"appId"`         // Platform tenant (required)
	EnvironmentID xid.ID `bun:"environment_id,notnull,type:varchar(20)" json:"environmentId"` // Environment within app (required)

	// Provider identification
	ProviderName string `bun:"provider_name,notnull" json:"providerName"` // google, github, microsoft, apple, facebook, discord, twitter, linkedin, spotify, twitch, dropbox, gitlab, line, reddit, slack, bitbucket, notion

	// OAuth credentials
	ClientID     string `bun:"client_id,notnull"     json:"clientId"`              // OAuth client ID
	ClientSecret string `bun:"client_secret,notnull" json:"-"`                     // OAuth client secret (encrypted, never exposed in JSON)
	RedirectURL  string `bun:"redirect_url"          json:"redirectUrl,omitempty"` // Custom redirect URL (optional, defaults to system URL)

	// OAuth scopes
	Scopes []string `bun:"scopes,type:jsonb" json:"scopes"` // OAuth scopes to request

	// Status
	IsEnabled bool `bun:"is_enabled,notnull,default:false" json:"isEnabled"` // Whether provider is active for this environment

	// Advanced provider-specific configuration
	// Examples: accessType for Google ("offline"), prompt settings, custom endpoints
	AdvancedConfig map[string]any `bun:"advanced_config,type:jsonb" json:"advancedConfig,omitempty"`

	// Metadata for UI/tracking
	DisplayName string `bun:"display_name" json:"displayName,omitempty"` // Custom display name (optional)
	Description string `bun:"description"  json:"description,omitempty"` // Admin notes/description

	// Soft delete
	DeletedAt *time.Time `bun:"deleted_at,soft_delete,nullzero" json:"-"`

	// Relations
	App         *App         `bun:"rel:belongs-to,join:app_id=id"         json:"app,omitempty"`
	Environment *Environment `bun:"rel:belongs-to,join:environment_id=id" json:"environment,omitempty"`
}

SocialProviderConfig stores OAuth provider configuration per app/environment This enables dashboard-based configuration of social providers instead of code-only config.

func (*SocialProviderConfig) GetDisplayName added in v0.0.3

func (c *SocialProviderConfig) GetDisplayName() string

GetDisplayName returns the display name or provider name if not set.

func (*SocialProviderConfig) GetEffectiveScopes added in v0.0.3

func (c *SocialProviderConfig) GetEffectiveScopes() []string

GetEffectiveScopes returns the configured scopes or defaults if empty.

func (*SocialProviderConfig) HasCustomRedirectURL added in v0.0.3

func (c *SocialProviderConfig) HasCustomRedirectURL() bool

HasCustomRedirectURL returns true if a custom redirect URL is configured.

func (*SocialProviderConfig) MaskClientSecret added in v0.0.3

func (c *SocialProviderConfig) MaskClientSecret() string

MaskClientSecret returns a masked version of the client secret for display.

type StringArray

type StringArray []string

StringArray is a helper type for storing arrays of strings.

func (*StringArray) Scan

func (s *StringArray) Scan(value any) error

Scan implements sql.Scanner for StringArray.

func (StringArray) Value

func (s StringArray) Value() (driver.Value, error)

Value implements driver.Valuer for StringArray.

type Team

type Team struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:teams,alias:t"`

	ID          xid.ID         `bun:"id,pk,type:varchar(20)"          json:"id"`
	AppID       xid.ID         `bun:"app_id,notnull,type:varchar(20)" json:"appID"` // App context
	Name        string         `bun:"name,notnull"                    json:"name"`
	Description string         `bun:"description"                     json:"description"`
	Metadata    map[string]any `bun:"metadata,type:jsonb"             json:"metadata"`

	// Provisioning tracking
	ProvisionedBy *string `bun:"provisioned_by,type:varchar(50)" json:"provisionedBy,omitempty"` // e.g., "scim"
	ExternalID    *string `bun:"external_id,type:varchar(255)"   json:"externalID,omitempty"`    // External system ID

	// Relations
	App     *App     `bun:"rel:belongs-to,join:app_id=id"     json:"app,omitempty"`
	Members []Member `bun:"m2m:team_members,join:Team=Member" json:"members,omitempty"`
}

Team represents the team table (belongs to App).

type TeamMember

type TeamMember struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:team_members,alias:tm"`

	ID       xid.ID `bun:"id,pk,type:varchar(20)"`
	TeamID   xid.ID `bun:"team_id,notnull,type:varchar(20)"`
	MemberID xid.ID `bun:"member_id,notnull,type:varchar(20)"`

	// Provisioning tracking
	ProvisionedBy *string `bun:"provisioned_by,type:varchar(50)" json:"provisionedBy,omitempty"` // e.g., "scim"

	// Relations
	Team   *Team   `bun:"rel:belongs-to,join:team_id=id"`
	Member *Member `bun:"rel:belongs-to,join:member_id=id"`
}

TeamMember represents the team_members table.

type TrustedDevice

type TrustedDevice struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:trusted_devices,alias:td"`

	ID        xid.ID    `bun:"id,pk,type:varchar(20)"`
	AppID     xid.ID    `bun:"app_id,notnull,type:varchar(20)"`
	UserID    xid.ID    `bun:"user_id,notnull,type:varchar(20)"`
	DeviceID  string    `bun:"device_id,notnull"`
	ExpiresAt time.Time `bun:"expires_at,notnull"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

TrustedDevice allows skipping 2FA for a period.

type TwoFASecret

type TwoFASecret struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:twofa_secrets,alias:tfs"`

	ID      xid.ID `bun:"id,pk,type:varchar(20)"`
	AppID   xid.ID `bun:"app_id,notnull,type:varchar(20)"`
	UserID  xid.ID `bun:"user_id,notnull,type:varchar(20)"`
	Method  string `bun:"method,notnull"` // totp or otp
	Secret  string `bun:"secret"`
	Enabled bool   `bun:"enabled,notnull,default:false"`

	// Relations
	App *App `bun:"rel:belongs-to,join:app_id=id"`
}

TwoFASecret stores per-user 2FA secret data.

type UsageEvent

type UsageEvent struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:usage_events,alias:ue"`

	ID             xid.ID  `bun:"id,pk,type:varchar(20)"           json:"id"`
	UserID         *xid.ID `bun:"user_id,type:varchar(20)"         json:"userId,omitempty"`
	OrganizationID *xid.ID `bun:"organization_id,type:varchar(20)" json:"organizationId,omitempty"`
	SessionID      *xid.ID `bun:"session_id,type:varchar(20)"      json:"sessionId,omitempty"`
	APIKeyID       *xid.ID `bun:"api_key_id,type:varchar(20)"      json:"apiKeyId,omitempty"`

	// Request details
	Method     string `bun:"method,notnull" json:"method"`
	Path       string `bun:"path,notnull"   json:"path"`
	Endpoint   string `bun:"endpoint"       json:"endpoint"` // Normalized endpoint
	StatusCode int    `bun:"status_code"    json:"statusCode"`

	// Authentication context
	AuthMethod string `bun:"auth_method" json:"authMethod,omitempty"` // session, apikey, jwt, anonymous

	// Network information
	IPAddress string `bun:"ip_address"           json:"ipAddress,omitempty"`
	UserAgent string `bun:"user_agent,type:text" json:"userAgent,omitempty"`
	Country   string `bun:"country"              json:"country,omitempty"`
	City      string `bun:"city"                 json:"city,omitempty"`

	// Performance metrics
	ResponseTimeMs int64 `bun:"response_time_ms" json:"responseTimeMs"`
	RequestSize    int64 `bun:"request_size"     json:"requestSize"`
	ResponseSize   int64 `bun:"response_size"    json:"responseSize"`

	// Feature tracking
	Plugin  string `bun:"plugin"  json:"plugin,omitempty"`
	Feature string `bun:"feature" json:"feature,omitempty"`

	// Error tracking
	Error     string `bun:"error,type:text" json:"error,omitempty"`
	ErrorCode string `bun:"error_code"      json:"errorCode,omitempty"`

	// Metadata
	Metadata string `bun:"metadata,type:text" json:"metadata,omitempty"` // JSON string
}

UsageEvent represents the usage_events table for tracking API usage Note: Indexes should be created in migrations for the following columns: user_id, organization_id, session_id, api_key_id, method, endpoint, status_code, auth_method, country, plugin, feature.

type User

type User struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:users,alias:u"`

	ID              xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID           *xid.ID    `bun:"app_id,type:varchar(20),notnull"` // App association (required in new architecture)
	Email           string     `bun:"email,notnull"`                   // Unique per app, not globally
	EmailVerified   bool       `bun:"email_verified,notnull,default:false"`
	EmailVerifiedAt *time.Time `bun:"email_verified_at"`
	Name            string     `bun:"name"`
	Image           string     `bun:"image"`
	PasswordHash    string     `bun:"password_hash"`

	// Username support (Phase 6)
	Username        string `bun:"username,unique"`
	DisplayUsername string `bun:"display_username"`

	// Soft delete
	DeletedAt *time.Time `bun:"deleted_at"`
}

User represents the user table In the new architecture: - Users are app-scoped (can exist in multiple apps with different IDs) - Same email can exist across different apps - Unique constraint is on (app_id, email) combination - User membership to apps is managed via the Member table in app service.

type UserBan

type UserBan struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:user_bans,alias:ub"`

	// Primary key
	ID xid.ID `bun:"id,pk,type:varchar(20)" json:"id"`

	// App context
	AppID xid.ID `bun:"app_id,notnull,type:varchar(20)" json:"appID"`

	// Foreign keys
	UserID       xid.ID  `bun:"user_id,notnull,type:varchar(20)"      json:"userID"`
	BannedByID   xid.ID  `bun:"banned_by_id,notnull,type:varchar(20)" json:"bannedByID"`
	UnbannedByID *xid.ID `bun:"unbanned_by_id,type:varchar(20)"       json:"unbannedByID,omitempty"`

	// Ban details
	Reason    string     `bun:"reason,notnull"                 json:"reason"`
	IsActive  bool       `bun:"is_active,notnull,default:true" json:"isActive"`
	ExpiresAt *time.Time `bun:"expires_at"                     json:"expiresAt,omitempty"`

	// Timestamps
	UnbannedAt *time.Time `bun:"unbanned_at" json:"unbannedAt,omitempty"`

	// Relations
	App        *App  `bun:"rel:belongs-to,join:app_id=id"`
	User       *User `bun:"rel:belongs-to,join:user_id=id"        json:"user,omitempty"`
	BannedBy   *User `bun:"rel:belongs-to,join:banned_by_id=id"   json:"bannedBy,omitempty"`
	UnbannedBy *User `bun:"rel:belongs-to,join:unbanned_by_id=id" json:"unbannedBy,omitempty"`
}

UserBan represents a user ban record in the database.

func (*UserBan) IsCurrentlyActive

func (ub *UserBan) IsCurrentlyActive() bool

IsCurrentlyActive checks if the ban is currently active.

func (*UserBan) IsExpired

func (ub *UserBan) IsExpired() bool

IsExpired checks if the ban has expired.

func (UserBan) TableName

func (UserBan) TableName() string

TableName returns the table name for the UserBan model.

type UserRole

type UserRole struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:user_roles,alias:ur"`

	ID     xid.ID `bun:"id,pk,type:varchar(20)"`
	UserID xid.ID `bun:"user_id,notnull,type:varchar(20)"`
	RoleID xid.ID `bun:"role_id,notnull,type:varchar(20)"`
	AppID  xid.ID `bun:"app_id,notnull,type:varchar(20)"` // App context for role assignment

	// Relations
	App  *App  `bun:"rel:belongs-to,join:app_id=id"`
	User *User `bun:"rel:belongs-to,join:user_id=id"`
	Role *Role `bun:"rel:belongs-to,join:role_id=id"`
}

UserRole maps users to roles within an app.

type UserVerificationStatus

type UserVerificationStatus struct {
	bun.BaseModel `bun:"table:user_verification_status,alias:uvs"`

	ID string `bun:"id,pk,type:varchar(255)" json:"id"`

	// V2 Multi-tenant context (App → Environment → Organization)
	AppID          string  `bun:"app_id,notnull,type:varchar(20)"          json:"appId"`
	EnvironmentID  *string `bun:"environment_id,type:varchar(20)"          json:"environmentId,omitempty"`
	OrganizationID string  `bun:"organization_id,notnull,type:varchar(20)" json:"organizationId"`
	UserID         string  `bun:"user_id,notnull,type:varchar(20)"         json:"userId"`

	// Overall verification status
	IsVerified             bool       `bun:"is_verified,default:false"             json:"isVerified"`
	VerificationLevel      string     `bun:"verification_level,type:varchar(50)"   json:"verificationLevel"` // none, basic, enhanced, full
	LastVerifiedAt         *time.Time `bun:"last_verified_at,type:timestamptz"     json:"lastVerifiedAt,omitempty"`
	VerificationExpiry     *time.Time `bun:"verification_expiry,type:timestamptz"  json:"verificationExpiry,omitempty"`
	RequiresReverification bool       `bun:"requires_reverification,default:false" json:"requiresReverification"`

	// Individual check statuses
	DocumentVerified bool `bun:"document_verified,default:false" json:"documentVerified"`
	LivenessVerified bool `bun:"liveness_verified,default:false" json:"livenessVerified"`
	AgeVerified      bool `bun:"age_verified,default:false"      json:"ageVerified"`
	AMLScreened      bool `bun:"aml_screened,default:false"      json:"amlScreened"`
	AMLClear         bool `bun:"aml_clear,default:false"         json:"amlClear"`

	// Most recent verification IDs
	LastDocumentVerificationID string `bun:"last_document_verification_id,type:varchar(255)" json:"lastDocumentVerificationId,omitempty"`
	LastLivenessVerificationID string `bun:"last_liveness_verification_id,type:varchar(255)" json:"lastLivenessVerificationId,omitempty"`
	LastAMLVerificationID      string `bun:"last_aml_verification_id,type:varchar(255)"      json:"lastAMLVerificationId,omitempty"`

	// Risk assessment
	OverallRiskLevel string   `bun:"overall_risk_level,type:varchar(20)" json:"overallRiskLevel"` // low, medium, high
	RiskFactors      []string `bun:"risk_factors,type:jsonb"             json:"riskFactors,omitempty"`

	// Compliance flags
	IsBlocked   bool       `bun:"is_blocked,default:false"    json:"isBlocked"`
	BlockReason string     `bun:"block_reason,type:text"      json:"blockReason,omitempty"`
	BlockedAt   *time.Time `bun:"blocked_at,type:timestamptz" json:"blockedAt,omitempty"`

	// Metadata
	Metadata map[string]any `bun:"metadata,type:jsonb" json:"metadata,omitempty"`

	CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"createdAt"`
	UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updatedAt"`

	// Relations
	User         *User         `bun:"rel:belongs-to,join:user_id=id"         json:"user,omitempty"`
	Organization *Organization `bun:"rel:belongs-to,join:organization_id=id" json:"organization,omitempty"`
}

UserVerificationStatus tracks the overall verification status of a user.

type Verification

type Verification struct {
	AuditableModel `bun:",inline"`
	bun.BaseModel  `bun:"table:verifications,alias:v"`

	ID        xid.ID     `bun:"id,pk,type:varchar(20)"`
	AppID     xid.ID     `bun:"app_id,notnull,type:varchar(20)"`
	UserID    xid.ID     `bun:"user_id,notnull,type:varchar(20)"`
	Token     string     `bun:"token,notnull,unique"`
	Code      string     `bun:"code"`         // 6-digit numeric code for mobile-friendly verification
	Type      string     `bun:"type,notnull"` // email, phone, password_reset
	ExpiresAt time.Time  `bun:"expires_at,notnull"`
	Used      bool       `bun:"used,notnull,default:false"`
	UsedAt    *time.Time `bun:"used_at"`

	// Relations
	App  *App  `bun:"rel:belongs-to,join:app_id=id"`
	User *User `bun:"rel:belongs-to,join:user_id=id"`
}

Verification represents email/phone verification tokens.

type Webhook

type Webhook struct {
	bun.BaseModel `bun:"table:webhooks,alias:w"`

	ID            xid.ID            `bun:"id,pk,type:varchar(20)"                                json:"id"`
	AppID         xid.ID            `bun:"app_id,notnull,type:varchar(20)"                       json:"app_id"`
	EnvironmentID xid.ID            `bun:"environment_id,notnull,type:varchar(20)"               json:"environment_id"`
	URL           string            `bun:"url,notnull"                                           json:"url"`
	Events        []string          `bun:"events,array"                                          json:"events"`
	Secret        string            `bun:"secret,notnull"                                        json:"-"`
	Enabled       bool              `bun:"enabled,notnull,default:true"                          json:"enabled"`
	MaxRetries    int               `bun:"max_retries,notnull,default:3"                         json:"max_retries"`
	RetryBackoff  string            `bun:"retry_backoff,notnull,default:'exponential'"           json:"retry_backoff"`
	Headers       map[string]string `bun:"headers,type:jsonb"                                    json:"headers,omitempty"`
	Metadata      map[string]string `bun:"metadata,type:jsonb"                                   json:"metadata,omitempty"`
	LastDelivery  *time.Time        `bun:"last_delivery"                                         json:"last_delivery,omitempty"`
	FailureCount  int               `bun:"failure_count,notnull,default:0"                       json:"failure_count"`
	CreatedAt     time.Time         `bun:"created_at,nullzero,notnull,default:current_timestamp" json:"created_at"`
	UpdatedAt     time.Time         `bun:"updated_at,nullzero,notnull,default:current_timestamp" json:"updated_at"`
	DeletedAt     *time.Time        `bun:"deleted_at,soft_delete,nullzero"                       json:"-"`
}

Webhook represents a webhook subscription.

Jump to

Keyboard shortcuts

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