← Project index

Production software and migration

Standard Schools

Academic operations software for two campuses and more than 2,000 students and staff.

Rebuilding without erasing history

The current portal replaces a split Vite frontend and .NET API with one Next.js service. The harder constraint was not the framework change. It was preserving a populated PostgreSQL database and Cloudinary assets while changing the domain model underneath active school operations.

The rewrite serves two school identities and more than 2,000 students and staff. It covers enrolment, fees, promotion, attendance, score entry, result validation, report publishing, and printable report cards.

Identity separated from enrolment

The legacy model stored a student row inside a particular session and class. The rewrite introduces a permanent StudentProfile and a session-scoped Enrollment. Promotion now creates the next enrolment while graduated, withdrawn, or archived outcomes remain explicit lifecycle states.

LegacyStudent rowidentity + class + session + fees
PermanentStudentProfileone school-scoped identity
Per sessionEnrollmentclass + fees + results

The migration keeps an exit

The production migration is additive. It establishes a baseline for existing tables, adds normalized continuity and result tables, and deliberately leaves legacy Students and ASP.NET Identity tables in place.

  1. 01

    Back up production and restore it into staging.

  2. 02

    Mark the reviewed legacy baseline as applied.

  3. 03

    Deploy additive schema changes, then run the idempotent backfill.

  4. 04

    Resolve duplicate admission conflicts and verify row counts.

  5. 05

    Cut over in a maintenance window while keeping the old deployment recoverable.

The backfill orders legacy records deterministically, keeps the newest row in a duplicate school, admission, and session group, normalizes admission numbers, and uses legacyStudentId to skip already imported enrolments.

Isolation is checked at the boundary

NextAuth credentials sessions carry a school identifier and an owner or staff role. Page queries and server actions independently include that school identifier. A submitted class, subject, term, student, or enrolment identifier is re-queried within the authenticated school before a mutation proceeds.

Owner-only operations cover publishing, users, academic structure, promotion, fees, and archival. Authentication also supports one-time migration of valid ASP.NET Identity password hashes into Argon2-backed portal accounts, temporary-password rotation, lockout, and an eight-hour JWT session.

Evidence in the repository

Tradeoff: preserving mapped legacy tables and a staged compatibility path adds schema complexity. It also keeps production data and rollback options intact while the new model proves itself.