Architecture¶
This codebase is a legacy PHP application that has been partially modernized with Slim 4
and a PHP-DI container. The UI and API entry points now run through Slim middleware stacks,
but most request handling still delegates to legacy include-style PHP scripts under app/.
High-Level Map¶
flowchart LR
Browser[Browser] --> Apache[Web Server]
ApiClient[API Client] --> Apache
Apache --> PublicUI[public/index.php<br/>Slim UI App]
Apache --> PublicAPI[public/api/index.php<br/>Slim API App]
PublicUI --> MiddlewareUI[UI Middleware Stack]
MiddlewareUI --> LegacyUI[LegacyRequestHandler]
LegacyUI --> AppModules[app/* legacy modules]
PublicAPI --> MiddlewareAPI[API Middleware Stack]
MiddlewareAPI --> ApiRoutes[Slim Routes]
MiddlewareAPI --> LegacyAPI[ApiLegacyFallbackMiddleware]
LegacyAPI --> ApiIncludes[app/api/* includes]
AppModules --> Services[App\\Services, Utilities]
ApiIncludes --> Services
Services --> DB[(MySQL)]
Bootstrap[bootstrap.php] --> PublicUI
Bootstrap --> PublicAPI
Bootstrap --> Services
Entry Points¶
- Web UI:
public/index.phpbuilds a Slim app, adds middleware, then delegates all routes toApp\HttpHandlers\LegacyRequestHandler. - API:
public/api/index.phpbuilds a Slim app, registers minimal routes, then falls back to legacy includes viaApp\Middlewares\Api\ApiLegacyFallbackMiddleware. - CLI/Tasks:
bin/*,app/tasks/*, andvendor/bin/crunzscripts are used for maintenance, background jobs, and setup. - Server-sent events:
public/sse/alerts.phprequiresbootstrap.phpdirectly, outside the Slim stacks, and checks the session itself.
Bootstrap and Configuration¶
bootstrap.phpsets session/cookie policies, defines paths, loads Composer autoload, loads system constants and version, registers DI, and installs error/exception handlers.- Environment config is loaded from
configs/config.<env>.php(defaulting to production). - Module toggles, database credentials and interfacing settings live in the config file
(see
configs/). Other settings are rows in theglobal_configtable, edited under ADMIN > Settings > General Configuration.
Dependency Injection and Registries¶
- PHP-DI container setup lives in
app/system/di.php. - The container is stored in
App\Registries\ContainerRegistryfor global access. App\Registries\AppRegistrystores per-request data (e.g., current request/URI).
Web UI Request Flow¶
sequenceDiagram
participant B as Browser
participant P as public/index.php
participant M as UI Middleware Stack
participant L as LegacyRequestHandler
participant A as app/* script
B->>P: HTTP Request
P->>M: Slim middleware pipeline
M->>L: catch-all route
L->>A: include legacy PHP file
A-->>L: output buffer
L-->>B: HTTP Response
UI Middleware Stack (order of execution)¶
- Error handling:
App\Middlewares\ErrorHandlerMiddleware - Security headers/CSP
- CORS:
App\Middlewares\CorsMiddleware - Request context: sets
AppRegistryvalues - Auth split:
SystemAdminAuthMiddlewareorAppAuthMiddleware - CSRF:
App\Middlewares\App\CSRFMiddleware - ACL:
App\Middlewares\App\AclMiddleware
API Request Flow¶
sequenceDiagram
participant C as API Client
participant P as public/api/index.php
participant M as API Middleware Stack
participant R as Slim Route (optional)
participant L as Legacy API include
C->>P: HTTP Request
P->>M: Slim middleware pipeline
M->>R: Matched route (e.g., /api/v1.1/init)
M->>L: Fallback include when no Slim route
L-->>C: JSON Response
API Middleware Stack (order of execution)¶
- Error handling:
App\Middlewares\Api\ApiErrorHandlingMiddleware - CORS (including preflight handling)
- Interface Tool API guard:
App\Middlewares\Api\InterfaceRequestGuardMiddleware - Body parsing:
Slim\Middleware\BodyParsingMiddleware - JSON content-type enforcement
- Auth:
App\Middlewares\Api\ApiAuthMiddleware - Request context:
AppRegistryrequest - Legacy fallback:
App\Middlewares\Api\ApiLegacyFallbackMiddleware - Content-Length header
GET /api/v1.1/health is a real Slim route (App\HttpHandlers\Api\HealthHandler)
and is excluded from auth. It answers 503 when the database is unreachable. Bootstrap
connects eagerly, so public/api/index.php recognises the health path before requiring
bootstrap and defines INTELIS_HEALTH_PROBE; DatabaseFactory then rethrows the
connection failure instead of printing the HTML outage page, and the front controller
answers with JSON.
The Interface Tool endpoints are registered as real Slim routes rather than
legacy includes. They carry their own InterfaceApiEnabledMiddleware and
InterfaceInstallationAuthMiddleware, so a lab is always resolved from the
credential instead of the request.
/api/v2/* routes are real Slim handlers under App\HttpHandlers\Api\V2 with one
response envelope (App\Http\ApiV2Response). ApiAuthMiddleware skips them, and each
handler authenticates its own caller (a user token or a lab token).
Legacy Application Layout¶
Most business logic and UI pages are in legacy include-based modules under app/:
app/<module>/feature folders (e.g.,vl,eid,tb,covid-19,dashboard)app/common/,app/includes/shared includes and helpersapp/header.php,app/footer.php,app/index.phpUI scaffolding and redirectsapp/api/versioned API scripts (e.g.,app/api/v1.1/*)app/classes/modern PHP classes (services, utilities, middlewares, registries)sys/migrations/versioned schema migrations, applied bybin/migrate.php.sql/init.sqlis the fresh-install seed only.sys/cron/the Crunz task definitions
Services, Utilities, and Domain Classes¶
PSR-4 autoloaded classes live under app/classes/:
Services/core services (DB, system, common helpers)Middlewares/Slim middleware for UI and APIHttpHandlers/request handlers (legacy bridge)Utilities/logging, helpers, and shared toolsInterop/external system integrations (DHIS2, FHIR)Repositories/data access classes.composer check-repository-boundariesenforces what may call them.ErrorHandlers/,Exceptions/error handling and exception typesFactories/object factories, includingDatabaseFactoryHttp/response helpers such asApiV2ResponseContracts/,Abstracts/,Helpers/interfaces, base classes and small helpers
These are auto-registered into the DI container and can be fetched via ContainerRegistry.
Database¶
App\Services\DatabaseServiceis the single database service. The container builds it throughApp\Factories\DatabaseFactory(app/system/di.php). Code reaches the database through it and never opens a connection of its own.App\Services\AuditTriggerServicemanages the audit triggers. The post-update run drops them before migrations and reinstalls them afterwards.
Background Jobs and Maintenance¶
- Scheduled jobs are defined in
sys/cron/ScheduledTasks.php.crunz.ymlpoints Crunz at that folder. cron.shandvendor/bin/crunzrun scheduled tasks.- CLI scripts live in
bin/andapp/tasks/(remote sync, archiving, migrations).
Data, Files, and Assets¶
- Web root:
public/ - Static assets:
public/assets/ - Uploads:
public/uploads/ - Temporary files:
public/temporary/ - Sensitive temporary files:
var/temporary/(served only throughdownload.php) - Runtime cache/logs:
var/cache/,var/logs/ - Backups:
backups/ - SQL schema and utilities:
sql/,db-tools.php
Integration Points¶
- Remote sync workflows live in
app/remote/andapp/tasks/remote/. - External service clients are in
app/classes/Interop/.
Checks¶
The CI checks every change must pass are listed in engineering-standards.md.
Notes for Ongoing Modernization¶
- Slim is currently used as the entry layer and middleware pipeline.
- Most routes still resolve to legacy PHP includes. Gradual refactors can move legacy pages into Slim routes or controllers while retaining middleware coverage.