2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00
2026-05-30 01:11:35 -04:00

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:

App\Providers\SchoolContextServiceProvider::class,

For Laravel 10 and older, you may also register the middleware alias in app/Http/Kernel.php:

protected $middlewareAliases = [
    'school.context' => \App\Http\Middleware\ResolveSchoolContext::class,
];

For Laravel 11+, register it in bootstrap/app.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:

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:

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:

App\Providers\SchoolCoreServiceProvider::class,
App\Providers\IslamicSundaySchoolServiceProvider::class,

Enable the extension policy overrides only when the school profile requires them:

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:

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:

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:

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:

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:

App\Providers\SchoolCoreReportingServiceProvider::class,
App\Domain\IslamicSundaySchool\Reporting\Providers\IslamicSundaySchoolReportingServiceProvider::class,

Added route file:

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:

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:

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.

S
Description
No description provided
Readme 26 MiB
Languages
PHP 88.4%
Blade 11.4%
JavaScript 0.1%