docs: add FIXPLAN.md (50-issue audit) + update BAUPLAN with audit phase 1

- docs/FIXPLAN.md: complete 50-issue list with severity, status, test-coverage
- BAUPLAN.md: new Phase 22 'Audit & Hardening Phase 1' + Audit-Stand 2026-06-30 header
- 11 of 50 issues fixed (all 8 CRITICAL + 3 HIGH)
- 39 issues open (10 HIGH, 15 MEDIUM, 14 LOW)
- Fix commits: 2e9dfdf, cf62a77, 8493138, 275b863, baba0cb, 4a5377c

Refs: CODE_ANALYSIS.md, test_report.md
This commit is contained in:
2026-06-30 11:09:56 +02:00
parent 4a5377cb53
commit 4b9140a99b
2 changed files with 404 additions and 0 deletions
+339
View File
@@ -0,0 +1,339 @@
# 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