Skip to content

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/tenancy 3.9). PostgreSQL pgsql_log connection 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. Single s3 disk config, endpoint-switchable at runtime via AWS_ENDPOINT.
  • Realtime: Laravel Reverb + pusher-js client + laravel-echo. Reverb is the broadcaster — pusher-php-server is 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 via mcp__kendo-emmie MCP 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-auditing is 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/telescope is registered with broad watcher defaults and an empty viewTelescope Gate. 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 → Model

All 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 adapterStoreModuleFactory for stores — predates @script-development/fs-adapter-store. ADR-0013 adoption decision is pending Commander disposition on the broader Armory strategic call.
  • A custom axios wrapper at apps/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 ​

DecisionStatus on Emmie
Audit LoggingNot Started — fractured across three mechanisms; doctrine deliberation complete, Engineer Phase 1 is the next move
Cascade DeletionPartial — at least 4 known cascade sites (one defensible inside stancl); explicit restrictOnDelete() preferred for new work
AI Interaction LoggingNot Started — one OpenAI call site exists with no compliant logging; shelved for a dedicated campaign
Multi-TenancyComplete — via stancl/tenancy; central vs tenant separation arch-test-enforced
Action Class ArchitectureComplete — 316 Actions on execute(); arch test enforces
FormRequest → DTO FlowComplete — interface-based pattern across 154 FormRequests
Domain-Driven Frontend StructureComplete — 25 domains follow the shape; lint enforces
Adapter-Store PatternNot Started — local pre-Armory factory in use; canonical adoption pending broader Armory disposition
Page Integration TestsNot Started — all 781 specs are shallowMount unit-style; integration harness not present
Input/Result DTO SplitNot 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.

Architecture documentation for contributors and collaborators.