Emmie
A care-reporting and daily-client-report management tool for Dutch healthcare providers. Caregivers record observations on clients; reports flow to client-facing summaries and management dashboards.
Tech Stack
- Backend: Laravel 12, PHP 8.4 (strict types architecturally enforced)
- Frontend: Vue 3.5, TypeScript 5.9 (pinned exact). UnoCSS (attributify mode); Bootstrap 5 reduced to tooltip + CSS-variable bridge only.
- Databases: MySQL on DigitalOcean (multi-tenant DB-per-customer via
stancl/tenancy3.9). PostgreSQLpgsql_logconnection as a dedicated logging tier (currently dormant — see Known Deviations). - Object storage: environment-partitioned. Cloudflare R2 on main/prod (2 live tenants); AWS S3 on staging/beta (1 tenant). Per-tenant buckets via
vinkla/hashids. Singles3disk config, endpoint-switchable at runtime viaAWS_ENDPOINT. - Realtime: Laravel Reverb +
pusher-jsclient +laravel-echo. Reverb is the broadcaster —pusher-php-serveris installed but unused. - AI: OpenAI via
openai-php/laravel. One call site live today. - Hosting: Fly.io — three apps, one per frontend bundle (user / admin / client).
- Default branch:
development - Ticket prefix:
EMMIE-XXXX(ally filing viamcp__kendo-emmieMCP surface)
Compliance
Emmie carries the highest compliance burden of any territory: ISO 27001 + AVG (Dutch GDPR) + NEN 7510 (Dutch healthcare information security). It is the first war-room territory exposed to NEN 7510.
The ambition is to "become the most secure" — that is aspirational, not achieved. Fortification campaigns take priority over feature work, and several intake-state deviations from war-room doctrine are open and tracked rather than hidden:
- Audit logging is fractured across three incompatible mechanisms; ADR-0001 is not compliant today. A doctrine deliberation has concluded; the implementation campaign is the next major move.
owen-it/laravel-auditingis in use on 12 models — war-room doctrine explicitly rejects this package (no user snapshot, no hash chain). Removal is gated on the audit-logging implementation.laravel/telescopeis registered with broad watcher defaults and an emptyviewTelescopeGate. Env-gating verification for the healthcare prod surface is outstanding.- Sentry session-replay sampling at 100% with no explicit masking — Commander disposition is remove Sentry entirely, pending an Engineer deployment.
These are documented honestly so allies and soldiers can see the trajectory rather than discover it later.
Architecture Overview
Emmie follows the standard war-room pipeline:
Controller → FormRequest → DTO → Action → ModelAll 316 Actions are final readonly class with public function execute(...) (migrated 2026-04-27 in PR #181 — the last territory holdout on __invoke() is closed). An architecture test enforces the shape.
Authorization is two-tier in spirit: CheckPermission middleware over an int-backed PermissionEnum resource-class-indexed at the route layer, with Policies under app/Policies/. The deeper alignment with ADR-0006 is described at a high level — implementation depth is verified per Action when soldiers touch authorization.
Multi-tenancy runs through stancl/tenancy 3.9 (a different shape from kendo's hand-rolled implementation, but the same DIY DB-per-tenant intent per ADR-0008). Architecture tests enforce central-vs-tenant model separation.
Frontend
The frontend is split into three SPAs (user / admin / client) plus shared and auth modules, with 25 business domains distributed across them (15 user / 5 admin / 4 client / 1 shared). The vertical-slice domain shape per ADR-0014 is fully implemented and machine-enforced by a custom scripts/lint-folder-structure.mjs checker.
Two pre-Armory in-house systems sit at the foundation:
- A custom
adapterStoreModuleFactoryfor stores — predates@script-development/fs-adapter-store. ADR-0013 adoption decision is pending Commander disposition on the broader Armory strategic call. - A custom
axioswrapper atapps/vue-services/http/— predates@script-development/fs-http. Same disposition.
Emmie has 0/10 fs-packages adoption today by deliberate posture, not oversight.
Customer terminology is translated at runtime via a terminologyTranslationService — customers may render 'client' as 'bewoner', 'cliënt', etc. Hardcoding the strings 'client' or 'clients' in user-facing surfaces is banned at lint time.
Authentication
JWT via php-open-source-saver/jwt-auth 2.8 — three guards (user, admin, client) plus a vestigial web session guard. HS256, blacklist enabled. JWT_TTL=15m, JWT_REFRESH_TTL=15d. Custom claims: tenant + entity (manipulating these without understanding the multi-tenant bootstrap chain breaks cross-tenant isolation).
2FA: TOTP (spomky-labs/otphp) plus YubiKey hardware (bitbeans/yubikey). The YubiKey package is currently pinned to dev-master rather than a tagged release — a tracked supply-chain concern under NEN 7510 A.8.30.
Key Decisions
| Decision | Status on Emmie |
|---|---|
| Audit Logging | Not Started — fractured across three mechanisms; doctrine deliberation complete, Engineer Phase 1 is the next move |
| Cascade Deletion | Partial — at least 4 known cascade sites (one defensible inside stancl); explicit restrictOnDelete() preferred for new work |
| AI Interaction Logging | Not Started — one OpenAI call site exists with no compliant logging; shelved for a dedicated campaign |
| Multi-Tenancy | Complete — via stancl/tenancy; central vs tenant separation arch-test-enforced |
| Action Class Architecture | Complete — 316 Actions on execute(); arch test enforces |
| FormRequest → DTO Flow | Complete — interface-based pattern across 154 FormRequests |
| Domain-Driven Frontend Structure | Complete — 25 domains follow the shape; lint enforces |
| Adapter-Store Pattern | Not Started — local pre-Armory factory in use; canonical adoption pending broader Armory disposition |
| Page Integration Tests | Not Started — all 781 specs are shallowMount unit-style; integration harness not present |
| Input/Result DTO Split | Not Started — 128 DTOs in one root namespace; full migration is a dedicated Phase 2 campaign |
External Integrations
- OpenAI (
openai-php/laravel) — care-reporting AI assist (one call site) - Cloudflare R2 / AWS S3 — environment-partitioned object storage
- Cloudflare — CDN / DNS
- Sentry — error and session-replay capture (slated for removal)
- MailerLite, CM.com — transactional email and SMS where applicable
Collaboration
The Commander has admin access and the most say in the Emmie alliance — collaborators offer the least resistance of any allied territory. The flip side: war-room doctrine becomes emmie doctrine by default, and our own discipline is the enforcement surface. Documentation does not defer to ally decisions — this page and the territory briefing are the authority.