Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ Requirements for initial release. Each maps to roadmap phases.

### Multi-Device Sync

- [ ] **SYNC-01**: Changes sync across devices via IPNS polling (~30s interval)
- [x] **SYNC-01**: Changes sync across devices via IPNS polling (~30s interval)
- [ ] **SYNC-02**: Desktop app runs background sync daemon
- [ ] **SYNC-03**: User sees loading state during IPNS resolution
- [x] **SYNC-03**: User sees loading state during IPNS resolution

### TEE Republishing

Expand Down Expand Up @@ -194,9 +194,9 @@ Which phases cover which requirements. Updated during roadmap creation.
| API-06 | Phase 4 | Complete |
| API-07 | Phase 4 | Complete |
| API-08 | Phase 8 | Pending |
| SYNC-01 | Phase 7 | Pending |
| SYNC-02 | Phase 7 | Pending |
| SYNC-03 | Phase 7 | Pending |
| SYNC-01 | Phase 7 | Complete |
| SYNC-02 | Phase 9 | Pending |
| SYNC-03 | Phase 7 | Complete |
| TEE-01 | Phase 8 | Pending |
| TEE-02 | Phase 8 | Pending |
| TEE-03 | Phase 8 | Pending |
Expand Down
18 changes: 10 additions & 8 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,14 +277,14 @@ Plans:

1. Changes made on one device appear on another within ~30 seconds
2. User sees loading state during IPNS resolution
3. Desktop sync daemon runs in background while app is open
**Plans**: 3 plans
**Plans**: 4 plans

Plans:

- [ ] 07-01-PLAN.md — Backend IPNS resolution endpoint and sync state store
- [ ] 07-02-PLAN.md — Polling infrastructure hooks (useInterval, useVisibility, useOnlineStatus, useSyncPolling)
- [ ] 07-03-PLAN.md — Frontend integration with SyncIndicator and OfflineBanner UI
- [x] 07-01-PLAN.md — Backend IPNS resolution endpoint and sync state store
- [x] 07-02-PLAN.md — Polling infrastructure hooks (useInterval, useVisibility, useOnlineStatus, useSyncPolling)
- [x] 07-03-PLAN.md — Frontend integration with SyncIndicator and OfflineBanner UI
- [x] 07-04-PLAN.md — Gap closure: full metadata refresh with decryption on sync

### Phase 8: TEE Integration

Expand Down Expand Up @@ -388,8 +388,8 @@ Decimal phases (if any) execute between their surrounding integers.
| 6. File Browser UI | 4/4 | Complete | 2026-01-22 |
| 6.1 Webapp Automation | 7/7 | Complete | 2026-01-22 |
| 6.2 Restyle App | 6/6 | Complete | 2026-01-27 |
| 6.3 UI Structure | 0/5 | Not started | - |
| 7. Multi-Device Sync | 0/3 | Not started | - |
| 6.3 UI Structure | 5/5 | Complete | 2026-01-30 |
| 7. Multi-Device Sync | 4/4 | Complete | 2026-02-02 |
| 8. TEE Integration | 0/4 | Not started | - |
| 9. Desktop Client | 0/5 | Not started | - |
| 10. Data Portability | 0/3 | Not started | - |
Expand Down Expand Up @@ -419,4 +419,6 @@ _Phase 7 planned: 2026-01-22_
_Phase 6.3 inserted: 2026-01-25_
_Phase 6.2 complete: 2026-01-27_
_Phase 6.3 planned: 2026-01-30_
_Total phases: 13 | Total plans: 65 | Depth: Comprehensive_
_Phase 6.3 complete: 2026-01-30_
_Phase 7 complete: 2026-02-02_
_Total phases: 13 | Total plans: 66 | Depth: Comprehensive_
41 changes: 27 additions & 14 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@
See: .planning/PROJECT.md (updated 2026-01-20)

**Core value:** Zero-knowledge privacy - files encrypted client-side, server never sees plaintext
**Current focus:** Phase 6.3 - UI Structure Refactor (inserted)
**Current focus:** Phase 8 - TEE Integration (next)

## Current Position

Phase: 6.3 of 11 (UI Structure Refactor)
Plan: 5 of 5 in Phase 6.3 complete
Status: Phase complete - UI restructure verified and approved
Last activity: 2026-01-30 - Completed 06.3-05-PLAN.md
Phase: 7 of 11 complete (Multi-Device Sync)
Plan: All 4 plans in Phase 7 complete
Status: Phase complete - verified
Last activity: 2026-02-02 - Phase 7 execution complete

Progress: [########..] 83% (39 of 47 plans)
Progress: [########..] 91% (44 of 48 plans)

## Performance Metrics

**Velocity:**

- Total plans completed: 39
- Average duration: 4.9 min
- Total execution time: 3.17 hours
- Total plans completed: 44
- Average duration: 4.8 min
- Total execution time: 3.64 hours

**By Phase:**

Expand All @@ -38,10 +38,11 @@ Progress: [########..] 83% (39 of 47 plans)
| 06-file-browser-ui | 4/4 | 19 min | 4.8 min |
| 06.1-webapp-automation | 6/6 | 25 min | 4.2 min |
| 06.3-ui-structure-refactor | 5/5 | 16 min | 3.2 min |
| 07-multi-device-sync | 4/4 | 17 min | 4.3 min |

**Recent Trend:**

- Last 5 plans: 2m, 3m, 4m, 6m, 3m
- Last 5 plans: 6m, 3m, 3m, 4m, 7m
- Trend: Consistent, stable

Updated after each plan completion.
Expand Down Expand Up @@ -168,6 +169,18 @@ Recent decisions affecting current work:
| AppShell overlay sidebar pattern | 06.3-04 | Fixed position with translateX for mobile slide-in animation |
| Visual verification via Playwright MCP | 06.3-05 | All must_haves verified programmatically before approval |
| [..] row absent in empty folders accepted | 06.3-05 | Minor UX issue - users can navigate via breadcrumbs or browser back |
| Pause polling when tab backgrounded | 07-02 | Battery optimization per RESEARCH.md, set delay to null when hidden |
| Immediate sync on focus regain | 07-02 | Per RESEARCH.md recommendation, poll immediately when user returns |
| Immediate sync on reconnect | 07-02 | Per CONTEXT.md auto-sync when connection returns |
| useRef for callback tracking | 07-02 | Prevents stale callback closure issue in setInterval |
| SSR guards on visibility/online hooks | 07-02 | typeof document/navigator checks prevent SSR errors |
| resolveIpnsRecord uses generated API client | 07-03 | Type-safe IPNS resolution via backend, null for 404/not found |
| SyncIndicator in toolbar actions area | 07-03 | Compact 16px icons next to upload, matches terminal aesthetic |
| Offline banner terminal colors | 07-03 | Amber on dark (#3d2e0a bg, #fcd34d text) for offline state |
| Full metadata refresh deferred | 07-03 | Sync detection complete; refresh requires decryption logic extraction |
| Sequence number comparison for sync | 07-04 | Used sequenceNumber instead of CID - local CID not cached, seq always inc |
| useFolderStore.getState() in async callback | 07-04 | Avoid stale closure issues when accessing store from async handleSync |
| Silent sync error handling | 07-04 | Log errors but don't crash - 30s interval auto-retries |

### Pending Todos

Expand Down Expand Up @@ -209,12 +222,12 @@ Recent decisions affecting current work:

## Session Continuity

Last session: 2026-01-30
Stopped at: Completed 06.3-05-PLAN.md - Phase 6.3 complete (visual verification passed)
Last session: 2026-02-02
Stopped at: Phase 7 complete - all 4 plans executed, verified ✓
Resume file: None
Next plan: Phase 7 (TEE Integration) or next priority phase
Next plan: Phase 8 (TEE Integration)

---

_State initialized: 2026-01-20_
_Last updated: 2026-01-30 after 06.3-05 completion (Phase 6.3 complete)_
_Last updated: 2026-02-02 after 07-04 completion (gap closure - multi-device sync working)_
117 changes: 117 additions & 0 deletions .planning/phases/07-multi-device-sync/07-01-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
phase: 07-multi-device-sync
plan: 01
subsystem: api, ui
tags: [ipns, zustand, sync, delegated-routing]

# Dependency graph
requires:
- phase: 05-folder-system
provides: IPNS publish endpoint and folder tracking
provides:
- GET /ipns/resolve endpoint for IPNS name resolution
- ResolveIpnsQueryDto and ResolveIpnsResponseDto
- useSyncStore for sync state management
affects: [07-02 (polling hook), 07-03 (sync indicator)]

# Tech tracking
tech-stack:
added: []
patterns:
- Delegated routing GET for IPNS resolution
- Zustand sync state pattern (status/lastSyncTime/syncError/isOnline)

key-files:
created:
- apps/api/src/ipns/dto/resolve.dto.ts
- apps/web/src/stores/sync.store.ts
- apps/web/src/api/models/resolveIpnsResponseDto.ts
- apps/web/src/api/models/ipnsControllerResolveRecordParams.ts
modified:
- apps/api/src/ipns/ipns.service.ts
- apps/api/src/ipns/ipns.controller.ts
- apps/api/src/ipns/dto/index.ts
- apps/web/src/api/ipns/ipns.ts
- packages/api-client/openapi.json

key-decisions:
- 'IPNS record parsing extracts CID from /ipfs/ path pattern'
- "Sequence number defaults to '0' - backend tracks its own sequence"
- '30 resolves per minute rate limit (higher than publish since read-only)'
- 'SyncStatus uses string literal type not enum'

patterns-established:
- 'Delegated routing resolution with retry/backoff'
- 'Zustand ephemeral state store (no persistence)'

# Metrics
duration: 3min
completed: 2026-02-02
---

# Phase 7 Plan 01: Sync Infrastructure Summary

GET /ipns/resolve endpoint with delegated routing and Zustand sync state store

## Performance

- **Duration:** 3 min
- **Started:** 2026-02-02T02:36:29Z
- **Completed:** 2026-02-02T02:39:37Z
- **Tasks:** 2
- **Files modified:** 9

## Accomplishments

- Backend IPNS resolution endpoint via delegated-ipfs.dev with retry/backoff
- DTO validation for IPNS name format (k51... or bafzaa...)
- Sync state store tracking status, lastSyncTime, syncError, isOnline
- Regenerated API client with new resolve endpoint

## Task Commits

Each task was committed atomically:

1. **Task 1: Backend IPNS resolution endpoint** - `67261b4` (feat)
2. **Task 2: Create sync state store** - `f87a505` (feat)

**Plan metadata:** Pending

## Files Created/Modified

- `apps/api/src/ipns/dto/resolve.dto.ts` - ResolveIpnsQueryDto and ResolveIpnsResponseDto
- `apps/api/src/ipns/ipns.service.ts` - Added resolveRecord method with retry logic
- `apps/api/src/ipns/ipns.controller.ts` - Added GET /ipns/resolve endpoint
- `apps/web/src/stores/sync.store.ts` - Zustand store for sync state
- `apps/web/src/api/ipns/ipns.ts` - Regenerated with resolve endpoint
- `packages/api-client/openapi.json` - Updated OpenAPI spec

## Decisions Made

1. **IPNS record parsing strategy** - Extract CID from /ipfs/ path pattern in record bytes rather than full CBOR/protobuf parsing. Simpler and sufficient for our needs.
2. **Sequence number handling** - Default to "0" since backend tracks its own sequence numbers. Full CBOR parsing deferred.
3. **Rate limiting** - 30 resolves/minute vs 10 publishes/minute since resolution is read-only.
4. **SyncStatus type** - String literal union type per CLAUDE.md (no enums).

## Deviations from Plan

None - plan executed exactly as written.

## Issues Encountered

None

## User Setup Required

None - no external service configuration required.

## Next Phase Readiness

- IPNS resolution endpoint ready for polling hook (07-02)
- Sync store ready for UI integration (07-03)
- No blockers for next plan

---

_Phase: 07-multi-device-sync_
_Completed: 2026-02-02_
116 changes: 116 additions & 0 deletions .planning/phases/07-multi-device-sync/07-02-SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
phase: 07-multi-device-sync
plan: 02
subsystem: ui
tags: [react, hooks, polling, visibility, network, zustand]

# Dependency graph
requires:
- phase: 07-01
provides: sync state store (useSyncStore)
provides:
- useInterval hook with proper cleanup
- useVisibility hook for Page Visibility API
- useOnlineStatus hook for network detection
- useSyncPolling orchestrator hook
affects: [07-03, ui-components, sync-indicator]

# Tech tracking
tech-stack:
added: []
patterns: [useRef for stale callback prevention, Page Visibility API, navigator.onLine]

key-files:
created:
- apps/web/src/hooks/useInterval.ts
- apps/web/src/hooks/useVisibility.ts
- apps/web/src/hooks/useOnlineStatus.ts
- apps/web/src/hooks/useSyncPolling.ts
modified:
- apps/web/src/hooks/index.ts

key-decisions:
- 'Pause polling when tab backgrounded (battery optimization per RESEARCH.md)'
- 'Immediate sync on visibility regain (per RESEARCH.md recommendation)'
- 'Immediate sync on reconnect (per CONTEXT.md)'
- 'useRef for callback tracking to avoid stale closure issue'

patterns-established:
- 'useInterval: pass null delay to pause, cleanup on unmount'
- 'Edge detection via useRef tracking previous state values'
- "SSR guards: typeof document/navigator !== 'undefined'"

# Metrics
duration: 3min
completed: 2026-02-02
---

# Phase 7 Plan 02: Polling Infrastructure Hooks Summary

Custom React hooks for interval polling, tab visibility, network status, and sync orchestration with proper cleanup and SSR safety.

## Performance

- **Duration:** 3 min
- **Started:** 2026-02-02T02:36:34Z
- **Completed:** 2026-02-02T02:39:43Z
- **Tasks:** 2
- **Files created:** 4
- **Files modified:** 1

## Accomplishments

- Created useInterval hook with ref-based callback and null-delay pause mechanism
- Created useVisibility hook wrapping Page Visibility API with SSR guard
- Created useOnlineStatus hook with online/offline event listeners and SSR guard
- Created useSyncPolling orchestrator that polls every 30s when visible+online, pauses otherwise
- Implemented immediate sync on visibility regain and network reconnect

## Task Commits

Each task was committed atomically:

1. **Task 1: Create utility hooks** - `f890d9f` (feat)
2. **Task 2: Create useSyncPolling orchestrator hook** - `e6b175f` (feat)

## Files Created/Modified

- `apps/web/src/hooks/useInterval.ts` - Reusable interval hook with cleanup, null pauses
- `apps/web/src/hooks/useVisibility.ts` - Page Visibility API wrapper
- `apps/web/src/hooks/useOnlineStatus.ts` - Network status detection via navigator.onLine
- `apps/web/src/hooks/useSyncPolling.ts` - Main sync polling orchestrator combining all hooks
- `apps/web/src/hooks/index.ts` - Added exports for all new hooks

## Decisions Made

1. **Pause polling when backgrounded** - Per RESEARCH.md recommendation, saves battery by setting delay to null when tab is hidden
2. **Immediate sync on focus regain** - Per RESEARCH.md, poll immediately when user returns to tab for fresh data
3. **Immediate sync on reconnect** - Per CONTEXT.md, auto-sync when connection returns
4. **useRef for callback tracking** - Prevents stale callback closure issue documented in RESEARCH.md pitfalls
5. **SSR guards on all hooks** - typeof checks prevent errors during server-side rendering

## Deviations from Plan

None - plan executed exactly as written.

Note: The sync store (useSyncStore) was already created by plan 07-01 which was executed prior to this plan. No additional deviations were needed.

## Issues Encountered

None - all hooks compiled and linted successfully on first attempt.

## User Setup Required

None - no external service configuration required.

## Next Phase Readiness

- Polling infrastructure complete and ready for sync service integration
- useSyncPolling hook takes an onSync callback that will be implemented in Plan 03 (sync service)
- All four hooks are exported from the hooks barrel file
- Ready for SyncIndicator component to consume sync state

---

_Phase: 07-multi-device-sync_
_Completed: 2026-02-02_
Loading
Loading