1111
IT-0 verify / verify (push) Waiting to run

This commit is contained in:
zfjia committed 2026-11-11 18:30:31 +08:00
1 parent 417c076465
commit 35751b4f00
144 files changed
+13905 -342

No files matched your search

+156
View File
@@ -0,0 +1,156 @@
-- =============================================================================
-- AMI 连接与语音链路增量(一公寓一 Asterisk 实例)
-- 依据:公寓端/19 设计文档;公寓端/05 表 5-12(SIP 叫乘链路)、表 5-13(AMI 事件映射);
-- docs/10 表 8-3(AMI 不出本机)、表 8-4(端口 7058)、D5(一进程一 gyid)
-- 口径:
-- 1) 新增 1 张映射表 apt_ast_instance:gyid 唯一 -> 一公寓一实例(UK 兜底)。
-- 这是对「59 张表」基线的显式偏离,已在公寓端/19 §7 登记(新增第 60 张)。
-- 2) AMI 口令**不落库**:只存环境变量引用 ami_secret_ref(红钱:口令不进仓库)。
-- 3) 复用既有 apt_ast_ami_session / apt_call_session / apt_call_event /
-- apt_tts_utterance / apt_recording,仅补列,不新建语音表。
-- 4) 幂等:建表 IF NOT EXISTS,补列走 apt_add_column_if_missing。
-- =============================================================================
SET NAMES utf8mb4;
-- -----------------------------------------------------------------------------
-- 1. 公寓 ↔ Asterisk 实例映射(1:1)
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS apt_ast_instance (
id BIGINT NOT NULL AUTO_INCREMENT COMMENT '代理主键',
gyid VARCHAR(32) NOT NULL COMMENT '公寓隔离标识(D5:一进程一 gyid)',
instance_code VARCHAR(64) NOT NULL COMMENT '实例编码,如 AST-REV01-001',
display_name VARCHAR(64) NULL COMMENT '展示名,如 1 号楼机房 Asterisk',
ami_host VARCHAR(128) NOT NULL COMMENT 'AMI 地址;生产固定 127.0.0.1(AMI 不出本机)',
ami_port INT NOT NULL DEFAULT 5038 COMMENT 'AMI 端口;现网配置值 7058',
ami_user VARCHAR(64) NOT NULL COMMENT 'AMI 账号',
ami_secret_ref VARCHAR(128) NOT NULL COMMENT '口令引用(环境变量名),禁止存明文',
tls_enabled TINYINT NOT NULL DEFAULT 0 COMMENT '0 明文 / 1 TLS(TLS 端口另配)',
conference VARCHAR(64) NOT NULL DEFAULT 'Conf-01' COMMENT '会议桥标识(D11 未定前不改)',
dial_context VARCHAR(64) NOT NULL DEFAULT 'from-internal' COMMENT '拨号计划上下文',
dial_prefix VARCHAR(16) NULL COMMENT '外呼前缀(如 9),本地分机为空',
channel_tech VARCHAR(16) NOT NULL DEFAULT 'PJSIP' COMMENT '话机通道技术:PJSIP / SIP',
recording_base_url VARCHAR(256) NULL COMMENT '录音 HTTP 基址(只对内网)',
connect_timeout_ms INT NOT NULL DEFAULT 3000 COMMENT 'TCP 建连超时',
action_timeout_ms INT NOT NULL DEFAULT 5000 COMMENT 'AMI Action 等待 Response 超时',
ping_interval_sec INT NOT NULL DEFAULT 30 COMMENT '心跳间隔(Action: Ping)',
ping_timeout_sec INT NOT NULL DEFAULT 5 COMMENT '单次心跳超时',
reconnect_initial_ms INT NOT NULL DEFAULT 1000 COMMENT '重连初始退避',
reconnect_max_ms INT NOT NULL DEFAULT 60000 COMMENT '重连最大退避(封顶)',
state VARCHAR(20) NOT NULL DEFAULT 'DOWN' COMMENT 'DOWN/CONNECTING/UP/DEGRADED/DISABLED',
last_connected_at DATETIME(3) NULL COMMENT '最近登录成功时刻',
last_ping_at DATETIME(3) NULL COMMENT '最近心跳成功时刻',
last_error VARCHAR(256) NULL COMMENT '最近一次失败原因(脱敏,不含口令)',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '0 停用(不建连、不叫乘)',
biz_version BIGINT NOT NULL DEFAULT 1 COMMENT '数据库条件更新乐观锁',
deleted TINYINT NOT NULL DEFAULT 0,
create_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
update_time DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_astinstance_gyid (gyid),
KEY idx_astinstance_gyid_state (gyid, state, enabled),
CONSTRAINT ck_astinstance_state CHECK (state IN ('DOWN','CONNECTING','UP','DEGRADED','DISABLED')),
CONSTRAINT ck_astinstance_enabled CHECK (enabled IN (0,1))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
COMMENT='公寓-Asterisk 实例映射与 AMI 连接配置(一公寓一实例)';
-- 默认实例:只写占位地址与口令引用,口令由部署环境 APT_AMI_SECRET 注入
INSERT INTO apt_ast_instance
(gyid, instance_code, display_name, ami_host, ami_port, ami_user, ami_secret_ref,
conference, dial_context, state, enabled, create_time, update_time)
SELECT 'APT-REV01-001', 'AST-REV01-001', '本机 Asterisk(AMI 仅本机)',
'127.0.0.1', 5038, 'apt', 'APT_AMI_SECRET',
'Conf-01', 'from-internal', 'DOWN', 1, NOW(3), NOW(3)
WHERE NOT EXISTS (
SELECT 1 FROM apt_ast_instance WHERE gyid = 'APT-REV01-001' AND deleted = 0
);
-- -----------------------------------------------------------------------------
-- 2. AMI 会话补列:心跳与断连原因(表已有 connected_at/disconnected_at/reconnect_count/state)
-- -----------------------------------------------------------------------------
CALL apt_add_column_if_missing('apt_ast_ami_session', 'last_ping_at',
"last_ping_at DATETIME(3) NULL COMMENT '最近心跳成功时刻'");
CALL apt_add_column_if_missing('apt_ast_ami_session', 'last_error',
"last_error VARCHAR(256) NULL COMMENT '本次连接断开的失败原因(脱敏)'");
CALL apt_add_column_if_missing('apt_ast_ami_session', 'close_reason',
"close_reason VARCHAR(64) NULL COMMENT 'CLIENT_CLOSE / IO_ERROR / PING_TIMEOUT / AUTH_FAILED / SHUTDOWN'");
-- -----------------------------------------------------------------------------
-- 3. 通话会话补列:双腿(房间/值班台)与通道映射
-- -----------------------------------------------------------------------------
CALL apt_add_column_if_missing('apt_call_session', 'leg_role',
"leg_role VARCHAR(16) NOT NULL DEFAULT 'ROOM' COMMENT '腿角色:ROOM 房间 / DUTY 值班台 / TTS 播报'");
CALL apt_add_column_if_missing('apt_call_session', 'channel',
"channel VARCHAR(128) NULL COMMENT 'AMI Channel(PJSIP/1001-00000001),事件反查用'");
CALL apt_add_column_if_missing('apt_call_session', 'originate_action_id',
"originate_action_id VARCHAR(64) NULL COMMENT 'Originate ActionID,OriginateResponse 关联用'");
CALL apt_add_column_if_missing('apt_call_session', 'ami_session_id',
"ami_session_id VARCHAR(64) NULL COMMENT '所属 AMI 连接会话(apt_ast_ami_session.ami_session_id)'");
-- -----------------------------------------------------------------------------
-- 4. TTS 播报补列:与会话/序号绑定,避免并发时互相覆盖(docs/10 表 10-13 TTS 槽位风险)
-- -----------------------------------------------------------------------------
CALL apt_add_column_if_missing('apt_tts_utterance', 'session_id',
"session_id VARCHAR(64) NULL COMMENT '关联会话;一次入会一条播报链'");
CALL apt_add_column_if_missing('apt_tts_utterance', 'utterance_seq',
"utterance_seq BIGINT NOT NULL DEFAULT 1 COMMENT '同会话单调递增,禁止共用槽位'");
CALL apt_add_column_if_missing('apt_tts_utterance', 'played_at',
"played_at DATETIME(3) NULL COMMENT '播放完成时刻'");
CALL apt_add_column_if_missing('apt_tts_utterance', 'error_msg',
"error_msg VARCHAR(256) NULL COMMENT '失败原因(不改叫乘结论,只告警)'");
-- 会话按通道反查(事件热点路径)
SET @apt_idx_channel = (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_call_session'
AND INDEX_NAME = 'idx_callsession_gyid_channel');
SET @apt_sql_channel = IF(@apt_idx_channel = 0,
'ALTER TABLE apt_call_session ADD KEY idx_callsession_gyid_channel (gyid, channel)',
'SELECT 1');
PREPARE apt_stmt_channel FROM @apt_sql_channel;
EXECUTE apt_stmt_channel;
DEALLOCATE PREPARE apt_stmt_channel;
SET @apt_idx_action = (SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_call_session'
AND INDEX_NAME = 'idx_callsession_gyid_action');
SET @apt_sql_action = IF(@apt_idx_action = 0,
'ALTER TABLE apt_call_session ADD KEY idx_callsession_gyid_action (gyid, originate_action_id)',
'SELECT 1');
PREPARE apt_stmt_action FROM @apt_sql_action;
EXECUTE apt_stmt_action;
DEALLOCATE PREPARE apt_stmt_action;
-- -----------------------------------------------------------------------------
-- 5. 校验
-- -----------------------------------------------------------------------------
SELECT '=== 27. 公寓-实例映射(应 1 行,一公寓一实例)===' AS section;
SELECT gyid, instance_code, ami_host, ami_port, ami_user, ami_secret_ref,
conference, dial_context, state, enabled
FROM apt_ast_instance WHERE deleted = 0 ORDER BY gyid;
SELECT '=== 28. 口令不落明文(应 0:secret_ref 不得是疑似明文口令)===' AS section;
SELECT COUNT(*) AS plaintext_secret_rows
FROM apt_ast_instance
WHERE deleted = 0
AND (ami_secret_ref LIKE '% %' OR ami_secret_ref LIKE '%.%' OR CHAR_LENGTH(ami_secret_ref) > 64);
SELECT '=== 29. AMI 会话补列(应 3)===' AS section;
SELECT COUNT(*) AS ami_session_columns
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_ast_ami_session'
AND COLUMN_NAME IN ('last_ping_at','last_error','close_reason');
SELECT '=== 30. 会话/TTS 补列(应 8:call_session 4 + tts 4)===' AS section;
SELECT COUNT(*) AS call_tts_columns
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND ((TABLE_NAME = 'apt_call_session'
AND COLUMN_NAME IN ('leg_role','channel','originate_action_id','ami_session_id'))
OR (TABLE_NAME = 'apt_tts_utterance'
AND COLUMN_NAME IN ('session_id','utterance_seq','played_at','error_msg')));
SELECT '=== 31. 会话索引(应 2)===' AS section;
SELECT INDEX_NAME, GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS cols
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'apt_call_session'
AND INDEX_NAME IN ('idx_callsession_gyid_channel','idx_callsession_gyid_action')
GROUP BY INDEX_NAME;