# Laravel SchoolContext Phase 1 Implementation This package-style scaffold implements Phase 1 of the SchoolContext foundation for a Laravel app. It includes: - immutable `SchoolContext` value object; - context factory, resolver, validator, store, and exception; - `ResolveSchoolContext` middleware; - service provider bindings; - helper for legacy adapters only; - query scoping trait; - first student read/list slice; - payment-file access slice that resolves files through payment context, not arbitrary filenames; - context payload helper for jobs/events; - unit, feature, and architecture tests. ## Install into an existing Laravel app Copy the `app`, `config`, `routes`, and `tests` folders into your Laravel project. Register the provider in `config/app.php` if your Laravel version does not auto-discover app providers: ```php App\Providers\SchoolContextServiceProvider::class, ``` For Laravel 10 and older, you may also register the middleware alias in `app/Http/Kernel.php`: ```php protected $middlewareAliases = [ 'school.context' => \App\Http\Middleware\ResolveSchoolContext::class, ]; ``` For Laravel 11+, register it in `bootstrap/app.php`: ```php ->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'school.context' => \App\Http\Middleware\ResolveSchoolContext::class, ]); }) ``` Load the example routes only after adapting controllers/model names to your app: ```php require base_path('routes/school_context_examples.php'); ``` ## Required model assumptions This scaffold expects these model concepts to exist or be adapted: - `App\Models\School` with optional `timezone`, `locale`, `currency`, `domain_profile`, `active` fields. - `App\Models\Configuration::getConfig($key)` during migration only. - `App\Models\Student` with `school_id`. - `App\Models\Payment` with `school_id` and a `files()` relationship. - user model with `school_id`, optional `role_id`, optional `roles()`, optional `schools()`, optional `is_platform_admin`. ## Migration policy New SchoolCore services should accept `SchoolContext` explicitly. Do not call `auth()`, `request()`, or `Configuration::getConfig()` inside SchoolCore services. The architecture test exists to catch that predictable human shortcut. ## Route middleware order Use this order: ```txt auth:api school.context permission/policy/controller ``` Do not run `school.context` before authentication for protected routes. ## Important note `SchoolContext::isIslamicSundaySchool()` exists as a convenience check, but SchoolCore should not branch into Islamic-specific concepts. Domain-specific behavior belongs in policies, bindings, labels, calendars, and extension providers. # Phase 2 Add-on: Core Contracts and Module Boundaries This scaffold now includes the Phase 2 contract layer: - neutral `SchoolCore` contracts for students, guardians, enrollment, attendance, academics, finance, files, communication, and reporting; - immutable DTO/read-model skeletons for cross-module payloads; - `SchoolCoreServiceProvider` with default core bindings; - `IslamicSundaySchoolServiceProvider` with extension policy/provider overrides; - race-safe student identifier generation through `StudentIdentifierGeneratorContract`; - payment file access through `FileAccessPolicyContract` and `FileStorageServiceContract`; - attendance policy and academic calendar provider stubs; - architecture tests for forbidden dependency direction, raw request leakage, `auth()` leakage, and non-neutral contract vocabulary; - a migration stub for `unique(school_id, school_id_number)`. ## Register Phase 2 providers Add these after `SchoolContextServiceProvider`: ```php App\Providers\SchoolCoreServiceProvider::class, App\Providers\IslamicSundaySchoolServiceProvider::class, ``` Enable the extension policy overrides only when the school profile requires them: ```env ISLAMIC_SUNDAY_SCHOOL_EXTENSION_ENABLED=true ``` ## Student identifier slice `StudentService` creates the student row first, then calls `StudentIdentifierGeneratorContract` with the persisted ID. This avoids the classic `max(id) + 1` race. The migration stub adds a database unique constraint, because relying on application code alone for uniqueness is how duplicates sneak in wearing a fake mustache. ## Payment file access slice Use payment IDs and stored file references. Do not serve files by guessed filename. The policy checks school context first, then role/relationship metadata. Adapt relationship metadata to your actual finance schema. ## Attendance policy stub Core scanner logic should call `AttendancePolicyContract` and `AcademicCalendarProviderContract`. The extension provider supplies domain-specific attendance behavior without making `SchoolCore` speak extension vocabulary. ## Phase 3: Modular Finance Extraction Phase 3 adds a reusable `SchoolCore\Finance` module. The core owns financial correctness: invoices, payments, refunds, payment files, audit events, balance calculation, idempotency, and transaction boundaries. Islamic Sunday School behavior is extension-owned through finance policies and reports. Register these providers after the Phase 1/2 providers: ```php App\Providers\SchoolCoreFinanceServiceProvider::class, App\Domain\IslamicSundaySchool\Finance\Providers\IslamicSundaySchoolFinanceServiceProvider::class, ``` Add `routes/finance_phase3.php` to your route loader, then migrate one vertical slice at a time. Start with payment-file access, then payment recording, payment editing, invoice recalculation, refunds/reversals, and only then reports. Reports consume finance truth. They do not invent it, despite humanity's long-running spreadsheet addiction. Important integration notes: - Finance services require `SchoolContext`. - Finance mutation services use `FinanceTransactionRunner`. - Payment files are downloaded by payment ID, never by arbitrary filename. - `Money` stores integer minor units and rejects float math. - `finance_audit_logs` are append-only. - Existing legacy finance methods should be labeled `canonical`, `adapter`, `deprecated`, or `remove` before migration continues. ## Phase 4: Modular Attendance and Scanner Extraction Phase 4 adds `SchoolCore\\Attendance` as the neutral attendance/scanner module. It includes scanner delegation, school-scoped badge lookup, scan idempotency, student/staff attendance services, session resolution, status policies, audit logging, migrations, HTTP requests/controllers, route examples, provider bindings, and Islamic Sunday School extension overrides. Register these providers after the base SchoolCore providers: ```php App\\Providers\\SchoolCoreAttendanceServiceProvider::class, App\\Domain\\IslamicSundaySchool\\Attendance\\Providers\\IslamicSundaySchoolAttendanceServiceProvider::class, // only for the Islamic Sunday School profile/app ``` Load the example routes from `routes/attendance_phase4.php` or merge them into your API route file. Keep legacy scanner endpoints as adapters only until compatibility tests pass. Controllers should delegate to `ScannerServiceContract`, not recreate attendance logic in private methods. ## Phase 5: Modular Student Lifecycle Extraction Phase 5 adds a neutral `SchoolCore\Students` lifecycle module for race-safe identifiers, student creation/update/status transitions, guardians, households, enrollment, assignments, promotion, read models, audit logging, and Islamic Sunday School profile extension points. Core student lifecycle stays reusable: no Qur'an, Arabic, Islamic studies, halaqa, masjid/community, or sensitive religious/community note fields belong in `SchoolCore\Students`. Those live in `App\Domain\IslamicSundaySchool\Students`. The point is not aesthetic purity; it is avoiding a global student model that secretly belongs to one domain and then acts innocent. Register: ```php App\Providers\SchoolCoreStudentServiceProvider::class, App\Domain\IslamicSundaySchool\Students\Providers\IslamicSundaySchoolStudentServiceProvider::class, ``` Example routes: `routes/student_lifecycle_phase5.php`. ## Phase 6: Modular Communication Extraction Phase 6 adds `SchoolCore\Communication` as the neutral communication engine. Bulk communication now uses a preview-first path: resolve recipients, dedupe, apply preferences, store a snapshot, confirm with a token, then send through channel contracts. This prevents accidental mass sends, duplicate deliveries, and cross-school recipient leakage. Register: ```php App\Providers\SchoolCoreCommunicationServiceProvider::class, App\Domain\IslamicSundaySchool\Communication\Providers\IslamicSundaySchoolCommunicationServiceProvider::class, ``` Routes are in `routes/communication_phase6.php`. Include them only after authentication and `ResolveSchoolContext` are active. Key rules: bulk sends require `preview_id` and `confirmation_token`; recipient queries live in resolvers, not controllers; email/SMS/WhatsApp/notification delivery lives behind channel contracts; Islamic Sunday School recipient behavior is extension-owned. ## Phase 7: Modular Reporting Extraction Phase 7 adds `SchoolCore\Reporting` as the reporting boundary. Reports are read-only, require `SchoolContext`, and must consume read models instead of inventing finance, attendance, communication, or student lifecycle truth with ad hoc queries. Added provider: ```php App\Providers\SchoolCoreReportingServiceProvider::class, App\Domain\IslamicSundaySchool\Reporting\Providers\IslamicSundaySchoolReportingServiceProvider::class, ``` Added route file: ```php require base_path('routes/reporting_phase7.php'); ``` The core reporting registry supports tagged report definitions using `schoolcore.reports`. Islamic Sunday School reports register through the extension provider and are only available when the context domain profile is `islamic_sunday_school`. Phase 7 deliberately treats exports as controlled access, not a casual CSV vending machine. Export paths go through `ReportExportServiceContract`, audit hooks exist, snapshots are school-scoped, and architecture tests prevent `SchoolCore\Reporting` from importing extension classes. ## Phase 8: Controller and API Cleanup Phase 8 adds the HTTP cleanup layer: - v2 route file: `routes/api_phase8.php` - standardized API response envelope: `App\Support\Api\ApiResponse` - centralized exception rendering helper: `App\Support\Api\ApiExceptionRenderer` - domain-profile middleware: `EnsureDomainProfile` - deprecation header middleware: `DeprecationHeaders` - route inventory generator: `php artisan api:route-inventory --markdown` - controller classification map: `config/api_controller_classification.php` - OpenAPI baseline: `docs/openapi.phase8.yaml` - route inventory docs: `docs/api-route-inventory.md` - v2 canonical controllers for finance, attendance, students, communication, reporting, and Islamic Sunday School extension routes - architecture tests blocking raw DB/provider/controller business logic patterns Phase 8 does not erase legacy routes. It creates canonical v2 delivery adapters and gives old routes a sane path to become adapters or deprecated endpoints. Because breaking clients for “architecture” is still breaking clients, just with nicer folder names. ## Phase 9: Boundary Enforcement and Modular Governance Phase 9 adds enforceable modular governance on top of the Phase 1-8 scaffold. Installed governance pieces: - `app:architecture-scan` artisan command for forbidden imports, HTTP leakage, controller/provider calls, finance float usage, unsafe file routes, extension vocabulary, and critical modular rules. - `app:dependency-map` command for dependency map artifacts. - `app:route-inventory-check` command for route inventory governance. - `app:docs-coverage` command for route/OpenAPI/deprecation coverage checks. - `tests/Architecture/*BoundaryTest.php` suites for module, controller, service, finance, attendance, student, communication, reporting, Islamic Sunday School, route inventory, and deprecation rules. - `.github/CODEOWNERS`, PR checklist, architecture workflow, and release gate workflow. - `docs/architecture/*`, `docs/modules/*`, `docs/deprecations.md`, and `docs/release-checklist.md`. Recommended rollout: ```bash php artisan app:architecture-scan --fail-on=none php artisan test tests/Architecture php artisan api:route-inventory --markdown php artisan app:route-inventory-check php artisan app:dependency-map --markdown php artisan app:docs-coverage ``` Start in warning mode for existing legacy code. Critical new violations should fail immediately. Letting legacy code break every build on day one is not governance; it is a morale experiment with predictable results. ## Phase 10: Migration, Release, and Production Readiness Phase 10 adds production rollout governance for the modular platform: - feature flag rollout map - migration validation commands - shadow comparison scaffolding - release readiness gate - rollback playbooks - monitoring and alerting docs - security/performance readiness checklists - UAT scenarios - support playbooks - pilot and Islamic Sunday School production rollout plans - legacy unsafe route audit Useful commands: ```bash php artisan app:release-feature-flags php artisan app:release-migration-validate php artisan app:release-shadow-compare php artisan app:legacy-unsafe-route-audit php artisan app:release-readiness-gate --warning-mode ``` Phase 10 is not a magic permission slip to ship everything. It is the checklist that stops the team from discovering rollback strategy during an incident, which is traditionally when everyone becomes philosophical and useless.