Commit Graph
86 Commits
Author SHA1 Message Date
admins 4f3b389f05 Update load test to 100 VUs with login jitter
Stages: 10 → 50 → 100 VUs, hold 3 min, ramp down.
Added random 0-10s sleep before first login to spread auth requests
and reduce Better Auth rate-limit retries.
Results: p(95)=244ms, pages 100% OK, auth retries 6.28% (rate-limit artifact).
2026-05-06 12:33:49 +00:00
admins 628226151b Add k6 load test script for 50 concurrent users
Tests login → dashboard → course page → 3 random lessons flow.
VU-level session: each VU logs in once and reuses the cookie jar.
Thresholds: p(95) < 3s, error rate < 5%.
Results on 50 VU / 5 min: p(95)=329ms, errors=4.94% (login rate-limit retries).
2026-05-06 11:51:39 +00:00
admins 9a21c705b7 Fix KinescopePlayer SSR crash on direct page load
The @kinescope/react-kinescope-player library accesses browser APIs
(window/document) during server-side rendering. In Next.js App Router,
client components are SSR-rendered on full page loads (direct URL,
refresh) but not on RSC navigations. This caused a 500 error for all
lessons with a kinescopeId when accessed directly.

Fix: defer rendering KinescopeReactPlayer until after mount with
useEffect + useState(false), so it only runs in the browser.
2026-05-06 11:42:01 +00:00
admins 7888a7598b Add coverImage poster to player, fix TipTap v3 editor reset, quiz admin preview
- Add coverImage field to Lesson model (prisma)
- Pass coverImage as poster prop to KinescopePlayer
- Show quiz in read-only preview mode for admin on lesson page
- Fix TipTap v3 editor reset on save: pass [lesson.id] as deps to useEditor
  to prevent setOptions() from reinitializing content on every re-render
- Replace saveLesson Server Action call with fetch PATCH /api/admin/lessons/[id]
  to avoid Next.js 16 automatic RSC refresh after Server Actions
- Simplify revalidatePath: only revalidate module page, not lesson editor page
2026-05-01 13:26:30 +00:00
adminsandClaude Sonnet 4.6 c25369b766 Add threaded comment replies for admin and curator
- Add parentId field to LessonComment (self-referential FK, SetNull on delete)
- Show replies indented under parent comment with left border visual
- Add reply button (visible to admin/curator only) with inline textarea
- Only root comments shown in main list; replies nested below their parent
- Update comment count to include replies
- Server-side validation: only admin/curator can reply, parent must belong to same lesson

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 13:17:30 +05:00
adminsandClaude Sonnet 4.6 6b5bfc853e Add name/email editing and days-based course access in admin user card
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 12:01:01 +05:00
adminsandClaude Sonnet 4.6 e691124058 Fix LessonFile duplication: upsert on upload, delete S3 on remove
POST /api/admin/lesson-files now checks for an existing record with the
same (lessonId, name) before uploading — replaces it (old S3 object
deleted) instead of always creating a new one. Previously every save
cycle accumulated an extra copy; 1183 duplicates occupying 6.5 GiB were
found and cleaned up.

DELETE now receives the file URL and extracts the S3 key from it, so
manual deletion actually removes the object from storage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 10:59:37 +05:00
adminsandClaude Sonnet 4.6 fdb9f96382 Add phone and birthday fields to User model with admin editor
- Add phone/birthday columns via Prisma migration
- Admin user page shows phone and birthday with inline edit UI
- UserContactEditor client component for editing contact info
- updateUserContact server action with admin-only guard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 16:43:35 +05:00
adminsandClaude Sonnet 4.6 c64f393a7b Implement platform settings (Stage 9)
- Wire settings to actual platform behavior: maintenance mode, registration toggle,
  notification emails, curator feedback emails, email verification flag
- Add logo (logoUrl, showLogo) and social network links (YouTube, VK, Telegram) settings
- Show logo + school name dynamically in student layout header
- Add footer to student layout with org requisites and social links
- Register page: read settings server-side, validate terms checkbox with legal links
- Login page: show notice when redirected from closed registration
- Settings form: add Logo and Social Networks sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 15:31:10 +05:00
adminsandClaude Sonnet 4.6 ba0a630fd9 Fix quiz attempts page: fetch users separately (no User relation on QuizAttempt)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:07:28 +05:00
adminsandClaude Sonnet 4.6 2468671d82 Fix QuizAttempt field name: createdAt -> completedAt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:06:13 +05:00
adminsandClaude Sonnet 4.6 7242a989ba Add admin quiz attempts viewer
- /admin/quizzes: list all quizzes with question and attempt counts
- /admin/quizzes/[quizId]: view all student attempts with answers per question
- Add "Тесты" link to admin sidebar navigation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 12:05:01 +05:00
adminsandClaude Sonnet 4.6 d2150153df Add quiz feature: student UI, admin editor, lesson page integration
- QuizSection component: shows questions as text inputs, read-only after submission
- QuizEditor component: admin CRUD for quiz questions with type selector
- saveQuiz/deleteQuiz server actions for admin
- submitQuizAttempt server action: idempotent, auto-marks lesson complete
- Student lesson page: renders QuizSection, updates complete button logic
- Admin lesson page: renders QuizEditor below homework section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-27 11:43:16 +05:00
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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>
2026-04-08 13:32:30 +05:00
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
adminsandClaude Sonnet 4.6 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
admins 8fdc67b4a5 Mark Stage 1.5 complete in ROADMAP 2026-04-07 12:01:19 +05:00
admins e9eff5bae5 Stage 1.5: categories, enrollment expiry, access log, bulk grant, user page 2026-04-07 11:59:13 +05:00
admins 992763aeb9 Apply Second Brain design: Fira Mono, Aubade cards, brand palette 2026-04-07 11:51:20 +05:00
admins 09325187f9 Fix createLesson return type: void instead of string 2026-04-07 11:39:51 +05:00
admins 01a9ef482c Fix DialogTrigger: remove asChild (base-ui doesn't support it) 2026-04-07 11:38:33 +05:00
admins d356dddc96 Stage 1: Course/Module/Lesson CRUD admin UI with TipTap editor 2026-04-07 11:36:27 +05:00
admins 9d82b73e58 feat: initial commit 2026-04-07 11:30:38 +05:00
admins da46f84ab8 Add S3 client for Hetzner Object Storage 2026-04-07 11:27:18 +05:00
admins b480b56caf Redirect to role-based dashboard after login 2026-04-07 11:13:24 +05:00
admins 4e6ab6fd2b Configure Better Auth to use bcrypt for password hashing 2026-04-07 11:07:47 +05:00
admins c3aefa8a0f Fix auth client baseURL — use window.location.origin auto-detect 2026-04-07 11:01:49 +05:00
adminsandClaude Sonnet 4.6 e1d24cef96 Stage 0 complete: deployed to school.second-brain.ru
Mark Stage 0 as complete in ROADMAP. App is live at
https://school.second-brain.ru with 3 test users seeded.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:57:14 +05:00
adminsandClaude Sonnet 4.6 1b028dc484 Fix: include prisma/migrations in Docker build context
Was accidentally excluded from .dockerignore, causing migrate deploy
to find no migration files and skip all schema creation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:53:19 +05:00
adminsandClaude Sonnet 4.6 4a627c3fad Add initial database migration
Generated baseline migration from Prisma 7 schema using:
  prisma migrate diff --from-empty --to-schema prisma/schema.prisma --script

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:52:49 +05:00
adminsandClaude Sonnet 4.6 f0f13f22d9 Fix runner stage: copy full node_modules for Prisma CLI
Cherry-picking modules missed @prisma/engines and other required
binaries. Copy the entire node_modules to runner to ensure
prisma migrate deploy works correctly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:50:15 +05:00
adminsandClaude Sonnet 4.6 1153bcc13a Add Prisma 7 PostgreSQL adapter
Prisma 7 requires explicit database adapter for runtime connections.
- Install @prisma/adapter-pg + pg
- Update prisma.ts: use PrismaPg adapter with DATABASE_URL
- Update seed.ts: same adapter pattern
- Dockerfile: copy pg deps to runner stage

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:48:08 +05:00
adminsandClaude Sonnet 4.6 0c88dcc535 Fix Prisma 7 client instantiation
In Prisma 7, connection URL is managed via prisma.config.ts.
PrismaClient constructor no longer accepts log options directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:46:43 +05:00
adminsandClaude Sonnet 4.6 017833cd99 Fix seed.ts import and exclude prisma dir from Next.js tsc
- seed.ts: use ../src/generated/prisma/client (Prisma 7 entry point)
- tsconfig.json: exclude prisma/ so seed.ts is not type-checked by Next.js build

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:45:56 +05:00
adminsandClaude Sonnet 4.6 d603b32ef5 Fix Prisma 7 import: use /client suffix
Prisma 7 no longer generates index.ts — entry point is client.ts.
Import changed from @/generated/prisma to @/generated/prisma/client.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:45:18 +05:00
adminsandClaude Sonnet 4.6 024cf7adac Fix build errors for Next.js 16 + Prisma 7
- Fix Prisma import: use @/generated/prisma alias (resolves Turbopack issue)
- Replace middleware.ts with proxy.ts (Next.js 16 convention)
- middleware function renamed to proxy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:40:59 +05:00
adminsandClaude Sonnet 4.6 8d3ff24e52 Add production Docker setup
- Dockerfile: multi-stage build (deps → builder → standalone runner)
- docker-compose.prod.yml: app on port 3010 + PostgreSQL 16
- entrypoint.sh: runs prisma migrate deploy then starts node server
- next.config.ts: standalone output for minimal Docker image
- .dockerignore: exclude dev files from build context

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:38:33 +05:00
adminsandClaude Sonnet 4.6 2f52d869d9 Update CLAUDE.md: add Gitea URL rule
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:32:50 +05:00
adminsandClaude Sonnet 4.6 80ca4b2d9d Initialize Stage 0: Next.js 16 scaffold with auth and role-based routing
- Next.js 16.2.2 + React 19 + TypeScript + Tailwind v4
- Better Auth with email/password and role system (student/curator/admin)
- Prisma 7 schema: User, Session, Account, Verification + full LMS model
- Role-based dashboards: student /dashboard, curator /curator/dashboard, admin /admin/dashboard
- Auth pages: login, register, verify-email
- Better Auth API route handler
- Middleware for route protection
- Docker Compose with PostgreSQL 16
- Seed script with test users (admin/curator/student)
- CLAUDE.md and ROADMAP.md project documentation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 10:32:37 +05:00