docs: regenerate codemaps from current codebase

6 codemaps updated with accurate line counts, routes, WS message
types, schema, and test infrastructure from 203 scanned source files.
This commit is contained in:
jevb
2026-03-30 16:47:19 +02:00
parent 1a8938f525
commit e4bb54405b
6 changed files with 490 additions and 209 deletions
+39 -41
View File
@@ -1,57 +1,55 @@
<!-- Generated: 2026-03-20 | Files scanned: ~120 | Token estimate: ~800 -->
<!-- Generated: 2026-03-30 | Files scanned: 203 | Token estimate: ~750 -->
# OwnCord Architecture
# Architecture Overview
## System Overview
## System Components
```
+-------------------+ +-------------------+
| Tauri Client | WSS | Go Server |
| (Rust + TS) |--------->| (chatserver.exe) |
| | HTTPS | |
| livekit-client |---. | LiveKit SDK |
+-------------------+ | +-------------------+
| |
v v
+-------------------+
| LiveKit Server |
| (companion proc) |
+-------------------+
Tauri Client (Rust + TypeScript)
|
|-- WS Proxy (Rust) ----> Go Server :8443 (WS)
|-- HTTP (Tauri plugin) -> Go Server :8443 (REST /api/v1/*)
|-- LK Proxy (Rust) ----> LiveKit :7880 (via /livekit/* reverse proxy)
|
v
Go Server (chatserver.exe)
|-- chi router: REST API + WS upgrade + admin panel
|-- ws.Hub: real-time message dispatch, voice orchestration
|-- SQLite (db.DB): all persistent state
|-- LiveKit: companion process or external, voice/video media
|-- storage/: file uploads on disk
|-- updater/: client auto-update (GitHub releases)
```
## Data Flow
```
Client Server Storage
------ ------ -------
ConnectPage api/auth_handler.go SQLite (WAL)
login/register ─HTTP──> POST /api/v1/auth/* ──> users, sessions
<─token─
### REST (request/response)
`Client -> Tauri HTTP plugin -> Go chi router -> AuthMiddleware -> handler -> db.DB -> JSON response`
MainPage ws/serve.go
ws.connect() ─WSS──> ServeWS() → Hub.register
dispatcher.ts <─ready─ handlers.go dispatcher
├─ chat_send ──> messages, attachments
├─ voice_join ──> voice_states + LiveKit token
└─ presence ──> users.status
### WebSocket (bidirectional)
`Client -> Rust ws_proxy (TLS + TOFU) -> /api/v1/ws -> ws.ServeWS -> ws.Hub`
- Client sends: auth, chat_send, voice_join, etc. (17 client msg types)
- Server broadcasts: chat_message, presence, voice_state, etc. (27 server msg types)
- Reconnection: client sends last_seq, server replays from 1000-event ring buffer
livekitSession.ts ws/livekit.go
Room.connect() ─WebRTC─> GenerateToken(JWT)
<─media─> LiveKit SFU (companion)
```
### Voice/Video (LiveKit)
`Client -> Rust livekit_proxy -> /livekit/* reverse proxy -> LiveKit server :7880`
- Token issued via WS voice_join flow (24h TTL, 23h refresh)
- Webhook: LiveKit -> POST /api/v1/livekit/webhook -> ghost cleanup
## Key Boundaries
| Boundary | Protocol | Auth |
|----------|----------|------|
| Client ↔ Server REST | HTTPS | Bearer token |
| Client ↔ Server WS | WSS (via Rust proxy) | In-band `auth` message |
| Client ↔ LiveKit | WebRTC (via wss proxy) | JWT access token |
| Server ↔ LiveKit | gRPC/HTTP | API key + secret |
| Server ↔ SQLite | In-process | Single-writer WAL |
| Boundary | Mechanism |
|----------|-----------|
| Auth | Session tokens (SHA-256 hash in DB), 30-day TTL |
| 2FA | TOTP with partial_token (10min), 5-attempt limit |
| Rate limiting | Per-IP token bucket (auth.RateLimiter) |
| DM authz | IsDMParticipant check (not role-based) |
| Admin | IP CIDR restriction (AdminIPRestrict middleware) |
| Uploads | 10 MiB max, MIME allowlist, 1 MiB default body |
| TLS | Rust-side TOFU cert pinning (certs.json store) |
## Entry Points
- **Server:** `main.go` → config → TLS → DB → migrate → router → HTTP server
- **Client:** `main.ts` → router → ConnectPage (auth) → MainPage (app)
- **Server:** `main.go` -> config -> TLS -> DB -> migrate -> router -> HTTP server
- **Client:** `main.ts` -> router -> ConnectPage (auth) -> MainPage (app)
- **LiveKit:** Auto-started by `livekit_process.go` alongside chatserver
+100 -65
View File
@@ -1,79 +1,114 @@
<!-- Generated: 2026-03-20 | Files scanned: 35 | Token estimate: ~900 -->
<!-- Generated: 2026-03-30 | Files scanned: 203 | Token estimate: ~800 -->
# Backend Codemap (Go Server)
# Go Server Codemap
## HTTP Routes
## Source Stats
- 74 source files, ~14,528 lines (excluding tests)
- 58 test files
### Auth (rate-limited)
```
POST /api/v1/auth/register → handleRegister [3/min]
POST /api/v1/auth/login → handleLogin [5/min]
POST /api/v1/auth/logout → handleLogout [AUTH]
GET /api/v1/auth/me → handleMe [AUTH]
```
## REST Routes (api/)
### Channels & Messages
```
GET /api/v1/channels/ → handleListChannels [AUTH]
GET /api/v1/channels/{id}/messages → handleGetMessages [AUTH, paginated]
GET /api/v1/search?q= → handleSearch [AUTH, FTS5]
```
### Auth -- /api/v1/auth
| Method | Path | Handler | Rate Limit |
|--------|------|---------|------------|
| POST | /register | handleRegister | 3/min |
| POST | /login | handleLogin | 60/min |
| POST | /verify-totp | handleVerifyTOTP | 10/min |
| POST | /logout | handleLogout | auth |
| GET | /me | handleMe | auth |
| DELETE | /account | handleDeleteAccount | 5/min |
### Invites, Uploads
```
POST /api/v1/invites/ → handleCreateInvite [AUTH, MANAGE_INVITES]
GET /api/v1/invites/ → handleListInvites [AUTH, MANAGE_INVITES]
DELETE /api/v1/invites/{code} → handleRevokeInvite [AUTH, MANAGE_INVITES]
POST /api/v1/uploads → handleUpload [AUTH, max 100MB]
GET /api/v1/uploads/{id} → handleDownload [AUTH]
```
### TOTP -- /api/v1/users/me/totp
| Method | Path | Handler | Rate Limit |
|--------|------|---------|------------|
| POST | /enable | handleEnableTOTP | 5/min |
| POST | /confirm | handleConfirmTOTP | 5/min |
| DELETE | / | handleDisableTOTP | 5/min |
### WebSocket & LiveKit
```
GET /api/v1/ws → ServeWS() [upgrade, in-band auth]
POST /api/v1/livekit/webhook → LiveKit webhook [JWT verify]
WS /livekit/* → reverse proxy → :7880 [mixed-content fix]
```
### Channels -- /api/v1/channels (all auth-required)
| Method | Path | Handler |
|--------|------|---------|
| GET | / | handleListChannels |
| GET | /{id}/messages | handleGetMessages |
| GET | /{id}/pins | handleGetPins |
| POST | /{id}/pins/{msgId} | handleSetPinned(true) |
| DELETE | /{id}/pins/{msgId} | handleSetPinned(false) |
| GET | /api/v1/search | handleSearch (30/min) |
### Admin (/admin, IP-restricted)
```
GET /admin/stats, /users, /channels, /audit-log, /settings, /backups
POST /admin/channels, /backup, /updates/apply
GET /admin/logs/stream [WebSocket log viewer]
```
### DMs -- /api/v1/dms (auth)
| Method | Path | Handler |
|--------|------|---------|
| POST | / | handleCreateDM |
| GET | / | handleListDMs |
| DELETE | /{channelId} | handleCloseDM |
### Invites -- /api/v1/invites (auth + MANAGE_INVITES)
| Method | Path | Handler |
|--------|------|---------|
| POST | / | handleCreateInvite |
| GET | / | handleListInvites |
| DELETE | /{code} | handleRevokeInvite |
### Other Endpoints
| Method | Path | Handler | Access |
|--------|------|---------|--------|
| GET | /health, /api/v1/health | handleHealth | public |
| GET | /api/v1/info | handleInfo | public |
| GET | /api/v1/metrics | handleMetrics | admin IP |
| GET | /api/v1/diagnostics/connectivity | handleDiagnosticsConnectivity | auth |
| POST | /api/v1/uploads | MountUploadRoutes | auth |
| GET | /api/v1/files/{id} | handleServeFile | auth |
| POST | /api/v1/livekit/webhook | MountWebhookRoute | admin IP |
| GET | /api/v1/livekit/health | handleLiveKitHealth | admin IP |
| Handle | /livekit/* | NewLiveKitProxy | 30/min |
| GET | /api/v1/ws | ws.ServeWS | WS upgrade |
## Middleware Chain
```
RequestID → Recoverer → requestLogger → SecurityHeaders → MaxBodySize(1MB)
Per-route: AuthMiddleware, RequirePermission(bit), RateLimitMiddleware
Admin: AdminIPRestrict(allowedCIDRs)
```
`RequestID -> Recoverer -> requestLogger -> SecurityHeaders -> MaxBodySize(1MiB) -> [per-route: Auth, RateLimit, AdminIP]`
## WS Message Handlers (ws/handlers.go)
## WS Message Types (ws/message_types.go)
**Client -> Server (17):** auth, chat_send, chat_edit, chat_delete, reaction_add, reaction_remove, typing_start, channel_focus, presence_update, voice_join, voice_leave, voice_mute, voice_deafen, voice_camera, voice_screenshare, voice_token_refresh, ping
| Type | Handler | Rate | DB | Broadcast |
|------|---------|------|-----|-----------|
| chat_send | handleChatSend | 10/s | CreateMessage | channel |
| chat_edit | handleChatEdit | 10/s | EditMessage | channel |
| chat_delete | handleChatDelete | 10/s | DeleteMessage | channel |
| reaction_add/remove | handleReaction | 5/s | Add/RemoveReaction | channel |
| typing_start | handleTyping | 1/3s | — | channel (excl sender) |
| presence_update | handlePresence | 1/10s | UpdateUserStatus | all |
| voice_join | handleVoiceJoin | — | JoinVoice + GenToken | all |
| voice_leave | handleVoiceLeave | — | LeaveVoice | all |
| voice_mute/deafen | handleVoiceMute/Deafen | — | UpdateVoice* | all |
| voice_camera | handleVoiceCamera | 2/s | UpdateVoiceCamera | all |
## Key Files
**Server -> Client (27):** auth_ok, auth_error, ready, chat_message, chat_send_ok, chat_edited, chat_deleted, reaction_update, typing, presence, channel_create, channel_update, channel_delete, voice_state, voice_config, voice_token, voice_speakers, voice_leave, member_join, member_leave, member_update, member_ban, server_restart, error, pong, dm_channel_open, dm_channel_close
## Key Source Files
| File | Lines | Purpose |
|------|-------|---------|
| main.go | 291 | Entry, init, graceful shutdown |
| api/router.go | 198 | Route mounting, Hub + LiveKit init |
| api/middleware.go | 325 | Auth, permissions, rate limit, security headers |
| ws/hub.go | 303 | Client registry, broadcast, settings cache |
| ws/handlers.go | 522 | WS message dispatcher |
| ws/voice_handlers.go | 332 | Voice join/leave/mute/camera |
| ws/livekit.go | 170 | Token generation, room management |
| ws/livekit_process.go | 189 | LiveKit binary lifecycle |
| ws/livekit_webhook.go | 178 | LiveKit event processing |
| api/router.go | 312 | chi router, middleware stack, Hub/LiveKit init |
| api/auth_handler.go | 829 | register, login, 2FA, delete account |
| api/channel_handler.go | 576 | messages, pins, search |
| api/middleware.go | 348 | auth, rate limit, CORS, security headers |
| api/dm_handler.go | 225 | DM CRUD with real-time close broadcast |
| api/invite_handler.go | 173 | invite management |
| api/upload_handler.go | 195 | file upload/serve with MIME validation |
| api/livekit_proxy.go | 198 | reverse proxy for LiveKit signaling |
| ws/hub.go | 499 | client registry, broadcast, heartbeat sweep |
| ws/handlers.go | 185 | message dispatch switch |
| ws/handlers_chat.go | 355 | chat_send, chat_edit, chat_delete |
| ws/handlers_presence.go | 139 | presence_update, channel_focus |
| ws/handlers_reaction.go | 103 | reaction_add, reaction_remove |
| ws/serve.go | 385 | WS upgrade, in-band auth, ready, reconnect replay |
| ws/voice_join.go | 235 | LiveKit token generation, voice state |
| ws/voice_controls.go | 179 | mute, deafen, camera, screenshare |
| ws/voice_leave.go | 87 | voice disconnect cleanup |
| ws/livekit.go | 202 | LiveKit SDK wrapper |
| ws/livekit_process.go | 309 | companion process lifecycle |
| ws/livekit_webhook.go | 195 | participant_joined/left events |
| ws/ringbuffer.go | 78 | 1000-event replay buffer |
| ws/messages.go | 480 | all payload struct definitions |
| config/config.go | 296 | TOML config with env overrides |
| main.go | 336 | startup, TLS, graceful shutdown |
## DB Layer (db/)
| File | Lines | Tables |
|------|-------|--------|
| auth_queries.go | 434 | users, sessions, login_attempts |
| message_queries.go | 522 | messages, messages_fts, reactions |
| channel_queries.go | 243 | channels, channel_overrides, read_states |
| dm_queries.go | 286 | dm_participants, dm_open_state |
| voice_queries.go | 278 | voice_states |
| admin_queries.go | 374 | audit_log, settings, roles |
| attachment_queries.go | 156 | attachments |
| models.go | 198 | all Go struct definitions |
| migrate.go | 203 | 8 migrations, schema_versions tracking |
| errors.go | 33 | sentinel errors: ErrNotFound, ErrDuplicate, ErrForbidden |
+99 -37
View File
@@ -1,52 +1,114 @@
<!-- Generated: 2026-03-20 | Tables: 16 | Migrations: 7 | Token estimate: ~700 -->
<!-- Generated: 2026-03-30 | Files scanned: 203 | Token estimate: ~700 -->
# Data Codemap (SQLite)
# Data Layer Codemap
## Tables
## SQLite Schema (8 migrations)
| Table | PK | Key Columns | Indexes |
|-------|----|----|---------|
| roles | id | name, permissions (bitfield), position, is_default | — |
| users | id | username, password (bcrypt), role_id FK, status, banned, totp_secret | username UNIQUE |
| sessions | id | user_id FK, token, ip_address, expires_at | token UNIQUE |
| channels | id | name, type (text/voice), category, position, voice_max_users | — |
| channel_overrides | id | channel_id FK, role_id FK, allow/deny (bitfields) | (channel_id, role_id) |
| messages | id | channel_id FK, user_id FK, content, reply_to, deleted, pinned | (channel_id, id DESC) |
| messages_fts | rowid | FTS5 virtual table (content, channel_id) | — |
| attachments | id (UUID) | message_id FK, filename, stored_as, mime_type, size | — |
| reactions | id | message_id FK, user_id FK, emoji | (message_id, emoji) UNIQUE w/ user |
| voice_states | user_id | channel_id, muted, deafened, camera, screenshare, joined_at | — |
| invites | id | code UNIQUE, created_by FK, max_uses, use_count, expires_at | — |
| read_states | (user_id, channel_id) | last_message_id, mention_count | — |
| audit_log | id | actor_id, action, target_type, target_id, detail, created_at | (actor_id), (created_at DESC) |
| login_attempts | id | ip_address, username, success, timestamp | (ip_address, timestamp) |
| settings | key | value (JSON text) | — |
| emoji, sounds | id | Custom emoji/soundboard storage | — |
### Core Tables
**users** -- User accounts
| Column | Type | Notes |
|--------|------|-------|
| id | INTEGER PK | auto-increment |
| username | TEXT UNIQUE | COLLATE NOCASE, 2-32 runes |
| password | TEXT | bcrypt hash |
| avatar | TEXT | nullable, file ID |
| role_id | INTEGER FK | -> roles(id), default 4 (Member) |
| totp_secret | TEXT | nullable, TOTP seed |
| status | TEXT | online/idle/dnd/offline |
| banned, ban_reason, ban_expires | | ban system |
**roles** -- Permission roles (4 defaults)
| ID | Name | Permissions | Position |
|----|------|-------------|----------|
| 1 | Owner | 0x7FFFFFFF | 100 |
| 2 | Admin | 0x3FFFFFFF | 80 |
| 3 | Moderator | 0x000FFFFF | 60 |
| 4 | Member | 0x00000663 | 40 (default) |
**channels** -- Text + voice + DM channels
- type: "text" | "voice" | "dm"
- voice fields: voice_max_users, voice_quality, mixing_threshold, voice_max_video
**channel_overrides** -- Per-role allow/deny bitfields per channel
- UNIQUE(channel_id, role_id)
### Messaging Tables
**messages** -- Chat messages
- FK: channel_id -> channels, user_id -> users, reply_to -> messages
- Indexes: (channel_id, id DESC), (user_id)
**messages_fts** -- FTS5 virtual table for full-text search
- Triggers: messages_ai (insert), messages_ad (delete), messages_au (update)
**attachments** -- File uploads linked to messages
- id: TEXT PK (UUID), mime_type, size, width/height (images)
**reactions** -- Emoji reactions
- UNIQUE(message_id, user_id, emoji)
### Auth Tables
**sessions** -- Login sessions
- token (SHA-256 hash), device, ip, 30-day TTL
- Indexes: (token), (user_id)
**login_attempts** -- Brute-force tracking
- Index: (ip_address, timestamp)
### DM Tables (migration 008)
**dm_participants** -- DM channel membership
- PK: (channel_id, user_id)
- Index: (user_id)
**dm_open_state** -- Per-user DM visibility
- PK: (user_id, channel_id)
### Voice Table (migration 002)
**voice_states** -- Active voice connections
- PK: user_id, FK: channel_id
- muted, deafened, speaking, joined_at
- Index: (channel_id)
### Other Tables
| Table | Purpose |
|-------|---------|
| invites | Invite codes with max_uses, expiry, revocation |
| read_states | Per-user per-channel last_message_id + mention_count |
| audit_log | Admin action log (user_id, action, target, details) |
| settings | Key-value server config (schema_version, require_2fa, etc.) |
| emoji | Custom emoji (shortcode, filename) |
| sounds | Custom sound effects |
## Migration History
| # | File | Change |
|---|------|--------|
| 001 | initial_schema.sql | All base tables + FTS5 |
| 001 | initial_schema.sql | All base tables, FTS5, triggers, default roles |
| 002 | voice_states.sql | voice_states table |
| 003a | audit_log.sql | Canonicalize audit columns |
| 003b | voice_optimization.sql | camera/screenshare fields, voice channel config |
| 004 | fix_member_permissions.sql | Member role perms = 0x663 |
| 005 | channel_overrides_index.sql | Composite index for permission lookups |
| 006 | member_video_permissions.sql | Add USE_VIDEO + SHARE_SCREEN bits |
| 007 | attachment_dimensions.sql | width/height columns on attachments |
| 008 | dm_tables.sql | dm_participants + dm_open_state tables |
## Query Files (db/)
| File | Tables | Methods |
|------|--------|---------|
| auth_queries.go | users, sessions, invites | CreateUser, GetUserBy*, BanUser, Session CRUD, Invite CRUD |
| channel_queries.go | channels, channel_overrides | List/Get/Create/Delete Channel, permissions |
| message_queries.go | messages, reactions, read_states | CRUD, Search (FTS5), pagination, reactions |
| voice_queries.go | voice_states | Join/Leave, GetState, Update mute/camera/etc |
| attachment_queries.go | attachments | Create, Link to message, Get by message IDs |
| admin_queries.go | audit_log, settings, users | Stats, audit, settings, backup |
## DB Config
- Driver: `modernc.org/sqlite` (pure Go, no CGO)
- WAL mode, busy timeout 5s, single-writer
- Foreign keys enforced
## DB Access Layer (db/)
| File | Lines | Operations |
|------|-------|-----------|
| auth_queries.go | 434 | CreateUser, AuthenticateUser, CreateSession, ValidateSession, SetTOTPSecret |
| message_queries.go | 522 | InsertMessage, GetMessages, EditMessage, DeleteMessage, SearchMessages (FTS5) |
| channel_queries.go | 243 | ListChannels, CreateChannel, UpdateChannel, DeleteChannel, GetChannelPermissions |
| dm_queries.go | 286 | GetOrCreateDMChannel, GetUserDMChannels, OpenDM, CloseDM, IsDMParticipant |
| voice_queries.go | 278 | JoinVoice, LeaveVoice, GetVoiceStates, UpdateVoiceState |
| admin_queries.go | 374 | GetStats, ListUsers, BanUser, AuditLog, GetSettings |
| attachment_queries.go | 156 | InsertAttachment, GetAttachment, GetMessageAttachments |
| account.go | 101 | ChangePassword, ChangeAvatar, DeleteAccount |
| errors.go | 33 | Sentinel errors: ErrNotFound, ErrDuplicate, ErrForbidden |
| db.go | 136 | Open, WAL mode, busy timeout, FK enforcement |
| models.go | 198 | All Go struct definitions (User, Message, Channel, VoiceState, etc.) |
+93 -66
View File
@@ -1,75 +1,102 @@
<!-- Generated: 2026-03-20 | Files scanned: 75 TS + 9 Rust | Token estimate: ~900 -->
<!-- Generated: 2026-03-30 | Files scanned: 203 | Token estimate: ~800 -->
# Frontend Codemap (Tauri v2 Client)
# TypeScript Frontend Codemap
## Page Flow
## Source Stats
- 110 source files, ~25,451 lines
- Vanilla TypeScript (no framework), imperative DOM
## Page Tree
```
main.ts → router("connect")
ConnectPage → login/register → wirePostAuth() → ws.connect()
→ dispatcher wires events → "ready" received
→ router.navigate("main")
MainPage → compose sidebar + chat + voice + modals
→ logout → router.navigate("connect")
main.ts (463 lines) -- entry point, router setup
ConnectPage.ts (290)
connect-page/LoginForm.ts (642)
connect-page/ServerPanel.ts (345)
MainPage.ts (468)
main-page/SidebarArea.ts (919) -- unified 240px sidebar
main-page/SidebarDmSection.ts (151)
main-page/SidebarDmHelpers.ts (138)
main-page/SidebarMemberSection.ts (176)
main-page/ChatArea.ts (142)
main-page/ChatHeader.ts (80)
main-page/ChannelController.ts (298)
main-page/MessageController.ts (132)
main-page/ReactionController.ts (134)
main-page/VoiceCallbacks.ts (140)
main-page/VideoModeController.ts (189)
main-page/OverlayManagers.ts (329)
main-page/MemberPickerModal.ts (105)
```
## Component Tree & Store Subscriptions
```
MainPage
├─ ChannelSidebar ── channels.store, voice.store, auth.store, ui.store
├─ ChatHeader ────── channels.store
├─ MessageList ───── messages.store, members.store
├─ TypingIndicator ─ members.store
├─ MessageInput ──── messages.store, rate-limiter
├─ VoiceWidget ───── voice.store, channels.store
├─ VideoGrid ─────── voice.store (camera-filtered subscription)
├─ MemberList ────── members.store
├─ UserBar ───────── auth.store
└─ SettingsOverlay ─ auth.store, ui.store, voice.store
```
## Stores (stores/)
| File | Lines | Key Exports |
|------|-------|-------------|
| messages.store.ts | 358 | addMessage, editMessage, deleteMessage, updateReaction, confirmSend |
| voice.store.ts | 312 | joinVoiceChannel, leaveVoiceChannel, setVoiceStates, updateVoiceState, setSpeakers |
| channels.store.ts | 216 | setChannels, addChannel, updateChannel, removeChannel, setActiveChannel, incrementUnread |
| ui.store.ts | 199 | setTransientError, UI flags and layout state |
| members.store.ts | 193 | setMembers, addMember, removeMember, updatePresence, setTyping |
| dm.store.ts | 102 | setDmChannels, addDmChannel, removeDmChannel, updateDmLastMessage |
| auth.store.ts | 70 | setAuth, clearAuth |
| roles.store.ts | 29 | role list state |
## Core Services (lib/)
| File | Lines | Purpose |
|------|-------|---------|
| livekitSession.ts | 1171 | LiveKit facade: connect, disconnect, device switch, token refresh |
| api.ts | 573 | REST client (fetch wrapper, all /api/v1/* calls) |
| ws.ts | 498 | WS client: connect, send, reconnect with last_seq |
| audioPipeline.ts | 398 | AudioWorklet VAD, gain, noise gate |
| dispatcher.ts | 396 | WS message -> store action mapping (all 27 server msg types) |
| profiles.ts | 448 | Server profile CRUD, auto-login, credential storage |
| types.ts | 632 | Shared TypeScript interfaces and type guards |
| media-visibility.ts | 324 | Intersection Observer for lazy media loading |
| connectionStats.ts | 234 | WebRTC stats polling (2s), quality indicator |
| audioElements.ts | 221 | Audio element pool for participant playback |
| noise-suppression.ts | 274 | RNNoise WASM integration |
| icons.ts | 277 | SVG icon library |
| deviceManager.ts | ~200 | Mic/speaker enumeration, hot-swap fallback |
| themes.ts | ~180 | Theme manager: built-in + custom JSON import/export |
| notifications.ts | ~170 | Desktop notifications + taskbar flash |
| ptt.ts | ~150 | Push-to-talk wiring (delegates to Rust PTT) |
| credentials.ts | ~120 | IPC bridge to Rust Windows Credential Manager |
| tenor.ts | ~100 | GIF picker (Tenor API v2) |
| toast.ts | ~80 | Toast notification system |
| store.ts | ~60 | Generic reactive store pattern (subscribe/getState) |
| disposable.ts | ~50 | Resource cleanup pattern |
| rate-limiter.ts | ~50 | Client-side rate limiting |
| router.ts | ~40 | Simple page router |
## Components (components/)
| File | Lines | Purpose |
|------|-------|---------|
| ChannelSidebar.ts | 836 | Legacy sidebar (superseded by SidebarArea) |
| MessageList.ts | 629 | Virtual scroll message list |
| MessageInput.ts | 517 | Rich input: replies, attachments, GIF/emoji picker |
| VoiceWidget.ts | 386 | Voice controls, timer, connection quality |
| EmojiPicker.ts | 326 | Emoji grid with search |
| SettingsOverlay.ts | 322 | Settings panel shell + tab routing |
| VideoGrid.ts | 292 | Video tile layout |
| VoiceChannel.ts | 243 | Voice channel user list with states |
| SearchOverlay.ts | 229 | Full-text search UI |
| settings/AccountTab.ts | 662 | Account, 2FA, avatar, delete |
| settings/VoiceAudioTab.ts | 447 | Audio device config, noise suppression |
| settings/AdvancedTab.ts | 282 | Cache clear, devtools, diagnostics |
| settings/LogsTab.ts | 281 | Log viewer + export |
| settings/AppearanceTab.ts | 227 | Theme, accent color, compact mode |
| message-list/renderers.ts | 284 | Message DOM rendering |
| message-list/attachments.ts | 387 | File attachment display |
| message-list/embeds.ts | 345 | URL preview embeds |
| message-list/media.ts | 479 | Image/video inline display |
## WS Dispatch Flow (dispatcher.ts)
```
ws.on("ready") channels/members/voice bulk load
ws.on("chat_message") messages.addMessage() + notifications.ts
ws.on("voice_state") voice.updateVoiceState()
ws.on("voice_token") livekitSession.handleVoiceToken()
ws.on("voice_leave") → voice.removeVoiceUser()
ws.on("presence") → members.updatePresence()
ws.on("channel_*") → channels.add/update/remove
ws.on("member_*") → members.add/update/remove
ws.on("ready") -> channels/members/voice/dm bulk load
ws.on("chat_message") -> messages.addMessage() + notifications.ts
ws.on("voice_state") -> voice.updateVoiceState()
ws.on("voice_token") -> livekitSession.handleVoiceToken()
ws.on("presence") -> members.updatePresence()
ws.on("channel_*") -> channels.add/update/remove
ws.on("member_*") -> members.add/update/remove
ws.on("dm_channel_*") -> dm.add/remove
```
## LiveKit Voice Flow (livekitSession.ts)
```
handleVoiceToken(token, url, channelId)
→ Room.connect(wss://host/livekit, token)
→ publishMic (optional RNNoise WASM)
→ startSpeakingPoll (100ms, Web Audio AnalyserNode)
→ onTrackSubscribed → <audio> elements (remote audio)
→ onTrackSubscribed → VideoGrid callback (remote video)
enableCamera() → setCameraEnabled(true) [optimistic UI]
disableCamera() → setCameraEnabled(false)
leaveVoice() → room.disconnect() + cleanup
```
## State Stores (lib/store.ts pattern)
| Store | Key Fields |
|-------|------------|
| auth | token, user, serverName, isAuthenticated |
| channels | channels: Map, activeChannelId |
| messages | messagesByChannel: Map, pendingSends, hasMore |
| members | members: Map, typingBy: Set |
| voice | currentChannelId, voiceUsers: Map<ch, Map<uid, VoiceUser>>, localMuted/Deafened/Camera |
| ui | theme, connectionStatus, collapsedCategories, activeModal |
## Rust Backend (src-tauri/src/)
| File | Tauri Commands |
|------|----------------|
| commands.rs | get_settings, save_settings (key allowlist), store/get_cert_fingerprint, open_devtools |
| credentials.rs | save/load/delete_credential (Windows Credential Manager) |
| ws_proxy.rs | ws_connect, ws_send, ws_disconnect, accept_cert_fingerprint |
| ptt.rs | ptt_start/stop/set_key/get_key, ppt_listen_for_key (GetAsyncKeyState) |
| update_commands.rs | check_client_update, download_and_install_update |
+74
View File
@@ -0,0 +1,74 @@
<!-- Generated: 2026-03-30 | Files scanned: 203 | Token estimate: ~600 -->
# Tauri Rust Backend Codemap
## Source Stats
- 10 source files, ~1,751 lines
- src-tauri/src/
## Module Map
### lib.rs (61 lines) -- App bootstrap
- Registers all Tauri plugins: store, global-shortcut, notification, http, opener, dialog, fs, updater, process
- Manages WsState and LiveKitProxyState
- Registers 19 IPC commands via generate_handler!
- Creates system tray on setup
### ws_proxy.rs (444 lines) -- WebSocket proxy
- **WsState**: Arc<Mutex<Option<WsConnection>>> singleton
- `ws_connect(url, token, fingerprint)` -- TLS with TOFU cert pinning, accept_invalid_certs for server URLs
- `ws_send(message)` -- forward text frame to server
- `ws_disconnect()` -- close connection
- `accept_cert_fingerprint()` -- mark fingerprint as trusted
- Emits `ws-message` and `ws-close` events to frontend
- SHA-256 fingerprint extraction from server cert
### livekit_proxy.rs (434 lines) -- LiveKit signaling proxy
- **LiveKitProxyState**: Arc<Mutex<Option<ProxyHandle>>>
- `start_livekit_proxy(server_url)` -- launches local TCP listener, proxies to server's /livekit/* path
- `stop_livekit_proxy()` -- shuts down proxy
- TLS passthrough with TOFU fingerprint checking
- Returns local proxy URL for LiveKit JS SDK to connect to
### credentials.rs (252 lines) -- Windows Credential Manager
- `save_credential(service, username, password)` -- writes to Windows Credential Manager
- `load_credential(service, username)` -- reads password
- `delete_credential(service, username)` -- removes entry
- Uses `windows-sys` crate for CredWriteW/CredReadW/CredDeleteW
- Non-Windows: compile-time stubs returning errors
### commands.rs (218 lines) -- Settings + certs IPC
- `get_settings()` / `save_settings(key, value)` -- tauri-plugin-store with key allowlist
- `store_cert_fingerprint(host, fp)` / `get_cert_fingerprint(host)` -- TOFU cert store
- `open_devtools()` -- conditional on "devtools" feature flag
- Key allowlist: `owncord:*`, `userVolume_*`, `windowState`
### update_commands.rs (112 lines) -- Client auto-updater
- `check_client_update(server_url)` -- polls server /api/v1/client-update
- `download_and_install_update(url)` -- downloads MSI, launches installer
### ptt.rs (97 lines) -- Push-to-talk
- `ptt_start()` / `ptt_stop()` -- start/stop key polling thread
- `ptt_set_key(vk_code)` / `ptt_get_key()` -- configure PTT key
- `ptt_listen_for_key()` -- 10s capture window, returns pressed VK code
- Uses Win32 GetAsyncKeyState (non-consuming, works globally)
- Emits `ptt-active` events to frontend
### tray.rs (92 lines) -- System tray
- `create_tray(handle)` -- icon + right-click menu (Show/Quit)
### hotkeys.rs (35 lines) -- Global shortcuts
- Hotkey registration helpers (delegates to tauri-plugin-global-shortcut)
### main.rs (6 lines) -- Entry point
- Calls lib::run()
## IPC Command Registry (19 commands)
```
commands: get_settings, save_settings, store_cert_fingerprint, get_cert_fingerprint, open_devtools
ws_proxy: ws_connect, ws_send, ws_disconnect, accept_cert_fingerprint
credentials: save_credential, load_credential, delete_credential
update: check_client_update, download_and_install_update
ptt: ptt_start, ptt_stop, ptt_set_key, ptt_get_key, ptt_listen_for_key
livekit: start_livekit_proxy, stop_livekit_proxy
```
+85
View File
@@ -0,0 +1,85 @@
<!-- Generated: 2026-03-30 | Files scanned: 203 | Token estimate: ~600 -->
# Testing Codemap
## Test Infrastructure Summary
| Layer | Framework | Test Files | Approx Tests | Coverage Target |
|-------|-----------|-----------|--------------|-----------------|
| Client unit | Vitest | 103 | ~2,905 | 95%+ |
| Client integration | Vitest | 1 | varies | -- |
| Client E2E (mocked) | Playwright | 20 | ~100+ | critical flows |
| Client E2E (native) | Playwright + CDP | 10 | ~50+ | real Tauri exe |
| Rust backend | cargo test | 10 (inline) | ~25 | key IPC commands |
| Go server | go test | 58 | ~400+ | 80%+ |
## Client Tests (Client/tauri-client/tests/)
### Unit Tests (103 files)
- Pattern: `tests/unit/*.test.ts`
- Framework: Vitest with jsdom
- Mocking: Tauri IPC mocked via `@tauri-apps/api` stubs
- Run: `npm test` or `npm run test:unit`
- Coverage: `npm run test:coverage` (Istanbul via Vitest)
Key test areas:
- Store tests (messages, voice, channels, members, dm, auth, ui, roles)
- Component tests (MessageList, MessageInput, VoiceWidget, Settings tabs)
- Lib tests (ws, api, dispatcher, livekitSession, audioPipeline, profiles)
- Page tests (ConnectPage, MainPage, SidebarArea)
### E2E Tests -- Mocked Tauri (20 files)
- Pattern: `tests/e2e/*.spec.ts`
- Framework: Playwright
- Environment: Vite dev server + mocked Tauri APIs
- Run: `npm run test:e2e`
- Covers: connect flow, chat, DMs, settings, overlays, message actions
### E2E Tests -- Native (10 files)
- Pattern: `tests/e2e/native/*.spec.ts`
- Framework: Playwright + WebView2 CDP
- Environment: Real Tauri exe + real Go server
- Run: `npm run test:e2e:native`
- Covers: auth, channel nav, chat ops, DMs, reconnection, themes
- Note: 60s login timeout due to server rate limiting
### Integration Tests (1 file)
- Pattern: `tests/integration/*.test.ts`
## Go Server Tests (Server/)
### Test Files: 58
- Pattern: `*_test.go` across all packages
- Run: `go test ./...` or `go test -race -cover ./...`
- Key packages with tests:
- `ws/` -- hub, handlers, voice, reconnect, ring buffer
- `api/` -- all handlers, middleware, router, contracts
- `db/` -- queries, migrations, backup
- `auth/` -- rate limiter, sessions, TOTP, TLS, password
- `admin/` -- handlers, middleware, logstream, setup, updates
- `config/` -- config loading
## Rust Tests (src-tauri/src/)
### Inline Tests: ~25
- Pattern: `#[cfg(test)] mod tests` in source files
- Run: `cd Client/tauri-client/src-tauri && cargo test`
- Covers: settings key allowlist validation, fingerprint format validation
## Test Commands Quick Reference
```bash
# Client
npm test # all vitest tests
npm run test:unit # unit only
npm run test:coverage # coverage report
npm run test:e2e # mocked Playwright
npm run test:e2e:native # real Tauri + server
npm run test:e2e:ui # Playwright UI mode
# Server
go test ./... # all Go tests
go test -race -cover ./... # with race + coverage
# Rust
cd Client/tauri-client/src-tauri && cargo test
```