Documentation
¶
Index ¶
- Constants
- Variables
- func MapToAPIError(err error) *apierror.Error
- func ValidatePassword(password string) error
- type EmailVerification
- type EmailVerifiedPayload
- type Invitation
- type PasswordChangedPayload
- type PasswordReset
- type PasswordResetPayload
- type PasswordResetRequestedPayload
- type PlatformUser
- func NewAdminUser(email, password string, now time.Time) (*PlatformUser, error)
- func NewInvitedUser(email, password string, now time.Time) (*PlatformUser, error)
- func NewPlatformUser(email, password string, now time.Time) (*PlatformUser, error)
- func NewTelegramUser(telegramID int64, tenantID, displayName string, now time.Time) (*PlatformUser, error)
- func (u *PlatformUser) ChangeDisplayName(name string, now time.Time) error
- func (u *PlatformUser) ChangePassword(newHash string, now time.Time)
- func (u *PlatformUser) LinkTelegram(telegramID int64, now time.Time) error
- func (u *PlatformUser) UnlinkTelegram(now time.Time) error
- func (u *PlatformUser) VerifyEmail(now time.Time)
- type RoleAssignedPayload
- type RoleRevokedPayload
- type Session
- type ShopCreatedPayload
- type TelegramLinkedPayload
- type TelegramUnlinkedPayload
- type TokenRefreshedPayload
- type UserInvitationAcceptedPayload
- type UserInvitedPayload
- type UserLoggedInPayload
- type UserRegisteredPayload
Constants ¶
const ( EventUserRegistered domainevent.EventType = "user.registered" EventEmailVerified domainevent.EventType = "user.email_verified" EventUserLoggedIn domainevent.EventType = "user.logged_in" EventProfileUpdated domainevent.EventType = "user.profile_updated" EventTokenRefreshed domainevent.EventType = "user.token_refreshed" EventPasswordResetRequested domainevent.EventType = "user.password_reset_requested" EventPasswordReset domainevent.EventType = "user.password_reset" EventPasswordChanged domainevent.EventType = "user.password_changed" EventTelegramLinked domainevent.EventType = "user.telegram_linked" EventTelegramUnlinked domainevent.EventType = "user.telegram_unlinked" // Phase B: account management & RBAC events. EventUserInvited domainevent.EventType = "user.invited" EventUserInvitationAccepted domainevent.EventType = "user.invitation_accepted" EventRoleAssigned domainevent.EventType = "user.role_assigned" EventRoleRevoked domainevent.EventType = "user.role_revoked" EventShopCreated domainevent.EventType = "shop.created" )
Identity-specific event types.
const ( MinPasswordLength = 8 MaxDisplayNameLen = 100 EmailVerificationTTL = 24 * time.Hour PasswordResetTTL = 1 * time.Hour VerificationTokenLen = 32 // bytes, hex-encoded = 64 chars PasswordResetTokenLen = 32 // bytes, hex-encoded = 64 chars // TelegramSyntheticEmailDomain is the domain used for synthetic emails // generated for Telegram-native users. These emails are never disclosed or // used for login — they exist solely to satisfy the globally-unique // email_lower constraint. TelegramSyntheticEmailDomain = "telegram.local" )
const InvitationTTL = 48 * time.Hour
InvitationTTL is how long an invitation token remains valid.
const InvitationTokenLen = 32
InvitationTokenLen is the random token byte length (hex-encoded to 2x chars).
Variables ¶
var ( ErrPasswordTooShort = errors.New("password must be at least 8 characters") ErrPasswordTooWeak = errors.New("password must contain uppercase, lowercase, and digit characters") ErrDisplayNameTooLong = errors.New("display name exceeds maximum length") ErrTelegramAlreadyLinked = errors.New("telegram already linked") ErrTelegramNotLinked = errors.New("telegram not linked") )
Functions ¶
func MapToAPIError ¶
MapToAPIError maps identity aggregate-level errors to API error codes. Returns nil if the error is not an identity aggregate error.
func ValidatePassword ¶
ValidatePassword checks that the password meets minimum complexity requirements: at least MinPasswordLength characters, contains an uppercase letter, a lowercase letter, and a digit.
Types ¶
type EmailVerification ¶
type EmailVerification struct {
ID string
UserID string
Email string
Token string
ExpiresAt time.Time
CreatedAt time.Time
}
func NewEmailVerification ¶
func NewEmailVerification(userID, email string, now time.Time) (*EmailVerification, error)
NewEmailVerification generates a new email verification record with a cryptographically random hex token and a TTL-based expiration.
func (*EmailVerification) IsExpiredAt ¶
func (v *EmailVerification) IsExpiredAt(now time.Time) bool
IsExpiredAt returns true if the verification token has passed its expiration relative to the given time.
type EmailVerifiedPayload ¶
EmailVerifiedPayload is the typed payload for EventEmailVerified.
func (EmailVerifiedPayload) EventType ¶
func (EmailVerifiedPayload) EventType() domainevent.EventType
type Invitation ¶
type Invitation struct {
ID string
Email string
Token string
RoleKey string
TenantID *string
CommissionRate *int
InvitedBy string
ExpiresAt time.Time
CreatedAt time.Time
}
Invitation is a pending account-creation grant addressed to an email. The invitee may not exist yet, so there is no UserID. role_key/tenant_id carry the binding to apply on accept; commission_rate is set only for shop_owner invites.
func NewInvitation ¶
func NewInvitation(email, roleKey string, tenantID *string, commissionRate *int, invitedBy string, now time.Time) (*Invitation, error)
NewInvitation validates the email and mints a single-use token with a TTL.
func (*Invitation) IsExpiredAt ¶
func (i *Invitation) IsExpiredAt(now time.Time) bool
IsExpiredAt reports whether the invitation has passed its expiry.
type PasswordChangedPayload ¶
type PasswordChangedPayload struct {
UserID string `json:"user_id"`
}
PasswordChangedPayload is the typed payload for EventPasswordChanged.
func (PasswordChangedPayload) EventType ¶
func (PasswordChangedPayload) EventType() domainevent.EventType
type PasswordReset ¶
type PasswordReset struct {
ID string
UserID string
Email string
Token string
ExpiresAt time.Time
CreatedAt time.Time
}
PasswordReset represents a token-based password reset request.
func NewPasswordReset ¶
func NewPasswordReset(userID, email string, now time.Time) (*PasswordReset, error)
NewPasswordReset generates a new password reset record with a cryptographically random hex token and a TTL-based expiration.
func (*PasswordReset) IsExpiredAt ¶
func (pr *PasswordReset) IsExpiredAt(now time.Time) bool
IsExpiredAt returns true if the password reset token has passed its expiration relative to the given time.
type PasswordResetPayload ¶
type PasswordResetPayload struct {
UserID string `json:"user_id"`
}
PasswordResetPayload is the typed payload for EventPasswordReset.
func (PasswordResetPayload) EventType ¶
func (PasswordResetPayload) EventType() domainevent.EventType
type PasswordResetRequestedPayload ¶
type PasswordResetRequestedPayload struct {
UserID string `json:"user_id"`
Email string `json:"email"`
Token string `json:"token"`
}
PasswordResetRequestedPayload is the typed payload for EventPasswordResetRequested.
func (PasswordResetRequestedPayload) EventType ¶
func (PasswordResetRequestedPayload) EventType() domainevent.EventType
type PlatformUser ¶
type PlatformUser struct {
domainevent.EventRecorder
ID string `json:"id"`
Email string `json:"email"`
PasswordHash string `json:"-"`
DisplayName string `json:"display_name"`
EmailVerified bool `json:"email_verified"`
TelegramID *int64 `json:"telegram_id,omitempty"`
Role vo.Role `json:"role"`
TenantID *string `json:"tenant_id,omitempty"`
MustChangePassword bool `json:"must_change_password"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
PlatformUser is the aggregate root for a platform identity. It embeds EventRecorder to accumulate domain events during mutations.
func NewAdminUser ¶
func NewAdminUser(email, password string, now time.Time) (*PlatformUser, error)
NewAdminUser builds the bootstrap administrator: role=admin with a pre-verified email (the first admin has no email-verification flow). It reuses the same email/password validation and hashing as NewPlatformUser.
func NewInvitedUser ¶
func NewInvitedUser(email, password string, now time.Time) (*PlatformUser, error)
NewInvitedUser builds an email-verified user from an accepted invitation. The legacy role column stays RoleCustomer; the real authorization is the role binding written alongside this user. email_verified=true is intentional — the invite token was delivered to that address (see spec §6).
func NewPlatformUser ¶
func NewPlatformUser(email, password string, now time.Time) (*PlatformUser, error)
NewPlatformUser validates inputs, hashes the password, and returns a new PlatformUser with a generated UUID and RoleCustomer.
func NewTelegramUser ¶
func NewTelegramUser(telegramID int64, tenantID, displayName string, now time.Time) (*PlatformUser, error)
NewTelegramUser builds a Telegram-native customer of a shop: a deterministic synthetic email unique per (telegramID, tenantID), a random unusable password (the user authenticates via Telegram, never the email/password form), with TelegramID and TenantID set.
func (*PlatformUser) ChangeDisplayName ¶
func (u *PlatformUser) ChangeDisplayName(name string, now time.Time) error
ChangeDisplayName validates and sets the user's display name.
func (*PlatformUser) ChangePassword ¶
func (u *PlatformUser) ChangePassword(newHash string, now time.Time)
ChangePassword sets a pre-hashed password on the user. Callers are responsible for hashing the raw password before invoking this method.
func (*PlatformUser) LinkTelegram ¶
func (u *PlatformUser) LinkTelegram(telegramID int64, now time.Time) error
LinkTelegram associates a Telegram account with the user. Returns an error if a Telegram account is already linked.
func (*PlatformUser) UnlinkTelegram ¶
func (u *PlatformUser) UnlinkTelegram(now time.Time) error
UnlinkTelegram removes the Telegram association. Returns an error if no Telegram account is currently linked.
func (*PlatformUser) VerifyEmail ¶
func (u *PlatformUser) VerifyEmail(now time.Time)
VerifyEmail marks the user's email as verified and updates the timestamp.
type RoleAssignedPayload ¶
type RoleAssignedPayload struct {
UserID string `json:"user_id"`
RoleKey string `json:"role_key"`
TenantID *string `json:"tenant_id,omitempty"`
GrantedBy string `json:"granted_by"`
}
RoleAssignedPayload is the typed payload for EventRoleAssigned.
func (RoleAssignedPayload) EventType ¶
func (RoleAssignedPayload) EventType() domainevent.EventType
type RoleRevokedPayload ¶
type RoleRevokedPayload struct {
UserID string `json:"user_id"`
RoleKey string `json:"role_key"`
TenantID *string `json:"tenant_id,omitempty"`
}
RoleRevokedPayload is the typed payload for EventRoleRevoked.
func (RoleRevokedPayload) EventType ¶
func (RoleRevokedPayload) EventType() domainevent.EventType
type ShopCreatedPayload ¶
type ShopCreatedPayload struct {
TenantID string `json:"tenant_id"`
OwnerUserID *string `json:"owner_user_id,omitempty"`
}
ShopCreatedPayload is the typed payload for EventShopCreated.
func (ShopCreatedPayload) EventType ¶
func (ShopCreatedPayload) EventType() domainevent.EventType
type TelegramLinkedPayload ¶
type TelegramLinkedPayload struct {
UserID string `json:"user_id"`
TelegramID int64 `json:"telegram_id"`
}
TelegramLinkedPayload is the typed payload for EventTelegramLinked.
func (TelegramLinkedPayload) EventType ¶
func (TelegramLinkedPayload) EventType() domainevent.EventType
type TelegramUnlinkedPayload ¶
type TelegramUnlinkedPayload struct {
UserID string `json:"user_id"`
TelegramID int64 `json:"telegram_id"`
}
TelegramUnlinkedPayload is the typed payload for EventTelegramUnlinked.
func (TelegramUnlinkedPayload) EventType ¶
func (TelegramUnlinkedPayload) EventType() domainevent.EventType
type TokenRefreshedPayload ¶
type TokenRefreshedPayload struct {
UserID string `json:"user_id"`
}
TokenRefreshedPayload is the typed payload for EventTokenRefreshed.
func (TokenRefreshedPayload) EventType ¶
func (TokenRefreshedPayload) EventType() domainevent.EventType
type UserInvitationAcceptedPayload ¶
type UserInvitationAcceptedPayload struct {
UserID string `json:"user_id"`
Email string `json:"email"`
}
UserInvitationAcceptedPayload is the typed payload for EventUserInvitationAccepted.
func (UserInvitationAcceptedPayload) EventType ¶
func (UserInvitationAcceptedPayload) EventType() domainevent.EventType
type UserInvitedPayload ¶
type UserInvitedPayload struct {
InvitationID string `json:"invitation_id"`
Email string `json:"email"`
RoleKey string `json:"role_key"`
TenantID *string `json:"tenant_id,omitempty"`
}
UserInvitedPayload is the typed payload for EventUserInvited.
func (UserInvitedPayload) EventType ¶
func (UserInvitedPayload) EventType() domainevent.EventType
type UserLoggedInPayload ¶
type UserLoggedInPayload struct {
UserID string `json:"user_id"`
}
UserLoggedInPayload is the typed payload for EventUserLoggedIn.
func (UserLoggedInPayload) EventType ¶
func (UserLoggedInPayload) EventType() domainevent.EventType
type UserRegisteredPayload ¶
UserRegisteredPayload is the typed payload for EventUserRegistered.
func (UserRegisteredPayload) EventType ¶
func (UserRegisteredPayload) EventType() domainevent.EventType