Solution Design: Desktop Electron EHR Client
Version: 1.0
Date: 2026-03-31
Companion: SPEC.md, TECHNICAL_REQUIREMENTS.md, AI_PLATFORM.md
1. Design goals
- Local-first UX with server authority for licensing, access-policy, and global invariants.
- Secure process boundaries (main vs preload vs renderer).
- Replay-safe mutations via
clientMutationId/Idempotency-Keywhere APIs support it. - Direct HTTPS to Kong (no dependency on a Next.js BFF for the primary sync path).
2. Logical components
| Component | Responsibility |
|---|---|
| Main process | Windows, menus, deep links, auto-update, OS integration, optional native modules for DB/crypto. |
| Preload | contextBridge API: narrow surface for DB access, token vault, sync control, safe file paths. |
| Renderer (React) | UI, forms, routing, MUI theme, offline/sync indicators. |
| Local store (SQLite) | Read models, drafts, encrypted PHI per policy. |
| Outbound queue | Pending mutations with ordering metadata per aggregate. |
| Sync scheduler | Online detection, token refresh before burst, backoff, reconciliation. |
| Kong | Edge TLS, auth, rate limits, routing to services. |
| Owning services | Business rules, idempotency, audit, NATS (server-only). |
3. Deployment topology
4. Comparison: ehr-web (Next.js) vs desktop
| Topic | ehr-web | Desktop Electron |
|---|---|---|
| Transport | HTTPS to Kong; may use Next.js app/api BFF | HTTPS to Kong from main or sync worker; no BFF required |
| Idempotency | BFF should forward Idempotency-Key (TR-OFF-005) | Client attaches headers on direct service calls |
| SSR / SEO | Next.js App Router | Not required; SPA in renderer |
| Local DB | IndexedDB / future unified outbox | SQLite in main (recommended) |
| Secrets | Browser cookie/session patterns | OS secure storage + preload boundary |
5. Sequence: login and tenant context
6. Sequence: capture while offline, sync on reconnect
7. Sequence: conflict path
8. Sync scheduler behavior
- Subscribe to OS online/offline events and optional heartbeat to Kong health or lightweight GET.
- Before a large flush: refresh tokens if within refresh window.
- Ordering: per module rules (e.g. per
patientIdserial where required). - Concurrency: bounded parallel requests where safe; never violate aggregate ordering rules.
- Poison queue: after N failures, mark
failedand surface support-oriented error withcorrelationIdif present.
9. IPC contract (illustrative)
Actual names and shapes belong in code; minimally:
| Channel / method | Direction | Purpose |
|---|---|---|
db.query / db.mutate | Renderer → Main (via preload) | Parameterized SQL or domain-level CRUD (prefer domain-level to avoid SQL injection) |
sync.flush | Renderer → Main | Trigger sync burst |
sync.status | Main → Renderer | Push sync state updates |
vault.getTokens / vault.setTokens | Preload ↔ Main | Never expose refresh token to renderer |
Rule: keep IPC surface small and reviewable; add new methods instead of passing arbitrary Node APIs through.
10. Locale and direction propagation
- Renderer owns React tree and MUI theme; on locale change it updates
IntlProvider, themedirection, anddocument.documentElementdir/lang(see TR-DSK-070–072). - Main process may receive
locale-changedIPC to refresh Menu labels and native dialog titles so chrome does not stay English while the SPA is Arabic — or product may accept English menus until a later phase (document the choice in app README). - Persistence: locale/direction saved via preload → SQLite settings (TR-DSK-076).
11. AI: cloud orchestrator vs optional local inference
Aligned with AI_PLATFORM.md. Public cloud AI uses the same Kong entrypoint as other clients. Local inference is optional and policy-gated.
- Cloud path: HTTPS only through Kong to orchestrator routes; no vendor secrets in renderer (TR-DSK-080).
- Local path:
LocalInferenceWorkerholds native / subprocess inference; PHI only crosses IPC under policy; outputs that enter the chart still require human acceptance per module rules (AI_PLATFORM.md §5). - Offline: cloud path unavailable; UI degrades or uses local if TR-DSK-082/083 allow.