Files
nocal/docs/ROADMAP.md
Bernardo Magri 74c798e7aa feat(sync): add Microsoft account connect CLI
nocal account connect microsoft runs the PKCE browser flow, reads /me,
upserts the deterministic account row, and persists tokens to Secret
Service as the final connected-state gate. Account IDs are hashed from
the remote subject so reconnect is idempotent, and a secret-store
failure leaves the same coherent state as a disconnect. Ships a
placeholder client ID with NOCAL_MICROSOFT_CLIENT_ID override until a
real Entra registration exists.
2026-07-21 18:44:47 +01:00

158 lines
7.3 KiB
Markdown

# Roadmap
## Foundation — current milestone
- C++20 domain model and deterministic six-week month layout
- Responsive, theme-native ANSI month view with keyboard navigation
- Appointment focus, dense-day traversal, and full-frame detail reader
- Validated add/edit/delete forms with confirmation and failure rollback
- Guarded atomic `.ics` persistence, advisory locking, and round-trip tests
- Bounded session undo/redo, exact external-change detection, and backup recovery
- Windowed recurrence expansion, compatible RDATE, EXDATE, IANA TZID, and
multi-day segment cues
- Occurrence-aware appointment search with exact result-to-grid navigation
- Session calendar toggles shared by month rendering, focus, and search
- Read-only 42-day agenda with bounded recurrence and exact return navigation
- Configurable week start with Monday-default CLI and consistent grid queries
- Explicit atomic import/export with validation, collision refusal, and backups
- Meson build, Nix development shell, desktop entry, and Hyprland launcher
- Seeded sample data when explicitly requested, never silent data mutation
## 0.1 — complete local calendar
- Advanced recurrence rule editing and detached RECURRENCE-ID overrides
- Embedded VTIMEZONE support
- Screen-reader-friendly linear view and full Unicode display-width handling
## 0.2 — durable cache and provider boundary — in progress
Completed cache foundation:
- Provider-neutral SQLite WAL cache in a private local file
- Versioned, all-or-nothing schema migrations
- Raw provider payload retention, inactive calendars, and event tombstones
- Per-calendar/window opaque cursors committed atomically with pulled pages
- Normalized event instances for immutable snapshots
- Reserved transactional outbox and conflict records for later remote writes
Completed HTTP/OAuth boundary:
- Generic injected HTTP transport and deterministic fakes, with retries left to
provider operations
- Public-desktop OAuth authorization code design with PKCE `S256`, system
browser, and loopback redirect
- Multitenant Microsoft account audience and delegated least-privilege
`Calendars.Read`; tenant policy may still require administrator consent or
block user consent
- No client secret in the open-source desktop binary
Completed concrete Linux adapters:
- libcurl transport with verified TLS, bounded responses/timeouts, no automatic
redirects/retries, and cleartext HTTP only for loopback tests
- Shell-free `xdg-open` launcher and one-shot `127.0.0.1` callback receiver
advertising `http://localhost:<dynamic-port>/nocal/oauth/callback`
- Mobile/Desktop public-client registration at
`http://localhost/nocal/oauth/callback`; Microsoft ignores localhost ports,
while literal HTTP `127.0.0.1` needs a manifest edit and IPv6 loopback is not
supported
Completed token/secret boundary:
- Strict, bounded token JSON parsing with a required initial refresh token
- Refresh-token rotation with retention of the previous token when a refresh
response omits a replacement
- Versioned libsecret payloads keyed by opaque local account IDs
- Synchronous, cancellable Secret Service calls restricted to worker threads
- Real isolated D-Bus/gnome-keyring integration tests
- Explicit missing, locked, cancelled, and failure results; no connected account
until the complete secret store succeeds
- OAuth secrets only in Secret Service, never SQLite, logs, CLI arguments, or
environment variables
Completed Microsoft Graph read phase:
- Public desktop multitenant organizational/personal account support
- Delegated `User.Read` for `/me` and `Calendars.Read` for calendars/events;
tenant policy may still require approval or block user consent
- Per-operation access tokens with persistent tokens retained only by Secret
Service
- Complete paged all-calendar discovery with atomic cache replacement and
deterministic local IDs
- Immutable Graph event IDs, strict bounded parsing, and credential-safe errors
- HTTPS `graph.microsoft.com`-only opaque continuation/delta links
- Half-open UTC event windows and per-page event/tombstone/cursor transactions
- Resumable primary-calendar v1 delta synchronization
Completed secondary-calendar stable-v1 reconciliation:
- Documented per-calendar `calendarView` reads with complete bounded paging
- Schema-v2 durable per-window event membership
- Atomic complete-window replacement after every page validates
- Range omission distinguished from a remote deletion tombstone
- Overlapping windows retain events until their last membership is removed
- No beta or undocumented per-calendar delta dependency
Completed provider-boundary contracts and token broker:
- Generic `SyncProvider`/`SyncObserver` contracts for account connect, sync,
and disconnect with staged progress events
- `OAuthTokenBroker` returning valid per-operation access tokens with a
five-minute refresh skew
- Refresh rotation persisted before use so a new refresh token is never lost;
transient refresh failures leave stored credentials untouched
- 400/401 refresh rejections erase the stored secret and surface
`AccountDisconnected` for re-authentication
- Credential material never appears in exception messages
Completed account setup (CLI):
- `nocal account connect microsoft` runs the PKCE browser flow, reads `/me`,
upserts the deterministic account row, and persists tokens to Secret
Service as the final connected-state gate
- Deterministic local account IDs hashed from the remote subject make
reconnect idempotent; a secret-store failure leaves the same coherent state
as a disconnect
- Placeholder client ID with `NOCAL_MICROSOFT_CLIENT_ID` override until a
real Entra mobile/desktop registration exists
- Deterministic failure-path tests: rejection, token errors, identity
failure, storage failure, and credential redaction in error messages
Next provider-boundary slices:
- TUI account orchestration and generic `SyncProvider` integration with
observable sync status
## 0.3 — CalDAV
- Discovery and incremental sync for Nextcloud and standards-compliant servers
- ETag-aware writes, offline mutation queue, conflict UI
- TLS and failure-path integration tests
## 0.4 — hosted providers
- Google Calendar adapter with incremental synchronization
- Microsoft 365 read-only discovery and Graph delta synchronization, followed by
ETag-aware remote writes after the conflict boundary is proven
- Account/calendar management UI and per-calendar ANSI identity
The Graph read boundary uses stable v1 delta for the primary calendar and
complete stable-v1 calendar views for secondary calendars; it deliberately
avoids beta and undocumented per-calendar delta routes. Account connect exists
as a CLI command with live credential integration through Secret Service, but
there is no account TUI or sync orchestration yet, and remote writes remain
out of scope.
## 1.0 — distribution quality
- Stable configuration/data format and documented recovery procedures
- Nomarchy package, Hyprland defaults, man page, shell completions
- Performance budgets exercised against large and adversarial calendars
- Fuzzed iCalendar parser, accessibility review, translations
## Quality gates
Every milestone requires clean warning-enabled builds, unit and integration
tests, sanitizer runs, terminal-state recovery after signals/errors, no network
access without explicit account setup, and no loss of unknown calendar data.