Install LOC guardrails (check-loc.sh, architecture.md, pre-commit hook) and split all 44 files exceeding 500 LOC into domain-focused modules: - consent-service (Go): models, handlers, services, database splits - backend-core (Python): security_api, rbac_api, pdf_service, auth splits - admin-core (TypeScript): 5 page.tsx + sidebar extractions - pitch-deck (TypeScript): 6 slides, 3 UI components, engine.ts splits - voice-service (Python): enhanced_task_orchestrator split Result: 0 violations, 36 exempted (pipeline, tests, pure-data files). Go build verified clean. No behavior changes — pure structural splits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
196 lines
7.9 KiB
Go
196 lines
7.9 KiB
Go
package models
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// User represents a user with full authentication support
|
|
type User struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
ExternalID *string `json:"external_id,omitempty" db:"external_id"`
|
|
Email string `json:"email" db:"email"`
|
|
PasswordHash *string `json:"-" db:"password_hash"` // Never exposed in JSON
|
|
Name *string `json:"name,omitempty" db:"name"`
|
|
Role string `json:"role" db:"role"` // 'user', 'admin', 'super_admin', 'data_protection_officer'
|
|
EmailVerified bool `json:"email_verified" db:"email_verified"`
|
|
EmailVerifiedAt *time.Time `json:"email_verified_at,omitempty" db:"email_verified_at"`
|
|
AccountStatus string `json:"account_status" db:"account_status"` // 'active', 'suspended', 'locked'
|
|
LastLoginAt *time.Time `json:"last_login_at,omitempty" db:"last_login_at"`
|
|
FailedLoginAttempts int `json:"failed_login_attempts" db:"failed_login_attempts"`
|
|
LockedUntil *time.Time `json:"locked_until,omitempty" db:"locked_until"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// EmailVerificationToken for email verification
|
|
type EmailVerificationToken struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
|
Token string `json:"token" db:"token"`
|
|
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
|
UsedAt *time.Time `json:"used_at,omitempty" db:"used_at"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// PasswordResetToken for password reset
|
|
type PasswordResetToken struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
|
Token string `json:"token" db:"token"`
|
|
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
|
UsedAt *time.Time `json:"used_at,omitempty" db:"used_at"`
|
|
IPAddress *string `json:"ip_address,omitempty" db:"ip_address"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// UserSession for session management
|
|
type UserSession struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
|
TokenHash string `json:"-" db:"token_hash"`
|
|
DeviceInfo *string `json:"device_info,omitempty" db:"device_info"`
|
|
IPAddress *string `json:"ip_address,omitempty" db:"ip_address"`
|
|
UserAgent *string `json:"user_agent,omitempty" db:"user_agent"`
|
|
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
|
RevokedAt *time.Time `json:"revoked_at,omitempty" db:"revoked_at"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
LastActivityAt time.Time `json:"last_activity_at" db:"last_activity_at"`
|
|
}
|
|
|
|
// RegisterRequest for user registration
|
|
type RegisterRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Password string `json:"password" binding:"required,min=8"`
|
|
Name *string `json:"name"`
|
|
}
|
|
|
|
// LoginRequest for user login
|
|
type LoginRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
Password string `json:"password" binding:"required"`
|
|
}
|
|
|
|
// LoginResponse after successful login
|
|
type LoginResponse struct {
|
|
User User `json:"user"`
|
|
AccessToken string `json:"access_token"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
ExpiresIn int `json:"expires_in"` // seconds
|
|
}
|
|
|
|
// RefreshTokenRequest for token refresh
|
|
type RefreshTokenRequest struct {
|
|
RefreshToken string `json:"refresh_token" binding:"required"`
|
|
}
|
|
|
|
// VerifyEmailRequest for email verification
|
|
type VerifyEmailRequest struct {
|
|
Token string `json:"token" binding:"required"`
|
|
}
|
|
|
|
// ForgotPasswordRequest for password reset request
|
|
type ForgotPasswordRequest struct {
|
|
Email string `json:"email" binding:"required,email"`
|
|
}
|
|
|
|
// ResetPasswordRequest for password reset
|
|
type ResetPasswordRequest struct {
|
|
Token string `json:"token" binding:"required"`
|
|
NewPassword string `json:"new_password" binding:"required,min=8"`
|
|
}
|
|
|
|
// ChangePasswordRequest for changing password
|
|
type ChangePasswordRequest struct {
|
|
CurrentPassword string `json:"current_password" binding:"required"`
|
|
NewPassword string `json:"new_password" binding:"required,min=8"`
|
|
}
|
|
|
|
// UpdateProfileRequest for profile updates
|
|
type UpdateProfileRequest struct {
|
|
Name *string `json:"name"`
|
|
}
|
|
|
|
// ========================================
|
|
// Two-Factor Authentication (2FA/TOTP)
|
|
// ========================================
|
|
|
|
// UserTOTP stores 2FA TOTP configuration for a user
|
|
type UserTOTP struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
|
Secret string `json:"-" db:"secret"` // Encrypted TOTP secret
|
|
Verified bool `json:"verified" db:"verified"` // Has 2FA been verified/activated
|
|
RecoveryCodes []string `json:"-" db:"recovery_codes"` // Encrypted backup codes
|
|
EnabledAt *time.Time `json:"enabled_at,omitempty" db:"enabled_at"`
|
|
LastUsedAt *time.Time `json:"last_used_at,omitempty" db:"last_used_at"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
|
|
}
|
|
|
|
// TwoFactorChallenge represents a pending 2FA challenge during login
|
|
type TwoFactorChallenge struct {
|
|
ID uuid.UUID `json:"id" db:"id"`
|
|
UserID uuid.UUID `json:"user_id" db:"user_id"`
|
|
ChallengeID string `json:"challenge_id" db:"challenge_id"` // Temporary token
|
|
IPAddress *string `json:"ip_address,omitempty" db:"ip_address"`
|
|
UserAgent *string `json:"user_agent,omitempty" db:"user_agent"`
|
|
ExpiresAt time.Time `json:"expires_at" db:"expires_at"`
|
|
UsedAt *time.Time `json:"used_at,omitempty" db:"used_at"`
|
|
CreatedAt time.Time `json:"created_at" db:"created_at"`
|
|
}
|
|
|
|
// Setup2FAResponse when initiating 2FA setup
|
|
type Setup2FAResponse struct {
|
|
Secret string `json:"secret"` // Base32 encoded secret for manual entry
|
|
QRCodeDataURL string `json:"qr_code"` // Data URL for QR code image
|
|
RecoveryCodes []string `json:"recovery_codes"` // One-time backup codes
|
|
}
|
|
|
|
// Verify2FARequest for verifying 2FA setup or login
|
|
type Verify2FARequest struct {
|
|
Code string `json:"code" binding:"required"` // 6-digit TOTP code
|
|
ChallengeID string `json:"challenge_id,omitempty"` // For login flow
|
|
}
|
|
|
|
// TwoFactorLoginResponse when 2FA is required during login
|
|
type TwoFactorLoginResponse struct {
|
|
RequiresTwoFactor bool `json:"requires_two_factor"`
|
|
ChallengeID string `json:"challenge_id"` // Use this to complete 2FA
|
|
Message string `json:"message"`
|
|
}
|
|
|
|
// Complete2FALoginRequest to complete login with 2FA
|
|
type Complete2FALoginRequest struct {
|
|
ChallengeID string `json:"challenge_id" binding:"required"`
|
|
Code string `json:"code" binding:"required"` // 6-digit TOTP or recovery code
|
|
}
|
|
|
|
// Disable2FARequest for disabling 2FA
|
|
type Disable2FARequest struct {
|
|
Password string `json:"password" binding:"required"` // Require password confirmation
|
|
Code string `json:"code" binding:"required"` // Current TOTP code
|
|
}
|
|
|
|
// RecoveryCodeUseRequest for using a recovery code
|
|
type RecoveryCodeUseRequest struct {
|
|
ChallengeID string `json:"challenge_id" binding:"required"`
|
|
RecoveryCode string `json:"recovery_code" binding:"required"`
|
|
}
|
|
|
|
// TwoFactorStatusResponse for checking 2FA status
|
|
type TwoFactorStatusResponse struct {
|
|
Enabled bool `json:"enabled"`
|
|
Verified bool `json:"verified"`
|
|
EnabledAt *time.Time `json:"enabled_at,omitempty"`
|
|
RecoveryCodesCount int `json:"recovery_codes_count"`
|
|
}
|
|
|
|
// Verify2FAChallengeRequest for verifying a 2FA challenge during login
|
|
type Verify2FAChallengeRequest struct {
|
|
ChallengeID string `json:"challenge_id" binding:"required"`
|
|
Code string `json:"code,omitempty"` // 6-digit TOTP code
|
|
RecoveryCode string `json:"recovery_code,omitempty"` // Alternative: recovery code
|
|
}
|