USE dating_app; CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, email_or_phone VARCHAR(320) UNIQUE, password_hash VARCHAR(256), status VARCHAR(20) NOT NULL DEFAULT 'active', created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_profiles ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL UNIQUE, full_name VARCHAR(120), gender VARCHAR(30), birth_date VARCHAR(10), city VARCHAR(120), county VARCHAR(120), country VARCHAR(120), relationship_goal VARCHAR(30), bio TEXT, occupation VARCHAR(120), education VARCHAR(120), height_cm INT, beliefs VARCHAR(120), smoking VARCHAR(50), drinking VARCHAR(50), pets VARCHAR(120), exercise VARCHAR(50), INDEX ix_user_profiles_city_country (city, country), CONSTRAINT fk_user_profiles_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_interests ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, name VARCHAR(120) NOT NULL, created_at DATETIME NOT NULL, CONSTRAINT uq_user_interest_name UNIQUE (user_id, name), CONSTRAINT fk_user_interests_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_user_interests_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS auth_identities ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, provider VARCHAR(30) NOT NULL, provider_user_id VARCHAR(255) NOT NULL, created_at DATETIME NOT NULL, CONSTRAINT uq_auth_provider_user UNIQUE (provider, provider_user_id), CONSTRAINT fk_auth_identities_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_media ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, media_type VARCHAR(20) NOT NULL, storage_path VARCHAR(500) NOT NULL, original_name VARCHAR(255), mime_type VARCHAR(100), review_status VARCHAR(20) NOT NULL DEFAULT 'pending', created_at DATETIME NOT NULL, INDEX ix_user_media_user (user_id), CONSTRAINT fk_user_media_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_locations ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL UNIQUE, latitude DOUBLE NOT NULL, longitude DOUBLE NOT NULL, updated_at DATETIME NOT NULL, CONSTRAINT fk_user_locations_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_sessions ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, refresh_token_hash VARCHAR(256) NOT NULL UNIQUE, expires_at DATETIME NOT NULL, created_at DATETIME NOT NULL, revoked_at DATETIME NULL, CONSTRAINT fk_user_sessions_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_user_sessions_user (user_id), INDEX ix_user_sessions_expires (expires_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS swipes ( id INT AUTO_INCREMENT PRIMARY KEY, actor_id INT NOT NULL, target_id INT NOT NULL, direction VARCHAR(10) NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, CONSTRAINT uq_swipe_actor_target UNIQUE (actor_id, target_id), CONSTRAINT ck_swipe_not_self CHECK (actor_id <> target_id), CONSTRAINT ck_swipe_direction CHECK (direction IN ('like', 'pass', 'super_like')), CONSTRAINT fk_swipes_actor FOREIGN KEY (actor_id) REFERENCES users(id) ON DELETE CASCADE, CONSTRAINT fk_swipes_target FOREIGN KEY (target_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_swipes_actor (actor_id), INDEX ix_swipes_target (target_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS matches ( id INT AUTO_INCREMENT PRIMARY KEY, user1_id INT NOT NULL, user2_id INT NOT NULL, matched_at DATETIME NOT NULL, CONSTRAINT uq_match_user_pair UNIQUE (user1_id, user2_id), CONSTRAINT ck_match_canonical_order CHECK (user1_id < user2_id), CONSTRAINT fk_matches_user1 FOREIGN KEY (user1_id) REFERENCES users(id) ON DELETE CASCADE, CONSTRAINT fk_matches_user2 FOREIGN KEY (user2_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_matches_user1 (user1_id), INDEX ix_matches_user2 (user2_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS posts ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, content TEXT NOT NULL, post_type VARCHAR(20) NOT NULL DEFAULT 'text', content_format VARCHAR(10) NOT NULL DEFAULT 'plain', feeling VARCHAR(50) NULL, location_name VARCHAR(255) NULL, location_latitude DOUBLE NULL, location_longitude DOUBLE NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, CONSTRAINT ck_posts_type CHECK (post_type IN ('text', 'image', 'video')), CONSTRAINT fk_posts_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_posts_user (user_id), INDEX ix_posts_created (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS post_media ( id INT AUTO_INCREMENT PRIMARY KEY, post_id INT NOT NULL, media_type VARCHAR(20) NOT NULL, storage_path VARCHAR(500) NOT NULL, original_name VARCHAR(255), mime_type VARCHAR(100) NOT NULL, size_bytes INT NOT NULL, position INT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL, CONSTRAINT ck_post_media_type CHECK (media_type IN ('image', 'video')), CONSTRAINT fk_post_media_post FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE, INDEX ix_post_media_post (post_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS post_likes ( id INT AUTO_INCREMENT PRIMARY KEY, post_id INT NOT NULL, user_id INT NOT NULL, created_at DATETIME NOT NULL, CONSTRAINT uq_post_like UNIQUE (post_id, user_id), CONSTRAINT fk_post_likes_post FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE, CONSTRAINT fk_post_likes_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_post_likes_post (post_id), INDEX ix_post_likes_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS post_comments ( id INT AUTO_INCREMENT PRIMARY KEY, post_id INT NOT NULL, user_id INT NOT NULL, parent_comment_id INT NULL, content TEXT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, CONSTRAINT fk_post_comments_post FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE, CONSTRAINT fk_post_comments_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, CONSTRAINT fk_post_comments_parent FOREIGN KEY (parent_comment_id) REFERENCES post_comments(id) ON DELETE CASCADE, INDEX ix_post_comments_post (post_id), INDEX ix_post_comments_user (user_id), INDEX ix_post_comments_parent (parent_comment_id), INDEX ix_post_comments_created (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS comment_likes ( id INT AUTO_INCREMENT PRIMARY KEY, comment_id INT NOT NULL, user_id INT NOT NULL, created_at DATETIME NOT NULL, CONSTRAINT uq_comment_like UNIQUE (comment_id, user_id), CONSTRAINT fk_comment_likes_comment FOREIGN KEY (comment_id) REFERENCES post_comments(id) ON DELETE CASCADE, CONSTRAINT fk_comment_likes_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_comment_likes_comment (comment_id), INDEX ix_comment_likes_user (user_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS conversations ( id INT AUTO_INCREMENT PRIMARY KEY, match_id INT NOT NULL UNIQUE, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, CONSTRAINT fk_conversations_match FOREIGN KEY (match_id) REFERENCES matches(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS chat_messages ( id INT AUTO_INCREMENT PRIMARY KEY, conversation_id INT NOT NULL, sender_id INT NOT NULL, content TEXT NOT NULL, message_type VARCHAR(20) NOT NULL DEFAULT 'text', created_at DATETIME NOT NULL, deleted_at DATETIME NULL, CONSTRAINT ck_chat_messages_type CHECK (message_type IN ('text')), CONSTRAINT fk_chat_messages_conversation FOREIGN KEY (conversation_id) REFERENCES conversations(id) ON DELETE CASCADE, CONSTRAINT fk_chat_messages_sender FOREIGN KEY (sender_id) REFERENCES users(id) ON DELETE CASCADE, INDEX ix_chat_messages_conversation (conversation_id), INDEX ix_chat_messages_sender (sender_id), INDEX ix_chat_messages_created (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS feed_questions ( id INT AUTO_INCREMENT PRIMARY KEY, code VARCHAR(100) NOT NULL UNIQUE, question_text VARCHAR(500) NOT NULL, question_text_zh VARCHAR(500), answer_type VARCHAR(20) NOT NULL DEFAULT 'boolean', is_active BOOLEAN NOT NULL DEFAULT TRUE, sort_order INT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL, CONSTRAINT ck_feed_questions_type CHECK (answer_type IN ('boolean', 'text')), INDEX ix_feed_questions_active (is_active) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE IF NOT EXISTS user_question_answers ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, question_id INT NOT NULL, boolean_answer BOOLEAN NULL, text_answer TEXT NULL, answered_at DATETIME NOT NULL, CONSTRAINT uq_user_question_answer UNIQUE (user_id, question_id), CONSTRAINT fk_user_question_answers_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, CONSTRAINT fk_user_question_answers_question FOREIGN KEY (question_id) REFERENCES feed_questions(id) ON DELETE CASCADE, INDEX ix_user_question_answers_user (user_id), INDEX ix_user_question_answers_question (question_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT IGNORE INTO feed_questions (code, question_text, question_text_zh, answer_type, is_active, sort_order, created_at) VALUES ('weekend_movies', 'Do you like watching movies on weekends?', '你喜欢周末看电影吗?', 'boolean', TRUE, 10, NOW()), ('outdoor_activities', 'Do you enjoy outdoor activities?', '你喜欢户外活动吗?', 'boolean', TRUE, 20, NOW()), ('quiet_weekends', 'Do you prefer quiet weekends?', '你更喜欢安静的周末吗?', 'boolean', TRUE, 30, NOW()), ('long_term_relationship', 'Are you looking for a long-term relationship?', '你希望发展长期关系吗?', 'boolean', TRUE, 40, NOW()), ('ideal_first_date', 'What is your ideal first date?', '你理想中的第一次约会是什么?', 'text', TRUE, 50, NOW());