CREATE TABLE IF NOT EXISTS user_registration_requests ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, username VARCHAR(50) NOT NULL, email VARCHAR(255), opaque_record BYTEA, opaque_credential_identifier BYTEA, opaque_ciphersuite VARCHAR(64), opaque_server_setup_version INTEGER, oauth2_provider_type SMALLINT, oauth2_provider_instance_name VARCHAR(64), oauth2_provider_issuer TEXT, oauth2_provider_user_id VARCHAR(255), oauth2_provider_username VARCHAR(255), oauth2_avatar_url TEXT, webauthn_credential_id BYTEA, webauthn_passkey JSONB, webauthn_credential_name VARCHAR(100), signup_method SMALLINT NOT NULL, status SMALLINT NOT NULL, requested_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, reviewed_at TIMESTAMPTZ, reviewed_by BIGINT REFERENCES users(id) ON DELETE RESTRICT, rejection_reason TEXT, CONSTRAINT user_registration_requests_email_not_empty CHECK (email IS NULL OR length(trim(email)) > 0), CONSTRAINT user_registration_requests_opaque_material_group_complete CHECK ( ( opaque_record IS NULL AND opaque_credential_identifier IS NULL AND opaque_ciphersuite IS NULL AND opaque_server_setup_version IS NULL ) OR ( opaque_record IS NOT NULL AND opaque_credential_identifier IS NOT NULL AND opaque_ciphersuite IS NOT NULL AND opaque_server_setup_version IS NOT NULL ) ), CONSTRAINT user_registration_requests_opaque_record_not_empty CHECK (opaque_record IS NULL OR length(opaque_record) > 0), CONSTRAINT user_registration_requests_opaque_identifier_not_empty CHECK (opaque_credential_identifier IS NULL OR length(opaque_credential_identifier) > 0), CONSTRAINT user_registration_requests_opaque_ciphersuite_not_empty CHECK (opaque_ciphersuite IS NULL OR length(trim(opaque_ciphersuite)) > 0), CONSTRAINT user_registration_requests_opaque_setup_version_positive CHECK ( opaque_server_setup_version IS NULL OR opaque_server_setup_version > 0 ), CONSTRAINT user_registration_requests_webauthn_name_not_empty CHECK ( webauthn_credential_name IS NULL OR length(trim(webauthn_credential_name)) > 0 ), CONSTRAINT user_registration_requests_webauthn_passkey_object CHECK ( webauthn_passkey IS NULL OR jsonb_typeof(webauthn_passkey) = 'object' ), CONSTRAINT user_registration_requests_webauthn_material_group_complete CHECK ( ( webauthn_credential_id IS NULL AND webauthn_passkey IS NULL AND webauthn_credential_name IS NULL ) OR ( webauthn_credential_id IS NOT NULL AND webauthn_passkey IS NOT NULL ) ), CONSTRAINT user_registration_requests_oauth2_material_group_complete CHECK ( ( oauth2_provider_type IS NULL AND oauth2_provider_instance_name IS NULL AND oauth2_provider_user_id IS NULL ) OR ( oauth2_provider_type IS NOT NULL AND oauth2_provider_instance_name IS NOT NULL AND oauth2_provider_user_id IS NOT NULL ) ), CONSTRAINT user_registration_requests_oauth2_instance_not_empty CHECK ( oauth2_provider_instance_name IS NULL OR length(trim(oauth2_provider_instance_name)) > 0 ), CONSTRAINT user_registration_requests_oauth2_user_id_not_empty CHECK ( oauth2_provider_user_id IS NULL OR length(trim(oauth2_provider_user_id)) > 0 ), CONSTRAINT user_registration_requests_auth_material_present CHECK ( opaque_record IS NOT NULL OR oauth2_provider_user_id IS NOT NULL OR webauthn_credential_id IS NOT NULL ), CONSTRAINT user_registration_requests_auth_material_exclusive CHECK ( ((opaque_record IS NOT NULL)::int + (oauth2_provider_user_id IS NOT NULL)::int + (webauthn_credential_id IS NOT NULL)::int) = 1 ), CONSTRAINT user_registration_requests_rejection_reason_not_empty CHECK ( rejection_reason IS NULL OR length(trim(rejection_reason)) > 0 ) ); CREATE INDEX IF NOT EXISTS idx_user_registration_requests_status_requested ON user_registration_requests(status, requested_at DESC); CREATE INDEX IF NOT EXISTS idx_user_registration_requests_pending_username ON user_registration_requests(LOWER(username)) WHERE reviewed_at IS NULL; CREATE INDEX IF NOT EXISTS idx_user_registration_requests_pending_email ON user_registration_requests(LOWER(email)) WHERE reviewed_at IS NULL AND email IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_user_registration_requests_pending_oauth2_identity ON user_registration_requests(oauth2_provider_instance_name, oauth2_provider_user_id) WHERE reviewed_at IS NULL AND oauth2_provider_instance_name IS NOT NULL AND oauth2_provider_user_id IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_user_registration_requests_pending_oauth2_type ON user_registration_requests(oauth2_provider_type) WHERE reviewed_at IS NULL AND oauth2_provider_type IS NOT NULL; CREATE UNIQUE INDEX IF NOT EXISTS idx_user_registration_requests_pending_webauthn_credential ON user_registration_requests(webauthn_credential_id) WHERE reviewed_at IS NULL AND webauthn_credential_id IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_user_registration_requests_reviewed_by ON user_registration_requests(reviewed_by) WHERE reviewed_by IS NOT NULL;