import { FastifyInstance } from 'fastify'; import { z } from 'zod'; import { getDashboard, getStreak, getHearts, restoreHearts, getChapterProgress, } from '../services/progress/progress-service.js'; const restoreHeartsSchema = z.object({ method: z.enum(['ad', 'wait']), }); const feedbackSchema = z.object({ content: z.string().min(1).max(2000), contact: z.string().max(255).optional(), pageContext: z.string().max(200).optional(), }); function getUserId(request: { user: unknown }): string { return (request.user as { userId: string }).userId; } export async function progressRoutes(app: FastifyInstance): Promise { app.get('/progress/dashboard', async (request) => { const data = await getDashboard(getUserId(request)); return { success: true, data, error: null }; }); app.get('/progress/streak', async (request) => { const data = await getStreak(getUserId(request)); return { success: true, data, error: null }; }); app.get('/progress/hearts', async (request) => { const data = await getHearts(getUserId(request)); return { success: true, data, error: null }; }); // [废弃] 请使用 POST /rewards/ad-recovery/session + /rewards/ad-recovery/complete 两步流程。 app.post('/progress/hearts/restore', async (request) => { const parsed = restoreHeartsSchema.safeParse(request.body); if (!parsed.success) { return { success: false, data: null, error: { code: 'VALIDATION_ERROR', message: parsed.error.issues[0]?.message } }; } const data = await restoreHearts(getUserId(request), parsed.data.method); return { success: true, data, error: null }; }); app.get('/progress/chapters', async (request) => { const data = await getChapterProgress(getUserId(request)); return { success: true, data, error: null }; }); app.post('/feedback', async (request) => { const parsed = feedbackSchema.safeParse(request.body); if (!parsed.success) { return { success: false, data: null, error: { code: 'VALIDATION_ERROR', message: parsed.error.issues[0]?.message } }; } const { db } = await import('../db/client.js'); const { userFeedback } = await import('../db/schema.js'); const { v4: uuid } = await import('uuid'); const userId = getUserId(request); await db.insert(userFeedback).values({ id: uuid(), userId, content: parsed.data.content, contact: parsed.data.contact ?? null, pageContext: parsed.data.pageContext ?? null, }); return { success: true, data: null, error: null }; }); }