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,4a5377cRefs: CODE_ANALYSIS.md, test_report.md
This commit is contained in:
+65
@@ -5,6 +5,16 @@ Basierend auf: Pflichtenheft v4 (633 Zeilen) + UI-Mockup Iteration 9
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Audit-Stand 2026-06-30
|
||||
|
||||
**Dieses Projekt wurde am 2026-06-29 einem brutal-honest Code-Audit unterzogen.**
|
||||
**Ergebnis**: 50 Probleme identifiziert (8 CRITICAL, 13 HIGH, 15 MEDIUM, 14 LOW).
|
||||
**Stand**: 11 von 50 Issues gefixt (alle CRITICAL + 3 HIGH).
|
||||
**Verbleibend**: 39 Issues — siehe `docs/FIXPLAN.md` für Details.
|
||||
**HEAD**: `4a5377c` (main, origin/main).
|
||||
|
||||
---
|
||||
|
||||
## Technologie-Stack
|
||||
|
||||
| Schicht | Technologie | Lizenz |
|
||||
@@ -702,3 +712,58 @@ web-cad-neu/
|
||||
└── specs/
|
||||
└── requirements.md # Kopie des Pflichtenhefts
|
||||
```
|
||||
|
||||
## Phase 22: Audit & Hardening Phase 1 (2026-06-29) ✅
|
||||
|
||||
**Trigger**: Codebase-Audit am 2026-06-29 durch Codebase Explorer (brutally-honest mode).
|
||||
**Quelle**: `CODE_ANALYSIS.md` (Audit-Report) + `docs/FIXPLAN.md` (50-Issue-Liste mit Status).
|
||||
**Verdict**: Funktionaler Prototyp mit kritischen Security-Lücken, gebrochener Collab-Sync und systemischer Architektur-Schuld — **NICHT production-ready**.
|
||||
|
||||
### Issues-Übersicht
|
||||
|
||||
| Schweregrad | Total | Fixed | Open |
|
||||
|---|---|---|---|
|
||||
| CRITICAL | 8 | 8 ✅ | 0 |
|
||||
| HIGH | 13 | 3 ✅ | 10 |
|
||||
| MEDIUM | 15 | 0 | 15 |
|
||||
| LOW | 14 | 0 | 14 |
|
||||
| **Total** | **50** | **11** | **39** |
|
||||
|
||||
### Fixes Phase 1 (alle 8 CRITICAL + 3 HIGH)
|
||||
|
||||
| Commit | Issues | Inhalt |
|
||||
|---|---|---|
|
||||
| `2e9dfdf` | #1, #3 | Auth middleware auf allen CRUD Routes + CORS restrict |
|
||||
| `cf62a77` | #2, #4, #5 | WebSocket auth + Yjs persistence + doc retention |
|
||||
| `8493138` | #6 | CRDT sync groups + bgConfig via Yjs |
|
||||
| `275b863` | #7, #8 | loadFromState race + plugin stale closure |
|
||||
| `baba0cb` | #9, #10, #11 | Remote sync + save all elements + block drop sync |
|
||||
| `4a5377c` | #9, #10, #11 | Quality-Review-Fixes (local-first merge) |
|
||||
|
||||
### Verifikation
|
||||
|
||||
- ✅ Backend `tsc --noEmit` clean
|
||||
- ✅ Frontend `tsc --noEmit` clean
|
||||
- ✅ Backend `npm run build` erfolgreich
|
||||
- ✅ Frontend `vite build` erfolgreich (341 modules)
|
||||
- ✅ Server startet ohne Fehler
|
||||
- ✅ Health endpoint `GET /api/health` → 200
|
||||
- ✅ WS ohne Token → Close code 4001 "Authentication required"
|
||||
- ✅ WS mit invalid Token → Close code 4001 "Invalid or expired session"
|
||||
- ✅ WS mit valid Token → accepted, initial state sync
|
||||
- ✅ Register + Login funktional
|
||||
|
||||
### Verbleibende Brocken (für Phase 23+)
|
||||
|
||||
- **App.tsx Refactoring** (Issue #22, 1207-Zeilen-Monolith in Module)
|
||||
- **Block-Persistence** (Issues #16, #17 — Rename + Duplicate)
|
||||
- **Layer-Persistence** (Issue #15)
|
||||
- **GROUP Command** (Issue #18 — No-Op)
|
||||
- **Image Insert / Paste / SVG-Import** (Issues #28, #32, #34)
|
||||
- **listProjects Owner-Filterung** (Issue #21)
|
||||
- **Input Validation** auf allen Backend-Routes (Issue #33)
|
||||
- **Cursor-Storage** in Y.Doc (Issue #19)
|
||||
- Diverse MEDIUM + LOW Cleanups
|
||||
|
||||
**Detaillierter Fixplan**: siehe `docs/FIXPLAN.md` (alle 50 Issues mit Severity, Status, Test-Coverage).
|
||||
|
||||
|
||||
+339
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user