TutorLoom
The learning platform for companies, colleges and training institutes. Free and open source, with an Enterprise edition.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Student Progress & School Portal - The Suman Nirmal Minda School, Ahmedabad
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗A school-owned, mobile-responsive web portal (classes I–XII). Its spine is a continuous, year-on-year student progress record with real analytics, wrapped in attendance, announcements/events, monthly reports, leave and parent feedback.
Access is driven by allotment, enforced at the database with Supabase Row Level Security — the UI hiding data is never the security boundary.
This deployment now points at its own dedicated Supabase project
(NEXT_PUBLIC_SUPABASE_URL in .env.local) — no longer the shared KV IIT
Kharagpur project this codebase was forked from. All migrations in
supabase/migrations/ (through 0031) are already applied to it, and the
site is seeded with Suman Nirmal Minda School's own students, staff and
allotments.
Production (suman-nirmal-minda-school.vercel.app) is deployed against this
same project, with the environment variables set to match — verified live in
a browser for the parent and office roles, including live bus tracking.
Still outstanding:
RESEND_API_KEY is not yet set on the transport-alert Edge Function, so
queued bus-alert emails to guardians are held rather than sent (see
Bus alerts below).Everything school-specific lives in src/lib/school.ts — name, sub-line, emblem,
sign-in photo, browser title, monogram — each overridable with a NEXT_PUBLIC_SCHOOL_*
env var (see .env.example). No school name is hardcoded in any component.
Drop the official emblem at public/brand/school-logo.png (see public/brand/README.md);
until it exists the app renders a typographic SM monogram rather than an invented logo.
With no sign-in photograph configured, the sign-in page shows a plain branded panel.
globals.css @theme.pg_cron.src/components/icons.tsx).src/i18n), localised numbers & dates.On the login screen, one tap signs you in as each role. Password (all): kviit@demo1.
| Role | Scope | |
|---|---|---|
| Principal | [email protected] | Whole school |
| Class Teacher | [email protected] | VIII-A (all subjects, full history) |
| Subject Teacher | [email protected] | Mathematics across allotted sections |
| Parent / Guardian | [email protected] | Two children (sibling switcher) |
| Student | [email protected] | Own record only |
| Office / Admin | [email protected] | Manage; unrestricted read |
Each lands in a DB-scoped view — RLS returns zero rows outside scope regardless of what the client asks for.
npm install
# .env.local already contains the public Supabase URL + anon key
npm run dev # http://localhost:3000
All schema lives in supabase/migrations/ and is already applied to the linked project.
To re-apply / point at another project, run them in order with the helper:
export SUPABASE_ACCESS_TOKEN=... # Supabase personal access token
export SUPABASE_REF=... # project ref
node scripts/apply-sql.mjs supabase/migrations/0001_core_schema.sql
# … 0002 … through 0008
| Migration | Purpose |
|---|---|
0001_core_schema | 25 tables, enums, constraints, indexes |
0002_security | app scope helpers + RLS policies on every table |
0003_analytics | RLS-aware views + RPC (trends, distributions, top/needs-support, auto-conclusions) |
0004_rls_performance | Set-based helpers so large tables stay fast under RLS |
0005_history_scope | Class teacher sees each student's full prior-year history |
0006_slippage_job | refresh_slippage_flags() — scheduled early-slippage computation |
0007_cron | Nightly pg_cron schedule for the slippage job |
0008_storage | brand (public) + reports (private) Storage buckets |
0009…0021 | Student features, attendance/marks refinements, dashboard overview, exams & promotion |
0022…0031 | Transport: schema, RLS, live tracking, trip/delay/crew handling, and the alert job |
export SUPABASE_SERVICE_ROLE=... # server-only key
node scripts/seed.mjs # ~270 students, 2 years of marks, attendance, comms
node scripts/seed-auth.mjs # demo auth users + profile links
node scripts/verify-rls.mjs # proves each role only sees its scope
verify-rls.mjs output (proof the boundary holds):
role students marks attendance slippage
principal 270 22680 8100 5
classteacher 30 2520 900 2
teacher 150 1440 4500 3
parent 2 168 60 0 ← never sees slippage
student 1 84 30 0 ← own record only
teacher_allotment (staff × section × subject, with is_class_teacher) drives everything.
Private app.* helpers (SECURITY DEFINER) resolve the caller's scope once per query:
pg_cron).supabase/functions/)| Function | Purpose |
|---|---|
absence-email | Emails guardians of students marked absent (Resend) |
monthly-report | Generates a class's monthly reports in one step → Storage + email |
transport-alert | Drains the bus-alert outbox and emails guardians (see below) |
Deploy (needs the Supabase CLI + RESEND_API_KEY secret):
supabase link --project-ref $SUPABASE_REF
supabase functions deploy absence-email
supabase functions deploy monthly-report
supabase secrets set RESEND_API_KEY=...
transport-alert)Deploying needs no CLI — the Management API takes the bundle directly:
export SUPABASE_ACCESS_TOKEN=... # personal access token
export SUPABASE_REF=... # project ref
node scripts/deploy-function.mjs transport-alert
The database queues alerts into transport_alert the instant a geofence or ETA
trigger observes something worth telling a family; pg_cron calls the function
every minute to drain the queue. The dispatcher reads its own URL and key from
Vault, not from a database parameter (a managed project will not let you set
one):
select vault.create_secret('https://<ref>.functions.supabase.co', 'transport_functions_url');
select vault.create_secret('<service-role key>', 'transport_service_key');
Mail itself is the last step. Until RESEND_API_KEY is set on the function, it
holds the queue rather than draining it — so nothing is silently marked sent
and nothing is thrown away before it could be delivered:
supabase secrets set RESEND_API_KEY=... # or set it in the dashboard
Warm, institutional: gold = aspiration, warm ink = trust; the tricolour
green/saffron appear only as data-status colours. Inter everywhere, hairline borders, soft
warm shadows, consistent rounding. The official emblem drops into
public/brand/school-logo.png (a typographic monogram ships until then — no invented logo).
.env.local SUPABASE_SERVICE_ROLE_KEY, Edge Functions). Never shipped to the client.