Skip to main content

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-Key where APIs support it.
  • Direct HTTPS to Kong (no dependency on a Next.js BFF for the primary sync path).

2. Logical components

ComponentResponsibility
Main processWindows, menus, deep links, auto-update, OS integration, optional native modules for DB/crypto.
PreloadcontextBridge 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 queuePending mutations with ordering metadata per aggregate.
Sync schedulerOnline detection, token refresh before burst, backoff, reconciliation.
KongEdge TLS, auth, rate limits, routing to services.
Owning servicesBusiness rules, idempotency, audit, NATS (server-only).

3. Deployment topology


4. Comparison: ehr-web (Next.js) vs desktop

Topicehr-webDesktop Electron
TransportHTTPS to Kong; may use Next.js app/api BFFHTTPS to Kong from main or sync worker; no BFF required
IdempotencyBFF should forward Idempotency-Key (TR-OFF-005)Client attaches headers on direct service calls
SSR / SEONext.js App RouterNot required; SPA in renderer
Local DBIndexedDB / future unified outboxSQLite in main (recommended)
SecretsBrowser cookie/session patternsOS 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 patientId serial where required).
  • Concurrency: bounded parallel requests where safe; never violate aggregate ordering rules.
  • Poison queue: after N failures, mark failed and surface support-oriented error with correlationId if present.

9. IPC contract (illustrative)

Actual names and shapes belong in code; minimally:

Channel / methodDirectionPurpose
db.query / db.mutateRenderer → Main (via preload)Parameterized SQL or domain-level CRUD (prefer domain-level to avoid SQL injection)
sync.flushRenderer → MainTrigger sync burst
sync.statusMain → RendererPush sync state updates
vault.getTokens / vault.setTokensPreload ↔ MainNever 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, theme direction, and document.documentElement dir / lang (see TR-DSK-070–072).
  • Main process may receive locale-changed IPC 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: LocalInferenceWorker holds 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.