Lexiverse
Lexiverse - 영어 학습자를 위한 AI 기반 문맥 독해 엔진
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 README에서 읽을 수 있습니다. 저장소 README ↗
README 전체를 불러오는 중입니다.
README 전문 보기 ↗A modern student management system for Mathabah Institute, built with
Next.js 14 (App Router), Supabase, Tailwind CSS, shadcn/ui and Resend.
Three roles: admin, teacher, student. All registrations are held
as pending until an admin approves them.
Status: All six phases are implemented. The app now ships with notifications, announcements, an admin audit log and course resources on top of the Phase 1–5 foundation.
| Area | Choice |
|---|---|
| Framework | Next.js 14 (App Router, RSC) |
| Styling | Tailwind CSS + shadcn/ui |
| Database / Auth | Supabase (Postgres + Auth + RLS) |
| Resend | |
| PDFs (Phase 5) | @react-pdf/renderer via API routes |
| Deploy target | Vercel |
The brand palette is black, dark red (#7a0a13 / #9b1c2b) and gold
(#c9a14a / #e6c878) to reflect Islamic academic tradition.
/auth/register, /auth/login, /auth/pendingprofiles row on signup (DB trigger), default
role = 'student', status = 'pending'middleware.ts that gates every route on auth + role + approval statusPOST /api/resend/send-approval invoked on registration → notifies adminapp/
api/resend/send-approval/route.ts ← admin notification on register
auth/
layout.tsx
login/page.tsx + login-form.tsx
register/page.tsx + register-form.tsx
pending/page.tsx + sign-out-button.tsx
dashboard/page.tsx ← redirects based on role
admin/page.tsx ← Phase 2+ home
teacher/page.tsx ← Phase 3+ home
student/page.tsx ← Phase 4+ home
layout.tsx
globals.css
page.tsx ← marketing landing
components/
ui/ ← shadcn primitives (Button, Card, …)
shared/
BrandMark.tsx
RoleShell.tsx
SignOutLink.tsx
lib/
supabase/
client.ts ← browser client
server.ts ← server-component / route-handler client
middleware.ts ← edge cookie refresh helper
types.ts
resend.ts ← all 6 email triggers
utils.ts
supabase/
migrations/
0001_initial_schema.sql
0002_rls_policies.sql
middleware.ts ← route protection + role routing
The full directory tree from the spec (admin/students, admin/teachers, teacher/my-courses, student/grades, etc.) will be added as Phases 2–6 land. The current admin/teacher/student home pages document which routes belong to which phase.
⚠️ The original task mentioned "Use the following exact database schema" but the block that followed was the directory tree, not a SQL schema. The schema in
supabase/migrations/0001_initial_schema.sqlis a complete, self-consistent design that covers every entity referenced in the spec. If you have an exact schema you want to use instead, drop it in and replace the migration before applying.
Tables created:
| Table | Purpose |
|---|---|
profiles | One row per auth.users. Holds role and status. |
students | Student profile data (guardian info, address, …). |
teachers | Teacher bio, specialisation, employment data. |
programs | Top-level academic programs. |
courses | Courses within a program, owned by a teacher. |
enrollments | Student ↔ course join with status. |
attendance | Per-session attendance keyed off enrollment. |
assessments | Assessment definitions per course. |
grades | Per-enrollment, per-assessment scores. |
payments | Payment ledger per student. |
teacher_reports | Mid-course / end-of-course / concern reports. |
announcements | Audience-targeted broadcasts. |
notifications | In-app notification bell items. |
audit_logs | Admin audit trail. |
course_resources | Course handouts / links (Phase 6). |
A trigger on auth.users auto-creates a matching profiles row with
role = 'student' and status = 'pending'.
0002_rls_policies.sql enables RLS on every table and applies the policies
described in the spec:
is_visible_to_student = true.npm install
supabase/migrations/ in order. Easiest options:
supabase db pushupdate public.profiles
set role = 'admin', status = 'approved', approved_at = now()
where email = '[email protected]';
Copy .env.example to .env.local and fill it in:
cp .env.example .env.local
| Variable | Notes |
|---|---|
NEXT_PUBLIC_SUPABASE_URL | Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY | Supabase anon (publishable) key |
SUPABASE_SERVICE_ROLE_KEY | Service role key — used by trusted routes |
RESEND_API_KEY | Resend API key |
RESEND_FROM_EMAIL | Verified sender e.g. Mathabah <…> |
ADMIN_NOTIFICATION_EMAIL | Inbox to notify on new registrations |
NEXT_PUBLIC_APP_URL | Public URL of the deployment |
npm run dev
Visit http://localhost:3000 and try the flow:
/auth/pending and admin will receive a Resend email./admin
instead of pending.All six triggers from the spec live in lib/resend.ts:
| Trigger | Function | Recipient |
|---|---|---|
| New user registers | sendNewRegistrationToAdmin | Admin |
| Admin approves account | sendApprovalWelcome | New user |
| Admin rejects account | sendApprovalRejection | Rejected user |
| Teacher submits report | sendTeacherReportToAdmin | Admin |
| Payment recorded | sendPaymentConfirmation | Student |
| New announcement | sendAnnouncement | Targeted users |
The first trigger is wired up in this phase via
POST /api/resend/send-approval. The remaining five will be invoked from the
relevant Phase 2+ API routes (/api/auth/approve, /api/payments, etc.).
/admin/* is fully gated by middleware
POST /api/auth/approve for non-UI callersaudit_logs(enrollment_id, session_date)(enrollment_id, assessment_id)is_visible_to_student toggle, list of past reportsconcern report fires the
sendTeacherReportToAdmin Resend trigger and creates in-app
notifications for every approved admin (via service role to bypass RLS)assertTeacherOwnsCourse() and check
the teacher actually has the student enrolled before writing a reportis_visible_to_student = true (RLS-enforced, belt-and-braces filter)updateStudentProfile which relies on the self-update RLS policies
on profiles and studentsThree branded PDF documents rendered server-side with
@react-pdf/renderer, protected by per-role access checks:
/api/pdf/student-report/[studentId]) —
title block, meta (email, student number, enrolment date), overall
attendance callout, per-course sections with teacher, weighted
average, attendance tallies, and a full assessments / grades table
with scores and feedback/api/pdf/payment-receipt/[paymentId]) —
branded header, MTB-XXXXXXXX receipt number, received-from block,
large amount callout, method / reference / recorded-by details and
notes/api/pdf/teacher-report/[reportId]) — header,
title, teacher + student meta, a red concern callout when the
report type is concern, body and a signature blocklib/pdf/styles.ts + lib/pdf/render.ts — brand palette,
table primitives, lazy-imported renderToBuffer so the large
@react-pdf/renderer bundle only loads in the Node runtime of the
route handlerexperimental.serverComponentsExternalPackages set to keep
@react-pdf/renderer out of the edge/client bundlesis_visible_to_student = true (RLS does most of the work, with
explicit guards inside the route handlers)app/teacher/my-courses/[id]/page.tsx where
the students rollup was using profiles.id instead of students.id,
which broke the "Write report" link and would have broken the new
PDF linkThe final polish phase closes out every cross-cutting concern in the spec:
notifications table is wired up end to end.
lib/notifications/actions.ts exposes markNotificationRead and
markAllNotificationsRead (both relying on the notifications_self RLS
policy so the action runs under the user's own client)components/shared/NotificationBell.tsx mounted in the admin, teacher
and student layouts. Shows an unread count badge (capped at 9+) and
deep-links into the per-role /notifications inbox pagecomponents/shared/NotificationsList.tsx renders
the notifications list with "mark read" / "mark all read" buttons. Thin
app/admin/notifications, app/teacher/notifications and
app/student/notifications pages mount it inside each role layoutlib/announcements/actions.ts implements
createAnnouncement + deleteAnnouncement with audience targeting
(all / admins / teachers / students). Publishing writes the
announcement row, fans out a notifications row per recipient via the
service-role client, sends the Resend broadcast through
sendAnnouncement, and records an audit_logs entry/admin/announcements now has a real
compose form (title + audience + body) and a Published table with
inline deletecomponents/shared/AnnouncementsFeed.tsx
widget mounted on the admin, teacher and student overview pages. RLS
(announcements_audience_r) automatically filters to what the viewer
is allowed to see/admin/audit-log page with entity-type and
title filters over the latest 100 audit events. Shows the actor, action,
entity and metadata for every admin mutation. Added to the admin
sidebar as a new nav entry/teacher/my-courses/[id]. Backed by addCourseResource and
deleteCourseResource in lib/teacher/actions.ts, both gated by
assertTeacherOwnsCourse. Students see the same list read-only via a
Resources tab on , filtered by the
RLS policy| Phase | Description | Status |
|---|---|---|
| 1 | Foundation — auth, schema, RLS, register/login/pending, Resend | ✅ shipped |
| 2 | Admin dashboard, approvals, students/teachers/courses CRUD | ✅ shipped |
| 3 | Teacher portal — courses, attendance, grades, reports | ✅ shipped |
| 4 | Student portal — courses, grades, payments, profile | ✅ shipped |
| 5 | PDF reports via @react-pdf/renderer | ✅ shipped |
| 6 | Notifications, announcements, audit log, course resources | ✅ shipped |
/student/my-courses/[id]resources_student_read/admin/reports
is replaced with a real teacher-reports list with type + title filters
and per-row PDF export links pointing at the Phase 5 endpoints