Files
Podcast-Generator/web/drizzle-schema.ts
hex2077 e479ffb789 feat: 实现积分系统与认证重构
重构认证系统,从next-auth迁移至better-auth,并实现完整的积分系统功能:
1. 新增积分账户管理、交易记录和扣减逻辑
2. 添加积分概览组件和API端点
3. 重构认证相关组件和路由
4. 优化播客生成流程与积分校验
5. 新增安全配置文档和数据库schema
6. 改进UI状态管理和错误处理

新增功能包括:
- 用户注册自动初始化积分账户
- 播客生成前检查积分余额
- 积分交易记录查询
- 用户积分实时显示
- 安全回调处理
2025-08-18 00:21:02 +08:00

92 lines
3.2 KiB
TypeScript

import { sqliteTable, AnySQLiteColumn, foreignKey, check, text, integer, uniqueIndex, index } from "drizzle-orm/sqlite-core"
import { sql } from "drizzle-orm"
export const account = sqliteTable("account", {
id: text().primaryKey().notNull(),
accountId: text("account_id").notNull(),
providerId: text("provider_id").notNull(),
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" } ),
accessToken: text("access_token"),
refreshToken: text("refresh_token"),
idToken: text("id_token"),
accessTokenExpiresAt: integer("access_token_expires_at"),
refreshTokenExpiresAt: integer("refresh_token_expires_at"),
scope: text(),
password: text(),
createdAt: integer("created_at").notNull(),
updatedAt: integer("updated_at").notNull(),
},
(table) => [
check("points_accounts_check_1", sql`total_points >= 0`),
]);
export const session = sqliteTable("session", {
id: text().primaryKey().notNull(),
expiresAt: integer("expires_at").notNull(),
token: text().notNull(),
createdAt: integer("created_at").notNull(),
updatedAt: integer("updated_at").notNull(),
ipAddress: text("ip_address"),
userAgent: text("user_agent"),
userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" } ),
},
(table) => [
uniqueIndex("session_token_unique").on(table.token),
check("points_accounts_check_1", sql`total_points >= 0`),
]);
export const user = sqliteTable("user", {
id: text().primaryKey().notNull(),
name: text().notNull(),
email: text().notNull(),
emailVerified: integer("email_verified").notNull(),
image: text(),
createdAt: integer("created_at").notNull(),
updatedAt: integer("updated_at").notNull(),
username: text(),
displayUsername: text("display_username"),
},
(table) => [
uniqueIndex("user_username_unique").on(table.username),
uniqueIndex("user_email_unique").on(table.email),
check("points_accounts_check_1", sql`total_points >= 0`),
]);
export const verification = sqliteTable("verification", {
id: text().primaryKey().notNull(),
identifier: text().notNull(),
value: text().notNull(),
expiresAt: integer("expires_at").notNull(),
createdAt: integer("created_at"),
updatedAt: integer("updated_at"),
},
(table) => [
check("points_accounts_check_1", sql`total_points >= 0`),
]);
export const pointsAccounts = sqliteTable("points_accounts", {
accountId: integer("account_id").primaryKey({ autoIncrement: true }),
userId: text("user_id").notNull(),
totalPoints: integer("total_points").default(0).notNull(),
updatedAt: text("updated_at").notNull(),
},
(table) => [
index("idx_points_accounts_user_id").on(table.userId),
uniqueIndex("points_accounts_user_id_unique").on(table.userId),
check("points_accounts_check_1", sql`total_points >= 0`),
]);
export const pointsTransactions = sqliteTable("points_transactions", {
transactionId: integer("transaction_id").primaryKey({ autoIncrement: true }),
userId: text("user_id").notNull(),
pointsChange: integer("points_change").notNull(),
reasonCode: text("reason_code").notNull(),
description: text(),
createdAt: text("created_at").default("sql`(CURRENT_TIMESTAMP)`").notNull(),
},
(table) => [
index("idx_points_transactions_user_id").on(table.userId),
check("points_accounts_check_1", sql`total_points >= 0`),
]);