feat: complete V1 phases 0-7
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
-- Phase 1 authentication and authorization baseline.
|
||||
-- Internal BIGINT identifiers are never exposed through public APIs.
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`status` ENUM('ACTIVE', 'SUSPENDED', 'DISABLED') NOT NULL DEFAULT 'ACTIVE',
|
||||
`user_type` ENUM('PUBLIC', 'STAFF') NOT NULL,
|
||||
`mobile_encrypted` VARCHAR(512) NULL,
|
||||
`mobile_hash` CHAR(64) NULL,
|
||||
`nickname` VARCHAR(100) NULL,
|
||||
`avatar_url` VARCHAR(512) NULL,
|
||||
`last_login_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `users_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `users_mobile_hash_key`(`mobile_hash`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `wechat_identities` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`appid` VARCHAR(64) NOT NULL,
|
||||
`openid_ciphertext` VARCHAR(512) NOT NULL,
|
||||
`openid_hash` CHAR(64) NOT NULL,
|
||||
`unionid_ciphertext` VARCHAR(512) NULL,
|
||||
`unionid_hash` CHAR(64) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
INDEX `wechat_identities_user_id_idx`(`user_id`),
|
||||
UNIQUE INDEX `wechat_identities_appid_openid_hash_key`(`appid`, `openid_hash`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `staff_profiles` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`employee_no` VARCHAR(50) NULL,
|
||||
`display_name` VARCHAR(100) NOT NULL,
|
||||
`department` VARCHAR(100) NULL,
|
||||
`status` ENUM('ACTIVE', 'INACTIVE') NOT NULL DEFAULT 'ACTIVE',
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `staff_profiles_user_id_key`(`user_id`),
|
||||
UNIQUE INDEX `staff_profiles_employee_no_key`(`employee_no`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `admin_credentials` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`username` VARCHAR(64) NOT NULL,
|
||||
`password_hash` VARCHAR(255) NOT NULL,
|
||||
`failed_login_count` INTEGER UNSIGNED NOT NULL DEFAULT 0,
|
||||
`locked_until` DATETIME(3) NULL,
|
||||
`password_changed_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `admin_credentials_user_id_key`(`user_id`),
|
||||
UNIQUE INDEX `admin_credentials_username_key`(`username`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `auth_sessions` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`channel` ENUM('WECHAT', 'ADMIN') NOT NULL,
|
||||
`token_hash` CHAR(64) NOT NULL,
|
||||
`expires_at` DATETIME(3) NOT NULL,
|
||||
`last_used_at` DATETIME(3) NULL,
|
||||
`revoked_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `auth_sessions_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `auth_sessions_token_hash_key`(`token_hash`),
|
||||
INDEX `auth_sessions_user_channel_status_idx`(`user_id`, `channel`, `revoked_at`, `expires_at`),
|
||||
INDEX `auth_sessions_expires_at_idx`(`expires_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `roles` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`code` VARCHAR(64) NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` VARCHAR(255) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `roles_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `roles_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `permissions` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`code` VARCHAR(100) NOT NULL,
|
||||
`name` VARCHAR(100) NOT NULL,
|
||||
`description` VARCHAR(255) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `permissions_code_key`(`code`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `user_roles` (
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`role_id` BIGINT UNSIGNED NOT NULL,
|
||||
`assigned_by` BIGINT UNSIGNED NULL,
|
||||
`assigned_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `user_roles_role_id_idx`(`role_id`),
|
||||
INDEX `user_roles_assigned_by_idx`(`assigned_by`),
|
||||
PRIMARY KEY (`user_id`, `role_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `role_permissions` (
|
||||
`role_id` BIGINT UNSIGNED NOT NULL,
|
||||
`permission_id` BIGINT UNSIGNED NOT NULL,
|
||||
INDEX `role_permissions_permission_id_idx`(`permission_id`),
|
||||
PRIMARY KEY (`role_id`, `permission_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `audit_logs` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`request_id` CHAR(36) NOT NULL,
|
||||
`actor_user_id` BIGINT UNSIGNED NULL,
|
||||
`actor_role` VARCHAR(64) NULL,
|
||||
`action` VARCHAR(100) NOT NULL,
|
||||
`resource_type` VARCHAR(100) NULL,
|
||||
`resource_public_id` VARCHAR(100) NULL,
|
||||
`result` ENUM('SUCCESS', 'FAILURE') NOT NULL,
|
||||
`metadata_json` JSON NULL,
|
||||
`ip_hash` CHAR(64) NULL,
|
||||
`user_agent_summary` VARCHAR(255) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `audit_logs_actor_created_at_idx`(`actor_user_id`, `created_at`),
|
||||
INDEX `audit_logs_resource_created_at_idx`(`resource_type`, `resource_public_id`, `created_at`),
|
||||
INDEX `audit_logs_action_created_at_idx`(`action`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
ALTER TABLE `wechat_identities` ADD CONSTRAINT `wechat_identities_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `staff_profiles` ADD CONSTRAINT `staff_profiles_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `admin_credentials` ADD CONSTRAINT `admin_credentials_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `auth_sessions` ADD CONSTRAINT `auth_sessions_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_role_id_fkey` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `user_roles` ADD CONSTRAINT `user_roles_assigned_by_fkey` FOREIGN KEY (`assigned_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `role_permissions` ADD CONSTRAINT `role_permissions_role_id_fkey` FOREIGN KEY (`role_id`) REFERENCES `roles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `role_permissions` ADD CONSTRAINT `role_permissions_permission_id_fkey` FOREIGN KEY (`permission_id`) REFERENCES `permissions`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `audit_logs` ADD CONSTRAINT `audit_logs_actor_user_id_fkey` FOREIGN KEY (`actor_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO `roles` (`public_id`, `code`, `name`, `description`, `updated_at`) VALUES
|
||||
('9fc73dca-5e75-4ce6-b8ad-d270bd020001', 'VOLUNTEER', '志愿者', '仅访问本人被分配的最小必要任务信息', CURRENT_TIMESTAMP(3)),
|
||||
('9fc73dca-5e75-4ce6-b8ad-d270bd020002', 'STAFF', '工作人员', '按负责范围处理公益服务', CURRENT_TIMESTAMP(3)),
|
||||
('9fc73dca-5e75-4ce6-b8ad-d270bd020003', 'PROJECT_MANAGER', '项目负责人', '按项目范围管理服务', CURRENT_TIMESTAMP(3)),
|
||||
('9fc73dca-5e75-4ce6-b8ad-d270bd020004', 'ADMIN', '管理员', '跨项目业务管理', CURRENT_TIMESTAMP(3)),
|
||||
('9fc73dca-5e75-4ce6-b8ad-d270bd020005', 'SUPER_ADMIN', '超级管理员', '系统级配置维护,日常不使用', CURRENT_TIMESTAMP(3));
|
||||
|
||||
INSERT INTO `permissions` (`code`, `name`, `description`) VALUES
|
||||
('admin:access', '访问管理后台', '允许进入管理后台'),
|
||||
('users:read', '查看用户', '按授权范围查看用户基础信息'),
|
||||
('users:manage', '管理用户', '管理用户状态与基础信息'),
|
||||
('roles:manage', '管理角色权限', '分配角色和维护权限'),
|
||||
('audit:read', '查看审计日志', '按权限查看审计记录'),
|
||||
('system:manage', '管理系统配置', '维护系统级配置'),
|
||||
('sensitive:read', '查看敏感信息', '经审计查看必要敏感信息'),
|
||||
('sensitive:export', '导出敏感信息', '受控导出敏感信息'),
|
||||
('resources:access_all', '跨范围访问资源', '按角色范围访问非本人资源');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p
|
||||
WHERE r.code = 'STAFF' AND p.code IN ('admin:access', 'users:read');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p
|
||||
WHERE r.code = 'PROJECT_MANAGER' AND p.code IN ('admin:access', 'users:read', 'resources:access_all');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p
|
||||
WHERE r.code = 'ADMIN' AND p.code IN ('admin:access', 'users:read', 'users:manage', 'roles:manage', 'audit:read', 'sensitive:read', 'resources:access_all');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p
|
||||
WHERE r.code = 'SUPER_ADMIN';
|
||||
@@ -0,0 +1,81 @@
|
||||
-- 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';
|
||||
@@ -0,0 +1,359 @@
|
||||
-- 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');
|
||||
@@ -0,0 +1,105 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `service_applications` ADD COLUMN `parent_application_id` BIGINT UNSIGNED NULL,
|
||||
ADD COLUMN `source_follow_up_task_id` BIGINT UNSIGNED NULL,
|
||||
MODIFY `source` ENUM('WECHAT_MINIPROGRAM', 'ADMIN', 'FOLLOW_UP') NOT NULL DEFAULT 'WECHAT_MINIPROGRAM';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `service_cases` ADD COLUMN `complete_request_fingerprint` CHAR(64) NULL,
|
||||
ADD COLUMN `complete_request_id` CHAR(36) NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `follow_up_tasks` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`follow_up_no` VARCHAR(32) NOT NULL,
|
||||
`beneficiary_id` BIGINT UNSIGNED NOT NULL,
|
||||
`case_id` BIGINT UNSIGNED NULL,
|
||||
`owner_staff_id` BIGINT UNSIGNED NOT NULL,
|
||||
`due_at` DATETIME(3) NOT NULL,
|
||||
`follow_up_type` ENUM('SERVICE_COMPLETION', 'KEY_CARE', 'MANUAL') NOT NULL,
|
||||
`status` ENUM('PENDING', 'COMPLETED', 'CANCELLED') NOT NULL DEFAULT 'PENDING',
|
||||
`source` ENUM('AUTO_SERVICE_COMPLETION', 'STAFF_MANUAL', 'KEY_CARE_PLAN') NOT NULL,
|
||||
`reason_encrypted` TEXT NOT NULL,
|
||||
`result_code` ENUM('SATISFIED', 'GENERALLY_SATISFIED', 'UNSATISFIED', 'NEED_MORE_HELP', 'UNREACHABLE', 'OTHER') NULL,
|
||||
`result_note_encrypted` TEXT NULL,
|
||||
`create_request_id` CHAR(36) NOT NULL,
|
||||
`create_request_fingerprint` CHAR(64) NOT NULL,
|
||||
`complete_request_id` CHAR(36) NULL,
|
||||
`complete_request_fingerprint` CHAR(64) 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 `follow_up_tasks_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `follow_up_tasks_follow_up_no_key`(`follow_up_no`),
|
||||
INDEX `follow_up_tasks_owner_status_due_at_idx`(`owner_staff_id`, `status`, `due_at`),
|
||||
INDEX `follow_up_tasks_status_due_at_idx`(`status`, `due_at`),
|
||||
INDEX `follow_up_tasks_beneficiary_due_at_idx`(`beneficiary_id`, `due_at`),
|
||||
INDEX `follow_up_tasks_case_created_at_idx`(`case_id`, `created_at`),
|
||||
UNIQUE INDEX `follow_up_tasks_creator_request_key`(`created_by`, `create_request_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `follow_up_status_history` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`follow_up_task_id` BIGINT UNSIGNED NOT NULL,
|
||||
`from_status` ENUM('PENDING', 'COMPLETED', 'CANCELLED') NULL,
|
||||
`to_status` ENUM('PENDING', 'COMPLETED', '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 `follow_up_status_history_task_created_at_idx`(`follow_up_task_id`, `created_at`),
|
||||
INDEX `follow_up_status_history_operator_created_at_idx`(`operator_user_id`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `service_applications_source_follow_up_task_id_key` ON `service_applications`(`source_follow_up_task_id`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `service_applications_parent_submitted_at_idx` ON `service_applications`(`parent_application_id`, `submitted_at`);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX `service_cases_complete_request_id_key` ON `service_cases`(`complete_request_id`);
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `service_applications` ADD CONSTRAINT `service_applications_source_follow_up_task_id_fkey` FOREIGN KEY (`source_follow_up_task_id`) REFERENCES `follow_up_tasks`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `service_applications` ADD CONSTRAINT `service_applications_parent_application_id_fkey` FOREIGN KEY (`parent_application_id`) REFERENCES `service_applications`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_tasks` ADD CONSTRAINT `follow_up_tasks_beneficiary_id_fkey` FOREIGN KEY (`beneficiary_id`) REFERENCES `beneficiary_profiles`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_tasks` ADD CONSTRAINT `follow_up_tasks_case_id_fkey` FOREIGN KEY (`case_id`) REFERENCES `service_cases`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_tasks` ADD CONSTRAINT `follow_up_tasks_owner_staff_id_fkey` FOREIGN KEY (`owner_staff_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_tasks` ADD CONSTRAINT `follow_up_tasks_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_tasks` ADD CONSTRAINT `follow_up_tasks_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_status_history` ADD CONSTRAINT `follow_up_status_history_follow_up_task_id_fkey` FOREIGN KEY (`follow_up_task_id`) REFERENCES `follow_up_tasks`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `follow_up_status_history` ADD CONSTRAINT `follow_up_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- Phase 4 follow-up permissions. Volunteers do not receive access to beneficiary follow-up results.
|
||||
INSERT INTO `permissions` (`code`, `name`, `description`) VALUES
|
||||
('follow_ups:read', '查看回访任务', '按负责人或管理范围查看回访工作台和任务'),
|
||||
('follow_ups:manage', '创建回访任务', '创建人工或重点关爱回访并在服务完成时生成回访'),
|
||||
('follow_ups:complete', '完成回访任务', '由任务负责人记录回访结论和继续帮扶授权');
|
||||
|
||||
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 ('follow_ups:read', 'follow_ups:manage', 'follow_ups:complete');
|
||||
@@ -0,0 +1,267 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `consents` MODIFY `consent_type` ENUM('SERVICE_APPLICATION', 'BENEFICIARY_GUARDIAN', 'VOLUNTEER_APPLICATION') NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `files` MODIFY `case_id` BIGINT UNSIGNED NULL,
|
||||
MODIFY `business_type` ENUM('SERVICE_RECORD', 'PROJECT_COVER', 'ACTIVITY_COVER') NOT NULL;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE `service_cases` ADD COLUMN `project_id` BIGINT UNSIGNED NULL;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `volunteers` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`consent_id` BIGINT UNSIGNED NOT NULL,
|
||||
`real_name_encrypted` VARCHAR(512) NOT NULL,
|
||||
`real_name_hash` CHAR(64) NOT NULL,
|
||||
`mobile_encrypted` VARCHAR(512) NOT NULL,
|
||||
`mobile_hash` CHAR(64) NOT NULL,
|
||||
`region_code` VARCHAR(100) NOT NULL,
|
||||
`availability_note_encrypted` TEXT NOT NULL,
|
||||
`status` ENUM('APPLIED', 'APPROVED', 'REJECTED', 'SUSPENDED', 'INACTIVE') NOT NULL DEFAULT 'APPLIED',
|
||||
`approved_by` BIGINT UNSIGNED NULL,
|
||||
`approved_at` DATETIME(3) NULL,
|
||||
`revision` INTEGER UNSIGNED NOT NULL DEFAULT 1,
|
||||
`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 `volunteers_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `volunteers_user_id_key`(`user_id`),
|
||||
UNIQUE INDEX `volunteers_consent_id_key`(`consent_id`),
|
||||
INDEX `volunteers_status_created_at_idx`(`status`, `created_at`),
|
||||
INDEX `volunteers_mobile_hash_idx`(`mobile_hash`),
|
||||
INDEX `volunteers_region_status_idx`(`region_code`, `status`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `volunteer_skills` (
|
||||
`volunteer_id` BIGINT UNSIGNED NOT NULL,
|
||||
`skill_code` VARCHAR(64) NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `volunteer_skills_code_idx`(`skill_code`),
|
||||
PRIMARY KEY (`volunteer_id`, `skill_code`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `volunteer_interests` (
|
||||
`volunteer_id` BIGINT UNSIGNED NOT NULL,
|
||||
`category` ENUM('OLD_AGE', 'WOMEN', 'CHILD', 'DISABILITY', 'LIFE_DIFFICULTY', 'OTHER') NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
INDEX `volunteer_interests_category_idx`(`category`),
|
||||
PRIMARY KEY (`volunteer_id`, `category`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `volunteer_status_history` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`volunteer_id` BIGINT UNSIGNED NOT NULL,
|
||||
`request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`from_status` ENUM('APPLIED', 'APPROVED', 'REJECTED', 'SUSPENDED', 'INACTIVE') NULL,
|
||||
`to_status` ENUM('APPLIED', 'APPROVED', 'REJECTED', 'SUSPENDED', 'INACTIVE') NOT NULL,
|
||||
`operator_user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`reason_code` VARCHAR(100) NOT NULL,
|
||||
`note_encrypted` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `volunteer_status_history_request_id_key`(`request_id`),
|
||||
INDEX `volunteer_status_history_volunteer_created_at_idx`(`volunteer_id`, `created_at`),
|
||||
INDEX `volunteer_status_history_operator_created_at_idx`(`operator_user_id`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `projects` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`project_no` VARCHAR(32) NOT NULL,
|
||||
`client_request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`name` VARCHAR(200) NOT NULL,
|
||||
`category` ENUM('OLD_AGE', 'WOMEN', 'CHILD', 'DISABILITY', 'LIFE_DIFFICULTY', 'OTHER') NOT NULL,
|
||||
`summary` VARCHAR(500) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`cover_file_id` BIGINT UNSIGNED NULL,
|
||||
`manager_user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`start_date` DATE NOT NULL,
|
||||
`end_date` DATE NOT NULL,
|
||||
`target_people` INTEGER UNSIGNED NULL,
|
||||
`status` ENUM('DRAFT', 'PUBLISHED', 'COMPLETED') NOT NULL DEFAULT 'DRAFT',
|
||||
`is_public` BOOLEAN NOT NULL DEFAULT false,
|
||||
`sort_order` INTEGER NOT NULL DEFAULT 0,
|
||||
`revision` INTEGER UNSIGNED NOT NULL DEFAULT 1,
|
||||
`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 `projects_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `projects_project_no_key`(`project_no`),
|
||||
UNIQUE INDEX `projects_cover_file_id_key`(`cover_file_id`),
|
||||
INDEX `projects_public_status_sort_idx`(`status`, `is_public`, `sort_order`, `created_at`),
|
||||
INDEX `projects_manager_status_idx`(`manager_user_id`, `status`, `created_at`),
|
||||
UNIQUE INDEX `projects_creator_request_key`(`created_by`, `client_request_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `project_status_history` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`project_id` BIGINT UNSIGNED NOT NULL,
|
||||
`request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`from_status` ENUM('DRAFT', 'PUBLISHED', 'COMPLETED') NULL,
|
||||
`to_status` ENUM('DRAFT', 'PUBLISHED', 'COMPLETED') 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),
|
||||
UNIQUE INDEX `project_status_history_request_id_key`(`request_id`),
|
||||
INDEX `project_status_history_project_created_at_idx`(`project_id`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `activities` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`activity_no` VARCHAR(32) NOT NULL,
|
||||
`project_id` BIGINT UNSIGNED NULL,
|
||||
`client_request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`title` VARCHAR(200) NOT NULL,
|
||||
`summary` VARCHAR(500) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`cover_file_id` BIGINT UNSIGNED NULL,
|
||||
`start_at` DATETIME(3) NOT NULL,
|
||||
`end_at` DATETIME(3) NOT NULL,
|
||||
`registration_deadline` DATETIME(3) NOT NULL,
|
||||
`location_text` VARCHAR(300) NOT NULL,
|
||||
`capacity` INTEGER UNSIGNED NULL,
|
||||
`status` ENUM('DRAFT', 'PUBLISHED', 'REGISTRATION_CLOSED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED') NOT NULL DEFAULT 'DRAFT',
|
||||
`published_at` DATETIME(3) NULL,
|
||||
`revision` INTEGER UNSIGNED NOT NULL DEFAULT 1,
|
||||
`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 `activities_public_id_key`(`public_id`),
|
||||
UNIQUE INDEX `activities_activity_no_key`(`activity_no`),
|
||||
UNIQUE INDEX `activities_cover_file_id_key`(`cover_file_id`),
|
||||
INDEX `activities_status_start_at_idx`(`status`, `start_at`),
|
||||
INDEX `activities_project_start_at_idx`(`project_id`, `start_at`),
|
||||
UNIQUE INDEX `activities_creator_request_key`(`created_by`, `client_request_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `activity_status_history` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`activity_id` BIGINT UNSIGNED NOT NULL,
|
||||
`request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`from_status` ENUM('DRAFT', 'PUBLISHED', 'REGISTRATION_CLOSED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED') NULL,
|
||||
`to_status` ENUM('DRAFT', 'PUBLISHED', 'REGISTRATION_CLOSED', 'IN_PROGRESS', 'COMPLETED', '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),
|
||||
UNIQUE INDEX `activity_status_history_request_id_key`(`request_id`),
|
||||
INDEX `activity_status_history_activity_created_at_idx`(`activity_id`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `activity_registrations` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`activity_id` BIGINT UNSIGNED NOT NULL,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`volunteer_id` BIGINT UNSIGNED NOT NULL,
|
||||
`client_request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`status` ENUM('PENDING', 'APPROVED', 'REJECTED', 'CANCELLED') NOT NULL DEFAULT 'PENDING',
|
||||
`check_in_status` ENUM('NOT_CHECKED_IN', 'CHECKED_IN', 'ABSENT') NOT NULL DEFAULT 'NOT_CHECKED_IN',
|
||||
`registered_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`reviewed_by` BIGINT UNSIGNED NULL,
|
||||
`reviewed_at` DATETIME(3) NULL,
|
||||
`review_note_encrypted` TEXT NULL,
|
||||
`checked_in_at` DATETIME(3) NULL,
|
||||
`checked_in_by` BIGINT UNSIGNED NULL,
|
||||
`service_minutes` INTEGER UNSIGNED NULL,
|
||||
`service_minutes_recorded_at` DATETIME(3) NULL,
|
||||
`service_minutes_recorded_by` BIGINT UNSIGNED NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `activity_registrations_public_id_key`(`public_id`),
|
||||
INDEX `activity_registrations_activity_status_idx`(`activity_id`, `status`, `registered_at`),
|
||||
INDEX `activity_registrations_volunteer_registered_idx`(`volunteer_id`, `registered_at`),
|
||||
UNIQUE INDEX `activity_registrations_activity_user_key`(`activity_id`, `user_id`),
|
||||
UNIQUE INDEX `activity_registrations_user_request_key`(`user_id`, `client_request_id`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `activity_registration_history` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`registration_id` BIGINT UNSIGNED NOT NULL,
|
||||
`request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`from_status` ENUM('PENDING', 'APPROVED', 'REJECTED', 'CANCELLED') NULL,
|
||||
`to_status` ENUM('PENDING', 'APPROVED', 'REJECTED', 'CANCELLED') NULL,
|
||||
`from_check_in_status` ENUM('NOT_CHECKED_IN', 'CHECKED_IN', 'ABSENT') NULL,
|
||||
`to_check_in_status` ENUM('NOT_CHECKED_IN', 'CHECKED_IN', 'ABSENT') NULL,
|
||||
`service_minutes_before` INTEGER UNSIGNED NULL,
|
||||
`service_minutes_after` INTEGER UNSIGNED NULL,
|
||||
`operator_user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`action_code` VARCHAR(100) NOT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `activity_registration_history_request_id_key`(`request_id`),
|
||||
INDEX `registration_history_registration_created_at_idx`(`registration_id`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE INDEX `service_cases_project_created_at_idx` ON `service_cases`(`project_id`, `created_at`);
|
||||
|
||||
ALTER TABLE `service_cases` ADD CONSTRAINT `service_cases_project_id_fkey` FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteers` ADD CONSTRAINT `volunteers_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteers` ADD CONSTRAINT `volunteers_consent_id_fkey` FOREIGN KEY (`consent_id`) REFERENCES `consents`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteers` ADD CONSTRAINT `volunteers_approved_by_fkey` FOREIGN KEY (`approved_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteers` ADD CONSTRAINT `volunteers_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteers` ADD CONSTRAINT `volunteers_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteer_skills` ADD CONSTRAINT `volunteer_skills_volunteer_id_fkey` FOREIGN KEY (`volunteer_id`) REFERENCES `volunteers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteer_interests` ADD CONSTRAINT `volunteer_interests_volunteer_id_fkey` FOREIGN KEY (`volunteer_id`) REFERENCES `volunteers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteer_status_history` ADD CONSTRAINT `volunteer_status_history_volunteer_id_fkey` FOREIGN KEY (`volunteer_id`) REFERENCES `volunteers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `volunteer_status_history` ADD CONSTRAINT `volunteer_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `projects` ADD CONSTRAINT `projects_cover_file_id_fkey` FOREIGN KEY (`cover_file_id`) REFERENCES `files`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `projects` ADD CONSTRAINT `projects_manager_user_id_fkey` FOREIGN KEY (`manager_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `projects` ADD CONSTRAINT `projects_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `projects` ADD CONSTRAINT `projects_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `project_status_history` ADD CONSTRAINT `project_status_history_project_id_fkey` FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `project_status_history` ADD CONSTRAINT `project_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activities` ADD CONSTRAINT `activities_project_id_fkey` FOREIGN KEY (`project_id`) REFERENCES `projects`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activities` ADD CONSTRAINT `activities_cover_file_id_fkey` FOREIGN KEY (`cover_file_id`) REFERENCES `files`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activities` ADD CONSTRAINT `activities_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activities` ADD CONSTRAINT `activities_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_status_history` ADD CONSTRAINT `activity_status_history_activity_id_fkey` FOREIGN KEY (`activity_id`) REFERENCES `activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_status_history` ADD CONSTRAINT `activity_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registrations` ADD CONSTRAINT `activity_registrations_activity_id_fkey` FOREIGN KEY (`activity_id`) REFERENCES `activities`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registrations` ADD CONSTRAINT `activity_registrations_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registrations` ADD CONSTRAINT `activity_registrations_volunteer_id_fkey` FOREIGN KEY (`volunteer_id`) REFERENCES `volunteers`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registrations` ADD CONSTRAINT `activity_registrations_reviewed_by_fkey` FOREIGN KEY (`reviewed_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registrations` ADD CONSTRAINT `activity_registrations_checked_in_by_fkey` FOREIGN KEY (`checked_in_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registrations` ADD CONSTRAINT `activity_registrations_service_minutes_recorded_by_fkey` FOREIGN KEY (`service_minutes_recorded_by`) REFERENCES `users`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registration_history` ADD CONSTRAINT `activity_registration_history_registration_id_fkey` FOREIGN KEY (`registration_id`) REFERENCES `activity_registrations`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `activity_registration_history` ADD CONSTRAINT `activity_registration_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
|
||||
('volunteers:read', '查看志愿者', '按授权范围查看志愿者脱敏列表与详情'),
|
||||
('volunteers:review', '审核志愿者', '审核、暂停和恢复志愿者资格'),
|
||||
('projects:read', '查看公益项目', '按授权范围查看公益项目'),
|
||||
('projects:manage', '管理公益项目', '创建和维护公益项目及关联工单'),
|
||||
('projects:publish', '发布公益项目', '执行公益项目发布和完成状态迁移'),
|
||||
('activities:read', '查看公益活动', '按授权范围查看活动和报名'),
|
||||
('activities:manage', '管理公益活动', '创建和维护公益活动'),
|
||||
('activities:publish', '发布公益活动', '执行活动发布及状态迁移'),
|
||||
('registrations:manage', '管理活动报名', '审核报名、签到并记录服务时长');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p
|
||||
WHERE r.code IN ('PROJECT_MANAGER', 'ADMIN', 'SUPER_ADMIN')
|
||||
AND p.code IN ('volunteers:read', 'volunteers:review', 'projects:read', 'projects:manage', 'projects:publish', 'activities:read', 'activities:manage', 'activities:publish', 'registrations:manage');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM roles r CROSS JOIN permissions p
|
||||
WHERE r.code = 'STAFF'
|
||||
AND p.code IN ('volunteers:read', 'projects:read', 'activities:read', 'registrations:manage');
|
||||
@@ -0,0 +1,120 @@
|
||||
-- Phase 6: reviewed public content and durable user notifications.
|
||||
ALTER TABLE `files` MODIFY `business_type` ENUM('SERVICE_RECORD', 'PROJECT_COVER', 'ACTIVITY_COVER', 'CONTENT_COVER') NOT NULL;
|
||||
|
||||
CREATE TABLE `content_posts` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`client_request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`type` ENUM('ORGANIZATION_INTRO','PUBLIC_WELFARE_NEWS','SERVICE_STORY','NOTICE','FAQ') NOT NULL,
|
||||
`title` VARCHAR(200) NOT NULL,
|
||||
`summary` VARCHAR(500) NOT NULL,
|
||||
`content` TEXT NOT NULL,
|
||||
`cover_file_id` BIGINT UNSIGNED NULL,
|
||||
`status` ENUM('DRAFT','PENDING_REVIEW','PUBLISHED','ARCHIVED') NOT NULL DEFAULT 'DRAFT',
|
||||
`revision` INTEGER UNSIGNED NOT NULL DEFAULT 1,
|
||||
`privacy_reviewed_at` DATETIME(3) NULL,
|
||||
`reviewed_by` BIGINT UNSIGNED NULL,
|
||||
`reviewed_at` DATETIME(3) NULL,
|
||||
`published_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 `content_posts_public_id_key` (`public_id`),
|
||||
UNIQUE INDEX `content_posts_cover_file_id_key` (`cover_file_id`),
|
||||
UNIQUE INDEX `content_posts_creator_request_key` (`created_by`, `client_request_id`),
|
||||
INDEX `content_posts_status_type_published_idx` (`status`, `type`, `published_at`),
|
||||
INDEX `content_posts_creator_status_updated_idx` (`created_by`, `status`, `updated_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `content_post_status_history` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`content_post_id` BIGINT UNSIGNED NOT NULL,
|
||||
`request_id` CHAR(36) NOT NULL,
|
||||
`request_fingerprint` CHAR(64) NOT NULL,
|
||||
`from_status` ENUM('DRAFT','PENDING_REVIEW','PUBLISHED','ARCHIVED') NULL,
|
||||
`to_status` ENUM('DRAFT','PENDING_REVIEW','PUBLISHED','ARCHIVED') NOT NULL,
|
||||
`operator_user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`reason_code` VARCHAR(100) NOT NULL,
|
||||
`note_encrypted` TEXT NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `content_post_status_history_request_id_key` (`request_id`),
|
||||
INDEX `content_status_history_post_created_idx` (`content_post_id`, `created_at`),
|
||||
INDEX `content_status_history_operator_created_idx` (`operator_user_id`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `notifications` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`event_key` VARCHAR(160) NOT NULL,
|
||||
`type` ENUM('APPLICATION_SUBMITTED','APPLICATION_ACCEPTED','SERVICE_ARRANGED','SERVICE_COMPLETED','FOLLOW_UP_PENDING','ACTIVITY_REGISTRATION_RESULT') NOT NULL,
|
||||
`title` VARCHAR(120) NOT NULL,
|
||||
`body` VARCHAR(500) NOT NULL,
|
||||
`resource_type` VARCHAR(80) NULL,
|
||||
`resource_public_id` CHAR(36) NULL,
|
||||
`read_at` DATETIME(3) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
UNIQUE INDEX `notifications_public_id_key` (`public_id`),
|
||||
UNIQUE INDEX `notifications_user_event_key` (`user_id`, `event_key`),
|
||||
INDEX `notifications_user_read_created_idx` (`user_id`, `read_at`, `created_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `notification_preferences` (
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`type` ENUM('APPLICATION_SUBMITTED','APPLICATION_ACCEPTED','SERVICE_ARRANGED','SERVICE_COMPLETED','FOLLOW_UP_PENDING','ACTIVITY_REGISTRATION_RESULT') NOT NULL,
|
||||
`in_app_enabled` BOOLEAN NOT NULL DEFAULT true,
|
||||
`wechat_enabled` BOOLEAN NOT NULL DEFAULT false,
|
||||
`authorized_at` DATETIME(3) NULL,
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
INDEX `notification_preferences_type_wechat_idx` (`type`, `wechat_enabled`),
|
||||
PRIMARY KEY (`user_id`, `type`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `notification_deliveries` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`public_id` CHAR(36) NOT NULL,
|
||||
`notification_id` BIGINT UNSIGNED NOT NULL,
|
||||
`channel` ENUM('WECHAT_SUBSCRIPTION') NOT NULL,
|
||||
`status` ENUM('PENDING','PROCESSING','SENT','FAILED','DEAD') NOT NULL DEFAULT 'PENDING',
|
||||
`attempt_count` INTEGER UNSIGNED NOT NULL DEFAULT 0,
|
||||
`next_attempt_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`last_attempt_at` DATETIME(3) NULL,
|
||||
`provider_message_id` VARCHAR(160) NULL,
|
||||
`error_code` VARCHAR(100) NULL,
|
||||
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
`updated_at` DATETIME(3) NOT NULL,
|
||||
UNIQUE INDEX `notification_deliveries_public_id_key` (`public_id`),
|
||||
UNIQUE INDEX `notification_deliveries_notification_channel_key` (`notification_id`, `channel`),
|
||||
INDEX `notification_deliveries_status_next_idx` (`status`, `next_attempt_at`),
|
||||
PRIMARY KEY (`id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
ALTER TABLE `content_posts` ADD CONSTRAINT `content_posts_cover_file_id_fkey` FOREIGN KEY (`cover_file_id`) REFERENCES `files` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `content_posts` ADD CONSTRAINT `content_posts_created_by_fkey` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `content_posts` ADD CONSTRAINT `content_posts_updated_by_fkey` FOREIGN KEY (`updated_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `content_posts` ADD CONSTRAINT `content_posts_reviewed_by_fkey` FOREIGN KEY (`reviewed_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `content_post_status_history` ADD CONSTRAINT `content_status_history_post_fkey` FOREIGN KEY (`content_post_id`) REFERENCES `content_posts` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `content_post_status_history` ADD CONSTRAINT `content_status_history_operator_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `notifications` ADD CONSTRAINT `notifications_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `notification_preferences` ADD CONSTRAINT `notification_preferences_user_id_fkey` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
ALTER TABLE `notification_deliveries` ADD CONSTRAINT `notification_deliveries_notification_id_fkey` FOREIGN KEY (`notification_id`) REFERENCES `notifications` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
INSERT INTO `permissions` (`code`, `name`, `description`) VALUES
|
||||
('content:read', '查看内容', '查看内容草稿、审核状态及历史'),
|
||||
('content:manage', '管理内容', '创建和维护内容草稿'),
|
||||
('content:review', '审核内容', '审核、发布、退回和归档内容'),
|
||||
('notifications:manage', '管理通知', '查看通知投递状态并安全重试');
|
||||
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM `roles` r CROSS JOIN `permissions` p
|
||||
WHERE r.code IN ('ADMIN','SUPER_ADMIN')
|
||||
AND p.code IN ('content:read','content:manage','content:review','notifications:manage');
|
||||
|
||||
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') AND p.code = 'content:read';
|
||||
@@ -0,0 +1,9 @@
|
||||
INSERT INTO `permissions` (`code`, `name`, `description`) VALUES
|
||||
('statistics:read', '查看统计', '查看基于真实业务数据生成的统计指标'),
|
||||
('exports:create', '创建导出', '创建并下载默认脱敏的受控统计导出');
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM `roles` r CROSS JOIN `permissions` p
|
||||
WHERE r.code IN ('ADMIN','SUPER_ADMIN') AND p.code IN ('statistics:read','exports:create');
|
||||
INSERT INTO `role_permissions` (`role_id`, `permission_id`)
|
||||
SELECT r.id, p.id FROM `roles` r CROSS JOIN `permissions` p
|
||||
WHERE r.code = 'PROJECT_MANAGER' AND p.code = 'statistics:read';
|
||||
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE `content_post_status_history`
|
||||
DROP FOREIGN KEY `content_status_history_post_fkey`,
|
||||
DROP FOREIGN KEY `content_status_history_operator_fkey`,
|
||||
ADD CONSTRAINT `content_post_status_history_content_post_id_fkey` FOREIGN KEY (`content_post_id`) REFERENCES `content_posts` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
ADD CONSTRAINT `content_post_status_history_operator_user_id_fkey` FOREIGN KEY (`operator_user_id`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
@@ -0,0 +1 @@
|
||||
provider = "mysql"
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user