Remove src/generated from .dockerignore so Turbopack can resolve
@/generated/prisma/client during build. The files are regenerated
by prisma generate inside the builder anyway.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use @/generated/prisma/client instead of @prisma/client to avoid
Turbopack creating a broken external proxy for the missing
.prisma/client/default module at runtime. Add @prisma/adapter-pg
to serverExternalPackages, remove unused resolveAlias.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without resolveAlias, Turbopack fails to resolve .prisma/client/default
and creates a temporary client reference, causing the toStringTag error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The new prisma-client generator outputs TypeScript files to src/generated/prisma/
which include import.meta.url at module level. Turbopack sees this and marks the
entire module as a client reference, causing 'Cannot access toStringTag on the
server' on every page that uses Prisma.
Switching to prisma-client-js puts the generated client in node_modules/@prisma/client
where serverExternalPackages can properly exclude it from the server bundle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Next.js 16 with Turbopack bundles @prisma/client into the RSC bundle,
causing it to be treated as a client module and creating 'temporary client
references'. This triggers the 'Cannot access toStringTag on the server' error
whenever Prisma result objects are used in Server Components.
Adding serverExternalPackages tells Turbopack to treat these as native
Node.js packages and keep them out of the RSC bundle.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All admin and student Client Components were importing Server Actions
from paths with dynamic segments ([courseId], [moduleId], [lessonId], [slug]).
This caused "Cannot access toStringTag on the server" RSC crash.
Consolidated all Server Actions into static files under src/lib/actions/:
- course-actions.ts (modules + enrollment)
- module-actions.ts (lessons + reorder + move)
- user-actions.ts (bulk grant / revoke)
- student-actions.ts (progress + homework + comments)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Server Actions imported from dynamic route paths ([courseId]/[moduleId]/[lessonId])
caused "Cannot access toStringTag on the server" crash after saving a lesson.
Moved saveLesson, saveHomework, deleteHomework to src/lib/actions/*.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prisma 7 proxy objects (DateTime, _count, relations) cannot be
serialized by React RSC. Convert all course page data to plain
JSON objects with JSON.parse/stringify before passing as props.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prisma 7 wraps Json fields in proxy objects that RSC cannot serialize.
Fix: select specific columns (exclude content) in module page,
and JSON.parse/stringify lesson content before passing to client.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
authClient.admin.impersonateUser is not registered in pathMethods
in better-auth v1.6 client plugin — call the endpoint directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Course: add allowAudio toggle (per-course setting, off by default)
- HomeworkSubmission: add audioUrl field
- Student: AudioRecorder in homework form when allowAudio is enabled
- Student: show audio player in submission view and curator feedback view
- Curator: show student audio on submission detail page
- AudioRecorder: accept uploadUrl prop (reused for student/curator)
- API: /api/student/audio-upload route for S3 upload
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CourseTree: expandable module/lesson overview with Eye/Video icons
- SortableLessons: Kinescope ID in create form, published toggle, move-to-module dropdown
- Actions: toggleLessonPublished, moveLessonToModule, updateModule with description
- Schema: add description field to Module model + migration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Homework (/curator/homework):
- Search by student name/email
- Filter by status (pending/reviewed) and course
- Server-side pagination (20 per page) with URL params
Users (/admin/users):
- Search by name/email, filter by role
- Hover popup on each row: enrolled courses + expiry dates + email
- Pagination (20 per page) with URL params
Comments (/admin/comments):
- New admin page with all active comments
- Search by author or text content
- One-click delete (soft-delete) from the table
- Pagination (30 per page)
- Added "Комментарии" link to admin nav
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Server action createUser() with bcrypt password hash + Account record
- Form with name, email, password (show/hide + generate), role, emailVerified toggle
- Optional welcome email toggle (bypasses auto-hook for admin-created users)
- /admin/users/new page with breadcrumb navigation
- After creation, redirects to the new user's profile page
- "Добавить пользователя" button on the users list page
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getSettings() and getSetting() now fall back to defaults when the
database is unavailable (e.g., during Docker image build).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Settings key-value table in Prisma with migration
- getSettings() / getSetting() helpers in lib/settings.ts
- Admin UI at /admin/settings with 6 sections: General, Notifications,
Student profile, Legal docs, Curator permissions, Code injection
- saveSettings() server action with admin-only guard
- Maintenance mode: non-admin users redirected to /maintenance page
- schoolName propagated to page metadata and all email templates
- headCode / bodyCode injected into root layout <head> and <body>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- All styles moved to inline attributes (no <style> block)
- Table-based layout for Gmail/Outlook/mobile client compatibility
- Aubade card effect via border-right/border-bottom:4px
- Monospace font stack with web-safe fallbacks
- btn() and quote() helper functions rewritten as <table> elements
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 4 stat cards: students (+monthly), courses (published), active enrollments (expiring alert), homework pending
- Recent enrollments list (last 8)
- Top courses by enrollment count
- Activity counters: total lessons completed, total homework submitted
- All cards link to relevant admin pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- src/lib/email.ts: HTML templates for 4 email types (Second Brain design)
- Welcome email on user registration (Better Auth databaseHooks)
- Course access email when admin grants enrollment
- Homework submitted email to all admins/curators (first submission only)
- Feedback received email to student with feedback text and lesson link
- Update TECHNICAL.md: Resend domain, from-address, email vars, Stage 3 summary
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Admin sidebar now has "ДЗ на проверку" link → /curator/homework
- Curator layout renders children-only for admin (no double sidebar)
- Active state highlights correctly when on /curator/* routes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Admin:
- HomeworkEditor in lesson page: create/update/delete assignment description
Student:
- HomeworkSection in lesson page: view assignment, submit text + files
- Resubmission allowed until curator gives feedback
- Shows feedback from curator with date and name
Curator:
- New layout with Second Brain dark sidebar (replaces green theme)
- /curator/dashboard: stats cards (pending, total, reviewed this week)
- /curator/homework: list of all submissions, pending highlighted
- /curator/homework/[id]: review submission, write feedback, redirect after send
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Toggle lesson completion via server action (LessonProgress table)
- "Отметить как пройденный" button on lesson page, turns accent when done
- Course sidebar: progress bar, checkmarks on completed lessons, X/Y counter per module
- Dashboard: progress bar on each course card with completion percentage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Course layout skips enrollment and published checks for admin role
- Lesson page skips published filter for admin role
- Enables admin preview button to work for any lesson/course state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Save button now shows floppy disk icon (lucide Save)
- New Preview button with eye icon opens lesson in student view (new tab)
- Pass courseSlug through to LessonEditor for preview URL construction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- createModule now redirects to module page after creation
- createLesson now redirects to lesson editor after creation
- Regenerate Prisma client to fix missing types (category, accessLog, expiresAt)
- Rewrite sortable-modules/lessons with Second Brain design tokens (remove amber/slate)
- Rewrite lesson-editor toolbar and toggle with design tokens
- Fix register page/form: replace amber theme with card-aubade design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>