feat: patient wallet — real Signing, encrypted share relay, import-from-app

Backend
- clinic Ed25519 signing key (services/signing.ts, routes/signing.ts,
  clinic_signing_keys table) — Settings → Signing is now real
- @noble wallet-crypto (lib/wallet-crypto.ts): ed25519 identity, base58check
  wallet numbers, sealed-box (x25519 + xchacha20poly1305)
- /wallet Socket.io relay namespace (challenge-signed device auth) forwarding
  only ciphertext; emitToWallet helper
- import-from-app flow (routes/patients-wallet.ts, services/wallet-share.ts):
  request-share → patient approval → decrypt + verify → review draft → commit
- temporary shares: patients.share_expires_at + 5-min auto-delete sweep; revoke

Frontend
- SigningPanel wired to live key/fingerprint/rotate + shared-records list
- "Import from a patient app" dialog (lib/signing.ts, import-from-wallet-dialog)
  reusing the draft-review path; temporary badge on the patient list

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalid Abdi
2026-06-21 18:19:57 +03:00
parent b74d5d2d05
commit 2d47abcc42
25 changed files with 5951 additions and 16 deletions
+3
View File
@@ -71,4 +71,7 @@ export type Patient = {
labTrend: Trend; // headline lab plotted as a sparkline
encounters: Encounter[];
source?: "manual" | "ai"; // "ai" = imported/drafted by the chat agent
// Set when this record was imported from a patient wallet as a *temporary*
// share — the ISO deadline after which it is auto-deleted from the clinic.
shareExpiresAt?: string | null;
};