refactor: 数据层迁往服务端 (Express+DuckDB), APP 变瘦客户端只留缓存
- server: 新增 DuckDB 数据层 (db.js) 与鉴权 (auth.js: 验证码+token), 挂载 /api 业务路由 (衣物/搭配/日历/统计/MCP), 错误统一中间件 - 前端 src/api/index.ts 全部业务调用改为 HTTP (Bearer token), 客户端不再持有数据库 - 删除 Rust 数据层 (db.rs/auth.rs/mcp.rs/models.rs), Cargo.toml 裁剪 duckdb/chrono 等依赖 - Dockerfile: 基镜像 alpine→slim (@duckdb/node-api glibc 预编译), DB 落 /app/data 卷 - docker-build.yml: 移除 prune --volumes, 挂具名卷 wardrobe-data 持久化 - Landing/Profile 文案改为云端同步口径; 退出登录调服务端会话销毁
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
// 登录/注册: 验证码(服务端一次性校验) + 服务端签发会话 token
|
||||
// 注意: 短信/邮件发送仍是假通道 (验证码固定 1111), 后续再接真实通道
|
||||
import { uu, dbCreateUser, dbGetUserByEmail, dbGetUserByPhone, dbGetUserById, dbGetSession, dbCreateSession, dbDeleteSession } from './db.js'
|
||||
|
||||
const VERIFICATION_CODE = '1111'
|
||||
const CODE_EXPIRY_SECONDS = 300
|
||||
const codes = new Map()
|
||||
|
||||
export function sendVerification(target) {
|
||||
codes.set(target, { code: VERIFICATION_CODE, expiresAt: Date.now() + CODE_EXPIRY_SECONDS * 1000 })
|
||||
console.log(`[auth] verification code for ${target}: ${VERIFICATION_CODE}`)
|
||||
return `验证码已发送至 ${target}`
|
||||
}
|
||||
|
||||
function verifyCode(target, code) {
|
||||
const v = codes.get(target)
|
||||
if (!v) return false
|
||||
if (v.code !== code || Date.now() >= v.expiresAt) return false
|
||||
codes.delete(target)
|
||||
return true
|
||||
}
|
||||
|
||||
export async function register({ email, phone, code, nickname }) {
|
||||
const target = email || phone
|
||||
if (!target) return { success: false, message: '请提供邮箱或手机号', user: null, token: null }
|
||||
if (!verifyCode(target, code)) {
|
||||
return { success: false, message: '验证码无效或已过期', user: null, token: null }
|
||||
}
|
||||
if (email && (await dbGetUserByEmail(email))) {
|
||||
return { success: false, message: '该邮箱已注册', user: null, token: null }
|
||||
}
|
||||
if (phone && (await dbGetUserByPhone(phone))) {
|
||||
return { success: false, message: '该手机号已注册', user: null, token: null }
|
||||
}
|
||||
const id = uu()
|
||||
const user = await dbCreateUser(id, email || null, phone || null, nickname || '时尚达人')
|
||||
const token = 'tok_' + uu().replaceAll('-', '')
|
||||
await dbCreateSession(token, id)
|
||||
console.log(`[auth] user registered: ${id}`)
|
||||
return { success: true, message: '注册成功', user, token }
|
||||
}
|
||||
|
||||
export async function login({ email, phone, code }) {
|
||||
const target = email || phone
|
||||
if (!target) return { success: false, message: '请提供邮箱或手机号', user: null, token: null }
|
||||
if (!verifyCode(target, code)) {
|
||||
return { success: false, message: '验证码无效或已过期', user: null, token: null }
|
||||
}
|
||||
const user = email ? await dbGetUserByEmail(email) : await dbGetUserByPhone(phone)
|
||||
if (!user) return { success: false, message: '账号不存在,请先注册', user: null, token: null }
|
||||
const token = 'tok_' + uu().replaceAll('-', '')
|
||||
await dbCreateSession(token, user.id)
|
||||
console.log(`[auth] user login: ${user.id}`)
|
||||
return { success: true, message: '登录成功', user, token }
|
||||
}
|
||||
|
||||
export async function logout(token) {
|
||||
if (token) await dbDeleteSession(token)
|
||||
}
|
||||
|
||||
export async function resolveSession(token) {
|
||||
const s = token ? await dbGetSession(token) : null
|
||||
if (!s) return null
|
||||
const user = await dbGetUserById(s.user_id)
|
||||
return user
|
||||
}
|
||||
Reference in New Issue
Block a user