Phase 6 (final storage phase).
- SidecarRepositoryRegistry tracks every open repo; SidecarFlushObserver
(a WidgetsBindingObserver in main) flushes them all on
inactive/hidden/paused/detached, awaiting each flush — the last
strokes can't be lost on app close, not just on the 800ms timer.
- VaultSearchIndex rebuilds by scanning vault sidecars (the source of
truth) — note titles, OCR text and document names — and search_provider
queries it, so search spans notes + PDFs. Rebuilt on launch / after
import.
The vault file-based storage migration (Phases 0-6) is complete:
annotations travel with the file, picked vault folder, atomic autosave,
one Import-file entry, SQLite migrated to sidecars. analyze clean,
tests green.
Phase 4. Standalone notes move off SQLite into the vault, like the
PDF annotations.
- "Create notebook" makes a vault folder with a notebook.badnote.json
(BadnoteSidecar docType 'notebook' + a title field), opened via
SidecarRepository.
- PenNoteScreen loads/saves its strokes (page 0) + title to that
sidecar instead of the SQLite Note model.
- note_provider lists notes from a vault scan (VaultService.scanNotes
= folders with notebook.badnote.json and no source file); the doc
scan still excludes them. Delete removes the folder.
PDF/slide editors unchanged; pre-existing SQLite notes migrate in
Phase 5. analyze clean, tests green.
Phase 3. Import becomes a single top-level action beside "Create
notebook" and the library is vault-backed.
- VaultService.createNotebook copies a picked file into a fresh
(de-duplicated) notebook folder under the vault; its sidecar lives
beside it, so annotations travel with the file.
- Home screen: one "Import file" action with a multi-extension picker
(pdf / docx / pptx); routes to the editor by extension.
- The document list is now a vault scan (folders with a source file),
not the SQLite documents table — no cache, always correct.
- PPTX soffice detection fix; DOCX convert-on-import is best-effort
and fails gracefully when LibreOffice is unavailable.
analyze clean, tests green.
Bug fixes (Flutter):
- Wrap multi-statement DB writes (insert/update/delete note, deleteDocument,
deletePageData, OCR FTS merge, migrations) in transactions to prevent data
loss on interruption and a read-modify-write FTS race.
- Fix PdfDocument leaks on exception (try/finally dispose) and preserve image
aspect ratio when stamping images onto PDF pages.
- Guard file-picker against empty selection (was .single -> crash).
- Fix eraser ConcurrentModificationError and unmodifiable-list crash on PDF
pages; capture page synchronously on save to stop wrong-page data loss.
- Fix Riverpod DB-not-ready races, broken pull-to-refresh, settings load race,
and search N+1; transform stored annotations on PDF page rotation.
- Normalize pen pressure for devices without a pressure range.
- PPT: single source of truth for slide strokes so ink displays and exports.
UI/UX:
- Material 3 typography, theme-aware colors (dark-mode fixes), hover cursors
and right-click/visible actions on desktop, keyboard shortcuts (undo/redo/
save/find), toolbar overflow handling, friendlier empty states, semantic OCR
status badges, relative timestamps, 1-based page indicators, large-deck PPT
navigation, and a scratchpad-scope label in split view.
Server (optional backend):
- Persist JWT secret (was per-process random), block path traversal in storage,
fix CORS '*'+credentials, add OCR job ownership checks, last-writer-wins sync
guard, constant-time login, and split out heavy OCR deps so the API/tests run
without them.
CI: Gitea workflows for format+analyze+test (Linux, system sqlite) and a
Windows release build; pristine `flutter analyze`, all Flutter and server tests
green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>