CREATE TABLE IF NOT EXISTS "performance_survey_employee_profiles" ( "id" TEXT PRIMARY KEY, "dingtalk_user_id" TEXT, "ding_email" TEXT, "job_number" TEXT, "flower_name" TEXT, "real_name" TEXT, "display_name" TEXT NOT NULL, "department_name" TEXT, "department_path" TEXT, "position_title" TEXT, "position_level" TEXT, "level_type" TEXT, "is_leadership" BOOLEAN NOT NULL DEFAULT FALSE, "manager_dingtalk_user_id" TEXT, "manager_job_number" TEXT, "manager_name" TEXT, "employment_status" TEXT, "work_place" TEXT, "source_payload" JSONB, "synced_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_employee_profiles_dingtalk_user_id_key" ON "performance_survey_employee_profiles" ("dingtalk_user_id"); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_employee_profiles_job_number_key" ON "performance_survey_employee_profiles" ("job_number"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_display_name_idx" ON "performance_survey_employee_profiles" ("display_name"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_ding_email_idx" ON "performance_survey_employee_profiles" ("ding_email"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_department_name_idx" ON "performance_survey_employee_profiles" ("department_name"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_position_level_idx" ON "performance_survey_employee_profiles" ("position_level"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_level_type_idx" ON "performance_survey_employee_profiles" ("level_type"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_is_leadership_idx" ON "performance_survey_employee_profiles" ("is_leadership"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_manager_dingtalk_user_id_idx" ON "performance_survey_employee_profiles" ("manager_dingtalk_user_id"); CREATE INDEX IF NOT EXISTS "performance_survey_employee_profiles_employment_status_idx" ON "performance_survey_employee_profiles" ("employment_status"); CREATE TABLE IF NOT EXISTS "performance_survey_department_profiles" ( "id" TEXT PRIMARY KEY, "name" TEXT NOT NULL, "parent_name" TEXT, "source_dept_id" TEXT, "sort_order" INTEGER NOT NULL DEFAULT 0, "employee_count" INTEGER NOT NULL DEFAULT 0, "synced_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_department_profiles_name_key" ON "performance_survey_department_profiles" ("name"); CREATE INDEX IF NOT EXISTS "performance_survey_department_profiles_parent_name_idx" ON "performance_survey_department_profiles" ("parent_name"); CREATE INDEX IF NOT EXISTS "performance_survey_department_profiles_source_dept_id_idx" ON "performance_survey_department_profiles" ("source_dept_id"); CREATE TABLE IF NOT EXISTS "performance_survey_templates" ( "id" TEXT PRIMARY KEY, "code" TEXT NOT NULL, "name" TEXT NOT NULL, "description" TEXT, "survey_type" TEXT NOT NULL DEFAULT 'person_period', "weight" DOUBLE PRECISION NOT NULL DEFAULT 1, "questions" JSONB NOT NULL, "score_bands" JSONB NOT NULL, "is_active" BOOLEAN NOT NULL DEFAULT TRUE, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_templates_code_key" ON "performance_survey_templates" ("code"); CREATE INDEX IF NOT EXISTS "performance_survey_templates_survey_type_idx" ON "performance_survey_templates" ("survey_type"); CREATE INDEX IF NOT EXISTS "performance_survey_templates_is_active_idx" ON "performance_survey_templates" ("is_active"); CREATE TABLE IF NOT EXISTS "performance_surveys" ( "id" TEXT PRIMARY KEY, "title" TEXT NOT NULL, "description" TEXT, "survey_kind" TEXT NOT NULL DEFAULT 'person_period', "template_code" TEXT NOT NULL, "template_snapshot" JSONB NOT NULL, "status" TEXT NOT NULL DEFAULT 'draft', "creator_user_id" TEXT NOT NULL, "creator_name" TEXT NOT NULL, "creator_employee_id" TEXT, "department_name" TEXT, "due_at" TIMESTAMP(3), "opened_at" TIMESTAMP(3), "closed_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS "performance_surveys_status_idx" ON "performance_surveys" ("status"); CREATE INDEX IF NOT EXISTS "performance_surveys_survey_kind_idx" ON "performance_surveys" ("survey_kind"); CREATE INDEX IF NOT EXISTS "performance_surveys_template_code_idx" ON "performance_surveys" ("template_code"); CREATE INDEX IF NOT EXISTS "performance_surveys_creator_user_id_idx" ON "performance_surveys" ("creator_user_id"); CREATE INDEX IF NOT EXISTS "performance_surveys_department_name_idx" ON "performance_surveys" ("department_name"); CREATE INDEX IF NOT EXISTS "performance_surveys_due_at_idx" ON "performance_surveys" ("due_at"); CREATE TABLE IF NOT EXISTS "performance_survey_targets" ( "id" TEXT PRIMARY KEY, "survey_id" TEXT NOT NULL, "target_type" TEXT NOT NULL DEFAULT 'employee', "employee_profile_id" TEXT, "target_name" TEXT NOT NULL, "target_snapshot" JSONB NOT NULL, "sort_order" INTEGER NOT NULL DEFAULT 0, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "performance_survey_targets_survey_id_fkey" FOREIGN KEY ("survey_id") REFERENCES "performance_surveys"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_targets_employee_profile_id_fkey" FOREIGN KEY ("employee_profile_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE SET NULL ON UPDATE CASCADE ); CREATE INDEX IF NOT EXISTS "performance_survey_targets_survey_id_idx" ON "performance_survey_targets" ("survey_id"); CREATE INDEX IF NOT EXISTS "performance_survey_targets_target_type_idx" ON "performance_survey_targets" ("target_type"); CREATE INDEX IF NOT EXISTS "performance_survey_targets_employee_profile_id_idx" ON "performance_survey_targets" ("employee_profile_id"); CREATE TABLE IF NOT EXISTS "performance_survey_assignments" ( "id" TEXT PRIMARY KEY, "survey_id" TEXT NOT NULL, "target_id" TEXT NOT NULL, "evaluator_employee_id" TEXT, "evaluator_user_id" TEXT, "evaluator_dingtalk_user_id" TEXT, "evaluator_key" TEXT NOT NULL, "evaluator_name" TEXT NOT NULL, "evaluator_snapshot" JSONB NOT NULL, "status" TEXT NOT NULL DEFAULT 'pending', "submitted_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "performance_survey_assignments_survey_id_fkey" FOREIGN KEY ("survey_id") REFERENCES "performance_surveys"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_assignments_target_id_fkey" FOREIGN KEY ("target_id") REFERENCES "performance_survey_targets"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_assignments_evaluator_employee_id_fkey" FOREIGN KEY ("evaluator_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE SET NULL ON UPDATE CASCADE ); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_assignment_target_evaluator_key" ON "performance_survey_assignments" ("target_id", "evaluator_key"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_survey_id_idx" ON "performance_survey_assignments" ("survey_id"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_target_id_idx" ON "performance_survey_assignments" ("target_id"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_evaluator_employee_id_idx" ON "performance_survey_assignments" ("evaluator_employee_id"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_evaluator_user_id_idx" ON "performance_survey_assignments" ("evaluator_user_id"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_evaluator_dingtalk_user_id_idx" ON "performance_survey_assignments" ("evaluator_dingtalk_user_id"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_evaluator_key_idx" ON "performance_survey_assignments" ("evaluator_key"); CREATE INDEX IF NOT EXISTS "performance_survey_assignments_status_idx" ON "performance_survey_assignments" ("status"); CREATE TABLE IF NOT EXISTS "performance_survey_responses" ( "id" TEXT PRIMARY KEY, "survey_id" TEXT NOT NULL, "target_id" TEXT NOT NULL, "assignment_id" TEXT NOT NULL, "respondent_user_id" TEXT NOT NULL, "respondent_employee_id" TEXT, "respondent_name" TEXT NOT NULL, "respondent_snapshot" JSONB NOT NULL, "scores" JSONB NOT NULL, "comment" TEXT, "total_score" DOUBLE PRECISION NOT NULL, "achievement_score" DOUBLE PRECISION NOT NULL, "kpi_score" DOUBLE PRECISION NOT NULL, "weighted_score" DOUBLE PRECISION NOT NULL, "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "performance_survey_responses_survey_id_fkey" FOREIGN KEY ("survey_id") REFERENCES "performance_surveys"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_responses_target_id_fkey" FOREIGN KEY ("target_id") REFERENCES "performance_survey_targets"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_responses_assignment_id_fkey" FOREIGN KEY ("assignment_id") REFERENCES "performance_survey_assignments"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_responses_respondent_employee_id_fkey" FOREIGN KEY ("respondent_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE SET NULL ON UPDATE CASCADE ); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_responses_assignment_id_key" ON "performance_survey_responses" ("assignment_id"); CREATE INDEX IF NOT EXISTS "performance_survey_responses_survey_id_idx" ON "performance_survey_responses" ("survey_id"); CREATE INDEX IF NOT EXISTS "performance_survey_responses_target_id_idx" ON "performance_survey_responses" ("target_id"); CREATE INDEX IF NOT EXISTS "performance_survey_responses_respondent_user_id_idx" ON "performance_survey_responses" ("respondent_user_id"); CREATE INDEX IF NOT EXISTS "performance_survey_responses_respondent_employee_id_idx" ON "performance_survey_responses" ("respondent_employee_id"); CREATE INDEX IF NOT EXISTS "performance_survey_responses_created_at_idx" ON "performance_survey_responses" ("created_at"); CREATE TABLE IF NOT EXISTS "performance_survey_notifications" ( "id" TEXT PRIMARY KEY, "survey_id" TEXT, "target_id" TEXT, "assignment_id" TEXT, "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), "last_status_code" INTEGER, "last_response_body" TEXT, "last_error" TEXT, "provider_message_id" TEXT, "sent_at" TIMESTAMP(3), "completed_at" TIMESTAMP(3), "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT "performance_survey_notifications_survey_id_fkey" FOREIGN KEY ("survey_id") REFERENCES "performance_surveys"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_notifications_target_id_fkey" FOREIGN KEY ("target_id") REFERENCES "performance_survey_targets"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_notifications_assignment_id_fkey" FOREIGN KEY ("assignment_id") REFERENCES "performance_survey_assignments"("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "performance_survey_notifications_recipient_employee_id_fkey" FOREIGN KEY ("recipient_employee_id") REFERENCES "performance_survey_employee_profiles"("id") ON DELETE SET NULL ON UPDATE CASCADE ); CREATE UNIQUE INDEX IF NOT EXISTS "performance_survey_notification_event_key" ON "performance_survey_notifications" ("event_type", "business_key"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_survey_id_idx" ON "performance_survey_notifications" ("survey_id"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_target_id_idx" ON "performance_survey_notifications" ("target_id"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_assignment_id_idx" ON "performance_survey_notifications" ("assignment_id"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_recipient_employee_id_idx" ON "performance_survey_notifications" ("recipient_employee_id"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_recipient_user_id_idx" ON "performance_survey_notifications" ("recipient_user_id"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_dingtalk_user_id_idx" ON "performance_survey_notifications" ("dingtalk_user_id"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_status_next_retry_idx" ON "performance_survey_notifications" ("status", "next_retry_at"); CREATE INDEX IF NOT EXISTS "performance_survey_notifications_created_at_idx" ON "performance_survey_notifications" ("created_at");