Commit Graph

123 Commits

Author SHA1 Message Date
admins 3ed7bc147b Add lesson complete button with homework-aware logic
- Show "Отметить как пройденный" button only on lessons without homework
- Show static "Пройдено" badge on homework lessons completed via approval
- Auto-create LessonProgress when curator/admin approves homework submission
- Revalidate student lesson, course, and dashboard pages on approval

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 14:00:47 +05:00
admins 39d84a3db2 Add labeled file materials with format badge
- Store human-readable label in LessonFile.name via optional label field on upload
- Add PATCH endpoint to rename existing files inline
- Admin: label input before upload, click-to-edit inline rename
- Student: colored format badge (PDF/DOCX/XLSX/ZIP/etc) replaces paperclip emoji

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 11:55:07 +05:00
admins 15df731e37 Make lesson editor header and toolbar sticky on scroll
Both the controls bar (Save button, publish toggle) and the formatting
toolbar now stick to the top of the viewport while editing long lessons.
Header sticks at top: 0, toolbar sticks just below it at top: 62px.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 18:10:07 +05:00
admins bfa037885f Fix saveLesson: sanitize content JSON to prevent RSC proxy error
React treats TipTap's editor.getJSON() output as a non-plain object when
passed through Server Action serialization, causing isDecimal() inside
Prisma's query builder to receive a temporary client reference proxy and
throw ERROR 1213974697. JSON.parse(JSON.stringify()) strips the prototype
chain and any non-enumerable properties, ensuring Prisma receives a
clean plain object.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 17:58:13 +05:00
admins 8757537344 Debug: add try/catch and JSON sanitize in saveLesson
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 17:54:10 +05:00
admins 65aa669522 Fix prisma generator provider to prisma-client
The generated TypeScript client in src/generated/prisma was created with
prisma-client provider (new TypeScript-first generator), but schema.prisma
had prisma-client-js. This caused Docker builds to generate files in
node_modules/@prisma/client instead of src/generated/prisma, breaking the
@/generated/prisma/client import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 17:47:26 +05:00
admins f4e74b38d4 Add explicit prisma output path to fix Docker build
Without output directive, Prisma 7 generates to node_modules/@prisma/client
in the Docker build context, causing the @/generated/prisma/client import
to fail with "Module not found". Explicit output ensures generated TypeScript
files are always placed at src/generated/prisma/.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 17:38:19 +05:00
admins c050c005e4 Include src/generated in Docker build context for Prisma 7 TS client
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>
2026-04-25 17:29:47 +05:00
admins af1fb6f61e Fix RSC toStringTag error: import PrismaClient from generated TS client
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>
2026-04-25 15:08:09 +05:00
admins 09e5653191 Add Turbopack resolveAlias for Prisma client to fix RSC crash
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>
2026-04-25 14:35:26 +05:00
admins 29f6533e63 Switch to prisma-client-js generator to fix Turbopack RSC crash
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>
2026-04-25 14:32:31 +05:00
admins 4821764a4f Fix Prisma 7 + Turbopack RSC compatibility by adding serverExternalPackages
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>
2026-04-25 14:23:02 +05:00
admins 5dfa79d357 Fix all Server Actions imported from dynamic route paths
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>
2026-04-25 14:05:26 +05:00
admins 9eb21e3ab4 Move Server Actions to static paths to fix RSC temporary client reference error
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>
2026-04-25 13:58:27 +05:00
admins af8644ebce Serialize all Prisma proxy data in admin lesson and module pages
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:48:43 +05:00
admins 0bde11b86e Serialize all Prisma data before passing to Client Components
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>
2026-04-25 13:42:05 +05:00
admins d8be6d6d95 Fix Prisma 7 JSON proxy serialization in RSC props
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>
2026-04-25 13:36:04 +05:00
admins 9731fcab48 Add impersonatedBy field to Session model for admin plugin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:25:39 +05:00
admins 0e4f6c4b01 Fix impersonation: use direct fetch to /api/auth/admin/impersonate-user
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>
2026-04-25 13:18:49 +05:00
admins dd198349fb Fix impersonation: hard navigation + stop impersonating banner
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:12:47 +05:00
admins 808bcadfca Fix nested list spacing in TipTap lesson content
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 13:05:33 +05:00
admins ab37af59f2 Fix server component passing event handlers to client components
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 12:59:00 +05:00
admins ce305eab58 Add admin impersonation button to users table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 12:52:13 +05:00
admins e590f541b3 Add automated backup scripts for PostgreSQL and S3 files to Backblaze B2
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 14:38:48 +05:00
admins 48a9398905 Add optional audio response for students in homework submissions
- 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>
2026-04-08 14:17:46 +05:00
admins 3855bbd4be Add homework review workflow: statuses, audio, file attachments, tabs
- HomeworkSubmission: add status (PENDING/REVIEWING/APPROVED/REJECTED) + statusAt
- HomeworkFeedback: add files (Json) + audioUrl fields
- Curator detail page: meta table, content tabs, feedback history with audio/files
- FeedbackForm: file upload, audio recorder (Web Audio API + S3), action buttons
- AudioRecorder component: record → preview → upload to S3
- ContentTabs: toggle between homework description and lesson content (TipTap read-only)
- Homework list: 4-color status badges with proper filtering
- API routes: /api/curator/upload and /api/curator/audio-upload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 14:01:55 +05:00
admins 768a38b9d3 Add course tree, lesson actions, and module description schema
- 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>
v1.0
2026-04-08 13:32:30 +05:00
admins f0024c4243 Add course management improvements: tree view, module descriptions, lesson toggles
- SortableModules: add description textarea in edit form, show description in row
- CourseDetailPage: fetch lessons per module, add CourseTree overview section
- ModulePage: fetch sibling modules, pass as otherModules to SortableLessons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:31:30 +05:00
admins d0ba4bf909 Polish: homework filters, users search/popup, admin comments
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>
2026-04-08 13:00:57 +05:00
admins dd46a10c20 Add CSV import/export for students (Stage 11)
Import wizard (4 steps):
- Upload CSV with UTF-8 or Windows-1251 (iconv-lite) decoding
- Auto-detect columns: Email, Имя, Фамилия, Телефон
- Preview table with per-row status: new / update / error
- Options: auto-verify email, assign course + access days, send welcome email
- Apply: creates users with bcrypt password + Account record, grants enrollments

Export:
- GET /api/admin/export-users with course filter + encoding selection
- UTF-8 with BOM (works in all apps) or Windows-1251 (legacy Excel)
- Fields: Email, Имя, Телефон, Дата регистрации, Курсы, Прогресс

Navigation: added "Импорт / Экспорт" link to admin sidebar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 12:51:43 +05:00
admins 99c143d670 Add manual user creation in admin panel
- 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>
2026-04-08 12:36:52 +05:00
admins 58a61d6f04 Fix settings: catch DB errors at build time, return defaults
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>
2026-04-08 12:23:26 +05:00
admins e77588deb8 Add platform settings (Stage 9)
- 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>
2026-04-08 11:18:37 +05:00
admins 093e403f5f Enhance lesson editor: prev/next nav + richer toolbar
- page.tsx: fetch sibling lessons, pass prevLesson/nextLesson props
- LessonEditor: ChevronLeft/Right nav buttons with lesson title tooltip
- Toolbar: added Underline, Strikethrough, inline Code, H1, Horizontal rule,
  Link dialog (prompt), labeled buttons for better discoverability
- Install @tiptap/extension-underline

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 10:29:39 +05:00
admins 66b311f17e Polish email template: white outer bg, beige card, Arial font
- Outer background: #FFFFFF
- Card background: #F5F5F0 (beige)
- All text/buttons: Arial/Helvetica (renders consistently on mobile)
- Shadow via table wrapper technique (works in Gmail Android)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 18:05:47 +05:00
admins 32b0fa9d6f Rewrite email template with inline styles for mobile compatibility
- 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>
2026-04-07 17:35:30 +05:00
admins c647b29712 Add Markdown import from Obsidian (Stage 8)
- md-to-tiptap.ts: remark-based converter (headings, lists, blockquotes,
  code blocks, bold/italic/strike, links, images, hr)
- Obsidian ![[wikilink]] stripped, [[link|alias]] → plain text
- POST /api/admin/import-md: parses frontmatter (gray-matter) + converts content
- LessonEditor: "Импорт .md" button populates editor without auto-save
- ROADMAP: marked Stages 2, 3, 5, 6, 7, 8 as complete, fixed numbering

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 15:44:42 +05:00
admins 6d93a7b406 Add lesson comments (Stage 6)
- LessonComment CRUD: addComment / deleteComment server actions
- LessonComments client component with form, avatar, delete
- Comments section at bottom of lesson page (enrolled users only)
- Soft-delete support, moderation for curator/admin
- ROADMAP: moved Квизы to end (Stage 11), marked Stage 7 done

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 15:33:47 +05:00
admins 97f4c1ec24 Fix admin sidebar missing on /curator/* routes
- Extract AdminShell component (sidebar + wrapper)
- admin/layout.tsx uses AdminShell
- curator/layout.tsx uses AdminShell for admin role (was rendering children only)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:59:51 +05:00
admins ec51dd34bb Replace admin dashboard stub with real stats
- 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>
2026-04-07 14:58:46 +05:00
admins b40d518b74 Fix Resend lazy init to avoid build-time API key error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:48:14 +05:00
admins 6975a9f97e Add email notifications via Resend
- 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>
2026-04-07 14:46:46 +05:00
admins 9bc18247df Add homework review link to admin sidebar
- 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>
2026-04-07 14:18:56 +05:00
admins 543d5b2d5e Add homework system (admin, student, curator)
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>
2026-04-07 14:13:24 +05:00
admins d0c8c6dd53 Add lesson progress tracking
- 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>
2026-04-07 13:16:28 +05:00
admins c88b5d2004 Allow admin to preview unpublished lessons without enrollment
- 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>
2026-04-07 12:57:18 +05:00
admins 4183a912e4 Add save and preview icons to lesson editor
- 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>
2026-04-07 12:45:30 +05:00
admins 07b9a6d261 Polish UX: auto-redirect on create, fix design consistency
- 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>
2026-04-07 12:38:46 +05:00
admins 05dd4d1df2 Stage 2: student lesson viewer, Kinescope player, PDF files, prev/next nav, My Courses dashboard 2026-04-07 12:13:12 +05:00
admins 03e3972388 Add TECHNICAL.md: infrastructure, design tokens, media specs, DB schema, done stages 2026-04-07 12:08:44 +05:00