CREATE TABLE IF NOT EXISTS "work_review_projects" ( "id" TEXT NOT NULL, "title" TEXT NOT NULL, "description" TEXT, "work_date" DATE NOT NULL, "submitter_user_id" TEXT NOT NULL, "submitter_employee_id" TEXT NOT NULL, "submitter_name" TEXT NOT NULL, "submitter_snapshot" JSONB NOT NULL, "manager_employee_id" TEXT NOT NULL, "manager_user_id" TEXT, "manager_dingtalk_user_id" TEXT, "manager_name" TEXT NOT NULL, "final_reviewer_employee_id" TEXT NOT NULL, "final_reviewer_user_id" TEXT, "final_reviewer_dingtalk_user_id" TEXT, "final_reviewer_name" TEXT NOT NULL, "status" TEXT NOT NULL DEFAULT 'pending_review', "latest_version" INTEGER NOT NULL DEFAULT 1, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "work_review_projects_pkey" PRIMARY KEY ("id"), CONSTRAINT "work_review_projects_status_check" CHECK ("status" IN ('pending_review', 'revision_required', 'approved')), CONSTRAINT "work_review_projects_latest_version_check" CHECK ("latest_version" > 0), CONSTRAINT "work_review_projects_submitter_employee_id_fkey" FOREIGN KEY ("submitter_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT "work_review_projects_manager_employee_id_fkey" FOREIGN KEY ("manager_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT "work_review_projects_final_reviewer_employee_id_fkey" FOREIGN KEY ("final_reviewer_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE RESTRICT ON UPDATE CASCADE ); CREATE TABLE IF NOT EXISTS "work_review_versions" ( "id" TEXT NOT NULL, "project_id" TEXT NOT NULL, "version" INTEGER NOT NULL, "submission_note" TEXT, "image_urls" JSONB NOT NULL, "status" TEXT NOT NULL DEFAULT 'pending_review', "submitted_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "completed_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "work_review_versions_pkey" PRIMARY KEY ("id"), CONSTRAINT "work_review_versions_version_check" CHECK ("version" > 0), CONSTRAINT "work_review_versions_status_check" CHECK ("status" IN ('pending_review', 'revision_required', 'approved')), CONSTRAINT "work_review_versions_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "work_review_projects"("id") ON DELETE CASCADE ON UPDATE CASCADE ); CREATE TABLE IF NOT EXISTS "work_review_reviews" ( "id" TEXT NOT NULL, "version_id" TEXT NOT NULL, "reviewer_role" TEXT NOT NULL, "reviewer_employee_id" TEXT NOT NULL, "reviewer_user_id" TEXT, "reviewer_name" TEXT NOT NULL, "reviewer_snapshot" JSONB NOT NULL, "decision" TEXT NOT NULL, "image_comments" JSONB NOT NULL, "general_comment" TEXT, "reviewed_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "work_review_reviews_pkey" PRIMARY KEY ("id"), CONSTRAINT "work_review_reviews_role_check" CHECK ("reviewer_role" IN ('manager', 'final_reviewer')), CONSTRAINT "work_review_reviews_decision_check" CHECK ("decision" IN ('revision_required', 'approved')), CONSTRAINT "work_review_reviews_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "work_review_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "work_review_reviews_reviewer_employee_id_fkey" FOREIGN KEY ("reviewer_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE RESTRICT ON UPDATE CASCADE ); CREATE TABLE IF NOT EXISTS "work_review_notifications" ( "id" TEXT NOT NULL, "project_id" TEXT NOT NULL, "version_id" TEXT NOT NULL, "recipient_employee_id" TEXT, "recipient_user_id" TEXT, "dingtalk_user_id" TEXT, "recipient_name" TEXT NOT NULL, "event_type" TEXT NOT NULL, "business_key" TEXT NOT NULL, "title" TEXT NOT NULL, "content" TEXT NOT NULL, "action_url" TEXT, "status" TEXT NOT NULL DEFAULT 'pending', "attempt_count" INTEGER NOT NULL DEFAULT 0, "max_attempts" INTEGER NOT NULL DEFAULT 5, "next_retry_at" TIMESTAMP(3), "provider_type" TEXT NOT NULL DEFAULT 'work_notice', "provider_message_id" TEXT, "last_error" TEXT, "sent_at" TIMESTAMP(3), "completed_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL, CONSTRAINT "work_review_notifications_pkey" PRIMARY KEY ("id"), CONSTRAINT "work_review_notifications_status_check" CHECK ("status" IN ('pending', 'processing', 'retrying', 'succeeded', 'exhausted', 'skipped')), CONSTRAINT "work_review_notifications_project_id_fkey" FOREIGN KEY ("project_id") REFERENCES "work_review_projects"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "work_review_notifications_version_id_fkey" FOREIGN KEY ("version_id") REFERENCES "work_review_versions"("id") ON DELETE CASCADE ON UPDATE CASCADE ); CREATE UNIQUE INDEX IF NOT EXISTS "work_review_versions_project_version_key" ON "work_review_versions"("project_id", "version"); CREATE UNIQUE INDEX IF NOT EXISTS "work_review_reviews_version_role_key" ON "work_review_reviews"("version_id", "reviewer_role"); CREATE UNIQUE INDEX IF NOT EXISTS "work_review_notifications_event_key" ON "work_review_notifications"("event_type", "business_key"); CREATE INDEX IF NOT EXISTS "work_review_projects_submitter_date_idx" ON "work_review_projects"("submitter_user_id", "work_date"); CREATE INDEX IF NOT EXISTS "work_review_projects_submitter_employee_date_idx" ON "work_review_projects"("submitter_employee_id", "work_date"); CREATE INDEX IF NOT EXISTS "work_review_projects_manager_status_idx" ON "work_review_projects"("manager_employee_id", "status"); CREATE INDEX IF NOT EXISTS "work_review_projects_final_reviewer_status_idx" ON "work_review_projects"("final_reviewer_employee_id", "status"); CREATE INDEX IF NOT EXISTS "work_review_projects_status_date_idx" ON "work_review_projects"("status", "work_date"); CREATE INDEX IF NOT EXISTS "work_review_projects_updated_at_idx" ON "work_review_projects"("updated_at"); CREATE INDEX IF NOT EXISTS "work_review_versions_project_submitted_idx" ON "work_review_versions"("project_id", "submitted_at"); CREATE INDEX IF NOT EXISTS "work_review_versions_status_submitted_idx" ON "work_review_versions"("status", "submitted_at"); CREATE INDEX IF NOT EXISTS "work_review_reviews_reviewer_reviewed_idx" ON "work_review_reviews"("reviewer_employee_id", "reviewed_at"); CREATE INDEX IF NOT EXISTS "work_review_reviews_decision_idx" ON "work_review_reviews"("decision"); CREATE INDEX IF NOT EXISTS "work_review_notifications_project_created_idx" ON "work_review_notifications"("project_id", "created_at"); CREATE INDEX IF NOT EXISTS "work_review_notifications_version_idx" ON "work_review_notifications"("version_id"); CREATE INDEX IF NOT EXISTS "work_review_notifications_recipient_employee_idx" ON "work_review_notifications"("recipient_employee_id"); CREATE INDEX IF NOT EXISTS "work_review_notifications_recipient_user_idx" ON "work_review_notifications"("recipient_user_id"); CREATE INDEX IF NOT EXISTS "work_review_notifications_dingtalk_user_idx" ON "work_review_notifications"("dingtalk_user_id"); CREATE INDEX IF NOT EXISTS "work_review_notifications_status_retry_idx" ON "work_review_notifications"("status", "next_retry_at");