openvibers/openvibe.chat AGENTS.md

AGENTS.md

main 10.5 KB · 168 lines · markdown

1# AGENTS.md — OpenVibe.Chat
2
3## Project overview
4
5The communication authority of the OpenVibe network: rooms, messages, DMs, group DMs, voice channels
6and calls, TTS/sounds, moderation, presence, and both of Live's chat paths. It was moved out of Live
7behind a service boundary (Wave 6) and has been the authority for `openvibe.live` chat in every mode
8since 2026-09-23; Live runs no chat of its own. Node.js/Express + `ws`, PostgreSQL, CommonJS, **no
9build step**.
10
11- Origin `https://openvibe.chat`; also served on **Live's origin**: nginx routes `/ws/chat`,
12 `/api/chat/`, `/api/dm/`, `/api/tts/`, `/api/sounds`, `/api/emotes` (and, after the calls cutover,
13 `/ws/call` and the call routes under `/api/streams`) to Chat.
14- Port `4400`, unit `openvibe-chat.service`, release root `/opt/openvibe.chat`; `openvibe.party` is
15 Chat's Watch Together host.
16
17## What it owns
18
19- Rooms: global, stream, channel, community, DM/group DM, call, system; servers (groups of rooms as
20 text and voice channels, with roles and invites).
21- Messages, replies/rich payloads, edit history, membership/roles, unread/read state, presence and
22 typing (ephemeral).
23- Moderation state: bans, timeouts, delete/purge, filters, slow/member-only modes, the moderation
24 audit and the moderation read API Live uses (`GET /internal/moderation/*`).
25- TTS/audio/soundboard/channel-sound queues with skip/clear/failure; the call signalling metadata and
26 the `pending/ringing/active/ended/missed/declined/failed` lifecycle.
27- The tables moved from Live: `chat_messages`, the DM tables, `tts_voice_overrides`,
28 `channel_sounds`, `relay_users`, `hidden_relay_users`, `pending_ip_messages`,
29 `stream_first_chats`, `moderation_actions`, plus `channel_moderators`,
30 `channel_moderation_settings`, `emotes`, `user_tags`, `chat_ai_summaries`,
31 `chat_timeline_events`. Live keeps no copy and reads through the internal API.
32- Rooms, Vibe (the assistant), support inboxes, the website widget, feeds, `openvibe.party`, agent
33 rooms and chat apps.
34
35**Stays in Live:** `media_requests` and `media_request_settings`. Do not grow Live's chat tables back.
36
37## Who calls it, and whom it calls
38
39- Callers: browsers on `openvibe.chat` and Live's origin; Live (internal reads, bridge and event
40 consumer); Bot (chat-app bridge); Actor (asks); other services with a Network service token
41 audience `openvibe.chat` and a `chat.*` capability.
42- Depends on: Network (identity, SSO, service tokens, the `chat.preferences` module, VIP badges),
43 Live (channel/stream context through `server/live-context.js` — the only module that talks to Live),
44 Events (outbox and subscriptions), Media (emote image bytes, namespace `chat`), AI
45 (`server/ai/`, off unless enabled), VIP (optional; without it nobody has a badge), Tools/Search
46 where the assistant needs them.
47
48## Repository map
49
50- **Entry:** [server/index.js](server/index.js) — database, first Live sync, chat and call WebSocket
51 servers, HTTP app with the Events consumer and `POST /internal/events`, background loops,
52 subscription check, graceful stop (tells clients the chat is restarting).
53- **App:** [server/app.js](server/app.js) — Live's guards for these routes: credentialed CORS for an
54 exact origin list, `/api` rate limit, IP/network bans, `ov_banned` cookie, WS origin+IP checks.
55- **Config:** [server/config.js](server/config.js); database [server/db/database.js](server/db/database.js)
56 (`openDb`, migrations via `DATABASE_DIRECT_URL`).
57- **Chat core:** [server/chat/](server/chat/) — `chat-server.js`, `dm.js`, `dm-routes.js`,
58 `history-store.js`, `moderation-utils.js`, `word-filter.js`, `deploy-notice.js`, the T3 APIs.
59- **Calls:** [server/calls/](server/calls/) — call server, lifecycle, REST routes, Live stream hooks.
60- **Rooms/servers:** [server/rooms/](server/rooms/) — `rooms.js`, `servers.js`, `vibe.js`,
61 `workspace.js`, parties, memory, feeds.
62- **Events:** [server/events/](server/events/) — `service-outbox.js`, `consumer.js`, `subscriptions.js`.
63- **Auth/net:** [server/auth/](server/auth/), [server/net/](server/net/) (service tokens, client IP).
64- **Browser:** [public/web/](public/web/) — `chat.js`, `chat-shell.js`, `call.js`, `vibe.js`,
65 `widget.js`, `embed.js`, `party.js`, `feed-view.js`, plus their CSS.
66- **Deploy:** [deploy/systemd/openvibe-chat.service](deploy/systemd/openvibe-chat.service),
67 [deploy/nginx/openvibe.chat.conf](deploy/nginx/openvibe.chat.conf),
68 [deploy/nginx/openvibe.live-chat.locations.conf](deploy/nginx/openvibe.live-chat.locations.conf),
69 [deploy/nginx/calls/openvibe.live-calls.locations.conf](deploy/nginx/calls/openvibe.live-calls.locations.conf).
70
71## Commands
72
73```bash
74npm ci
75npm run dev # NODE_ENV=development node server/index.js
76npm start # node server/index.js, http://127.0.0.1:4400
77npm test # test/run.js: every file in its own process, PGlite per process
78npm run test:pg # same on PostgreSQL + PgBouncer + Valkey (containers)
79npm test -- ws import # filter by file name; --strict makes a skip fail
80npm run n-1:record # record the N-1 fixtures after a deploy
81ov test # the harness's sharded run of what the change reaches
82```
83
84## Database and migrations
85
86Chat's own PostgreSQL database on the host's data role (`add-service.sh chat`); development and
87tests use embedded PGlite, PostgreSQL in production through PgBouncer. Migrations are
88`migrations/NNNN_*.sql`, applied at boot with the owner connection (`DATABASE_DIRECT_URL`), then the
89app serves through the pooled runtime role (`DATABASE_URL`, DML only). Never edit an applied
90migration. The moved tables keep Live's ids and columns plus Network subject columns
91(`subject_id`, `sender_subject_id`, …). `docs/parity.md` records the parity method.
92
93## Auth and the WebSocket rules
94
95- People sign in with a Network session JWT, verified against the Network key; tokens issued before a
96 subject's `token_valid_after` are refused. `hbt_` API tokens are resolved through Live.
97- A WebSocket upgrade authenticates with an `Authorization: Bearer` header only (bots); a browser's
98 socket starts anonymous and presents its token in the first message (`join`, `join_room`,
99 `auth-update`). **Neither the `ov_token` cookie nor `?token=` in the URL signs a socket in** (removed
100 2026-10-10); a token in the URL gets a `system` frame saying to use the header or `join`.
101- The `ov_token` cookie only exempts staff from a network/IP ban at upgrade.
102- Services use client-credentials tokens for audience `openvibe.chat`, checked per capability
103 (`chat.live_bridge.write`, `chat.message.send`, `chat.presence.read`, `chat.moderation.read`, …).
104- DMs go only to participants, private rooms only to members; network blocks count like DM blocks; a
105 staff member reading someone else's chat is recorded as a moderation action.
106
107## Frontend loading model
108
109Browsers load plain, no-build scripts from [public/web/](public/web/) on Chat's own site; Live's
110origin keeps Live's existing chat JavaScript and talks to the same sockets/APIs (the Wave 6 rule was
111"move behind a service boundary before changing behaviour"). There is no SPA, bundler or transpiler.
112`openvibe-shared` supplies the Frame and `/shared/*` from the pinned node_modules. The widget is a
113shadow-root bubble under 3 KB compressed; embeds and `openvibe.party` are separate pages/scripts.
114
115## Deploy
116
117`sudo ovhost deploy chat` (git-checkout: fetch, fast-forward `/opt/openvibe.chat`, install on a
118lockfile change, restart, wait for **`/ready`**, not `/api/ready`). Unit `openvibe-chat.service` on
119`127.0.0.1:4400`, env `/etc/openvibe/chat.env`; vhosts
120[deploy/nginx/openvibe.chat.conf](deploy/nginx/openvibe.chat.conf) and the Live locations include
121(inside Live's `server { … }`). After a deploy, record the N-1 fixtures (`npm run n-1:record`).
122Rollback is a Chat release rollback (`sudo ovhost rollback chat --to <sha>`), never a switch back to
123Live. Migrations only add tables and columns.
124
125## Tests
126
127`npm test` runs each `test/*.test.js` in its own process (60 s) against one migrated PGlite database
128per process (`test/helpers/pg-preload.mjs`); `npm run test:pg` uses the PostgreSQL/PgBouncer/Valkey
129containers. The suite covers the WS gates and commands, DMs and privacy, history latency, moderation
130and staff audit, calls and capture-on-load, TTS/audio queues, rooms/servers/Vibe, the widget/embeds,
131feeds, chat apps, Events consumption, account export/deletion and the N-1 fixtures. `ov test` runs the
132same.
133
134## Conventions
135
136- CommonJS; 4-space indent in the newer modules, Live's original style preserved in the moved files.
137- `server/live-context.js` is the **only** module that talks to Live; do not call Live from routes.
138- Errors are problem+json or the chat frames' own stable codes; never leak a DM, a staff log or a
139 token into a response or a log.
140- CORS and WS origins are exact origins; no wildcard for credentialed requests.
141
142## Pitfalls
143
144- **A token in the socket URL or a cookie must not sign the socket in** (C-05/C-06). Keep the
145 first-message auth and the `Authorization` header for bots.
146- **Chat is required in every mode.** Live's chat routes are retired; do not add a fallback to Live.
147- **The CORS/WS origin list is exact.** `*.openvibe.tools` must not be honoured: a credentialed grant
148 would let it read signed-in DMs.
149- **`/internal/*` and `/metrics` must stay unreachable through nginx** (404 there); nginx sets the
150 client address from the connection only.
151- **DM privacy:** participants only, block-aware, and staff reads are audited moderation actions.
152- **Bans/mutes are Chat's**, and Live reads moderation through the internal API; `media_requests`
153 remains Live's.
154- **Readiness is `/ready`**, not `/api/ready` — the standard deploy probe assumes the latter.
155- **Do not "fix" a message by editing the store**: the Live bridge mirrors changes; use the service
156 paths so events, the bridge and Search stay consistent.
157- **N-1 fixtures** are part of shipping: record them after the deploy.
158
159## Documentation
160
161- [README.md](README.md) — the product, cutover, data, events, rooms, Vibe, inboxes, feeds, deploy.
162- [docs/platform.md](docs/platform.md) — agent rooms and the digest Code/Chat/Actor use.
163- [docs/vibe-personas.md](docs/vibe-personas.md) — the persona shape, the topic check, models, spend cap, owner page and tests.
164- [docs/chat-ingress.md](docs/chat-ingress.md) — `/internal/chat/*` tickets and reads.
165- [docs/calls-cutover.md](docs/calls-cutover.md), [docs/parity.md](docs/parity.md),
166 [docs/chat-apps.md](docs/chat-apps.md), [docs/party-pool.md](docs/party-pool.md).
167- `openvibe-contracts` holds `chat.*` shapes and capabilities.
168