openvibers/openvibe.tips AGENTS.md
AGENTS.md
| 1 | # AGENTS.md — OpenVibe.Tips |
| 2 | |
| 3 | ## Project overview |
| 4 | |
| 5 | OpenVibe.Tips (`https://openvibe.tips`) is creator support: tips, goals, paid messages, TTS and media |
| 6 | requests, paid sounds, creator posts and overlays. It orchestrates Billing, Chat, Live and Media and |
| 7 | owns the **interaction**; money never lives here (ADR-012). |
| 8 | |
| 9 | - **Entry:** `server/index.js`; app `server/app.js`; port `4610`, service id `tips`. |
| 10 | - **API:** `server/api/v1.js`, auth `server/api/auth.js`, idempotency `server/api/idempotency.js`, |
| 11 | subject assertion `server/api/subject-assertion.js`, limits `server/api/actor-limits.js`. |
| 12 | - **Domain:** `server/domain/` — `interactions.js`, `goals.js`, `overlays.js`, `overlay-hub.js`, |
| 13 | `sounds.js`, `paid messages`/`effects.js`, `posts.js`, `profiles.js`, `moderation.js`, |
| 14 | `privacy.js`, `account-data.js`, `support-links.js`, `markdown.js`, `filter.js`. |
| 15 | - **Delivery and clients:** `server/delivery/` (chat adapter), `server/clients/live-now.js`, |
| 16 | `server/vip/client.js`, `server/events/` (Billing inbox and outbox). |
| 17 | - **Pages:** `server/web/` (`pages.js`, `routes.js`, `layout.js`, `session.js`, `multipart.js`) renders |
| 18 | the creator pages and overlays; `public/css` and `public/js` are small enhancements. No bundler. |
| 19 | - **Docs:** `docs/threat-review.md`; `npm run subscribe` creates the Events subscriptions. |
| 20 | |
| 21 | ## Owns, does not own |
| 22 | |
| 23 | Owns `tip_interactions`, `creator_tip_profiles`, `tip_goals`, `tip_goal_contributions`, |
| 24 | `paid_messages`, `paid_media_requests`, `creator_sounds`, `overlay_configs`, `overlay_deliveries`, |
| 25 | `interaction_effects` (PostgreSQL `ov_tips`) — interaction state and **references to Billing |
| 26 | transaction ids, never a mutable cash balance** — and revocable scoped overlay tokens |
| 27 | (`overlay_tokens`, hashed at rest; never creator cookies). |
| 28 | |
| 29 | Does not own: monetary accounting, prices, balances, refunds or payouts (Billing); chat rooms, TTS |
| 30 | synthesis and queues (Chat); media bytes and the media queue (Media/Live); identity (Network). |
| 31 | |
| 32 | ## Who calls it, what it calls |
| 33 | |
| 34 | People use the pages and the API with their own Network Bearer token; services use a |
| 35 | client-credentials token for audience `openvibe.tips`, one capability per route. SDK |
| 36 | `openvibe-sdk/tips` is the client surface (`tip`, messages/TTS/media/sound, goals, receipts, overlay |
| 37 | tokens, export/erase). Tips calls Network (SSO, JWKS), Billing (checkout/intent, |
| 38 | entitlements/transactions), Events (subscriptions and the outbox), Chat (`TIPS_CHAT_ADAPTER=chat` |
| 39 | posts the chat lines/alerts), Live (channel goal/tip history) and Media (bytes). Billing's events |
| 40 | arrive signed (`TIPS_EVENTS_SECRET`) through an inbox that dedupes them. |
| 41 | |
| 42 | ## Database and migrations |
| 43 | |
| 44 | PostgreSQL `ov_tips` through `openvibe-sdk/db` (PgBouncer for reads/writes, owner role for |
| 45 | migrations); Valkey holds shared state. Migrations `migrations/NNNN_*.sql` run at boot and are |
| 46 | **expand-only** until a contract release: never edit one that has run, never drop or rename a |
| 47 | column/table that an older release still reads. State lives in `/var/lib/openvibe-tips`. |
| 48 | Idempotency receipts are stored, not held in memory. |
| 49 | |
| 50 | ## Auth and idempotency |
| 51 | |
| 52 | Network RS256 JWTs (JWKS) and SSO on the pages. **The API never reads cookies**: people present a |
| 53 | Bearer user token and act on their own things; services present a service token and the capability |
| 54 | for the route. Overlays use revocable, scoped tokens hashed at rest — never a creator cookie. |
| 55 | Every POST/PATCH carries `Idempotency-Key`; the key is claimed before the handler runs, so the same |
| 56 | key twice at once runs once and the second gets `409 idempotency.in_progress` with `Retry-After` |
| 57 | until the first answer is stored and replayed. `/internal/` and `/metrics` are never public. |
| 58 | |
| 59 | ## Deploy |
| 60 | |
| 61 | `sudo ovhost deploy tips` (git-checkout: fetch, fast-forward `/opt/openvibe.tips`, install on a |
| 62 | lockfile change, restart, wait for `/api/ready`; rollback `sudo ovhost rollback tips --to <sha>`). |
| 63 | Unit `openvibe-tips.service` on `127.0.0.1:4610`, env `/etc/openvibe/tips.env`, nginx |
| 64 | `deploy/nginx/openvibe.tips.conf` (live since the 2026-10-17 launch). |
| 65 | |
| 66 | ## Commands and tests |
| 67 | |
| 68 | ```bash |
| 69 | npm ci |
| 70 | npm run dev # http://127.0.0.1:4610 |
| 71 | npm test # every test/*.test.js, in-process stubs, temp DB |
| 72 | npm test -- overlays import # only matching files |
| 73 | npm run test:pg # the same on PostgreSQL |
| 74 | npm run subscribe # create the Events subscriptions once |
| 75 | ``` |
| 76 | |
| 77 | `test/run.js` uses `openvibe-shared/test-runner` (60 s, serial); stubs of Network, Billing, Events |
| 78 | and Live, temp databases and random ports, never the network. Coverage includes billing-client |
| 79 | contracts, idempotency, the moderation/filter/markdown rules, overlays and their hub, delivery, |
| 80 | pages/empty states, open redirects, account data and the threat-review cases. |
| 81 | |
| 82 | ## Conventions and pitfalls |
| 83 | |
| 84 | - CommonJS, 4-space indent, single quotes, semicolons; problem+json errors and escaped HTML. |
| 85 | - **Tips never moves money.** It creates Billing intents/transfers and stores Billing ids; every |
| 86 | balance, refund and payout question is Billing's. A local "balance" field is a bug. |
| 87 | - **Settlement is not interaction.** Always distinguish payment settled from interaction recorded; |
| 88 | a failed/refunded payment must not leave a delivered paid message without its state. |
| 89 | - **Keep the idempotency claim** before any side effect, and store the answer for replay; a retry |
| 90 | from Billing or the browser must not double-post a message, sound or tip. |
| 91 | - **Overlay tokens are revocable and hashed at rest.** Never put a creator session cookie in an |
| 92 | overlay URL or log a token. |
| 93 | - **Billing events are signed and deduped**; an unsigned delivery is refused and a redelivery changes |
| 94 | nothing. |
| 95 | - **Deleting a person does not delete the books:** the creator's settings/overlays/moderators go, the |
| 96 | amount and its Billing reference stay, and a pending payment is kept for reconciliation. |
| 97 | - Paid content respects the moderation/filter rules in `server/domain/filter.js` and |
| 98 | `moderation.js`; the API never trusts text or a media URL from the client. |
| 99 |