domain

package
v1.28.0 Latest Latest
Warning

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

Go to latest
Published: Feb 22, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PBKDF2MinIterations     = 600000  // Minimum (security)
	PBKDF2DefaultIterations = 600000  // Default (balanced)
	PBKDF2MaxIterations     = 2000000 // Maximum (high security)
)

PBKDF2 defaults (OWASP 2023 recommendations)

View Source
const (
	Argon2DefaultIterations  = 3  // Time cost
	Argon2DefaultMemory      = 64 // 64 MB
	Argon2DefaultParallelism = 4  // 4 threads

	Argon2MinIterations  = 2
	Argon2MaxIterations  = 10
	Argon2MinMemory      = 16   // 16 MB
	Argon2MaxMemory      = 1024 // 1 GB
	Argon2MinParallelism = 1
	Argon2MaxParallelism = 16
)

Argon2id defaults (industry standard)

View Source
const (
	// Users permissions
	PermissionUsersRead   = "users.read"
	PermissionUsersCreate = "users.create"
	PermissionUsersUpdate = "users.update"
	PermissionUsersDelete = "users.delete"

	// Logins permissions
	PermissionLoginsRead   = "logins.read"
	PermissionLoginsCreate = "logins.create"
	PermissionLoginsUpdate = "logins.update"
	PermissionLoginsDelete = "logins.delete"

	// Credit Cards permissions
	PermissionCreditCardsRead   = "credit_cards.read"
	PermissionCreditCardsCreate = "credit_cards.create"
	PermissionCreditCardsUpdate = "credit_cards.update"
	PermissionCreditCardsDelete = "credit_cards.delete"

	// Bank Accounts permissions
	PermissionBankAccountsRead   = "bank_accounts.read"
	PermissionBankAccountsCreate = "bank_accounts.create"
	PermissionBankAccountsUpdate = "bank_accounts.update"
	PermissionBankAccountsDelete = "bank_accounts.delete"

	// Notes permissions
	PermissionNotesRead   = "notes.read"
	PermissionNotesCreate = "notes.create"
	PermissionNotesUpdate = "notes.update"
	PermissionNotesDelete = "notes.delete"

	// Emails permissions
	PermissionEmailsRead   = "emails.read"
	PermissionEmailsCreate = "emails.create"
	PermissionEmailsUpdate = "emails.update"
	PermissionEmailsDelete = "emails.delete"
)

Permission name constants

View Source
const (
	// Organization permissions
	PermOrgView              = "org:view"
	PermOrgUpdate            = "org:update"
	PermOrgDelete            = "org:delete"
	PermOrgTransferOwnership = "org:transfer_ownership"
	PermOrgManageSettings    = "org:manage_settings"

	// Member permissions
	PermMemberView       = "member:view"
	PermMemberInvite     = "member:invite"
	PermMemberRemove     = "member:remove"
	PermMemberUpdateRole = "member:update_role"

	// Billing permissions
	PermBillingView            = "billing:view"
	PermBillingUpdate          = "billing:update"
	PermBillingCancel          = "billing:cancel"
	PermBillingDownloadInvoice = "billing:download_invoice"

	// Collection permissions
	PermCollectionCreate = "collection:create"
	PermCollectionView   = "collection:view"
	PermCollectionUpdate = "collection:update"
	PermCollectionDelete = "collection:delete"

	// Item permissions
	PermItemCreate = "item:create"
	PermItemView   = "item:view"
	PermItemUpdate = "item:update"
	PermItemDelete = "item:delete"
	PermItemShare  = "item:share"
	PermItemExport = "item:export"

	// Activity/Audit permissions
	PermActivityView   = "activity:view"
	PermActivityExport = "activity:export"

	// Security permissions
	PermSecurityRotateKeys     = "security:rotate_keys"
	PermSecurityRevokeSessions = "security:revoke_sessions"
)

Permission constants

View Source
const (
	SCIMSchemaUser          = "urn:ietf:params:scim:schemas:core:2.0:User"
	SCIMSchemaGroup         = "urn:ietf:params:scim:schemas:core:2.0:Group"
	SCIMSchemaListResponse  = "urn:ietf:params:scim:api:messages:2.0:ListResponse"
	SCIMSchemaError         = "urn:ietf:params:scim:api:messages:2.0:Error"
	SCIMSchemaPatchOp       = "urn:ietf:params:scim:api:messages:2.0:PatchOp"
	SCIMSchemaServiceConfig = "urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig"
	SCIMSchemaResourceType  = "urn:ietf:params:scim:schemas:core:2.0:ResourceType"
	SCIMSchemaSchema        = "urn:ietf:params:scim:schemas:core:2.0:Schema"
)

SCIM 2.0 schema URNs

Variables

PermissionMatrix defines permissions for each role

Functions

func Can

func Can(role OrganizationRole, permission string) bool

Can checks if a role has a specific permission

func DetectStoreFromSubscriptionID

func DetectStoreFromSubscriptionID(subscriptionID *string) string

DetectStoreFromSubscriptionID extracts the store name from a RevenueCat subscription ID. Returns empty string for non-RevenueCat subscriptions. RevenueCat format: "rc_{STORE}_{transaction_id}" e.g. "rc_PLAY_STORE_abc123"

func GenerateSCIMToken

func GenerateSCIMToken() (string, error)

GenerateSCIMToken creates a cryptographically secure random token string

func GetPermissions

func GetPermissions(role OrganizationRole) []string

GetPermissions returns all permissions for a role

func IsWritePermission

func IsWritePermission(permission string) bool

IsWritePermission checks if a permission is a write operation

func StoreDisplayName

func StoreDisplayName(store string) string

StoreDisplayName returns a user-friendly name for the store

Types

type ActivityType

type ActivityType string

ActivityType represents the type of user activity

const (
	ActivityTypeSignIn         ActivityType = "signin"
	ActivityTypeSignOut        ActivityType = "signout"
	ActivityTypePasswordChange ActivityType = "password_change"
	ActivityTypeEmailVerified  ActivityType = "email_verified"
	ActivityTypeAccountCreated ActivityType = "account_created"
	ActivityTypeVaultUnlock    ActivityType = "vault_unlock"
	ActivityTypeVaultLock      ActivityType = "vault_lock"
	ActivityTypeItemCreated    ActivityType = "item_created"
	ActivityTypeItemUpdated    ActivityType = "item_updated"
	ActivityTypeItemDeleted    ActivityType = "item_deleted"
	ActivityTypeFailedSignIn   ActivityType = "failed_signin"

	// Admin / Audit activities (admin-only visibility in UI)
	ActivityTypeAdminUserCreated ActivityType = "admin_user_created"
	ActivityTypeAdminUserUpdated ActivityType = "admin_user_updated"
	ActivityTypeAdminUserDeleted ActivityType = "admin_user_deleted"

	// Billing & Subscription Activities
	ActivityTypeCheckoutCreated         ActivityType = "checkout_created"
	ActivityTypeSubscriptionCreated     ActivityType = "subscription_created"
	ActivityTypeSubscriptionUpdated     ActivityType = "subscription_updated"
	ActivityTypeSubscriptionCanceled    ActivityType = "subscription_canceled"
	ActivityTypeSubscriptionReactivated ActivityType = "subscription_reactivated"
	ActivityTypeInvoicePaid             ActivityType = "invoice_paid"
	ActivityTypeInvoicePaymentFailed    ActivityType = "invoice_payment_failed"
	ActivityTypeOrganizationUpgraded    ActivityType = "organization_upgraded"
	ActivityTypeOrganizationDowngraded  ActivityType = "organization_downgraded"
)

type AddTeamUserRequest

type AddTeamUserRequest struct {
	OrganizationUserID uint `json:"organization_user_id" validate:"required"`
	IsManager          bool `json:"is_manager"`
}

AddTeamUserRequest for adding users to team

type AuthResponse

type AuthResponse struct {
	AccessToken           string       `json:"access_token"`
	RefreshToken          string       `json:"refresh_token"`
	Type                  string       `json:"type"`                               // "Bearer"
	AccessTokenExpiresAt  int64        `json:"access_token_expires_at,omitempty"`  // unix seconds
	RefreshTokenExpiresAt int64        `json:"refresh_token_expires_at,omitempty"` // unix seconds
	ProtectedUserKey      string       `json:"protected_user_key"`
	KdfConfig             *KdfConfig   `json:"kdf_config"`
	User                  *UserAuthDTO `json:"user"`
}

AuthResponse represents the authentication response

type BillingCycle

type BillingCycle string

BillingCycle represents billing period

const (
	BillingCycleMonthly BillingCycle = "monthly"
	BillingCycleYearly  BillingCycle = "yearly"
)

type BillingInfo

type BillingInfo struct {
	Organization *OrganizationDTO `json:"organization"`
	Subscription *SubscriptionDTO `json:"subscription,omitempty"`

	// Current usage
	CurrentUsers       int `json:"current_users"`
	CurrentCollections int `json:"current_collections"`
	CurrentItems       int `json:"current_items"`

	// Invoices
	Invoices []*InvoiceDTO `json:"invoices,omitempty"`
}

BillingInfo contains billing and subscription information

type CancelSubscriptionRequest

type CancelSubscriptionRequest struct {
	Immediate bool `json:"immediate"` // Cancel immediately or at period end
}

CancelSubscriptionRequest for API requests

type ChangeMasterPasswordRequest

type ChangeMasterPasswordRequest struct {
	// NOTE: This endpoint is authenticated (JWT). The server will use the
	// authenticated user (context) and ignore any client-provided email.
	Email string `json:"email,omitempty"`

	OldMasterPasswordHash string `json:"old_master_password_hash" validate:"required"`

	NewMasterPasswordHash string `json:"new_master_password_hash" validate:"required"`
	NewProtectedUserKey   string `json:"new_protected_user_key" validate:"required"`

	// Optional: rotate KDF settings and salt
	NewKdfConfig *KdfConfig `json:"new_kdf_config,omitempty"`
	NewKdfSalt   string     `json:"new_kdf_salt,omitempty"`
}

ChangeMasterPasswordRequest represents master password change request

type Collection

type Collection struct {
	ID        uint       `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID  `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
	DeletedAt *time.Time `json:"deleted_at,omitempty" gorm:"index"`

	OrganizationID uint `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Collection details
	Name        string `json:"name" gorm:"type:varchar(255);not null"`
	Description string `json:"description,omitempty" gorm:"type:text"`

	// System defaults
	IsDefault bool `json:"is_default" gorm:"not null;default:false"`

	// Access control
	IsPrivate bool `json:"is_private" gorm:"default:false"` // Only assigned users can access

	// External ID for LDAP/AD sync
	ExternalID *string `json:"external_id,omitempty" gorm:"type:varchar(255);index"`

	// Stats (runtime calculated, not stored in DB)
	ItemCount *int `json:"item_count,omitempty" gorm:"-"`
	UserCount *int `json:"user_count,omitempty" gorm:"-"`
	TeamCount *int `json:"team_count,omitempty" gorm:"-"`

	// Associations
	Organization *Organization      `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
	UserAccess   []CollectionUser   `json:"user_access,omitempty" gorm:"foreignKey:CollectionID"`
	TeamAccess   []CollectionTeam   `json:"team_access,omitempty" gorm:"foreignKey:CollectionID"`
	Items        []OrganizationItem `json:"items,omitempty" gorm:"foreignKey:CollectionID"`
}

Collection represents a shared folder at organization level

func (Collection) TableName

func (Collection) TableName() string

TableName specifies the table name

type CollectionDTO

type CollectionDTO struct {
	ID             uint      `json:"id"`
	UUID           uuid.UUID `json:"uuid"`
	OrganizationID uint      `json:"organization_id"`
	Name           string    `json:"name"`
	Description    string    `json:"description,omitempty"`
	IsPrivate      bool      `json:"is_private"`
	ExternalID     *string   `json:"external_id,omitempty"`
	IsDefault      bool      `json:"is_default"`
	CreatedAt      time.Time `json:"created_at"`
	UpdatedAt      time.Time `json:"updated_at"`

	// Stats (optional)
	ItemCount *int `json:"item_count,omitempty"`
	UserCount *int `json:"user_count,omitempty"`
	TeamCount *int `json:"team_count,omitempty"`
}

CollectionDTO for API responses

func ToCollectionDTO

func ToCollectionDTO(c *Collection) *CollectionDTO

ToCollectionDTO converts Collection to DTO

type CollectionTeam

type CollectionTeam struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	CollectionID uint `json:"collection_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	TeamID       uint `json:"team_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Permissions
	CanRead       bool `json:"can_read" gorm:"default:true"`
	CanWrite      bool `json:"can_write" gorm:"default:false"`
	CanAdmin      bool `json:"can_admin" gorm:"default:false"`
	HidePasswords bool `json:"hide_passwords" gorm:"default:false"`

	// Associations
	Collection *Collection `json:"collection,omitempty" gorm:"foreignKey:CollectionID"`
	Team       *Team       `json:"team,omitempty" gorm:"foreignKey:TeamID"`
}

CollectionTeam represents team permissions for a collection

func (CollectionTeam) TableName

func (CollectionTeam) TableName() string

TableName specifies the table name

type CollectionTeamDTO

type CollectionTeamDTO struct {
	ID            uint      `json:"id"`
	CollectionID  uint      `json:"collection_id"`
	TeamID        uint      `json:"team_id"`
	TeamName      string    `json:"team_name"`
	CanRead       bool      `json:"can_read"`
	CanWrite      bool      `json:"can_write"`
	CanAdmin      bool      `json:"can_admin"`
	HidePasswords bool      `json:"hide_passwords"`
	CreatedAt     time.Time `json:"created_at"`
}

CollectionTeamDTO for API responses

func ToCollectionTeamDTO

func ToCollectionTeamDTO(ct *CollectionTeam) *CollectionTeamDTO

ToCollectionTeamDTO converts CollectionTeam to DTO

type CollectionUser

type CollectionUser struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	CollectionID       uint `json:"collection_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	OrganizationUserID uint `json:"organization_user_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Permissions
	CanRead       bool `json:"can_read" gorm:"default:true"`
	CanWrite      bool `json:"can_write" gorm:"default:false"`
	CanAdmin      bool `json:"can_admin" gorm:"default:false"`
	HidePasswords bool `json:"hide_passwords" gorm:"default:false"` // Can view metadata but not passwords

	// Associations
	Collection       *Collection       `json:"collection,omitempty" gorm:"foreignKey:CollectionID"`
	OrganizationUser *OrganizationUser `json:"organization_user,omitempty" gorm:"foreignKey:OrganizationUserID"`
}

CollectionUser represents user permissions for a collection

func (CollectionUser) TableName

func (CollectionUser) TableName() string

TableName specifies the table name

type CollectionUserDTO

type CollectionUserDTO struct {
	ID                 uint      `json:"id"`
	CollectionID       uint      `json:"collection_id"`
	OrganizationUserID uint      `json:"organization_user_id"`
	UserID             uint      `json:"user_id"`
	UserEmail          string    `json:"user_email"`
	UserName           string    `json:"user_name"`
	CanRead            bool      `json:"can_read"`
	CanWrite           bool      `json:"can_write"`
	CanAdmin           bool      `json:"can_admin"`
	HidePasswords      bool      `json:"hide_passwords"`
	CreatedAt          time.Time `json:"created_at"`
}

CollectionUserDTO for API responses

func ToCollectionUserDTO

func ToCollectionUserDTO(cu *CollectionUser) *CollectionUserDTO

ToCollectionUserDTO converts CollectionUser to DTO

type CreateActivityRequest

type CreateActivityRequest struct {
	UserID       uint
	ActivityType ActivityType
	IPAddress    string
	UserAgent    string
	Details      string
}

CreateActivityRequest for logging activity

type CreateCollectionRequest

type CreateCollectionRequest struct {
	Name        string  `json:"name" validate:"required,max=255"`
	Description string  `json:"description,omitempty" validate:"max=1000"`
	IsPrivate   bool    `json:"is_private"`
	ExternalID  *string `json:"external_id,omitempty"`
}

CreateCollectionRequest for API requests

type CreateExcludedDomainRequest

type CreateExcludedDomainRequest struct {
	Domain string `json:"domain" validate:"required"`
}

CreateExcludedDomainRequest for API requests

type CreateInvitationRequest

type CreateInvitationRequest struct {
	Email       string  `json:"email" validate:"required,email"`
	RoleID      uint    `json:"role_id" validate:"required"`
	Description *string `json:"description,omitempty"` // Optional personal note

	// Organization invitation fields (optional)
	OrganizationID  *uint   `json:"organization_id,omitempty"`
	OrgRole         *string `json:"org_role,omitempty"`
	EncryptedOrgKey *string `json:"encrypted_org_key,omitempty"`
	AccessAll       *bool   `json:"access_all,omitempty"`
}

CreateInvitationRequest represents invitation creation request

func (*CreateInvitationRequest) Validate

func (r *CreateInvitationRequest) Validate() error

Validate validates the invitation request

type CreateItemShareRequest

type CreateItemShareRequest struct {
	ItemUUID         string     `json:"item_uuid" validate:"required"`
	SharedWithUserID *uint      `json:"shared_with_user_id,omitempty"`
	SharedWithTeamID *uint      `json:"shared_with_team_id,omitempty"`
	CanView          bool       `json:"can_view"`
	CanEdit          bool       `json:"can_edit"`
	CanShare         bool       `json:"can_share"`
	EncryptedKey     string     `json:"encrypted_key" validate:"required"` // Item key wrapped for recipient
	ExpiresAt        *time.Time `json:"expires_at,omitempty"`
}

CreateItemShareRequest for API requests

type CreateOrganizationFolderRequest

type CreateOrganizationFolderRequest struct {
	Name string `json:"name" validate:"required,max=255"`
}

type CreateOrganizationItemRequest

type CreateOrganizationItemRequest struct {
	CollectionID *uint        `json:"collection_id,omitempty"`
	ItemType     ItemType     `json:"item_type" validate:"required"`
	Data         string       `json:"data" validate:"required"` // Encrypted with Org Key
	Metadata     ItemMetadata `json:"metadata" validate:"required"`
	IsFavorite   bool         `json:"is_favorite"`
	FolderID     *uint        `json:"folder_id,omitempty"`
	Reprompt     bool         `json:"reprompt"`
	AutoFill     *bool        `json:"auto_fill,omitempty"`
	AutoLogin    *bool        `json:"auto_login,omitempty"`
}

CreateOrganizationItemRequest for API requests

type CreateOrganizationRequest

type CreateOrganizationRequest struct {
	Name            string `json:"name" validate:"required,max=255"`
	BillingEmail    string `json:"billing_email" validate:"required,email"`
	Plan            string `json:"plan" validate:"omitempty,oneof=free business enterprise"`
	EncryptedOrgKey string `json:"encrypted_org_key" validate:"required"` // Owner's copy of org key
}

CreateOrganizationRequest for API requests

type CreateSCIMTokenRequest

type CreateSCIMTokenRequest struct {
	Label     string     `json:"label" binding:"required,max=255"`
	ExpiresAt *time.Time `json:"expires_at,omitempty"`
}

CreateSCIMTokenRequest for generating a new SCIM token

type CreateSSOConnectionRequest

type CreateSSOConnectionRequest struct {
	Protocol        SSOProtocol      `json:"protocol" binding:"required,oneof=saml oidc"`
	Name            string           `json:"name" binding:"required,max=255"`
	Domain          string           `json:"domain" binding:"required,max=255"`
	SAMLConfig      *SAMLConfig      `json:"saml_config,omitempty"`
	OIDCConfig      *OIDCConfig      `json:"oidc_config,omitempty"`
	AutoProvision   *bool            `json:"auto_provision,omitempty"`
	DefaultRole     OrganizationRole `json:"default_role,omitempty"`
	JITProvisioning *bool            `json:"jit_provisioning,omitempty"`
}

CreateSSOConnectionRequest for creating a new SSO connection

type CreateSubscriptionRequest

type CreateSubscriptionRequest struct {
	PlanCode string `json:"plan_code" validate:"required"`
}

CreateSubscriptionRequest for API requests

type CreateTeamRequest

type CreateTeamRequest struct {
	Name                 string  `json:"name" validate:"required,max=255"`
	Description          string  `json:"description,omitempty" validate:"max=1000"`
	AccessAllCollections bool    `json:"access_all_collections"`
	ExternalID           *string `json:"external_id,omitempty"`
}

CreateTeamRequest for API requests

type CreateUserByAdminRequest

type CreateUserByAdminRequest struct {
	Name               string     `json:"name" validate:"required,max=100"`
	Email              string     `json:"email" validate:"required,email"`
	MasterPasswordHash string     `json:"master_password_hash" validate:"required"` // HKDF(masterKey, info="auth")
	ProtectedUserKey   string     `json:"protected_user_key" validate:"required"`   // EncString: "2.iv|ct|mac"
	EncryptedOrgKey    string     `json:"encrypted_org_key" validate:"required"`    // Organization key encrypted with User Key
	KdfConfig          *KdfConfig `json:"kdf_config" validate:"required"`
	KdfSalt            string     `json:"kdf_salt" validate:"required"` // hex-encoded random salt
	RoleID             *uint      `json:"role_id,omitempty"`
}

CreateUserByAdminRequest represents admin-created user request (zero-knowledge)

func (*CreateUserByAdminRequest) Validate

func (r *CreateUserByAdminRequest) Validate() error

Validate validates the create user request

type Credentials

type Credentials struct {
	Email              string `json:"email" validate:"required,email"`
	MasterPasswordHash string `json:"master_password_hash" validate:"required"`
	// Optional device identifier to keep a stable session per app/device.
	// Example: Vault can persist this in localStorage to avoid orphan sessions after tab close.
	DeviceID string `json:"device_id,omitempty"`
	// Optional app identifier (used with device_id). Expected: vault|extension|mobile|desktop
	App string `json:"app,omitempty"`
	// Optional login override:
	// when true and free-plan device limit is hit, revoke all active sessions and continue login.
	LogoutOtherDevices bool `json:"logout_other_devices,omitempty"`
}

Credentials represents user login credentials

type DeleteWithOrganizationsRequest

type DeleteWithOrganizationsRequest struct {
	OrganizationIDs []uint `json:"organization_ids" binding:"required"`
}

DeleteWithOrganizationsRequest represents a request to delete user with their organizations

type ErrValidation

type ErrValidation struct {
	Field   string
	Message string
}

ErrValidation represents a validation error

func (ErrValidation) Error

func (e ErrValidation) Error() string

type ExcludedDomain

type ExcludedDomain struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;type:varchar(100);" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	UserID uint   `json:"user_id" gorm:"not null;index"`
	Domain string `json:"domain" gorm:"type:varchar(255);not null"`
}

ExcludedDomain represents a domain where Passwall is disabled for a specific user

func (ExcludedDomain) TableName

func (ExcludedDomain) TableName() string

type ExcludedDomainDTO

type ExcludedDomainDTO struct {
	ID        uint      `json:"id"`
	UUID      uuid.UUID `json:"uuid"`
	Domain    string    `json:"domain"`
	CreatedAt time.Time `json:"created_at"`
}

ExcludedDomainDTO for API responses

func ToExcludedDomainDTO

func ToExcludedDomainDTO(ed *ExcludedDomain) *ExcludedDomainDTO

func ToExcludedDomainDTOs

func ToExcludedDomainDTOs(eds []*ExcludedDomain) []*ExcludedDomainDTO

type FieldType

type FieldType int

FieldType - Custom field types

const (
	FieldTypeText    FieldType = 0 // Plain text
	FieldTypeHidden  FieldType = 1 // Password/secret (encrypted)
	FieldTypeBoolean FieldType = 2 // Checkbox
	FieldTypeLinked  FieldType = 3 // Linked to another field
)

type GrantCollectionAccessRequest

type GrantCollectionAccessRequest struct {
	CanRead       bool `json:"can_read"`
	CanWrite      bool `json:"can_write"`
	CanAdmin      bool `json:"can_admin"`
	HidePasswords bool `json:"hide_passwords"`
}

GrantCollectionAccessRequest for granting access to users/teams

type Invitation

type Invitation struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	// NOTE: Email is NOT unique because a user can have multiple invitations
	// (e.g. multiple organization invites). Code remains unique.
	Email     string     `json:"email" gorm:"type:varchar(255);index;not null"`
	Code      string     `json:"code" gorm:"type:varchar(64);uniqueIndex;not null"`
	RoleID    uint       `json:"role_id" gorm:"not null"`
	CreatedBy uint       `json:"created_by" gorm:"not null"` // Admin user ID
	ExpiresAt time.Time  `json:"expires_at" gorm:"not null"`
	UsedAt    *time.Time `json:"used_at,omitempty"`

	// Organization invitation fields (optional)
	OrganizationID  *uint   `json:"organization_id,omitempty" gorm:"index"`
	OrgRole         *string `json:"org_role,omitempty" gorm:"type:varchar(50)"`
	EncryptedOrgKey *string `json:"encrypted_org_key,omitempty" gorm:"type:text"`
	AccessAll       bool    `json:"access_all" gorm:"default:false"`
}

Invitation represents a user invitation

func (*Invitation) IsExpired

func (i *Invitation) IsExpired() bool

IsExpired checks if invitation is expired

func (*Invitation) IsUsed

func (i *Invitation) IsUsed() bool

IsUsed checks if invitation is already used

func (Invitation) TableName

func (Invitation) TableName() string

TableName specifies the table name for Invitation

type InviteUserToOrgRequest

type InviteUserToOrgRequest struct {
	Email           string           `json:"email" binding:"required,email"`
	Role            OrganizationRole `json:"role" binding:"required,oneof=owner admin manager member"`
	EncryptedOrgKey string           `json:"encrypted_org_key" binding:"required"` // Org key wrapped for invitee
	AccessAll       bool             `json:"access_all"`
	Collections     []uint           `json:"collections,omitempty"` // Collection IDs to grant access
}

InviteUserToOrgRequest for inviting users

type InvoiceDTO

type InvoiceDTO struct {
	ID               uint          `json:"id,omitempty"`              // Not used (no DB)
	UUID             string        `json:"uuid,omitempty"`            // Not used (no DB)
	SubscriptionID   uint          `json:"subscription_id,omitempty"` // Not used (no DB)
	Status           InvoiceStatus `json:"status"`
	AmountCents      int           `json:"amount_cents"`
	AmountDisplay    string        `json:"amount_display"`
	Currency         string        `json:"currency"`
	IssuedAt         time.Time     `json:"issued_at"`
	PaidAt           *time.Time    `json:"paid_at,omitempty"`
	DueDate          *time.Time    `json:"due_date,omitempty"`
	StripeInvoiceID  *string       `json:"stripe_invoice_id,omitempty"`
	InvoicePDFURL    *string       `json:"invoice_pdf_url,omitempty"`
	HostedInvoiceURL *string       `json:"hosted_invoice_url,omitempty"`
	CreatedAt        time.Time     `json:"created_at,omitempty"` // Not used (no DB)
}

InvoiceDTO represents invoice data fetched from Stripe (no DB table) Invoices are fetched directly from Stripe API, not stored in database

type InvoiceStatus

type InvoiceStatus string

InvoiceStatus represents the status of an invoice (from Stripe)

const (
	InvoiceStatusDraft         InvoiceStatus = "draft"
	InvoiceStatusOpen          InvoiceStatus = "open"
	InvoiceStatusPaid          InvoiceStatus = "paid"
	InvoiceStatusVoid          InvoiceStatus = "void"
	InvoiceStatusUncollectible InvoiceStatus = "uncollectible"
)

func (InvoiceStatus) String

func (i InvoiceStatus) String() string

String returns the string representation of InvoiceStatus

type Item

type Item struct {
	ID        uint       `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID  `gorm:"type:uuid;uniqueIndex" json:"uuid"`
	SupportID int64      `gorm:"uniqueIndex;not null" json:"support_id"` // Human-readable ID for support
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
	DeletedAt *time.Time `json:"deleted_at,omitempty" gorm:"index"`

	// Sync
	Revision    int64 `json:"revision" gorm:"not null;default:0"`
	SyncVersion int   `json:"sync_version" gorm:"not null;default:1"`

	ItemType ItemType `json:"item_type" gorm:"not null"`
	Data     string   `json:"data" gorm:"type:text;not null"` // Encrypted JSON
	// Optional: encrypted item key (for per-item key envelope encryption)
	ItemKeyEnc *string      `json:"item_key_enc,omitempty" gorm:"type:text"`
	Metadata   ItemMetadata `json:"metadata" gorm:"type:jsonb;not null"`

	// User preferences
	IsFavorite bool  `json:"is_favorite" gorm:"default:false"`
	FolderID   *uint `json:"folder_id,omitempty"`
	Reprompt   bool  `json:"reprompt" gorm:"default:false"`

	// Browser extension features (Password items only)
	AutoFill  bool `json:"auto_fill" gorm:"default:true"`   // Enable auto-fill
	AutoLogin bool `json:"auto_login" gorm:"default:false"` // Enable auto-submit

	ArchivedAt *time.Time `json:"archived_at,omitempty"`
}

Item - Universal vault item entity

func (*Item) FormatSupportID

func (i *Item) FormatSupportID() string

FormatSupportID formats support ID for display Example: 1855215206460051939 → "1855 2152 0646 0051 939"

func (*Item) IsArchived

func (i *Item) IsArchived() bool

IsArchived checks if item is archived

func (*Item) IsDeleted

func (i *Item) IsDeleted() bool

IsDeleted checks if item is soft deleted

func (Item) TableName

func (Item) TableName() string

TableName specifies the table name for Item

type ItemMetadata

type ItemMetadata struct {
	Name     string   `json:"name"`                // Required: display name
	URIHint  string   `json:"uri_hint,omitempty"`  // For passwords: domain for autofill
	Brand    string   `json:"brand,omitempty"`     // For cards: Visa, Mastercard, etc.
	Category string   `json:"category,omitempty"`  // Custom category
	Tags     []string `json:"tags,omitempty"`      // User tags for organization
	IconHint string   `json:"icon_hint,omitempty"` // For UI (favicon URL hint)
}

ItemMetadata - Searchable metadata (NOT encrypted)

func (*ItemMetadata) Scan

func (m *ItemMetadata) Scan(value interface{}) error

Scan implements sql.Scanner for ItemMetadata (JSONB)

func (ItemMetadata) Value

func (m ItemMetadata) Value() (interface{}, error)

Value implements driver.Valuer for ItemMetadata (JSONB)

type ItemShare

type ItemShare struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	// Item reference (organization item)
	ItemUUID       uuid.UUID `json:"item_uuid" gorm:"type:uuid;not null;index"`
	OrganizationID uint      `json:"organization_id" gorm:"not null;index"`

	OwnerID uint `json:"owner_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Share target (either user or team)
	SharedWithUserID *uint `json:"shared_with_user_id,omitempty" gorm:"index;constraint:OnDelete:CASCADE"`
	SharedWithTeamID *uint `json:"shared_with_team_id,omitempty" gorm:"index;constraint:OnDelete:CASCADE"`

	// Permissions
	CanView  bool `json:"can_view" gorm:"default:true"`
	CanEdit  bool `json:"can_edit" gorm:"default:false"`
	CanShare bool `json:"can_share" gorm:"default:false"` // Can re-share to others

	// Encrypted item key wrapped for recipient
	EncryptedKey string `json:"-" gorm:"type:text;not null"`

	// Expiration
	ExpiresAt *time.Time `json:"expires_at,omitempty"`

	// Associations
	Owner          *User `json:"owner,omitempty" gorm:"foreignKey:OwnerID"`
	SharedWithUser *User `json:"shared_with_user,omitempty" gorm:"foreignKey:SharedWithUserID"`
	SharedWithTeam *Team `json:"shared_with_team,omitempty" gorm:"foreignKey:SharedWithTeamID"`
}

ItemShare represents a direct share of an organization item to another user/team

func (*ItemShare) IsExpired

func (is *ItemShare) IsExpired() bool

IsExpired checks if the share has expired

func (ItemShare) TableName

func (ItemShare) TableName() string

TableName specifies the table name

type ItemShareDTO

type ItemShareDTO struct {
	ID               uint       `json:"id"`
	UUID             uuid.UUID  `json:"uuid"`
	ItemUUID         uuid.UUID  `json:"item_uuid"`
	OwnerID          uint       `json:"owner_id"`
	OwnerEmail       string     `json:"owner_email,omitempty"`
	SharedWithUserID *uint      `json:"shared_with_user_id,omitempty"`
	SharedWithTeamID *uint      `json:"shared_with_team_id,omitempty"`
	SharedWithEmail  string     `json:"shared_with_email,omitempty"`
	SharedWithName   string     `json:"shared_with_name,omitempty"`
	CanView          bool       `json:"can_view"`
	CanEdit          bool       `json:"can_edit"`
	CanShare         bool       `json:"can_share"`
	ExpiresAt        *time.Time `json:"expires_at,omitempty"`
	CreatedAt        time.Time  `json:"created_at"`
}

ItemShareDTO for API responses

type ItemType

type ItemType int16

ItemType - Enum for vault item types

const (
	ItemTypePassword    ItemType = 1
	ItemTypeSecureNote  ItemType = 2
	ItemTypeCard        ItemType = 3
	ItemTypeBankAccount ItemType = 4
	ItemTypeEmail       ItemType = 5
	ItemTypeServer      ItemType = 6
	ItemTypeIdentity    ItemType = 7
	ItemTypeSSHKey      ItemType = 8
	ItemTypeAddress     ItemType = 9  // Address/Location
	ItemTypeCustom      ItemType = 99 // User-defined
)

func (ItemType) IsValid

func (it ItemType) IsValid() bool

IsValid checks if item type is valid

func (ItemType) String

func (it ItemType) String() string

String returns the string representation of ItemType

type KdfConfig

type KdfConfig struct {
	Type        KdfType `json:"kdf_type"`
	Iterations  int     `json:"kdf_iterations"`
	Memory      *int    `json:"kdf_memory,omitempty"`      // For Argon2id (MB)
	Parallelism *int    `json:"kdf_parallelism,omitempty"` // For Argon2id (threads)
	Salt        string  `json:"kdf_salt,omitempty"`        // hex-encoded random salt
}

KdfConfig represents KDF (Key Derivation Function) configuration

func NewArgon2KdfConfig

func NewArgon2KdfConfig() *KdfConfig

NewArgon2KdfConfig returns default Argon2id configuration

func NewDefaultKdfConfig

func NewDefaultKdfConfig() *KdfConfig

NewDefaultKdfConfig returns default PBKDF2 configuration

func (*KdfConfig) Validate

func (c *KdfConfig) Validate() error

Validate validates the KDF configuration

func (*KdfConfig) ValidateForPrelogin

func (c *KdfConfig) ValidateForPrelogin() error

ValidateForPrelogin validates KDF config against downgrade attacks Server should never allow iterations below minimum

type KdfType

type KdfType int

KdfType represents the key derivation function type

const (
	KdfTypePBKDF2   KdfType = 0
	KdfTypeArgon2id KdfType = 1
)

func (KdfType) String

func (k KdfType) String() string

String returns the string representation of KdfType

type MoveItemToCollectionRequest

type MoveItemToCollectionRequest struct {
	CollectionID *uint `json:"collection_id"` // NULL to move to org-wide
}

MoveItemToCollectionRequest for moving items between collections

type OIDCConfig

type OIDCConfig struct {
	Issuer       string   `json:"issuer"`
	ClientID     string   `json:"client_id"`
	ClientSecret string   `json:"client_secret"`
	AuthURL      string   `json:"auth_url,omitempty"`
	TokenURL     string   `json:"token_url,omitempty"`
	UserInfoURL  string   `json:"user_info_url,omitempty"`
	JwksURI      string   `json:"jwks_uri,omitempty"`
	Scopes       []string `json:"scopes,omitempty"`
	UseDiscovery bool     `json:"use_discovery"`
	PKCEEnabled  bool     `json:"pkce_enabled"`
	EmailClaim   string   `json:"email_claim,omitempty"`
	NameClaim    string   `json:"name_claim,omitempty"`
	GroupsClaim  string   `json:"groups_claim,omitempty"`
}

OIDCConfig holds OIDC-specific IdP configuration

func (*OIDCConfig) Scan

func (c *OIDCConfig) Scan(value interface{}) error

Scan implements sql.Scanner

func (OIDCConfig) Value

func (c OIDCConfig) Value() (driver.Value, error)

Value implements driver.Valuer

type OIDCConfigDTO

type OIDCConfigDTO struct {
	Issuer       string   `json:"issuer"`
	ClientID     string   `json:"client_id"`
	AuthURL      string   `json:"auth_url,omitempty"`
	TokenURL     string   `json:"token_url,omitempty"`
	Scopes       []string `json:"scopes,omitempty"`
	UseDiscovery bool     `json:"use_discovery"`
	PKCEEnabled  bool     `json:"pkce_enabled"`
}

OIDCConfigDTO strips the client secret

type Organization

type Organization struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	// Organization info
	Name         string `json:"name" gorm:"type:varchar(255);not null"`
	BillingEmail string `json:"billing_email" gorm:"type:varchar(255);not null"`

	// System defaults
	// IsDefault is a legacy concept kept for backward compatibility.
	// Do not use it for default-org resolution; use users.default_organization_id instead.
	IsDefault bool `json:"is_default" gorm:"not null;default:false"`

	// Personal Vault model (new)
	IsPersonal          bool  `json:"is_personal" gorm:"not null;default:false"`
	PersonalOwnerUserID *uint `json:"personal_owner_user_id,omitempty" gorm:"index"`

	// Creator snapshot (denormalized).
	// Users can be hard-deleted, so we keep immutable creator identity fields here.
	CreatedByUserID    *uint   `json:"created_by_user_id,omitempty" gorm:"index"`
	CreatedByUserEmail *string `json:"created_by_user_email,omitempty" gorm:"type:varchar(255)"`
	CreatedByUserName  *string `json:"created_by_user_name,omitempty" gorm:"type:varchar(255)"`

	// Encryption
	// Organization symmetric key (AES-256) encrypted with owner's User Key
	EncryptedOrgKey string `json:"-" gorm:"type:text;not null"`

	// RSA key pair for organization (optional, for advanced key management)
	OrgPublicKey       *string `json:"-" gorm:"type:text"` // RSA-2048 public key (PEM)
	OrgPrivateKeyEnc   *string `json:"-" gorm:"type:text"` // RSA private key encrypted with recovery key
	KeyRotationCounter int     `json:"key_rotation_counter" gorm:"default:0"`

	// Status
	Status              OrganizationStatus `json:"status" gorm:"type:varchar(20);not null;default:'active'"`
	IsActive            bool               `json:"is_active" gorm:"default:true"`
	SuspendedAt         *time.Time         `json:"suspended_at,omitempty"`
	DeletedAt           *time.Time         `json:"deleted_at,omitempty" gorm:"index"`
	ScheduledDeletionAt *time.Time         `json:"scheduled_deletion_at,omitempty"`

	// Billing & Stripe Integration
	StripeCustomerID *string `json:"stripe_customer_id,omitempty" gorm:"type:varchar(255);index"`

	// Stats (runtime calculated, not stored in DB)
	MemberCount     *int `json:"member_count,omitempty" gorm:"-"`
	TeamCount       *int `json:"team_count,omitempty" gorm:"-"`
	CollectionCount *int `json:"collection_count,omitempty" gorm:"-"`
	ItemCount       *int `json:"item_count,omitempty" gorm:"-"`

	// Associations (not loaded by default)
	Members     []OrganizationUser `json:"members,omitempty" gorm:"foreignKey:OrganizationID"`
	Teams       []Team             `json:"teams,omitempty" gorm:"foreignKey:OrganizationID"`
	Collections []Collection       `json:"collections,omitempty" gorm:"foreignKey:OrganizationID"`
}

Organization represents a team/company organization

func (Organization) TableName

func (Organization) TableName() string

TableName specifies the table name

type OrganizationDTO

type OrganizationDTO struct {
	ID                 uint               `json:"id"`
	UUID               uuid.UUID          `json:"uuid"`
	Name               string             `json:"name"`
	BillingEmail       string             `json:"billing_email"`
	IsDefault          bool               `json:"is_default"`
	CreatedByUserID    *uint              `json:"created_by_user_id,omitempty"`
	CreatedByUserEmail *string            `json:"created_by_user_email,omitempty"`
	CreatedByUserName  *string            `json:"created_by_user_name,omitempty"`
	Plan               OrganizationPlan   `json:"plan"`
	MaxUsers           int                `json:"max_users"`
	MaxCollections     int                `json:"max_collections"`
	Status             OrganizationStatus `json:"status"`
	IsActive           bool               `json:"is_active"`
	CreatedAt          time.Time          `json:"created_at"`
	UpdatedAt          time.Time          `json:"updated_at"`

	// Subscription (optional)
	Subscription *SubscriptionDTO `json:"subscription,omitempty"`

	// Stats (optional)
	MemberCount     *int `json:"member_count,omitempty"`
	TeamCount       *int `json:"team_count,omitempty"`
	CollectionCount *int `json:"collection_count,omitempty"`
	ItemCount       *int `json:"item_count,omitempty"`

	// Encrypted org key (safe to send - user's own copy, encrypted with their User Key)
	EncryptedOrgKey string `json:"encrypted_org_key,omitempty"`
}

OrganizationDTO for API responses

func ToOrganizationDTO

func ToOrganizationDTO(org *Organization) *OrganizationDTO

ToOrganizationDTO converts Organization to DTO

func ToOrganizationDTOWithSubscription

func ToOrganizationDTOWithSubscription(org *Organization, sub *Subscription) *OrganizationDTO

ToOrganizationDTOWithSubscription converts Organization to DTO and derives plan/limits from the provided subscription (source of truth).

type OrganizationFolder

type OrganizationFolder struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;type:varchar(100);" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	OrganizationID  uint   `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	CreatedByUserID uint   `json:"created_by_user_id" gorm:"not null;index"`
	Name            string `json:"name" gorm:"type:varchar(255);not null"`
}

OrganizationFolder represents a folder for organization vault items

func (OrganizationFolder) TableName

func (OrganizationFolder) TableName() string

type OrganizationFolderDTO

type OrganizationFolderDTO struct {
	ID        uint      `json:"id"`
	UUID      uuid.UUID `json:"uuid"`
	Name      string    `json:"name"`
	CreatedAt time.Time `json:"created_at"`
}

func ToOrganizationFolderDTO

func ToOrganizationFolderDTO(f *OrganizationFolder) *OrganizationFolderDTO

func ToOrganizationFolderDTOs

func ToOrganizationFolderDTOs(folders []*OrganizationFolder) []*OrganizationFolderDTO

type OrganizationItem

type OrganizationItem struct {
	ID        uint       `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID  `gorm:"type:uuid;not null" json:"uuid"`
	SupportID int64      `gorm:"not null" json:"support_id"` // Human-readable ID for support
	CreatedAt time.Time  `json:"created_at"`
	UpdatedAt time.Time  `json:"updated_at"`
	DeletedAt *time.Time `json:"deleted_at,omitempty" gorm:"index"`

	// Organization and collection
	OrganizationID uint  `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	CollectionID   *uint `json:"collection_id,omitempty" gorm:"index;constraint:OnDelete:SET NULL"` // NULL means org-wide item

	// Sync
	Revision    int64 `json:"revision" gorm:"not null;default:0"`
	SyncVersion int   `json:"sync_version" gorm:"not null;default:1"`

	// Item type and data
	ItemType ItemType     `json:"item_type" gorm:"not null"`
	Data     string       `json:"data" gorm:"type:text;not null"` // Encrypted with Org Key
	Metadata ItemMetadata `json:"metadata" gorm:"type:jsonb;not null"`

	// User preferences
	IsFavorite bool  `json:"is_favorite" gorm:"default:false"`
	FolderID   *uint `json:"folder_id,omitempty"` // Organization folder (future feature)
	Reprompt   bool  `json:"reprompt" gorm:"default:false"`

	// Browser extension features (Password items only)
	AutoFill  bool `json:"auto_fill" gorm:"default:true"`
	AutoLogin bool `json:"auto_login" gorm:"default:false"`

	ArchivedAt *time.Time `json:"archived_at,omitempty"`

	// Creator info
	CreatedByUserID uint `json:"created_by_user_id" gorm:"not null;index"`

	// Associations
	Organization *Organization `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
	Collection   *Collection   `json:"collection,omitempty" gorm:"foreignKey:CollectionID"`
	CreatedBy    *User         `json:"created_by,omitempty" gorm:"foreignKey:CreatedByUserID"`
}

OrganizationItem represents a vault item shared within an organization Unlike personal items (in user schemas), org items are in the public schema and encrypted with the organization key instead of user key

func (*OrganizationItem) FormatSupportID

func (oi *OrganizationItem) FormatSupportID() string

FormatSupportID formats support ID for display

func (*OrganizationItem) IsArchived

func (oi *OrganizationItem) IsArchived() bool

IsArchived checks if item is archived

func (*OrganizationItem) IsDeleted

func (oi *OrganizationItem) IsDeleted() bool

IsDeleted checks if item is soft deleted

func (OrganizationItem) TableName

func (OrganizationItem) TableName() string

TableName specifies the table name

type OrganizationItemDTO

type OrganizationItemDTO struct {
	ID                 uint         `json:"id"`
	UUID               uuid.UUID    `json:"uuid"`
	SupportID          int64        `json:"support_id"`
	SupportIDFormatted string       `json:"support_id_formatted"`
	OrganizationID     uint         `json:"organization_id"`
	CollectionID       *uint        `json:"collection_id,omitempty"`
	ItemType           ItemType     `json:"item_type"`
	Data               string       `json:"data"` // Still encrypted
	Metadata           ItemMetadata `json:"metadata"`
	IsFavorite         bool         `json:"is_favorite"`
	FolderID           *uint        `json:"folder_id,omitempty"`
	Reprompt           bool         `json:"reprompt"`
	AutoFill           bool         `json:"auto_fill"`
	AutoLogin          bool         `json:"auto_login"`
	Revision           int64        `json:"revision"`
	SyncVersion        int          `json:"sync_version"`
	CreatedByUserID    uint         `json:"created_by_user_id"`
	CreatedByUserEmail string       `json:"created_by_user_email,omitempty"`
	CreatedAt          time.Time    `json:"created_at"`
	UpdatedAt          time.Time    `json:"updated_at"`
	ArchivedAt         *time.Time   `json:"archived_at,omitempty"`
}

OrganizationItemDTO for API responses

func ToOrganizationItemDTO

func ToOrganizationItemDTO(oi *OrganizationItem) *OrganizationItemDTO

ToOrganizationItemDTO converts OrganizationItem to DTO

type OrganizationPlan

type OrganizationPlan string

OrganizationPlan represents the subscription plan "family" at the product level.

NOTE: This is a presentation/UX concept. Source-of-truth entitlements MUST come from subscriptions + plans.

const (
	PlanFree       OrganizationPlan = "free"
	PlanPremium    OrganizationPlan = "premium" // Premium plan does NOT use organizations
	PlanFamily     OrganizationPlan = "family"
	PlanTeam       OrganizationPlan = "team"
	PlanBusiness   OrganizationPlan = "business"
	PlanEnterprise OrganizationPlan = "enterprise"
)

type OrganizationRole

type OrganizationRole string

OrganizationRole represents a user's role in an organization

const (
	OrgRoleOwner   OrganizationRole = "owner"   // Full control, billing, delete org
	OrgRoleAdmin   OrganizationRole = "admin"   // Manage users, collections, all items
	OrgRoleManager OrganizationRole = "manager" // Manage specific teams/collections
	OrgRoleMember  OrganizationRole = "member"  // Access assigned collections only
	OrgRoleBilling OrganizationRole = "billing" // Billing management only
)

type OrganizationStatus

type OrganizationStatus string

OrganizationStatus represents the status of an organization

const (
	OrgStatusActive               OrganizationStatus = "active"
	OrgStatusSuspended            OrganizationStatus = "suspended"
	OrgStatusScheduledForDeletion OrganizationStatus = "scheduled_for_deletion"
	OrgStatusDeleted              OrganizationStatus = "deleted"
)

type OrganizationUser

type OrganizationUser struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	OrganizationID uint `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	UserID         uint `json:"user_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Role in organization
	Role OrganizationRole `json:"role" gorm:"type:varchar(20);not null;default:'member'"`

	// Organization key wrapped for this user
	// Encrypted with user's RSA public key (or User Key if RSA not available)
	EncryptedOrgKey string `json:"-" gorm:"type:text;not null"`

	// Permissions
	AccessAll   bool   `json:"access_all" gorm:"default:false"` // Access all collections
	Permissions string `json:"permissions,omitempty" gorm:"type:text"`

	// Status
	Status     OrganizationUserStatus `json:"status" gorm:"type:varchar(20);default:'invited'"`
	InvitedAt  *time.Time             `json:"invited_at,omitempty"`
	AcceptedAt *time.Time             `json:"accepted_at,omitempty"`

	// External ID for LDAP/AD sync
	ExternalID *string `json:"external_id,omitempty" gorm:"type:varchar(255);index"`

	// Associations
	Organization *Organization `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
	User         *User         `json:"user,omitempty" gorm:"foreignKey:UserID"`
}

OrganizationUser represents a user's membership in an organization

func (*OrganizationUser) CanManageCollections

func (ou *OrganizationUser) CanManageCollections() bool

CanManageCollections checks if the user can manage collections

func (*OrganizationUser) CanManageUsers

func (ou *OrganizationUser) CanManageUsers() bool

CanManageUsers checks if the user can manage other users

func (*OrganizationUser) IsAdmin

func (ou *OrganizationUser) IsAdmin() bool

IsAdmin checks if the user is an admin or owner

func (*OrganizationUser) IsOwner

func (ou *OrganizationUser) IsOwner() bool

IsOwner checks if the user is an owner

func (OrganizationUser) TableName

func (OrganizationUser) TableName() string

TableName specifies the table name

type OrganizationUserDTO

type OrganizationUserDTO struct {
	ID             uint                   `json:"id"`
	UUID           uuid.UUID              `json:"uuid"`
	OrganizationID uint                   `json:"organization_id"`
	UserID         uint                   `json:"user_id"`
	UserEmail      string                 `json:"user_email"`
	UserName       string                 `json:"user_name"`
	Role           OrganizationRole       `json:"role"`
	AccessAll      bool                   `json:"access_all"`
	Status         OrganizationUserStatus `json:"status"`
	InvitedAt      *time.Time             `json:"invited_at,omitempty"`
	AcceptedAt     *time.Time             `json:"accepted_at,omitempty"`
	CreatedAt      time.Time              `json:"created_at"`
}

OrganizationUserDTO for API responses

func ToOrganizationUserDTO

func ToOrganizationUserDTO(ou *OrganizationUser) *OrganizationUserDTO

ToOrganizationUserDTO converts OrganizationUser to DTO

type OrganizationUserStatus

type OrganizationUserStatus string

OrganizationUserStatus represents the status of a user's membership

const (
	OrgUserStatusInvited   OrganizationUserStatus = "invited"
	OrgUserStatusAccepted  OrganizationUserStatus = "accepted"
	OrgUserStatusConfirmed OrganizationUserStatus = "confirmed"
	OrgUserStatusSuspended OrganizationUserStatus = "suspended"
)

type OwnershipCheckResult

type OwnershipCheckResult struct {
	IsSoleOwner   bool                    `json:"is_sole_owner"`
	Organizations []SoleOwnerOrganization `json:"organizations"`
}

OwnershipCheckResult represents organizations where user is sole owner

type PaymentProvider

type PaymentProvider string

PaymentProvider represents the payment provider for a subscription

const (
	PaymentProviderStripe     PaymentProvider = "stripe"
	PaymentProviderRevenueCat PaymentProvider = "revenuecat"
	PaymentProviderManual     PaymentProvider = "manual"
	PaymentProviderNone       PaymentProvider = "none"
)

func DetectPaymentProvider

func DetectPaymentProvider(subscriptionID *string) PaymentProvider

DetectPaymentProvider determines the payment provider from a subscription ID. RevenueCat subscriptions use the format "rc_{store}_{transaction_id}". Empty or nil subscription IDs indicate a manual/admin grant.

func (PaymentProvider) IsManagedExternally

func (p PaymentProvider) IsManagedExternally() bool

IsManagedExternally returns true if the subscription is managed by an external store (App Store / Play Store via RevenueCat). These subscriptions can only be canceled/modified from the respective store — not from our API.

func (PaymentProvider) IsRevenueCat

func (p PaymentProvider) IsRevenueCat() bool

IsRevenueCat returns true if the provider is RevenueCat (mobile in-app purchase)

func (PaymentProvider) IsStripe

func (p PaymentProvider) IsStripe() bool

IsStripe returns true if the provider is Stripe (web payment)

func (PaymentProvider) String

func (p PaymentProvider) String() string

type Permission

type Permission struct {
	ID          uint      `gorm:"primary_key" json:"id"`
	Name        string    `json:"name" gorm:"type:varchar(100);uniqueIndex;not null"`
	DisplayName string    `json:"display_name" gorm:"type:varchar(100);not null"`
	Description string    `json:"description" gorm:"type:text"`
	Resource    string    `json:"resource" gorm:"type:varchar(50);not null"` // e.g., "users", "logins"
	Action      string    `json:"action" gorm:"type:varchar(50);not null"`   // e.g., "read", "create", "update", "delete"
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

Permission represents a specific action/access right

func (Permission) TableName

func (Permission) TableName() string

TableName specifies the table name for Permission

type Plan

type Plan struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	Code         string       `json:"code" gorm:"type:varchar(50);uniqueIndex;not null"`
	Name         string       `json:"name" gorm:"type:varchar(100);not null"`
	BillingCycle BillingCycle `json:"billing_cycle" gorm:"type:varchar(20);not null"`
	PriceCents   int          `json:"price_cents" gorm:"not null"`
	Currency     string       `json:"currency" gorm:"type:varchar(3);not null;default:'USD'"`
	TrialDays    int          `json:"trial_days" gorm:"not null;default:0"`

	// Limits (null = unlimited)
	MaxUsers       *int `json:"max_users,omitempty"`
	MaxCollections *int `json:"max_collections,omitempty"`
	MaxItems       *int `json:"max_items,omitempty"`

	// Feature flags
	Features PlanFeatures `json:"features" gorm:"type:jsonb;not null"`

	// Status
	IsActive bool `json:"is_active" gorm:"default:true"`

	// Stripe integration
	StripeProductID *string `json:"stripe_product_id,omitempty" gorm:"type:varchar(255)"`
	StripePriceID   *string `json:"stripe_price_id,omitempty" gorm:"type:varchar(255)"`
}

Plan represents a subscription plan

func (*Plan) GetPriceDisplay

func (p *Plan) GetPriceDisplay() string

GetPriceDisplay returns formatted price for display (e.g., "$5.99")

func (*Plan) HasTrial

func (p *Plan) HasTrial() bool

HasTrial checks if plan has trial period

func (*Plan) IsFree

func (p *Plan) IsFree() bool

IsFree checks if plan is free

func (*Plan) IsUnlimitedCollections

func (p *Plan) IsUnlimitedCollections() bool

IsUnlimitedCollections checks if plan allows unlimited collections

func (*Plan) IsUnlimitedItems

func (p *Plan) IsUnlimitedItems() bool

IsUnlimitedItems checks if plan allows unlimited items

func (*Plan) IsUnlimitedUsers

func (p *Plan) IsUnlimitedUsers() bool

IsUnlimitedUsers checks if plan allows unlimited users

func (Plan) TableName

func (Plan) TableName() string

TableName specifies the table name

type PlanChangePreview

type PlanChangePreview struct {
	CurrentPlan       string `json:"current_plan"`
	NewPlan           string `json:"new_plan"`
	ProratedAmount    int64  `json:"prorated_amount"` // cents
	Currency          string `json:"currency"`
	NextBillingDate   string `json:"next_billing_date"`
	NextBillingAmount int64  `json:"next_billing_amount"`
	ImmediateCharge   bool   `json:"immediate_charge"` // true if user will be charged now
}

PlanChangePreview shows the cost impact of switching to a different plan.

type PlanChangeResult

type PlanChangeResult struct {
	Success bool   `json:"success"`
	Message string `json:"message"`
}

PlanChangeResult represents the result of an inline plan change.

type PlanDTO

type PlanDTO struct {
	ID             uint         `json:"id"`
	UUID           uuid.UUID    `json:"uuid"`
	Code           string       `json:"code"`
	Name           string       `json:"name"`
	BillingCycle   BillingCycle `json:"billing_cycle"`
	PriceCents     int          `json:"price_cents"`
	PriceDisplay   string       `json:"price_display"`
	Currency       string       `json:"currency"`
	TrialDays      int          `json:"trial_days"`
	MaxUsers       *int         `json:"max_users,omitempty"`
	MaxCollections *int         `json:"max_collections,omitempty"`
	MaxItems       *int         `json:"max_items,omitempty"`
	Features       PlanFeatures `json:"features"`
	IsActive       bool         `json:"is_active"`
	CreatedAt      time.Time    `json:"created_at"`
	UpdatedAt      time.Time    `json:"updated_at"`
}

PlanDTO for API responses

func ToPlanDTO

func ToPlanDTO(p *Plan) *PlanDTO

ToPlanDTO converts Plan to DTO

type PlanFeatures

type PlanFeatures struct {
	Items           *int `json:"items"`            // Max items (null = unlimited)
	Sharing         bool `json:"sharing"`          // Item sharing enabled
	Teams           bool `json:"teams"`            // Team management enabled
	Audit           bool `json:"audit"`            // Audit logs enabled
	SSO             bool `json:"sso"`              // Single Sign-On enabled
	APIAccess       bool `json:"api_access"`       // API access enabled
	PrioritySupport bool `json:"priority_support"` // Priority support enabled
}

PlanFeatures represents feature flags for a plan

func (*PlanFeatures) Scan

func (f *PlanFeatures) Scan(value interface{}) error

Scan implements sql.Scanner for PlanFeatures (JSONB)

func (PlanFeatures) Value

func (f PlanFeatures) Value() (driver.Value, error)

Value implements driver.Valuer for PlanFeatures (JSONB)

type PreLoginRequest

type PreLoginRequest struct {
	Email string `json:"email" validate:"required,email"`
}

PreLoginRequest represents prelogin request

type PreLoginResponse

type PreLoginResponse struct {
	KdfType        KdfType `json:"kdf_type"`
	KdfIterations  int     `json:"kdf_iterations"`
	KdfMemory      *int    `json:"kdf_memory,omitempty"`
	KdfParallelism *int    `json:"kdf_parallelism,omitempty"`
	KdfSalt        string  `json:"kdf_salt"` // hex-encoded salt for master key derivation
}

PreLoginResponse represents prelogin response (KDF config for client)

type Preference

type Preference struct {
	ID uint `json:"id" gorm:"primaryKey"`

	OwnerType string `` /* 153-byte string literal not displayed */
	OwnerID   uint   `` /* 134-byte string literal not displayed */

	Section string `` /* 150-byte string literal not displayed */
	Key     string `json:"key" gorm:"type:varchar(64);not null;uniqueIndex:uq_preferences_owner_section_key,priority:4"`

	// Value is stored as text; interpretation depends on Type.
	// Type can be: string | number | boolean | json
	Value string `json:"value" gorm:"type:text;not null;default:''"`
	Type  string `json:"type" gorm:"type:varchar(16);not null;default:'string'"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

Preference stores a single preference value for a scoped owner (user/org). One row represents one setting: (owner_type, owner_id, section, key) → (type, value).

func (Preference) TableName

func (Preference) TableName() string

type PreferenceDTO

type PreferenceDTO struct {
	Section string `json:"section"`
	Key     string `json:"key"`
	Type    string `json:"type"`
	Value   string `json:"value"`
}

func ToPreferenceDTO

func ToPreferenceDTO(p *Preference) *PreferenceDTO

type ResendVerificationRequest

type ResendVerificationRequest struct {
	Email string `json:"email" binding:"required,email"`
}

ResendVerificationRequest represents resend verification email request

type Role

type Role struct {
	ID          uint         `gorm:"primary_key" json:"id"`
	Name        string       `json:"name" gorm:"type:varchar(50);uniqueIndex;not null"`
	DisplayName string       `json:"display_name" gorm:"type:varchar(100);not null"`
	Description string       `json:"description" gorm:"type:text"`
	CreatedAt   time.Time    `json:"created_at"`
	UpdatedAt   time.Time    `json:"updated_at"`
	Permissions []Permission `gorm:"many2many:role_permissions;" json:"permissions,omitempty"`
}

Role represents a user role in the system

func (Role) TableName

func (Role) TableName() string

TableName specifies the table name for Role

type SAMLConfig

type SAMLConfig struct {
	EntityID            string `json:"entity_id"`
	SSOURL              string `json:"sso_url"`
	SLOURL              string `json:"slo_url,omitempty"`
	Certificate         string `json:"certificate"`
	SignAuthnRequests   bool   `json:"sign_authn_requests"`
	WantAssertionSigned bool   `json:"want_assertion_signed"`
	NameIDFormat        string `json:"name_id_format,omitempty"`
}

SAMLConfig holds SAML-specific IdP configuration

func (*SAMLConfig) Scan

func (c *SAMLConfig) Scan(value interface{}) error

Scan implements sql.Scanner

func (SAMLConfig) Value

func (c SAMLConfig) Value() (driver.Value, error)

Value implements driver.Valuer

type SAMLConfigDTO

type SAMLConfigDTO struct {
	EntityID            string `json:"entity_id"`
	SSOURL              string `json:"sso_url"`
	SLOURL              string `json:"slo_url,omitempty"`
	HasCertificate      bool   `json:"has_certificate"`
	SignAuthnRequests   bool   `json:"sign_authn_requests"`
	WantAssertionSigned bool   `json:"want_assertion_signed"`
	NameIDFormat        string `json:"name_id_format,omitempty"`
}

SAMLConfigDTO strips the certificate body for list views

type SCIMEmail

type SCIMEmail struct {
	Value   string `json:"value"`
	Type    string `json:"type,omitempty"`
	Primary bool   `json:"primary,omitempty"`
}

SCIMEmail represents an email in the SCIM schema

type SCIMError

type SCIMError struct {
	Schemas  []string `json:"schemas"`
	Detail   string   `json:"detail"`
	Status   string   `json:"status"`
	ScimType string   `json:"scimType,omitempty"`
}

SCIMError represents a SCIM 2.0 error response

type SCIMGroup

type SCIMGroup struct {
	Schemas     []string        `json:"schemas"`
	ID          string          `json:"id"`
	ExternalID  string          `json:"externalId,omitempty"`
	DisplayName string          `json:"displayName"`
	Members     []SCIMMemberRef `json:"members,omitempty"`
	Meta        *SCIMMeta       `json:"meta,omitempty"`
}

SCIMGroup represents a SCIM 2.0 Group resource

type SCIMGroupRef

type SCIMGroupRef struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Ref     string `json:"$ref,omitempty"`
}

SCIMGroupRef is a reference to a group the user belongs to

type SCIMListResponse

type SCIMListResponse struct {
	Schemas      []string    `json:"schemas"`
	TotalResults int         `json:"totalResults"`
	StartIndex   int         `json:"startIndex"`
	ItemsPerPage int         `json:"itemsPerPage"`
	Resources    interface{} `json:"Resources"`
}

SCIMListResponse wraps a SCIM list with pagination envelope

type SCIMMemberRef

type SCIMMemberRef struct {
	Value   string `json:"value"`
	Display string `json:"display,omitempty"`
	Ref     string `json:"$ref,omitempty"`
}

SCIMMemberRef is a reference to a group member

type SCIMMeta

type SCIMMeta struct {
	ResourceType string `json:"resourceType"`
	Created      string `json:"created,omitempty"`
	LastModified string `json:"lastModified,omitempty"`
	Location     string `json:"location,omitempty"`
}

SCIMMeta holds resource metadata per SCIM spec

type SCIMName

type SCIMName struct {
	Formatted  string `json:"formatted,omitempty"`
	FamilyName string `json:"familyName,omitempty"`
	GivenName  string `json:"givenName,omitempty"`
}

SCIMName represents the name component of a SCIM user

type SCIMPatchOp

type SCIMPatchOp struct {
	Schemas    []string          `json:"schemas"`
	Operations []SCIMPatchOpItem `json:"Operations"`
}

SCIMPatchOp represents a SCIM PATCH operation (RFC 7644 §3.5.2)

type SCIMPatchOpItem

type SCIMPatchOpItem struct {
	Op    string      `json:"op"`
	Path  string      `json:"path,omitempty"`
	Value interface{} `json:"value,omitempty"`
}

SCIMPatchOpItem is a single patch operation

type SCIMToken

type SCIMToken struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null;uniqueIndex" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	OrganizationID uint   `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	Label          string `json:"label" gorm:"type:varchar(255);not null"`

	// Token value (hashed for storage, plain text returned only on creation)
	TokenHash string     `json:"-" gorm:"type:varchar(512);not null;uniqueIndex"`
	ExpiresAt *time.Time `json:"expires_at,omitempty"`

	LastUsedAt *time.Time `json:"last_used_at,omitempty"`
	IsActive   bool       `json:"is_active" gorm:"not null;default:true"`

	// Associations
	Organization *Organization `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
}

SCIMToken represents an API bearer token used by IdP directory sync (SCIM 2.0)

func (*SCIMToken) IsExpired

func (t *SCIMToken) IsExpired() bool

IsExpired checks if the token has expired

func (*SCIMToken) IsValid

func (t *SCIMToken) IsValid() bool

IsValid returns true if the token is active and not expired

func (SCIMToken) TableName

func (SCIMToken) TableName() string

TableName specifies the table name

type SCIMTokenCreatedDTO

type SCIMTokenCreatedDTO struct {
	SCIMTokenDTO
	Token string `json:"token"`
}

SCIMTokenCreatedDTO includes the plain-text token (returned only on creation)

type SCIMTokenDTO

type SCIMTokenDTO struct {
	ID             uint       `json:"id"`
	UUID           uuid.UUID  `json:"uuid"`
	OrganizationID uint       `json:"organization_id"`
	Label          string     `json:"label"`
	ExpiresAt      *time.Time `json:"expires_at,omitempty"`
	LastUsedAt     *time.Time `json:"last_used_at,omitempty"`
	IsActive       bool       `json:"is_active"`
	CreatedAt      time.Time  `json:"created_at"`
}

SCIMTokenDTO for API responses

func ToSCIMTokenDTO

func ToSCIMTokenDTO(t *SCIMToken) *SCIMTokenDTO

ToSCIMTokenDTO converts SCIMToken to DTO

type SCIMUser

type SCIMUser struct {
	Schemas    []string       `json:"schemas"`
	ID         string         `json:"id"`
	ExternalID string         `json:"externalId,omitempty"`
	UserName   string         `json:"userName"`
	Name       *SCIMName      `json:"name,omitempty"`
	Emails     []SCIMEmail    `json:"emails,omitempty"`
	Active     bool           `json:"active"`
	Groups     []SCIMGroupRef `json:"groups,omitempty"`
	Meta       *SCIMMeta      `json:"meta,omitempty"`
}

SCIMUser represents a SCIM 2.0 User resource

type SSOCallbackResult

type SSOCallbackResult struct {
	User         *User         `json:"user"`
	Organization *Organization `json:"organization"`
	IsNewUser    bool          `json:"is_new_user"`
	AccessToken  string        `json:"access_token"`
	RefreshToken string        `json:"refresh_token"`
}

SSOCallbackResult returned after successful SSO authentication

type SSOConnection

type SSOConnection struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null;uniqueIndex" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	OrganizationID uint        `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	Protocol       SSOProtocol `json:"protocol" gorm:"type:varchar(10);not null"`

	// Display
	Name   string `json:"name" gorm:"type:varchar(255);not null"`
	Domain string `json:"domain" gorm:"type:varchar(255);not null;uniqueIndex"`

	// Protocol-specific configuration (stored as JSONB)
	SAMLConfig *SAMLConfig `json:"saml_config,omitempty" gorm:"type:jsonb"`
	OIDCConfig *OIDCConfig `json:"oidc_config,omitempty" gorm:"type:jsonb"`

	// SP (Passwall) metadata — generated at creation, read-only for admin
	SPEntityID string `json:"sp_entity_id" gorm:"type:varchar(512)"`
	SPAcsURL   string `json:"sp_acs_url" gorm:"type:varchar(512)"`
	SPMetadata string `json:"-" gorm:"type:text"`

	// Behaviour
	AutoProvision   bool                `json:"auto_provision" gorm:"default:true"`
	DefaultRole     OrganizationRole    `json:"default_role" gorm:"type:varchar(20);default:'member'"`
	JITProvisioning bool                `json:"jit_provisioning" gorm:"default:true"`
	Status          SSOConnectionStatus `json:"status" gorm:"type:varchar(20);not null;default:'draft'"`

	// Associations
	Organization *Organization `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
}

SSOConnection represents an SSO provider configuration for an organization

func (*SSOConnection) IsActive

func (s *SSOConnection) IsActive() bool

IsActive returns true if connection is active

func (*SSOConnection) IsOIDC

func (s *SSOConnection) IsOIDC() bool

IsOIDC returns true if protocol is OIDC

func (*SSOConnection) IsSAML

func (s *SSOConnection) IsSAML() bool

IsSAML returns true if protocol is SAML

func (SSOConnection) TableName

func (SSOConnection) TableName() string

TableName specifies the table name

type SSOConnectionDTO

type SSOConnectionDTO struct {
	ID              uint                `json:"id"`
	UUID            uuid.UUID           `json:"uuid"`
	OrganizationID  uint                `json:"organization_id"`
	Protocol        SSOProtocol         `json:"protocol"`
	Name            string              `json:"name"`
	Domain          string              `json:"domain"`
	SPEntityID      string              `json:"sp_entity_id"`
	SPAcsURL        string              `json:"sp_acs_url"`
	AutoProvision   bool                `json:"auto_provision"`
	DefaultRole     OrganizationRole    `json:"default_role"`
	JITProvisioning bool                `json:"jit_provisioning"`
	Status          SSOConnectionStatus `json:"status"`
	CreatedAt       time.Time           `json:"created_at"`
	UpdatedAt       time.Time           `json:"updated_at"`

	// Protocol-specific (admin-visible only)
	SAMLConfig *SAMLConfigDTO `json:"saml_config,omitempty"`
	OIDCConfig *OIDCConfigDTO `json:"oidc_config,omitempty"`
}

SSOConnectionDTO for API responses (sensitive fields stripped)

func ToSSOConnectionDTO

func ToSSOConnectionDTO(conn *SSOConnection) *SSOConnectionDTO

ToSSOConnectionDTO converts SSOConnection to DTO

type SSOConnectionStatus

type SSOConnectionStatus string

SSOConnectionStatus represents the status of an SSO connection

const (
	SSOStatusDraft    SSOConnectionStatus = "draft"
	SSOStatusActive   SSOConnectionStatus = "active"
	SSOStatusInactive SSOConnectionStatus = "inactive"
)

type SSOInitiateRequest

type SSOInitiateRequest struct {
	Domain      string `json:"domain" binding:"required"`
	RedirectURL string `json:"redirect_url,omitempty"`
}

SSOInitiateRequest for starting SSO login

type SSOProtocol

type SSOProtocol string

SSOProtocol represents the SSO protocol type

const (
	SSOProtocolSAML SSOProtocol = "saml"
	SSOProtocolOIDC SSOProtocol = "oidc"
)

type SSOState

type SSOState struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	CreatedAt time.Time `json:"created_at"`

	State          string    `json:"state" gorm:"type:varchar(512);not null;uniqueIndex"`
	ConnectionID   uint      `json:"connection_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	OrganizationID uint      `json:"organization_id" gorm:"not null;index"`
	RedirectURL    string    `json:"redirect_url" gorm:"type:varchar(2048)"`
	CodeVerifier   string    `json:"-" gorm:"type:varchar(512)"`
	Nonce          string    `json:"-" gorm:"type:varchar(512)"`
	ExpiresAt      time.Time `json:"expires_at" gorm:"not null;index"`
}

SSOState stores transient SSO authentication state (CSRF protection)

func (*SSOState) IsExpired

func (s *SSOState) IsExpired() bool

IsExpired checks if the state has expired

func (SSOState) TableName

func (SSOState) TableName() string

TableName specifies the table name

type SeatChangePreview

type SeatChangePreview struct {
	CurrentSeats      int    `json:"current_seats"`
	RequestedSeats    int    `json:"requested_seats"`
	ProratedAmount    int64  `json:"prorated_amount"`     // cents – positive means charge, negative means credit
	Currency          string `json:"currency"`            // e.g. "usd"
	NextBillingDate   string `json:"next_billing_date"`   // ISO-8601
	NextBillingAmount int64  `json:"next_billing_amount"` // cents – full amount at next renewal
}

SeatChangePreview shows the cost impact of changing seat count before the user confirms. This uses Stripe's upcoming invoice preview so the amount matches exactly what will be charged.

type SharePersonalItemRequest

type SharePersonalItemRequest struct {
	PersonalItemUUID string `json:"personal_item_uuid" validate:"required"`
	CollectionID     *uint  `json:"collection_id,omitempty"`
	Data             string `json:"data" validate:"required"` // Re-encrypted with Org Key
}

SharePersonalItemRequest for sharing a personal item to organization

type SignUpRequest

type SignUpRequest struct {
	Name               string     `json:"name" validate:"max=100"`
	Email              string     `json:"email" validate:"required,email"`
	MasterPasswordHash string     `json:"master_password_hash" validate:"required"` // HKDF(masterKey, info="auth")
	ProtectedUserKey   string     `json:"protected_user_key" validate:"required"`   // EncString: "2.iv|ct|mac"
	KdfConfig          *KdfConfig `json:"kdf_config" validate:"required"`
	KdfSalt            string     `json:"kdf_salt" validate:"required"`          // hex-encoded random salt from client
	EncryptedOrgKey    string     `json:"encrypted_org_key" validate:"required"` // Organization key encrypted with User Key
}

SignUpRequest represents a user registration request

func (*SignUpRequest) Validate

func (r *SignUpRequest) Validate() error

Validate validates the signup request

type SoleOwnerOrganization

type SoleOwnerOrganization struct {
	ID          uint   `json:"id"`
	Name        string `json:"name"`
	MemberCount int    `json:"member_count"`
	CanTransfer bool   `json:"can_transfer"` // True if there are other members to transfer to
}

SoleOwnerOrganization represents an organization where user is the sole owner

type Subscription

type Subscription struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	OrganizationID uint              `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	PlanID         uint              `json:"plan_id" gorm:"not null;index"`
	State          SubscriptionState `json:"state" gorm:"type:varchar(20);not null;default:'draft'"`

	// Lifecycle timestamps
	StartedAt         *time.Time `json:"started_at,omitempty"`
	RenewAt           *time.Time `json:"renew_at,omitempty"`
	CancelAt          *time.Time `json:"cancel_at,omitempty"`
	EndedAt           *time.Time `json:"ended_at,omitempty"`
	GracePeriodEndsAt *time.Time `json:"grace_period_ends_at,omitempty"`
	TrialEndsAt       *time.Time `json:"trial_ends_at,omitempty"`

	// Stripe integration
	StripeSubscriptionID *string `json:"stripe_subscription_id,omitempty" gorm:"type:varchar(255);uniqueIndex"`

	// Seat-based billing (quantity-based Stripe subscriptions)
	// Null means "not seat-based / unknown". When set, it becomes the effective user limit.
	SeatsPurchased *int `json:"seats_purchased,omitempty" gorm:"index"`

	// Associations
	Organization *Organization `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
	Plan         *Plan         `json:"plan,omitempty" gorm:"foreignKey:PlanID"`
}

Subscription represents an organization's subscription to a plan

func (*Subscription) CanWrite

func (s *Subscription) CanWrite() bool

CanWrite checks if subscription allows write operations

func (*Subscription) IsActive

func (s *Subscription) IsActive() bool

IsActive checks if subscription allows full access

func (*Subscription) IsCanceled

func (s *Subscription) IsCanceled() bool

IsCanceled checks if subscription is canceled

func (*Subscription) IsExpired

func (s *Subscription) IsExpired() bool

IsExpired checks if subscription has expired

func (*Subscription) IsInGracePeriod

func (s *Subscription) IsInGracePeriod() bool

IsInGracePeriod checks if subscription is in grace period after payment failure

func (*Subscription) ShouldExpire

func (s *Subscription) ShouldExpire() bool

ShouldExpire checks if subscription should be expired (grace period ended or cancel period ended)

func (Subscription) TableName

func (Subscription) TableName() string

TableName specifies the table name

type SubscriptionDTO

type SubscriptionDTO struct {
	ID                   uint              `json:"id"`
	UUID                 uuid.UUID         `json:"uuid"`
	OrganizationID       uint              `json:"organization_id"`
	Plan                 *PlanDTO          `json:"plan,omitempty"`
	State                SubscriptionState `json:"state"`
	StartedAt            *time.Time        `json:"started_at,omitempty"`
	RenewAt              *time.Time        `json:"renew_at,omitempty"`
	CancelAt             *time.Time        `json:"cancel_at,omitempty"`
	EndedAt              *time.Time        `json:"ended_at,omitempty"`
	GracePeriodEndsAt    *time.Time        `json:"grace_period_ends_at,omitempty"`
	TrialEndsAt          *time.Time        `json:"trial_ends_at,omitempty"`
	StripeSubscriptionID *string           `json:"stripe_subscription_id,omitempty"`
	SeatsPurchased       *int              `json:"seats_purchased,omitempty"`
	CreatedAt            time.Time         `json:"created_at"`
	UpdatedAt            time.Time         `json:"updated_at"`
}

SubscriptionDTO for API responses

func ToSubscriptionDTO

func ToSubscriptionDTO(s *Subscription) *SubscriptionDTO

ToSubscriptionDTO converts Subscription to DTO

type SubscriptionState

type SubscriptionState string

SubscriptionState represents the state of a subscription

const (
	SubStateDraft    SubscriptionState = "draft"
	SubStateTrialing SubscriptionState = "trialing"
	SubStateActive   SubscriptionState = "active"
	SubStatePastDue  SubscriptionState = "past_due"
	SubStateCanceled SubscriptionState = "canceled"
	SubStateExpired  SubscriptionState = "expired"
)

func (SubscriptionState) String

func (s SubscriptionState) String() string

String returns the string representation of SubscriptionState

type Team

type Team struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	OrganizationID uint `json:"organization_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Team details
	Name        string `json:"name" gorm:"type:varchar(255);not null"`
	Description string `json:"description,omitempty" gorm:"type:text"`

	// System defaults
	IsDefault bool `json:"is_default" gorm:"not null;default:false"`

	// Access control
	AccessAllCollections bool `json:"access_all_collections" gorm:"default:false"`

	// External ID for LDAP/AD sync
	ExternalID *string `json:"external_id,omitempty" gorm:"type:varchar(255);index"`

	// Associations
	Organization *Organization `json:"organization,omitempty" gorm:"foreignKey:OrganizationID"`
	Members      []TeamUser    `json:"members,omitempty" gorm:"foreignKey:TeamID"`
}

Team represents a group of users within an organization

func (Team) TableName

func (Team) TableName() string

TableName specifies the table name

type TeamDTO

type TeamDTO struct {
	ID                   uint      `json:"id"`
	UUID                 uuid.UUID `json:"uuid"`
	OrganizationID       uint      `json:"organization_id"`
	Name                 string    `json:"name"`
	Description          string    `json:"description,omitempty"`
	AccessAllCollections bool      `json:"access_all_collections"`
	ExternalID           *string   `json:"external_id,omitempty"`
	IsDefault            bool      `json:"is_default"`
	CreatedAt            time.Time `json:"created_at"`
	UpdatedAt            time.Time `json:"updated_at"`

	// Stats (optional)
	MemberCount *int `json:"member_count,omitempty"`
}

TeamDTO for API responses

func ToTeamDTO

func ToTeamDTO(team *Team) *TeamDTO

ToTeamDTO converts Team to DTO

type TeamUser

type TeamUser struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	CreatedAt time.Time `json:"created_at"`

	TeamID             uint `json:"team_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`
	OrganizationUserID uint `json:"organization_user_id" gorm:"not null;index;constraint:OnDelete:CASCADE"`

	// Role in team
	IsManager bool `json:"is_manager" gorm:"default:false"`

	// Associations
	Team             *Team             `json:"team,omitempty" gorm:"foreignKey:TeamID"`
	OrganizationUser *OrganizationUser `json:"organization_user,omitempty" gorm:"foreignKey:OrganizationUserID"`
}

TeamUser represents a user's membership in a team

func (TeamUser) TableName

func (TeamUser) TableName() string

TableName specifies the table name

type TeamUserDTO

type TeamUserDTO struct {
	ID                 uint      `json:"id"`
	TeamID             uint      `json:"team_id"`
	OrganizationUserID uint      `json:"organization_user_id"`
	UserID             uint      `json:"user_id"`
	UserEmail          string    `json:"user_email"`
	UserName           string    `json:"user_name"`
	IsManager          bool      `json:"is_manager"`
	CreatedAt          time.Time `json:"created_at"`
}

TeamUserDTO for API responses

func ToTeamUserDTO

func ToTeamUserDTO(tu *TeamUser) *TeamUserDTO

ToTeamUserDTO converts TeamUser to DTO

type Token

type Token struct {
	ID     int       `gorm:"primary_key" json:"id"`
	UserID int       `json:"user_id" gorm:"index;not null"`
	UUID   uuid.UUID `gorm:"type:uuid;type:varchar(100);uniqueIndex;not null" json:"uuid"`
	// SessionUUID groups access+refresh tokens belonging to the same login/session.
	// This allows multiple concurrent sessions (e.g. vault + extension) without revoking each other.
	SessionUUID uuid.UUID `gorm:"type:uuid;index" json:"-"`
	// DeviceID is an optional stable identifier for a device/app installation.
	// For Vault we currently align DeviceID with SessionUUID to avoid orphan sessions after tab close.
	DeviceID uuid.UUID `gorm:"type:uuid;index" json:"-"`
	// App identifies the client type: vault|extension|mobile|desktop
	App string `gorm:"type:varchar(16);index" json:"-"`
	// Kind is either "access" or "refresh" (optional for legacy rows).
	Kind       string    `gorm:"type:varchar(16);index" json:"-"`
	Token      string    `gorm:"type:text;not null" json:"-"`
	ExpiryTime time.Time `json:"expiry_time" gorm:"index;not null"`
}

Token represents authentication tokens stored in the database

func (*Token) IsExpired

func (t *Token) IsExpired() bool

IsExpired checks if the token has expired

func (Token) TableName

func (Token) TableName() string

TableName specifies the table name for Token

type TokenClaims

type TokenClaims struct {
	UserID uint      `json:"user_id"`
	Email  string    `json:"email"`
	Schema string    `json:"schema"`
	Role   string    `json:"role"`
	UUID   uuid.UUID `json:"uuid"`
	Exp    int64     `json:"exp"`
}

TokenClaims represents JWT token claims

type TokenDetails

type TokenDetails struct {
	AccessToken           string    `json:"access_token"`
	RefreshToken          string    `json:"refresh_token"`
	AccessTokenExpiresAt  int64     `json:"access_token_expires_at,omitempty"`  // unix seconds
	RefreshTokenExpiresAt int64     `json:"refresh_token_expires_at,omitempty"` // unix seconds
	AtExpiresTime         time.Time `json:"-"`
	RtExpiresTime         time.Time `json:"-"`
	AtUUID                uuid.UUID `json:"-"`
	RtUUID                uuid.UUID `json:"-"`
	SessionUUID           uuid.UUID `json:"-"`
}

TokenDetails represents JWT token details

type TransferOwnershipRequest

type TransferOwnershipRequest struct {
	UserID         uint `json:"user_id" binding:"required"`
	OrganizationID uint `json:"organization_id" binding:"required"`
	NewOwnerUserID uint `json:"new_owner_user_id" binding:"required"`
}

TransferOwnershipRequest represents a request to transfer organization ownership

type UpdateCollectionRequest

type UpdateCollectionRequest struct {
	Name        *string `json:"name,omitempty" validate:"omitempty,max=255"`
	Description *string `json:"description,omitempty" validate:"omitempty,max=1000"`
	IsPrivate   *bool   `json:"is_private,omitempty"`
}

UpdateCollectionRequest for API requests

type UpdateOrgUserRoleRequest

type UpdateOrgUserRoleRequest struct {
	Role      OrganizationRole `json:"role" binding:"required,oneof=owner admin manager member"`
	AccessAll *bool            `json:"access_all,omitempty"`
}

UpdateOrgUserRoleRequest for updating user role

type UpdateOrganizationFolderRequest

type UpdateOrganizationFolderRequest struct {
	Name string `json:"name" validate:"required,max=255"`
}

type UpdateOrganizationItemRequest

type UpdateOrganizationItemRequest struct {
	CollectionID *uint         `json:"collection_id,omitempty"`
	Data         *string       `json:"data,omitempty"`
	Metadata     *ItemMetadata `json:"metadata,omitempty"`
	IsFavorite   *bool         `json:"is_favorite,omitempty"`
	FolderID     *uint         `json:"folder_id,omitempty"`
	Reprompt     *bool         `json:"reprompt,omitempty"`
	AutoFill     *bool         `json:"auto_fill,omitempty"`
	AutoLogin    *bool         `json:"auto_login,omitempty"`
}

UpdateOrganizationItemRequest for API requests

type UpdateOrganizationRequest

type UpdateOrganizationRequest struct {
	Name         *string `json:"name,omitempty" validate:"omitempty,max=255"`
	BillingEmail *string `json:"billing_email,omitempty" validate:"omitempty,email"`
}

UpdateOrganizationRequest for API requests

type UpdateSSOConnectionRequest

type UpdateSSOConnectionRequest struct {
	Name            *string              `json:"name,omitempty" binding:"omitempty,max=255"`
	Domain          *string              `json:"domain,omitempty" binding:"omitempty,max=255"`
	SAMLConfig      *SAMLConfig          `json:"saml_config,omitempty"`
	OIDCConfig      *OIDCConfig          `json:"oidc_config,omitempty"`
	AutoProvision   *bool                `json:"auto_provision,omitempty"`
	DefaultRole     *OrganizationRole    `json:"default_role,omitempty"`
	JITProvisioning *bool                `json:"jit_provisioning,omitempty"`
	Status          *SSOConnectionStatus `json:"status,omitempty" binding:"omitempty,oneof=draft active inactive"`
}

UpdateSSOConnectionRequest for updating an SSO connection

type UpdateSubscriptionRequest

type UpdateSubscriptionRequest struct {
	PlanCode string `json:"plan_code" validate:"required"`
}

UpdateSubscriptionRequest for API requests

type UpdateTeamRequest

type UpdateTeamRequest struct {
	Name                 *string `json:"name,omitempty" validate:"omitempty,max=255"`
	Description          *string `json:"description,omitempty" validate:"omitempty,max=1000"`
	AccessAllCollections *bool   `json:"access_all_collections,omitempty"`
}

UpdateTeamRequest for API requests

type UpdateTeamUserRequest

type UpdateTeamUserRequest struct {
	IsManager bool `json:"is_manager"`
}

UpdateTeamUserRequest for updating team member

type UpdateUserAppearancePreferencesRequest

type UpdateUserAppearancePreferencesRequest struct {
	Theme *string `json:"theme"`
	Font  *string `json:"font"`
}

UpdateUserAppearancePreferencesRequest supports partial updates. (Fields are pointers so "unset" can be distinguished from empty values.)

type UpdateUserNotificationPreferencesRequest

type UpdateUserNotificationPreferencesRequest struct {
	CommunicationEmails *bool `json:"communication_emails"`
	MarketingEmails     *bool `json:"marketing_emails"`
	SocialEmails        *bool `json:"social_emails"`
	SecurityEmails      *bool `json:"security_emails"`
}

UpdateUserNotificationPreferencesRequest supports partial updates. (Booleans are pointers so "unset" can be distinguished from false.)

type UpdateUserRequest

type UpdateUserRequest struct {
	Name        *string `json:"name,omitempty"`
	Email       *string `json:"email,omitempty"`
	RoleID      *uint   `json:"role_id,omitempty"`
	DateOfBirth *string `json:"date_of_birth,omitempty"`
	Language    *string `json:"language,omitempty"`
}

UpdateUserRequest represents user update request

func (*UpdateUserRequest) ApplyTo

func (r *UpdateUserRequest) ApplyTo(user *User)

ApplyTo applies the update request to a user

func (*UpdateUserRequest) HasUpdates

func (r *UpdateUserRequest) HasUpdates() bool

HasUpdates checks if any field is being updated

type UpsertPreferenceRequest

type UpsertPreferenceRequest struct {
	Section string `json:"section"`
	Key     string `json:"key"`
	Type    string `json:"type"`
	Value   string `json:"value"`
}

type UpsertPreferencesRequest

type UpsertPreferencesRequest struct {
	Preferences []UpsertPreferenceRequest `json:"preferences"`
}

type User

type User struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;type:varchar(100);" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	Name   string `json:"name" gorm:"type:varchar(255)"`
	Email  string `json:"email" gorm:"type:varchar(255);uniqueIndex;not null"`
	Schema string `json:"schema" gorm:"type:varchar(255);uniqueIndex;not null"`

	// Organization pointers (per user)
	PersonalOrganizationID uint `json:"personal_organization_id" gorm:"not null"`
	DefaultOrganizationID  uint `json:"default_organization_id" gorm:"not null"`

	// Modern Zero-Knowledge Encryption Fields
	MasterPasswordHash string `json:"-" gorm:"type:varchar(255);not null"` // bcrypt(HKDF(masterKey, info="auth"))
	ProtectedUserKey   string `json:"-" gorm:"type:text;not null"`         // EncString: "2.iv|ct|mac"

	// KDF Configuration (per user, configurable)
	KdfType        KdfType `json:"kdf_type" gorm:"not null;default:0"`            // 0=PBKDF2, 1=Argon2id
	KdfIterations  int     `json:"kdf_iterations" gorm:"not null;default:600000"` // Default: 600K
	KdfMemory      *int    `json:"kdf_memory,omitempty"`                          // For Argon2 (MB)
	KdfParallelism *int    `json:"kdf_parallelism,omitempty"`                     // For Argon2 (threads)
	KdfSalt        string  `json:"-" gorm:"type:varchar(64);not null"`            // hex-encoded 32 bytes, random per user

	// RSA Keys for Organization Sharing (optional, generated when joining first org)
	RSAPublicKey     *string `json:"rsa_public_key,omitempty" gorm:"type:text"` // RSA-2048 public key (PEM format)
	RSAPrivateKeyEnc *string `json:"-" gorm:"type:text"`                        // RSA private key encrypted with User Key (EncString)

	// User metadata
	RoleID       uint   `json:"role_id" gorm:"not null;default:2;constraint:OnUpdate:CASCADE,OnDelete:RESTRICT"`
	Role         *Role  `json:"role,omitempty" gorm:"foreignKey:RoleID"`
	IsVerified   bool   `json:"is_verified" gorm:"default:false"`
	IsSystemUser bool   `json:"is_system_user" gorm:"default:false;index"` // System users (e.g., super admin) cannot be deleted
	Language     string `json:"language" gorm:"type:varchar(10);default:'en'"`

	// Stripe integration for personal subscriptions
	StripeCustomerID *string `json:"-" gorm:"type:varchar(255);index"` // Stripe customer ID for user-level billing

	// Stats (runtime calculated, not stored in DB)
	ItemCount *int `json:"item_count,omitempty" gorm:"-"`
}

User represents a user account in the system

func (*User) GetKdfConfig

func (u *User) GetKdfConfig() *KdfConfig

GetKdfConfig extracts KDF config from user

func (*User) GetRoleName

func (u *User) GetRoleName() string

GetRoleName returns the role name with proper null handling

func (*User) HasPermission

func (u *User) HasPermission(permission string) bool

HasPermission checks if user has a specific permission (requires Role.Permissions to be loaded)

func (*User) IsAdmin

func (u *User) IsAdmin() bool

IsAdmin checks if user is an admin

func (User) TableName

func (User) TableName() string

TableName specifies the table name for User

type UserActivity

type UserActivity struct {
	ID           uint         `gorm:"primary_key" json:"id"`
	UserID       uint         `gorm:"not null;index" json:"user_id"`
	ActivityType ActivityType `gorm:"type:varchar(50);not null;index" json:"activity_type"`
	IPAddress    string       `gorm:"type:varchar(45)" json:"ip_address"` // IPv4 or IPv6
	UserAgent    string       `gorm:"type:varchar(500)" json:"user_agent"`
	Details      string       `gorm:"type:text" json:"details,omitempty"` // JSON for additional info
	CreatedAt    time.Time    `gorm:"index" json:"created_at"`
}

UserActivity represents user activity log for audit trail

func (UserActivity) TableName

func (UserActivity) TableName() string

TableName specifies the table name

type UserActivityDTO

type UserActivityDTO struct {
	ID           uint         `json:"id"`
	UserID       uint         `json:"user_id"`
	ActivityType ActivityType `json:"activity_type"`
	IPAddress    string       `json:"ip_address"`
	UserAgent    string       `json:"user_agent"`
	Details      string       `json:"details,omitempty"`
	CreatedAt    time.Time    `json:"created_at"`
}

UserActivityDTO for API responses

func ToUserActivityDTO

func ToUserActivityDTO(activity *UserActivity) *UserActivityDTO

ToUserActivityDTO converts UserActivity to DTO

func ToUserActivityDTOs

func ToUserActivityDTOs(activities []*UserActivity) []*UserActivityDTO

ToUserActivityDTOs converts multiple activities to DTOs

type UserAppearancePreferences

type UserAppearancePreferences struct {
	UserID uint `json:"user_id" gorm:"primaryKey"`

	// Theme can be: dark | light | system
	Theme string `json:"theme" gorm:"not null;default:dark"`

	// Font is a UI hint (e.g. inter, manrope, system).
	Font string `json:"font" gorm:"not null;default:inter"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

UserAppearancePreferences stores per-user UI preferences (theme, font).

This is a 1:1 table keyed by user_id (PK) to keep reads/updates fast.

func (UserAppearancePreferences) TableName

func (UserAppearancePreferences) TableName() string

type UserAppearancePreferencesDTO

type UserAppearancePreferencesDTO struct {
	Theme string `json:"theme"`
	Font  string `json:"font"`
}

UserAppearancePreferencesDTO is the API response shape.

type UserAuthDTO

type UserAuthDTO struct {
	ID                     uint   `json:"id"`
	UUID                   string `json:"uuid"`
	Email                  string `json:"email"`
	Name                   string `json:"name"`
	Schema                 string `json:"schema"`
	Role                   string `json:"role"`
	IsVerified             bool   `json:"is_verified"`
	Language               string `json:"language"`
	PersonalOrganizationID uint   `json:"personal_organization_id"`
	DefaultOrganizationID  uint   `json:"default_organization_id"`
}

UserAuthDTO represents user data in auth responses

type UserBillingInfo

type UserBillingInfo struct {
	UserID       uint                 `json:"user_id"`
	Email        string               `json:"email"`
	Name         string               `json:"name"`
	IsPro        bool                 `json:"is_pro"` // true if user has active Pro subscription
	Subscription *UserSubscriptionDTO `json:"subscription,omitempty"`
	CurrentPlan  string               `json:"current_plan"` // "free" or plan code like "pro-monthly"
	CurrentItems int                  `json:"current_items"`
	Invoices     []*InvoiceDTO        `json:"invoices,omitempty"`

	// Payment provider information
	Provider          PaymentProvider `json:"provider"`                     // "stripe", "revenuecat", "manual", "none"
	Store             string          `json:"store,omitempty"`              // "APP_STORE", "PLAY_STORE", etc. (only for revenuecat)
	StoreDisplayName  string          `json:"store_display_name,omitempty"` // "Apple App Store", "Google Play Store", etc.
	ManagedExternally bool            `json:"managed_externally"`           // true if subscription can only be canceled from external store
	CanCancel         bool            `json:"can_cancel"`                   // true if subscription can be canceled from our API
	CanUpgrade        bool            `json:"can_upgrade"`                  // true if plan can be changed from our API
}

UserBillingInfo represents billing information for a user

type UserDTO

type UserDTO struct {
	ID            uint      `json:"id"`
	UUID          uuid.UUID `json:"uuid"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
	Name          string    `json:"name"`
	Email         string    `json:"email"`
	Schema        string    `json:"schema"`
	Role          string    `json:"role"`
	IsVerified    bool      `json:"is_verified"`
	IsSystemUser  bool      `json:"is_system_user"` // System users cannot be deleted
	Language      string    `json:"language"`
	ItemCount     *int      `json:"item_count,omitempty"`
	KdfType       KdfType   `json:"kdf_type"`
	KdfIterations int       `json:"kdf_iterations"`
}

UserDTO is the data transfer object for User It converts the Role relationship to a simple string for API responses

func ToUserDTO

func ToUserDTO(user *User) *UserDTO

ToUserDTO converts User to UserDTO

func ToUserDTOs

func ToUserDTOs(users []*User) []*UserDTO

ToUserDTOs converts multiple Users to UserDTOs

type UserNotificationPreferences

type UserNotificationPreferences struct {
	UserID uint `json:"user_id" gorm:"primaryKey"`

	CommunicationEmails bool `json:"communication_emails" gorm:"not null;default:false"`
	MarketingEmails     bool `json:"marketing_emails" gorm:"not null;default:false"`
	SocialEmails        bool `json:"social_emails" gorm:"not null;default:false"`

	// Security emails are mandatory and should not be disabled.
	SecurityEmails bool `json:"security_emails" gorm:"not null;default:true"`

	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

UserNotificationPreferences stores per-user notification delivery preferences.

This is intentionally a 1:1 table keyed by user_id (PK) to keep reads/updates fast and to avoid having to manage separate IDs for a purely user-scoped row.

func (UserNotificationPreferences) TableName

func (UserNotificationPreferences) TableName() string

type UserNotificationPreferencesDTO

type UserNotificationPreferencesDTO struct {
	CommunicationEmails bool `json:"communication_emails"`
	MarketingEmails     bool `json:"marketing_emails"`
	SocialEmails        bool `json:"social_emails"`
	SecurityEmails      bool `json:"security_emails"`
}

UserNotificationPreferencesDTO is the API response shape.

type UserSubscription

type UserSubscription struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	UUID      uuid.UUID `gorm:"type:uuid;not null" json:"uuid"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`

	UserID uint              `json:"user_id" gorm:"not null;uniqueIndex;constraint:OnDelete:CASCADE"`
	PlanID uint              `json:"plan_id" gorm:"not null;index"`
	State  SubscriptionState `json:"state" gorm:"type:varchar(20);not null;default:'draft'"`

	// Lifecycle timestamps
	StartedAt         *time.Time `json:"started_at,omitempty"`
	RenewAt           *time.Time `json:"renew_at,omitempty"`
	CancelAt          *time.Time `json:"cancel_at,omitempty"`
	EndedAt           *time.Time `json:"ended_at,omitempty"`
	GracePeriodEndsAt *time.Time `json:"grace_period_ends_at,omitempty"`
	TrialEndsAt       *time.Time `json:"trial_ends_at,omitempty"`

	// Stripe integration
	StripeSubscriptionID *string `json:"stripe_subscription_id,omitempty" gorm:"type:varchar(255);uniqueIndex"`

	// Associations
	User *User `json:"user,omitempty" gorm:"foreignKey:UserID"`
	Plan *Plan `json:"plan,omitempty" gorm:"foreignKey:PlanID"`
}

UserSubscription represents a user's personal subscription to a plan (e.g., Pro) This is separate from organization subscriptions - every user can have their own subscription.

func (*UserSubscription) CanWrite

func (s *UserSubscription) CanWrite() bool

CanWrite checks if subscription allows write operations

func (*UserSubscription) IsActive

func (s *UserSubscription) IsActive() bool

IsActive checks if subscription allows full access

func (*UserSubscription) IsCanceled

func (s *UserSubscription) IsCanceled() bool

IsCanceled checks if subscription is canceled

func (*UserSubscription) IsExpired

func (s *UserSubscription) IsExpired() bool

IsExpired checks if subscription has expired

func (*UserSubscription) IsInGracePeriod

func (s *UserSubscription) IsInGracePeriod() bool

IsInGracePeriod checks if subscription is in grace period after payment failure

func (*UserSubscription) ShouldExpire

func (s *UserSubscription) ShouldExpire() bool

ShouldExpire checks if subscription should be expired

func (UserSubscription) TableName

func (UserSubscription) TableName() string

TableName specifies the table name

type UserSubscriptionDTO

type UserSubscriptionDTO struct {
	ID                   uint              `json:"id"`
	UUID                 uuid.UUID         `json:"uuid"`
	UserID               uint              `json:"user_id"`
	Plan                 *PlanDTO          `json:"plan,omitempty"`
	State                SubscriptionState `json:"state"`
	StartedAt            *time.Time        `json:"started_at,omitempty"`
	RenewAt              *time.Time        `json:"renew_at,omitempty"`
	CancelAt             *time.Time        `json:"cancel_at,omitempty"`
	EndedAt              *time.Time        `json:"ended_at,omitempty"`
	GracePeriodEndsAt    *time.Time        `json:"grace_period_ends_at,omitempty"`
	TrialEndsAt          *time.Time        `json:"trial_ends_at,omitempty"`
	StripeSubscriptionID *string           `json:"stripe_subscription_id,omitempty"`
	CreatedAt            time.Time         `json:"created_at"`
	UpdatedAt            time.Time         `json:"updated_at"`
}

UserSubscriptionDTO for API responses

func ToUserSubscriptionDTO

func ToUserSubscriptionDTO(s *UserSubscription) *UserSubscriptionDTO

ToUserSubscriptionDTO converts UserSubscription to DTO

type VerificationCode

type VerificationCode struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	Email     string    `json:"email" gorm:"type:varchar(255);not null;index:idx_verification_code_email"`
	Code      string    `json:"code" gorm:"type:varchar(6);not null;index:idx_verification_code_email"`
	ExpiresAt time.Time `json:"expires_at" gorm:"not null;index:idx_verification_code_expires"`
	CreatedAt time.Time `json:"created_at"`
}

VerificationCode represents email verification code in database

func (*VerificationCode) IsExpired

func (v *VerificationCode) IsExpired() bool

IsExpired checks if the verification code has expired

func (VerificationCode) TableName

func (VerificationCode) TableName() string

TableName specifies the table name for VerificationCode

type VerificationCodeRequest

type VerificationCodeRequest struct {
	Name  string `json:"name" binding:"required,max=100"`
	Email string `json:"email" binding:"required,email"`
}

VerificationCodeRequest represents a request to send verification code

type VerificationCodeResponse

type VerificationCodeResponse struct {
	Message string `json:"message"`
}

VerificationCodeResponse represents verification code response

type VerifyEmailRequest

type VerifyEmailRequest struct {
	Email string `json:"email" binding:"required,email"`
	Code  string `json:"code" binding:"required,len=6"`
}

VerifyEmailRequest represents email verification request

type VerifyEmailResponse

type VerifyEmailResponse struct {
	Message string `json:"message"`
	Success bool   `json:"success"`
}

VerifyEmailResponse represents email verification response

type WebhookEvent

type WebhookEvent struct {
	ID        uint      `gorm:"primary_key" json:"id"`
	CreatedAt time.Time `json:"created_at"`

	StripeEventID string         `json:"stripe_event_id" gorm:"type:varchar(255);uniqueIndex;not null"`
	EventType     string         `json:"event_type" gorm:"type:varchar(100);not null"`
	Payload       WebhookPayload `json:"payload" gorm:"type:jsonb;not null"`
	ProcessedAt   *time.Time     `json:"processed_at,omitempty"`
	Error         *string        `json:"error,omitempty" gorm:"type:text"`
}

WebhookEvent represents a Stripe webhook event for idempotency

func (*WebhookEvent) HasError

func (w *WebhookEvent) HasError() bool

HasError checks if webhook processing failed

func (*WebhookEvent) IsProcessed

func (w *WebhookEvent) IsProcessed() bool

IsProcessed checks if webhook event has been processed

func (*WebhookEvent) MarkFailed

func (w *WebhookEvent) MarkFailed(err error)

MarkFailed marks the webhook as failed with an error

func (*WebhookEvent) MarkProcessed

func (w *WebhookEvent) MarkProcessed()

MarkProcessed marks the webhook as successfully processed

func (WebhookEvent) TableName

func (WebhookEvent) TableName() string

TableName specifies the table name

type WebhookPayload

type WebhookPayload json.RawMessage

WebhookPayload represents the webhook payload

func (*WebhookPayload) Scan

func (p *WebhookPayload) Scan(value interface{}) error

Scan implements sql.Scanner for WebhookPayload (JSONB)

func (WebhookPayload) Value

func (p WebhookPayload) Value() (driver.Value, error)

Value implements driver.Valuer for WebhookPayload (JSONB)

Jump to

Keyboard shortcuts

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