# Phase 1 implementation and local verification

Date: 28 October 2026. Implemented in the existing Laravel/Inertia/React application. The additive migration was applied to the retained local PostgreSQL `school` database. No commit, push or production deployment was performed.

The later [batch-first enrollment revision](batch-enrollment-workflow.md) supersedes the individual-start entry described below. That revision is applied to `school_simulation`, preserving the separate original `school` database and its private files.

## Delivered workflow

School Administrator prepares Courses, subjects, published curricula, Year/Grade and term requirements, prerequisites, school-level enrollment cycles, continuing Sections, intake availability/fill order, and scheduled Subject Classes. A curriculum defines requirements; the actual class defines its Teacher, weekly meetings, capacity and roster.

Enrollment Staff or Registrar selects the Student, College/Course, Year/Grade and dated period. College filters Courses, or is filled from the selected Course. The server applies the configured Course curriculum for incoming Students and retains an existing assigned version for returning Students; curriculum is read-only in the enrollment form. The draft suggests a Section and eligible usual classes, excludes credited/passed requirements and blocks unmet prerequisites. Staff can adjust individual load selections and intentionally retake a completed subject with a warning. Drafts reserve no places. Different Courses/Sections can share a class when the same subject belongs to the assigned curriculum and the Branch, period and school level are compatible. See [College/Course and curriculum decision](adr/0011-colleges-and-course-owned-enrollment-curricula.md).

Finance Staff records Cleared or On Hold. Earlier-period/unassigned opening debt additionally requires settlement or an approved arrangement from the Finance Approver. Approval retains the debt and documented terms; it does not itself clear enrollment. New ledger entries invalidate clearance/arrangement review. Current-term payment conditions remain a manual Finance decision.

Registrar finalization rechecks the load, prerequisites, Section/class capacity, Teacher authorization, current Student/Teacher meetings and finance together. It confirms any new Section membership, updates the actual roster and issues COR version 1. Independent Section and class exceptions require an authorized approver, one Student/target/context and a reason; configured limits remain unchanged.

Registrar amendments require a reason and renewed checks and issue another COR Version atomically. Original documents remain readable. Finalized passing **and failing** grades prevent dropping or switching that Student's graded subject. Other ungraded subjects remain amendable. Teacher corrections retain the prior result and do not unlock the enrollment.

Teachers enter draft final subject grades directly and finalize the reviewed class results without assessments. School-defined percentage and numeric values/passing outcomes are supported. Official earlier passing results and approved equivalent credits satisfy later prerequisites. A later failed retake does not erase an earlier valid pass. No automatic Year/Grade promotion or GPA is introduced.

School Administrator meeting changes require a reason and check every actually enrolled Student and the assigned Teacher, including overlapping dated periods. Failed changes are atomic. Saved current timetables update while issued CORs remain unchanged. Teacher assignments remain protected after Students enroll; finalized classes retain their timetable.

## Ending Section membership

Registrar selects **Sections → Student → End membership**, enters a reason and submits the action. The current membership receives its end date, Registrar and reason. Its Section place is freed.

The action preserves enrollment status, subjects, actual class rosters and class places, official grades/corrections, COR Versions and audit history. It does not withdraw subjects or automatically promote/graduate a Student. The Student profile shows current and ended memberships. A draft prepared before membership ended cannot silently restore it; staff must explicitly review the Section choice before finalization.

## Access and screens

| Role | Phase 1 authority |
| --- | --- |
| School Administrator | School-wide setup and account management; academic monitoring |
| Enrollment Staff | Scoped Student records, drafts and transfer evidence preparation |
| Registrar | Scoped Student/enrollment management, credit approval, finalization, amendments, capacity approval and membership ending |
| Finance Staff | Scoped financial entries and manual clearance |
| Finance Approver | Finance duties plus recorded past-debt arrangement approval |
| Teacher | Own assigned class rosters/read-only timetable; manual grade entry, finalization and corrections |
| Dean | Scoped academic monitoring and explicit capacity approval; no enrollment, finance or grade modification |
| Department Monitor | Department-scoped academic monitoring |
| Student | Own enrolled subjects, schedule, issued CORs and official final grades |

Permissions are fixed bundles in `config/school.php`; each grant retains its own Branch/department scope. Views and direct mutation requests enforce scope on the server. Grade ownership remains separate from administrative titles. Student private file access is retained. Audit events cover changes, approvals, security/access and sensitive downloads/exports in the database; no audit viewer is exposed.

Main routes: `/setup`, `/students`, `/students/{id}`, `/enrollments`, `/enrollments/{id}`, `/enrollments/{id}/cor?version=N`, `/finance`, `/classes`, `/classes/{id}`, `/schedule`, `/sections`, `/capacity`, `/users` and `/reports`. Navigation shows the relevant role's actions. Class codes and continuing Sections use distinct labels.

## Model and transaction choices

The additive migration introduces school-level cycles, explicit term/classification metadata, continuing Sections/memberships, Section availability and usual classes, capacity approvals, structured class meeting JSON, finance approval metadata and retained COR Versions. Historical free-text class labels remain intact. Existing issued COR JSON is copied exactly into version 1.

Short academic writes take ordered Branch row locks, including shared Teachers across Branches. Finalization, amendments, scheduling, finance decisions and manual grade writes use that boundary. The one-current-membership database constraint and COR-version uniqueness complement server checks. This keeps the MVP within one application/database without a scheduling engine or workflow service.

Primary owners: `EnrollmentService`, `SectionService`, `ScheduleService`, `PhaseOneSetupService`, `FinanceService`, `GradeService`, `AccessService`, `DocumentService`, `StudentProfileService`, Form Requests and authorization policies. React pages use those server decisions rather than independently granting permission.

## Verification evidence

| Check | Result |
| --- | --- |
| TypeScript/Vite production build | Passed |
| SQLite suite | 33 tests, 608 assertions passed |
| PostgreSQL feature suite | 32 tests, 607 assertions passed against isolated `school_mvp_test` |
| Concurrent PostgreSQL finalization | Two independent PHP workers released together; exactly one got the last Section/class place, the other was blocked, and no partial membership/COR remained |
| Full browser suite | 19 passed, one duplicate mobile account-creation check skipped; includes login, role views, account creation and Student photo/private-file maintenance |
| Expanded Phase 1 browser run | Six passed: college semester and yearly junior-high form flows on desktop/phone, plus the two role-layout checks |
| Phase 1 form flow | Passed on 1440px desktop and 390px phone for both numeric and percentage grades: class setup/linking, draft, Finance Hold/arrangement/Cleared, enrollment, COR amendment/version reads, manual grade/finalization/correction, grade lock and membership ending |
| Role page layouts | Existing and new role pages passed desktop/phone checks for JavaScript errors, missing main views and document overflow |
| Retained local data | All 110 original rows checked match their original-column hashes; all 21 original private files match their hashes |

The SQLite suite also includes the existing trivial unit test, explaining the one-test/one-assertion difference from the PostgreSQL feature suite. Source tests additionally cover yearly junior/senior high and next-semester enrollment, transfer-credit draft cleanup, retake history, scoped denials, conflict rejection, immutable earlier CORs and failed-amendment rollback.

Evidence is under `design/implementation/`: `phase1-verification.json`, `phase1-concurrency.json`, the retained row/file hash baselines, and desktop/mobile screenshots named `phase1-enrollment-*` and `phase1-final-grade-*`. The expanded screenshots include `college` or `junior_high` in the filename. The preservation checker accepts newly added browser fixtures while verifying every original row/file; it never replaces the original baseline. The full browser suite added four private sample files belonging to its new Student records; all 21 originals remain unchanged.

Reproduce with:

```powershell
npm run build
php vendor/phpunit/phpunit/phpunit --configuration phpunit.xml --no-progress
php vendor/phpunit/phpunit/phpunit --configuration phpunit.pgsql.xml --no-progress
php tests/phase1-concurrency.php
npm run test:e2e
php design/implementation/phase1-preservation.php verify
```

The PostgreSQL suite and concurrency script rebuild **only** the exact isolated test database. Never run schema resets against the retained application database. Browser fixtures are additive and clearly labeled. Login rate limiting remains enabled; the browser helper honors its actual Retry-After response when many role switches occur.

## Local rollout and remaining school setup

The local app is available at `http://127.0.0.1:8097`. It now uses the [readable school simulation](school-simulation.md), with real-looking names, school years, semesters, Courses and subjects. The login page has a local-only role selector that fills the existing demo credentials. Real account creation remains in Users and access, with mandatory first-password changes.

The older `school` database and its unresolved legacy mappings remain preserved separately. The clean `school_simulation` dataset has complete term/classification, Section and timetable setup for the named sample Students. Automated browser fixtures now use only `school_browser_test` at port 8098 rather than cluttering the user-facing demo. See the simulation notes for current verification and data boundaries.

School-specific grading values, curriculum content, capacity policy, period dates, actual Teachers/timetables, payment conditions and operational acceptance still belong to the school. Production infrastructure, backups, data import and deployment remain separate from this local implementation.

Assessments/quizzes, automatic calculation, grading-period results, learning modules/materials, GPA/GWA, library workflows, Branch movement and native apps remain deferred. Historical tables/data stay stored, while the deferred assessment/material routes and controls are unavailable. The installed Laravel AI SDK remains ready for later use without a product AI feature in Phase 1.
