-- Banban shared schema -- Sources: -- 1. talkingq-url/mysql/init/01-init.sql -- 2. mini-program/database/init.sql -- Target database: talkingq -- -- Notes: -- 1. talkingq-url base tables are kept as the device-domain foundation. -- 2. mini-program business tables are merged into the same database. -- 3. device_auth.device_id is the shared device identity key. -- 4. Device <-> AI conversation records remain in -- conversation_histories / conversation_messages. -- 5. The database owner is shared, but table ownership is explicit: -- talkingq-url owns device-domain base tables; mini-program owns -- parent/child/binding/im/location extension tables. -- 6. During migration to the shared database, talkingq-url data in -- `talkingq` is the source of truth. Legacy `mini_program` data is -- not merged into `talkingq`. CREATE DATABASE IF NOT EXISTS `talkingq` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE `talkingq`; -- --------------------------------------------------------------------------- -- talkingq-url base tables -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `device_configs` ( `id` INT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `selected_role_key` VARCHAR(64) NOT NULL, `preferred_language` VARCHAR(10) NULL, `volume` INT NULL, `last_update_time` FLOAT NOT NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE INDEX `device_id_UNIQUE` (`device_id` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `conversation_histories` ( `id` INT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `role_key` VARCHAR(64) NOT NULL, `last_interaction_time` FLOAT NOT NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_device_id` (`device_id` ASC), INDEX `idx_role_key` (`role_key` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `conversation_messages` ( `id` INT NOT NULL AUTO_INCREMENT, `conversation_id` INT NOT NULL, `is_user` TINYINT(1) NOT NULL DEFAULT 0, `content` TEXT NOT NULL, `timestamp` FLOAT NOT NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), INDEX `idx_conversation_id` (`conversation_id` ASC), CONSTRAINT `fk_messages_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `conversation_histories` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `roles` ( `id` INT NOT NULL AUTO_INCREMENT, `role_key` VARCHAR(64) NOT NULL, `name` VARCHAR(128) NOT NULL, `description` TEXT NULL, `content` TEXT NOT NULL, `default_language` VARCHAR(10) NULL, `asr_provider` VARCHAR(64) NULL, `llm_provider` VARCHAR(64) NULL, `tts_provider` VARCHAR(64) NULL, `competitive_llm_mode` TINYINT(1) NULL, `volcano_model_id` VARCHAR(64) NULL, `volcano_voice_type` VARCHAR(64) NULL, `tencent_voice_type` VARCHAR(64) NULL, `aliyun_voice_name` VARCHAR(64) NULL, `minimax_voice_id` VARCHAR(64) NULL, `url` VARCHAR(255) NULL, `homophones` JSON NULL, `enabled` TINYINT(1) NOT NULL DEFAULT 1, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE INDEX `role_key_UNIQUE` (`role_key` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `role_languages` ( `id` INT NOT NULL AUTO_INCREMENT, `role_id` INT NOT NULL, `language_code` VARCHAR(10) NOT NULL, `name` VARCHAR(128) NULL, `content` TEXT NULL, `asr_provider` VARCHAR(64) NULL, `llm_provider` VARCHAR(64) NULL, `tts_provider` VARCHAR(64) NULL, `volcano_voice_type` VARCHAR(64) NULL, `tencent_voice_type` VARCHAR(64) NULL, `aliyun_voice_name` VARCHAR(64) NULL, `minimax_voice_id` VARCHAR(64) NULL, `url` VARCHAR(255) NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE INDEX `uix_role_language` (`role_id`, `language_code`), CONSTRAINT `fk_role_languages_role` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `device_auth` ( `id` INT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `serial_number` VARCHAR(64) NOT NULL, `batch_id` VARCHAR(20) NULL, `is_active` TINYINT(1) NOT NULL DEFAULT 1, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE INDEX `device_id_UNIQUE` (`device_id` ASC), INDEX `idx_batch_id` (`batch_id` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `device_firmware_update` ( `id` INT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `serial_number` VARCHAR(64) NOT NULL, `mac_address` VARCHAR(512) NULL, `firmware_version` VARCHAR(64) NOT NULL, `update_status` VARCHAR(32) NOT NULL DEFAULT 'success', `progress` FLOAT NULL DEFAULT 0.0, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE INDEX `device_id_UNIQUE` (`device_id` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `system_config` ( `id` INT NOT NULL AUTO_INCREMENT, `config_key` VARCHAR(128) NOT NULL, `config_value` TEXT NULL, `description` VARCHAR(255) NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE INDEX `config_key_UNIQUE` (`config_key` ASC) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO `device_configs` (`device_id`, `selected_role_key`, `preferred_language`, `last_update_time`) VALUES ('default', 'assistant', 'zh', UNIX_TIMESTAMP()) ON DUPLICATE KEY UPDATE `selected_role_key` = `selected_role_key`; INSERT INTO `system_config` (`config_key`, `config_value`, `description`) VALUES ('latest_firmware_version', '1.0.0', '最新固件版本'), ('update_firmware_url', 'https://example.com/firmware/latest.bin', '固件更新URL') ON DUPLICATE KEY UPDATE `config_value` = `config_value`; INSERT INTO `roles` (`role_key`, `name`, `description`, `content`, `default_language`, `enabled`) VALUES ( 'assistant', '智能助手', '默认智能助手角色', '你是一个友好的智能助手,乐于帮助用户解答问题。', 'zh', 1 ) ON DUPLICATE KEY UPDATE `role_key` = `role_key`; -- --------------------------------------------------------------------------- -- mini-program extension tables -- --------------------------------------------------------------------------- CREATE TABLE IF NOT EXISTS `parents` ( `user_id` BIGINT NOT NULL AUTO_INCREMENT, `openid` VARCHAR(64) NOT NULL, `unionid` VARCHAR(64) NULL, `nickname` VARCHAR(64) NULL, `avatar_url` VARCHAR(255) NULL, `avatar_file_key` VARCHAR(255) NULL, `phone` VARCHAR(20) NULL, `status` TINYINT NOT NULL DEFAULT 1, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`user_id`), UNIQUE KEY `uq_parents_openid` (`openid`), KEY `idx_parents_unionid` (`unionid`), KEY `idx_parents_phone` (`phone`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `children` ( `child_id` BIGINT NOT NULL AUTO_INCREMENT, `child_name` VARCHAR(32) NOT NULL, `child_gender` TINYINT NOT NULL DEFAULT 2, `child_birthday` DATE NULL, `status` TINYINT NOT NULL DEFAULT 1, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`child_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `parent_child_relations` ( `id` BIGINT NOT NULL 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 ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), CONSTRAINT `uq_user_child` UNIQUE (`user_id`, `child_id`), KEY `idx_pcr_user_id` (`user_id`), KEY `idx_pcr_child_id` (`child_id`), CONSTRAINT `fk_pcr_user` FOREIGN KEY (`user_id`) REFERENCES `parents` (`user_id`) ON DELETE CASCADE, CONSTRAINT `fk_pcr_child` FOREIGN KEY (`child_id`) REFERENCES `children` (`child_id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `device_bindings` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `owner_user_id` BIGINT NOT NULL, `child_id` BIGINT NULL, `status` TINYINT NOT NULL DEFAULT 1, `bound_at` DATETIME NOT NULL, `unbound_at` DATETIME NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), CONSTRAINT `uq_device_binding_device` UNIQUE (`device_id`), CONSTRAINT `uq_device_binding_child` UNIQUE (`child_id`), KEY `idx_device_bindings_owner_user_id` (`owner_user_id`), CONSTRAINT `fk_device_bindings_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`), CONSTRAINT `fk_device_bindings_owner` FOREIGN KEY (`owner_user_id`) REFERENCES `parents` (`user_id`), CONSTRAINT `fk_device_bindings_child` FOREIGN KEY (`child_id`) REFERENCES `children` (`child_id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `device_bind_sessions` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `bind_token` CHAR(36) NOT NULL, `device_id` VARCHAR(64) NOT NULL, `initiator_user_id` BIGINT NOT NULL, `target_child_id` BIGINT NULL, `challenge_code_hash` CHAR(64) NULL, `challenge_set_at` DATETIME NULL, `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 NULL, `consumed_at` DATETIME NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uq_device_bind_sessions_token` (`bind_token`), KEY `idx_device_bind_sessions_device_id` (`device_id`), KEY `idx_device_bind_sessions_initiator_user_id` (`initiator_user_id`), KEY `idx_device_bind_sessions_target_child_id` (`target_child_id`), KEY `idx_device_bind_sessions_expires_at` (`expires_at`), CONSTRAINT `fk_device_bind_sessions_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`), CONSTRAINT `fk_device_bind_sessions_initiator` FOREIGN KEY (`initiator_user_id`) REFERENCES `parents` (`user_id`), CONSTRAINT `fk_device_bind_sessions_target_child` FOREIGN KEY (`target_child_id`) REFERENCES `children` (`child_id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `device_bind_history` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `child_id` BIGINT NULL, `bound_by_user_id` BIGINT NOT NULL, `unbound_by_user_id` BIGINT NULL, `bind_source` TINYINT NOT NULL DEFAULT 1, `bound_at` DATETIME NOT NULL, `unbound_at` DATETIME NULL, `unbind_reason` VARCHAR(191) NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_device_bind_history_device_id` (`device_id`), KEY `idx_device_bind_history_child_id` (`child_id`), KEY `idx_device_bind_history_bound_by_user_id` (`bound_by_user_id`), KEY `idx_device_bind_history_unbound_by_user_id` (`unbound_by_user_id`), KEY `idx_device_bind_history_bound_at` (`bound_at`), CONSTRAINT `fk_device_bind_history_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`), CONSTRAINT `fk_device_bind_history_child` FOREIGN KEY (`child_id`) REFERENCES `children` (`child_id`) ON DELETE SET NULL, CONSTRAINT `fk_device_bind_history_bound_by` FOREIGN KEY (`bound_by_user_id`) REFERENCES `parents` (`user_id`), CONSTRAINT `fk_device_bind_history_unbound_by` FOREIGN KEY (`unbound_by_user_id`) REFERENCES `parents` (`user_id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `cards` ( `card_id` BIGINT NOT NULL AUTO_INCREMENT, `card_uuid` VARCHAR(64) NOT NULL, `device_id` VARCHAR(64) NULL, `card_name` VARCHAR(64) NULL, `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 ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`card_id`), UNIQUE KEY `uq_cards_card_uuid` (`card_uuid`), UNIQUE KEY `uq_cards_device_id` (`device_id`), KEY `idx_cards_status` (`status`), CONSTRAINT `fk_cards_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`) ON DELETE SET NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -- Shared device volume is recommended to use device_configs.volume as source of truth. -- device_settings.volume is retained for mini-program compatibility and UI storage. CREATE TABLE IF NOT EXISTS `device_settings` ( `setting_id` BIGINT NOT NULL AUTO_INCREMENT, `device_id` VARCHAR(64) NOT NULL, `sleep_mode` TINYINT NOT NULL DEFAULT 0, `disable_time_start` TIME NULL, `disable_time_end` TIME NULL, `timezone` VARCHAR(32) NOT NULL DEFAULT 'Asia/Shanghai', `volume` TINYINT UNSIGNED NULL, `brightness` TINYINT UNSIGNED NULL, `disable_weekdays` VARCHAR(32) NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`setting_id`), UNIQUE KEY `uq_device_settings_device_id` (`device_id`), CONSTRAINT `fk_device_settings_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `im_conversations` ( `id` BIGINT UNSIGNED NOT NULL 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) NULL, `last_message_at` DATETIME NULL, `ext_json` JSON NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), CONSTRAINT `uq_conv_type_pair` UNIQUE (`conversation_type`, `pair_key`), KEY `idx_im_conv_participant_a` (`participant_a_type`, `participant_a_id`), KEY `idx_im_conv_participant_b` (`participant_b_type`, `participant_b_id`), KEY `idx_im_conv_last_message_at` (`last_message_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `im_messages` ( `id` BIGINT NOT NULL 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 NULL, `content_json` JSON NULL, `media_file_key` VARCHAR(255) NULL, `media_duration_ms` INT UNSIGNED NULL, `media_mime_type` VARCHAR(64) NULL, `media_size_bytes` BIGINT UNSIGNED NULL, `media_transcript_text` TEXT NULL, `client_msg_id` VARCHAR(64) NULL, `sender_name_snapshot` VARCHAR(64) NULL, `sender_avatar_snapshot` VARCHAR(255) NULL, `receiver_name_snapshot` VARCHAR(64) NULL, `receiver_avatar_snapshot` VARCHAR(255) NULL, `ext_json` JSON NULL, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `deleted_at` DATETIME NULL, PRIMARY KEY (`id`), CONSTRAINT `uq_im_msg_conv_seq` UNIQUE (`conversation_id`, `seq`), CONSTRAINT `uq_im_msg_client` UNIQUE (`conversation_id`, `client_msg_id`), KEY `idx_im_msg_conversation_created_at` (`conversation_id`, `created_at`), KEY `idx_im_msg_sender` (`sender_type`, `sender_id`, `created_at`), KEY `idx_im_msg_receiver` (`receiver_type`, `receiver_id`, `created_at`), CONSTRAINT `fk_im_messages_conversation` FOREIGN KEY (`conversation_id`) REFERENCES `im_conversations` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `child_location_current` ( `child_id` BIGINT 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 NULL, `altitude_m` DECIMAL(8, 2) NULL, `speed_mps` DECIMAL(8, 2) NULL, `heading_deg` SMALLINT UNSIGNED NULL, `source` TINYINT UNSIGNED NOT NULL, `battery_pct` TINYINT UNSIGNED NULL, `device_time` DATETIME NOT NULL, `server_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`child_id`), KEY `idx_child_loc_current_device` (`device_id`), KEY `idx_child_loc_current_server_time` (`server_time`), CONSTRAINT `fk_child_loc_current_child` FOREIGN KEY (`child_id`) REFERENCES `children` (`child_id`) ON DELETE CASCADE, CONSTRAINT `fk_child_loc_current_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS `child_location_history` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `child_id` BIGINT 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 NULL, `altitude_m` DECIMAL(8, 2) NULL, `speed_mps` DECIMAL(8, 2) NULL, `heading_deg` SMALLINT UNSIGNED NULL, `source` TINYINT UNSIGNED NOT NULL, `battery_pct` TINYINT UNSIGNED NULL, `device_time` DATETIME NOT NULL, `server_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_child_loc_hist_child` (`child_id`, `created_at`), KEY `idx_child_loc_hist_device` (`device_id`, `created_at`), CONSTRAINT `fk_child_loc_hist_child` FOREIGN KEY (`child_id`) REFERENCES `children` (`child_id`) ON DELETE CASCADE, CONSTRAINT `fk_child_loc_hist_device` FOREIGN KEY (`device_id`) REFERENCES `device_auth` (`device_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;