feat: v1.3.0 — desktop app, on-device AI, attachment browser, specialty cards#69
Open
beniamin-szilagyi wants to merge 119 commits into
Open
feat: v1.3.0 — desktop app, on-device AI, attachment browser, specialty cards#69beniamin-szilagyi wants to merge 119 commits into
beniamin-szilagyi wants to merge 119 commits into
Conversation
…m-aware navigation - Add AppPlatform enum with desktop/mobile detection - Add main_desktop.dart entry point with desktop DI registration - Enable macOS and Linux platform runners - Desktop dashboard shows 4 tabs: Home, Records, Import, Backup - Skip P2P discovery and receive mode on desktop - Add BackupRoute to app router
- Add BMAD config, memory, and core templates - Add project context, PRD, epics, and sprint status - Add implementation artifact stubs for desktop stories
…m-aware navigation - Add AppPlatform enum with desktop/mobile detection - Add main_desktop.dart entry point with desktop DI registration - Enable macOS and Linux platform runners - Desktop dashboard shows 4 tabs: Home, Records, Import, Backup - Skip P2P discovery and receive mode on desktop - Add BackupRoute to app router
…encrypted TCP - Add BackupBloc with pairing state management - Implement QR-based pairing with DevicePairing model - TCP service with AES-256-GCM encryption and keepalive - Device discovery via mDNS (_healthwallet._tcp) and SSDP (UPnP) - Desktop: shows QR code, runs TCP server, advertises via mDNS/SSDP - Mobile: scans QR, discovers desktop, connects as TCP client - PairingStorageService for persistent pairing via SharedPreferences
…firewall, encryption - Fix BackupBloc not registered in GetIt on both mobile and desktop entry points - Fix permission_handler MissingPluginException on macOS by guarding for desktop platforms - Fix TCP server using isolate to bypass Flutter macOS engine socket issue where ServerSocket in main isolate silently drops external connections - Fix discovery probe (Socket.connect + destroy) poisoning server state by removing TCP probe — discovery now returns saved IP directly - Fix BackupBloc.close() destroying singleton TcpService connections when factory-created BLoC instances were garbage collected - Fix GCM encryption buffer overflow — use actual bytes written (len + finalLen) instead of pre-allocated getOutputSize() buffer which included trailing zeros - Fix nonce generation using proper Random.secure() instead of weak Fortuna seed - Fix server port mismatch — startServer now returns actual port when fallback used - Add QR scanner to Sync page for backup pairing (detects pairing_key in QR JSON) - Add backup pairing flow via direct service calls instead of throwaway BackupBloc - Update BackupPage with desktop two-column layout showing connection details, QR pairing card, and HM-2 epic phase progress tracker - Update BackupBloc to dispatch BackupConnected on TcpService state changes - Clean up debug logging, remove verbose hex dumps
… device_id Tables modified: - FhirResource: +updated_at, +deleted_at, +device_id - Sources: +deleted_at (already has updatedAt) - ProcessingSessions: +updated_at, +deleted_at, +device_id - RecordNotes: +updated_at, +deleted_at Schema bumped from v9 to v10 with ALTER TABLE migration. Prerequisite for LWW sync and multi-device tracking.
Desktop tab renamed from "Backup" to "Sync" with sections: - Connection card (QR pairing, device info, transport type) - Backup card (placeholder: backup now, restore, history) - LWW Sync card (placeholder: status, pending changes) - Processing History card (origin badges: phone/desktop/import) Added ConnectionTransport enum to BackupState: - tcp (WiFi Router) - multipeerConnectivity (Direct, no router) - unknown Transport type shown in connection chip and info rows so user always knows HOW devices are connected. Mobile layout updated: "Desktop Backup" → "Desktop Sync" with transport label shown when connected.
New transport architecture: CommunicationService (abstract interface) ├── TcpTransport (wraps existing TcpService, for WiFi/cross-platform) ├── MpcTransport (MultipeerConnectivity, for iPhone ↔ macOS direct) └── TransportSelector (picks primary transport based on platform) Apple platforms (iOS/macOS): MPC primary, TCP fallback Other platforms (Windows/Linux/Android): TCP only MpcTransport uses MethodChannel 'dev.lifevalue.healthwallet/mpc' with methods: startAdvertising, startBrowsing, sendData, disconnect and callbacks: onPeerConnected, onPeerDisconnected, onDataReceived Native Swift/macOS implementation needed in macos/Runner/ (next step). Airdrop package has iOS MPC only — macOS requires new platform code.
…S support Transport abstraction layer (Dart): - CommunicationService abstract interface - TcpTransport wraps existing TcpService - MpcTransport for MultipeerConnectivity via airdrop package - TransportSelector auto-picks MPC on Apple, TCP elsewhere macOS entitlements: added network.incoming for MPC Airdrop package (packages/airdrop/) updated separately: - Added macos/ platform with AirdropPlugin.swift + MacOSMultipeerManager.swift - macOS platform registered in pubspec.yaml - Same channel (dev.lifevalue.airdrop) for iOS and macOS - Leaner than iOS: focused on data transport for desktop sync
- build.yaml: exclude transport/ from drift_dev analysis - pubspec.yaml: airdrop → local path (../packages/airdrop) for dev - Podfile: macOS deployment target 10.15 → 12.0 (MPC requires 12.0) - Xcode project: MACOSX_DEPLOYMENT_TARGET → 12.0
…ktop/communication Structure: sync/presentation/ — Universal Sync page, QR scanner sync/data/ — Shared: FHIR local data, remote data source, DTOs, JWT, mappers sync/domain/ — Shared: SyncRepository interface, Source entity, services, use cases sync/ehrs/fasten/ — Fasten-specific only (3 files: sources API, repository impl, QR format) sync/desktop/communication/ — Desktop sync (moved from backup/) Generic code kept in shared layer (reusable for future EHR providers): - SyncRepository interface - SyncRemoteDataSource (generic FHIR fetch) - JwtService - Source entity, DTOs, mappers Fasten-specific code isolated (only what cannot be reused): - source_remote_data_source (Fasten sources API) - sync_repository_impl (Fasten sync logic) - sync_qr_data (Fasten QR format) No functional changes. All imports updated.
Connection order on mobile (iPhone/Android): Step 1: MPC (Apple only, 10s timeout, no network needed) Step 2: TCP saved IP (fast, works if network unchanged) Step 3: mDNS + SSDP network discovery (finds desktop on new IP) Step 4: Fail with "scan QR again" message Auto-reconnect: on disconnect, waits 3s then retries the full chain. Handles network changes (new WiFi, USB tethering, etc). Added DiscoveryService.discoverViaNetwork() — skips saved IP, goes directly to mDNS+SSDP for when saved IP is stale.
…-level features Major restructure following SOLID principles: features/processing/ ← Shared AI pipeline (platform-agnostic) - data/: llamadart engine, OCR, prompts, repositories, session storage - domain/: MappingResources, ProcessingSession, AI services - presentation/: ProcessingBloc, shared widgets, model management features/capture/ ← Input methods (HOW documents enter the pipeline) - scan/: Camera capture (mobile only), focus mode, preview, reorder - import/: File picker (both platforms) features/desktop/ ← Desktop-specific features - communication/: TCP, MPC, pairing, discovery (CommunicationBloc) - backup/: Snapshot transfer, restore (placeholder) - handover/: Processing handover protocol (placeholder) - lww_sync/: Delta sync (placeholder) features/sync/ ← Data connections (Fasten + future EHRs) - presentation/: Universal Sync page, QR scanner - ehrs/fasten/: Fasten-specific (3 files) - data/: Shared FHIR data layer, DTOs, JWT - domain/: SyncRepository interface, Source entity Class renames: BackupBloc → CommunicationBloc BackupState → DesktopSyncState BackupEvent → CommunicationEvent BackupPage → SyncDesktopPage BackupConnectionStatus → ConnectionStatus All imports updated. No functional changes.
Features restructured: features/processing/ — Shared AI pipeline (ProcessingBloc, no capture code) features/capture/ scan/ — Camera capture (ScanBloc, mobile only) import/ — File picker (ImportBloc, both platforms) desktop_import/ — Drag & drop (DesktopBloc, desktop only) features/desktop/ communication/ — TCP, MPC, pairing (CommunicationBloc) presentation/ — Desktop hub page + widget cards backup/ — Placeholder handover/ — Placeholder lww_sync/ — Placeholder features/sync/ presentation/ — Universal Sync page ehrs/fasten/ — Fasten-specific (3 files) data/ — Shared FHIR data layer domain/ — Generic interfaces + services Class renames: ScanBloc (processing) → ProcessingBloc ScanState → ProcessingState ScanEvent → ProcessingEvent ScanStatus → PipelineStatus ScanMode → CaptureMode BackupBloc → CommunicationBloc BackupState → DesktopSyncState BackupPage → DesktopPage Capture blocs extracted from ProcessingBloc: ScanBloc — camera scanning business logic ImportBloc — file picker + image picker logic DesktopBloc — drag & drop validation logic Desktop page split into composable widgets: ConnectionCard, BackupCard, ProcessingCard, SyncStatusCard, ConnectionChip, DesktopCard, InfoRow Connection improvements: Fallback chain: MPC → saved IP → mDNS+SSDP Auto-reconnect on disconnect (3s delay) discoverViaNetwork() bypasses stale saved IP All imports updated. No functional changes to mobile flows.
…p PDF viewing LWW delta sync engine syncing fhir_resource, sources, record_notes, and processing_sessions between mobile and desktop over encrypted TCP. Sync protocol: table status exchange → full delta for differing tables → bidirectional verify → file request for missing attachments. Attachments embedded as base64 in DocumentReference deltas, restored with unique names and proper extensions. Broken file URLs from backup restore auto-fixed on startup and after each delta apply. LWW override prefers incoming rows when local has unresolvable file paths. Schema v10 adds updated_at, deleted_at, device_id columns with SQLite triggers. TCP write lock serializes concurrent socket writes. Offline queue persists unsent deltas across app restarts. Desktop PDF viewing uses pdfx (supports macOS/Windows/Linux) with flutter_pdfview fallback on mobile. File existence checks prevent crashes on missing attachments.
…r, history UI BackupService creates SQLite snapshots via VACUUM INTO with SHA-256 checksums. BackupBloc manages backup/restore lifecycle with progress tracking. Desktop streams backup to mobile in 64KB chunks over encrypted TCP (backup_start → backup_chunk → backup_complete protocol). MobileBackupHandler receives and reassembles chunks on mobile side. DesktopBackupReceiver handles incoming backups on desktop. Both verify checksums before applying. ChunkTransferService provides reusable chunked binary transfer over TCP. MessageRouter dispatches incoming TCP messages to appropriate handlers. BackupCard UI shows backup history with timestamps, sizes, record counts, progress indicators during backup/restore, location picker, and delete confirmation dialogs.
HandoverService manages desktop-side session lifecycle: receives file chunks from mobile, stores in temporary session directory, triggers AI processing via ProcessingBloc, and returns results over TCP. HandoverBloc orchestrates the handover flow with session tracking and status updates. HandoverSession entity models session state including file paths, processing status, and results. Scaffolding for full integration — desktop processes documents with on-device AI models and streams results back to mobile.
Add macOS/desktop handling in device capability service and scan network data source. Update sync page layout for desktop. Minor processing bloc adjustments for cross-platform compatibility.
macOS vm.page_free_count reports only truly free pages (not inactive/purgeable cache), giving misleadingly low values like 218MB on machines with 16GB+ RAM. Desktop platforms skip the available memory gate since they have sufficient resources for AI model loading.
Google ML Kit Text Recognizer is not available on macOS/Windows/Linux. Desktop now skips OCR entirely and uses the vision model directly for both basic info extraction and remaining resources. Mobile flow unchanged — still uses OCR fast path with vision fallback.
Saved SharedPreferences AI settings (context=512, gpuLayers=0) from mobile caused vision model crash on macOS. Desktop now passes null for gpuLayers, threads, and contextSize so auto-config kicks in based on actual RAM (e.g., 64GB → ctx=4096, gpuLayers=99, threads=8).
The processing handler ran Google ML Kit OCR before AI extraction. On desktop (macOS), ML Kit is unavailable so OCR returned empty text, causing the session to be set to draft without ever running the AI model. Desktop now skips the OCR pre-match phase entirely and goes directly to mapBasicInfo which uses the vision model. Mobile flow unchanged.
…60px) Mobile resizes images to 560px max to fit in constrained memory. Desktop with abundant RAM uses 1120px for better text recognition in medical documents. The vision model can read smaller text and extract more accurate data from the higher resolution input.
Small vision models sometimes generate conversational text instead of JSON. Adding '\n\nJSON:\n' suffix forces the model to start generating JSON immediately, matching the text prompt behavior.
This reverts commit 46c8d97.
…me scan→processing P0: GBNF grammar-constrained JSON output (all platforms) - GbnfGrammars.jsonArray constrains model output to valid JSON arrays - Eliminates conversational text and malformed JSON from all inference - Applied to both vision and text inference via GenerationParams.grammar P1: macOS OCR via Apple Vision framework - AppDelegate.swift registers MethodChannel (dev.lifevalue.healthwallet/ocr) - VNRecognizeTextRequest with accurate recognition + language correction - MacOsOcrChannel Dart wrapper with graceful error handling P2: Abstract TextRecognitionService with platform DI - TextRecognitionService now abstract interface - MobileTextRecognitionService (Google ML Kit) for iOS/Android - DesktopTextRecognitionService (Apple Vision) for macOS - PdfConversionMixin shares cross-platform PDF rasterization - Platform-conditional registration in RegisterModule P3: Unified pipeline — removed all isDesktop bypass - Desktop uses same flow as mobile: OCR → text fast path → vision fallback - Full quality stack enabled: post-processing, OCR validation, patient pre-match - Handler passes null for AI settings on desktop → auto-config P4: Image preprocessing for desktop OCR/vision - ImagePreprocessor applies contrast (1.3x) + sharpen kernel before OCR - No-op on mobile, 95% JPEG quality on desktop (vs 85% mobile) - 1120px max image dimension on desktop (vs 560px mobile) P5: Desktop vision tokens increased to 1024 (vs 512 mobile) Qwen 8B desktop model variant: - AiModelVariant.qwen7b (Qwen3-VL-8B-Instruct Q4_K_M, ~5.3GB) - Default on desktop, available in model management dialog - 4x parameters vs 2B for better text recognition accuracy LoadModel state refactored to dynamic maps: - Map<AiModelVariant, bool> for downloaded/downloading status - Map<AiModelVariant, double> for per-variant progress - Model management dialog iterates AiModelConfig.availableVariants Rename scan→processing throughout processing feature: - ScanRepository → ProcessingRepository - ScanNetworkDataSource → AiInferenceDataSource - ScanInferenceHandler → AiInferenceHandler - ScanProcessingRepository → AiExtractionRepository - ScanLocalDataSource → ProcessingLocalDataSource - ScanLogBuffer → ProcessingLogBuffer - ScanPathHelper → ProcessingPathHelper
MpcSyncPlugin registers a FlutterMethodChannel (dev.lifevalue.healthwallet/mpc_sync) for iPhone↔macOS direct connection via Apple MultipeerConnectivity framework. Supports: startAdvertising, startBrowsing, sendData, disconnect. Auto-accepts peer invitations, relays connection state and received data back to Dart via method channel callbacks.
… pairing" This reverts commit 455aeac.
- Create EphemeralAttachmentBrowseService for in-memory records - Add view mode toggle (Attachments/Records) to ephemeral viewer - Add styled header with shadow on scroll matching Records page - Add search, filter, and filter chips to ephemeral viewer - Pass sourceRecords through bloc for full record context - Restrict filter bottom sheet to available FHIR types from sender
…shed AppButton variant - Show warning style (amber) instead of error when AI model not found - Add "Attach without processing" primary button for no-model case - Hide Retry button when model is missing - Add dashed variant to AppButton (replaces DottedBorder dependency) - Add hasError support to AppDropdownField - Fix specialty field validation with red border on error - Align error messages from start in create encounter dialog - Constrain attach-to-encounter dialog to 500px max width for desktop
- Add ConnectionDialog.openQRScanner for direct full-screen QR scanning - Auto-detect QR type: Desktop pairing vs Fasten Health sync - Fix Fasten sync by removing clearDemoData call that threw exception - Make SyncBloc a lazySingleton to ensure single instance across app - Add app-level BlocListener for sync success dialog - Add debug logging throughout sync flow - Bold HealthWallet.me and Fasten Health in scanner description - Rename section label to "Data Sync & Backup"
…eferences - Add GitHub-style type-to-confirm for source deletion - Allow deletion of HealthWallet (wallet) sources - Strip "Wallet - " prefix from wallet source display names - Show EHR sync status in preferences sync section with last sync time - Open QR scanner directly from preferences without dismissing modal - Use wallet icon for all source types in source list dialog - Add l10n keys for new features
…assifier - Add specialty section with reorderable cards on home dashboard - Add specialty icons (18 SVG assets) mapped to MedicalSpecialty enum - Add SpecialtyClassifier for auto-classifying records by specialty - Add specialty picker with icons in grid layout - Match icon sizes (22/26) for both specialties and resources sections - Add home overview toggle, section headers, and visibility preferences
…ITMS-90291) Simplify framework fix into a reusable private lane that runs after archive and before export. Fixes Resources symlink pointing to Versions/A/Resources instead of Versions/Current/Resources.
… msix Store config - Update FHIR entity interfaces and implementations across all resource types - Refine attachment browse bloc, repository service, and ephemeral service - Update records page, detail page, and attachment detail panel - Add specialty classifier interface and implementation - Update home data handler and dashboard sections - Fix app_database schema alignment - Update macos Fastfile app bundle name to HealthWallet.me - Configure msix_config with Microsoft Store identity and publisher values
… panel fixes, multi-file attach - Expand SpecialtyClassifier to classify all main record types (not just Encounter/DiagnosticReport) - Add encounter-inheritance: solo records inherit parent encounter's specialty - Add specialtyOverride column (DB v11) for manual overrides without mutating EHR data - Remove hardcoded [Encounter, DiagnosticReport] defaults — specialty filter loads all types - Fix specialty filter flow: clear type filters when specialty is active - Desktop details panel: fix negative Row spacing crash (ITMS-90291), resizable to 800px - Desktop nav arrows with pill buttons (Figma design) for attachment preview - Responsive preview padding (240px desktop, 16px mobile) - Multi-file attachment: accept List<File> in single event, process all files - File counter shows current file index "(1 of 2 files)" below filename - Transparent preview background in dark mode - Larger preview area (55% screen height)
Storage: - Add "Reset App Data" section in Preferences (macOS only) - Type-to-confirm dialog (user must type "RESET") - Clears database, SharedPreferences, cache, and documents - Exits app after reset for clean restart Tray performance fixes: - Add .distinct() filters on CommunicationBloc/LwwSyncBloc stream listeners - Capture and cancel messages stream subscription in CommunicationBloc - Debounce tray menu rebuilds (100ms) to prevent rapid redraws - Skip redundant state emissions in TrayBloc event handlers
Backup dialog: - Fixed header and footer layout (scrollable list only) - Location and History labels - Inline backup description (date, records, size) - Hide create form when viewing backup details - Buttons right-aligned, checkbox left-aligned and smaller - Divider color matched to app theme Storage: - Reset App Data section in preferences (macOS only) - Type-to-confirm dialog (type RESET) - Clears database, preferences, cache Tray fixes: - Debounced menu rebuilds (100ms) - Captured message stream subscription - Distinct filters on bloc listeners - Skip redundant state emissions UI polish: - Mini status cards match Figma colors (light/dark mode) - Nav pill buttons match Figma (rounded, proper opacity) - Collapse pill button with overlapping chevrons - Removed minimize-to-tray from preferences - Reverted pubspec airdrop to git SSH ref
- Ephemeral viewer: 3-row split header (shared-from + info icon, toggle/search/filter, chips), AppBar removed in tablet landscape split mode, right detail panel full height - SessionBottomBar centered and width-constrained (wideDialogWidth) in ephemeral viewer using Stack overlay; thumbnails/timeline pushed above bar via bottomNavHeight: 140 - AttachmentBrowseView: didUpdateWidget triggers rebuild when bottomNavHeight changes - EphemeralDesktopDetailsPanel: resizable right panel for attachment browse in split mode - Incoming Health Records dialog constrained to dialogWidth on tablet (receive_mode_manager) - PeerInvitationView constrained to dialogWidth in PeerDiscoveryView on tablet - SelectionBottomBar constrained to wideDialogWidth on tablet (record_selection_view) - CustomArrowTooltip alignment changed to center in tablet landscape split mode
- Move demo_data.json to assets/demo_data/, add pdf_preview_demo_data.pdf - Remove deprecated ephemeral_attachment_view and attachment_detail_panel_ephemeral widgets - Update attachment_detail_panel, attachment_thumbnail_strip, records_repository_impl, pdf_thumbnail_utils - Update pubspec.yaml dependency, CLAUDE.md, untranslated_messages
…VisibleWindows guard
…ight - Fix attachment count on Encounters showing files from child resources. Encounters now only count directly owned DocumentReferences (no context.related or related pointing to the Encounter itself). - Non-Encounter records only show their own directly linked attachments, not all files sharing the same encounter. - Encounter attachment dialog shows all related files with grey subtitle indicating source record (title · type), direct files labeled "Current record" and sorted to top. - Fix attachment browse not refreshing after adding a file — capture bloc references before async FilePicker to avoid unmounted context. - Preserve selected record and thumbnail scroll position after reload. - Reduce mobile preview card height (0.45 clamp 280–420) without affecting tablet/desktop sizes. - Add l10n key "currentRecord" (EN/DE/ES/RO).
Remove reverse-page logic that started from the last page when navigating to a previous record. Tapping or swiping to any record now consistently opens at page 1.
background_downloader fails silently on macOS when handling HuggingFace 302 redirect chains. Desktop platforms now use Dio for model downloads with proper redirect support. Mobile keeps background_downloader for foreground service notifications.
…option Store DocumentReference files in Documents/HealthWallet/Documents on Windows instead of cluttering the root Documents folder. Enable reset option on Windows. Fix import page browse button behind nav bar.
373db12 to
0c210a6
Compare
…s on desktop - Use getApplicationSupportDirectory()/ocr_temp/ instead of getTemporaryDirectory() so preprocessed images are not purged by macOS during long AI inference - Delete preprocessed files immediately after OCR to avoid stale file accumulation - Guard handover sender against missing source files before readAsBytes() - Wrap preprocessForOcr in try-catch so any failure gracefully falls back to original path - Add disk-validation of cached image paths in onSessionActivated
…ve scroll and UX - Fix specialty field rendering gender options instead of medical specialties - Add icon + label display for each specialty item in both processing form and create-encounter dialog - Wrap specialty in FormField to enforce mandatory selection with validation error - Add openAbove option to AppDropdownField; specialty opens upward to avoid clipping - Fix processing page scroll: move Column to Scaffold.body directly so Expanded gets tight height constraints; move width constraint inside SingleChildScrollView child
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's new in v1.3.0
AI document processing on Mac
HealthWallet can now process your health documents entirely on your Mac — no internet connection required. When you import a scan or PDF, the on-device AI model (Qwen3-VL) reads the document, extracts structured health data, and maps it to FHIR records automatically. The Mac's hardware is used directly, bypassing the need to offload to a mobile device. You can also trigger processing from your iPhone and have your Mac do the heavy lifting via the Handover flow — useful when your phone doesn't have enough memory for inference.
Sync with your iPhone via QR code
Pair your iPhone and Mac once by scanning a QR code shown on the desktop app. After pairing, the two devices stay in sync automatically over your local network — no iCloud, no third-party servers. Any health records you add, edit, or delete on one device propagate to the other using a Last-Write-Wins sync protocol with conflict resolution. The connection uses AES-256-GCM encryption over TCP, with MultipeerConnectivity as a fallback when a VPN or firewall blocks direct LAN access.
New way to browse your health documents
The records browser now offers two modes: Attachments view shows your documents as a scrollable visual timeline with thumbnail previews, a year/month scrubber, and a full detail panel — ideal for quickly locating a specific scan or lab report by date. Records list view shows the structured FHIR data extracted from your documents, grouped by type. You can switch between modes freely and share records directly from either view.
Organize by specialty
Your health dashboard now groups records by medical specialty — Cardiology, Oncology, Neurology, Orthopedics, and more. Each specialty card on the home screen shows a count of relevant records and lets you jump straight to a filtered view. Cards are fully reorderable so you can surface the specialties most relevant to you. The classifier runs locally against your existing records and updates automatically as new documents are processed.
Test plan
SessionBottomBaron tabletSelectionBottomBarare constrained width on tablet