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 |
|
|
|
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 trackingserver/local-first/backup-routes.ts— Hono REST API (PUT/GET/DELETE /api/backup/:space/:docId) with JWT authshared/local-first/backup.ts— BackupSyncManager with delta-only push, full restore, auto-backupdocs/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-utilsserver/local-first/doc-persistence.ts— Added encryptionKeyId param, rSEN detection in loadAllDocs, saveEncryptedBlob/loadEncryptedBlob for relay blobsserver/local-first/sync-server.ts— Added relay-backup/relay-restore wire messages, onRelayBackup/onRelayLoad callbacksserver/sync-instance.ts— Added encryption key lookup + relay backup/load wiringshared/local-first/sync.ts— Added RelayBackupMessage/RelayRestoreMessage types, sendRelayBackup(), handleRelayRestore()shared/local-first/storage.ts— Added loadRaw() for backup managershared/local-first/encryptid-bridge.ts— Wired backup stubs to BackupSyncManager, added getBackupManager()/initBackupManager()shared/local-first/index.ts— Exported new backup + relay message typesdocker-compose.yml— Added rspace-backups:/data/backups volumeserver/index.ts— Mounted backup routes at /api/backup
Verification
npx tsc --noEmit— zero errorsbun run scripts/test-automerge-roundtrip.ts— 35/35 pass- Deployed to Netcup, container starts cleanly with 33 docs loaded