Initializing
Back to Projects
Year2026
DomainFullstack
AccessPrivate Repo
Complexity8.3 / 10
Video DemoArchitecture DocsScreenshots
PHP 8.3Laravel 11Vue.js 3PostgreSQL 16RedisDockerInertia.jsTailwind CSSJWTModular MonolithOpenAPI 3.1Pest PHP
FullstackProduction

Aatmanova — School Management System

A production-grade, modular monolith ERP for Indian schools. 16 domain modules, 17 roles, JWT + RBAC, async bulk ops, and a SystemPulse stress test validating 2,000 concurrent students.

Domain Modules0
User Roles0
Database Seeders0
Students (Stress Test)0
API Endpoints0+
Test Suites0

Table of Contents


The Challenge

Modern Indian schools operate under a maze of complexity: CBSE, ICSE, State Board, Cambridge IGCSE, and IB curriculums each have different grading policies and compliance requirements. Admin staff juggle fee collection, timetable management, UDISE statutory reporting, hostel allocations, and parent communications — often across disconnected spreadsheets and paper registers.

Generic school administration packages fall apart under real operational load:

  • Monolithic codebase → one bad feature breaks the whole system
  • No offline support → schools with poor connectivity lose data
  • No audit trail → compliance violations with no accountability
  • Hardcoded role structures → can't model the nuanced hierarchy of Indian schools
  • Concurrent bulk operations (attendance for 1,200 students at once) cause request timeouts and data corruption

The requirement: Build an ERP that handles the full operational lifecycle of an Indian school — admissions, academics, attendance, examinations, payroll, compliance, and welfare — as a maintainable, extensible system that teams can actually own.


Architecture & Solution

Aatmanova is engineered as a Modular Monolith — a single deployable unit where each feature lives in a completely self-contained domain module. Each module has its own Models, Services, Controllers, Policies, Events, Repositories, DTOs, Jobs, and Tests. Modules communicate exclusively through Events and shared Service Interfaces — never through direct Model imports across boundaries.

Parsing system architecture diagram...

Module Isolation Principle

Every module passes the deletion test: you can remove the entire app/Modules/Finance/ directory and zero other modules are affected. Features communicate through:

  • Laravel Events — for side-effects (withdrawal saga, notifications)
  • Shared Service Interfaces — for cross-module data reads without direct coupling
  • HydrationService — resolves entity names across module boundaries without importing foreign Models

Offline-First Architecture

Schools in rural India often face intermittent connectivity. The system includes a Sync Queue — a transactional outbox that stores mutations locally and replays them against the server when connectivity is restored, with full conflict resolution and idempotency guarantees.


Tech Stack

LayerTechnologyVersionRole
Backend FrameworkLaravel11.xApplication orchestration, DI, queue, events
LanguagePHP8.3+Business logic, type-safe services
DatabasePostgreSQL16+Primary data store, ACID transactions
Cache & QueueRedis7.xJob queue, session store, rate limit counters
FrontendVue 3 + Inertia.jsLatestReactive SPA with server-side routing
Build ToolVite5.xHot module replacement, production bundling
UI StylingTailwind CSS3.xUtility-first, consistent indigo-600 brand
Reactive ComponentsAlpine.js3.xLightweight interactivity for Blade views
API AuthJWT (php-open-source-saver)2.xStateless API authentication
Web AuthLaravel SanctumLatestSession-based auth for web routes
TestingPest PHP + PHPUnitLatestUnit, feature, and module integration tests
API SpecificationOpenAPI3.1Full API contract (openapi/sms.yaml)
Secrets ManagementHashiCorp VaultCompatibleProduction secrets isolation
ContainerizationDocker + Docker ComposeLatestDev/prod parity
Process SupervisionSupervisorLatestQueue worker management in production

16 Domain Modules

Each module is a complete vertical slice following the same internal structure:

code
app/Modules/
├── Auth/           # JWT auth, Sanctum, RBAC, MFA scaffolding, session management
├── Student/        # Enrollments, profiles, documents, withdrawal SAGA pattern
├── Staff/          # HR, recruitment, leaves, appraisals, salary slips, payroll
├── Academic/       # CBSE/ICSE/State/Cambridge/IB boards, classes, subjects, timetable
├── Attendance/     # Daily attendance, bulk entry with optimistic locking, async batching
├── Examination/    # Exam scheduling, marks entry, grade computation, result generation
├── Finance/        # Fee structures, concessions, payments, receipts, async bulk payroll
├── Library/        # Book catalogue, issue/return, overdue fine calculation
├── Transport/      # Routes, vehicles, student assignments, GPS-ready stubs
├── Hostel/         # Room inventory, student allocations, warden management
├── Communication/  # Circulars, announcements, parent notifications
├── Events/         # School events, inter-school competitions, registrations
├── Counseling/     # Student welfare cases, counselor assignment, case tracking
├── Compliance/     # UDISE reports, statutory registers, safety certificates
├── Facilities/     # Asset inventory, maintenance scheduling, work orders
└── Reports/        # Dynamic templates, PDF/Excel export, configurable output

Per-module structure (consistent across all 16):

code
ModuleName/
├── Controllers/     # Thin HTTP controllersno business logic
├── DTOs/            # Data Transfer Objects with PII masking
├── Events/          # Domain events emitted on state changes
├── Jobs/            # Async background jobs for bulk operations
├── Listeners/       # Event listeners for cross-module side-effects
├── Models/          # Eloquent models with observers
├── Observers/       # Auto audit logging, version increment
├── Policies/        # RBAC authorization gates per resource
├── Providers/       # Module service provider registration
├── Repositories/    # Data access abstraction from Services
├── Requests/        # Form request validation (Zod equivalent)
├── Resources/       # API response transformers
├── Services/        # Business logic orchestration
├── Tests/           # Module-isolated feature and unit tests
├── database/
│   ├── factories/   # Eloquent model factories for testing
│   └── migrations/  # Module-specific schema migrations
└── routes/          # Module API and web routes

Module Synchronization Status

All 16 modules have achieved full backend-frontend synchronization (from system audit):

ModuleBackend ServiceFrontend ServiceUI Integration
Auth Full authService.js Live
Academic Full academicService.js Live
Student Full studentService.js Live
Attendance Full attendanceService.js Live
Staff Full staffService.js Live
Finance Full financeService.js Live
Library Full libraryService.js Live
Examination Full examinationService.js Live
Transport Full transportService.js Live
Hostel Full hostelService.js Live
Communication Full communicationService.js Live
Events Full eventsService.js Live
Counseling Full counselingService.js Live
Compliance Full complianceService.js Live
Facilities Full facilitiesService.js Live
Reports Full reportsService.js Live

RBAC — 17 Roles

The permission system is context-aware, not flat. A class teacher's attendance:write permission is silently scoped to their assigned class — they cannot record or read attendance for other sections even with the same permission flag.

TierRoles
GovernanceSuper Admin, Board Member, Trustee, Management
ExecutivePrincipal, Vice Principal
AcademicAcademic Coordinator, Class Teacher, Subject Teacher
AdministrationAdmin Staff, Front Office, Accounts Staff
WelfareCounselor, Librarian, Transport Coordinator, Warden
End UsersParent/Guardian, Student (Grade 6+)

JWT Token Lifecycle:

TokenTTLStorage
Access Token15 minutesAuthorization header
Refresh Token14 daysSecure cookie
Web Session4 hoursRedis-backed Sanctum
Mobile Session30 daysRedis-backed Sanctum

Key Engineering Decisions

1. Modular Monolith over Microservices

The team is a single developer. Microservices introduce operational overhead that isn't justified at v1 scale. The modular monolith provides:

  • Full domain isolation without the network overhead
  • Single deployment, single database transaction boundary
  • Clean extraction path if any module needs to scale independently

Each module passes the 5-file rule: a typical feature change touches ≤ 5 files, all within the same module directory.

2. Optimistic Locking on Concurrent Writes

Bulk attendance for 1,200 students submitted simultaneously causes race conditions on attendance records. Every concurrency-sensitive table has a version column. The HasOptimisticLock trait increments this on every write and rejects stale updates with a 409 Conflict — preventing silent data corruption without expensive row-level locks.

php
// HasOptimisticLock trait — version-based concurrent write protection
public function updateWithLock(array $data): bool {
    return $this->where('id', $this->id)
                ->where('version', $this->version)
                ->update(array_merge($data, ['version' => $this->version + 1])) > 0;
}

3. Dynamic Batch Routing (Sync/Async Threshold)

The HasDynamicThreshold trait makes the system self-adaptive. Any bulk operation — attendance, marks entry, payroll disbursement — automatically routes to a background job when the payload exceeds 10 records, and executes synchronously for small batches. No manual job dispatch required.

php
// Dynamic threshold routing
if (count($records) > self::ASYNC_THRESHOLD) {
    BulkAttendanceJob::dispatch($records, $academicYearId);
    return response()->json(['status' => 'queued', 'job_id' => $jobId]);
}
// < 10 records: process inline, return result immediately

4. Student Withdrawal SAGA

When a student is withdrawn from school, 6 different modules must be updated atomically: Library access revoked, transport route cancelled, hostel room vacated, fee account settled, academic records archived, and staff notification sent. If any step fails, the entire saga rolls back.

This uses Laravel's transactional outbox pattern: all events are written to a domain_events table within the same DB transaction as the withdrawal record. A separate dispatcher reads and broadcasts confirmed events, guaranteeing exactly-once delivery even if the process crashes mid-saga.

5. PII Protection at the DTO Layer

Sensitive fields (Aadhaar numbers, phone numbers, emergency contacts) are masked at the DTO level — not at the API layer. This means even internal service calls return masked values for non-privileged consumers. The masking rule is: XXXX-XXXX-1234 for Aadhaar, +91-XXXXX-XXXXX for mobile.

Only roles with pii:read permission receive full values.

6. UUIDv7 Primary Keys

All tables use UUIDv7 (time-sortable) primary keys instead of auto-incrementing integers. This enables:

  • Global uniqueness across future multi-tenant or sharded deployments
  • Time-based ordering without a separate created_at index scan
  • No sequential ID enumeration attacks

7. Multi-Board Support

The Academic module models the full Indian school board ecosystem. Grade policies, passing criteria, grading scales, and subject structures differ between CBSE, ICSE, State Board, Cambridge IGCSE, and IB. Each board has its own GradePolicy configuration that plugs into the Examination module's grade computation engine without code changes.


API Design

The full API is documented as an OpenAPI 3.1 specification (openapi/sms.yaml), renderable via Redocly, Swagger UI, or Postman.

Design Principles:

  • All endpoints versioned under /api/v1/
  • Consistent JSON envelope: { data: {}, meta: {}, errors: [] }
  • Pagination on all list endpoints (default 20, max 100)
  • PII masking in list responses for non-privileged roles
  • Async operations return { status: "queued", job_id: "..." } immediately

Core Endpoint Groups:

http
# Authentication
POST   /api/v1/auth/login          → { access_token, refresh_token }
POST   /api/v1/auth/logout
POST   /api/v1/auth/refresh
GET    /api/v1/auth/me             → Current user profile + permissions

# Students
GET    /api/v1/students            → Paginated list (PII-masked for non-admins)
POST   /api/v1/students            → Enroll new student
GET    /api/v1/students/{id}
PUT    /api/v1/students/{id}
DELETE /api/v1/students/{id}       → Triggers Withdrawal SAGA

# Attendance (async for > 10 records)
POST   /api/v1/attendance          → Single or bulk entry
GET    /api/v1/attendance/report   → Paginated report by class/date

# Marks Entry (async for > 10 records)
POST   /api/v1/marks               → Bulk marks submission
GET    /api/v1/results/{studentId} → Computed grades + GPA

# Finance
POST   /api/v1/fee-payments        → Fee collection
GET    /api/v1/fee-receipts/{id}   → PDF-ready receipt
POST   /api/v1/payroll/disburse    → Async bulk payroll (always async)

# Reports
POST   /api/v1/reports/generate    → Dynamic template rendering (PDF/Excel)

Security Model

Layered Defense

LayerControl
TransportHTTPS enforced, HSTS headers
AuthenticationJWT (API) + Sanctum sessions (web), both short-lived
AuthorizationContext-aware RBAC via Laravel Policies
Input ValidationForm Requests (every endpoint, every parameter)
Rate LimitingAggressive throttling on auth endpoints; per-route limits elsewhere
PII ProtectionField-level encryption + DTO masking for non-privileged reads
Audit TrailImmutable audit_logs table with actor, delta, IP, session
SecretsHashiCorp Vault integration for production secrets
CSRFLaravel's built-in CSRF token + SameSite cookies for web routes

Audit Log Schema

Every create/update/delete on sensitive models emits an immutable audit record:

code
audit_logs
├── id            UUID v7
├── actor_id      UUIDusers.id (who)
├── action        ENUM: created|updated|deleted|accessed
├── model_type    string (what type)
├── model_id      UUID (what record)
├── old_values    JSONB (before state)
├── new_values    JSONB (after state)
├── ip_address    inet
├── user_agent    text
└── created_at    timestamptz

Records in audit_logs have no updated_at or deleted_at — they are append-only by design.


Database Design

Key Conventions

ConventionDetail
Primary KeysUUIDv7 — time-sortable, globally unique
Soft Deletesdeleted_at on all critical tables
Audit Columnscreated_by, updated_by, deleted_by (UUID refs)
Optimistic Lockversion (integer) — incremented on every write
Timestampscreated_at, updated_at — all tables
Table Naming{module}_{entity} — e.g., fee_payments, staff_leaves

27 Seeders — Full Data Coverage

SeederWhat it creates
RoleSeeder17 predefined roles with permission sets
PermissionSeederFull permission registry for all 16 modules
BoardSeederCBSE, ICSE, State Board, Cambridge IGCSE, IB
SchoolSeederSample school profile
SchoolClassSeederClasses I–XII with board associations
SectionSeederSections A–D per class
SubjectSeederCore subjects mapped per board
AcademicYearSeederCurrent academic year
GradePolicySeederGrade thresholds per board
AdminUserSeederDemo accounts for all 10 role tiers
StaffSeeder20 sample staff profiles
FeeStructureSeederFee structures per class with concessions
FeeConcessionSeederScholarship and sibling discount rules
BookCategorySeederLibrary book categories
BookSeeder100 sample books with availability
HostelRoomSeederRoom inventory with capacity
TransportRouteSeederBus routes across city zones
TransportVehicleSeederFleet inventory
LeaveTypeSeederStaff leave type catalogue
ExamSeederSample exam schedules
ReportTemplateSeederDynamic report template configurations
SchoolEventSeederAnnual school event calendar
CircularSeederSample communication circulars
FacilitiesSeederAsset inventory and maintenance records
StudentSeeder50 sample students
SystemPulseSeederFull stress test — 2,000 students + all modules

Testing Strategy

Three test suites provide layered coverage:

SuiteLocationWhat it tests
Unittests/Unit/Isolated services, DTOs, utility functions
Featuretests/Feature/Full HTTP request-response cycles
Modulesapp/Modules/*/Tests/Per-domain integration tests
bash
# Full test run
php artisan test

# Run in parallel (faster)
php artisan test --parallel

# Run specific module
php artisan test --filter=StudentModule

# Coverage report
php artisan test --coverage

# Static analysis
./vendor/bin/phpstan analyse

SystemPulse Stress Test (SystemPulseSeeder) validates the system under full load:

  • 2,000 students enrolled across all 12 classes and 4 sections
  • Library: books issued, returned, fines calculated for overdue
  • Transport: all students assigned to routes, vehicles at capacity
  • Hostel: rooms allocated, wardens assigned
  • Examinations: exams created, marks entered, grades computed
  • Finance: fee structures applied, payments recorded, receipts generated
  • Events: school events created, students registered
  • All cross-module references validated for FK integrity

Deployment

bash
# One-command dev start
cp docker.env .env
docker-compose up -d --build
docker-compose exec app php artisan key:generate
docker-compose exec app php artisan jwt:secret
docker-compose exec app php artisan migrate --seed
ServiceTechnologyAccess
appPHP 8.3-FPMPort 9000 (internal)
webNginxPort 8000 (external)
dbPostgreSQL 16Port 5432 (internal)
redisRedis 7Port 6379 (internal)
workerLaravel Queue WorkerBackground
mailMailpitPort 8025 (web), 1025 (SMTP)

Production Stack

code
NginxPHP-FPM 8.3Laravel 11
PostgreSQL 16 (primary + read replica)
Redis 7 (cache + queue + sessions)
Supervisor (queue workers3 concurrent)
Let's Encrypt (SSL via Certbot)
HashiCorp Vault (secrets)

Production Deployment Checklist

bash
composer install --optimize-autoloader --no-dev
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan event:cache
npm ci && npm run build
php artisan migrate --force
php artisan queue:restart

Roadmap

✅ Phase 1 — Foundation (Complete)

  • 16-module architecture with full domain isolation and event-driven cross-module communication
  • JWT + RBAC with 17 roles and context-aware permission scoping
  • All core database schema with 27 seeders and SystemPulse validation
  • OpenAPI 3.1 specification with 50+ endpoints
  • Optimistic locking, audit logging, PII field-level encryption
  • Async bulk operations (attendance, marks entry, payroll)
  • Transactional SAGA for student withdrawal
  • Offline-first sync queue architecture
  • Full backend–frontend synchronization audit (all 16 modules: STABLE)

🔄 Phase 2 — Frontend Polish (In Progress)

  • Vue 3 + Inertia.js SPA with role-based dashboard views
  • Real-time notifications (Laravel Echo + Redis Channels)
  • One-click demo login for all 10 role tiers
  • Progressive Web App (PWA) for mobile access

⏳ Phase 3 — Advanced Features

  • React Native mobile app (API-first)
  • PDF/Excel bulk report export
  • AI-powered attendance anomaly detection
  • Automated UDISE report generation
  • Dynamic fee reminder SMS/email workflows

🔭 Phase 4 — Scale

  • Multi-tenant SaaS architecture (school-per-subdomain)
  • Microservice extraction for high-traffic modules (Finance, Attendance)
  • Kubernetes deployment with horizontal pod autoscaling
  • Real-time GPS tracking integration for transport
  • Advanced analytics dashboard with cohort analysis

Engineering Proof

Real-world validation, system demonstrations, and interface captures of the execution states.

System Demonstration

Video walkthrough detailing core logic, interactions, and system behaviors in action.

System Captures

Full Page Web Captures

Scrollable web preview simulations. Hover or scroll to preview the entire page. Use the maximize trigger to view the full resolution capture.

portfolio.aatmanova.in/projects/aatmanova-school/full-capture-1
Full Webpage Simulation 1
portfolio.aatmanova.in/projects/aatmanova-school/full-capture-2
Full Webpage Simulation 2

Architecture Feedback

Spotted a potential optimization or antipattern? Let me know.

Submit a Technical Suggestion