-- AlterTable ALTER TABLE `consents` ADD COLUMN `beneficiary_id` BIGINT UNSIGNED NULL, MODIFY `user_id` BIGINT UNSIGNED NULL, MODIFY `consent_type` ENUM('SERVICE_APPLICATION', 'BENEFICIARY_GUARDIAN') NOT NULL, MODIFY `granted_by` ENUM('SELF', 'APPLICANT', 'GUARDIAN') NOT NULL; -- AlterTable ALTER TABLE `service_applications` ADD COLUMN `beneficiary_id` BIGINT UNSIGNED NULL; -- CreateTable CREATE TABLE `beneficiary_profiles` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `display_name_encrypted` VARCHAR(512) NOT NULL, `display_name_hash` CHAR(64) NOT NULL, `gender` ENUM('FEMALE', 'MALE', 'OTHER', 'UNDISCLOSED') NULL, `birth_year` SMALLINT UNSIGNED NULL, `mobile_encrypted` VARCHAR(512) NULL, `mobile_hash` CHAR(64) NULL, `region_code` VARCHAR(100) NOT NULL, `address_detail_encrypted` VARCHAR(1024) NULL, `primary_category` ENUM('OLD_AGE', 'WOMEN', 'CHILD', 'DISABILITY', 'LIFE_DIFFICULTY', 'OTHER') NOT NULL, `key_care_flag` BOOLEAN NOT NULL DEFAULT false, `is_minor` BOOLEAN NOT NULL DEFAULT false, `status` ENUM('ACTIVE', 'INACTIVE', 'ARCHIVED') NOT NULL DEFAULT 'ACTIVE', `notes_encrypted` TEXT NULL, `created_by` BIGINT UNSIGNED NOT NULL, `updated_by` BIGINT UNSIGNED NOT NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `updated_at` DATETIME(3) NOT NULL, UNIQUE INDEX `beneficiary_profiles_public_id_key`(`public_id`), INDEX `beneficiary_profiles_display_name_hash_idx`(`display_name_hash`), INDEX `beneficiary_profiles_mobile_hash_idx`(`mobile_hash`), INDEX `beneficiary_profiles_category_status_created_at_idx`(`primary_category`, `status`, `created_at`), INDEX `beneficiary_profiles_key_care_status_created_at_idx`(`key_care_flag`, `status`, `created_at`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `beneficiary_contacts` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `beneficiary_id` BIGINT UNSIGNED NOT NULL, `name_encrypted` VARCHAR(512) NOT NULL, `relation` VARCHAR(50) NOT NULL, `mobile_encrypted` VARCHAR(512) NOT NULL, `mobile_hash` CHAR(64) NOT NULL, `is_guardian` BOOLEAN NOT NULL DEFAULT false, `is_emergency_contact` BOOLEAN NOT NULL DEFAULT false, `consent_record_id` BIGINT UNSIGNED NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `updated_at` DATETIME(3) NOT NULL, `removed_at` DATETIME(3) NULL, UNIQUE INDEX `beneficiary_contacts_public_id_key`(`public_id`), UNIQUE INDEX `beneficiary_contacts_consent_record_id_key`(`consent_record_id`), INDEX `beneficiary_contacts_beneficiary_active_guardian_idx`(`beneficiary_id`, `removed_at`, `is_guardian`), INDEX `beneficiary_contacts_mobile_hash_idx`(`mobile_hash`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `tags` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `code` VARCHAR(64) NOT NULL, `name` VARCHAR(50) NOT NULL, `description` VARCHAR(255) NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), UNIQUE INDEX `tags_public_id_key`(`public_id`), UNIQUE INDEX `tags_code_key`(`code`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `beneficiary_tags` ( `beneficiary_id` BIGINT UNSIGNED NOT NULL, `tag_id` BIGINT UNSIGNED NOT NULL, `assigned_by` BIGINT UNSIGNED NOT NULL, `assigned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), INDEX `beneficiary_tags_tag_id_idx`(`tag_id`), PRIMARY KEY (`beneficiary_id`, `tag_id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `service_cases` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `case_no` VARCHAR(32) NOT NULL, `application_id` BIGINT UNSIGNED NOT NULL, `accept_request_id` CHAR(36) NOT NULL, `accept_request_fingerprint` CHAR(64) NOT NULL, `beneficiary_id` BIGINT UNSIGNED NOT NULL, `owner_staff_id` BIGINT UNSIGNED NOT NULL, `category` ENUM('OLD_AGE', 'WOMEN', 'CHILD', 'DISABILITY', 'LIFE_DIFFICULTY', 'OTHER') NOT NULL, `priority` ENUM('LOW', 'NORMAL', 'HIGH', 'URGENT') NOT NULL DEFAULT 'NORMAL', `status` ENUM('ASSIGNED', 'IN_SERVICE', 'SERVICE_COMPLETED', 'SUSPENDED', 'CANCELLED') NOT NULL DEFAULT 'ASSIGNED', `planned_start_at` DATETIME(3) NULL, `planned_end_at` DATETIME(3) NULL, `service_location_encrypted` VARCHAR(1024) NULL, `summary_encrypted` TEXT NOT NULL, `result_summary_encrypted` TEXT NULL, `follow_up_plan_encrypted` TEXT NULL, `completed_at` DATETIME(3) NULL, `created_by` BIGINT UNSIGNED NOT NULL, `updated_by` BIGINT UNSIGNED NOT NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `updated_at` DATETIME(3) NOT NULL, UNIQUE INDEX `service_cases_public_id_key`(`public_id`), UNIQUE INDEX `service_cases_case_no_key`(`case_no`), UNIQUE INDEX `service_cases_application_id_key`(`application_id`), INDEX `service_cases_owner_status_planned_idx`(`owner_staff_id`, `status`, `planned_start_at`), INDEX `service_cases_beneficiary_created_at_idx`(`beneficiary_id`, `created_at`), INDEX `service_cases_status_created_at_idx`(`status`, `created_at`), UNIQUE INDEX `service_cases_creator_accept_request_key`(`created_by`, `accept_request_id`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `case_assignees` ( `case_id` BIGINT UNSIGNED NOT NULL, `user_id` BIGINT UNSIGNED NOT NULL, `assignee_type` ENUM('STAFF', 'VOLUNTEER') NOT NULL, `role` ENUM('OWNER', 'COLLABORATOR') NOT NULL, `assigned_by` BIGINT UNSIGNED NOT NULL, `assigned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `removed_at` DATETIME(3) NULL, INDEX `case_assignees_user_active_assigned_idx`(`user_id`, `removed_at`, `assigned_at`), PRIMARY KEY (`case_id`, `user_id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `service_case_status_history` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `case_id` BIGINT UNSIGNED NOT NULL, `from_status` ENUM('ASSIGNED', 'IN_SERVICE', 'SERVICE_COMPLETED', 'SUSPENDED', 'CANCELLED') NULL, `to_status` ENUM('ASSIGNED', 'IN_SERVICE', 'SERVICE_COMPLETED', 'SUSPENDED', 'CANCELLED') NOT NULL, `operator_user_id` BIGINT UNSIGNED NOT NULL, `reason_code` VARCHAR(100) NOT NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), INDEX `case_status_history_case_created_at_idx`(`case_id`, `created_at`), INDEX `case_status_history_operator_created_at_idx`(`operator_user_id`, `created_at`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `service_records` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `case_id` BIGINT UNSIGNED NOT NULL, `beneficiary_id` BIGINT UNSIGNED NOT NULL, `client_request_id` CHAR(36) NOT NULL, `request_fingerprint` CHAR(64) NOT NULL, `service_start_at` DATETIME(3) NOT NULL, `service_end_at` DATETIME(3) NULL, `service_type` ENUM('HOME_VISIT', 'PHONE_CONTACT', 'ESCORT', 'MATERIAL_SUPPORT', 'ACTIVITY', 'OTHER') NOT NULL, `content_encrypted` TEXT NOT NULL, `result_encrypted` TEXT NOT NULL, `follow_up_suggestion_encrypted` TEXT NULL, `beneficiary_confirm_status` ENUM('NOT_REQUESTED', 'CONFIRMED', 'PARTIALLY_CONFIRMED', 'DISPUTED') NOT NULL DEFAULT 'NOT_REQUESTED', `created_by` BIGINT UNSIGNED NOT NULL, `updated_by` BIGINT UNSIGNED NOT NULL, `revision` INTEGER UNSIGNED NOT NULL DEFAULT 1, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `updated_at` DATETIME(3) NOT NULL, UNIQUE INDEX `service_records_public_id_key`(`public_id`), INDEX `service_records_case_start_at_idx`(`case_id`, `service_start_at`), INDEX `service_records_beneficiary_start_at_idx`(`beneficiary_id`, `service_start_at`), UNIQUE INDEX `service_records_creator_client_request_key`(`created_by`, `client_request_id`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `service_record_revisions` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `service_record_id` BIGINT UNSIGNED NOT NULL, `revision` INTEGER UNSIGNED NOT NULL, `service_start_at` DATETIME(3) NOT NULL, `service_end_at` DATETIME(3) NULL, `service_type` ENUM('HOME_VISIT', 'PHONE_CONTACT', 'ESCORT', 'MATERIAL_SUPPORT', 'ACTIVITY', 'OTHER') NOT NULL, `content_encrypted` TEXT NOT NULL, `result_encrypted` TEXT NOT NULL, `follow_up_suggestion_encrypted` TEXT NULL, `beneficiary_confirm_status` ENUM('NOT_REQUESTED', 'CONFIRMED', 'PARTIALLY_CONFIRMED', 'DISPUTED') NOT NULL, `revised_by` BIGINT UNSIGNED NOT NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), INDEX `service_record_revisions_reviser_created_at_idx`(`revised_by`, `created_at`), UNIQUE INDEX `service_record_revisions_record_revision_key`(`service_record_id`, `revision`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `files` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `case_id` BIGINT UNSIGNED NOT NULL, `client_request_id` CHAR(36) NOT NULL, `request_fingerprint` CHAR(64) NOT NULL, `storage_provider` VARCHAR(50) NOT NULL, `bucket` VARCHAR(255) NOT NULL, `object_key` VARCHAR(512) NOT NULL, `original_filename_encrypted` VARCHAR(1024) NOT NULL, `mime_type` VARCHAR(100) NOT NULL, `size` BIGINT UNSIGNED NOT NULL, `sha256` CHAR(64) NULL, `business_type` ENUM('SERVICE_RECORD') NOT NULL, `uploader_user_id` BIGINT UNSIGNED NOT NULL, `status` ENUM('UPLOAD_PENDING', 'AVAILABLE', 'QUARANTINED', 'DELETED') NOT NULL DEFAULT 'UPLOAD_PENDING', `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `updated_at` DATETIME(3) NOT NULL, UNIQUE INDEX `files_public_id_key`(`public_id`), UNIQUE INDEX `files_object_key_key`(`object_key`), INDEX `files_case_status_created_at_idx`(`case_id`, `status`, `created_at`), INDEX `files_uploader_status_created_at_idx`(`uploader_user_id`, `status`, `created_at`), UNIQUE INDEX `files_uploader_client_request_key`(`uploader_user_id`, `client_request_id`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateTable CREATE TABLE `service_record_files` ( `service_record_id` BIGINT UNSIGNED NOT NULL, `file_id` BIGINT UNSIGNED NOT NULL, `attached_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), INDEX `service_record_files_file_id_idx`(`file_id`), PRIMARY KEY (`service_record_id`, `file_id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- CreateIndex CREATE INDEX `consents_beneficiary_type_granted_at_idx` ON `consents`(`beneficiary_id`, `consent_type`, `granted_at`); -- CreateIndex CREATE INDEX `service_applications_beneficiary_submitted_at_idx` ON `service_applications`(`beneficiary_id`, `submitted_at`); -- AddForeignKey ALTER TABLE `consents` ADD CONSTRAINT `consents_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_applications` ADD CONSTRAINT `service_applications_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_profiles` ADD CONSTRAINT `beneficiary_profiles_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_profiles` ADD CONSTRAINT `beneficiary_profiles_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_contacts` ADD CONSTRAINT `beneficiary_contacts_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_contacts` ADD CONSTRAINT `beneficiary_contacts_consent_record_id_fkey` FOREIGN KEY (`consent_record_id`) REFERENCES `consents`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_tags` ADD CONSTRAINT `beneficiary_tags_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_tags` ADD CONSTRAINT `beneficiary_tags_tag_id_fkey` FOREIGN KEY (`tag_id`) REFERENCES `tags`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `beneficiary_tags` ADD CONSTRAINT `beneficiary_tags_assigned_by_fkey` FOREIGN KEY (`assigned_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_cases` ADD CONSTRAINT `service_cases_application_id_fkey` FOREIGN KEY (`application_id`) REFERENCES `service_applications`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_cases` ADD CONSTRAINT `service_cases_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_cases` ADD CONSTRAINT `service_cases_owner_staff_id_fkey` FOREIGN KEY (`owner_staff_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_cases` ADD CONSTRAINT `service_cases_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_cases` ADD CONSTRAINT `service_cases_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `case_assignees` ADD CONSTRAINT `case_assignees_case_id_fkey` FOREIGN KEY (`case_id`) REFERENCES `service_cases`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `case_assignees` ADD CONSTRAINT `case_assignees_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `case_assignees` ADD CONSTRAINT `case_assignees_assigned_by_fkey` FOREIGN KEY (`assigned_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_case_status_history` ADD CONSTRAINT `service_case_status_history_case_id_fkey` FOREIGN KEY (`case_id`) REFERENCES `service_cases`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_case_status_history` ADD CONSTRAINT `service_case_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_records` ADD CONSTRAINT `service_records_case_id_fkey` FOREIGN KEY (`case_id`) REFERENCES `service_cases`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_records` ADD CONSTRAINT `service_records_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_records` ADD CONSTRAINT `service_records_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_records` ADD CONSTRAINT `service_records_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_record_revisions` ADD CONSTRAINT `service_record_revisions_service_record_id_fkey` FOREIGN KEY (`service_record_id`) REFERENCES `service_records`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_record_revisions` ADD CONSTRAINT `service_record_revisions_revised_by_fkey` FOREIGN KEY (`revised_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `files` ADD CONSTRAINT `files_case_id_fkey` FOREIGN KEY (`case_id`) REFERENCES `service_cases`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `files` ADD CONSTRAINT `files_uploader_user_id_fkey` FOREIGN KEY (`uploader_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_record_files` ADD CONSTRAINT `service_record_files_service_record_id_fkey` FOREIGN KEY (`service_record_id`) REFERENCES `service_records`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- AddForeignKey ALTER TABLE `service_record_files` ADD CONSTRAINT `service_record_files_file_id_fkey` FOREIGN KEY (`file_id`) REFERENCES `files`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; -- Phase 3 fixed service tags. Product operations may request additions in a later reviewed migration. INSERT INTO `tags` (`public_id`, `code`, `name`, `description`) VALUES ('4ed0570a-6051-4a29-9fd2-3c3d45dc52a7', 'ALONE_LIVING', '独居', '独居服务对象'), ('044792f8-2982-4890-a8d4-cc6d01ac78c4', 'ADVANCED_AGE', '高龄', '高龄关爱对象'), ('dc02d25f-5a4c-4f31-9ec8-c5a5f3904e6a', 'MOBILITY_LIMITED', '行动不便', '日常行动存在困难'), ('75292f5f-72e0-4a19-9e9b-5fd7b455956a', 'REGULAR_VISIT', '定期探访', '需要定期探访关爱'), ('94e041fe-0745-4f50-a3c6-b0cad8e286b5', 'CHILD_IN_DIFFICULTY', '困境儿童', '需要加强保护的儿童服务对象'), ('76e280f4-8f6f-4e06-9570-ce998c8c38c4', 'KEY_CARE', '重点关爱', '由工作人员评估的重点关爱对象'); INSERT INTO `permissions` (`code`, `name`, `description`) VALUES ('applications:manage', '处理服务申请', '按状态机联系、评估并受理服务申请'), ('beneficiaries:read', '查看服务对象', '按授权范围查看服务对象档案'), ('beneficiaries:manage', '管理服务对象', '建档并维护服务对象、联系人和标签'), ('cases:read', '查看服务工单', '按负责或管理范围查看服务工单'), ('cases:manage', '管理服务工单', '按状态机推进负责的服务工单'), ('cases:assign', '分配服务工单', '分配负责人和协作人员'), ('assigned_cases:read', '查看已分配工单', '查看本人被分配工单的最小必要信息'), ('service_records:write', '填写服务记录', '为本人被分配工单新增或修订服务记录'), ('files:write', '管理服务附件', '上传、确认和读取授权范围内的私有服务附件'); INSERT INTO `role_permissions` (`role_id`, `permission_id`) SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.code IN ('STAFF', 'PROJECT_MANAGER', 'ADMIN', 'SUPER_ADMIN') AND p.code IN ('applications:manage', 'beneficiaries:read', 'beneficiaries:manage', 'cases:read', 'cases:manage', 'cases:assign', 'assigned_cases:read', 'service_records:write', 'files:write'); INSERT INTO `role_permissions` (`role_id`, `permission_id`) SELECT r.id, p.id FROM roles r CROSS JOIN permissions p WHERE r.code = 'VOLUNTEER' AND p.code IN ('assigned_cases:read', 'service_records:write', 'files:write');