# Web-CAD Fixplan — 50-Issue Audit **Audit-Datum**: 2026-06-29 **Audit-Quelle**: `CODE_ANALYSIS.md` (Codebase Explorer, brutally-honest mode) **Stand**: 2026-06-30 **HEAD**: `4a5377c` (main, origin/main) **Verdict**: Funktionaler Prototyp mit kritischen Security-Lücken, gebrochener Collab-Sync und systemischer Architektur-Schuld — **NICHT production-ready**. --- ## Zusammenfassung | Schweregrad | Total | Fixed | Open | |---|---|---|---| | CRITICAL | 8 | 8 ✅ | 0 | | HIGH | 13 | 3 ✅ | 10 | | MEDIUM | 15 | 0 ✅ | 15 | | LOW | 14 | 0 ✅ | 14 | | **Total** | **50** | **11** | **39** | ## Fix-Commits (Audit-Phase 1) - `2e9dfdf` — Issues #1, #3 (auth middleware + CORS) - `cf62a77` — Issues #2, #4, #5 (WebSocket auth + Yjs persistence + doc retention) - `8493138` — Issue #6 (CRDT sync groups + bgConfig) - `275b863` — Issues #7, #8 (loadFromState race + plugin stale closure) - `baba0cb` — Issues #9, #10, #11 (remote sync, save all, block drop) - `4a5377c` — Quality-Review-Fixes (Issues #9, #10, #11 local-first merge) ## Test-Coverage-Schema - ✅ **Verified**: Smoke-Test im `test_report.md` beweist das Verhalten - ⚠️ **Build-only**: `tsc --noEmit` clean + `vite build` erfolgreich, aber kein funktionaler Test - ❌ **Untested**: Kein Test-Beleg vorhanden --- ## Issues ### #1: [backend/src/routes/*.ts] NO Authentication on All CRUD Routes - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ✅ Verified - **Notes**: 2e9dfdf: auth middleware on all CRUD routes; smoke-test: no token → 401 (projects.ts tested) ### #2: [backend/src/websocket/yjsServer.ts:84] WebSocket Collaboration Has No Authentication - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ✅ Verified - **Notes**: cf62a77: WS token validation; 3 tests: no token→4001, invalid token→4001, valid token→accepted ### #3: [backend/src/server.ts:26] CORS Allows All Origins - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: 2e9dfdf: CORS restricted to env allowlist; no test in test_report.md (manual CORS-header check needed) ### #4: [backend/src/websocket/yjsServer.ts:43] Yjs Persistence NEVER Loads - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: cf62a77: persistenceReady flag set; server start log shows '/tmp/yjs-documents initialized', but no restart-roundtrip test ### #5: [backend/src/websocket/yjsServer.ts:125] In-Memory Doc Deleted When Last Client Disconnects - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: cf62a77: docs retained after last disconnect; no specific test in test_report.md ### #6: [frontend/src/App.tsx:280-319] CRDT Sync: Groups and bgConfig NOT Synced via Yjs - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: 8493138: groups + bgConfig synced via Yjs; no E2E-collab-test ### #7: [frontend/src/App.tsx:267-269] loadFromState Called Before Data Is Loaded — Race Condition - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: 275b863: race condition resolved; no specific race-condition test ### #8: [frontend/src/App.tsx:128-142] Plugin Context Has Stale Closure — Captures Empty State - **Severity**: CRITICAL - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: 275b863: plugin context stale closure fixed; no plugin-context test ### #9: [frontend/src/App.tsx:306-317] Band-Aid Guards for Empty Remote Arrays - **Severity**: HIGH - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: baba0cb + 4a5377c (quality review): band-aid guards replaced with local-first merge; no test ### #10: [frontend/src/App.tsx:588] Save Action Only Saves Elements Starting with 'el-' - **Severity**: HIGH - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: baba0cb + 4a5377c (quality review): save all elements; no test ### #11: [frontend/src/App.tsx:509-517] Block Drop Doesn't Save to Backend or Yjs - **Severity**: HIGH - **Status**: ✅ FIXED - **Test-Coverage**: ⚠️ Build-only - **Notes**: baba0cb + 4a5377c (quality review): block drop backend sync; no test ### #12: [frontend/src/App.tsx:528-550] Import Doesn't Save to Backend or Yjs - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #13: [frontend/src/App.tsx:628] Copy/Paste Uses Non-Existent `selected` Property - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #14: [frontend/src/App.tsx:1021] activeLayerName Hardcoded to 'layer-0' - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #15: [frontend/src/App.tsx:754-789] Layer Operations Don't Persist to Backend - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #16: [frontend/src/App.tsx:436-438] Block Rename Doesn't Persist to Backend - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #17: [frontend/src/App.tsx:440-454] Block Duplicate Doesn't Persist to Backend - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #18: [frontend/src/App.tsx:906-912] GROUP Command Doesn't Actually Create Groups - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #19: [frontend/src/crdt/AwarenessManager.ts:38-39] Cursor Data Stored in Shared Y.Doc - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #20: [frontend/src/crdt/WebSocketProvider.ts:62-65] Client Sends Local State on Connect — Conflicts with Server State - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #21: [backend/src/routes/projects.ts:9-11] listProjects Returns ALL Projects — No Owner Filtering - **Severity**: HIGH - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #22: [frontend/src/App.tsx:1207 lines] Monolithic Component — God Component Anti-Pattern - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #23: [frontend/src/App.tsx:380] Stale `elements` in handleElementsDeleted Dependencies - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #24: [frontend/src/App.tsx:607-621] Export Uses NW.js-Specific `nwsave` Attribute - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #25: [frontend/src/services/api.ts:354-388] Project Load Cache Race Condition - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #26: [frontend/src/App.tsx:66] Global Mutable Set for StrictMode Dedup — Module-Level State - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #27: [frontend/src/App.tsx:170-173] SeatingService Instantiated on Every Elements Change - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #28: [frontend/src/App.tsx:467-472] SVG Import Doesn't Persist to Backend - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #29: [frontend/src/App.tsx:474-488] Save Group as Block Only Uses Single Selected Element - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #30: [backend/src/database/SqliteAdapter.ts:267] Session Expiry Comparison Uses Wrong Format - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #31: [frontend/src/App.tsx:421-428] Text Edit Uses window.prompt — Blocking UX - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #32: [frontend/src/App.tsx:657-680] Image Insert Doesn't Save to Backend or Yjs - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #33: [backend/src/routes/*.ts] No Input Validation on Any Route - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #34: [frontend/src/App.tsx:637-642] Paste Doesn't Save to Backend or Yjs - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #35: [frontend/src/crdt/useYjsBinding.ts:110] useEffect Dependencies Include Values That Don't Change - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #36: [frontend/src/App.tsx:145] Online Count Includes Self Even When Disconnected - **Severity**: MEDIUM - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #37: [frontend/src/App.tsx:50-63] Mock Data Used as Initial State - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #38: [frontend/src/App.tsx:40-46] Initial Layers Hardcoded — Not from Backend - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #39: [frontend/src/services/api.ts:34,44,54] Return Type `any` for Auth Functions - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #40: [frontend/src/App.tsx:667-671] Multiple `as any` Casts for Image Element - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #41: [frontend/src/history/HistoryManager.ts] generateId() Method Never Used - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #42: [frontend/src/App.tsx:501-503] handleBlockSearch Is a No-Op - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #43: [frontend/src/App.tsx:691-695] Zoom Fit/100 Are No-Ops - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #44: [frontend/src/App.tsx:683-686] Format Actions Are No-Ops - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #45: [frontend/src/App.tsx:706-708] Search Action Is a No-Op - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #46: [backend/src/database/SqliteAdapter.ts:93] Indentation Inconsistency - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #47: [frontend/src/App.tsx:159] BackgroundService Instantiated in useRef — Never Cleaned Up - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #48: [frontend/src/App.tsx:349-352] handleToggleElementVisible Calls API Inside setElements - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #49: [frontend/src/App.tsx:951-960] Plugin Context Duplicated in handleCommand - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed ### #50: [frontend/src/App.tsx:799] handleZoomIn/Out/Fit Only Log Messages - **Severity**: LOW - **Status**: ⏳ OPEN - **Test-Coverage**: ❌ Untested - **Notes**: Not fixed