inti project
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user