DDL schemas for Trading Platform: - User management - Authentication - Payments - Education - ML predictions - Trading data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
107 lines
5.0 KiB
SQL
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';
|