import { mysqlTable, char, mysqlEnum, varchar, int, tinyint, smallint, decimal, text, json, date, datetime, uniqueIndex, foreignKey, index, } from 'drizzle-orm/mysql-core'; import { sql } from 'drizzle-orm'; // ── Users ────────────────────────────────────────────────────────── export const users = mysqlTable('users', { id: char('id', { length: 36 }).primaryKey(), authType: mysqlEnum('auth_type', ['huawei', 'guest', 'phone', 'apple', 'google']).notNull(), authId: varchar('auth_id', { length: 255 }).notNull(), nickname: varchar('nickname', { length: 50 }), avatarUrl: varchar('avatar_url', { length: 500 }), tier: mysqlEnum('tier', ['free', 'pro', 'proplus']).default('free'), xpTotal: int('xp_total').default(0), streakDays: int('streak_days').default(0), streakLastDate: date('streak_last_date'), heartsRemaining: tinyint('hearts_remaining').default(5), heartsLastRestore: datetime('hearts_last_restore'), dailyXpGoal: smallint('daily_xp_goal').default(50), dailyXpEarned: smallint('daily_xp_earned').default(0), dailyXpDate: date('daily_xp_date'), currentTheme: varchar('current_theme', { length: 20 }).default('inkTeal'), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_auth').on(table.authType, table.authId), ]); // ── Categories ───────────────────────────────────────────────────── export const categories = mysqlTable('categories', { id: varchar('id', { length: 50 }).primaryKey(), name: varchar('name', { length: 100 }).notNull(), slug: varchar('slug', { length: 100 }).notNull(), parentId: varchar('parent_id', { length: 50 }), sortOrder: int('sort_order').default(0), questionCount: int('question_count').default(0), status: mysqlEnum('status', ['active', 'inactive']).default('active'), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_slug').on(table.slug), ]); // ── Questions ────────────────────────────────────────────────────── export const questions = mysqlTable('questions', { id: char('id', { length: 36 }).primaryKey(), stem: json('stem').notNull(), contentType: mysqlEnum('content_type', ['text', 'image', 'video', 'audio']).notNull(), correctAnswer: varchar('correct_answer', { length: 500 }).notNull(), distractors: json('distractors').notNull(), categoryId: varchar('category_id', { length: 50 }).notNull(), difficulty: tinyint('difficulty'), dynamicDifficulty: decimal('dynamic_difficulty', { precision: 3, scale: 1 }), source: mysqlEnum('source', ['system', 'ugc']).default('system'), creatorId: char('creator_id', { length: 36 }), status: mysqlEnum('status', ['draft', 'reviewing', 'published', 'archived']).default('draft'), stats: json('stats').$type<{ timesAnswered: number; correctRate: number; avgTimeMs: number }>() .default({ timesAnswered: 0, correctRate: 0, avgTimeMs: 0 }), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }, (table) => [ foreignKey({ columns: [table.categoryId], foreignColumns: [categories.id] }), ]); // ── Knowledge Cards ──────────────────────────────────────────────── export const knowledgeCards = mysqlTable('knowledge_cards', { id: char('id', { length: 36 }).primaryKey(), questionId: char('question_id', { length: 36 }).notNull(), summary: varchar('summary', { length: 300 }).notNull(), deepDive: text('deep_dive'), sourceRef: varchar('source_ref', { length: 500 }), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_question').on(table.questionId), foreignKey({ columns: [table.questionId], foreignColumns: [questions.id] }), ]); // ── User Progress ────────────────────────────────────────────────── export const userProgress = mysqlTable('user_progress', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), questionId: char('question_id', { length: 36 }).notNull(), correct: tinyint('correct').notNull(), timeMs: int('time_ms'), answeredAt: datetime('answered_at').default(sql`CURRENT_TIMESTAMP`), }, (table) => [ index('idx_user_answered').on(table.userId, table.answeredAt), foreignKey({ columns: [table.userId], foreignColumns: [users.id] }), foreignKey({ columns: [table.questionId], foreignColumns: [questions.id] }), ]); // ── Skill Tree ───────────────────────────────────────────────────── export const skillTree = mysqlTable('skill_tree', { id: char('id', { length: 36 }).primaryKey(), categoryId: varchar('category_id', { length: 50 }).notNull(), title: varchar('title', { length: 100 }).notNull(), parentId: char('parent_id', { length: 36 }), sortOrder: int('sort_order').default(0), questionsRequired: tinyint('questions_required').default(4), passThreshold: tinyint('pass_threshold').default(2), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), }, (table) => [ foreignKey({ columns: [table.categoryId], foreignColumns: [categories.id] }), ]); // ── User Chapter Progress ────────────────────────────────────────── export const userChapterProgress = mysqlTable('user_chapter_progress', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), chapterId: char('chapter_id', { length: 36 }).notNull(), status: mysqlEnum('status', ['locked', 'unlocked', 'passed', 'perfect']).default('locked'), bestCorrectCount: tinyint('best_correct_count').default(0), attempts: int('attempts').default(0), completedAt: datetime('completed_at'), }, (table) => [ uniqueIndex('uk_user_chapter').on(table.userId, table.chapterId), foreignKey({ columns: [table.userId], foreignColumns: [users.id] }), foreignKey({ columns: [table.chapterId], foreignColumns: [skillTree.id] }), ]); // ── Question Ratings ────────────────────────────────────────────── export const questionRatings = mysqlTable('question_ratings', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), questionId: char('question_id', { length: 36 }).notNull(), rating: mysqlEnum('rating', ['good', 'bad']).notNull(), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_user_question_rating').on(table.userId, table.questionId), ]); // ── User Feedback ────────────────────────────────────────────────── export const userFeedback = mysqlTable('user_feedback', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), content: text('content').notNull(), contact: varchar('contact', { length: 255 }), pageContext: varchar('page_context', { length: 200 }), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), }); // ── Achievements ────────────────────────────────────────────────── export const achievements = mysqlTable('achievements', { id: char('id', { length: 36 }).primaryKey(), type: mysqlEnum('type', ['knowledge', 'behavior']).notNull(), name: varchar('name', { length: 100 }).notNull(), description: varchar('description', { length: 300 }).notNull(), iconUrl: varchar('icon_url', { length: 500 }), condition: json('condition').notNull(), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), }); export const userAchievements = mysqlTable('user_achievements', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), achievementId: char('achievement_id', { length: 36 }).notNull(), unlockedAt: datetime('unlocked_at').default(sql`CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_user_achievement').on(table.userId, table.achievementId), ]); // ── Leaderboard Snapshots ────────────────────────────────────────── export const leaderboardSnapshots = mysqlTable('leaderboard_snapshots', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), tier: mysqlEnum('tier', ['bronze', 'silver', 'gold', 'platinum', 'diamond', 'master', 'grandmaster', 'champion', 'legend', 'mythic']).notNull(), weeklyXp: int('weekly_xp').default(0), rank: int('rank'), league: varchar('league', { length: 50 }), weekStart: date('week_start'), weekEnd: date('week_end'), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), }, (table) => [ index('idx_user_week').on(table.userId, table.weekStart), ]); // ── Subscriptions ────────────────────────────────────────────────── export const subscriptions = mysqlTable('subscriptions', { id: char('id', { length: 36 }).primaryKey(), userId: char('user_id', { length: 36 }).notNull(), tier: mysqlEnum('tier', ['free', 'pro', 'proplus']).default('free'), platform: mysqlEnum('platform', ['huawei', 'apple', 'google']), purchaseToken: varchar('purchase_token', { length: 500 }), expiresAt: datetime('expires_at'), autoRenew: tinyint('auto_renew').default(0), status: mysqlEnum('status', ['active', 'expired', 'cancelled']).default('active'), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_subscription_user').on(table.userId), ]); // ── Admin Audit Log ──────────────────────────────────────────────── export const adminAuditLog = mysqlTable('admin_audit_log', { id: int('id').primaryKey().autoincrement(), adminId: varchar('admin_id', { length: 36 }).notNull(), action: varchar('action', { length: 10 }).notNull(), resource: varchar('resource', { length: 500 }), details: json('details'), ipAddress: varchar('ip_address', { length: 45 }), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), }); // ── Admin Users ─────────────────────────────────────────────────────── export const adminUsers = mysqlTable('admin_users', { id: char('id', { length: 36 }).primaryKey(), username: varchar('username', { length: 50 }).notNull(), passwordHash: varchar('password_hash', { length: 255 }).notNull(), role: mysqlEnum('role', ['admin', 'super_admin']).default('admin'), isActive: tinyint('is_active').default(1), lastLoginAt: datetime('last_login_at'), createdAt: datetime('created_at').default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime('updated_at').default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }, (table) => [ uniqueIndex('uk_admin_username').on(table.username), ]);