- Add /db/local/:db path type that stores diagrams locally without syncing - New diagrams now default to local storage (browser-only) - Share button creates public copy when sharing local diagrams - Add storage type badges (Local/Public/Private) in diagram manager - Add GitHub Actions workflow for automated builds - Block local- database requests at server with 404 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
180 lines
5.0 KiB
Markdown
180 lines
5.0 KiB
Markdown
# Future Sync Strategy: Keeping Local and Public Clones in Sync
|
|
|
|
## Current State (v1)
|
|
|
|
- Sharing creates a **ONE-TIME COPY** from local to public
|
|
- Copies diverge independently after sharing
|
|
- No automatic sync between local and public versions
|
|
- Local diagrams are browser-only (IndexedDB via PouchDB)
|
|
- Public diagrams sync with server via express-pouchdb
|
|
|
|
### URL Scheme
|
|
|
|
| Route | Sync | Access | Status |
|
|
|-------|------|--------|--------|
|
|
| `/db/local/:id` | None | Browser-only | Implemented |
|
|
| `/db/public/:id` | Yes | Anyone | Implemented |
|
|
| `/db/private/:id` | Yes | Authorized users | Route only (no auth) |
|
|
|
|
## Future Options
|
|
|
|
### Option 1: Manual Push/Pull (Recommended for v2)
|
|
|
|
Add explicit user-triggered sync between local and public copies.
|
|
|
|
**Features:**
|
|
- "Push to Public" button - sends local changes to public copy
|
|
- "Pull from Public" button - gets public changes into local
|
|
- Track `lastSyncedAt` timestamp
|
|
- Show indicator when copies have diverged
|
|
- Conflict resolution: Last write wins (simple) or user choice (advanced)
|
|
|
|
**Pros:**
|
|
- User stays in control
|
|
- Clear mental model
|
|
- Simple to implement incrementally
|
|
|
|
**Cons:**
|
|
- Manual effort required
|
|
- Risk of forgetting to sync
|
|
|
|
### Option 2: Automatic Background Sync
|
|
|
|
Continuous bidirectional sync between local and public copies.
|
|
|
|
**Features:**
|
|
- Real-time sync like Google Docs
|
|
- Works across devices
|
|
- Offline-first with automatic merge
|
|
|
|
**Pros:**
|
|
- Seamless experience
|
|
- Always up to date
|
|
|
|
**Cons:**
|
|
- Complex conflict resolution (may need CRDTs)
|
|
- Higher performance overhead
|
|
- Harder to reason about state
|
|
|
|
### Option 3: Fork/Branch Model
|
|
|
|
One-way relationship: local is "draft", public is "published".
|
|
|
|
**Features:**
|
|
- Push only (local → public)
|
|
- No pull mechanism
|
|
- Public is the "source of truth" once published
|
|
|
|
**Pros:**
|
|
- Clear mental model
|
|
- No merge conflicts
|
|
- Simple implementation
|
|
|
|
**Cons:**
|
|
- Cannot incorporate public changes back to local
|
|
- Multiple people can't collaborate on draft
|
|
|
|
## Recommended Implementation (v2)
|
|
|
|
Implement **Option 1 (Manual Push/Pull)** as it provides the best balance of user control and simplicity.
|
|
|
|
### Data Model Changes
|
|
|
|
Add to diagram directory entry:
|
|
```typescript
|
|
interface DiagramEntry {
|
|
_id: string;
|
|
name: string;
|
|
description: string;
|
|
storageType: 'local' | 'public' | 'private';
|
|
createdAt: string;
|
|
|
|
// New fields for sync tracking
|
|
publicCopyId?: string; // ID of the public clone (if shared)
|
|
lastPushedAt?: string; // When changes were last pushed to public
|
|
lastPulledAt?: string; // When public changes were last pulled
|
|
publicVersion?: number; // Version number of public copy at last sync
|
|
}
|
|
```
|
|
|
|
### API Endpoints
|
|
|
|
```typescript
|
|
// Push local changes to public
|
|
POST /api/sync/push
|
|
Body: { localDbName: string, publicDbName: string }
|
|
Response: { success: boolean, documentsUpdated: number }
|
|
|
|
// Pull public changes to local
|
|
POST /api/sync/pull
|
|
Body: { localDbName: string, publicDbName: string }
|
|
Response: { success: boolean, documentsUpdated: number }
|
|
|
|
// Check if copies have diverged
|
|
GET /api/sync/status?local={localDbName}&public={publicDbName}
|
|
Response: {
|
|
diverged: boolean,
|
|
localChanges: number,
|
|
publicChanges: number,
|
|
lastSyncedAt: string
|
|
}
|
|
```
|
|
|
|
### UI Components
|
|
|
|
1. **Sync Status Indicator**
|
|
- Shows in header when viewing a local diagram that has a public copy
|
|
- Green check: In sync
|
|
- Orange dot: Changes pending
|
|
- Red warning: Conflicts detected
|
|
|
|
2. **Push/Pull Buttons**
|
|
- In hamburger menu under "Share" section
|
|
- "Push to Public" - shows confirmation with change count
|
|
- "Pull from Public" - shows confirmation with change count
|
|
|
|
3. **Divergence Warning Badge**
|
|
- Shows on diagram card in Manage Diagrams modal
|
|
- Indicates when local and public have diverged
|
|
|
|
4. **Conflict Resolution Dialog**
|
|
- Shows when both local and public have changes to same entity
|
|
- Options: Keep Local, Keep Public, Keep Both (creates duplicate)
|
|
|
|
### Implementation Phases
|
|
|
|
**Phase 1: Tracking**
|
|
- Add `publicCopyId` when sharing local → public
|
|
- Track sharing relationship in directory
|
|
|
|
**Phase 2: Push**
|
|
- Implement push from local to public
|
|
- Overwrite public with local changes
|
|
- Update `lastPushedAt` timestamp
|
|
|
|
**Phase 3: Pull**
|
|
- Implement pull from public to local
|
|
- Merge public changes into local
|
|
- Update `lastPulledAt` timestamp
|
|
|
|
**Phase 4: Status**
|
|
- Implement divergence detection
|
|
- Add UI indicators
|
|
- Show sync status in Manage Diagrams
|
|
|
|
**Phase 5: Conflict Resolution**
|
|
- Detect entity-level conflicts
|
|
- Show resolution dialog
|
|
- Allow user to choose resolution strategy
|
|
|
|
## Migration Notes
|
|
|
|
Existing diagrams without `storageType` are treated as `public` for backwards compatibility. When such diagrams are loaded, the UI should work correctly but sync tracking features won't be available until the diagram metadata is updated.
|
|
|
|
## Security Considerations
|
|
|
|
- Push/pull operations should validate that the user has access to both databases
|
|
- Public databases remain world-readable/writable
|
|
- Private database sync will require authentication tokens
|
|
- Rate limiting should be applied to sync operations
|