Documentation
¶
Overview ¶
Package user defines the user domain entity and its store interface.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NormalizeEmail ¶
NormalizeEmail lowercases and trims an email address so lookups and uniqueness checks are case-insensitive and whitespace-insensitive.
Types ¶
type List ¶
type List struct {
Users []*User `json:"users"`
NextCursor string `json:"next_cursor,omitempty"`
Total int `json:"total"`
}
List is a paginated list of users.
type Query ¶
type Query struct {
AppID id.AppID `json:"app_id"`
EnvID id.EnvironmentID `json:"env_id,omitempty"`
Email string `json:"email,omitempty"`
Cursor string `json:"cursor,omitempty"`
Limit int `json:"limit,omitempty"`
}
Query holds query parameters for listing users.
type Store ¶
type Store interface {
CreateUser(ctx context.Context, u *User) error
GetUser(ctx context.Context, userID id.UserID) (*User, error)
// GetUserByEmail resolves the user whose primary email matches within
// (appID, envID). A nil envID matches app-wide, mirroring GetUserByAnyEmail.
GetUserByEmail(ctx context.Context, appID id.AppID, envID id.EnvironmentID, email string) (*User, error)
// GetUserByPhone resolves the user owning phone within (appID, envID).
// A nil envID matches app-wide, mirroring GetUserByAnyEmail.
GetUserByPhone(ctx context.Context, appID id.AppID, envID id.EnvironmentID, phone string) (*User, error)
// GetUserByUsername resolves the user owning username within (appID,
// envID). A nil envID matches app-wide, which is what the signup and
// rename guards rely on to keep handles unique across a whole app.
GetUserByUsername(ctx context.Context, appID id.AppID, envID id.EnvironmentID, username string) (*User, error)
UpdateUser(ctx context.Context, u *User) error
DeleteUser(ctx context.Context, userID id.UserID) error
ListUsers(ctx context.Context, q *Query) (*List, error)
// CreateUserWithPrimaryEmail creates a user and its primary email row.
// The address must be free within (AppID, EnvID), else ErrEmailTaken.
CreateUserWithPrimaryEmail(ctx context.Context, u *User, primary *UserEmail) error
// AddUserEmail attaches an additional email to a user. Returns
// account.ErrEmailTaken if the address is already owned within the env.
AddUserEmail(ctx context.Context, e *UserEmail) error
// GetUserByAnyEmail resolves the user owning any (primary or secondary)
// verified-or-not email matching (appID, envID, email). ErrNotFound when none.
GetUserByAnyEmail(ctx context.Context, appID id.AppID, envID id.EnvironmentID, email string) (*User, error)
// GetUserEmailRecord returns the email row matching (appID, envID, email)
// so callers can inspect Verified before linking. ErrNotFound when none.
GetUserEmailRecord(ctx context.Context, appID id.AppID, envID id.EnvironmentID, email string) (*UserEmail, error)
// GetUserEmails returns all live emails for a user, primary first.
GetUserEmails(ctx context.Context, userID id.UserID) ([]*UserEmail, error)
// MarkUserEmailVerified marks an email verified, mirroring onto the user
// record when it is the primary email.
MarkUserEmailVerified(ctx context.Context, userID id.UserID, email string) error
// SetPrimaryEmail makes a verified, user-owned email primary, updating the
// user mirror. Returns account.ErrEmailNotVerified if the target is unverified.
SetPrimaryEmail(ctx context.Context, userID id.UserID, email string) error
// DeleteUserEmail soft-deletes a non-primary email. Refuses the primary
// with store.ErrConflict.
DeleteUserEmail(ctx context.Context, userID id.UserID, email string) error
}
Store defines the persistence interface for user operations.
type User ¶
type User struct {
ID id.UserID `json:"id"`
AppID id.AppID `json:"app_id"`
EnvID id.EnvironmentID `json:"env_id"`
Email string `json:"email"`
EmailVerified bool `json:"email_verified"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Image string `json:"image,omitempty"`
Username string `json:"username,omitempty"`
DisplayUsername string `json:"display_username,omitempty"`
Phone string `json:"phone,omitempty"`
PhoneVerified bool `json:"phone_verified"`
PasswordHash string `json:"-"`
PasswordChangedAt *time.Time `json:"password_changed_at,omitempty"`
Banned bool `json:"banned"`
BanReason string `json:"ban_reason,omitempty"`
BanExpires *time.Time `json:"ban_expires,omitempty"`
Metadata Metadata `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
}
User represents an authenticated identity within an application.
type UserEmail ¶
type UserEmail struct {
ID id.UserEmailID `json:"id"`
UserID id.UserID `json:"user_id"`
AppID id.AppID `json:"app_id"`
EnvID id.EnvironmentID `json:"env_id"`
Email string `json:"email"` // always stored lowercased + trimmed
Verified bool `json:"verified"`
IsPrimary bool `json:"is_primary"`
Source string `json:"source"` // e.g. "password", "social:github", "sso", "scim", "admin", "backfill"
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt *time.Time `json:"deleted_at,omitempty"`
}
UserEmail is a single email address belonging to a user. A user may own multiple emails; exactly one is marked primary and mirrors User.Email / User.EmailVerified. Email uniqueness is enforced per (AppID, EnvID, Email) so an address can belong to at most one account within an environment.
func NewPrimaryEmail ¶
NewPrimaryEmail builds the primary UserEmail row mirroring a user's current Email/EmailVerified, for use with Store.CreateUserWithPrimaryEmail. source records where the address came from (e.g. "password", "sso", "scim").