Worksaas-school-management-dotnet-api

SaaS School Management System API

I built the backend for a multi-tenant school management platform in .NET 10.

Role
Backend Developer
Timeline
Aug 2026 – Present
Main stack
.NET 10
SaaS School Management System API — .NET 10 project screenshot

Overview

I built the backend for a multi-tenant school management platform in .NET 10. Each school gets its own PostgreSQL schema and file folder, and the API covers 27 modules, from admissions, exams and payroll to accounting, a library, messaging and fingerprint attendance, with 484 routes in all.

Problem

School software is usually sold school by school: each school gets its own installation, its own database and its own upgrades. That is slow to set up, expensive to maintain and hard to keep consistent. Schools also need far more than a student list: fees, payroll, exams, attendance, a library and messages.

Approach

I built one API that serves many schools. A registry holds the list of schools, and every school gets its own database schema and file folder created automatically. Each request carries the school it belongs to, so the same code serves every school without ever mixing their data. The modules cover a school's whole day, and a documented module index kept the work organised as it grew.

Outcome

API routes
484
Controllers
82
Modules
27
Entity classes
80
Migrations
34
Lines of C#
~51k

What I built

  • Multi-tenant design: one PostgreSQL schema and one file folder per school, created when a school is provisioned
  • Super Admin tools to create schools, set branding and view platform statistics
  • Admissions: students and guardians, online applications with approve or decline, and bulk CSV import with failed-row export
  • Student and parent directories with search, filters, soft delete, export and login switches
  • Employees, departments, salary templates, monthly payroll, advance salary, leave and awards
  • Academic setup: classes, sections, subjects, class teachers, timetables and promotion
  • Exams: terms, halls, mark distributions, schedules, mark entry, grade ranges and automatic ranks and GPA
  • Attendance for students, staff and exams, with reports
  • Fingerprint attendance from multi-device ZKTeco readers, routed to the right school by device serial number
  • Library with books, issue and return, and fines; events with a public list
  • Student accounting (fee types, invoices, offline payments, reminders) and office accounting with debit, credit and running balance
  • Messaging with inbox, sent, important and trash; per-school email and SMS gateways with templates
  • Roles and permissions matrix, sessions, scheduled jobs, database backup and login history
  • Layered .NET solution, Swagger docs, Docker image and a CI pipeline that builds and publishes it

Architecture

System architecture

Diagram: client apps and biometric devices call an ASP.NET API that uses PostgreSQL, MinIO and email and SMS gateways.
One API in front of one database server, one object store and the gateways each school configures. Open full size ↗

Multi-tenancy

Diagram: a request with a school header is matched to a tenant registry and routed to that school schema and folder.
A school header on every request decides which schema and folder are used. One school never touches another school. Open full size ↗

Module map

Diagram: twelve groups of modules from schools and people to settings and gateways.
Twenty-seven documented modules grouped by area of school life. Open full size ↗

Exam results

Diagram: exam setup, mark entry, grades and positions.
Marks become grades, ranks, GPA and pass or fail without manual calculation. Open full size ↗

Biometric attendance

Diagram: punch, serial number, PIN map and attendance.
A device serial number finds the school, and a PIN finds the student or staff member. Open full size ↗

Engineering decisions

  1. 01A schema per school

    Each school has its own PostgreSQL schema. Isolation is built into the database layout, so a mistake in a query cannot leak another school's rows.

  2. 02One shared storage bucket, one folder per school

    Files live in a single object store with a folder for each school. Storage stays simple to run, and files are always found by the school name.

  3. 03Devices are identified by serial number

    A fingerprint reader cannot send a login token or a school header. A registry maps each device serial to its school, so punches reach the right place without storing passwords on the device.

  4. 04Updates use PATCH only

    Every update is a PATCH, never a PUT, so a client sends only what changed and cannot accidentally erase a field it did not know about.

  5. 05Bulk import with partial success

    A CSV import saves the good rows and returns the failed rows as a file. A school can fix a few bad lines instead of re-uploading hundreds.

  6. 06Secrets are encrypted at rest

    A school SMTP password is encrypted before it is stored and only decrypted when mail is sent. A database copy does not reveal mail credentials.

  7. 07Documentation that ships with the code

    A module index and a system workflow document are updated as modules ship, so a frontend developer can build against the API without reading the source.

Need something similar?

Tell me what you are building and I will reply within one working day.

Start a project
↑↓ navigate↵ openesc closeCtrl K toggles this menu