* feat(canvas): native field preservation, label materialization, batch workspace delete
- fillNativeFields() + repairContainerBinding() in db layer ensure every
element stored in SQLite is a complete, round-trippable Excalidraw element
with correct containerId ↔ boundElements bidirectional binding
- materializeLabel() in server.ts: shapes with label.text/text produce a
native bound text element at write time (create, update, batch) so text
follows its container when moved — matches VSCode Excalidraw extension behavior
- Batch workspace UI: Select/Unselect All, per-row checkboxes, Delete N
workspaces button with confirmation
- POST /api/tenants/batch-delete: delete up to 50 tenants in one request
- 42 new backend tests; 519 total passing
- Bump version 1.0.6 → 1.1.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(tests): update e2e assertions for label materialization
phase2-regressions: label is now a native bound text element
(id: pos-stable-1-label) — check bound text element text instead
of container.label?.text which is no longer stored.
sync-flows FTS: search now matches the bound text element (fts-el-label)
rather than the container — accept either id as valid match.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Deletions made in the UI were silently lost on page reload because the sync
baseline (lastSyncedElementsRef) was never populated after initial load,
making the delta algorithm unable to detect removed elements. Additionally,
import_scene and restore_snapshot used a non-atomic clear+create pattern
that could permanently lose all canvas data if the batch create failed
after clearing, and duplicate_elements copied stale binding references
pointing to original element IDs instead of remapped duplicates.
🔧 Sync baseline restoration:
- Populate deletion-detection baseline on every server-to-client data path
(page load, delta resync, hello handshake, initial elements broadcast)
- Establish sync version and hash baselines to prevent phantom re-syncs
🛡️ Data-loss prevention:
- Backup current scene before destructive clear in replace-mode operations
- Atomic restore from backup when subsequent batch create fails
- Remap all binding references (start/end IDs, boundElements, containerId)
to new IDs during element duplication
✅ Comprehensive test coverage (154 new tests, 344 total):
- Delta sync flows including deletion persistence and bidirectional sync
- Multi-tenant element/sync/WebSocket isolation
- Arrow binding resolution across all shape types and edge cases
- MCP tool integration covering backup-restore and binding remapping
- Input validation and security boundary testing
- Frontend sync algorithm unit tests reproducing the exact regression
🎯 Eliminates the most critical data-integrity risks: deletions now
persist reliably, destructive operations are rollback-safe, and the
full test suite provides regression coverage for every sync path.