Overview
EMIS (Education Management Information System) coordinates student records, fee structures, examinations, and reporting. The product goal is trust: finance and academic staff need an audit trail for every change.
Problem
School operations mix high-volume CRUD (enrollment, attendance) with low-volume, high-risk actions (fee overrides, mark entry, result publication). A generic CRUD app would lose the ability to reconstruct who changed what when disputes occur.
Architecture
- MongoDB for flexible document shapes where modules evolve (exam metadata, attachments) with strict schema validation at the application boundary.
- Redis for caching hot reference data (academic year config, active terms) and ephemeral session assists.
- Next.js + React surfaces for staff; Node/Express exposes versioned APIs consumed by both web and eventual mobile clients.
- Docker + CI for consistent environments between Nepal-based dev machines and cloud deploys.
Schema & auditing
Fee structures are versioned. Adjustments apply to a window; historical invoices remain tied to the snapshot that was active when they were issued.
Audit fields are first-class: actor, timestamp, previous hash or diff pointer—enough to answer compliance questions without drowning in raw JSON.
Exam module
Seat plans, routines, and mark entry share a workflow state machine:
- Draft routine
- Locked for entry
- Review
- Published results
Illegal transitions return domain errors, not generic 400s, so the UI can guide recovery.
Reporting
PDF/CSV exports run asynchronously when datasets exceed a threshold size. Staff see job status instead of blocking HTTP requests—better UX and fewer gateway timeouts.
Technical challenges
| Area | Mitigation |
|---|---|
| Concurrent mark entry | Optimistic locking on marksheet rows; conflicts surfaced to the user |
| Large CSV exports | Streaming responses + worker queue for big jobs |
| RBAC sprawl | Permission strings namespaced by module; middleware composes checks |
Performance
- Indexes on studentId + academicYear patterns used by every list screen.
- Aggregation pipelines reviewed with explain before shipping new dashboards.
Tradeoffs
- Mongo vs Postgres for EMIS: documents win for evolving forms; relational reporting paths sometimes require denormalized read models—document where those exist.
Results (directional)
Replace with your real figures: e.g. report generation time before/after streaming, or reduction in support tickets after audit logs shipped.
Lessons learned
- Publishing is an event, not a flag flip—wire webhooks or notifications at the state transition, not in ad-hoc controllers.
- UX for partial saves in mark entry matters more than micro-optimizations on the happy path.