387 lines
32 KiB
Bash
Executable File
387 lines
32 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
if ! command -v docker >/dev/null || ! docker ps --format '{{.Names}}' | grep -qx 'wygj-mysql'; then
|
|
echo "SKIP: AIHR schema migration test requires wygj-mysql"
|
|
exit 0
|
|
fi
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
MYSQL_CONTAINER="wygj-mysql"
|
|
DB="wygj_aihr_schema_test_$$"
|
|
LEGACY_DB="wygj_aihr_candidate_legacy_test_$$"
|
|
|
|
while IFS= read -r migration; do
|
|
migration_name="$(basename "$migration")"
|
|
grep -Fq "backend/script/sql/update/$migration_name" "$ROOT_DIR/docs/BRD_PRODUCTION_MIGRATION_RUNBOOK.md" || {
|
|
echo "FAIL: AIHR migration missing from production Runbook: $migration_name" >&2
|
|
exit 1
|
|
}
|
|
done < <(find "$ROOT_DIR/backend/script/sql/update" -maxdepth 1 -type f -name 'aihr_*_mysql8.sql' -print | sort)
|
|
|
|
mysql() {
|
|
docker exec -i "$MYSQL_CONTAINER" mysql -uroot -proot --default-character-set=utf8mb4 "$@"
|
|
}
|
|
|
|
cleanup() {
|
|
mysql -e "DROP DATABASE IF EXISTS \`$DB\`;" >/dev/null 2>&1 || true
|
|
mysql -e "DROP DATABASE IF EXISTS \`$LEGACY_DB\`;" >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
mysql -e "CREATE DATABASE \`$DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;"
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_media_mysql8.sql"
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_case_record (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
tenant_id varchar(20) DEFAULT '000000',
|
|
case_id varchar(80) NOT NULL,
|
|
summary varchar(1000) DEFAULT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_aihr_case_record_case (tenant_id, case_id)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_media_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_media_mysql8.sql"
|
|
case_media_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_case_record' AND column_name IN ('media_oss_id','media_url');")"
|
|
test "$case_media_columns" = 'media_oss_id,media_url'
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_learning_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_case_learning_mysql8.sql"
|
|
case_learning_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_case_record' AND column_name IN ('learning_points','supervisor_comment');")"
|
|
test "$case_learning_columns" = 'learning_points,supervisor_comment'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_prompt_template (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
tenant_id varchar(20) DEFAULT '000000',
|
|
code varchar(80) NOT NULL,
|
|
name varchar(100) NOT NULL,
|
|
category varchar(50) NOT NULL,
|
|
output_format varchar(50) NOT NULL,
|
|
system_prompt text,
|
|
template text NOT NULL,
|
|
variables varchar(1000),
|
|
version varchar(30) DEFAULT 'v1',
|
|
enabled tinyint DEFAULT 1,
|
|
description varchar(500),
|
|
create_time datetime,
|
|
update_time datetime,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_aihr_prompt_template (tenant_id, code, output_format, version)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_prompt_template_seed_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_prompt_template_seed_mysql8.sql"
|
|
prompt_template_count="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM aihr_prompt_template WHERE tenant_id='000000';")"
|
|
test "$prompt_template_count" = '6'
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql"
|
|
knowledge_feedback_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_knowledge_answer_feedback','aihr_knowledge_gap');")"
|
|
test "$knowledge_feedback_tables" = 'aihr_knowledge_answer_feedback,aihr_knowledge_gap'
|
|
|
|
mysql "$DB" -e "DROP TABLE aihr_knowledge_answer_feedback"
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_knowledge_answer_feedback (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
tenant_id varchar(20) DEFAULT '000000',
|
|
query_text varchar(1000) NOT NULL,
|
|
query_norm varchar(500) NOT NULL,
|
|
fragment_id bigint NOT NULL,
|
|
verdict varchar(10) NOT NULL,
|
|
category varchar(100),
|
|
position varchar(80),
|
|
source varchar(50),
|
|
review_status varchar(30),
|
|
create_time datetime,
|
|
update_time datetime,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_knowledge_feedback_mysql8.sql"
|
|
feedback_review_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_knowledge_answer_feedback' AND column_name IN ('review_id','reviewer','reviewed_time');")"
|
|
test "$feedback_review_columns" = 'review_id,reviewer,reviewed_time'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_practice_session (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
session_id varchar(100) NOT NULL,
|
|
total_score int,
|
|
ai_comment varchar(1000),
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_practice_session_evidence_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_practice_session_evidence_mysql8.sql"
|
|
practice_session_evidence_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_practice_session' AND column_name IN ('annotations_json','review_advice','incentive_point','satisfaction_score','satisfaction_comment');")"
|
|
test "$practice_session_evidence_columns" = '5'
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_practice_evidence_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_practice_evidence_mysql8.sql"
|
|
evidence_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_practice_audio','aihr_practice_audio_upload','aihr_practice_calibration');")"
|
|
test "$evidence_tables" = 'aihr_practice_audio,aihr_practice_audio_upload,aihr_practice_calibration'
|
|
|
|
practice_help_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260723_practice_m2_help_event_mysql8.sql"
|
|
test -f "$practice_help_migration"
|
|
mysql "$DB" < "$practice_help_migration"
|
|
mysql "$DB" < "$practice_help_migration"
|
|
practice_help_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_practice_help_event';")"
|
|
test "$practice_help_columns" = 'id,tenant_id,session_id,scenario_id,ext_party_id,round_index,create_time'
|
|
practice_help_tenant_collation="$(mysql "$DB" -N -B -e "SELECT CONCAT(character_set_name,'|',collation_name) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_practice_help_event' AND column_name='tenant_id';")"
|
|
test "$practice_help_tenant_collation" = 'utf8mb4|utf8mb4_general_ci'
|
|
practice_help_session_index="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_practice_help_event' AND index_name='idx_aihr_practice_help_session';")"
|
|
test "$practice_help_session_index" = 'tenant_id,session_id,create_time'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_sop_answer_review (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
snippet_count int DEFAULT 0,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_sop_requester_identity_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_sop_requester_identity_mysql8.sql"
|
|
sop_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_sop_answer_review' AND column_name IN ('source','prompt_version','requester_ext_party_id');")"
|
|
test "$sop_columns" = 'source,prompt_version,requester_ext_party_id'
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_org_hire_date_mysql8.sql"
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_org_snapshot (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
tenant_id varchar(20) NOT NULL,
|
|
project_code varchar(50) NOT NULL,
|
|
ext_party_id varchar(100) NOT NULL,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_aihr_org_party (tenant_id, ext_party_id)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_org_hire_date_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260714_org_hire_date_mysql8.sql"
|
|
org_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_org_snapshot' AND column_name='hire_date';")"
|
|
test "$org_columns" = 'hire_date'
|
|
org_multi_project_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260721_org_multi_project_membership_mysql8.sql"
|
|
mysql "$DB" < "$org_multi_project_migration"
|
|
mysql "$DB" < "$org_multi_project_migration"
|
|
org_party_unique="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_org_snapshot' AND index_name='uk_aihr_org_party';")"
|
|
test "$org_party_unique" = 'tenant_id,project_code,ext_party_id'
|
|
|
|
tenant_org_governance_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260723_tenant_org_governance_mysql8.sql"
|
|
test -f "$tenant_org_governance_migration"
|
|
mysql "$DB" < "$tenant_org_governance_migration"
|
|
mysql "$DB" < "$tenant_org_governance_migration"
|
|
tenant_org_governance_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_org_directory','aihr_tenant_org_binding');")"
|
|
test "$tenant_org_governance_tables" = 'aihr_org_directory,aihr_tenant_org_binding'
|
|
tenant_org_binding_unique="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_tenant_org_binding' AND index_name='uk_aihr_tenant_org_binding_tenant';")"
|
|
test "$tenant_org_binding_unique" = 'tenant_id'
|
|
tenant_org_binding_tenant_collation="$(mysql "$DB" -N -B -e "SELECT CONCAT(character_set_name,'|',collation_name) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_tenant_org_binding' AND column_name='tenant_id';")"
|
|
test "$tenant_org_binding_tenant_collation" = 'utf8mb4|utf8mb4_general_ci'
|
|
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_position_sop_qualification_mysql8.sql"
|
|
mysql "$DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_position_sop_qualification_mysql8.sql"
|
|
position_sop_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_onboard_task','aihr_position_responsibility','aihr_qualification_gate','aihr_sop_applicability');")"
|
|
test "$position_sop_tables" = 'aihr_onboard_task,aihr_position_responsibility,aihr_qualification_gate,aihr_sop_applicability'
|
|
position_responsibility_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_position_responsibility' AND column_name IN ('position_code','responsibility_text','sop_id','sop_code');")"
|
|
test "$position_responsibility_columns" = '4'
|
|
sop_applicability_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_sop_applicability' AND column_name IN ('sop_id','sop_code','project_type','industry','org_scope');")"
|
|
test "$sop_applicability_columns" = '5'
|
|
onboard_task_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_onboard_task' AND column_name IN ('ext_party_id','position_code','task_type','status','assign_by');")"
|
|
test "$onboard_task_columns" = '5'
|
|
qualification_gate_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_qualification_gate' AND column_name IN ('ext_party_id','position_code','cert_id','passed','valid_thru');")"
|
|
test "$qualification_gate_columns" = '5'
|
|
|
|
mysql -e "CREATE DATABASE \`$LEGACY_DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;"
|
|
mysql "$LEGACY_DB" <<'SQL'
|
|
CREATE TABLE aihr_candidate_material (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
status varchar(20) DEFAULT '待审核',
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
CREATE TABLE aihr_interview_result (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
session_id varchar(100) NOT NULL,
|
|
total_score int,
|
|
answers_json text,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB;
|
|
SQL
|
|
mysql "$LEGACY_DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_candidate_interview_review_mysql8.sql"
|
|
mysql "$LEGACY_DB" < "$ROOT_DIR/backend/script/sql/update/aihr_20260715_candidate_interview_review_mysql8.sql"
|
|
candidate_interview_tables="$(mysql "$LEGACY_DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$LEGACY_DB' AND table_name IN ('aihr_candidate_material','aihr_interview_result','aihr_candidate_employee_link');")"
|
|
test "$candidate_interview_tables" = 'aihr_candidate_employee_link,aihr_candidate_material,aihr_interview_result'
|
|
candidate_interview_columns="$(mysql "$LEGACY_DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$LEGACY_DB' AND ((table_name = 'aihr_candidate_material' AND column_name IN ('reviewer','reviewed_time')) OR (table_name = 'aihr_interview_result' AND column_name IN ('questions_json','reviewed_score','review_status','reviewer','review_note','reviewed_time')));")"
|
|
test "$candidate_interview_columns" = '8'
|
|
|
|
service_memory_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260719_service_memory_mysql8.sql"
|
|
test -f "$service_memory_migration"
|
|
mysql "$DB" < "$service_memory_migration"
|
|
mysql "$DB" < "$service_memory_migration"
|
|
service_memory_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_memory_candidate','aihr_assistant_capture','aihr_service_memory','aihr_service_memory_version');")"
|
|
test "$service_memory_tables" = 'aihr_assistant_capture,aihr_memory_candidate,aihr_service_memory,aihr_service_memory_version'
|
|
assistant_capture_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_assistant_capture' AND column_name IN ('save_scope','suggested_type','delivery_status','confirm_idempotency_key','confirm_request_hash');")"
|
|
test "$assistant_capture_columns" = '5'
|
|
service_memory_version_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND ((table_name = 'aihr_memory_candidate' AND column_name IN ('version','confirm_idempotency_key','confirm_request_hash','source_conversation_id','source_request_id')) OR (table_name = 'aihr_service_memory' AND column_name IN ('project_code','version')) OR (table_name = 'aihr_service_memory_version' AND column_name IN ('memory_id','version')));")"
|
|
test "$service_memory_version_columns" = '9'
|
|
|
|
work_assistant_results_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260721_work_assistant_results_mysql8.sql"
|
|
test -f "$work_assistant_results_migration"
|
|
mysql "$DB" < "$work_assistant_results_migration"
|
|
mysql "$DB" < "$work_assistant_results_migration"
|
|
work_assistant_result_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_assistant_capture_status_log','aihr_daily_work_result','aihr_knowledge_conversation');")"
|
|
test "$work_assistant_result_tables" = 'aihr_assistant_capture_status_log,aihr_daily_work_result,aihr_knowledge_conversation'
|
|
work_assistant_result_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND ((table_name = 'aihr_knowledge_conversation' AND column_name = 'project_code') OR (table_name = 'aihr_memory_candidate' AND column_name IN ('work_date','source_snapshot_json')) OR (table_name = 'aihr_assistant_capture' AND column_name IN ('work_date','business_status','source_snapshot_json')));")"
|
|
test "$work_assistant_result_columns" = '6'
|
|
work_assistant_snapshot_columns="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_daily_work_result' AND column_name='content_hash';")"
|
|
test "$work_assistant_snapshot_columns" = '1'
|
|
|
|
broadcast_question_context_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260722_broadcast_question_context_mysql8.sql"
|
|
test -f "$broadcast_question_context_migration"
|
|
mysql "$DB" < "$broadcast_question_context_migration"
|
|
mysql "$DB" < "$broadcast_question_context_migration"
|
|
broadcast_question_context_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_knowledge_conversation' AND column_name='broadcast_message_id';")"
|
|
test "$broadcast_question_context_columns" = 'broadcast_message_id'
|
|
broadcast_question_context_index="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_knowledge_conversation' AND index_name='idx_aihr_knowledge_conversation_broadcast';")"
|
|
test "$broadcast_question_context_index" = 'tenant_id,broadcast_message_id'
|
|
|
|
work_report_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260719_work_report_idempotency_mysql8.sql"
|
|
test -f "$work_report_migration"
|
|
mysql "$DB" < "$work_report_migration"
|
|
mysql "$DB" < "$work_report_migration"
|
|
work_report_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_work_report' AND column_name IN ('request_key','request_hash');")"
|
|
test "$work_report_columns" = 'request_key,request_hash'
|
|
work_report_unique_index="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_work_report' AND index_name='uk_aihr_work_report_request';")"
|
|
test "$work_report_unique_index" = 'tenant_id,submitter_user_id,request_key'
|
|
|
|
mysql "$DB" -e "ALTER TABLE aihr_work_report DROP INDEX uk_aihr_work_report_request, ADD INDEX uk_aihr_work_report_request (tenant_id, request_key(20), submitter_user_id);"
|
|
mysql "$DB" < "$work_report_migration"
|
|
work_report_repaired_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_work_report' AND index_name='uk_aihr_work_report_request';")"
|
|
test "$work_report_repaired_index" = '0|tenant_id,submitter_user_id,request_key|0'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
ALTER TABLE aihr_work_report
|
|
DROP INDEX uk_aihr_work_report_request,
|
|
ADD INDEX uk_aihr_work_report_request (tenant_id, request_key(20), submitter_user_id);
|
|
INSERT INTO aihr_work_report (
|
|
tenant_id, report_type, title, content, status,
|
|
submitter_user_id, request_key, request_hash
|
|
) VALUES
|
|
('000000', 'CASE', 'duplicate migration guard 1', 'content', 'PENDING', 1, 'duplicate-migration-guard', REPEAT('a', 64)),
|
|
('000000', 'CASE', 'duplicate migration guard 2', 'content', 'PENDING', 1, 'duplicate-migration-guard', REPEAT('b', 64));
|
|
SQL
|
|
if mysql "$DB" < "$work_report_migration" >/dev/null 2>&1; then
|
|
echo "FAIL: work-report migration must reject duplicate idempotency keys" >&2
|
|
exit 1
|
|
fi
|
|
work_report_failed_repair_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_work_report' AND index_name='uk_aihr_work_report_request';")"
|
|
test "$work_report_failed_repair_index" = '1|tenant_id,request_key,submitter_user_id|1'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
CREATE TABLE aihr_knowledge_info (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
tenant_id varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
CREATE TABLE aihr_knowledge_attach (
|
|
id bigint NOT NULL AUTO_INCREMENT,
|
|
tenant_id varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
|
knowledge_id bigint NOT NULL,
|
|
PRIMARY KEY (id)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
|
|
SQL
|
|
knowledge_category_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260722_knowledge_category_mysql8.sql"
|
|
test -f "$knowledge_category_migration"
|
|
mysql "$DB" < "$knowledge_category_migration"
|
|
mysql "$DB" < "$knowledge_category_migration"
|
|
knowledge_category_table="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$DB' AND table_name='aihr_knowledge_category';")"
|
|
test "$knowledge_category_table" = '1'
|
|
knowledge_category_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_knowledge_category' AND column_name IN ('tenant_id','knowledge_id','code','name','status','sort_order');")"
|
|
test "$knowledge_category_columns" = 'tenant_id,knowledge_id,code,name,status,sort_order'
|
|
knowledge_attach_category_column="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_knowledge_attach' AND column_name='category_id';")"
|
|
test "$knowledge_attach_category_column" = '1'
|
|
knowledge_attach_category_index="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY seq_in_index) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_knowledge_attach' AND index_name='idx_aihr_knowledge_attach_category';")"
|
|
test "$knowledge_attach_category_index" = 'tenant_id,knowledge_id,category_id'
|
|
knowledge_category_code_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_knowledge_category' AND index_name='uk_aihr_knowledge_category_code';")"
|
|
test "$knowledge_category_code_index" = '0|tenant_id,knowledge_id,code|0'
|
|
knowledge_category_collation="$(mysql "$DB" -N -B -e "SELECT table_collation FROM information_schema.tables WHERE table_schema='$DB' AND table_name='aihr_knowledge_category';")"
|
|
test "$knowledge_category_collation" = 'utf8mb4_general_ci'
|
|
|
|
broadcast_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260722_broadcast_mysql8.sql"
|
|
test -f "$broadcast_migration"
|
|
mysql "$DB" < "$broadcast_migration"
|
|
mysql "$DB" < "$broadcast_migration"
|
|
broadcast_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_broadcast_message','aihr_broadcast_read','aihr_broadcast_version');")"
|
|
test "$broadcast_tables" = 'aihr_broadcast_message,aihr_broadcast_read,aihr_broadcast_version'
|
|
broadcast_publish_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_broadcast_message' AND column_name IN ('publish_request_key','publish_request_hash','withdraw_reason');")"
|
|
test "$broadcast_publish_columns" = 'publish_request_key,publish_request_hash,withdraw_reason'
|
|
broadcast_publish_unique_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_message' AND index_name='uk_aihr_broadcast_message_publish_request';")"
|
|
test "$broadcast_publish_unique_index" = '0|tenant_id,published_by,publish_request_key|0'
|
|
broadcast_read_unique_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_read' AND index_name='uk_aihr_broadcast_read';")"
|
|
test "$broadcast_read_unique_index" = '0|tenant_id,message_id,user_id|0'
|
|
broadcast_version_unique_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_version' AND index_name='uk_aihr_broadcast_version';")"
|
|
test "$broadcast_version_unique_index" = '0|tenant_id,message_id,version|0'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
INSERT INTO aihr_broadcast_message (
|
|
tenant_id, title, content, status, published_by, published_time, create_time, update_time
|
|
) VALUES ('000000', 'legacy M0 targeting default', 'legacy content', 'PUBLISHED', 1, NOW(), NOW(), NOW());
|
|
SQL
|
|
|
|
broadcast_targeting_migration="$ROOT_DIR/backend/script/sql/update/aihr_20260723_broadcast_targeting_mysql8.sql"
|
|
test -f "$broadcast_targeting_migration"
|
|
mysql "$DB" < "$broadcast_targeting_migration"
|
|
mysql "$DB" < "$broadcast_targeting_migration"
|
|
broadcast_targeting_column_contract="$(mysql "$DB" -N -B -e "SELECT CONCAT(column_name,'|',column_type,'|',is_nullable,'|',COALESCE(column_default,'<NULL>')) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_broadcast_message' AND column_name IN ('required_read','target_payload_hash') ORDER BY FIELD(column_name,'required_read','target_payload_hash');")"
|
|
test "$broadcast_targeting_column_contract" = $'required_read|tinyint(1)|NO|0\ntarget_payload_hash|char(64)|YES|<NULL>'
|
|
broadcast_targeting_legacy_defaults="$(mysql "$DB" -N -B -e "SELECT CONCAT(required_read,'|',COALESCE(target_payload_hash,'NULL')) FROM aihr_broadcast_message WHERE title='legacy M0 targeting default';")"
|
|
test "$broadcast_targeting_legacy_defaults" = '0|NULL'
|
|
broadcast_targeting_tables="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(table_name ORDER BY table_name) FROM information_schema.tables WHERE table_schema='$DB' AND table_name IN ('aihr_broadcast_target_rule','aihr_broadcast_target_recipient');")"
|
|
test "$broadcast_targeting_tables" = 'aihr_broadcast_target_recipient,aihr_broadcast_target_rule'
|
|
broadcast_target_table_contract="$(mysql "$DB" -N -B -e "SELECT CONCAT(table_name,'.',column_name,'|',column_type,'|',is_nullable) FROM information_schema.columns WHERE table_schema='$DB' AND table_name IN ('aihr_broadcast_target_rule','aihr_broadcast_target_recipient') ORDER BY FIELD(table_name,'aihr_broadcast_target_rule','aihr_broadcast_target_recipient'), ordinal_position;")"
|
|
test "$broadcast_target_table_contract" = $'aihr_broadcast_target_rule.id|bigint|NO\naihr_broadcast_target_rule.tenant_id|varchar(20)|NO\naihr_broadcast_target_rule.message_id|bigint|NO\naihr_broadcast_target_rule.target_type|varchar(20)|NO\naihr_broadcast_target_rule.target_value|varchar(100)|NO\naihr_broadcast_target_rule.create_time|datetime|NO\naihr_broadcast_target_recipient.id|bigint|NO\naihr_broadcast_target_recipient.tenant_id|varchar(20)|NO\naihr_broadcast_target_recipient.message_id|bigint|NO\naihr_broadcast_target_recipient.recipient_key|varchar(180)|NO\naihr_broadcast_target_recipient.subject_ref|varchar(100)|NO\naihr_broadcast_target_recipient.user_id|bigint|YES\naihr_broadcast_target_recipient.target_status|varchar(20)|NO\naihr_broadcast_target_recipient.target_reason|varchar(100)|NO\naihr_broadcast_target_recipient.create_time|datetime|NO\naihr_broadcast_target_recipient.update_time|datetime|NO'
|
|
broadcast_target_rule_unique_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_target_rule' AND index_name='uk_aihr_broadcast_target_rule';")"
|
|
test "$broadcast_target_rule_unique_index" = '0|tenant_id,message_id,target_type,target_value|0'
|
|
broadcast_target_recipient_unique_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_target_recipient' AND index_name='uk_aihr_broadcast_target_recipient';")"
|
|
test "$broadcast_target_recipient_unique_index" = '0|tenant_id,message_id,recipient_key|0'
|
|
|
|
mysql "$DB" -e "ALTER TABLE aihr_broadcast_message DROP INDEX uk_aihr_broadcast_message_publish_request, DROP COLUMN publish_request_hash, DROP COLUMN publish_request_key, DROP COLUMN withdraw_reason;"
|
|
mysql "$DB" <<'SQL'
|
|
INSERT INTO aihr_broadcast_message (
|
|
tenant_id, title, content, status, published_by, published_time, create_time, update_time
|
|
) VALUES ('000000', 'legacy broadcast', 'legacy content', 'PUBLISHED', 1, NOW(), NOW(), NOW());
|
|
SQL
|
|
mysql "$DB" < "$broadcast_migration"
|
|
broadcast_legacy_snapshot_count="$(mysql "$DB" -N -B -e "SELECT COUNT(*) FROM aihr_broadcast_version v JOIN aihr_broadcast_message m ON m.tenant_id=v.tenant_id AND m.id=v.message_id WHERE m.title='legacy broadcast' AND v.\`version\`=1;")"
|
|
test "$broadcast_legacy_snapshot_count" = '1'
|
|
broadcast_legacy_columns="$(mysql "$DB" -N -B -e "SELECT GROUP_CONCAT(column_name ORDER BY ordinal_position) FROM information_schema.columns WHERE table_schema='$DB' AND table_name='aihr_broadcast_message' AND column_name IN ('publish_request_key','publish_request_hash','withdraw_reason');")"
|
|
test "$broadcast_legacy_columns" = 'publish_request_key,publish_request_hash,withdraw_reason'
|
|
|
|
mysql "$DB" -e "ALTER TABLE aihr_broadcast_message DROP INDEX uk_aihr_broadcast_message_publish_request, ADD INDEX uk_aihr_broadcast_message_publish_request (tenant_id, publish_request_key(20), published_by);"
|
|
mysql "$DB" < "$broadcast_migration"
|
|
broadcast_repaired_publish_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_message' AND index_name='uk_aihr_broadcast_message_publish_request';")"
|
|
test "$broadcast_repaired_publish_index" = '0|tenant_id,published_by,publish_request_key|0'
|
|
|
|
mysql "$DB" <<'SQL'
|
|
ALTER TABLE aihr_broadcast_message
|
|
DROP INDEX uk_aihr_broadcast_message_publish_request,
|
|
ADD INDEX uk_aihr_broadcast_message_publish_request (tenant_id, publish_request_key(20), published_by);
|
|
INSERT INTO aihr_broadcast_message (
|
|
tenant_id, title, content, status, published_by, published_time,
|
|
publish_request_key, publish_request_hash, create_time, update_time
|
|
) VALUES
|
|
('000000', 'duplicate publish guard 1', 'content', 'PUBLISHED', 1, NOW(),
|
|
'duplicate-publish-migration-guard', REPEAT('a', 64), NOW(), NOW()),
|
|
('000000', 'duplicate publish guard 2', 'content', 'PUBLISHED', 1, NOW(),
|
|
'duplicate-publish-migration-guard', REPEAT('b', 64), NOW(), NOW());
|
|
SQL
|
|
if mysql "$DB" < "$broadcast_migration" >/dev/null 2>&1; then
|
|
echo "FAIL: broadcast migration must reject duplicate publish idempotency keys" >&2
|
|
exit 1
|
|
fi
|
|
broadcast_failed_publish_index="$(mysql "$DB" -N -B -e "SELECT CONCAT(MIN(non_unique),'|',GROUP_CONCAT(column_name ORDER BY seq_in_index),'|',SUM(sub_part IS NOT NULL)) FROM information_schema.statistics WHERE table_schema='$DB' AND table_name='aihr_broadcast_message' AND index_name='uk_aihr_broadcast_message_publish_request';")"
|
|
test "$broadcast_failed_publish_index" = '1|tenant_id,publish_request_key,published_by|1'
|
|
|
|
echo "PASS: AIHR legacy schema migrations are idempotent, including knowledge-space categories, practice evidence, knowledge feedback, candidate interview review, position/SOP qualification contracts, assistant capture, work-report idempotency, broadcast publish/withdraw audit with M1 targeting defaults and target-table contracts, v1 snapshots, and trusted broadcast question context"
|