Skip to main content

Technical Requirements: Desktop Electron EHR Client

Domain: Platform client (Electron)
Version: 1.0
Date: 2026-03-31
Companion: SPEC.md, SOLUTION_DESIGN.md

References:


1. Technology stack

Canonical theme stack: ../../common/THEME.md §3 defines the single base theme shared by desktop, web, and mobile. The table below summarises desktop-specific choices aligned to that canonical source.

AreaRequirement
ShellElectron (supported LTS track; version pinned in repo).
RendererReact + MUI (foundation + complex components) + Tailwind CSS (utility styling, Preflight disabled — MUI CssBaseline is the reset) + Emotion (MUI internals + sx escape hatch) + Motion (motion.dev) for animation. Major versions aligned with apps/ehr-web.
Tokens & theme@ghasi/design-tokens + @ghasi/theme-runtime — tokens drive MUI theme, Tailwind preset, CSS variables, and motion tokens. Per-tenant overrides resolved via config-resolver per ../../common/THEME.md §5.
Icons@ghasi/icons-react — shared SVG source with RTL-mirror metadata.
BuildVite for renderer and preload bundles; avoid running Next.js inside Electron for the primary UI.
LanguageTypeScript strict mode.
HTTPHTTPS to Kong-exposed APIs only for sync; no NATS from client (offline-first SPEC).
Shared UIWorkspace packages: @ghasi/design-tokens, @ghasi/theme-runtime, @ghasi/design-system, @ghasi/widgets, and other shared clients as applicable.

2. Process architecture (TR-DSK-###)

IDRequirement
TR-DSK-001Main process SHALL manage window lifecycle, optional auto-update, and privileged IPC; it SHALL NOT expose Node APIs directly to the renderer.
TR-DSK-002Preload script SHALL be the only bridge; expose a minimal, typed API (contextBridge) for storage, sync, and secure token operations.
TR-DSK-003Renderer SHALL be treated as untrusted; assume XSS attempts; no secrets in renderer bundle.
TR-DSK-004Content-Security-Policy and webPreferences (e.g. contextIsolation: true, nodeIntegration: false) SHALL follow Electron security best practices.

3. Local persistence and encryption

IDRequirement
TR-DSK-010Primary local store SHALL be SQLite (e.g. better-sqlite3 in main, or equivalent) with a documented schema version and migrations.
TR-DSK-011PHI SHALL be encrypted at rest at the file level or via SQLCipher-compatible extension per deployment policy; document key derivation (e.g. OS keychain + tenant-scoped salt).
TR-DSK-012Local database files SHALL live in user-data paths appropriate per OS; paths SHALL NOT be world-readable.
TR-DSK-013Tenant isolation: all persisted rows SHALL be scoped by tenantId (and user/session where required); queries SHALL enforce the same.

4. Outbound queue (outbox)

Aligned with offline-first TECHNICAL_REQUIREMENTS.md §4:

FieldPurpose
idLocal primary key
clientMutationIdStable idempotency token (UUID v4 or ULID)
tenantIdFrom session; queue entries MUST NOT be replayed under wrong tenant
operationTarget operation (e.g. POST /v1/patients, POST /v1/orders)
payloadSerialized JSON
statuspending / syncing / completed / failed / conflict
serverResponseLast snapshot or structured error for UX
createdAt / updatedAtOrdering and retention
IDRequirement
TR-DSK-020Every queued mutation SHALL include clientMutationId; HTTP SHALL send Idempotency-Key and/or body token per service API docs.
TR-DSK-021Mutations affecting the same aggregate (e.g. same patientId) SHOULD be sent in causal order per module rules.
TR-DSK-022Idempotent success responses SHALL be reconciled by stable server ids in local store (same semantics as web).

5. Sync and HTTP behavior

IDRequirement
TR-DSK-030Base URL SHALL target Kong public routes per API_PATH_CONVENTIONS.md (/api/, /v1/, /fhir/R4/ as applicable).
TR-DSK-031Authorization: Bearer JWT; refresh tokens handled per IAM policy; on 401/403 do not infinite-retry sync (TR-OFF-007).
TR-DSK-032On 429, exponential backoff with jitter (TR-OFF-008).
TR-DSK-033Structured error bodies SHALL use code for branching (TR-OFF-009); map to user-visible conflict and retry flows.
TR-DSK-034Correlation: optional X-Correlation-Id on sync requests (TR-OFF-010).
TR-DSK-035There is no Next.js BFF in the desktop stack; the client MUST attach idempotency headers directly to upstream-appropriate calls (equivalent to BFF forwarding in TR-OFF-005).

6. Authentication and token storage

IDRequirement
TR-DSK-040Use OIDC/OAuth2 flows compatible with platform IAM (Keycloak or as deployed); PKCE for public desktop clients where applicable.
TR-DSK-041Store refresh tokens in OS credential storage (e.g. keytar or Electron safeStorage) where available; avoid plain-text localStorage for long-lived secrets.
TR-DSK-042Session timeout and logout SHALL clear local sensitive state per policy (tokens, cached PHI as required).

7. Localization and direction (TR-DSK-070–076)

IDRequirement
TR-DSK-070Renderer SHALL use react-intl (IntlProvider) with message catalogs aligned to @ghasi/i18n / ehr-web keys; avoid divergent copy for the same clinical concept.
TR-DSK-071For RTL locales, SHALL apply MUI direction: 'rtl' and Emotion CacheProvider with stylis-plugin-rtl (same pattern as apps/ehr-web); ensure both LTR and RTL are tested.
TR-DSK-072On locale or direction change, SHALL update document.documentElement.dir and lang without a full app reload where possible; keep theme direction in sync.
TR-DSK-073Main process native menus, OS dialogs, and window titles SHALL follow a single documented strategy: either app-selected locale (preferred for parity with in-app language) or OS app.getLocale() with explicit product decision; avoid mixed-language chrome without intent.
TR-DSK-074Dates, times, numbers, and calendars SHALL use dayjs (or equivalent) with the correct locale plugin and REGIONAL_PROFILE.md rules (Gregorian + optional Hijri display where required).
TR-DSK-075E2E tests SHALL include at least one RTL run: assert dir="rtl" (or equivalent) on the shell and one clinical surface; optional screenshot baseline for visual regression.
TR-DSK-076Persist locale/direction preference in local settings store; if the server exposes user preferences, reconcile on login per product rules.

8. Updates and distribution

IDRequirement
TR-DSK-050Built artifacts SHALL be signed; auto-update SHALL verify signatures before apply.
TR-DSK-051Document channels (beta/stable) and tenant-specific pinning if required.

9. Testing obligations

IDRequirement
TR-DSK-060Unit tests for outbox state machine, idempotency reconciliation, and backoff.
TR-DSK-061Integration tests against mock Kong or test stack for sync paths.
TR-DSK-062E2E (e.g. Playwright) for login → offline edit → online sync smoke paths.
TR-DSK-063E2E or component tests for RTL shell and mixed-direction identifier display (see TR-DSK-075).

10. AI integration (TR-DSK-080–083)

IDRequirement
TR-DSK-080Cloud AI calls SHALL use only Kong-exposed orchestrator routes (e.g. /v1/ai/... per AI_PLATFORM.md §7) with Bearer JWT; no third-party model API keys or SDKs embedded in the renderer bundle.
TR-DSK-081Optional local inference SHALL run in the main process or a dedicated worker subprocess with a typed IPC contract (request/response size limits, timeouts, optional redaction); the renderer MUST NOT load arbitrary native inference stacks directly.
TR-DSK-082Feature toggles for ai.cloud and ai.local (or equivalent keys) SHALL come from config-resolver / tenant policy and licensing; default deny until explicitly enabled.
TR-DSK-083When both cloud and local are enabled, document routing policy (e.g. prefer local when offline or for latency; cloud when policy requires centralized audit only) — product-owned; SHALL remain consistent with AI_PLATFORM.md §8.

11. Appendix: Server-side idempotency (current baseline)

Non-exhaustive; verify in code and module API_DOCS.md:

FlowNotes
POST /v1/patients (registration)Idempotency-Key / clientMutationId — reference implementation in offline-first pack.
POST /v1/orders (orders)Idempotency-Key supported (see orders).

Additional modules MUST be verified before marking offline write as complete.