Home Doh Ref
Dohballs
  • 📁 doh_chat
    • 📦 chat_extensions
  • 📁 doh_modules
    • 📦 dataforge
    • 📦 express
    • 📁 sso
    • 📁 user
  • 📁 sites
    • 📁 cec
      • 📦 game

doh_chat

Real-time chat, collaboration, and AI services suite for Doh.js applications.

Suite Overview

doh_chat is a full-featured communication platform built on Doh.js. It provides room-based chat with direct messages, peer-to-peer file sharing, real-time collaborative document editing (code and rich text), multi-provider AI integration, issue tracking, and embeddable chat widgets. All modules share a common Socket.IO transport layer and permission system.

Suite Architecture

                              ┌─────────────────┐
                              │      chat        │  Core chat system
                              │  rooms, DMs,     │  (server + browser)
                              │  presence, bots  │
                              └────────┬─────────┘
                                       │ loads
     ┌───────────┬────────────┬────────┼──────────┬────────────┬────────────┐
     │           │            │        │           │            │            │
  ┌──┴────┐ ┌───┴───┐ ┌──────┴──┐ ┌──┴──────┐ ┌──┴──────┐ ┌──┴──────┐ ┌──┴──────────┐
  │chat_  │ │chat_  │ │chat_    │ │chat_    │ │chat_    │ │chat_    │ │ ai_services │
  │files  │ │url_   │ │push_    │ │web_push │ │calls    │ │onboarding│ │ AI gateway  │
  │WebRTC │ │utils  │ │server   │ │(VAPID/  │ │WebRTC   │ │spotlight │ │ (6 providers│
  │file   │ │       │ │(APNs/   │ │Web Push)│ │activities│ │tour      │ │ + token     │
  │xfer   │ │       │ │iOS push)│ │         │ │         │ │          │ │ tracking)   │
  └───────┘ └───────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └──────┬──────┘
                                                                               │
  ┌──────────────┐ ┌──────────────┐ ┌──────────────┐                    ┌──────┴──────┐
  │ collab_docs  │ │  collab_     │ │  collab_     │                    │ ai_keys_    │
  │ Monaco code  │ │  richtext    │ │  tracker     │                    │ admin       │
  │ editor + Yjs │ │ TinyMCE+Yjs │ │ task list+Yjs│                    │ key mgmt UI │
  └──────┬───────┘ └──────┬───────┘ └──────┬───────┘                    └─────────────┘
         │                │                │
         └────────┬───────┴────────────────┘
           ┌──────┴──────┐
           │collab_shared│
           │ Yjs socket  │
           │ provider    │
           └─────────────┘

  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
  │ chat_proxy  │ │   dohtop    │ │   games     │ │chat_io_     │ │ chat_       │
  │ URL proxy   │ │ floating    │ │ in-room     │ │devices      │ │ extensions  │
  │ for embeds  │ │ window sys  │ │ multiplayer │ │ mic/cam/    │ │ Chrome MV3  │
  │ (htmlpog)   │ │ tab groups  │ │ game engine │ │ speaker mgmt│ │ + Safari    │
  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘

  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
  │ chat_embed  │ │    chat_    │ │   issues    │ │ user_avatar │
  │ iframe chat │ │  messenger  │ │ bug capture │ │ DiceBear    │
  │ for embeds  │ │ floating bar│ │ + tracking  │ │ avatars     │
  └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘

  ┌─────────────┐ ┌─────────────┐
  │ dohpro_     │ │ dohpro_     │
  │ admin       │ │ sales       │
  │ tier/credit │ │ /pro pricing│
  │ management  │ │ /what-is-   │
  │ /admin/     │ │ dohchat     │
  │ dohpro      │ │ pages       │
  └─────────────┘ └─────────────┘

Module Dependency Tree

chat.doh.js
├── chat_url_utils              (shared)
├── ai_services                 (nodejs, async)
├── chat_server                 (nodejs)   ← routes, socket events, permissions, DB
├── chat_files_server           (nodejs)
├── chat_push_server            (nodejs)   ← APNs push (iOS/macOS)
├── chat_web_push_server        (nodejs)   ← VAPID Web Push (browsers)
├── chat_calls_server           (nodejs)   ← Activities (WebRTC signaling)
├── chat_proxy_server           (nodejs)   ← URL proxy for embeds (htmlpog)
├── games                       (shared, async)
├── collab_docs                 (shared, async)
├── collab_richtext             (shared, async)
├── collab_tracker              (shared, async)  ← collaborative task list (Yjs CRDT)
├── dohtop                      (await)    ← floating window system
├── user_avatar                 (browser)
├── chat_client                 (browser, await)  ← full UI (ChatApp + 60+ patterns)
├── chat_files_client           (browser, async)
├── chat_push_client            (browser, async)
├── chat_web_push_client        (browser, async)
├── chat_calls_client           (browser, async)  ← Activities UI
├── chat_onboarding_client      (browser, async)
└── chat_io_devices_client      (browser, async)  ← I/O device management

Dependency flow: chat is the core — it loads chat_files, chat_push_server, chat_web_push_server, chat_calls, chat_proxy_server, chat_onboarding_client, chat_io_devices_client, ai_services, collab_docs, collab_richtext, collab_tracker, games, dohtop, and user_avatar. Standalone packages like chat_embed, issues, dohpro_admin, and dohpro_sales depend on chat. The chat_messenger is browser-only and used by chat_embed and issues for floating UI.

Depends on: express_router, user_host (auth), db_dataforge Depended on by: chat_embed, issues

Module Inventory

Module Description Server Browser
chat Core room/DM chat, presence, bots, messaging chat_server.js chat_client.js
chat_files P2P file transfer (WebRTC + socket relay fallback) chat_files_server.js chat_files_client.js
chat_embed Embeddable iframe chat for extensions chat_embed_server.js chat_embed_client.js
chat_messenger OS-style dock bar with halfback glass strip, DockItem icons, popup windows -- chat_messenger_client.js
chat_onboarding Spotlight tour for first-time users (desktop + mobile) -- chat_onboarding_client.js
collab_docs Monaco code editor with Yjs CRDT sync collab_docs_server.js collab_docs_client.js
collab_richtext TinyMCE rich text editor on collab_docs backend collab_richtext_server.js collab_richtext_client.js
collab_shared Yjs socket provider and presence utilities -- collab_shared_client.js
ai_services Multi-provider AI gateway and token tracking ai_services.js --
ai_keys_admin Admin UI/API for AI provider API keys ai_keys_admin.js ai_keys_admin.js
dohpro_admin Subscription tier config and credit mapping (admin) dohpro_admin_server.js dohpro_admin_client.js
dohpro_sales Pricing page (/pro) and features page (/what-is-dohchat) dohpro_sales_server.js dohpro_sales_client.js
issues Bug capture, issue tracking, analytics issues_server.js issues_client.js
chat_proxy URL proxy for embeds (htmlpog frame, Google Cache/Archive.org/Jina fallbacks) chat_proxy_server.js --
dohtop Floating window system: drag, resize, tab groups, dock integration -- dohtop_client.js
chat_io_devices I/O device management: mics, cameras, speakers, VU meters, routing -- chat_io_devices_client.js
collab_tracker Real-time collaborative task list (Yjs CRDT) -- collab_tracker_client.js
games In-room multiplayer games (Hangman, 20 Questions, Poker, WOPR) game_engine.js game_client.js
chat_extensions Browser extensions (Chrome MV3 + Safari) for URL tracking -- browser_chat_panel.js
user_avatar DiceBear avatar generation -- user_avatar.js

How Modules Load

  1. Add chat (or chat_embed, issues, etc.) to host_load in boot.pod.yaml
  2. The chat.doh.js package declares the dependency graph
  3. Sub-packages like chat_embed, issues, dohpro_admin, and dohpro_sales list chat as a dependency and add their own server/client modules
# boot.pod.yaml
host_load:
  - express_router
  - users
  - chat           # Loads the full chat stack
  - chat_embed     # Optional: adds embed endpoints
  - issues         # Optional: adds issue tracking
  - ai_keys_admin  # Optional: adds key management UI
  - dohpro_admin   # Optional: adds /admin/dohpro tier management
  - dohpro_sales   # Optional: adds /pro and /what-is-dohchat pages

Prerequisites

  • Doh.js runtime
  • users module (provides authentication, Users.requireAuth, Doh.permit())
  • express_router module (provides Router.AddRoute, Router.SendJSON, Router.SendHTML)

Quick Start

With the local server running:

URL What it loads
/chat Full chat application
/doh-chat-embed?room=<name> Embeddable chat widget
/docs Collaborative document list (Monaco)
/collab/<doc-id> Specific collaborative document
/richtext Rich text document list (TinyMCE)
/richtext/<doc-id> Specific rich text document
/admin/ai-keys AI provider key management (admin only)
/admin/dohpro DohPro subscription tier and credit management (admin only)
/pro DohPro pricing page
/what-is-dohchat DohChat features and capabilities showcase

Supplementary Documentation


Chat Module Overview

File Purpose
chat.doh.js Package definition (dependency graph)
chat_server.js Server routes, socket events, permissions, DB setup (~8,700 lines)
chat_client.js Full client UI — 70+ Doh Patterns (~24,700 lines)
chat_calls_server.js Activities signaling server (~740 lines)
chat_calls_client.js Activities manager and UI patterns (~2,600 lines)
chat_proxy_server.js URL proxy for embed frames (htmlpog, Google Cache, Archive.org, Jina fallbacks) (~900 lines)
chat_push_server.js APNs push notification registration and sending (~385 lines)
chat_push_client.js Capacitor push notification setup (~200 lines)
chat_web_push_server.js VAPID Web Push subscription and sending
chat_web_push_client.js Browser Web Push API registration
chat-notification-sw.js Service worker for Web Push notification display
chat_url_utils.js URL parsing utilities (~100 lines)
chat.css Main chat styles
chat_calls.css Activities UI styles
BROWSER_TOOLS.md Browser extension tool registry docs

Configuration & Database

Pod Configuration

# pod.yaml
chat:
  lobby_name: "General Chat"
  max_message_length: 5000
  attachment_storage_enabled: true
  user_key_secret: "your-secret-key"  # AES key for encrypting user AI keys
  models: {}                          # AI model configuration overrides
  providers: {}                       # Provider key map overrides

Database Schema

All tables are in the chat database (SQLite via AsyncDataforge). All are Idea tables (id TEXT, data TEXT JSON blob) unless noted.

Table Purpose
chat.rooms Room metadata (name, type, members, settings, created_by, owners)
chat.messages Message history (sender, content, timestamps, provenance)
chat.room_members Membership records (username, role, joined_at, unread_count)
chat.contacts User contact lists
chat.connections Established user-to-user connections
chat.connection_requests Pending connection requests
chat.blocked_users Blocked user records
chat.email_invites Email-based room invitations
chat.sidebar_layouts Saved sidebar panel layouts per user
chat.trace Browser navigation trace/history entries
chat.bots Bot configurations and metadata
chat.user_ai_keys Encrypted user API keys (AES-256-GCM)
chat.pro_interest Doh Pro subscription interest registrations
chat.token_usage AI token usage tracking per user/room/model
chat.approval_requests Pending AI bot action approval requests
chat.scheduled_tasks Recurring and one-shot AI bot scheduled tasks
chat.notifications In-app notification records
chat.notification_prefs Per-user notification scope preferences
chat.room_invitations Room invitation tracking
chat.settings_interactions Feature usage tracking for analytics

Constants: LOBBY_ID = 'lobby'

Room ownership: Rooms have an owners array (string[]) that controls who can delete or clear the room. Regular rooms are created with owners: [creator]. DM rooms are created with owners: [userA, userB] (both participants). Old rooms without an owners field fall back to created_by for permission checks. DM rooms cannot be deleted or cleared regardless of ownership.

Permissions

Contexts

Context Condition
chat_room ctx?.roomId exists
server_logs Always true
chat_maintenance Always true
dohpro Always true

Groups

Group Type Permissions Use Case
chat_room_creator Assignable create:chat_room Users who can create rooms
log_viewer Assignable view:server_logs Users who can stream server logs
chat_admin Assignable admin:chat_maintenance Admin maintenance (delete rooms, view all token usage)
dohpro_subscriber Assignable is:dohpro Doh Pro subscribers (access managed AI keys)

Granting Permissions

doh users add-group user@example.com chat_room_creator
doh users add-group user@example.com chat_admin

Features

Messaging

Core send/edit/delete with emoji reactions. Messages carry provenance tracking (who created, edited, or deleted, with timestamps). Sticky notes via chat:notey_edit for the notey room format. Message reordering via chat:reorder. Unread counts tracked per-user per-room.

Message object shape:

{
  id: string,                  // UUID
  room_id: string,
  sender: string,              // username (or 'system' for system messages, 'bot:<id>' for bots)
  sender_name: string,         // chat_name (system messages only; regular messages resolve from ChatUserStore)
  content: string,
  created_at: number,          // timestamp
  edited_at: number | null,
  deleted: boolean,
  is_guest: boolean,
  original_sequence_number: number,
  adhoc_sequence_number: number | null,
  provenance: [{ action: 'created'|'edited'|'deleted', user, name, at }]
}

Rooms & Formats

Public lobby room (always available, auto-join). Permission-gated room creation. Room types: public, private, dm, bot, issue. Room format switching between:

  • chatty — standard linear chat
  • notey — sticky note grid with inline editing
  • jelly — spatial canvas with draggable message tiles and connections
  • gamey — game interface format

Room export/import via YAML. Activity rollup folds consecutive system messages into collapsible summaries.

Direct Messages

Create/get DM rooms via POST /api/chat/dm/:username or POST /api/chat/dm/bot/:bot_id. DM rooms have both participants as co-owners and cannot be deleted or cleared. Bot DMs auto-create a bot room with the specified bot.

Presence & Typing

Rich presence tracking: Online / Away / Busy / Offline with per-user persistence. Status saved to user record and broadcast to all lobby users via chat:presence. Typing indicators broadcast per-room excluding the sender.

onlineUsers Map: username → { sockets: Set<socket.id>, chat_name, avatar_salt, avatar_style, status }
socketToUser Map: socket.id → username
userRooms Map: socket.id → Set<room_id>

status is loaded from Users.getUserByUsername() on connect (field chat_status, defaults to 'online'). Updated in-memory on POST /api/chat/status and re-saved via Users.updateUser(). On socket disconnect the broadcast uses status: 'offline' regardless of saved value.

AI Bots

Multi-provider AI support (Anthropic, OpenAI, Google, xAI, Moonshot, HuggingFace) via ai_services. Users create custom bots with system prompts and model selection. Bot DM rooms for private conversations. User API keys encrypted with AES-256-GCM, stored as "iv:tag:encrypted" (hex, colon-separated). Masked display shows first 7 + last 4 characters.

Bot tool indicators (chat:bot_tool_use / chat:bot_tool_done) show real-time tool usage. Bot chaining (chat:bot_chain) allows bots to hand off to other bots. Browser extension tool integration lets bots interact with the user's browser — see BROWSER_TOOLS.md.

Workflow Execution

Bots execute via a graph-based workflow engine (agent_executor) instead of flat generateBotResponse. When a bot has a valid workflow document (a Yjs surface canvas with at least one input node and one output node), the graph executes; otherwise the bot falls back to flat mode (direct generateBotResponse).

  • agent_executor — walks the workflow graph: finds the input node, resolves edges to downstream nodes, executes each node type via agent_node_types, and routes results along edges until reaching the output node.
  • handleBotResponseOutput — shared post-response handler used by both the workflow path and the flat path. Saves the bot's message, broadcasts it to the room, fires notifications, and handles bot-to-bot delegation (chaining).
  • ChatBotContext — SPR source declaration (= {}) that shares helpers (DB access, bot lookup, message formatting) between chat_server, agent_executor, and agent_node_types without requiring load chain dependencies between them.
  • workflowFromLegacy — validates and rebuilds workflow documents that are missing or incomplete. Called by the ensure-workflow endpoint. Checks for input/output nodes and re-creates them if absent.

Workflow Socket Events

Event Direction Description
agent:join_builder C → S Join a bot's workflow builder room for live execution updates
agent:leave_builder C → S Leave a bot's workflow builder room
agent:resume C → S Resume a paused workflow execution (e.g. after human review)
agent:finish_tools C → S Signal that tool execution is complete and workflow can continue

Stuck Queue Protection

Bot response processing sets a processing flag to prevent duplicate concurrent executions. A 2-minute auto-reset timer clears the flag if the bot becomes stuck (crash, timeout, unhandled error), allowing the next queued message to proceed.

Approval & Scheduling

AI bots can request approval before executing high-impact actions.

Flow:

  1. Bot generates an [APPROVAL] message with a JSON card describing the proposed action
  2. Room owner responds via chat:approval_respond
  3. On approval, if the payload indicates a scheduled_task, the server creates a task record with schedule type and next-run timestamp
  4. A scheduler loop (SCHEDULER_INTERVAL_MS) polls for due tasks and queues bot responses
  5. chat:approval_resolved broadcast updates the card UI to approved or denied

Scheduled tasks support once and recurring types with configurable intervals. Tasks can be cancelled or reactivated via REST API.

Context Compression

Bot room conversations can be compressed or fully cleared to manage AI context window size.

  • Clear context (POST /api/chat/rooms/:id/clear-context) — hard deletes all messages, wipes summary, sets last_cleared_at. Owner only.
  • Compress (POST /api/chat/rooms/:id/compress) — uses the room's AI model to summarize the conversation, replaces all messages with a summary system message. Owner only.
  • Admin clear (POST /api/chat/admin/clear-room) — hard deletes all messages in any room. Requires admin:chat_maintenance.

Connections, Contacts & Blocking

Connections are bidirectional friendship links. Send/accept/decline requests. If mutual pending requests exist, auto-accepts. On connection, the server auto-creates a DM room and sends chat:navigate_to_room to switch to it. Connection records use compound ID "user1:user2" (alphabetically sorted) for deduplication.

Contacts are a lightweight one-way list for quick access. Add/remove via REST.

Blocking prevents message visibility and connection requests. Block records checked server-side in filterBlockedMessages before returning message history. Blocking cancels any pending connection requests between the users. The onlineUsers lobby list also filters blocked users per requesting user.

Notifications

In-app notification bell with toast popups, unread badges, and per-user scope preferences. Paginated notification list with mark-read and clear-all. Socket events chat:notification and chat:notification_updated for real-time delivery.

Push notifications via two channels:

  • APNs (iOS/macOS) via chat_push_server — see PUSH_NOTIFICATIONS.md
  • Web Push (browsers) via chat_web_push_server using VAPID keys. Service worker chat-notification-sw.js handles display and click-to-open navigation.

Activities

Activities (WebRTC audio/video/screen sharing) are managed by chat_calls_server.js. Fully mesh topology — every participant establishes a direct peer connection to every other. The server acts as a signaling relay only.

Participant A ──── direct RTCPeerConnection ──── Participant B
      │                                                │
      └────── direct RTCPeerConnection ──── Participant C

Multi-device support: When a user joins from a second socket, the join mode controls behavior: 'move' (default) tears down old sockets and emits chat:call:replaced; 'add' keeps existing sockets and adds the new one, enabling multi-device participation (e.g. phone mic + laptop screen). chat:call:check_existing lets the client detect an active session before choosing a mode.

TURN credentials: Generated per-request using HMAC-SHA1. The /api/chat/calls/ice endpoint returns a fresh ice_servers array with time-limited TURN entries.

Pod configuration:

Key Default Description
chat_calls.turn_secret null HMAC secret for TURN credential generation
chat_calls.turn_host null TURN server address, e.g. "1.2.3.4:3478"
chat_calls.turn_ttl 86400 TURN credential TTL in seconds
chat_calls.max_participants 8 Maximum simultaneous participants

max_participants is sent to the browser via browser_pod. turn_secret and turn_host remain server-side only. See TURN_SERVER_SETUP.md for COTURN setup.

Jelly Canvas

Messages in jelly format have persistent x, y, width, height positions stored under _jelly. Position updates via chat:jelly_positions, broadcast to room members.

Room merge (chat:room_merge) groups selected messages into a new private sub-room with parent_room_id pointing back. Posts a system message in the parent as a room-tile marker. Returns an undo descriptor for reversal.

Undo (chat:room_merge_undo) restores deleted messages, removes the system tile, and deletes the sub-room.

Add message (chat:room_add_message) moves or copies a single message into an existing sub-room with optional jelly positioning.

Connections (chat:jelly_connections) allow add/remove of visual connections between jelly messages.

Collaboration

Embedded collaborative documents (Monaco code editor, TinyMCE rich text) and collaborative task tracking via Yjs CRDT sync. Document tile size and open state synced across room members via chat:update_doc_size and chat:update_doc_open_state.

Shared browser panels (chat:browser_panel:*) for collaborative URL browsing within a room — open, navigate, move/resize, and close panels synced to all members.

URL Trace

The chat_embed browser extension reports page visits to a chat room. Each visit creates or updates a trace entry keyed by room_id:urlKey (hostname + pathname). A system message is posted with trace: true flag. Trace entries include URL, title, favicon, visitor info, scroll anchor, and user-assigned nickname.

Scroll & YouTube Sync

Scroll sync relays scroll position within a shared browsing context via chat:scroll_sync. Used by chat_embed to synchronize the host page scroll position with room participants.

YouTube sync relays player state (play/pause/seek with timestamp) across room members via chat:yt_sync so everyone watches in sync.

Server Log Streaming

Users with the log_viewer group can subscribe to real-time server log entries via chat:logs:subscribe. Entries stream as chat:logs:entry with timestamp, level, message, and source. Subscription is per-socket, auto-cleaned on disconnect.

Games

In-room multiplayer games via the gamey room format. Game engine handles start/end/move/state lifecycle. Available games: Hangman, Twenty Questions, Poker, WOPR, Exquisite Corpse. See ../games/README.md for game definitions and engine API.

REST API Reference

All routes prefixed /api/chat/ unless noted. Doh routes infer GET (no data) or POST (data sent) from the request. Auth = [Users.requireAuth]. Nickname = user must have set chat_name.

Profile & Settings

Path Auth Description
/api/chat/nickname Yes POST: Set chat display name (2-32 chars)
/api/chat/avatar Yes GET: current settings; POST: update avatar_salt/avatar_style
/api/chat/status Yes POST: Set presence status (online/away/busy/offline)
/api/chat/me Yes GET: Current user profile

Rooms

Path Auth Description
/api/chat/lobby Yes + Nick GET: Lobby room and members
/api/chat/rooms/public Yes + Nick GET: All public rooms
/api/chat/rooms Yes + Nick GET: Rooms user is a member of
/api/chat/rooms/create Yes + Nick POST: Create a room (create:chat_room)
/api/chat/rooms/:id Yes + Nick GET: Room details + members
/api/chat/rooms/:id/preview Yes GET: Room preview (non-members)
/api/chat/rooms/:id/messages Optional GET: Message history (paginated, limit/skip)
/api/chat/rooms/:id/settings Yes POST: Edit room settings (room admin)
/api/chat/rooms/:id/delete Yes POST: Delete room (room owner; DMs cannot be deleted)
/api/chat/rooms/:id/clear Yes POST: Clear all messages in room (room owner)
/api/chat/rooms/:id/join Yes + Nick POST: Join public/auto_membership room
/api/chat/rooms/:id/join-me Yes + Nick POST: Self-join room by ID
/api/chat/rooms/:id/leave Yes POST: Leave room (can't leave lobby)
/api/chat/rooms/:id/ping-members Yes POST: Ping room members
/api/chat/rooms/:id/members Yes POST: Add/invite member to room
/api/chat/rooms/:id/members/:username Yes DELETE: Remove member (room admin)
/api/chat/rooms/:id/invitations/accept Yes POST: Accept a room invitation
/api/chat/rooms/:id/bot Yes POST: Add bot to room
/api/chat/rooms/:id/export Yes POST: Export room as YAML
/api/chat/rooms/:id/import Yes POST: Import YAML into room (room admin)
/api/chat/share-window Yes POST: Share a window/tab with a room

Direct Messages

Path Auth Description
/api/chat/dm/:username Yes + Nick POST: Create/get DM room
/api/chat/dm/bot/:bot_id Yes POST: Create/get bot DM room

AI & Bots

Path Auth Description
/api/chat/ai/models Yes GET: List available AI models
/api/chat/ai/keys Yes GET: Key status per provider (masked)
/api/chat/ai/keys/save Yes POST: Save encrypted AI key
/api/chat/ai/keys/delete Yes POST: Delete AI key
/api/chat/ai/keys/reveal Yes POST: Decrypt and return full key
/api/chat/bots Yes GET: List user's bots
/api/chat/bots/create Yes POST: Create a bot
/api/chat/bots/:id Yes GET: Bot details
/api/chat/bots/:id/update Yes POST: Update bot config
/api/chat/bots/:id/delete Yes POST: Delete bot
/api/chat/bots/:id/ensure-workflow Yes POST: Validate/rebuild bot workflow doc (creates input+output nodes if missing)
/api/chat/bots/:id/sync-workflow Yes POST: Sync bot workflow doc from canvas state
/api/chat/bots/:id/editors Yes GET: List users currently editing a bot's workflow
/api/chat/bots/tool-registry Yes GET: Available tools for workflow node configuration
/api/chat/rooms/:id/clear-context Yes POST: Clear bot conversation context
/api/chat/rooms/:id/compress Yes POST: Summarize and compress context
/api/chat/rooms/:id/clone Yes POST: Clone bot room with empty history
/api/chat/rooms/:id/model Yes GET: Get bot's current AI model

Token Usage

Path Auth Description
/api/chat/token-usage Yes GET: User's aggregated token usage
/api/chat/rooms/:id/token-usage Yes GET: Per-room token usage
/api/chat/admin/token-usage Admin GET: All users' token usage

Connections & Contacts

Path Auth Description
/api/chat/contacts Yes GET: Contact list with online status
/api/chat/contacts/:username Yes GET/POST: Get or add contact
/api/chat/contacts/:username/remove Yes DELETE: Remove from contacts
/api/chat/connections/request/:username Yes POST: Send connection request
/api/chat/connections/requests/pending Yes GET: Incoming requests
/api/chat/connections/requests/sent Yes GET: Outgoing requests
/api/chat/connections/accept/:requester Yes POST: Accept request
/api/chat/connections/decline/:requester Yes POST: Decline request
/api/chat/connections Yes GET: All connections
/api/chat/connections/status/:username Yes GET: Check connection status
/api/chat/connections/remove/:username Yes DELETE: Remove connection
/api/chat/block/:username Yes POST: Block user
/api/chat/unblock/:username Yes POST: Unblock user
/api/chat/blocked Yes GET: List blocked users

Notifications & Invites

Path Auth Description
/api/chat/notifications Yes GET: List notifications (paginated)
/api/chat/notifications/unread-count Yes GET: Unread notification count
/api/chat/notifications/read Yes POST: Mark notifications read
/api/chat/notifications/clear Yes POST: Clear all notifications
/api/chat/notifications/prefs Yes GET/POST: Notification scope preferences
/api/chat/notifications/channel Yes POST: Update notification channel delivery
/api/chat/invite-by-email Yes POST: Send room invite via email
/api/chat/invitations Yes GET: Pending room invitations

Approval & Scheduling

Path Auth Description
/api/chat/approvals Yes GET: List pending approvals
/api/chat/schedules Yes GET: List scheduled tasks
/api/chat/schedules/:id/cancel Yes POST: Cancel scheduled task
/api/chat/schedules/:id/reactivate Yes POST: Reactivate recurring task
/api/chat/rooms/:id/pending-approvals Yes GET: Count pending approvals in room

Presence & Users

Path Auth Description
/api/chat/presence Yes + Nick GET: Online users list
/api/chat/users Yes + Nick GET: Paginated user discovery
/api/chat/users/by-email Yes GET: Find user by email

Sidebar & Links

Path Auth Description
/api/chat/sidebar-layout Yes GET: Saved sidebar layout
/api/chat/sidebar-layout/save Yes POST: Save sidebar layout
/api/chat/sidebar-layout/reset Yes POST: Reset to default
/api/chat/links/user Yes + Nick GET: Browser trace links
/api/chat/collabs/user Yes + Nick GET: User's collab documents

Pro & Misc

Path Auth Description
/api/chat/ai/pro-interest Yes POST: Register for Doh Pro
/api/chat/ai/pro-interest/check Yes POST: Check Pro registration
/api/chat/backgrounds -- GET: List available chat backgrounds
/api/chat/unfurl -- POST: URL metadata unfurl
/api/chat/settings-interaction Yes POST: Track feature usage for analytics

Activities

Path Auth Description
/api/chat/calls/:roomId Yes GET: Current activity state for a room
/api/chat/calls/ice Yes POST: Fresh ICE server list (with TURN credentials)

Push Notifications

Path Auth Description
/api/chat/push/register Yes POST: Register APNs push token
/api/chat/push/unregister Yes POST: Unregister push token
/api/chat/push/test Yes POST: Send test push notification
/api/chat/web-push/subscribe Yes POST: Register browser push subscription
/api/chat/web-push/unsubscribe Yes POST: Remove push subscription
/api/chat/web-push/vapid-key -- GET: Public VAPID key
/api/chat/web-push/test Yes POST: Send test web push notification
/chat-notification-sw.js -- GET: Service worker file

Admin

Path Auth Description
/api/chat/admin/delete-all-rooms Admin POST: Delete all rooms except lobby
/api/chat/admin/delete-empty-rooms Admin POST: Delete rooms with < 3 messages
/api/chat/admin/clear-room Admin POST: Hard delete all messages in a room
/api/chat/admin/clear-lobby Admin POST: Clear lobby messages
/api/chat/admin/test-models Admin POST: Test AI provider connectivity
/api/chat/admin/feature-stats Admin POST: Feature adoption statistics

Page Routes

Path Auth Description
/chat Yes Full chat application page
/chatop Yes Chat application (chatop layout)
/os Yes Chat application (os layout)

Socket Events Reference

All events use wrapSocketHandler for consistent error handling. Auth comes from socket.user (authenticated) or socket.guestUser (guest with nickname).

Connection & Identity

Event Direction Description
chat:set_guest_identity C → S Set guest name and ID
window:join C → S Join shared window room
window:leave C → S Leave shared window room
window:presence S → Room Window presence update

Room Lifecycle

Event Direction Description
chat:join C → S Join a room socket room
chat:leave C → S Leave a room socket room
chat:embed_joined C → S Register embed client for a room
chat:user_joined S → Room User joined lobby
chat:room_peer_joined S → Room Peer joined any room
chat:room_created S → Users Room created
chat:room_updated S → Room Room metadata changed
chat:room_deleted S → Room Room deleted
chat:member_added S → Room Member added
chat:member_removed S → Room Member removed
chat:room_invite S → User Received room invite
chat:room_cleared S → Room Admin hard-cleared room messages

Messaging

Event Direction Description
chat:message C → S Send a message
chat:edit C → S Edit a message
chat:delete C → S Delete a message
chat:react C → S Add a reaction
chat:unreact C → S Remove a reaction
chat:notey_edit C → S Edit a sticky note message
chat:reorder C → S Reorder messages in a room
chat:read C → S Mark messages as read
chat:message_received S → Room New message
chat:message_edited S → Room Message edited
chat:message_deleted S → Room Message deleted
chat:messages_reordered S → Room Message order changed
chat:reaction_updated S → Room Reactions updated
chat:unread_update S → User Unread count for a room

Typing & Presence

Event Direction Description
chat:typing C → S Broadcast typing state
chat:user_typing S → Room Typing indicator
chat:presence S → Lobby User presence state

Jelly Canvas

Event Direction Description
chat:jelly_positions C → S Update canvas positions for messages
chat:jelly_connections C → S Add/remove connections between jelly messages
chat:room_format C → S Change room format (chatty/notey/jelly/gamey)
chat:room_merge C → S Group messages into a new sub-room
chat:room_merge_undo C → S Reverse a room merge
chat:room_add_message C → S Move/copy a message into an existing sub-room
chat:update_tile_state C → S Update generic tile position/size
chat:jelly_positions_updated S → Room Canvas positions updated
chat:jelly_connections_updated S → Room Jelly connections updated
chat:room_format_updated S → Room Room format changed
chat:tile_state_updated S → Room Generic tile state updated

Collaboration & Sync

Event Direction Description
chat:update_doc_size C → S Update collab doc tile size
chat:update_doc_open_state C → S Update collab doc open/closed
chat:scroll_sync C → S Relay scroll position to room
chat:yt_sync C → S Relay YouTube player state
chat:doc_size_updated S → Room Collab doc tile size updated
chat:doc_open_state_updated S → Room Collab doc open state updated
chat:file_preview_size_updated S → Room File preview size changed

Browser Panels & Tools

Event Direction Description
chat:browser_panel:open C → S Open a shared browser panel
chat:browser_panel:url C → S Update browser panel URL
chat:browser_panel:state C → S Update browser panel position/size
chat:browser_panel:close C → S Close a browser panel
chat:browser_tool_result C → S Return browser tool result to server
chat:browser_panel:opened S → Room Browser panel opened
chat:browser_panel:url_update S → Room Browser panel URL changed
chat:browser_panel:state_update S → Room Browser panel moved/resized
chat:browser_panel:close S → Room Browser panel closed
chat:browser_tool_request S → Room Bot requesting browser tool

URL Trace

Event Direction Description
chat:trace_update C → S Report a page visit
chat:trace_sync C → S Request all trace entries for a room
chat:trace_delete C → S Delete a trace entry
chat:trace_rename C → S Set a nickname on a trace entry
chat:trace_updated S → Room Trace entry upserted
chat:trace_deleted S → Room Trace entry deleted
chat:trace_renamed S → Room Trace entry renamed

Bots & Approvals

Event Direction Description
chat:approval_respond C → S Approve or deny a bot approval request
chat:bot_tool_use S → Room Bot started using a tool
chat:bot_tool_done S → Room Bot finished using a tool
chat:bot_chain S → Room Bot chaining to another bot
chat:approval_pending S → Room New approval request pending
chat:approval_resolved S → Room Approval approved or denied
chat:context_cleared S → Room Bot room context cleared/compressed
agent:join_builder C → S Join bot workflow builder room for live updates
agent:leave_builder C → S Leave bot workflow builder room
agent:resume C → S Resume paused workflow execution
agent:finish_tools C → S Signal tool execution complete

Activities

Event Direction Description
chat:call:check_existing C → S Check for existing activity session
chat:call:join C → S Join/start room activities
chat:call:leave C → S Leave activities
chat:call:toggle_audio C → S Toggle own audio
chat:call:toggle_video C → S Toggle own video
chat:call:toggle_screen C → S Toggle screen share
chat:call:rtc_offer C → S / relay Relay SDP offer to peer
chat:call:rtc_answer C → S / relay Relay SDP answer to peer
chat:call:rtc_ice C → S / relay Relay ICE candidate to peer
chat:call:get_state C → S Query current activity state
chat:activity:stream_meta C → S / S → Room Stream metadata update (audio/video/screen info)
chat:activity:stream_meta_remove C → S / S → Room Remove stream metadata
chat:activity:stream_route C → S Route audio/video stream to device
chat:activity:get_streams C → S Get current active streams
chat:call:state S → Room Full participant list
chat:activity:stream_state S → Room Stream state broadcast
chat:call:peer_joined S → Room Participant joined
chat:call:peer_left S → Room Participant left
chat:call:media_state S → Room Participant media state changed
chat:call:resend_meta S → Client Request meta resend after reconnect

Notifications & Push

Event Direction Description
chat:notification S → User New notification
chat:notification_updated S → User Notification updated
chat:push:register C → S Register push token
chat:push:unregister C → S Unregister push token

Games

Event Direction Description
chat:game_start C → S Start a game in a room
chat:game_end C → S End a game
chat:game_move C → S Submit a game move
chat:game_request_state C → S Request current game state
chat:game_state S → Room Game state update
chat:game_ended S → Room Game finished

Server Logs

Event Direction Description
chat:logs:subscribe C → S Start streaming server logs (requires view:server_logs)
chat:logs:unsubscribe C → S Stop streaming server logs
chat:logs:entry S → Client Server log entry

Connections & Social

Event Direction Description
chat:connection_request S → User Incoming connection request
chat:connection_accepted S → Both Connection accepted
chat:navigate_to_room S → User Navigate to newly created DM room
chat:connection_removed S → Both Connection removed
chat:sidebar_layout_updated S → User Sidebar layout saved

Programmatic API

chat_server exports a Chat object for use by other modules:

Doh.Module('my_module', ['chat_server'], function(Chat) {
  // Create a system room
  const room = await Chat.createSystemRoom({
    name: 'Issue #42',
    type: 'issue',
    members: ['alice', 'bob'],
    adminUser: 'alice'
  });

  // Manage membership
  await Chat.addMemberToRoom(room.id, 'charlie', 'member');
  await Chat.removeMemberFromRoom(room.id, 'bob');

  // Query state
  const online = Chat.isUserOnline('alice');           // boolean
  const rooms = Chat.getUserRooms('alice');             // Room[]
  const msgs = Chat.getRecentMessages(room.id, 50);    // Message[]
  const isMember = Chat.isRoomMember(room.id, 'alice'); // boolean
  await Chat.deleteRoom(room.id);
});

Exported Functions

Function Params Returns Description
createSystemRoom(config) { name, type?, members?, created_by?, is_public?, allow_guests?, adminUser? } Room Create room programmatically
addMemberToRoom(roomId, username, role?) string, string, 'member'|'admin' MemberRecord | null Add member
removeMemberFromRoom(roomId, username) string, string void Remove member
deleteRoom(roomId) string boolean Delete room and all data
getChatName(user) user object string Get chat display name for a user
isUserOnline(username) string boolean Check presence
trackUserOnline(socket, user) socket, user void Register presence
trackUserOffline(socket) socket void Unregister presence
getOnlineUsers() -- [{ username, chat_name, status }] All online users
broadcastUserPresence(user, online) user, boolean void Emit chat:presence to lobby
getRoomById(roomId) string Room | null Fetch room
getUserRooms(username) string Room[] User's rooms
getPublicRooms() -- Room[] All public rooms
getRecentMessages(roomId, limit?) string, number Message[] Fetch messages
isRoomMember(roomId, username) string, string boolean Check membership
canParticipate(user) user boolean Has chat_name set

Client Patterns

Core UI (chat_client.js)

Pattern Parent Purpose
ChatApp ['ChatConversation', 'ChatAppSocket'] Top-level app: sidebar, room state, nickname setup; shows partner status in DM room headers
ChatAppSocket (mixin, no parent) Unified socket event wiring for app-level concerns: presence, room CRUD, unread, notifications, activity state; used by both ChatApp and ChatMessengerBar
ChatConversation html Shared base for ChatApp (full page) and ChatMessengerPopup (floating window): per-conversation messages, input, controls, socket wiring
ChatSidebar ['html', 'DohtopWindowBehavior'] Left nav: rooms, DMs, folders, issues section, user panel with clickable status picker. Pin/unpin toggle (default unpinned): unpinned = auto-sizing menu anchored above dock; pinned = persistent draggable/resizable window
ChatStatusPicker html Floating or inline status picker (Online/Away/Busy/Offline); used by sidebar and settings
ChatMessageList html Message container with layout modes (linear/thread/grouped)
ChatMessage html Single message: avatar, content, actions, attachments
ChatInput html Textarea with emoji picker, file attach, link preview, auto-resize
ChatTypingIndicator html "User is typing..." display
ChatNicknameSetup html First-login nickname prompt

Content Tiles

Pattern Parent Purpose
ChatCollabTile html Embedded collab document tile with mini editor
ChatCollabCreatePopover html Popover for creating new collab documents
ChatLogTile html Log/trace content display (URLs, stack traces)
ChatUrlTile html Unfurled URL preview (title, description, thumbnail)
ChatUrlOverlay html Full-page URL preview expansion
ChatDropPopover html File drag-and-drop preview popover

Modals & Menus

Pattern Parent Purpose
ChatAddMenu html Dropdown: create room, contact, folder, doc, bot
ChatModal html Base modal dialog container
ChatEmojiPickerModal html Emoji picker modal
ChatAddContactModal html Add contact by username
ChatUserPickerModal html Multi-select user picker
ChatFolderContextMenu html Folder right-click: rename, delete
ChatRoomContextMenu html Room right-click: rename, delete, archive

Settings Panels

Pattern Parent Purpose
ChatSettings html Root settings container with tab nav
ChatSettingsAccount html Profile, password, preferences, inline status picker
ChatSettingsAppearance html Theme, font size, message layout
ChatSettingsExtensions html Plugins management
ChatSettingsAIKeys html AI provider API key management
ChatSettingsUsage html Token usage analytics
ChatSettingsAIBots html Bot definitions and config
ChatSettingsNotifications html Sound, desktop, mute rules
ChatSettingsAttachments html File upload limits
ChatSettingsStorage html Local cache, export/import
ChatSettingsSchedules html Scheduled task management
ChatSettingsConnections html Integrations management
ChatSettingsFiles html File management and room files
ChatSettingsDashboard html Admin dashboard
ChatSettingsMaintenance html Admin tools (delete rooms, diagnostics)
ChatSettingsTesting html Admin AI provider testing
ChatSettingsFeatureStats html Admin feature adoption analytics

Sidebar Items

Pattern Parent Purpose
ChatSidebarNode html Base tree node (draggable, selectable)
ChatRoomItem html Room in sidebar with unread badge
ChatFolderItem html Folder with expand/collapse
ChatOnlineAvatars html Online user avatar row
ChatMiniProfile html User hover card

Utility

Pattern Parent Purpose
ChatToast html Temporary notification
NotificationBell html Header notification icon with unread count badge
NotificationCenter html Dropdown notification list with mark-read and clear-all
NotificationItem html Single notification row in the dropdown
NotificationToast html Notification popup with action buttons (view, mark read)
ChatEmojiPicker html Floating emoji picker
ChatApprovalCard html Bot approval request card (accept/reject/dismiss)
ChatExpandableTile html Base collapsible tile for embedded content
ChatTextTile ChatExpandableTile Inline text/note tile
ChatRoomTile ChatExpandableTile Embedded sub-room tile (from jelly merge)
ChatCreateGroupModal html Group room creation dialog
ChatInvitePickerModal html Room invite user picker
ChatSwarmPickerModal html Multi-bot swarm picker
ChatContextFlyout html Context menu flyout
ChatActivityRollup html Folds consecutive system messages into a collapsible summary
ChatUsersPanel html User list panel for room members and online users
ChatUrlBrowserPanel html Moved to url_browser module. URL browser panel with address bar, navigation, proxy toggle — see doh_chat/url_browser/.
ChatRoomFileViewer html Room file viewer for browsing room attachments. Supports _storagePrefix for per-window localStorage isolation and onFiltersChanged callback. loadRoom() accepts a single ID, array of IDs, or null.
FilesDohtopContent html Files DohtopWindow content: room sidebar + ChatRoomFileViewer. Supports multi-instance via _windowId, dynamic title sync, room context menus, and getContextMenuItems() for dock menu extension.
ChatEmptySpaceContextMenu html Right-click on empty sidebar space
ChatMessageContextMenu html Message right-click menu
ChatFileContextMenu html File attachment context menu

Activities UI (chat_calls_client.js)

Pattern/Object Parent Purpose
ChatCallManager object WebRTC peer connections, media tracks, activity state
ChatCallIndicator html Room header badge: active activity, join buttons
ChatActivityIndicator html Streaming activity indicator (typing, tool use, multi-device)
ChatCallBar html Controls during activity: mute, video, screen share, leave, grid
ChatCallRoomBadge html Room sidebar badge showing participant count

Architecture Notes

Unified Socket Architecture

All real-time features share a single Doh.socket connection. The client uses two composable patterns:

ChatAppSocket — a mixin pattern (no parent, non-html) that handles app-level socket events shared across all chat surfaces. Defines melded Method hooks (onPresenceChanged, onRoomCreated, onRoomUpdated, onRoomInvite, onRoomDeleted, onMemberRemoved, onUnreadUpdate, onSidebarLayout, onNotification, onNotificationUpdated) with base implementations that update centralized stores. Wired via wireAppSocket().

ChatConversation — a shared html base for per-conversation UI (messages, input, typing, controls). Both ChatApp (full page) and ChatMessengerPopup (floating window) extend it. Provides setupCoreSocketListeners() for message CRUD, layout sync, reactions, games, and format changes. Also provides setupCoreTypingListeners() for typing indicators.

Composition: ChatApp inherits both — Pattern('ChatApp', ['ChatConversation', 'ChatAppSocket'], {...}). ChatMessengerBar separately calls wireAppSocket() for app-level events, while each ChatMessengerPopup extends ChatConversation for its own conversation scope.

Client Stores

Four singleton stores provide reactive data across all chat surfaces:

  • ChatUserStore — user display data cache (chat_name, avatar_salt, avatar_style). Messages only carry sender (username); display data resolves from this store at render time. Methods: update(), get(), subscribe(), renderAvatar(), seedFromRooms(), seedFromSenders().

  • ChatPresenceStore — online/away/busy/offline status per user. On reconnect, all cached users reset to offline before re-seeding. Methods: update(), get() (defaults to 'offline'), subscribe().

  • RoomActivityStore — live activities per room (activities, games, open windows). Tracks participant counts, voice/video/screen flags, active games, and local activity state. Methods: update(), get(), seed(), setLocalCall(), setOpen(), subscribe(), _fromCallSummary().

  • ChatRoomStore — centralized room object cache. Lazy-fetches from /api/chat/rooms on first ensure(), dedupes concurrent calls, and auto-seeds ChatUserStore for DM partner data. Kept live by socket events (chat:room_createdupdate(), chat:room_updatedupdate(), chat:room_deletedremove()). Bulk-seeded by ChatApp.loadRooms() and ChatSidebar messenger mode via seed() to avoid redundant fetches. Methods: ensure(), get(roomId), getAll(), update(room), remove(roomId), seed(rooms), subscribe(fn).

  • CollabDocStore — centralized collab document metadata cache (id, title, type, owner, language, updated_at). SPR source declaration (= {}) on Doh.Globals.CollabDocStore for cross-module access. Lazy-fetches from /api/collab/docs/:id on ensure(docId) (deduped). Kept live by collab:doc:meta_updated socket events wired in wireAppSocket(). Surfaces and trackers emit collab:doc:update_meta when their Yjs name changes, which triggers the server broadcast and store update. ChatCollabTile subscribes for live title updates and calls ensure() on mount to refresh stale message-time titles. Methods: ensure(docId), get(docId), update(doc), subscribe(fn).

Files DohtopWindow

The Files browser runs as a DohtopWindow (FilesDohtopContent pattern) with a room-navigation sidebar and a ChatRoomFileViewer panel.

Multi-instance: Multiple Files windows can be open simultaneously. Default click on the Files button opens/restores the singleton 'files' window. Right-click opens the dock context menu of the last-interacted Files window (which includes "New Files Window"). Each window has independent filter state, room selection, view mode, and sidebar width — persisted via per-window localStorage keys (chat-files-<windowId>-*).

Dynamic title: The window title and dock item label reflect the active type filters — e.g. "Files + Docs + Links", "Docs", "Files + Links". Updates on every filter change.

Room sidebar grouping: Rooms are partitioned into three sections:

  1. Regular rooms — displayed with format icons (chatty/notey/jelly/gamey), DM avatars via ChatUserStore, bot gear icons, lobby #
  2. Issues folder — collapsible, starts collapsed, expanding auto-selects all issue files
  3. Deleted Rooms folder — collapsible, starts collapsed, shows orphaned files from destroyed rooms

Filter toggle behavior: Type filters (Files/Docs/Links) and storage filters use click-to-solo, Ctrl/Shift-click-to-toggle. Tooltips show "Hold Ctrl to select multiple". Same toggle pattern for room selection in the sidebar.

Room context menu: Right-click a room in the files sidebar for "Open Room" (navigates in ChatApp) and "Open in New Window".

Orphaned files: The server (/api/chat/files/user) returns files uploaded by the current user whose room was deleted, enriched with room_type: 'deleted' and room_deleted: true. The /api/chat/links/user and /api/chat/collabs/user endpoints similarly return orphaned links/collabs.

Effective User Resolution

Socket handlers resolve user via: socket.user (authenticated) → socket.guestUser (guest) → null

Message Provenance

Every message tracks its edit/delete history:

provenance: [
  { action: 'created', user: 'alice', name: 'Alice', at: 1700000000 },
  { action: 'edited', user: 'alice', name: 'Alice', at: 1700000060 }
]

Testing

  1. Start server and open /chat
  2. Verify: lobby loads, room list populates, nickname prompt appears on first visit
  3. Verify messaging: send, edit, delete, typing indicator
  4. Verify DMs: create DM, send messages, check unread badges
  5. Verify activities: join activity, audio/video toggle, screen share
  6. Verify socket flows: trace updates, browser panel sync in multiple clients
  7. Verify admin: delete empty rooms (requires chat_admin group)
Last updated: 3/27/2026