trading-platform-database-v2/ddl/schemas/auth/tables/01-users.sql
rckrdmrd 45e77e9a9c feat: Initial commit - Database schemas and scripts
DDL schemas for Trading Platform:
- User management
- Authentication
- Payments
- Education
- ML predictions
- Trading data

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 04:30:23 -06:00

107 lines
5.0 KiB
SQL

-- ============================================================================
-- OrbiQuant IA - Trading Platform
-- Schema: auth
-- File: tables/01-users.sql
-- Description: Core users table for authentication and user management
-- ============================================================================
CREATE TABLE auth.users (
-- Primary Key
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
-- Authentication Credentials
email CITEXT NOT NULL UNIQUE,
email_verified BOOLEAN NOT NULL DEFAULT false,
email_verified_at TIMESTAMPTZ,
password_hash VARCHAR(255),
-- User Status and Role
status auth.user_status NOT NULL DEFAULT 'pending_verification',
role auth.user_role NOT NULL DEFAULT 'user',
-- Multi-Factor Authentication
mfa_enabled BOOLEAN NOT NULL DEFAULT false,
mfa_method auth.mfa_method NOT NULL DEFAULT 'none',
mfa_secret VARCHAR(255),
backup_codes JSONB DEFAULT '[]',
-- Phone Information
phone_number VARCHAR(20),
phone_verified BOOLEAN NOT NULL DEFAULT false,
phone_verified_at TIMESTAMPTZ,
-- Security Settings
last_login_at TIMESTAMPTZ,
last_login_ip INET,
failed_login_attempts INTEGER NOT NULL DEFAULT 0,
locked_until TIMESTAMPTZ,
-- Account Lifecycle
suspended_at TIMESTAMPTZ,
suspended_reason TEXT,
deactivated_at TIMESTAMPTZ,
-- Audit Fields
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
created_by_id UUID,
updated_by_id UUID,
-- Constraints
CONSTRAINT valid_email CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'),
-- NOTE: password_or_oauth constraint moved to 99-deferred-constraints.sql
-- to resolve circular dependency with oauth_accounts
CONSTRAINT failed_attempts_non_negative CHECK (failed_login_attempts >= 0),
CONSTRAINT email_verified_at_consistency CHECK (
(email_verified = true AND email_verified_at IS NOT NULL) OR
(email_verified = false AND email_verified_at IS NULL)
),
CONSTRAINT phone_verified_at_consistency CHECK (
(phone_verified = true AND phone_verified_at IS NOT NULL) OR
(phone_verified = false AND phone_verified_at IS NULL)
),
CONSTRAINT mfa_secret_consistency CHECK (
(mfa_enabled = true AND mfa_secret IS NOT NULL AND mfa_method != 'none') OR
(mfa_enabled = false)
)
);
-- Indexes for Performance
CREATE INDEX idx_users_email ON auth.users(email);
CREATE INDEX idx_users_status ON auth.users(status);
CREATE INDEX idx_users_role ON auth.users(role);
CREATE INDEX idx_users_last_login ON auth.users(last_login_at DESC);
CREATE INDEX idx_users_created_at ON auth.users(created_at DESC);
CREATE INDEX idx_users_email_verified ON auth.users(email_verified) WHERE email_verified = false;
CREATE INDEX idx_users_locked ON auth.users(locked_until) WHERE locked_until IS NOT NULL;
CREATE INDEX idx_users_phone ON auth.users(phone_number) WHERE phone_number IS NOT NULL;
-- Table Comments
COMMENT ON TABLE auth.users IS 'Core users table for authentication and user management';
-- Column Comments
COMMENT ON COLUMN auth.users.id IS 'Unique identifier for the user';
COMMENT ON COLUMN auth.users.email IS 'User email address (case-insensitive, unique)';
COMMENT ON COLUMN auth.users.email_verified IS 'Whether the email has been verified';
COMMENT ON COLUMN auth.users.email_verified_at IS 'Timestamp when email was verified';
COMMENT ON COLUMN auth.users.password_hash IS 'Bcrypt hashed password (null for OAuth-only users)';
COMMENT ON COLUMN auth.users.status IS 'Current status of the user account';
COMMENT ON COLUMN auth.users.role IS 'User role for role-based access control';
COMMENT ON COLUMN auth.users.mfa_enabled IS 'Whether multi-factor authentication is enabled';
COMMENT ON COLUMN auth.users.mfa_method IS 'MFA method used (totp, sms, email)';
COMMENT ON COLUMN auth.users.mfa_secret IS 'Secret key for TOTP MFA';
COMMENT ON COLUMN auth.users.phone_number IS 'User phone number for SMS verification';
COMMENT ON COLUMN auth.users.phone_verified IS 'Whether the phone number has been verified';
COMMENT ON COLUMN auth.users.phone_verified_at IS 'Timestamp when phone was verified';
COMMENT ON COLUMN auth.users.last_login_at IS 'Timestamp of last successful login';
COMMENT ON COLUMN auth.users.last_login_ip IS 'IP address of last successful login';
COMMENT ON COLUMN auth.users.failed_login_attempts IS 'Counter for failed login attempts';
COMMENT ON COLUMN auth.users.locked_until IS 'Account locked until this timestamp (null if not locked)';
COMMENT ON COLUMN auth.users.suspended_at IS 'Timestamp when account was suspended';
COMMENT ON COLUMN auth.users.suspended_reason IS 'Reason for account suspension';
COMMENT ON COLUMN auth.users.deactivated_at IS 'Timestamp when account was deactivated';
COMMENT ON COLUMN auth.users.created_at IS 'Timestamp when user was created';
COMMENT ON COLUMN auth.users.updated_at IS 'Timestamp when user was last updated';
COMMENT ON COLUMN auth.users.created_by_id IS 'ID of user who created this record';
COMMENT ON COLUMN auth.users.updated_by_id IS 'ID of user who last updated this record';