rspace-online/backlog/tasks/task-77 - EncryptID-Optiona...

4.4 KiB

id title status assignee created_date updated_date labels dependencies references documentation priority
TASK-77 EncryptID: Optional encrypted VPS backup for client-side data Done
2026-03-02 20:19 2026-03-03 03:31
encryptid
privacy
feature
server/local-first/encryption-utils.ts
server/local-first/backup-store.ts
server/local-first/backup-routes.ts
shared/local-first/backup.ts
server/local-first/doc-persistence.ts
server/local-first/sync-server.ts
server/sync-instance.ts
shared/local-first/sync.ts
shared/local-first/encryptid-bridge.ts
docs/DATA-ARCHITECTURE.md
docs/DATA-ARCHITECTURE.md
medium

Description

Add an EncryptID settings option for users to backup their encrypted client-side data (wallet associations, etc.) to a VPS. Default is client-side only (maximum privacy). Optional backup enables device-loss recovery and cross-device sync.

Architecture:

  • Client-side encrypted localStorage is the default (current wallet-store.ts pattern)
  • Settings toggle: "Backup encrypted data to server"
  • When enabled, encrypted blobs (already AES-256-GCM) are synced to the EncryptID server or a user-specified VPS
  • Server stores opaque ciphertext — same zero-knowledge pattern as encrypted_addresses
  • On new device login, user can restore from backup after passkey authentication

Consider extending this to all client-side data (wallet associations, preferences) and potentially migrating encrypted_addresses to the same pattern (client-first, optional server backup).

Acceptance Criteria

  • #1 Settings UI toggle for encrypted backup (default: off)
  • #2 Encrypted blobs sync to EncryptID server when enabled
  • #3 Restore flow on new device after passkey auth
  • #4 Server never sees plaintext — only stores opaque ciphertext + IV
  • #5 User can optionally specify a custom VPS endpoint for backup

Implementation Notes

2026-03-03: Implemented full 4-layer architecture. AC #5 (custom VPS) deferred to future Layer 3 federated replication phase. Commit 46c2a0b on dev, merged to main, deployed to Netcup.

Final Summary

Layered Local-First Data Architecture — Complete Implementation

What was done

Implemented the full 4-layer data architecture (device → encrypted backup → shared sync → federated):

New files (5):

  • server/local-first/encryption-utils.ts — Shared AES-256-GCM primitives (deriveSpaceKey, encrypt/decrypt, rSEN pack/unpack)
  • server/local-first/backup-store.ts — Filesystem opaque blob storage with manifest tracking
  • server/local-first/backup-routes.ts — Hono REST API (PUT/GET/DELETE /api/backup/:space/:docId) with JWT auth
  • shared/local-first/backup.ts — BackupSyncManager with delta-only push, full restore, auto-backup
  • docs/DATA-ARCHITECTURE.md — 4-layer architecture design doc with threat model and data flow diagrams

Modified files (10):

  • server/community-store.ts — Replaced inline encryption with shared encryption-utils
  • server/local-first/doc-persistence.ts — Added encryptionKeyId param, rSEN detection in loadAllDocs, saveEncryptedBlob/loadEncryptedBlob for relay blobs
  • server/local-first/sync-server.ts — Added relay-backup/relay-restore wire messages, onRelayBackup/onRelayLoad callbacks
  • server/sync-instance.ts — Added encryption key lookup + relay backup/load wiring
  • shared/local-first/sync.ts — Added RelayBackupMessage/RelayRestoreMessage types, sendRelayBackup(), handleRelayRestore()
  • shared/local-first/storage.ts — Added loadRaw() for backup manager
  • shared/local-first/encryptid-bridge.ts — Wired backup stubs to BackupSyncManager, added getBackupManager()/initBackupManager()
  • shared/local-first/index.ts — Exported new backup + relay message types
  • docker-compose.yml — Added rspace-backups:/data/backups volume
  • server/index.ts — Mounted backup routes at /api/backup

Verification

  • npx tsc --noEmit — zero errors
  • bun run scripts/test-automerge-roundtrip.ts — 35/35 pass
  • Deployed to Netcup, container starts cleanly with 33 docs loaded

AC #5 (custom VPS endpoint) deferred to Layer 3 (Federated Replication) — designed in DATA-ARCHITECTURE.md but not yet implemented.