Agilearn is a school-management platform for teachers and administrators. It brings classrooms, rosters, weighted gradebooks, attendance tracking, and a shared teaching-modules library into one calm, dark-leaning workspace.
Built as a Vite + React single-page app backed by Supabase, with Postgres Row Level Security as the access-control boundary. There is no application server β the browser holds the anon key, RLS enforces access per user, and Vercel serves the static frontend.
For Teachers:
- Classrooms & rosters β organize courses by year and block; bulk-import rosters from spreadsheets; manage students by name and identifier.
- Weighted gradebook β spreadsheet-like grading grid; organize by periods β categories (lecture/laboratory) β activities; final grade = lecture weight Γ lecture component + lab weight Γ lab component (default 40/60). All grade math is pure and unit-tested in one module.
- Attendance tracking β create class sessions; mark each student present, absent, late, or excused; view per-student summaries.
- Teaching modules β shared library of lesson plans, activity stories, and resources in a private storage bucket.
- Analytics & calendar β per-classroom insights, calendar view of sessions and grading periods.
- Slideshow β present classroom grades in a full-screen, themed slideshow.
- Import/export β read and write rosters and grades as Excel workbooks; export grades to PDF.
For Administrators:
- User & role management β manage teacher accounts, assign roles, view audit trail of admin actions.
- Domain allowlist β approve email domains for teacher self-signup; manage domain requests.
- School-wide analytics β overview dashboard; analytics on usage and grade distributions.
- Audit log β track admin actions for compliance and debugging.
Platform:
- Installable PWA β install as an app; works offline with automatic sync when reconnected.
- Dark-leaning UI β calm, focused interface; responsive across desktop and tablet.
- Email auth β teacher self-signup is domain-gated (self-serve); admins are provisioned out-of-band.
- Security β RLS enforces that teachers see only their own classrooms and data; admins see everything. No privileged backend path.
See docs/ARCHITECTURE.md for system design and CONTRIBUTING.md for contributor rules.
| Layer | Technology |
|---|---|
| Frontend | React 19 + TypeScript (strict mode) + Vite (dev server & build) |
| Routing | TanStack Router (file-based, type-safe) |
| State | TanStack Query (server state + caching) + Zustand (local state) |
| Tables | TanStack Table (virtualized gradebook & rosters) + TanStack Virtual |
| Styling | Tailwind CSS v4 (CSS-first, no config file) + Radix UI primitives + Motion (animations) |
| Backend | Supabase: Postgres (RLS enforces access) + Auth (email/OTP) + Storage (private bucket for teaching modules) |
| Import/Export | pdf-lib (PDF generation) + xlsx (Excel read/write) |
| Observability | Bugsnag (error tracking & performance monitoring) |
| Testing | Vitest (unit tests) + Testing Library (component testing) |
| PWA | vite-plugin-pwa (service worker + offline shell) |
| Package Mgr | pnpm v11.22+ (lockfile + workspace-aware runner) |
- Node.js 18+ (pnpm requires Node for the package manager)
- pnpm 11+ (install globally or use
npm install -g pnpm@11) - Supabase project with credentials (get URL + anon key from supabase.com)
# Clone and install dependencies
git clone https://github.com/azialah/agilearn.git
cd agilearn
pnpm install
# Copy the environment template and add Supabase credentials
cp .env.example .env
# Edit .env: fill in VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY
# Start the dev server
pnpm devOpen the printed local URL (usually http://localhost:5173).
| Command | Purpose |
|---|---|
pnpm dev |
Start the Vite dev server with HMR |
pnpm build |
Typecheck (tsc -b) + build for production |
pnpm preview |
Preview the production build locally |
pnpm run test |
Run the test suite (Vitest) |
pnpm run typecheck |
Type-check without emitting (quick CI feedback) |
pnpm run format |
Format code with Prettier |
pnpm run lint |
Check formatting (CI gate, no ESLint) |
Create .env from .env.example. Required variables:
VITE_SUPABASE_URLβ your Supabase project URL (public, Vite-inlined)VITE_SUPABASE_ANON_KEYβ the anon public key (public, used in the browser)
service_role key, database password, or any other secret in this file or the app.
src/
routes/ TanStack Router file-based routes (routeTree.gen.ts is auto-generated)
_auth/ Authenticated routes (gated by Supabase session)
teacher/ Teaching surfaces (dashboard, classrooms, grades, attendance, modules, analytics)
admin/ Admin surfaces (users, domain requests, overview, audit log)
settings.* Account settings (both roles)
teacher.signup.* Domain-gated teacher onboarding wizard (pre-auth)
index.tsx Landing page
login.tsx Sign-in page
forgot-password.tsx Password recovery (OTP)
about.tsx, features.tsx, privacy.tsx, terms.tsx Public pages
features/ Feature UI + business logic (one dir per major feature)
teacher/ Teaching features
dashboard/ Home dashboard (grade/attendance summary)
classrooms/ Classroom management, roster
grades/ Weighted gradebook grid
attendance/ Session tracking + attendance records
modules/ Teaching modules library
slideshow/ Grade slideshow presentation
analytics/ Per-classroom analytics
calendar/ Calendar view
profile/ Teacher profile
usage/ Usage stats
io/ Import/export helpers (PDF/xlsx generation)
notifications/ Notification system
onboarding/ Teacher signup wizard
admin/ Admin features
auth/ Shared auth UI (login, signup, password reset flows)
settings/ Account settings (shared across roles)
landing/ Marketing landing page
public/ Public legal pages
lib/
supabase.ts Typed Supabase client (createClient<Database>)
database.types.ts Postgres schema as TypeScript types (keep in sync with migrations)
grading.ts Grade calculation logic (pure, no Supabase imports, unit-tested)
queries/ TanStack Query hooks (the only place Supabase is read/written)
keys.ts Query-key factory (used for cache invalidation)
theme.ts, locale.tsx, cn.ts Utility modules
components/
ui/ Reusable design-system primitives (built on Radix UI + Tailwind)
layout/ App shell, top bar, page layouts
types/
domain.ts Friendly type aliases derived from database.types
styles/
app.css Global styles + Tailwind v4 CSS-first tokens under @theme
test/ Test utilities and mocks
supabase/
migrations/ Ordered SQL files (source of truth for DB schema)
0001_profiles_roles.sql auth users, roles, RLS helper functions
0002_classrooms.sql courses, year, block, weights
... (through 0038_performance_indexes.sql)
seed.sql Sample data for local development only
config.toml Supabase local configuration
.github/workflows/ci.yml CI pipeline: format:check β typecheck β test β build
vercel.json Vercel deployment config (build command, output directory, SPA rewrite)
.env.example Template environment variables
package.json Dependencies (do not edit; use pnpm install)
Generated files (do not edit):
src/routeTree.gen.tsβ auto-generated fromsrc/routes/**; regenerates on dev/builddist/β build output; generated bypnpm build
Access Control:
- RLS in Postgres is the real security boundary. Teachers only ever see their own classrooms; admins see everything.
- Two helper functions (
is_admin(),owns_classroom()) enforce access in every table policy. - No server backend, no service-role key in the client.
Data Model:
- 10 tables: profiles, classrooms, students, grading_periods, activity_categories, activities, scores, class_sessions, attendance_records, teaching_modules.
- 1 view: v_class_roster (classroom Γ students, security-invoker).
Grade Math:
- Lives in one pure module:
src/lib/grading.ts(no Supabase imports, fully tested ingrading.test.ts). - Rollup: activities β categories β per-component totals β final grade = lecture component Γ lecture_weight + lab component Γ lab_weight.
Offline:
- Installed as a PWA; service worker caches the shell and API responses.
- Mutations queue locally when offline; sync when reconnected (via
offlineQueue.ts).
See docs/ARCHITECTURE.md for system design.
Frontend: Vercel (static SPA with SPA rewrite)
Backend: Supabase (Postgres + Auth + Storage)
Full setup walkthrough: docs/DEPLOYMENT.md
# Vercel deployment
# Push to GitHub; Vercel auto-deploys from main (configured in .vercelignore for non-runtime files)
git push origin mainEnvironment on Vercel:
VITE_SUPABASE_URLβ Project URLVITE_SUPABASE_ANON_KEYβ Anon public key
No database migrations or secrets ship in the app β manage Supabase separately via the dashboard or CLI.
- ARCHITECTURE.md β System design, layers, data model, auth, storage, deployment pipeline
- DEPLOYMENT.md β Supabase provisioning, schema application, first admin setup, Vercel deploy
- CONTRIBUTING.md β Contributor contract, project layout, hard rules, CI gate, naming conventions
- BACKLOG.md β Three-milestone roadmap with acceptance criteria and implementation context
- EMAIL_DELIVERY_ROADMAP.md β Email notification system design
- MOBILE.md β Mobile-first design and responsive behavior
- STORAGE_QUOTA_ADMIN_HANDOFF.md β Supabase storage quotas and admin responsibilities
Before committing, run the CI order locally:
pnpm run format:check # Check formatting (Prettier)
pnpm run typecheck # Check types (TypeScript)
pnpm run test # Run tests (Vitest)
pnpm run build # Build for productionAll must pass. There is no ESLint β Prettier is the only lint gate.
- Read CONTRIBUTING.md for the contributor contract (layout, rules, commands).
- Create a feature branch from
main. - Make changes; run the quality gate above.
- Open a pull request with a clear description.
- Address review feedback; re-run the gate before merge.
Key rules:
- Keep routes thin, features fat.
- Grade math lives only in
src/lib/grading.ts. - Query keys come from
src/lib/queries/keys.ts. - Never add dependencies; use pnpm's existing packages.
- No AI attributions in code or comments.
LICENSE (if applicable)
Last updated: 2026-08-31
Project status: Active development, production-ready for school management