-- ============================================================================ -- OrbiQuant IA - Trading Platform -- Schema: auth -- File: tables/09-login_attempts.sql -- Description: Login attempt tracking for rate limiting and security monitoring -- ============================================================================ CREATE TABLE auth.login_attempts ( -- Primary Key id UUID PRIMARY KEY DEFAULT gen_random_uuid(), -- Attempt Information email CITEXT, user_id UUID, -- Request Context ip_address INET NOT NULL, user_agent TEXT, -- Attempt Result success BOOLEAN NOT NULL, failure_reason VARCHAR(100), -- Additional Details attempted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Metadata metadata JSONB DEFAULT '{}'::jsonb, -- Audit Fields created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), -- Check Constraints CONSTRAINT login_attempt_has_identifier CHECK ( email IS NOT NULL OR user_id IS NOT NULL ), CONSTRAINT failure_reason_consistency CHECK ( (success = false AND failure_reason IS NOT NULL) OR (success = true AND failure_reason IS NULL) ) ); -- Indexes for Performance CREATE INDEX idx_login_attempts_email ON auth.login_attempts(email, created_at DESC); CREATE INDEX idx_login_attempts_user_id ON auth.login_attempts(user_id, created_at DESC); CREATE INDEX idx_login_attempts_ip ON auth.login_attempts(ip_address, created_at DESC); CREATE INDEX idx_login_attempts_created ON auth.login_attempts(created_at DESC); CREATE INDEX idx_login_attempts_failures ON auth.login_attempts(email, ip_address, created_at DESC) WHERE success = false; CREATE INDEX idx_login_attempts_success ON auth.login_attempts(email, created_at DESC) WHERE success = true; CREATE INDEX idx_login_attempts_metadata ON auth.login_attempts USING gin(metadata); -- Table Comments COMMENT ON TABLE auth.login_attempts IS 'Login attempt tracking for rate limiting, brute force detection, and security monitoring'; -- Column Comments COMMENT ON COLUMN auth.login_attempts.id IS 'Unique identifier for the login attempt'; COMMENT ON COLUMN auth.login_attempts.email IS 'Email address used in login attempt'; COMMENT ON COLUMN auth.login_attempts.user_id IS 'User ID if resolved from email'; COMMENT ON COLUMN auth.login_attempts.ip_address IS 'IP address of the login attempt'; COMMENT ON COLUMN auth.login_attempts.user_agent IS 'User agent string from the request'; COMMENT ON COLUMN auth.login_attempts.success IS 'Whether the login attempt was successful'; COMMENT ON COLUMN auth.login_attempts.failure_reason IS 'Reason for login failure (invalid_password, account_locked, etc.)'; COMMENT ON COLUMN auth.login_attempts.attempted_at IS 'Timestamp when login was attempted'; COMMENT ON COLUMN auth.login_attempts.metadata IS 'Additional attempt metadata as JSON'; COMMENT ON COLUMN auth.login_attempts.created_at IS 'Timestamp when record was created';