feat: micro-learning module with seed data

- Add Course and Module models to Prisma schema
- Create seed-learn.json with Daily Fiqh for Beginners (5 modules)
- Create seed-learn.js with Hermes patch (strip id/courseId from create)
- Add /learn page with course listing
- Add /learn/[courseSlug]/[moduleId] page with content + quiz
- Quiz data stored as JSON string per module
- Content rendered as markdown with Key Concept, Details, Reflection, Action Step sections

TODO:
- Add audio player component for listen toggle
- Add progress tracking per user
- Add actual quiz scoring/validation
- Connect to TTS pipeline for audio generation
This commit is contained in:
wmj2024
2026-06-28 04:27:21 +08:00
commit 1f60f1c908
66 changed files with 4713 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { verifyJWT } from '@/lib/auth'
import { moderateContent } from '@/lib/ai'
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url)
const categoryId = searchParams.get('categoryId')
const where = categoryId ? { categoryId } : {}
const threads = await prisma.forumThread.findMany({
where: { ...where, shariahStatus: 'approved' },
include: {
author: { select: { id: true, name: true, isPremium: true, isPro: true } },
category: { select: { id: true, name: true } },
_count: { select: { posts: true } },
},
orderBy: [{ pinned: 'desc' }, { createdAt: 'desc' }],
})
return NextResponse.json({ threads })
}
export async function POST(req: NextRequest) {
const auth = req.headers.get('authorization')
if (!auth?.startsWith('Bearer ')) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
const payload = await verifyJWT(auth.slice(7))
if (!payload) return NextResponse.json({ error: 'Invalid token' }, { status: 401 })
const { title, content, categoryId } = await req.json()
if (!title || !content || !categoryId) return NextResponse.json({ error: 'title, content, and categoryId required' }, { status: 400 })
const user = await prisma.user.findUnique({ where: { id: payload.id } })
if (!user || (!user.isPremium && !user.isPro)) return NextResponse.json({ error: 'Premium subscription required to create threads' }, { status: 403 })
const moderation = moderateContent(title + ' ' + content)
const thread = await prisma.forumThread.create({
data: {
title, content, categoryId, authorId: payload.id,
shariahStatus: moderation.approved ? 'approved' : 'flagged',
shariahFlags: moderation.reason || null,
},
include: { author: { select: { id: true, name: true } }, category: { select: { name: true } } },
})
return NextResponse.json({ thread }, { status: 201 })
}