CREATE TABLE IF NOT EXISTS room_creation_requests ( id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, requested_by BIGINT NOT NULL REFERENCES users(id) ON DELETE RESTRICT, name TEXT NOT NULL, description TEXT NOT NULL DEFAULT '', category_id BIGINT NULL REFERENCES room_categories(id) ON DELETE SET NULL, settings_payload JSONB, opaque_password_record BYTEA, opaque_password_credential_identifier BYTEA, opaque_password_ciphersuite VARCHAR(64), opaque_password_server_setup_version INTEGER, 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 room_creation_requests_opaque_password_metadata_required CHECK ( ( opaque_password_record IS NULL AND opaque_password_credential_identifier IS NULL AND opaque_password_ciphersuite IS NULL AND opaque_password_server_setup_version IS NULL ) OR ( opaque_password_record IS NOT NULL AND opaque_password_credential_identifier IS NOT NULL AND opaque_password_ciphersuite IS NOT NULL AND opaque_password_server_setup_version IS NOT NULL ) ), CONSTRAINT room_creation_requests_opaque_password_record_not_empty CHECK (opaque_password_record IS NULL OR length(opaque_password_record) > 0), CONSTRAINT room_creation_requests_opaque_password_identifier_not_empty CHECK ( opaque_password_credential_identifier IS NULL OR length(opaque_password_credential_identifier) > 0 ), CONSTRAINT room_creation_requests_opaque_password_ciphersuite_not_empty CHECK ( opaque_password_ciphersuite IS NULL OR length(trim(opaque_password_ciphersuite)) > 0 ), CONSTRAINT room_creation_requests_opaque_password_setup_version_positive CHECK ( opaque_password_server_setup_version IS NULL OR opaque_password_server_setup_version > 0 ), CONSTRAINT room_creation_requests_settings_payload_object CHECK ( settings_payload IS NULL OR jsonb_typeof(settings_payload) = 'object' ), CONSTRAINT room_creation_requests_rejection_reason_not_empty CHECK ( rejection_reason IS NULL OR length(trim(rejection_reason)) > 0 ) ); CREATE TABLE IF NOT EXISTS room_creation_request_labels ( request_id BIGINT NOT NULL REFERENCES room_creation_requests(id) ON DELETE CASCADE, label_id BIGINT NOT NULL REFERENCES room_labels(id) ON DELETE RESTRICT, PRIMARY KEY (request_id, label_id) ); CREATE INDEX IF NOT EXISTS idx_room_creation_requests_requested_by ON room_creation_requests(requested_by, requested_at DESC); CREATE INDEX IF NOT EXISTS idx_room_creation_requests_status_requested ON room_creation_requests(status, requested_at DESC); CREATE INDEX IF NOT EXISTS idx_room_creation_requests_reviewed_by ON room_creation_requests(reviewed_by) WHERE reviewed_by IS NOT NULL; CREATE INDEX IF NOT EXISTS idx_room_creation_request_labels_label_request ON room_creation_request_labels(label_id, request_id);