Lexiverse
Lexiverse - AI contextual reading engine for English learners. Your next article is your next review.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 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