feat: add durable provider cache
Add a private provider-neutral SQLite WAL cache with transactional migrations, retained raw payloads and tombstones, per-window opaque checkpoints, and reserved outbox/conflict tables. Verify migrations, permissions, identity invariants, concurrent access, atomic pull-page rollback, and future-schema rejection with deterministic tests. No OAuth, networking, secrets, or Graph synchronization is included yet.
This commit is contained in:
@@ -6,7 +6,7 @@ and terminal rendering replaceable.
|
||||
```text
|
||||
src/main.cpp
|
||||
├── tui/ ANSI rendering, input decoding, terminal lifecycle
|
||||
├── storage/ iCalendar file adapter (later: SQLite cache)
|
||||
├── storage/ iCalendar file adapter and provider-neutral cache
|
||||
└── domain/ Event, Calendar, civil dates, month layout and queries
|
||||
|
||||
future sync workers
|
||||
@@ -118,13 +118,27 @@ semantically. Browsing remains available for unsupported files. This
|
||||
conservative boundary is more important than partial editing because a
|
||||
successful-looking edit must not erase unrelated calendar data.
|
||||
|
||||
Provider synchronization will not write directly into this UI file. It will use
|
||||
a transaction-capable local cache and preserve remote ETags/sync tokens in a
|
||||
provider metadata table.
|
||||
Provider synchronization does not write directly into this UI file. Its
|
||||
prerequisite durable boundary is a provider-neutral SQLite database in WAL mode.
|
||||
The database is a private local file, and schema changes run as versioned,
|
||||
all-or-nothing migrations so a failed upgrade cannot leave a partially migrated
|
||||
cache.
|
||||
|
||||
The planned cache schema has `calendars`, `events`, `event_instances`, and
|
||||
`sync_state`. Raw provider payloads are retained alongside normalized fields so
|
||||
an older Nocal cannot destroy fields it does not understand.
|
||||
The cache separates provider records from normalized projections. It retains
|
||||
raw provider payloads alongside normalized fields so an older Nocal cannot
|
||||
destroy fields it does not understand. Inactive calendars and tombstoned events
|
||||
remain recorded rather than disappearing from history. Normalized event
|
||||
instances are materialized for immutable UI snapshots; provider payload details
|
||||
do not cross into rendering or the domain model.
|
||||
|
||||
Incremental progress is scoped by provider account, calendar, and synchronization
|
||||
window. A provider's opaque cursor is committed in the same transaction as each
|
||||
pulled page, preventing a crash from advancing the cursor beyond durable data.
|
||||
Transactional outbox and conflict records are reserved in the boundary for
|
||||
future local writes and deterministic conflict handling. This cache does not
|
||||
itself implement networking, authentication, or Microsoft Graph synchronization.
|
||||
OAuth tokens and other secrets are explicitly excluded from SQLite and belong
|
||||
in the Freedesktop Secret Service.
|
||||
|
||||
## Terminal backend
|
||||
|
||||
@@ -149,3 +163,10 @@ Service, never in the calendar database or command line.
|
||||
Conflict resolution is deterministic: unchanged side wins; otherwise retain
|
||||
both versions and mark a conflict for the user. Network work happens outside the
|
||||
render loop and publishes immutable snapshots to it.
|
||||
|
||||
The first provider-facing step after the cache is verified is an injectable HTTP
|
||||
boundary, browser-based authorization-code flow with PKCE, and fake transports
|
||||
for deterministic authentication and failure tests. Read-only Microsoft Graph
|
||||
calendar discovery and delta synchronization follows. Graph delta links remain
|
||||
opaque and are persisted only through the calendar/window transaction described
|
||||
above; remote writes and conflict resolution come later.
|
||||
|
||||
Reference in New Issue
Block a user