-- Current MySQL schema for mini-program CREATE DATABASE IF NOT EXISTS mini_program DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE mini_program; -- parents CREATE TABLE IF NOT EXISTS parents ( user_id BIGINT PRIMARY KEY AUTO_INCREMENT, openid VARCHAR(64) UNIQUE NOT NULL, unionid VARCHAR(64), nickname VARCHAR(64), avatar_url VARCHAR(255), avatar_file_key VARCHAR(255), phone VARCHAR(20), status TINYINT NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE INDEX idx_parents_unionid ON parents(unionid); CREATE INDEX idx_parents_phone ON parents(phone); -- children CREATE TABLE IF NOT EXISTS children ( child_id BIGINT PRIMARY KEY AUTO_INCREMENT, child_name VARCHAR(32) NOT NULL, child_gender TINYINT NOT NULL DEFAULT 2, child_birthday DATE, status TINYINT NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- parent_child_relations CREATE TABLE IF NOT EXISTS parent_child_relations ( id BIGINT PRIMARY KEY AUTO_INCREMENT, user_id BIGINT NOT NULL, child_id BIGINT NOT NULL, relation_type TINYINT NOT NULL DEFAULT 9, is_primary TINYINT(1) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 1, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_user_child UNIQUE (user_id, child_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE INDEX idx_pcr_user_id ON parent_child_relations(user_id); CREATE INDEX idx_pcr_child_id ON parent_child_relations(child_id); -- device_bindings CREATE TABLE IF NOT EXISTS device_bindings ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL, owner_user_id BIGINT NOT NULL, child_id BIGINT, status TINYINT NOT NULL DEFAULT 1, bound_at DATETIME NOT NULL, unbound_at DATETIME, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_device_binding_device UNIQUE (device_id), CONSTRAINT uq_device_binding_child UNIQUE (child_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE INDEX idx_device_bindings_owner_user_id ON device_bindings(owner_user_id); -- device_bind_sessions CREATE TABLE IF NOT EXISTS device_bind_sessions ( id BIGINT PRIMARY KEY AUTO_INCREMENT, bind_token CHAR(36) UNIQUE NOT NULL, device_id VARCHAR(64) NOT NULL, initiator_user_id BIGINT NOT NULL, target_child_id BIGINT, challenge_code_hash CHAR(64), challenge_set_at DATETIME, expires_at DATETIME NOT NULL, max_attempt_count TINYINT UNSIGNED NOT NULL DEFAULT 5, attempt_count TINYINT UNSIGNED NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 1, confirmed_at DATETIME, consumed_at DATETIME, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- device_bind_history CREATE TABLE IF NOT EXISTS device_bind_history ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL, child_id BIGINT, bound_by_user_id BIGINT NOT NULL, unbound_by_user_id BIGINT, bind_source TINYINT NOT NULL DEFAULT 1, bound_at DATETIME NOT NULL, unbound_at DATETIME, unbind_reason VARCHAR(191), created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- cards CREATE TABLE IF NOT EXISTS cards ( card_id BIGINT PRIMARY KEY AUTO_INCREMENT, card_uuid VARCHAR(64) UNIQUE NOT NULL, device_id VARCHAR(64) UNIQUE, card_name VARCHAR(64), status TINYINT NOT NULL DEFAULT 0, total_swaps INT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- device_settings CREATE TABLE IF NOT EXISTS device_settings ( setting_id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL UNIQUE, sleep_mode TINYINT NOT NULL DEFAULT 0, disable_time_start TIME, disable_time_end TIME, timezone VARCHAR(32) NOT NULL DEFAULT 'Asia/Shanghai', volume TINYINT UNSIGNED, brightness TINYINT UNSIGNED, disable_weekdays VARCHAR(32), created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- im_conversations CREATE TABLE IF NOT EXISTS im_conversations ( id BIGINT PRIMARY KEY AUTO_INCREMENT, conversation_type TINYINT UNSIGNED NOT NULL, participant_a_type TINYINT UNSIGNED NOT NULL, participant_a_id VARCHAR(64) NOT NULL, participant_b_type TINYINT UNSIGNED NOT NULL, participant_b_id VARCHAR(64) NOT NULL, pair_key VARCHAR(191) NOT NULL, status TINYINT NOT NULL DEFAULT 1, last_seq BIGINT UNSIGNED NOT NULL DEFAULT 0, message_count BIGINT UNSIGNED NOT NULL DEFAULT 0, last_message_preview VARCHAR(255), last_message_at DATETIME, ext_json JSON, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT uq_conv_type_pair UNIQUE (conversation_type, pair_key) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE INDEX idx_im_conv_participant_a ON im_conversations(participant_a_type, participant_a_id); CREATE INDEX idx_im_conv_participant_b ON im_conversations(participant_b_type, participant_b_id); CREATE INDEX idx_im_conv_last_message_at ON im_conversations(last_message_at); -- im_messages CREATE TABLE IF NOT EXISTS im_messages ( id BIGINT PRIMARY KEY AUTO_INCREMENT, conversation_id BIGINT UNSIGNED NOT NULL, seq BIGINT UNSIGNED NOT NULL, sender_type TINYINT UNSIGNED NOT NULL, sender_id VARCHAR(64) NOT NULL, receiver_type TINYINT UNSIGNED NOT NULL, receiver_id VARCHAR(64) NOT NULL, content_type TINYINT UNSIGNED NOT NULL, content_text MEDIUMTEXT, content_json JSON, media_file_key VARCHAR(255), media_duration_ms INT UNSIGNED, media_mime_type VARCHAR(64), media_size_bytes BIGINT UNSIGNED, media_transcript_text TEXT, client_msg_id VARCHAR(64), sender_name_snapshot VARCHAR(64), sender_avatar_snapshot VARCHAR(255), receiver_name_snapshot VARCHAR(64), receiver_avatar_snapshot VARCHAR(255), ext_json JSON, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, deleted_at DATETIME, CONSTRAINT uq_im_msg_conv_seq UNIQUE (conversation_id, seq), CONSTRAINT uq_im_msg_client UNIQUE (conversation_id, client_msg_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE INDEX idx_im_msg_sender ON im_messages(sender_type, sender_id, created_at); CREATE INDEX idx_im_msg_receiver ON im_messages(receiver_type, receiver_id, created_at); -- child_location_current CREATE TABLE IF NOT EXISTS child_location_current ( child_id BIGINT UNSIGNED PRIMARY KEY, device_id VARCHAR(64) NOT NULL, coord_type VARCHAR(16) NOT NULL DEFAULT 'gcj02', lat DECIMAL(10,7) NOT NULL, lng DECIMAL(10,7) NOT NULL, accuracy_m INT UNSIGNED, altitude_m DECIMAL(8,2), speed_mps DECIMAL(8,2), heading_deg SMALLINT UNSIGNED, source TINYINT UNSIGNED NOT NULL, battery_pct TINYINT UNSIGNED, device_time DATETIME NOT NULL, server_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- child_location_history CREATE TABLE IF NOT EXISTS child_location_history ( id BIGINT PRIMARY KEY AUTO_INCREMENT, child_id BIGINT UNSIGNED NOT NULL, device_id VARCHAR(64) NOT NULL, coord_type VARCHAR(16) NOT NULL DEFAULT 'gcj02', lat DECIMAL(10,7) NOT NULL, lng DECIMAL(10,7) NOT NULL, accuracy_m INT UNSIGNED, altitude_m DECIMAL(8,2), speed_mps DECIMAL(8,2), heading_deg SMALLINT UNSIGNED, source TINYINT UNSIGNED NOT NULL, battery_pct TINYINT UNSIGNED, device_time DATETIME NOT NULL, server_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE INDEX idx_child_loc_hist_child ON child_location_history(child_id, created_at);