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.