// Package domain holds the core data model types and business rules shared // across handlers, stores, and workers. It has no Mongo or HTTP dependencies // beyond bson struct tags. package domain import "time" type Roles struct { Admin bool `bson:"admin" json:"admin"` Consultant bool `bson:"consultant" json:"consultant"` Developer bool `bson:"developer" json:"developer"` } // Has reports whether the role named r is set. Known names: admin, // consultant, developer. func (r Roles) Has(role string) bool { switch role { case "admin": return r.Admin case "consultant": return r.Consultant case "developer": return r.Developer default: return false } } type LocalAuth struct { PasswordHash string `bson:"passwordHash" json:"-"` MustChange bool `bson:"mustChange" json:"mustChange"` } type OIDCAuth struct { Issuer string `bson:"issuer" json:"issuer"` Subject string `bson:"subject" json:"subject"` } type Auth struct { Local *LocalAuth `bson:"local" json:"local,omitempty"` OIDC *OIDCAuth `bson:"oidc" json:"oidc,omitempty"` } type Contact struct { Phone string `bson:"phone" json:"phone"` Location string `bson:"location" json:"location"` Links []string `bson:"links" json:"links"` } type NotificationPrefs struct { Email bool `bson:"email" json:"email"` InApp bool `bson:"inApp" json:"inApp"` } type UserSettings struct { Theme string `bson:"theme" json:"theme"` NavLayout string `bson:"navLayout" json:"navLayout"` // "side" (default) | "top" Notifications NotificationPrefs `bson:"notifications" json:"notifications"` LeaderboardOptOut bool `bson:"leaderboardOptOut" json:"leaderboardOptOut"` } type User struct { ID string `bson:"_id" json:"id"` Email string `bson:"email" json:"email"` Name string `bson:"name" json:"name"` AvatarFileID string `bson:"avatarFileId,omitempty" json:"avatarFileId,omitempty"` Bio string `bson:"bio" json:"bio"` Contact Contact `bson:"contact" json:"contact"` Extra map[string]any `bson:"extra" json:"extra"` Roles Roles `bson:"roles" json:"roles"` Auth Auth `bson:"auth" json:"-"` Settings UserSettings `bson:"settings" json:"settings"` Disabled bool `bson:"disabled" json:"disabled"` LastSeenAt time.Time `bson:"lastSeenAt" json:"lastSeenAt"` CreatedAt time.Time `bson:"createdAt" json:"createdAt"` UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"` Version int64 `bson:"version" json:"version"` } // MustChangePassword reports whether the user is locked to the // password-change flow. func (u *User) MustChangePassword() bool { return u.Auth.Local != nil && u.Auth.Local.MustChange }