-- Phase 2 service application baseline. -- L3 fields are encrypted by the application before persistence. CREATE TABLE `consents` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `user_id` BIGINT UNSIGNED NOT NULL, `consent_type` ENUM('SERVICE_APPLICATION') NOT NULL, `version` VARCHAR(32) NOT NULL, `granted_by` ENUM('SELF', 'APPLICANT') NOT NULL, `granted_at` DATETIME(3) NOT NULL, `revoked_at` DATETIME(3) NULL, `evidence_json` JSON NULL, `ip_hash` CHAR(64) NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), UNIQUE INDEX `consents_public_id_key`(`public_id`), INDEX `consents_user_type_granted_at_idx`(`user_id`, `consent_type`, `granted_at`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE TABLE `service_applications` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `public_id` CHAR(36) NOT NULL, `application_no` VARCHAR(32) NOT NULL, `applicant_user_id` BIGINT UNSIGNED NOT NULL, `consent_id` BIGINT UNSIGNED NOT NULL, `client_request_id` CHAR(36) NOT NULL, `request_fingerprint` CHAR(64) NOT NULL, `apply_mode` ENUM('SELF', 'FAMILY', 'COMMUNITY', 'VOLUNTEER', 'OTHER') NOT NULL, `service_category` ENUM('OLD_AGE', 'WOMEN', 'CHILD', 'DISABILITY', 'LIFE_DIFFICULTY', 'OTHER') NOT NULL, `beneficiary_name_encrypted` VARCHAR(512) NOT NULL, `contact_mobile_encrypted` VARCHAR(512) NOT NULL, `contact_mobile_hash` CHAR(64) NOT NULL, `region_code` VARCHAR(100) NOT NULL, `description_encrypted` TEXT NOT NULL, `preferred_contact_time` VARCHAR(100) NULL, `needs_home_visit` BOOLEAN NULL, `mobility_difficulty` BOOLEAN NULL, `status` ENUM('SUBMITTED', 'PENDING_CONTACT', 'ASSESSING', 'REJECTED', 'OUT_OF_SCOPE', 'REFERRED', 'ACCEPTED', 'SERVICE_PLANNED', 'IN_SERVICE', 'SERVICE_COMPLETED', 'FOLLOW_UP_PENDING', 'CLOSED', 'CANCELLED', 'SUSPENDED') NOT NULL DEFAULT 'SUBMITTED', `source` ENUM('WECHAT_MINIPROGRAM', 'ADMIN') NOT NULL DEFAULT 'WECHAT_MINIPROGRAM', `submitted_at` DATETIME(3) NOT NULL, `accepted_at` DATETIME(3) NULL, `closed_at` DATETIME(3) NULL, `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), `updated_at` DATETIME(3) NOT NULL, UNIQUE INDEX `service_applications_public_id_key`(`public_id`), UNIQUE INDEX `service_applications_application_no_key`(`application_no`), UNIQUE INDEX `service_applications_consent_id_key`(`consent_id`), UNIQUE INDEX `service_applications_applicant_client_request_key`(`applicant_user_id`, `client_request_id`), INDEX `service_applications_applicant_submitted_at_idx`(`applicant_user_id`, `submitted_at`), INDEX `service_applications_status_submitted_at_idx`(`status`, `submitted_at`), INDEX `service_applications_category_submitted_at_idx`(`service_category`, `submitted_at`), INDEX `service_applications_contact_mobile_hash_idx`(`contact_mobile_hash`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE TABLE `service_application_status_history` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `application_id` BIGINT UNSIGNED NOT NULL, `from_status` ENUM('SUBMITTED', 'PENDING_CONTACT', 'ASSESSING', 'REJECTED', 'OUT_OF_SCOPE', 'REFERRED', 'ACCEPTED', 'SERVICE_PLANNED', 'IN_SERVICE', 'SERVICE_COMPLETED', 'FOLLOW_UP_PENDING', 'CLOSED', 'CANCELLED', 'SUSPENDED') NULL, `to_status` ENUM('SUBMITTED', 'PENDING_CONTACT', 'ASSESSING', 'REJECTED', 'OUT_OF_SCOPE', 'REFERRED', 'ACCEPTED', 'SERVICE_PLANNED', 'IN_SERVICE', 'SERVICE_COMPLETED', 'FOLLOW_UP_PENDING', 'CLOSED', 'CANCELLED', 'SUSPENDED') 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 `application_status_history_application_created_at_idx`(`application_id`, `created_at`), INDEX `application_status_history_operator_created_at_idx`(`operator_user_id`, `created_at`), PRIMARY KEY (`id`) ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE `consents` ADD CONSTRAINT `consents_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `service_applications` ADD CONSTRAINT `service_applications_applicant_user_id_fkey` FOREIGN KEY (`applicant_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `service_applications` ADD CONSTRAINT `service_applications_consent_id_fkey` FOREIGN KEY (`consent_id`) REFERENCES `consents`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `service_application_status_history` ADD CONSTRAINT `service_application_status_history_application_id_fkey` FOREIGN KEY (`application_id`) REFERENCES `service_applications`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; ALTER TABLE `service_application_status_history` ADD CONSTRAINT `service_application_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE; INSERT INTO `permissions` (`code`, `name`, `description`) VALUES ('applications:read', '查看服务申请', '按授权范围查看服务申请列表和详情'); 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 = 'applications:read';