A multi-tenant school management platform: public website, role-based dashboards (admin, teacher, student, super admin), and a Node.js API backed by PostgreSQL. The system covers exams, marks, automated merit lists, marksheet PDFs, attendance SMS, admissions, registration, notices, gallery, and more.
Built with pnpm workspaces. Shared packages keep validation and UI consistent across apps.
School/
βββ server/ # Express API, Prisma, background workers
βββ dashboard/ # Vite + React (admin / teacher / student / super_admin modes)
βββ client-next/ # Next.js public school website
βββ client/ # Legacy public client (Vite)
βββ workers/
β βββ auth-bff/ # Cloudflare Worker β auth BFF
β βββ tenant-router/ # Cloudflare Worker β subdomain β tenant routing
βββ packages/
β βββ shared-schemas/ # Zod schemas (frontend + backend)
β βββ common-ui/ # Shared UI primitives
βββ docker-proxy/ # Local dev reverse proxy
βββ server/docs/ # Deep-dive technical docs (e.g. marksheets)
| App | Purpose | Default dev port |
|---|---|---|
| server | REST API, Prisma, Bull workers, PDF generation | 5000 (see PORT) |
| dashboard (admin) | School admin panel | 5174 |
| dashboard (student) | Student portal | 5175 |
| dashboard (teacher) | Teacher portal | 5176 |
| dashboard (super_admin) | Platform / multi-school admin | 5177 |
| client-next | Public institutional website | 3000 |
| workers/auth-bff | Cookie/session edge worker | 8787 |
flowchart LR
subgraph clients [Clients]
WEB[client-next Public site]
ADM[Dashboard Admin]
TCH[Dashboard Teacher]
STU[Dashboard Student]
end
subgraph edge [Cloudflare Workers]
TR[tenant-router]
BFF[auth-bff]
end
subgraph backend [Server]
API[Express API]
W[Marksheet Worker in-process]
Q[Bull Queue Redis]
end
subgraph data [Data]
PG[(PostgreSQL + RLS)]
R2[(Cloudflare R2)]
RD[(Redis)]
end
WEB --> TR
ADM --> TR
TCH --> TR
STU --> TR
TR --> BFF
BFF --> API
API --> PG
API --> Q
Q --> RD
W --> Q
W --> R2
W --> PG
- Multi-tenant: Schools are isolated via subdomain routing and Postgres row-level security (RLS) (
school_idcontext on each request). - Source of truth: Postgres (
marks, enrollments, exams). R2 and cache tables are disposable PDF cache. - Background jobs: Bull + Redis β marksheet PDF queue, SMS, and other async work.
- Exams β create exams, assign classes, upload exam routine PDFs, publish/unpublish (
visible). - Mark entry β TOTAL or BREAKDOWN (CQ / MCQ / Practical) with validation; teachers limited to assigned sections.
- View marks β class grid sorted by subject priority; per-student details; download exam PDFs.
- Merit & promotion β class merit lists,
final_merit, auto-promotion fields (next_year_roll,next_year_section). - Public results β login with student ID + parent phone; published exams only.
All exam marksheets are rendered only in a background worker (PDFKit). HTTP handlers never render inline. Cached PDFs live in Cloudflare R2 with hash-verified staleness.
| PDF type | Who downloads | Auto background? |
|---|---|---|
| Per-student exam | Student, teacher, admin, public | Yes on publish, mark save (if published), teacher/head/level change, progress UI gap-fill |
| Class bundle | Admin (ALL), teacher (section) |
On download; auto only on teacher/head/level change |
| Session student | Student, teacher, admin | On download only |
| Session year | Admin | On download only |
Publish vs hidden exams
| Exam state | Save marks | PDF generation |
|---|---|---|
Hidden (visible = false) |
Saves to DB only | On download (any authorized role) |
| Published | Auto-invalidates per-student cache | Normal background + on download |
Progress UI β View Marks and Exam PDF Routine poll GET /api/marks/generation-status/:examId, show generation progress, and list outdated bundles (bundles.staleItems) before download.
Full specification: server/docs/marksheet-regeneration.md
- Online admission, merit/waiting lists, class 6 / 8 / 9 registration forms (Puppeteer PDFs for form output).
- Student CRUD, photos, fourth subject, alumni transition.
- Teachers β profiles, signatures (used on marksheets), class assignments (
levels). - Head of institution message and signature on marksheets.
- Syllabus, holidays, citizen charter, class & exam routines.
- Notices with PDF attachments.
- SMS β attendance alerts, templates, delivery logs (Bulk SMS API).
- Email β Brevo integration.
- Events and gallery with student upload + admin approval workflow.
| Capability | Admin | Teacher | Student | Public |
|---|---|---|---|---|
| Manage exams / levels | β | β | β | β |
| Enter / edit marks | β | β (assigned) | β | β |
| View class marks | β | β (assigned) | β | β |
| Download exam marksheet | β | β | β (own) | β (published only) |
| Download class bundle | β | β (section) | β | β |
| Session year PDF | β | β | β | β |
| Publish results | β | β | β | β |
| Attendance / SMS | β | β | β | β |
| Gallery approval | β | β | β | β |
| Layer | Technology |
|---|---|
| Dashboard | React 19, Vite, TanStack Query, Tailwind 4, shadcn/Radix, Framer Motion |
| Public site | Next.js 16, React 19, Tailwind 4 |
| API | Node.js, Express (ESM), TypeScript, Zod |
| Database | PostgreSQL, Prisma, RLS per school |
| Queue | Bull, Redis (ioredis) |
| Marksheet PDFs | PDFKit, pdf-to-img rasterization, hash cache on R2 |
| Other PDFs | Puppeteer (admission / registration forms) |
| Storage | Cloudflare R2 (primary), Cloudinary (images) |
| Edge | Cloudflare Workers (tenant routing, auth BFF) |
| Observability | Winston, Sentry (optional) |
- Node.js 20+
- PostgreSQL
- Redis (required for marksheet queue and other Bull jobs)
- Cloudflare R2 credentials (for file storage and marksheet cache)
git clone https://github.com/Mutiur03/School.git
cd School
pnpm installCreate env files from samples in each app:
| Path | Purpose |
|---|---|
server/.env |
Database, JWT, Redis, R2, SMS, Brevo, Sentry |
dashboard/.env.admin (and .teacher, .student, .super_admin) |
API URL, mode-specific config |
client-next/.env |
Public site API / analytics |
Server β required
DATABASE_URL=postgresql://...
JWT_SECRET=...Server β marksheets & files
REDIS_HOST=127.0.0.1
R2_ACCOUNT_ID=...
R2_ACCESS_KEY_ID=...
R2_SECRET_ACCESS_KEY=...
R2_BUCKET_NAME=...
R2_PUBLIC_URL=https://...Server β optional tuning
MARKSHEET_WORKER_CONCURRENCY=1
MARKSHEET_SERVE_TIMEOUT_MS=180000
MARKSHEET_SERVE_POLL_MS=500cd server
pnpm exec prisma generate
pnpm exec prisma migrate dev
pnpm run db:seedAll services (recommended on Linux/macOS):
./run-all.shStarts server, client-next, shared package watchers, dashboard modes (admin, teacher, super_admin), and auth-bff worker.
Minimal (root package.json):
pnpm run devIndividual:
pnpm run dev:server
pnpm --filter dashboard dev:admin
pnpm run dev:client-nextEnsure Redis is running before starting the server β the marksheet worker registers on boot.
pnpm run build
# or separately:
pnpm run build:server
pnpm run build:dashboard
pnpm run build:client:core| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/marks/addMarks |
admin, teacher | Save marks |
GET |
/api/marks/getClassMarks/:class/:year/:exam |
admin, teacher | Class mark grid |
GET |
/api/marks/:id/:year/:exam/download |
admin, teacher, student | Per-student exam PDF |
GET |
/api/marks/class-exam/:class/:year/:exam/download |
admin, teacher | Class bundle PDF |
GET |
/api/marks/:id/:year/download |
admin, teacher, student | Session student PDF |
GET |
/api/marks/all/:year |
admin | Session year PDF |
GET |
/api/marks/generation-status/:examId |
admin, teacher | Progress + stale bundles |
POST |
/api/marks/public/verify |
public | Public result login |
GET |
/api/marks/public/download |
public token | Published exam PDF |
| Document | Contents |
|---|---|
server/docs/marksheet-regeneration.md |
PDF types, triggers, hashes, worker flow, progress UI |
dashboard/README.md |
Dashboard-specific notes |
client-next/README.md |
Public site notes |
server/src/
βββ modules/marks/ # Marks CRUD, marksheet service, worker, queue
βββ modules/level/ # Classβteacher assignments
βββ modules/teacher/ # Teacher + head signatures
βββ controllers/examController.js
βββ middlewares/ # Auth, tenant, RLS
βββ config/ # Prisma, R2, Redis, env
- Live demo: Panchbibi School
- Video walkthrough: YouTube
Developed by Mutiur Rahman.