mirror of
https://github.com/J3vb/OwnCord.git
synced 2026-09-03 03:50:00 +03:00
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:
@@ -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
@@ -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
@@ -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
@@ -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 |
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
```
|
||||
Reference in New Issue
Block a user