Files
banban/mini-program/database/sql/001_init_chat.sql
2026-03-26 09:53:09 +08:00

372 lines
9.0 KiB
SQL

-- Chat schema and seed data for mini-program
-- Target: MySQL 8+
CREATE DATABASE IF NOT EXISTS mini_program
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE mini_program;
SET FOREIGN_KEY_CHECKS=0;
DROP TABLE IF EXISTS chat_message;
DROP TABLE IF EXISTS chat_conversation_member;
DROP TABLE IF EXISTS chat_conversation;
DROP TABLE IF EXISTS chat_user_auth;
DROP TABLE IF EXISTS chat_user;
SET FOREIGN_KEY_CHECKS=1;
CREATE TABLE IF NOT EXISTS chat_user (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
nickname VARCHAR(64) NULL,
avatar_file_key VARCHAR(255) NULL COMMENT 'Stored file key, not URL',
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1-active 2-disabled 3-deleted',
last_login_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
KEY idx_status (status),
KEY idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS chat_user_auth (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT UNSIGNED NOT NULL,
auth_type TINYINT UNSIGNED NOT NULL COMMENT '1-wechat_miniapp_openid 2-wechat_unionid 3-phone_sms 4-email_magic_link 5-oauth 6-username_password',
auth_identifier VARCHAR(191) NOT NULL COMMENT 'openid/unionid/phone/email/oauth-sub/username',
password_hash CHAR(64) NULL COMMENT 'sha256 hex for demo only; production should use bcrypt/argon2',
credential_json JSON NULL COMMENT 'Extra auth payload, e.g. app_id/provider/phone_area',
is_primary TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1-primary login identity 0-secondary',
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1-active 2-disabled 3-revoked',
last_login_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_auth_type_identifier (auth_type, auth_identifier),
KEY idx_user_status (user_id, status),
KEY idx_last_login_at (last_login_at),
CONSTRAINT fk_user_auth_user
FOREIGN KEY (user_id) REFERENCES chat_user(id)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS chat_conversation (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
title VARCHAR(128) NULL,
conversation_type TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1-direct 2-group',
member_signature CHAR(64) NOT NULL COMMENT 'sha256 of sorted member user_ids, e.g. sha256("1,2")',
status TINYINT UNSIGNED NOT NULL DEFAULT 1 COMMENT '1-active 2-archived',
last_seq BIGINT UNSIGNED NOT NULL DEFAULT 0,
message_count BIGINT UNSIGNED NOT NULL DEFAULT 0,
last_message_preview VARCHAR(255) NULL,
last_message_at DATETIME(3) NULL,
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (id),
UNIQUE KEY uk_type_member_signature (conversation_type, member_signature),
KEY idx_last_message_at (last_message_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS chat_conversation_member (
conversation_id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED NOT NULL,
member_role TINYINT UNSIGNED NOT NULL DEFAULT 2 COMMENT '1-owner 2-member',
joined_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
left_at DATETIME(3) NULL,
PRIMARY KEY (conversation_id, user_id),
KEY idx_user_conversation (user_id, conversation_id),
CONSTRAINT fk_member_conv
FOREIGN KEY (conversation_id) REFERENCES chat_conversation(id)
ON DELETE CASCADE,
CONSTRAINT fk_member_user
FOREIGN KEY (user_id) REFERENCES chat_user(id)
ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS chat_message (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
conversation_id BIGINT UNSIGNED NOT NULL,
seq BIGINT UNSIGNED NOT NULL COMMENT 'Conversation-local incremental sequence',
sender_user_id BIGINT UNSIGNED NULL COMMENT 'Null means assistant/system sender',
role TINYINT UNSIGNED NOT NULL COMMENT '1-user 2-assistant 3-system 4-tool',
content_type TINYINT UNSIGNED NOT NULL COMMENT '1-text 2-audio 3-image 4-json',
content_text MEDIUMTEXT NULL,
content_json JSON NULL,
media_file_key VARCHAR(255) NULL COMMENT 'Stored file key, not URL',
media_duration_ms INT UNSIGNED NULL,
client_msg_id VARCHAR(64) NULL COMMENT 'Idempotency key from client',
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
deleted_at DATETIME(3) NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_conv_seq (conversation_id, seq),
UNIQUE KEY uk_conv_client_msg (conversation_id, client_msg_id),
KEY idx_conv_created (conversation_id, created_at),
KEY idx_sender_created (sender_user_id, created_at),
CONSTRAINT fk_msg_conv
FOREIGN KEY (conversation_id) REFERENCES chat_conversation(id)
ON DELETE CASCADE,
CONSTRAINT fk_msg_sender_user
FOREIGN KEY (sender_user_id) REFERENCES chat_user(id)
ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO chat_user (
id,
nickname,
avatar_file_key,
status,
last_login_at,
created_at,
updated_at
)
VALUES
(
1,
'Parent A',
'avatars/parent-a.png',
1,
'2026-03-25 09:58:00.000',
'2026-03-25 09:00:00.000',
'2026-03-25 09:58:00.000'
),
(
2,
'Parent B',
'avatars/parent-b.png',
1,
'2026-03-25 10:01:00.000',
'2026-03-25 09:20:00.000',
'2026-03-25 10:01:00.000'
),
(
3,
'Parent C',
'avatars/parent-c.png',
1,
'2026-03-25 21:11:00.000',
'2026-03-25 20:30:00.000',
'2026-03-25 21:11:00.000'
);
INSERT INTO chat_user_auth (
id,
user_id,
auth_type,
auth_identifier,
password_hash,
credential_json,
is_primary,
status,
last_login_at,
created_at,
updated_at
)
VALUES
(
1,
1,
6,
'test1',
SHA2('123', 256),
JSON_OBJECT('provider', 'local_account'),
1,
1,
'2026-03-25 09:58:00.000',
'2026-03-25 09:00:00.000',
'2026-03-25 09:58:00.000'
),
(
2,
2,
6,
'test2',
SHA2('123', 256),
JSON_OBJECT('provider', 'local_account'),
1,
1,
'2026-03-25 10:01:00.000',
'2026-03-25 09:20:00.000',
'2026-03-25 10:01:00.000'
),
(
3,
3,
6,
'test3',
SHA2('123', 256),
JSON_OBJECT('provider', 'local_account'),
1,
1,
'2026-03-25 21:11:00.000',
'2026-03-25 20:30:00.000',
'2026-03-25 21:11:00.000'
);
INSERT INTO chat_conversation (
id,
title,
conversation_type,
member_signature,
status,
last_seq,
message_count,
last_message_preview,
last_message_at,
created_at,
updated_at
)
VALUES
(
1,
'Direct Chat',
1,
'17f8af97ad4a7f7639a4c9171d5185cbafb85462877a4746c21bdb0a4f940ca0',
1,
4,
4,
'user: Great, explain how to solve it.',
'2026-03-25 10:00:30.000',
'2026-03-25 10:00:00.000',
'2026-03-25 10:00:30.000'
),
(
2,
'Family Group',
2,
'8a6ae15122001229edb8866f56e342af12ae8187203c3e3b33931743e7c0c48d',
1,
3,
3,
'user: Okay, we will wait in the living room.',
'2026-03-25 21:16:10.000',
'2026-03-25 21:15:00.000',
'2026-03-25 21:16:10.000'
);
INSERT INTO chat_conversation_member (
conversation_id,
user_id,
member_role,
joined_at,
left_at
)
VALUES
(1, 1, 1, '2026-03-25 10:00:00.000', NULL),
(1, 2, 2, '2026-03-25 10:00:00.000', NULL),
(2, 1, 1, '2026-03-25 21:15:00.000', NULL),
(2, 2, 2, '2026-03-25 21:15:00.000', NULL),
(2, 3, 2, '2026-03-25 21:15:00.000', NULL);
INSERT INTO chat_message (
id,
conversation_id,
seq,
sender_user_id,
role,
content_type,
content_text,
content_json,
media_file_key,
media_duration_ms,
client_msg_id,
created_at
)
VALUES
(
1001,
1,
1,
1,
1,
1,
'Hi, did you finish homework?',
JSON_OBJECT('lang', 'en'),
NULL,
NULL,
'c1-m1',
'2026-03-25 10:00:05.000'
),
(
1002,
1,
2,
2,
1,
1,
'Almost done, one question left.',
JSON_OBJECT('lang', 'en'),
NULL,
NULL,
'c1-m2',
'2026-03-25 10:00:12.000'
),
(
1003,
1,
3,
NULL,
2,
1,
'I can help explain the last question.',
JSON_OBJECT('tone', 'assistant'),
NULL,
NULL,
'c1-m3',
'2026-03-25 10:00:20.000'
),
(
1004,
1,
4,
1,
1,
1,
'Great, explain how to solve it.',
JSON_OBJECT('lang', 'en'),
NULL,
NULL,
'c1-m4',
'2026-03-25 10:00:30.000'
),
(
2001,
2,
1,
1,
1,
1,
'Dinner at 7?',
JSON_OBJECT('lang', 'en'),
NULL,
NULL,
'c2-m1',
'2026-03-25 21:15:08.000'
),
(
2002,
2,
2,
3,
1,
2,
NULL,
JSON_OBJECT('note', 'voice message'),
'audios/family-group-001.mp3',
95000,
'c2-m2',
'2026-03-25 21:15:30.000'
),
(
2003,
2,
3,
2,
1,
1,
'Okay, we will wait in the living room.',
JSON_OBJECT('lang', 'en'),
NULL,
NULL,
'c2-m3',
'2026-03-25 21:16:10.000'
);