-
change in progress1. Local persistence subsystem ARCH-001 The local persistence subsystem owns the application's local database — a SQLite file encrypted at rest via SQLCipher, located under the configured AppData path — applies schema migrations via Drift on first open, and exposes a typed API to the application layer for the clinic, patient, and recording domain entities.
-
change in progress1. First-launch database initialisation SRS-001 On first launch, when no database file exists at the configured application data path, the software shall create the local database, apply the current schema version, and create a default local clinic record that serves as the container for locally-created patient records.
-
change in progress1. First-launch readiness for local enrolment SYS-001 When the device is opened on a workstation that has no pre-existing BioFlow data directory, a default local clinic shall be present and immediately available for the clinician to attach newly-enrolled patient records, without requiring the clinician to first create or configure a clinic record manually.
-
-
Instantiate AppDatabase against a temporary filesystem path at which no database file exists. Trigger the initialisation pathway by performing any query that forces Drift's onCreate migration to run. Inspect the resulting state of the database on disk and of the seeded tables.
-
change in progress2. Local database encryption ARCH-002 The local SQLite database is encrypted on disk via the SQLCipher extension. The encryption key is held by flutter_secure_storage, which on Windows persists it as an entry in a DPAPI-encrypted file (flutter_secure_storage.dat) under the user's local app-data directory. On application bootstrap, the key is retrieved from secure storage and generated-and-persisted on first launch if absent. On every database connection open, the database connection service applies the key as the first statement (PRAGMA key) before any other operation; SQLCipher then transparently encrypts and decrypts SQLite pages.
-
change in progress2. Local database confidentiality at rest SRS-002 The software shall keep the local database file unreadable to any process that opens it without supplying the database credential, and shall reject database read and write operations when the credential is missing or incorrect.
-
change in progress2. Confidentiality of patient data at rest SYS-002 The device shall keep clinic, patient, clinical-user, recording, and audit-log data stored on the local workstation confidential against any party gaining access to the workstation's filesystem without the operator's BioFlow credentials.
-
-
Initialise an AppDatabase against a temporary filesystem path through the production openEncryptedConnection pathway with a known test key. Write a canonical row through the typed clinic API and close the database. Attempt to open the resulting file with the plain sqlite3 driver (no credential supplied) and read any user table. Attempt to open the same file through the production pathway with an incorrect key and read any user table. Then re-open the file through the production pathway with the correct key and read the canonical row.
-
change in progress3. Local database integrity mechanisms ARCH-003 The local SQLite database enforces referential integrity and write atomicity through three schema- and connection-level mechanisms. First, the Drift-declared schema carries foreign-key constraints linking patient rows to their clinic and to their assigned clinical user, and recording rows to their patient. Column-level constraints declared in Dart (NOT NULL by default, plus CHECK on enumerated text columns such as clinics.origin, patients.origin, and recordings.upload_status) cause the SQLite engine to reject schema-violating writes at insert time. Second, the database connection service enables foreign-key enforcement on every connection by issuing PRAGMA foreign_keys = ON immediately after applying the encryption key, so the schema-declared FK relations are enforced by the SQLite engine for every read and write throughout the application's lifetime. Third, application-layer use cases that perform multi-row or cross-table writes execute them inside a single Drift transaction, so a crash or process termination during the mutation leaves the database in either the pre-mutation or the post-mutation state and never a partial state. Together, these three properties of how the persistence subsystem is configured realise SRS-003.
-
change in progress3. Local database integrity enforcement SRS-003 The software shall enforce referential integrity between clinic, patient, and recording records through database foreign-key constraints; shall wrap any multi-row or cross-table mutation in a single transaction such that a crash or process termination during the mutation leaves the database in either the pre-mutation state or the post-mutation state and never a partial state; and shall reject — rather than silently truncate or drop — any write that would violate a NOT NULL, FOREIGN KEY, or CHECK constraint declared in the schema.
-
change in progress3. Integrity of patient data at rest SYS-003 The device shall preserve the integrity of clinic, patient, recording, and audit-log data stored on the local workstation against accidental alteration, partial writes, referential inconsistency, and concurrent-write corruption — such that any record returned by the device represents a complete and consistent state authored through the application.
-
-
Initialise an AppDatabase against a temporary filesystem path through the production openEncryptedConnection pathway with a known test key, forcing first-launch onCreate so the seeded LOCAL_CLINIC and the schema (including foreign-key declarations) are in place. Then, in four independent scenarios, exercise each of the rejection categories named in SRS-003 / ARCH-003.
(a) Foreign-key enforcement — attempt to insert a patient row whose clinic_id references a clinic that does not exist, and verify the SQLite engine rejects the write.
(b) Transactional atomicity — open a Drift transaction that performs two writes (insert a new clinic, then insert a patient referencing that clinic), then throw an exception inside the transaction; re-open the database and verify neither row is present.
(c) CHECK constraint enforcement — attempt to insert a clinic row whose origin column value is outside the enumerated set ('local', 'remote', 'cloud') declared on the schema, and verify the SQLite engine rejects the write.
(d) NOT NULL constraint enforcement — issue a raw INSERT (via customStatement, bypassing Drift's typed companion which guards NOT NULL at compile time) that supplies NULL for the clinics.name column, and verify the SQLite engine rejects the write at runtime. Bypassing Drift is necessary to prove the engine — not the compile-time guard — is what protects the data when a future migration, an unsafe raw write, or another customStatement caller bypasses the type system.
-
change in progress4. Audit-logging subsystem ARCH-004 The audit-logging subsystem realises SRS-004 through three software items in the hexagonal architecture. A domain-layer audit-repository port whose surface offers create and read operations only — no update or delete is exposed to the application. A service in the application/infrastructure boundary that exposes one semantic logging method per audited operation (logPatientCreated, logPatientUpdated, logPatientDeleted, logRecordingStarted, logRecordingStopped, logRecordingDeleted, logRecordingUploaded). A Drift-backed adapter that persists entries into the audit_logs table of the local persistence subsystem (ARCH-001). Application- layer use cases invoke the service after the corresponding record mutation; the service composes an entry (action, entity type, entity identifier, actor identifier when available, JSON details, and timestamp) and delegates persistence to the port.
-
change in progress4. Audit logging of clinical record operations SRS-004 The software shall write one audit-log entry for each of the following operations on local clinical records: creation, modification, and deletion of a patient; start, stop, and deletion of a recording; and successful upload of a recording to the cloud. Each entry shall carry the action, the identifier of the affected record, and a system-generated UTC timestamp. After an entry is written, the software shall not modify it in a way that obscures previously recorded information, and shall not delete audit entries.
-
change in progress4. Audit trail of clinical record operations SYS-004 The device shall maintain an audit trail that independently records every operation that creates, modifies, or deletes a clinical record on the local workstation, and every action that exports such a record to an external system. Each entry shall capture the action, the affected record, and a system-generated UTC timestamp. Audit entries shall not be modified in a way that obscures previously recorded information after they are written.
-
-
Initialise an AppDatabase against a temporary filesystem path through the production encrypted-connection pathway with a known test key, forcing first-launch onCreate so the schema and seeded LOCAL_CLINIC are in place. Construct the use cases or the production callers that participate in the audit chain, wired with a real AuditService backed by the production audit-repository adapter against the same database. Then, in seven independent scenarios, exercise the SRS-004 commitment that each named operation writes its audit entry.
(a) Patient creation: invoke the create-patient use case for a fresh patient; query audit_logs for entries on that patient; verify exactly one entry of action "PATIENT_CREATED" exists with the patient's identifier and a non-null timestamp.
(b) Patient update: create a patient (setup), invoke the update-patient use case with a changed field; verify exactly one entry of action "PATIENT_UPDATED" exists with the patient's identifier.
(c) Patient deletion: create a patient (setup), invoke the delete-patient use case; verify exactly one entry of action "PATIENT_DELETED" exists with the patient's identifier.
(d) Recording start: drive the recording-start pathway through the production recording-notifier (with the signal-processing engine and sleep-prevention port replaced by test doubles); verify one entry of action "RECORDING_STARTED" exists with the recording identifier.
(e) Recording stop: drive the recording-start then recording-stop pathways through the production recording-notifier with test doubles for the heavy collaborators; verify one entry of action "RECORDING_STOPPED" exists with the recording identifier (in addition to the "RECORDING_STARTED" entry).
(f) Recording deletion: create a recording (setup), invoke the delete-recording use case; verify one entry of action "RECORDING_DELETED" exists with the recording identifier.
(g) Upload: insert a recording (setup), drive the upload pathway through the production upload-manager with a test stub for the cloud client; verify one entry of action "RECORDING_UPLOADED" exists with the recording identifier.
-
change in progress5. Audit-log record shape and immutability ARCH-005 The audit_logs table in the local SQLite database stores one row per audit entry. Each row carries an audit identifier (UUID, primary key, immutable), an action string drawn from the application's enumerated set of audited operations, an entity_type and entity_id polymorphic reference to the subject record, a nullable user_id for the authenticated actor, a JSON-serialised details payload, and a UTC timestamp defaulted at the database level. No production code path issues UPDATE or DELETE against the table; the audit-repository port surface (ARCH-004) does not expose those operations.
-
change in progress4. Audit logging of clinical record operations SRS-004 The software shall write one audit-log entry for each of the following operations on local clinical records: creation, modification, and deletion of a patient; start, stop, and deletion of a recording; and successful upload of a recording to the cloud. Each entry shall carry the action, the identifier of the affected record, and a system-generated UTC timestamp. After an entry is written, the software shall not modify it in a way that obscures previously recorded information, and shall not delete audit entries.
-
change in progress4. Audit trail of clinical record operations SYS-004 The device shall maintain an audit trail that independently records every operation that creates, modifies, or deletes a clinical record on the local workstation, and every action that exports such a record to an external system. Each entry shall capture the action, the affected record, and a system-generated UTC timestamp. Audit entries shall not be modified in a way that obscures previously recorded information after they are written.
-
-
Initialise an AppDatabase against a temporary filesystem path through the production encrypted-connection pathway with a known test key. Construct the audit chain (AuditService + production audit-repository adapter against the same database). Then, in two scenarios, verify the ARCH-005 commitments on the audit_logs row shape and the SRS-004 immutability rule.
(a) Record shape: write a known audit entry via the audit service and query audit_logs for it; verify the row has a non-empty audit identifier, an action string drawn from the application's enumerated audit actions, the expected entity_type and entity_id, a non-null UTC timestamp generated by the database (not by the caller), and a parseable JSON details payload.
(b) Write-then-read sanity check: write an audit entry via the audit service, re-read it, and assert the details payload and system timestamp match what was written. Immutability is enforced structurally — the audit-repository port (SRS-004 / ARCH-005) exposes only create-and-read methods, so no application path can mutate a row. This scenario is the runtime corollary, confirming that the storage layer round-trips an entry faithfully.
-
change in progress6. Audit-trail review-and-export presentation surface ARCH-006 The audit-trail review-and-export surface realises SRS-005 by extending the Activities overlay (lib/presentation/overlays/activities_overlay.dart) with a tab titled "Audit Log". The pre-existing first tab is renamed from "Recent Activities" to "Recent Recordings" so that its name matches what it actually lists (rows from the recordings table) and does not collide with the new audit-trail tab. The resulting tab set, in order, is: Recent Recordings, Audit Log, Statistics, Archive. The Audit Log tab subscribes to the auditLogListProvider exposed by the application/providers layer, which streams the audit_logs rows from the local persistence subsystem (ARCH-001) via the audit-repository read side (ARCH-004). Entries are rendered as a scrollable list ordered by timestamp descending, each row showing the action, the entity_type/entity_id pair, and the UTC timestamp. The tab carries an Export button whose on-press handler serialises the currently-loaded entries to a file in one of two portable, human-readable formats — CSV (one row per entry, fields: audit_id, timestamp, action, entity_type, entity_id, user_id, details) or JSON (an array of entry objects with the same fields) — and writes the file to a workstation path chosen by the operator through the platform's standard save-file dialog.
-
change in progress5. Audit-trail review and export SRS-005 The software shall present the local audit trail to an authorised operator in a form that lists each entry's action, affected record, and system timestamp, ordered by time. The software shall additionally provide a means to export the current audit trail to a file in a portable, human-readable format that preserves the same fields as the on-screen presentation, so that the exported file can be examined off the device by an auditor or by the clinical organisation's own information-security review.
-
change in progress4. Audit trail of clinical record operations SYS-004 The device shall maintain an audit trail that independently records every operation that creates, modifies, or deletes a clinical record on the local workstation, and every action that exports such a record to an external system. Each entry shall capture the action, the affected record, and a system-generated UTC timestamp. Audit entries shall not be modified in a way that obscures previously recorded information after they are written.
-
-
Initialise an AppDatabase against a temporary filesystem path through the production encrypted-connection pathway with a known test key. Construct the audit chain (AuditService + production audit-repository adapter against the same database) and exercise two distinct audited operations through their use cases (a patient creation and a patient deletion) so that at least two distinguishable entries are present in audit_logs. Then, in two scenarios, exercise the SRS-005 / ARCH-006 commitment that the review-and-export surface produces a faithful copy of the trail.
(a) CSV export: invoke the production export pathway requesting CSV output to a temporary file path; re-open the file with a CSV reader and assert that each row in audit_logs has a corresponding row in the file with the same audit_id, action, entity_type, entity_id, user_id, timestamp, and details content.
(b) JSON export: invoke the production export pathway requesting JSON output to a temporary file path; re-open the file with a JSON parser and assert that each row in audit_logs has a corresponding object in the resulting array with the same audit_id, action, entity_type, entity_id, user_id, timestamp, and details content.
-
reviewed8. Recording control widget ARCH-008 The recording control widget occupies the fixed top region of the main window. It is a provider-bound presentation container (RecordingWidget) that subscribes to the recording, selected-patient, and signal-engine application providers and renders, through its view (RecordingWidgetView) and the recording sub-components (status badge, action buttons, center content, and menu panel), the recording controls, the current patient name and recording status, and the elapsed-recording-time readout. It dispatches operator actions — start and stop recording — to the recording view-model and holds no recording domain logic itself. The recorded duration shown in that readout is derived from the native recording engine's sample-accurate timing, pushed into the recording view-model as signal is captured rather than from a wall-clock timer, and is formatted as zero-padded HH:MM:SS by the recording widget state (RecordingWidgetState.formattedElapsedTime).
-
reviewed7. Always-visible recording control widget SRS-007 The software shall display a recording control widget anchored to the top of the main window, and shall keep that widget visible in all interaction states, including signal-control mode, menu mode, and while any overlay is open.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed13. Recorded-duration readout format SRS-013 While a recording session is active, the software shall display the recorded duration in HH:MM:SS format.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed14. Patient name in recording widget SRS-014 While a patient is selected, the software shall display the selected patient's name in the recording control widget.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
Pump the RecordingWidgetView — the rendering view that the provider-bound RecordingWidget container drives — in a flutter_test widget test with a seeded RecordingWidgetState representing a recording in progress for a known patient with a known elapsed time. Render the view and inspect its widget tree.
-
reviewed9. Bottom-bar mode controller ARCH-009 The bottom-bar mode controller owns the bottom bar's signal/menu mode. The mode is modelled as a domain value object (BottomBarMode) carrying the two modes and the pure toggle and per-mode content definitions; an application view-model (BottomBarNotifier) holds the current mode — signal mode at launch — and switches it via toggleMode(). The bottom bar widget (BottomBar) watches the mode provider and renders the controls for the current mode: the signal-parameter controls (high-pass, low-pass and notch filters, sensitivity, timebase, and montage) in signal mode, and the Patients/Montages/Settings/Activities navigation buttons in menu mode. A single toggle control invokes toggleMode() when the operator activates it; switching to menu mode opens the corresponding navigation overlay (the last-opened one, or Patients by default) and switching back to signal mode closes it. Dismissing the open overlay — by Escape, a click outside it, or re-selecting the active navigation item — clears the navigation selection, which resets the controller to signal mode.
-
reviewed8. Bottom-bar signal and menu mode toggle SRS-008 The software shall provide a bottom bar that switches between a signal-control mode and a menu mode when the operator activates the bottom-bar mode toggle.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed11. Signal-mode bottom-bar controls SRS-011 In signal mode, the bottom bar shall present the signal-parameter controls: a high-pass filter, a low-pass filter, a notch filter, a sensitivity control, a timebase control, and a montage selector.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed12. Menu-mode bottom-bar navigation buttons SRS-012 In menu mode, the bottom bar shall present the navigation buttons: Patients, Montages, Settings, and Activities.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed15. Bottom bar default and resting mode SRS-015 The bottom bar shall be in signal mode when the application launches, and shall return to signal mode whenever the open navigation overlay is dismissed.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
Pump the BottomBar in a flutter_test widget test with the bottom-bar mode provider in its default state. Inspect the rendered controls in signal mode. Activate the mode toggle. Inspect the rendered controls again, then activate the toggle a second time and inspect once more.
-
reviewed10. Overlay navigation subsystem ARCH-010 The overlay navigation subsystem manages the application's modal navigation overlays (Patients, Montages, Settings, Activities). The open-overlay state is held as a single selected index in the navigation view-model (NavigationNotifier), which drives which overlay the main page renders. A companion overlay view-model (OverlayNotifier) tracks overlay visibility, the dismissible flag, and per-overlay data. Because the rendered overlay is keyed off one index rather than a stack, at most one overlay is shown at a time and selecting another replaces it: MainPage renders the selected overlay in a single AnimatedSwitcher slot above a dimmed signal area, with the recording widget and bottom bar layered above it. Dismissal is wired two ways: a KeyboardListener closes the active overlay on the ESC key, and a full-screen barrier behind the overlay closes it when the operator taps outside the overlay content. Both paths call clearSelection(), which is gated by a dismissible flag (overlayDismissibleProvider) so an overlay with in-progress edits (the montage editor) intercepts the close attempt instead of discarding unsaved work.
-
reviewed9. Dismiss overlay on ESC or click-outside SRS-009 The software shall dismiss the active navigation overlay when the operator either presses the ESC key or clicks outside the overlay's content area.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed10. At most one overlay open at a time SRS-010 The software shall display at most one navigation overlay at a time; opening an overlay shall replace any overlay that is currently open.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
Construct a ProviderContainer and exercise the overlay navigation subsystem through its view-models without a running UI. (a) From the initial state, call selectItem(0) on the navigation notifier and inspect the navigation and overlay state. (b) With overlay 0 open, call selectItem(1) and inspect the state. (c) With an overlay open and the bottom bar in menu mode, call clearSelection() and inspect the navigation, overlay, and bottom-bar state.
-
reviewed9. Bottom-bar mode controller ARCH-009 The bottom-bar mode controller owns the bottom bar's signal/menu mode. The mode is modelled as a domain value object (BottomBarMode) carrying the two modes and the pure toggle and per-mode content definitions; an application view-model (BottomBarNotifier) holds the current mode — signal mode at launch — and switches it via toggleMode(). The bottom bar widget (BottomBar) watches the mode provider and renders the controls for the current mode: the signal-parameter controls (high-pass, low-pass and notch filters, sensitivity, timebase, and montage) in signal mode, and the Patients/Montages/Settings/Activities navigation buttons in menu mode. A single toggle control invokes toggleMode() when the operator activates it; switching to menu mode opens the corresponding navigation overlay (the last-opened one, or Patients by default) and switching back to signal mode closes it. Dismissing the open overlay — by Escape, a click outside it, or re-selecting the active navigation item — clears the navigation selection, which resets the controller to signal mode.
-
reviewed8. Bottom-bar signal and menu mode toggle SRS-008 The software shall provide a bottom bar that switches between a signal-control mode and a menu mode when the operator activates the bottom-bar mode toggle.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed11. Signal-mode bottom-bar controls SRS-011 In signal mode, the bottom bar shall present the signal-parameter controls: a high-pass filter, a low-pass filter, a notch filter, a sensitivity control, a timebase control, and a montage selector.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed12. Menu-mode bottom-bar navigation buttons SRS-012 In menu mode, the bottom bar shall present the navigation buttons: Patients, Montages, Settings, and Activities.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
reviewed15. Bottom bar default and resting mode SRS-015 The bottom bar shall be in signal mode when the application launches, and shall return to signal mode whenever the open navigation overlay is dismissed.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
Pump the BottomBar in a flutter_test widget test with the bottom-bar mode provider in its default state. Inspect the rendered controls in signal mode. Activate the mode toggle to switch to menu mode. Inspect the rendered controls again.
-
reviewed11. Theme subsystem ARCH-011 The theme subsystem owns the application's visual theming. The available themes are modelled as a domain value object (ThemeType: minimalLight, minimal, and darkGlass — surfaced to the operator as Light, Dark, and Dark Glass). AppTheme.forPreset builds the Flutter ThemeData for a given type, and application providers expose the active selection: the UISettingsNotifier holds the selected ThemeType, currentThemeTypeProvider reads it, and the theme-data and theme-mode providers derive the rendered theme from it, so the whole application re-themes when the selection changes.
-
reviewed17. Selectable application themes SRS-017 The software shall provide three selectable visual themes — Light, Dark, and Dark Glass — and shall apply the operator's selected theme across the application.
-
reviewed5. Operator workstation for recording sessions SYS-005 The device shall present the operator a workstation interface for conducting EEG recording sessions in which the live EEG signal display remains continuously visible while the operator accesses recording controls and overlay menus.
-
-
Construct a ProviderContainer overriding the current-theme-type selection to each of the three theme types in turn, and read the theme-mode and theme-data providers for each.