Client Sync & Steps Islands
The UI is Astro pages hydrating React islands (src/islands). Islands read/write through the offline layer (Dexie cache + outbox) rather than calling the API directly, so the same optimistic, offline-first path backs every interaction.
The diagram below shows how the islands wire into the offline layer and the live/poll transports that refresh the cache.
flowchart LR
Ctx["WorkspaceContext.tsx<br/>(shared state)"]
Islands["islands<br/>(StepsRegion, TaskDetailPanel, ...)"]
Status["SyncStatus.tsx"]
Sync["sync.ts<br/>(offline mutation API)"]
Core["sync-core.ts<br/>(reconcilers)"]
Dexie[("Dexie cache<br/>+ outbox")]
Live["live.ts<br/>(WS client)"]
Poll["poll.ts<br/>(poll controller)"]
Worker{{"Worker API"}}
Ctx --> Islands
Islands -->|mutate| Sync
Sync -->|optimistic write + queue| Dexie
Islands -->|liveQuery| Dexie
Sync -->|replayOutbox| Worker
Live --> Core
Poll --> Core
Core --> Dexie
Live --> Status
Poll --> Status
Workspace + sync wiring
Section titled “Workspace + sync wiring”WorkspaceContext.tsxprovides shared client state (current selection/scope, cached data) to islands.- Islands mutate via the offline mutation API (
src/lib/offline/sync.ts) and observe reconciled data from the Dexie cache; the live/poll transports refresh that cache (see LiveConnection WS Client, Poll Controller, Sync-Core Reconcilers).SyncStatus.tsxsurfaces transport state.
Steps region
Section titled “Steps region”StepsRegion.tsxrenders a Task’s Steps as a flat checklist (withinTaskDetailPanel.tsx): add at bottom, toggle done, rename, reorder by drag (fractional rank, per-Task scope). It reflects the Step domain rules — no nesting, title + done only (Product Brief §5.2; see Steps in a Task).- Step edits are optimistic and queued like any other mutation; reconciliation uses
reconcileSteps/reconcileAllSteps.
The sequence below traces a Step toggle from StepsRegion.tsx through the optimistic write to outbox replay and reconciliation.
sequenceDiagram participant User participant Steps as StepsRegion.tsx participant Sync as sync.ts participant Dexie as Dexie cache + outbox participant Worker as Worker API User->>Steps: toggle Step done Steps->>Sync: toggleStep(stepId, done) Sync->>Dexie: optimistic write + queue op Dexie-->>Steps: liveQuery emits (UI updates) Sync->>Worker: replayOutbox() Worker-->>Dexie: reconcileSteps / reconcileAllSteps
Related: Steps in a Task (server side), Offline Outbox & Optimistic Writes, Sync-Core Reconcilers.