chore: untrack docs/brain/ files (local-only vault)

These were accidentally force-added. The vault is gitignored and
should remain local-only. Files are preserved on disk.
This commit is contained in:
jevb
2026-04-01 15:51:50 +02:00
parent 4cdb10b76c
commit 0cfe1a7ced
5 changed files with 0 additions and 2524 deletions
-670
View File
@@ -1,670 +0,0 @@
# Backlog
**Goal:** Ship v1.2, then build gaming-native features that
differentiate OwnCord from Discord/TeamSpeak/Mumble.
Last task ID: T-457. New tasks start at T-458.
---
## Core Stability — Bugs Found 2026-03-28 (audit + Codex review)
- [x] **T-165:** Fix BUG-046 — wrap voice `switchActiveDevice` in try-catch with device fallback — 2026-03-28
- [x] **T-166:** Fix BUG-047 — block send until uploads complete or cancel in-flight uploads — 2026-03-28
- [x] **T-167:** Fix BUG-048 — add client-side file size/type validation before upload (incl. paste path) — 2026-03-28
- [x] **T-168:** Fix BUG-049 — migrate VAD from requestAnimationFrame to setTimeout — 2026-03-28
- [x] **T-169:** Fix BUG-050 — clear stale audio elements on voice auto-reconnect — 2026-03-28
- [x] **T-170:** Fix BUG-051 — add origin/path check to LiveKit HTTP proxy handler — 2026-03-28
- [x] **T-171:** Fix BUG-052 — replace swallowed `.catch(() => {})` with debug/warn logging — 2026-03-28
- [x] **T-172:** Fix BUG-053 — add TOFU fingerprint pinning to LiveKit TLS proxy — 2026-03-28
- [x] **T-173:** Fix BUG-054 — implement account deletion (server endpoint + client UI) — 2026-03-28
## Cleanup — Found 2026-03-28
- [x] **T-182:** Fix BUG-055 — remove 4 stale vitest coverage exclusions — 2026-03-28
- [x] **T-183:** Fix BUG-056 — fix livekit-session.test.ts proxy URL test (mock Tauri invoke) — 2026-03-28
## Refactoring
- [x] **T-184:** Refactor `livekitSession.ts` — remove duplicate audio pipeline fields/methods, delegate entirely to `_audioPipeline`. 1,438 → 1,171 lines (267 lines removed) — 2026-03-29
- [x] **T-185:** Add unit tests for delete account UI flow in `settings-overlay.test.ts` — 7 tests: trigger, cancel, password validation, callback, disabled state, error display, input clearing — 2026-03-29
## Code Quality — Found 2026-03-29 (full-project audit)
- [x] **T-190:** Propagate `context.Context` from WS upgrade through all handlers — added ctx to Client struct, updated MessageHandler signature, threaded ctx through all 17 WS handlers across 9 files. Added ExecContext/QueryRowContext/QueryContext/BeginTx to DB wrapper. — 2026-03-29
- [x] **T-191:** Add ESLint v9 config with `@typescript-eslint/no-floating-promises`, `no-unused-vars`, `consistent-return` — installed eslint v9.39.4 + typescript-eslint, created flat config, fixed 61 lint violations across 22 files — 2026-03-29
---
## 2FA Client Integration — 2026-03-29
### High Priority
- [x] **T-192:** Client 2FA enrollment/disable settings UI — AccountTab TOTP section, auth store state, SettingsOverlay wiring — 2026-03-29
- [x] **T-193:** Client 2FA test coverage — Unit tests for TOTP settings flows, api.ts TOTP methods, auth store totp_enabled state — 2026-03-29
- [x] **T-194:** Full regression validation pass — `go test ./...`, `npm test`, `golangci-lint`, `npm run lint` — 2026-03-29
### Medium Priority
- [ ] **T-195:** User profile/password/session management endpoints — PATCH /users/me, PUT /users/me/password, GET/DELETE /users/me/sessions (server-side)
- [ ] **T-196:** DM sidebar incremental DOM update — Replace full DOM rebuild at SidebarArea.ts:753 with reconciliation
## Bugs — 2026-03-29
### High Priority
- [ ] **T-202:** Admin panel tab navigation broken — Clicking Audit Logs, Members, or other tabs in the `/admin` panel does not switch pages. Likely regression from recent `handlers_settings.go` or `logstream.go` changes. Investigate JS console errors and admin static files.
## Code Review Findings — 2026-03-29
### High Priority
- [x] **T-197:** Fix double `updateUser` call on TOTP confirm/disable — Verified false positive: `updateUser` called once in MainPage.ts, `onEnrolled`/`onDisabled` only re-render UI — 2026-03-31
- [x] **T-198:** Add TOTP audit log events — Added `database.LogAudit(...)` calls for totp_verified, totp_enabled, totp_disabled — 2026-03-31
- [x] **T-199:** Safe default for `registration_open` on upgrade — Changed default from `false` to `true` in `isRegistrationOpen()` — 2026-03-31
- [x] **T-200:** Extract TOTP handlers to `totp_handler.go` — Moved 4 handlers + 4 types; auth_handler.go 829 → 583 lines — 2026-03-31
### Medium Priority
- [x] **T-201:** TOTP constant-time code comparison — Replaced `==` with `subtle.ConstantTimeCompare` in `totp.go:207` — 2026-03-31
---
## Project Map Dashboard Enhancements — 2026-03-31
*Transform `tools/project-map/` from a tool you visit into a daily driver.
Eliminate cold-start friction, capture bugs in real-time, automate scans,
and surface trends. See plan in session log for full rationale.*
### Phase PM-1: Morning Experience (the cold-start killer)
- [ ] **T-203:** Briefing as default landing view — Restructure dashboard.html renderSession() to lead with briefing content, not the session card. Briefing should be the top-level content on load.
- [ ] **T-204:** Last session summary inline — Enhance morning-briefing.mjs to include lastSession details: files touched, commits made, duration, modules worked on. Render as compact summary card.
- [ ] **T-205:** "Time since last session" prominent indicator — Upgrade from text greeting to colored badge (green <1d, yellow 2-3d, red >3d) with exact hours/days.
- [ ] **T-206:** Agent results surfaced at top — Move completed agent results above the session plan in briefing. Add result count badge to Session tab label.
- [ ] **T-207:** One-click "Start Session" with plan acceptance — Enhance Start Session button to auto-accept suggested plan. Add plan items to session start POST body.
### Phase PM-2: Bug Capture During Live Testing
- [ ] **T-208:** Persistent quick-add bug bar — Fixed-position bar at dashboard bottom (always visible). Text input + module dropdown + severity selector + submit.
- [ ] **T-209:** Bug creation backend endpoint — `POST /api/bugs` in server.mjs. New lib/bug-writer.mjs for ID generation (next T-XXX), markdown formatting, atomic file write to Backlog.md.
- [ ] **T-210:** Severity tags and auto-tagging — Support crash/broken/cosmetic severity. Auto-add `found-in-testing` tag. Update backlog-parser.mjs to recognize new tags.
- [ ] **T-211:** Mobile-friendly bug capture page — `GET /api/bugs/quick` serves minimal standalone HTML form. Responsive, large touch targets, no navigation chrome.
- [ ] **T-212:** SSE broadcast on bug creation — Broadcast `bug-created` event via SSE. Dashboard refreshes backlog data on receipt.
### Phase PM-3: Proactive Scanning
- [ ] **T-213:** Scan staleness configuration — New `.cache/scan-config.json` with per-scan-type day thresholds (security: 7d, code-review: 14d, debt: 3d, tests: 7d). `POST /api/scan-config` to override.
- [ ] **T-214:** Auto-scan on server start — New lib/scan-scheduler.mjs. On startup, check each module's last scan date against thresholds. Track timestamps in `.cache/scan-history.json`.
- [ ] **T-215:** Scan results auto-create backlog entries — Post-process completed agent results in agent-manager.mjs. Parse for issue indicators, auto-create backlog entries via bug-writer.mjs with `agent-discovered` tag.
- [ ] **T-216:** Dashboard "due scans" indicator — Show count of modules due for scanning in briefing. "Run all due scans" button batch-queues agent jobs for all due modules.
### Phase PM-4: Session Polish
- [ ] **T-217:** Session plan preview with editing — Add checkboxes to plan items. Unchecked items excluded from session. Pass accepted items to `POST /api/session/start` body.
- [ ] **T-218:** Browser tab title with session state — Update `document.title` dynamically. Active: `"▶ 47min | OwnCord"` (60s interval). Idle: `"Project Map | OwnCord"`.
- [ ] **T-219:** Session end summary with improvement metrics — Compute coverage deltas, backlog items closed (from commit task IDs), tests added (git diff stats). Display in summary modal.
- [ ] **T-220:** Smooth session auto-recovery UX — Visible notification bar when stale session detected. "Resume or discard?" with stale session stats (started at, files changed).
### Phase PM-5: Dashboard UX
- [ ] **T-221:** SSE-driven visible updates — Toast notifications on file-change events. Flash Agents tab on job-update. Small event log in header showing last 3 SSE events.
- [ ] **T-222:** Loading states with cached data — Show cached data from localStorage on initial load. Fetch fresh in background, swap in. Show "cached · refreshing..." indicator.
- [ ] **T-223:** Keyboard shortcuts — S: start/end session, Q: focus bug bar, N: Focus Next tab, R: refresh, 1-9: switch tabs. Help overlay on `?` key.
- [ ] **T-224:** Collapsible sections — Toggle buttons (▸/▾) on each card h2. Persist collapsed state in localStorage.
- [ ] **T-225:** Dark theme contrast audit — Verify CSS variables against WCAG AA (4.5:1). Adjust `--text-dim` and other colors if needed.
### Phase PM-6: Agent Workflow Improvements
- [ ] **T-226:** Batch queue endpoint — `POST /api/jobs/batch` with filter criteria (e.g. `coverage_below: 50`). Resolves filter against data, creates one job per matching module.
- [ ] **T-227:** Agent result diffing — Track result metadata (issue count, findings hash) in scan-history.json. Compare previous vs current results. Show added/removed issues in result overlay.
- [ ] **T-228:** Estimated completion indicator — Track actual job durations in scan-history.json per type. Compute rolling average. Display "~3m remaining" on running jobs.
- [ ] **T-229:** Browser notifications on job completion — Request `Notification.permission` on load. Fire `new Notification()` on completed job SSE events. Optional sound toggle.
### Phase PM-7: Data Continuity
- [ ] **T-230:** Weekly summary auto-generation — New lib/weekly-summary.mjs. Aggregate sessions, time, tasks closed, coverage deltas, bugs found. Write to `docs/brain/03-Sessions/weekly-YYYY-WW.md`. Trigger on server start if missing for previous week.
- [ ] **T-231:** Trend lines on dashboard — Mini sparkline charts for coverage, debt, velocity over time. Store historical snapshots in `.cache/trend-data.json` (appended each collectData, max 90 entries).
- [ ] **T-232:** Export/snapshot and restore — `GET /api/export` bundles all .cache/ JSON into single download. `POST /api/import` restores from snapshot. Dashboard button in header.
### Phase PM-8: Small but High-Impact
- [ ] **T-233:** Dynamic favicon — Two inline SVG favicons (cyan active, dim idle). Swap on session state change via `link[rel="icon"]`.
- [ ] **T-234:** "What did I do last week" view — Filtered History tab view for past 7 days. Aggregate files, commits, tasks, coverage changes. Auto-triggered when `daysSince > 1` in briefing.
- [ ] **T-235:** VS Code direct links — Wrap all file path displays (debt markers, churn, coverage) with `vscode://file/${ROOT}/${path}:${line}` links. Pass ROOT from server via `/api/data` response.
- [ ] **T-236:** New files: lib/bug-writer.mjs — Backlog entry creation with atomic writes, next-ID generation, markdown formatting
- [ ] **T-237:** New files: lib/scan-scheduler.mjs — Staleness tracking, threshold config, auto-scan scheduling logic
- [ ] **T-238:** New files: lib/weekly-summary.mjs — Weekly aggregate report generation and vault writing
- [ ] **T-239:** New files: .cache/scan-config.json, scan-history.json, trend-data.json — Persistent state for scanning and trends
- [ ] **T-240:** Dashboard.html size audit — If dashboard exceeds 1500 lines after all phases, split JS into separate file
---
## Unified Sidebar — Deferred Items (from 2026-03-27 redesign)
- [x] **T-161:** Relocate MemberList into unified sidebar as collapsible section — SidebarArea.ts:625-743, with resize handle and localStorage persistence — verified 2026-03-29
- [x] **T-162:** Wire DM conversations to real data source — SidebarArea.ts:408-419 reads from dmStore, renders with status/unread/timestamps — verified 2026-03-29
- [x] **T-163:** Wire quick-switch overlay disconnect/reconnect flow — SidebarArea.ts:844-850, stores target in sessionStorage, calls clearAuth() — verified 2026-03-29
- [x] **T-164:** Add per-server collapsible section state persistence to localStorage — ui.store.ts:124-176, keyed by server hostname — verified 2026-03-29
---
## Phase 1: Fix Bugs & Wire Dead Features
*Everything that's broken or exists but isn't connected.*
### P0 — Bugs & Broken Code
- [x] **T-033**: Fix voice state broadcast silent DB failures — 2026-03-21
- [x] **T-034**: Fix file storage partial write cleanup — 2026-03-21
- [x] **T-053**: Voice leave ghost session cleanup — 2026-03-21
- [x] **T-054**: Dispatcher payload validation — 2026-03-21
- [x] **T-072**: Fix Arrow-up edit-last-message listener — 2026-03-21
### P0 — Dead Features (code exists, not wired)
- [x] **T-066**: Add pin button to message action bar — 2026-03-21
- [x] **T-067**: Wire MemberList context menu to AdminActions — 2026-03-21
---
## Phase 2: Server Reliability & Correctness
*Make the Go server robust and production-grade.*
### P1 — Critical Reliability
- [x] **T-031**: hub.GracefulStop() already called in main.go — verified 2026-03-21
- [x] **T-032**: Add panic recovery wrapper around Hub.Run() — 2026-03-21
- [x] **T-035**: Add WS invalid payload counter — 2026-03-21
- [x] **T-106**: Typed message structs in Go — 2026-03-21
- [x] **T-107**: Sentinel errors in db package — 2026-03-21
### P1 — Performance (free wins)
- [x] **T-108**: SQLite pragma tuning — 2026-03-21
- [x] **T-052**: Batch permission query — verified already done 2026-03-21
### P1 — Graceful Shutdown
- [x] **T-109**: Server graceful shutdown with connection draining — 2026-03-21
---
## Phase 3: Client Reliability & Performance
*Make the client robust for long sessions.*
### P1 — Memory & Lifecycle
- [x] **T-110**: Disposable component lifecycle pattern — 2026-03-21
- [x] **T-056**: Cap messages store per channel (500 max) — 2026-03-21
- [x] **T-055**: Orphaned attachment cleanup job — 2026-03-21
### P2 — Performance
- [x] **T-111**: Virtual scrolling — already implemented (verified 2026-03-21)
- [x] **T-112**: Lazy loading — already implemented (verified 2026-03-21)
---
## Phase 4: Protocol & Reconnection
*Make the WebSocket protocol resilient to disconnects.*
### P1 — Message Delivery Reliability
- [x] **T-113**: Sequence numbers on server broadcasts — 2026-03-21
- [x] **T-114**: Client reconnection with state recovery — 2026-03-21
- [x] **T-115**: Server-side heartbeat monitoring — 2026-03-21
---
## Phase 5: Code Quality & Standards
*Clean up code structure for maintainability.*
### P2 — Server Code Quality
- [x] **T-116**: Structured logging level audit — 2026-03-21
- [x] **T-036**: Add request correlation IDs — 2026-03-21
- [x] **T-050**: Extract WS error constants (14 constants) — 2026-03-21
- [x] **T-051**: Split voice_handlers.go into 4 files — 2026-03-21
### P2 — Client Code Quality
- [x] **T-117**: TypeScript strict mode — already enabled, removed 3 unnecessary casts — 2026-03-21
- [x] **T-049**: Refactor MainPage → ChatArea + SidebarArea — 2026-03-21
- [x] **T-118**: Shared protocol schema + 7 drift issues found — 2026-03-21
- [x] **T-119**: LiveKit track lifecycle — already correct, verified — 2026-03-21
### P2 — Store Improvements
- [x] **T-120**: shallowEqual comparator (Map/Set/Array/Object) — 2026-03-21
---
## Phase 6: Testing & Verification
*Ensure the solid base is verified.*
### P2 — Integration Tests
- [x] **T-121**: WebSocket integration tests — 2026-03-21
- [x] **T-122**: LiveKit voice test script — 2026-03-21
### P3 — Security Hardening
- [x] **T-123**: Tighten Tauri CSP — 2026-03-21
- [x] **T-057**: Presence update failure ack — 2026-03-21
- [x] **T-075**: Mic permission denial notification — 2026-03-21
---
## Phase 7: Polish & Remaining Items
*Nice-to-haves that improve the experience.*
### P3 — Client Polish
- [x] **T-073**: Persist LogsTab filter and level preferences — 2026-03-21
- [x] **T-058**: Metrics endpoint (/api/v1/metrics) — 2026-03-21
---
## Deferred (Pre-Roadmap Features)
*Existing deferred features from stabilization era. Still valid.*
- [ ] **T-059**: Implement User Profile Popup component
- [ ] **T-060**: Implement Friends/DMs View
- [ ] **T-061**: Implement Status Picker component
- [ ] **T-062**: Implement DM Profile Sidebar
- [ ] **T-063**: Implement Soundboard component (protocol types exist, no UI)
- [ ] **T-024**: Implement screen sharing
- [ ] **T-023**: Add TOTP 2FA support — Login challenge flow: DONE; Server enable/confirm/disable endpoints: DONE; Client enrollment UI: IN PROGRESS (see [[02-Tasks/In Progress|T-192]]); Client test coverage: TODO (see T-193)
- [ ] **T-027**: Code signing certificate for SmartScreen
- [ ] **T-028**: Windows Service mode
- [ ] **T-029**: Custom emoji support
- [ ] **T-030**: Client auto-update via Tauri updater
---
## Feature Roadmap — Community Essentials (Phase R1)
*Low effort, high impact. Complete before first public release.*
*See [[00-Overview/Feature-Roadmap]] for full context and research.*
### P2 — Core Community Features
- [ ] **T-124**: Native polls — new `poll` message type with question, options, real-time vote counts via WebSocket
- [ ] **T-125**: Media gallery — per-channel gallery view filtering messages by images/videos/GIFs, grid layout with lightbox
- [ ] **T-126**: Event/session scheduler — "Next LAN Party" scheduler with date, time, RSVP, countdown timer in sidebar
- [ ] **T-127**: Server activity feed — sidebar widget showing recent joins, voice sessions, files shared, milestones
- [ ] **T-128**: Pinned notes — simple markdown pages per channel, wiki-lite for server rules, game configs, network guides
---
## Feature Roadmap — Gaming DNA (Phase R2)
*Revive the Xfire spirit. What made Xfire special, brought to 2026.*
*See [[00-Overview/Feature-Roadmap]] for Xfire research.*
### P2 — Game Integration
- [ ] **T-129**: Game detection + "Now Playing" — Rust-side process scanner detects running games, shows in user status, configurable game library
- [ ] **T-130**: Game time tracking — track playtime per game per user, lifetime stats on profile, server-wide "most played" leaderboard
- [ ] **T-131**: LAN game server browser — mDNS/UDP broadcast auto-discovery of game servers on LAN, show name/map/players/ping, click to join
- [ ] **T-132**: Screenshot capture + gallery — global hotkey to capture screenshot (Rust), auto-upload to channel, shared gallery with captions
- [ ] **T-133**: Friends activity view — "Friends of Friends Playing" tab, see what friends' friends are playing, one-click join or add friend
---
## Feature Roadmap — Voice Power Features (Phase R3)
*Features from TeamSpeak/Mumble that Discord lacks.*
*See [[00-Overview/Feature-Roadmap]] for competitive analysis.*
### P2 — Voice Enhancements
- [ ] **T-134**: Whisper lists — bind hotkey to whisper to specific users/groups across channels, stay in your channel but talk privately
- [ ] **T-135**: Positional/spatial audio — 3D audio positioning based on in-game coordinates, voices from player direction
- [ ] **T-136**: Voice channel nesting — sub-channels within voice channels (Team 1, Team 2), drag-and-drop between sub-channels
- [ ] **T-137**: Priority speaker — designated users talk over others, auto-duck other voices when priority speaker talks
---
## Feature Roadmap — LAN Party Toolkit (Phase R4)
*The killer differentiator. No competitor offers this integrated experience.*
*See [[00-Overview/Feature-Roadmap]] for LAN party tool research.*
### P3 — LAN Party Features
- [ ] **T-138**: Tournament brackets — single/double elimination, round robin, Swiss, auto-generated schedule, report results in-chat, live bracket display
- [ ] **T-139**: Seat map — visual seat map for venue, claim/reserve seats, see who sits where, show online status per seat
- [ ] **T-140**: Local leaderboard — per-event scoring across games, configurable points system, live leaderboard widget
- [ ] **T-141**: LanCache status widget — integration with LanCache.NET, show cache hit rate, downloaded games, bandwidth saved
- [ ] **T-142**: Shared music queue — collaborative playlist for venue, vote to skip, "now playing" display
---
## Feature Roadmap — Platform & Extensibility (Phase R5)
*Turn OwnCord from a product into a platform.*
*See [[00-Overview/Feature-Roadmap]] for platform research.*
### P3 — Extensibility
- [ ] **T-143**: Custom themes — theme engine with CSS variables, community theme sharing, dark/light/custom palettes
- [ ] **T-144**: Webhook integrations — incoming webhooks (post from external services), outgoing webhooks (trigger actions on events)
- [ ] **T-145**: Bot framework — bot accounts via REST API, slash commands, interactive messages, scheduled tasks
- [ ] **T-146**: Plugin system — server-side (Go) + client-side (TypeScript) plugins, API for custom channel types and widgets
- [ ] **T-147**: Backup/restore — one-command backup of SQLite DB + uploads + config, restore to new machine, scheduled backups
- [ ] **T-148**: Admin monitoring dashboard — CPU, RAM, disk, connected users, voice channels, bandwidth, Prometheus export
---
## Feature Roadmap — Future Vision (Phase R6)
*Exploratory. Emerging tech for long-term differentiation.*
*See [[00-Overview/Feature-Roadmap]] for trend research.*
### P4 — Exploratory
- [ ] **T-149**: AI noise cancellation — on-device noise suppression using lightweight ML models, no cloud dependency
- [ ] **T-150**: Real-time voice translation — AI-powered live translation between languages in voice chat
- [ ] **T-151**: In-game overlay — transparent overlay with voice controls, chat, FPS/ping via Rust DirectX/Vulkan hooks
- [ ] **T-152**: Local streaming — stream screen to a channel within OwnCord, LAN-optimized, LiveKit-based
- [ ] **T-153**: Chat summarization — AI-powered "catch up" on missed messages, local model or optional cloud
---
## Code & Security Review — 2026-04-01
Full codebase review across 4 sections: Server Core, Server Realtime, Client & Tauri, Security.
Reviewed by 4 parallel agents. Findings deduplicated and prioritized below.
### CRITICAL (P0) — Must Fix
- [x] **T-241:** Fix hub panic recovery loop — added `h.Stop()` in defer when `panicCount >= 3` — 2026-04-01
- [x] **T-242:** Fix ring buffer `EventsSince` replay — returns non-nil empty slice instead of nil — 2026-04-01
- [x] **T-243:** Fix PTT event listener leak — stores unsubscribe handle, calls it in `stopPtt()` and before re-init — 2026-04-01
- [x] **T-244:** Fix `verifyTotp` hardcoded `acceptInvalidCerts: true` — now respects `config.allowSelfSigned` — 2026-04-01
- [x] **T-245:** Fix `ptt_listen_for_key` blocking Tauri thread pool — moved to `tokio::task::spawn_blocking` — 2026-04-01
### HIGH (P1) — Fix Before Release
**Server Core:**
- [x] **T-246:** Fix TOTP rate-limit slot consumed before body decode — moved limiter check after body decode — 2026-04-01
- [x] **T-247:** Fix TOTP dual rate-limit counters — added `limiter.Reset(totpKey)` on successful verification — 2026-04-01
- [x] **T-248:** Fix TOTP enable allows silent secret rotation — returns 409 if `TOTPSecret` already set — 2026-04-01
- [x] **T-249:** Fix global search leaks restricted channel content — pre-computes accessible channel IDs for FTS WHERE clause — 2026-04-01
- [x] **T-250:** Fix `DeleteAccount` hard-coded role IDs — queries roles by name instead of ID — 2026-04-01
- [x] **T-251:** Fix `BackupToSafe` relative path — uses `absClean` in allowlist check and VACUUM INTO — 2026-04-01
**Server Realtime:**
- [x] **T-252:** Fix voice join camera slot TOCTOU — atomic `EnableCameraIfUnderLimit` DB method with conditional UPDATE — 2026-04-01
- [x] **T-253:** Fix readPump replaced-connection TOCTOU — snapshots voiceChID before unregister, guards handleVoiceLeave — 2026-04-01
- [x] **T-254:** Fix voice join sets state before token — moved `setVoiceState` after token send, rollback takes broadcast flag — 2026-04-01
- [x] **T-255:** Fix updater `downloadFile` overflow — uses probe pattern like storage.Save — 2026-04-01
- [x] **T-256:** Fix LiveKit webhook reads body before auth — checks Authorization header first — 2026-04-01
- [x] **T-257:** Fix `storage.Save` fsync + double close — added `f.Sync()`, used closed flag to prevent double close — 2026-04-01
**Client & Tauri:**
- [x] **T-258:** Fix WS event race — generation counter discards stale events from previous connections — 2026-04-01
- [x] **T-259:** Fix AudioWorklet load race — pipeline generation counter guards stale `.then()` callbacks — 2026-04-01
- [x] **T-260:** Fix screenshare mute state lost on reconnect — only clears mute map in full `leaveVoice()`, not reconnect — 2026-04-01
- [x] **T-261:** Fix `handleVoiceToken` unbounded recursion — replaced with iterative `while (pendingJoin)` loop — 2026-04-01
- [x] **T-262:** Fix `store.ts` re-entrant setState — added updating guard with pending queue — 2026-04-01
- [x] **T-263:** Fix notification AudioContext leak — exported `cleanupNotificationAudio()`, called on logout — 2026-04-01
**Security:**
- [x] **T-264:** SEC: Fix default WS origin — empty `allowedOrigins` now denies cross-origin (safe default) — 2026-04-01
### MEDIUM (P2) — Fix When Possible
**Server Core:**
- [ ] **T-265:** Fix `handleDeleteAccount` lockout key allows DoS — attacker with stolen token sends 3 bad passwords to lock out legitimate deletion. Consider IP+userID key — `Server/api/auth_handler.go:452-488`
- [ ] **T-266:** Fix `handleUpload` leaks internal storage error details in 400 response — log raw error, return generic message — `Server/api/upload_handler.go:117-124`
- [ ] **T-267:** Document `handleServeFile` intentional `Cache-Control` override of global `no-store` header — `Server/api/upload_handler.go:203`
- [ ] **T-268:** Fix `parseBooleanSettingValue` blocks all logins on typo — log warning and return safe default instead of 500 — `Server/api/auth_handler.go:575-584`
- [ ] **T-269:** Fix `handleCloseDM` raw JSON via `fmt.Sprintf` — use typed struct + `json.Marshal``Server/api/dm_handler.go:216`
- [ ] **T-270:** Fix rate limiter timestamps slice never shrinks memory — periodically replace with new slice — `Server/auth/ratelimit.go:60-65`
**Server Realtime:**
- [ ] **T-271:** Fix `wrapWithSeq` produces invalid JSON `{"seq":N,}` for empty objects — handle `msg == "{}"` case — `Server/ws/hub.go:446-458`
- [ ] **T-272:** Fix `handleReconnect` registers client before `writePump` starts — messages queued in 256-buffer can overflow under burst — `Server/ws/serve.go:119-127`
- [ ] **T-273:** Fix `handleChatEdit` permission check inconsistency — checks `SendMessages` only, inconsistent with delete handler's `ManageMessages || isOwner``Server/ws/handlers_chat.go:281-288`
- [ ] **T-274:** Fix stale voice sweep broadcasts `voice_leave` to all clients including those who never saw the join — `Server/ws/hub.go:533-535`
- [ ] **T-275:** Fix LiveKit YAML credential sanitization incomplete — expand blocklist to include `>`, `|`, `!`, `%` or use proper YAML library — `Server/ws/livekit_process.go:82-108`
- [ ] **T-276:** Fix updater `CheckForUpdate` cache stampede — multiple goroutines call `fetchLatestRelease` concurrently. Use `singleflight.Group``Server/updater/updater.go:121-152`
**Client & Tauri:**
- [ ] **T-277:** Fix WS dedup cache unreliable eviction — single-entry Set eviction under flood loses coverage. Use bounded LRU — `Client/tauri-client/src/lib/ws.ts:204-207`
- [ ] **T-278:** Fix `AudioPipeline.setupAudioPipeline``source` node not stored/disconnected on teardown — `Client/tauri-client/src/lib/audioPipeline.ts:89-138`
- [ ] **T-279:** Refactor `verifyTotp` to use `doFetch` instead of duplicating fetch logic — `Client/tauri-client/src/lib/api.ts:208-249`
- [ ] **T-280:** Fix `prependMessages` `hasMore` wrong when channel has exactly MAX+1 messages — `Client/tauri-client/src/lib/stores/messages.store.ts:170-183`
- [ ] **T-281:** Fix `DeviceManager` fallback unmutes user silently — check `localMuted` before re-enabling mic on device removal — `Client/tauri-client/src/lib/deviceManager.ts:87-93`
- [ ] **T-282:** Fix PTT `initPtt` double listener race — set `listening = true` before first await, or use promise lock — `Client/tauri-client/src/lib/ptt.ts:47-75`
- [ ] **T-283:** Fix `ws_disconnect` asymmetric cleanup — proxy loop exit leaves `inner.port` stale — `Client/tauri-client/src-tauri/src/livekit_proxy.rs:297-315`
**Security:**
- [ ] **T-284:** SEC: Add per-username login failure tracking to complement per-IP tracking — `Server/api/auth_handler.go:306`
- [ ] **T-285:** SEC: Lower login route-level rate limit from 60/min to 10/min — `Server/api/auth_handler.go:76`
- [ ] **T-286:** SEC: Add admin role hierarchy check — prevent non-owner admins from assigning Owner role — `Server/admin/handlers_users.go:100`
- [ ] **T-287:** SEC: Add MIME type allowlist for served files — prevents stored XSS via upload in browser contexts — `Server/api/upload_handler.go:104`
- [ ] **T-288:** SEC: Bind partial tokens to IP address — `Server/api/totp_handler.go:89`
- [ ] **T-289:** SEC: Add per-user session cap — no limit on concurrent sessions currently — `Server/db/auth_queries.go:184`
- [ ] **T-290:** SEC: Add WS message flood limit — no per-client message rate enforcement in hub — `Server/ws/serve.go:201`
- [ ] **T-291:** SEC: Sanitize error messages in update handler response — `Server/admin/update_handlers.go:44`
- [ ] **T-292:** SEC: Review config startup logging for secrets exposure — `Server/config/config.go:231`
### LOW (P3) — Nice to Have
- [ ] **T-293:** Add max bound to invite `ExpiresInHours` (cap at 8760 = 1 year) — `Server/api/invite_handler.go:72-75`
- [ ] **T-294:** Propagate `context.Context` through `GetServerStats` (6 sequential queries without cancellation) — `Server/db/admin_queries.go:27-54`
- [ ] **T-295:** Document lock ordering invariant (`hub.mu``c.mu`) at top of `hub.go``Server/ws/hub.go`
---
## Task Summary
| Phase | Focus | Tasks | Priority | Status |
|-------|-------|-------|----------|--------|
| 1-7 | Stabilization (original) | 37 | P0-P3 | All done |
| Audit | Security + code quality (2026-03-29) | 8 done | P1 | All done |
| PM-18 | Project Map Dashboard Enhancements | 38 | P2 | Pending |
| Deferred | Pre-roadmap features | 11 | P2-P3 | Pending |
| R1 | Community Essentials | 5 | P2 | Pending |
| R2 | Gaming DNA (Xfire) | 5 | P2 | Pending |
| R3 | Voice Power Features | 4 | P2 | Pending |
| R4 | LAN Party Toolkit | 5 | P3 | Pending |
| R5 | Platform & Extensibility | 6 | P3 | Pending |
| R6 | Future Vision | 5 | P4 | Pending |
| Review | Code & Security Review (2026-04-01) | 55 | P0-P3 | Pending |
| **Total new** | | **134 tasks** | |
Recommended order for PM phases: PM-8 (quick wins) → PM-1 → PM-5 → PM-4 → PM-2 → PM-3 → PM-7 → PM-6.
Recommended order for features: Deferred (quick wins) → R1 → R2 → R3 → R4 → R5 → R6.
Within each phase, tasks are independent and can be parallelized.
---
## Client Full Review — 2026-04-01
4-agent parallel review (security, code quality, bugs, architecture).
Findings below are NEW items not already tracked in the 2026-04-01 server+client review above.
### CRITICAL (P0) — Must Fix
- [ ] **T-382:** Fix BUG-082 — Remove `devtools` from default Cargo features; use `cfg(debug_assertions)` gate — `src-tauri/Cargo.toml:15`, `src-tauri/src/commands.rs:145-152`
- [ ] **T-383:** Fix BUG-076 — Add ref count decrement in drag-reorder cleanup; abort controller when count hits 0 — `src/components/channel-sidebar/drag-reorder.ts:26-31`
- [ ] **T-384:** Fix BUG-077 — Add null guard before `connect(config!)` in WS reconnect — `src/lib/ws.ts:154`
### HIGH (P1) — Fix Before Release
**Security:**
- [ ] **T-385:** SEC: Make HTTP `dangerous-settings` opt-in per-request — Remove from `Cargo.toml` default, pass cert settings per-request instead of globally — `src-tauri/Cargo.toml:25`, `src/lib/api.ts:94`
- [ ] **T-386:** SEC: Add HTTP certificate pinning — Extend TOFU fingerprint store to cover REST API / file upload calls, not just WebSocket — `src/lib/api.ts:81-107`
- [ ] **T-387:** SEC: Add WebSocket message authentication — Sign/HMAC critical message types to prevent injection via compromised proxy — `src/lib/ws.ts:165-241`
**Bugs:**
- [ ] **T-388:** Fix BUG-078 — Add abort check after room creation in LiveKit reconnect; wrap in try/finally — `src/lib/livekitSession.ts:350-397`
- [ ] **T-389:** Fix BUG-079 — Call `removeAutoplayUnlock()` in all voice cleanup paths, not just `handleDisconnected``src/lib/livekitSession.ts:280-308`
- [ ] **T-390:** Fix BUG-080 — Clear both `intervalId` and `qualityDebounceTimer` in connection stats cleanup — `src/lib/connectionStats.ts:130-192`
- [ ] **T-391:** Fix BUG-081 — Call `stopVadPolling()` at start of `teardownAudioPipeline()``src/lib/audioPipeline.ts:30,315,345`
**Code Quality:**
- [ ] **T-392:** Add logging to ~20 silent catch blocks in message-list components — `src/components/message-list/media.ts:46,85,150,204`, `attachments.ts:59,101,132,157,172`, `embeds.ts:152,220,247,319`
- [ ] **T-393:** Replace 2 unsafe `as any` casts with proper types — `src/lib/audioPipeline.ts:75` (LiveKit processor), `src/lib/livekitSession.ts:103` (pendingJoin)
### MEDIUM (P2) — Fix When Possible
**Code Quality:**
- [ ] **T-394:** Split `livekitSession.ts` further — Still 1,293 lines after T-184 reduction. Extract `VoiceChannelManager` and `TrackManager` sub-modules (~430 lines each)
- [ ] **T-395:** Split `SidebarArea.ts` (919 lines) and `ChannelSidebar.ts` (864 lines) — Extract sub-components: `SidebarHeader`, `ChannelSidebarManager`, `DmSidebarManager`
- [ ] **T-396:** Fix array mutations in store updates — Use spread operator instead of `.push()``src/stores/channels.store.ts:169`, `src/stores/members.store.ts:168-171`
- [ ] **T-397:** Standardize error narrowing — Replace bare `catch { }` with `catch (err: unknown)` across codebase — `src/main.ts:160,198`, `src/lib/api.ts:152`, others
**Security:**
- [ ] **T-398:** SEC: Tighten settings key validation — Replace prefix allowlist with explicit key allowlist — `src-tauri/src/commands.rs:21-29`
**Bugs (Potential):**
- [ ] **T-399:** Fix AdminActions context menu listener leaks — Add `signal` parameter to `addEventListener` calls — `src/components/AdminActions.ts:63,104,107`
- [ ] **T-400:** Fix unhandled promise in image fetch — Add `.catch()` to `fetchImageAsDataUrl` void call — `src/components/message-list/attachments.ts:323-326`
### LOW (P3) — Nice to Have
- [ ] **T-401:** Replace PTT polling (254 keys per 20ms) with `SetWindowsHookEx` WH_KEYBOARD_LL for efficiency — `src-tauri/src/ptt.rs:36-50`
- [ ] **T-402:** Add client unit test infrastructure — Currently 0 unit tests; add initial coverage for stores, lib/api.ts, lib/ws.ts
- [ ] **T-403:** Add IPC command rate limiting in Tauri backend — Prevent renderer spam of expensive commands — `src-tauri/src/lib.rs`
---
## Server Deep Review — 2026-04-01
Full server review by 3 parallel agents: security, code quality, bug hunt.
Findings: 2 CRITICAL security, 5 HIGH security, 6 HIGH bugs, 4 MEDIUM bugs, 12 MEDIUM quality, 7 MEDIUM security, 5 LOW security, 8 LOW quality.
### P0 — Bugs (HIGH) — Fix Immediately
- [ ] **T-404:** Fix BUG-084 — broadcast filter silently drops messages for clients with `channelID==0` (no `channel_focus` sent) — `Server/ws/hub.go:562`
- [ ] **T-405:** Fix BUG-085 — ring buffer `EventsSince` off-by-one: oldest boundary event dropped on reconnect. Change `<` to `<=``Server/ws/ringbuffer.go:54`
- [ ] **T-406:** Fix BUG-086 — `leaveVoiceChannelWithRetry` goroutine has no context/cancellation, leaks on hub stop — `Server/ws/voice_leave.go:71-93`
- [ ] **T-407:** Fix BUG-087 — `GracefulStop` not idempotent, `lkProcess.Stop()` called twice on concurrent shutdown. Wrap in `sync.Once``Server/ws/hub.go:213-234`
- [ ] **T-408:** Fix BUG-088 — voice channel capacity check unreliable during channel switch when DB leave fails — `Server/ws/voice_join.go:74-98`
- [ ] **T-409:** Fix BUG-089 — `go RemoveParticipant` goroutine in `handleFreshConnect` races with `registerNow` voice state transfer — `Server/ws/serve.go:153`
### P0 — Security (CRITICAL) — Fix Immediately
- [ ] **T-410:** SEC: Make `BackupTo` unexported or accept `time.Time` only — exported function with raw string path is SQL injection risk for future callers — `Server/db/admin_queries.go:369`
- [ ] **T-411:** SEC: Add localhost fallback for LiveKit webhook CIDR — empty `AdminAllowedCIDRs` exposes webhook to public internet — `Server/api/middleware.go:255-257`
### P1 — Security (HIGH) — Fix Before Release
- [ ] **T-412:** SEC: Block SVG/HTML uploads or force `Content-Disposition: attachment` — stored XSS via malicious SVG — `Server/storage/storage.go` + `Server/api/upload_handler.go:202`
- [ ] **T-413:** SEC: Add rate limiting to TOTP confirmation endpoint — brute-forceable 6-digit code space — `Server/api/totp_handler.go:180-238`
- [ ] **T-414:** SEC: Add auth middleware to LiveKit proxy endpoint — unauthenticated WS connections accepted — `Server/api/livekit_proxy.go`
- [ ] **T-415:** SEC: Move GitHub token from config YAML to environment variable — plaintext secret in config file — `Server/config/config.go:31`
- [ ] **T-416:** SEC: Persist brute-force lockouts to SQLite — in-memory rate limiter wiped on restart — `Server/auth/ratelimit.go`
### P1 — Bugs (MEDIUM)
- [ ] **T-417:** Fix BUG-090 — `sanitizeFTSQuery` truncates at byte boundary, not rune boundary — invalid UTF-8 for multi-byte chars — `Server/db/message_queries.go:23`
- [ ] **T-418:** Fix rate limiter `Check` vs `Allow` window pruning divergence — overly aggressive rate limiting at boundary — `Server/api/totp_handler.go:70`
- [ ] **T-419:** Fix BUG-091 — updater `downloadFile` double-closes `*os.File` on error — unsafe on Windows — `Server/updater/updater.go:416`
- [ ] **T-420:** Fix `refreshSettingsLocked` called without lock in `NewHub` — latent data race if settings read before `Run()``Server/ws/hub.go:74`
### P2 — Security (MEDIUM)
- [ ] **T-421:** SEC: Add per-connection bandwidth throttle on WS — 1MB messages at rate limit = excessive data — `Server/ws/serve.go:38`
- [ ] **T-422:** SEC: Sanitize `handleLiveKitHealth` error details — leaks internal hostnames/ports to admin callers — `Server/api/router.go:237-256`
- [ ] **T-423:** SEC: Log warning when WS session token sent over plaintext (TLS off) — `Server/ws/serve.go:277-303`
- [ ] **T-424:** SEC: Add emoji length validation before DB insert — no cap on emoji string length — `Server/db/message_queries.go:149`
- [ ] **T-425:** SEC: Omit token hash from admin session listings — `Server/db/admin_queries.go:126`
- [ ] **T-426:** SEC: Tighten `data/` directory permissions from 0o755 to 0o700 — `Server/main.go:72`
- [ ] **T-427:** SEC: Add `Vary: Origin` header to file serving endpoint — CORS caching issue — `Server/api/upload_handler.go:205`
### P2 — Code Quality (MEDIUM)
- [ ] **T-428:** Extract `handleSearch` into `searchSingleChannel`/`searchAllChannels` helpers — 180 lines, 4+ nesting levels — `Server/api/channel_handler.go:261-441`
- [ ] **T-429:** Extract `generateAndSendVoiceToken` from `handleVoiceJoin` — 186 lines with 9 steps — `Server/ws/voice_join.go:32-186`
- [ ] **T-430:** Move `refreshSettingsLocked` to use `db.GetSetting()` instead of raw SQL — `Server/ws/hub.go:105-108`
- [ ] **T-431:** Add `slog.Warn` wrapper for `LogAudit` failures instead of `_ =``Server/api/auth_handler.go:212+`
- [ ] **T-432:** Extract DM participant authorization check into shared helper — copy-pasted in 3 REST handlers — `Server/api/channel_handler.go:170,470,558`
- [ ] **T-433:** Consolidate 4 voice control toggle handlers into table-driven `handleVoiceToggle``Server/ws/voice_controls.go`
- [ ] **T-434:** Add named constants for ring buffer size (1000), broadcast channel (256), login lockout (9) — `Server/ws/hub.go:68-69`
- [ ] **T-435:** Remove duplicate `ClearVoiceState` — identical to `LeaveVoiceChannel``Server/db/voice_queries.go:82,217`
---
## Deep Research Pass 3 — Beyond Linters & Checkers (2026-04-01)
Tools that find bugs linters fundamentally cannot. Full research report: `docs/research/deep-research-pass3-beyond-linters.md`
### Phase 1 — Done (2026-04-01)
- [x] **T-436:** Add goleak goroutine leak detection — `TestMain` in all 9 test packages — 2026-04-01
- [x] **T-437:** Add go-deadlock detection — `syncutil/` package with build-tagged mutex shims, updated 8 files (13 mutexes), CI step with `-tags deadlock` — 2026-04-01
### Phase 2 — Go Native Fuzzing (HIGH, low effort)
- [ ] **T-438:** Write `Fuzz*` tests for WS message handlers — target `ws/handlers.go` (main dispatch), `handlers_chat.go`, `handlers_presence.go`, `handlers_reaction.go`, `voice_controls.go` — find panics/nil derefs from malformed input
- [ ] **T-439:** Write `Fuzz*` tests for REST API JSON parsers — target `api/auth_handler.go`, `dm_handler.go`, `profile_handler.go`, `totp_handler.go`, `invite_handler.go`, `upload_handler.go`
- [ ] **T-440:** Add fuzz CI step — `go test -fuzz=Fuzz -fuzztime=30s` per package in `.github/workflows/ci.yml` (or separate scheduled workflow)
### Phase 3 — Authorization Matrix Testing (CRITICAL)
- [ ] **T-441:** Write table-driven authz matrix tests — exhaustive role/endpoint permutations for all REST endpoints (admin vs member vs guest vs unauthenticated) — `Server/api/authz_matrix_test.go`
- [ ] **T-442:** Write WS authz matrix tests — verify members can't perform admin-only WS operations (channel create/delete, kick, ban) — `Server/ws/authz_matrix_test.go`
### Phase 4 — Mutation Testing (HIGH)
- [ ] **T-443:** Add go-gremlins mutation testing — `.gremlins.yaml` config targeting ws/, api/, auth/, db/ packages. Separate weekly CI workflow `.github/workflows/mutation.yml`
- [ ] **T-444:** Add Stryker mutation testing for client — `stryker.config.mjs`, run against Vitest suite. Add to weekly mutation workflow
### Phase 5 — Protocol Contract Testing (HIGH)
- [ ] **T-445:** Formalize WebSocket protocol schema — expand `docs/protocol-schema.json` to full JSON Schema for all 40 message types. Add Go contract test (`ws/contract_test.go`) and Vitest contract test. Add Zod runtime validation on client
### Phase 6 — Load & Chaos Testing (MEDIUM-HIGH)
- [ ] **T-446:** Add k6 WebSocket load tests — `Server/scripts/k6/ws-load.js` simulating 500 concurrent users: connect, auth, send, receive. Manual-trigger CI workflow
- [ ] **T-447:** Add toxiproxy chaos tests — integration tests for reconnection/replay buffer under network faults (latency, drops, resets). Build-tagged `//go:build integration`
### Phase 7 — Defense in Depth (MEDIUM)
- [x] **T-448:** Add Coraza WAF middleware — embed `corazawaf/coraza/v3` as chi middleware with OWASP CRS rules. Config toggle `waf_enabled` + `waf_paranoia_level` — 2026-04-01
- [ ] **T-449:** Tauri security audit — audit CSP in `tauri.conf.json`, check `withGlobalTauri`, scope HTTP permissions, validate IPC command inputs. Write report to `docs/security/tauri-audit.md`
- [ ] **T-450:** Tauri production capability hardening — create tightened `capabilities/production.json`, restrict `connect-src`/HTTP permissions to configured server URL only
---
## Mutation Testing — Surviving Mutants (2026-04-01)
Stryker mutation testing results. Files below 60% mutation score need
additional tests to kill surviving mutants. LiveKit/browser-API files
require deeper SDK mocking.
### P1 — High Survivor Count (170+ mutants)
- [ ] **T-451:** Kill surviving mutants in `livekitSession.ts` (25.88%, 170 survivors) — largest gap. Needs deep LiveKit SDK mocking: Room, LocalParticipant, RemoteParticipant, Track lifecycle. Focus on voice join/leave, camera toggle, reconnect, and cleanup paths — `src/lib/livekitSession.ts`
### P2 — Medium Survivor Count (14-44 mutants)
- [ ] **T-452:** Kill surviving mutants in `media-visibility.ts` (52.63%, 44 survivors) — IntersectionObserver-dependent. Mock observer callbacks, test visibility transitions, lazy-load triggers — `src/lib/media-visibility.ts`
- [ ] **T-453:** Kill surviving mutants in `streamPreview.ts` (55.37%, 37 survivors) — LiveKit video track preview. Mock track attach/detach, element creation, thumbnail rendering — `src/lib/streamPreview.ts`
- [ ] **T-454:** Kill surviving mutants in `screenShare.ts` (9.68%, 30 survivors) — Needs getDisplayMedia mock, track lifecycle, screenshare toggle, and spotlight view logic — `src/lib/screenShare.ts`
- [ ] **T-455:** Kill surviving mutants in `safe-render.ts` (54.84%, 14 survivors) — DOM rendering edge cases, sanitization guards, fallback rendering — `src/lib/safe-render.ts`
### P3 — Low Survivor Count (6-7 mutants, mostly no-coverage)
- [ ] **T-456:** Kill surviving mutants in `roomEventHandlers.ts` (8.08%, 7 survivors) — LiveKit room event callbacks. Mock Room.on() events: participantConnected/Disconnected, trackSubscribed/Unsubscribed — `src/lib/roomEventHandlers.ts`
- [ ] **T-457:** Kill surviving mutants in `livekitDiagnostics.ts` (3.19%, 6 survivors) — LiveKit diagnostics. Mock preflight checks, network quality indicators — `src/lib/livekitDiagnostics.ts`
### Completed (2026-04-01)
- [x] **notifications.ts** — improved 39.36% → 79.79% (+40.43%) — 32 tests added
- [x] **audioPipeline.ts** — improved 53.61% → 64.43% (+10.82%) — 61 tests added
- [x] **ws.ts** — improved 46.67% → 50.39% (+3.72%) — 50 tests added
-51
View File
@@ -1,51 +0,0 @@
# In Progress
Tasks currently being worked on.
## Active
*No tasks currently in progress.*
## Completed This Session (2026-04-01)
- [x] **T-438:** Install & configure mutation testing tools (Stryker + go-gremlins)
- Stryker config at `Client/tauri-client/stryker.config.mjs`
- go-gremlins config at `Server/.gremlins.yaml`
- npm scripts: `test:mutate`, `test:mutate:dry`
- Added to TESTING-STRATEGY.md Section 15
- [x] **T-439:** Install & configure k6 WebSocket load testing
- Script at `Server/scripts/k6/ws-load.js`
- Added to CLAUDE.md build commands
- [x] **T-440:** Install & configure toxiproxy chaos testing
- Script at `Server/scripts/toxiproxy/chaos-test.sh`
- Added to CLAUDE.md build commands
- [x] **T-441:** Install & configure Coraza WAF (OWASP CRS middleware)
- Config fields: `server.waf_enabled`, `server.waf_paranoia_level`
- Code at `Server/api/waf.go` (opt-in via config)
- Added to Server-Configuration.md
- [x] **T-442:** Add Zod runtime schema validation
- Installed via npm, already in package.json
- [x] **T-443:** Fix IPv6 loopback detection in livekitSession.ts
- `::1` loopback now handled correctly in `resolveLiveKitUrl`
- [x] **T-444:** Fix Go migration split statements for CREATE TRIGGER
- `splitStatements` now handles multi-line `BEGIN...END` blocks
- [x] **T-445:** Resolve all 57 oxlint warnings → 0
- `.sort()``.toSorted()`
- `.reverse()``.toReversed()`
- Event listener fixes, no-await-in-loop fixes, etc.
- [x] **T-446:** Add 182 new tests (2,962 → 3,144 total)
- Key files: ws.ts, notifications.ts, audioPipeline.ts, livekitSession.ts
- [x] **T-447:** Documentation updates for all new tools
- Updated CLAUDE.md with new commands
- Created Testing-Tools.md guide
- Updated TESTING-STRATEGY.md with mutation section
- Updated Server-Configuration.md with WAF config
## Queued (Not Yet Started)
### Test Coverage Session 1 (remaining)
- API upgrades: auth_handler, channel_handler, dm_handler, invite_handler, upload_handler, middleware, contract edge cases
- Auth upgrades: password, ratelimit, session, totp, tls edge cases
- DB missing: invite_queries_test.go, role_queries_test.go
- DB upgrades: message_queries, channel_queries, dm_queries, migrate
- Config upgrades: env overrides, malformed YAML
File diff suppressed because it is too large Load Diff
@@ -1,154 +0,0 @@
# Server Configuration Reference
## Overview
OwnCord server reads configuration from `config.yaml` in the working directory.
On first run, if the file does not exist, a default `config.yaml` is created automatically.
Configuration is loaded in three layers (later layers override earlier ones):
1. **Built-in defaults** (compiled into the binary)
2. **YAML file** (`config.yaml`)
3. **Environment variables** (prefix: `OWNCORD_`)
## Config Key Reference
### Server (`server`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `server.port` | int | `8443` | HTTP(S) listen port |
| `server.name` | string | `"OwnCord Server"` | Server display name (shown in `/api/v1/info` and admin panel) |
| `server.data_dir` | string | `"data"` | Directory for database, certs, uploads, backups |
| `server.allowed_origins` | string[] | `["*"]` | WebSocket CORS allowed origins; restrict in production |
| `server.trusted_proxies` | string[] | `[]` | CIDRs of trusted reverse proxies (for X-Forwarded-For) |
| `server.admin_allowed_cidrs` | string[] | private networks | CIDRs allowed to access `/admin` routes. Default: `127.0.0.0/8`, `::1/128`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7` |
### TLS (`tls`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `tls.mode` | string | `"self_signed"` | TLS mode: `self_signed`, `acme`, `manual`, `off` |
| `tls.cert_file` | string | `"data/cert.pem"` | Path to TLS certificate (used by `manual` and `self_signed`) |
| `tls.key_file` | string | `"data/key.pem"` | Path to TLS private key |
| `tls.domain` | string | `""` | Domain for ACME/Let's Encrypt (required when `mode: acme`) |
| `tls.acme_cache_dir` | string | `"data/acme_certs"` | Directory for cached Let's Encrypt certificates |
### Database (`database`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `database.path` | string | `"data/chatserver.db"` | Path to SQLite database file |
### Uploads (`upload`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `upload.max_size_mb` | int | `100` | Maximum file upload size in megabytes |
| `upload.storage_dir` | string | `"data/uploads"` | Directory where uploaded files are stored |
### Voice / LiveKit (`voice`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `voice.livekit_api_key` | string | *(random per run)* | LiveKit API key. Set a stable value in config for persistent voice tokens. |
| `voice.livekit_api_secret` | string | *(random per run)* | LiveKit API secret (min 32 chars). Set a stable value for persistent tokens. |
| `voice.livekit_url` | string | `"ws://localhost:7880"` | LiveKit server WebSocket URL |
| `voice.livekit_binary` | string | `""` | Path to `livekit-server` binary; empty = don't auto-start |
| `voice.node_ip` | string | `""` | Public IP for WebRTC ICE candidates; empty = auto-detect. Required for remote users behind NAT. |
| `voice.quality` | string | `"medium"` | Voice quality preset: `low`, `medium`, `high` |
> **Warning:** If `livekit_api_key` or `livekit_api_secret` are left empty, random credentials are generated on each startup. This means voice tokens break on restart. Always set stable credentials in production. See [[08-Guides/LiveKit-Setup]] for details.
### GitHub / Updates (`github`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `github.token` | string | `""` | Optional GitHub API token for higher rate limits on update checks (5000 req/hr vs 60) |
### Security / WAF (`server`)
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `server.waf_enabled` | bool | `false` | Enable Coraza WAF (OWASP CRS middleware) |
| `server.waf_paranoia_level` | int | `2` | OWASP CRS paranoia level (14); higher = stricter rules but more false positives |
## Environment Variable Overrides
Every config key can be overridden via environment variables using the prefix `OWNCORD_`.
**Format:** `OWNCORD_<SECTION>_<KEY>`
The first underscore after `OWNCORD_` separates the section from the key. Underscores within key names are preserved.
| Environment Variable | Config Path |
|---------------------|-------------|
| `OWNCORD_SERVER_PORT` | `server.port` |
| `OWNCORD_SERVER_NAME` | `server.name` |
| `OWNCORD_SERVER_DATA_DIR` | `server.data_dir` |
| `OWNCORD_DATABASE_PATH` | `database.path` |
| `OWNCORD_TLS_MODE` | `tls.mode` |
| `OWNCORD_TLS_CERT_FILE` | `tls.cert_file` |
| `OWNCORD_TLS_DOMAIN` | `tls.domain` |
| `OWNCORD_UPLOAD_MAX_SIZE_MB` | `upload.max_size_mb` |
| `OWNCORD_UPLOAD_STORAGE_DIR` | `upload.storage_dir` |
| `OWNCORD_VOICE_LIVEKIT_API_KEY` | `voice.livekit_api_key` |
| `OWNCORD_VOICE_LIVEKIT_API_SECRET` | `voice.livekit_api_secret` |
| `OWNCORD_VOICE_LIVEKIT_URL` | `voice.livekit_url` |
| `OWNCORD_VOICE_NODE_IP` | `voice.node_ip` |
| `OWNCORD_VOICE_QUALITY` | `voice.quality` |
| `OWNCORD_GITHUB_TOKEN` | `github.token` |
| `OWNCORD_SERVER_WAF_ENABLED` | `server.waf_enabled` |
| `OWNCORD_SERVER_WAF_PARANOIA_LEVEL` | `server.waf_paranoia_level` |
## Example config.yaml
```yaml
# OwnCord Server Configuration
server:
port: 8443
name: "OwnCord Server"
data_dir: "data"
allowed_origins: ["*"] # restrict in production, e.g. ["https://chat.example.com"]
trusted_proxies: [] # e.g. ["10.0.0.0/8"] if behind a reverse proxy
admin_allowed_cidrs: # CIDRs allowed to reach /admin
- "127.0.0.0/8"
- "::1/128"
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
database:
path: "data/chatserver.db"
tls:
mode: "self_signed" # self_signed | acme | manual | off
cert_file: "data/cert.pem"
key_file: "data/key.pem"
domain: "" # required for acme mode
acme_cache_dir: "data/acme_certs"
upload:
max_size_mb: 100
storage_dir: "data/uploads"
voice:
livekit_api_key: "your-api-key"
livekit_api_secret: "your-secret-at-least-32-characters-long"
livekit_url: "ws://localhost:7880"
livekit_binary: "" # path to livekit-server binary; empty = don't auto-start
node_ip: "" # public IP for remote users behind NAT
quality: "medium" # low | medium | high
github:
token: "" # optional GitHub PAT for update check rate limits
```
## See Also
- [[08-Guides/Deployment]] -- production deployment guide
- [[08-Guides/LiveKit-Setup]] -- voice/video setup
- [[08-Guides/quick-start]] -- getting started
---
Last verified: 2026-03-29
-316
View File
@@ -1,316 +0,0 @@
# Testing Tools Guide
This guide covers the mutation testing, load testing, and chaos testing tools
installed in the OwnCord project.
## Quick Reference
| Tool | Purpose | Config | Command |
|------|---------|--------|---------|
| **Stryker** | Client mutation testing | `stryker.config.mjs` | `npm run test:mutate` |
| **go-gremlins** | Server mutation testing | `.gremlins.yaml` | `go-gremlins mutate ./...` |
| **k6** | WebSocket load testing | `scripts/k6/ws-load.js` | `k6 run scripts/k6/ws-load.js` |
| **toxiproxy** | Chaos/network testing | `scripts/toxiproxy/chaos-test.sh` | `bash scripts/toxiproxy/chaos-test.sh` |
| **Coraza WAF** | OWASP security middleware | `server.waf_enabled` config | Optional; enable in `config.yaml` |
## Client: Stryker Mutation Testing
**Purpose:** Verify that your unit/integration tests actually catch bugs.
Stryker introduces small mutations into your TypeScript code and checks
if tests fail. Tests that don't catch mutations are "survivors."
### Installation
Already in `package.json` as dev dependency:
```bash
cd Client/tauri-client
npm install
```
### Configuration
File: `Client/tauri-client/stryker.config.mjs`
- Runs against all tests in `tests/unit/` and `tests/integration/`
- Uses vitest as the test runner
- Generates HTML and JSON reports
### Running Mutations
```bash
cd Client/tauri-client
# Full mutation testing (will take several minutes)
npm run test:mutate
# Dry run (checks what would be tested, no actual mutations)
npm run test:mutate:dry
```
### Understanding Results
After a run, open the HTML report:
```bash
# On Windows
start reports\mutation\index.html
# On Linux/macOS
open reports/mutation/index.html
```
**Key metrics:**
- **Killed**: Mutations that tests caught (good)
- **Survived**: Mutations that tests missed (investigate)
- **Timeout**: Mutation caused infinite loop
- **Compile error**: Mutation syntax was invalid (rare)
**Kill rate interpretation:**
- **>95%**: Excellent, tests are very thorough
- **80-95%**: Good, typical for mature projects
- **<80%**: Poor, tests may have gaps
### Investigating Survivors
A surviving mutation means tests don't cover that code path. Steps:
1. Find the mutation in the HTML report (file + line number)
2. Read the mutation details (what changed?)
3. Determine if this path is reachable
4. If reachable, add a test that kills this mutation
Example:
```typescript
// Original code
if (count > 0) {
console.log("positive");
}
// Mutation: > becomes >=
// Surviving mutation means no test with count === 0
```
## Server: go-gremlins Mutation Testing
**Purpose:** Same as Stryker, but for Go code. Mutates Go source
and runs `go test ./...` to check if tests catch the mutations.
### Installation
```bash
go install github.com/go-gremlins/gremlins/cmd/go-gremlins@latest
```
### Configuration
File: `Server/.gremlins.yaml`
Specifies which files to mutate and mutation settings.
### Running Mutations
```bash
cd Server
# Run full mutation testing
go-gremlins mutate ./...
# View JSON report
cat gremlins-report.json
```
### Mutation Types
go-gremlins applies mutations like:
- Boundary changes: `<``<=`, `>``>=`
- Logical operators: `&&``||`
- Assignment mutations: `x = y``x = 0`
- Arithmetic: `x + y``x - y`
See [go-gremlins docs](https://github.com/go-gremlins/gremlins) for full list.
## Load Testing: k6
**Purpose:** Stress-test the WebSocket server and HTTP API.
Simulates many concurrent clients sending messages.
### Installation
Download from [k6.io](https://k6.io/docs/get-started/installation/):
```bash
# On Windows (via chocolatey)
choco install k6
# On macOS
brew install k6
# On Linux
sudo apt-get install k6
```
### Configuration
File: `Server/scripts/k6/ws-load.js`
- Configurable VU (virtual users), duration, ramp-up, etc.
- Measures: response time, throughput, errors, WebSocket latency
### Running Load Tests
```bash
cd Server
# Run the default WebSocket load test
k6 run scripts/k6/ws-load.js
# With custom options
k6 run --vus 100 --duration 30s scripts/k6/ws-load.js
```
### Interpreting Results
Output shows:
- **http_req_duration**: Response time (ms)
- **http_reqs**: Total requests per second
- **errors**: Failed requests
- **ws_connecting**: WebSocket connection latency
Monitor for:
- High error rates (server instability)
- Increasing latency (saturation)
- Resource exhaustion (check server logs)
## Chaos Testing: toxiproxy
**Purpose:** Inject network faults (latency, packet loss, timeouts)
to verify reconnection and error handling logic.
### Installation
Download from [shopify/toxiproxy](https://github.com/shopify/toxiproxy):
```bash
# On Windows
# Download release from GitHub
# On macOS
brew install shopify/shopify/toxiproxy
# On Linux
# Download release from GitHub
```
### Configuration
File: `Server/scripts/toxiproxy/chaos-test.sh`
- Defines toxiproxy proxies (intercept server connections)
- Applies faults: latency, bandwidth limits, packet loss, timeouts
- Runs tests before/during/after fault injection
### Running Chaos Tests
```bash
cd Server
bash scripts/toxiproxy/chaos-test.sh
```
### Fault Scenarios
Common scenarios defined in the script:
1. **Latency injection**: Add 500ms delay to all packets
2. **Packet loss**: Drop 10% of packets
3. **Bandwidth throttle**: Limit to 1 Mbps
4. **Connection timeout**: Kill connections after inactivity
5. **Periodic disconnects**: Force reconnect every 30s
Watch for:
- Client reconnects successfully
- No data loss (seq numbers correct)
- Graceful fallback (no app crashes)
## Security: Coraza WAF
**Purpose:** Protect against OWASP top 10 attacks (SQL injection, XSS, etc.)
using OWASP CRS (Core Rule Set) rules.
### Configuration
Enable in `config.yaml`:
```yaml
server:
waf_enabled: true
waf_paranoia_level: 2
```
Or via environment variable:
```bash
OWNCORD_SERVER_WAF_ENABLED=true
OWNCORD_SERVER_WAF_PARANOIA_LEVEL=2
```
### Paranoia Levels
| Level | Coverage | False Positives | Recommended For |
|-------|----------|-----------------|-----------------|
| 1 | Basic | Very low | Production (default baseline) |
| 2 | Standard | Low | Production (balance) |
| 3 | Strict | Medium | Staging/QA |
| 4 | Paranoid | High | Testing only |
### Behavior
With WAF enabled:
- All HTTP requests are scanned against OWASP CRS rules
- Suspicious requests are blocked with HTTP 403
- Benign requests pass through
- Logs show rule violations
### Testing the WAF
Try a simple SQL injection attempt (should be blocked):
```bash
curl -X POST http://localhost:8443/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin\" OR \"1\"=\"1", "password": "test"}'
# Response: 403 Forbidden (if WAF enabled)
```
## Integration with CI
All mutation tests can run in CI pipelines:
```bash
# Client
npm run test:mutate
# Server
go-gremlins mutate ./...
# Load testing (optional, longer duration)
k6 run --vus 50 --duration 60s scripts/k6/ws-load.js
# Chaos testing (optional, requires toxiproxy)
bash scripts/toxiproxy/chaos-test.sh
```
## Next Steps
- See [[06-Specs/TESTING-STRATEGY|TESTING-STRATEGY.md]] for detailed test patterns
- See [[06-Specs/CHATSERVER|CHATSERVER.md]] for security rules (WAF context)
- See [[08-Guides/Server-Configuration|Server-Configuration.md]] for config details