Architecture & Domain Model
Architecture & Domain Model
Section titled “Architecture & Domain Model”This page is the map. It explains which moving parts exist, where requests enter, and how the core school entities relate — read it before the other System Internals pages.
Runtime shape
Section titled “Runtime shape”KoAkademy is a modular monolith. One Laravel 13 application serves everything — admin panel, portals, public pages, and API — running on PHP 8.5. The supported production image uses FrankenPHP behind Caddy in the default single-node Swarm topology; long-lived application and queue workers must not leak mutable state across requests or jobs.
The production container images are multi-stage builds (docker/Dockerfile and
docker/Dockerfile.franken) that install Composer dependencies, generate
Wayfinder routes, build Vite assets, and package the runtime processes.
Supporting services are external: PostgreSQL (primary data), Redis (cache, sessions, queues), Gotenberg (PDF rendering), and S3-compatible object storage (uploads via media library).
Entry points
Section titled “Entry points”| Entry | Path / guard | Implementation | Audience |
|---|---|---|---|
| Administration panel | /admin (web guard) | Filament 5 panel, SPA mode | Administrative staff |
| Admin workspace | /administrators/* | Inertia + React pages | Administrative staff |
| Faculty portal | faculty routes | Inertia + React pages | Teaching staff |
| Student portal | student routes | Inertia + React pages | Students |
| Public pages | /, /enrollment*, /setup, /docs, /changelog, /id-card/verify/{token} | Inertia + React pages | Everyone |
| API | /api/* (auth:sanctum) | Laravel API routes | Integrations |
Two things to know about this table:
- There is no separate admin application. The Filament panel and the three React portals share the same models, policies, and services.
- A second Filament panel (
portal,/portal) exists but is intentionally a stub — the real student/faculty experiences are the Inertia/React portals. Do not build new features into the stub panel.
Core domain entities
Section titled “Core domain entities”The domain is school administration. The principal entities and their relationships:
- School — the tenant. Most records carry a
school_id(see Multi-school tenancy below). - Student — a person enrolled or enrollable; holds documents, signature, clearances, medical records (module), and a generated institutional identifier (configurable format).
- Faculty — teaching staff; assigned to classes and departments.
- Course / Department / Program — the curriculum structure students enroll into. Senior High is modeled as its own cluster (SHS strands and SHS students).
- Class — a taught section of a subject: schedule, room, capacity, assigned faculty, roster. Timetable conflict detection guards scheduling.
- StudentEnrollment — a student’s enrollment for an academic period; moves through the verification pipeline (see Enrollment engine).
- ClassEnrollment / SubjectEnrollment — the join between an enrollment and the classes/subjects it includes; grades live at this level and follow a submit → finalize → verify workflow.
- Transactions / Invoices — assessments, payments, and statements of account issued to students.
- Events, Announcements, NotificationTemplates — calendar, broadcast messaging, and templated notifications.
Around these sit cross-cutting records: User accounts with roles, activity-log entries, media attachments, export jobs, and enrollment-policy records.
Multi-school tenancy
Section titled “Multi-school tenancy”Tenancy is lightweight and school-scoped — there is no stancl/tenancy package and no database-per-tenant:
- A
SchoolScopeglobal scope appliesschool_idfiltering to tenant-owned models. TenantContextresolves the active school from the session (current_school_id), falling back to the user’s default school; super administrators bypass the scope.SetTenantContextmiddleware establishes the context per request; the/organizationsAPI (list, current, switch, store, clear-context) powers the organization switcher in the UI.
When you add a tenant-owned model, give it a school_id and the global scope — never filter by school manually in controllers.
Data planes
Section titled “Data planes”| Plane | Store | Notes |
|---|---|---|
| Relational data | PostgreSQL | Single source of truth; SQLite supported for dev/tests |
| Cache / sessions / queues | Redis | Separate redis and redis-pdf queue connections (see Queues & PDF) |
| Files | S3-compatible storage | spatie/laravel-medialibrary; required in production |
| Search | Scout, database driver by default | Meilisearch optional |
| Settings | Database via spatie/laravel-settings | GeneralSetting holds institution-wide configuration |
| Feature flags | Database via Laravel Pennant | See Modules & feature flags |
Where things live in the repo
Section titled “Where things live in the repo”| Path | Contents |
|---|---|
app/ | Services, models, middleware, jobs, policies, Filament panel, enrollment engine (app/Enrollment/) |
Modules/ | Six optional domain modules (Laravel Modules) |
routes/ | Web route files split per audience, api.php, channels.php |
resources/js/ | Inertia React pages and components (~184 pages) |
database/ | Migrations, factories, seeders |
docker/ | Production image, supervisord variants, runtime scripts |
docs/ | This documentation site |
Reading guide for the rest of this section
Section titled “Reading guide for the rest of this section”- Auth, roles & permissions — who can do what, and how sign-in is hardened.
- Modules & feature flags — how optional functionality is composed and toggled.
- The enrollment engine — the deepest subsystem: pipeline, policies, blueprints.
- Queues, jobs & PDF — background work and document generation.
- Frontend architecture — Inertia, React, Wayfinder, and the design system.
- Extending the enrollment engine — contracts for custom rules and actions.