-- New tables per design.md -- Supports both MySQL and SQLite -- parents table 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), 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 ); -- SQLite uses TRIGGER for updated_at, MySQL uses ON UPDATE -- For SQLite compatibility, we'll handle in app layer CREATE INDEX IF NOT EXISTS idx_parents_unionid ON parents(unionid); CREATE INDEX IF NOT EXISTS idx_parents_phone ON parents(phone); -- children table 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 ); -- parent_child_relations table 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, UNIQUE (user_id, child_id) ); -- device_bindings table CREATE TABLE IF NOT EXISTS device_bindings ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL, child_id BIGINT NOT NULL, 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, UNIQUE (device_id), UNIQUE (child_id) ); -- device_bind_sessions table 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 ); -- device_bind_history table CREATE TABLE IF NOT EXISTS device_bind_history ( id BIGINT PRIMARY KEY AUTO_INCREMENT, device_id VARCHAR(64) NOT NULL, child_id BIGINT NOT NULL, 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 ); -- cards table 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 ); -- device_settings table 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 ); -- im_conversations table 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, UNIQUE (conversation_type, pair_key) ); CREATE INDEX IF NOT EXISTS idx_im_conv_participant_a ON im_conversations(participant_a_type, participant_a_id); CREATE INDEX IF NOT EXISTS idx_im_conv_participant_b ON im_conversations(participant_b_type, participant_b_id); CREATE INDEX IF NOT EXISTS idx_im_conv_last_message_at ON im_conversations(last_message_at); -- im_messages table 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, UNIQUE (conversation_id, seq), UNIQUE (conversation_id, client_msg_id) ); CREATE INDEX IF NOT EXISTS idx_im_msg_sender ON im_messages(sender_type, sender_id, created_at); CREATE INDEX IF NOT EXISTS idx_im_msg_receiver ON im_messages(receiver_type, receiver_id, created_at); -- child_location_current table 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 ); -- child_location_history table 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 ); CREATE INDEX IF NOT EXISTS idx_child_loc_hist_child ON child_location_history(child_id, created_at);