openvibers/openvibe.tips Commits
README and STATUS: launched 2026-10-17 at openvibe.tips; chat through OpenVibe.Chat; Live's goal from tips.interaction.ready (#64)
Changes
@@@ -2,11 +2,13 @@> Creator support: tips, goals, paid messages, TTS, media requests and paid sounds, overlays.--**Status:** alpha — runtime built and tested against stubs (roadmap Wave 9). Deployed internally, not--launched: running on the host since 2026-09-23 on `127.0.0.1:4610` only, with no--creator profile yet, with no public route. OpenVibe.Live remains where tips happen until the Billing cutover (see *What waits*).++**Status:** alpha — **launched 2026-10-17** at [openvibe.tips](https://openvibe.tips) (openvibe-contracts 0.200.0), right++after the Billing cutover made OpenVibe.Billing the money ledger. Tips posts its chat lines and alerts through++OpenVibe.Chat (`TIPS_CHAT_ADAPTER=chat`), records a streamer's own PowerChat tips from Billing, and OpenVibe.Live++moves its channel goal and tip history from `tips.interaction.ready`. Paid sounds since the same day. On launch day++production held the 139 interactions imported from Live and no creator profile yet.Data: PostgreSQL through PgBouncer, and Valkey for shared state ([ADR-035](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-035-postgresql-and-valkey.md));--**Domain:** `openvibe.tips` (keeps its OpenVibe.Sites placeholder until the launch rule below holds)++**Domain:** `openvibe.tips`**Port / service id:** 4610 / `tips`**Decision:** [ADR-012](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-012-economic-classification.md) — Tips never moves money; Billing does.**Plan:** OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026), §11.2; roadmap Wave 9, §15.11, §29.@@@ -83,10 +85,9 @@ npm run test:pg # every test file through PgBouncer and Valkeynpm run subscribe # create the billing.transaction.* and billing.receipt.* subscriptions in OpenVibe.Events```--Production (deployed, loopback only): `/opt/openvibe.tips`, env `/etc/openvibe/tips.env`, unit--[deploy/systemd/openvibe-tips.service](deploy/systemd/openvibe-tips.service) (state in `/var/lib/openvibe-tips`).--The vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf) is not installed yet:--`openvibe.tips` still serves the Sites placeholder.++Production: `/opt/openvibe.tips`, env `/etc/openvibe/tips.env`, unit++[deploy/systemd/openvibe-tips.service](deploy/systemd/openvibe-tips.service) (state in `/var/lib/openvibe-tips`),++vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf) (installed 2026-10-17: `openvibe.tips` serves Tips).## Design@@@ -328,10 +329,9 @@ minutes); a creator with no Live account fails at once. The body is rebuilt on einteraction's current public view, so a word-filter change between attempts makes Chat answer 409, whichfails the effect. A job carries the interaction's public view and `privacy`: "Anonymous" and no subjectfor an anonymous supporter, `amount: null` and a line without the amount when it is hidden, no private--message. `test` records jobs in memory (development; simulations always use it). `none` (the production--default) creates no chat effects, and it is what production runs. To enable delivery: grant the `tips`--principal the three capabilities above, then set `TIPS_CHAT_ADAPTER=chat` (and `TIPS_CHAT_URL` when Chat--is not on `127.0.0.1:4400`).++message. `test` records jobs in memory (development; simulations always use it). `none` (the default) creates++no chat effects. Production runs `chat` since the launch (2026-10-17): the `tips` principal holds the three++capabilities above (`TIPS_CHAT_URL` only when Chat is not on `127.0.0.1:4400`).## Pages (server-rendered, useful without JavaScript)@@@ -406,18 +406,15 @@ With `VALKEY_URL` every process counts one caller together (`test/integration.te## What waits--- **Billing cutover** (Billing README runbook): until Live's money writes go through Billing, real tips-- still happen on Live; Tips can only record them from Billing events once Live sends donations as-- Billing transfers. For PowerChat checkout, Billing answers with a `checkout_ref` and no URL — Tips needs-- `TIPS_POWERCHAT_LINK_TEMPLATE` or Billing returning the link.--- **EXTERNAL PowerChat tips** arrive as `billing.receipt.external` once Billing is the authority. They need-- the `billing.receipt.*` subscription (`npm run subscribe`) and `TIPS_CHAT_ADAPTER=chat`; the chat-- adapter posts the chat line and plays the alert but does not advance **Live's own**-- `donation_goals` or send its `goal-update`/`goal-reached` frames (Tips' goals and overlay do advance).++- **PowerChat checkout from openvibe.tips**: Billing answers a PowerChat checkout with a `checkout_ref` and no++ URL, and `TIPS_POWERCHAT_LINK_TEMPLATE` is not set in production, so supporters on openvibe.tips pay with Vibes++ credit. (Tips on a streamer's own PowerChat page do arrive: `billing.receipt.external`, see below.)++- **EXTERNAL PowerChat tips** arrive as `billing.receipt.external` since the Billing cutover (2026-10-17), through++ the `billing.receipt.*` subscription; the chat adapter posts the chat line and plays the alert, and Live advances++ its own channel goal and tip history from `tips.interaction.ready` (OpenVibe.Live `server/tips/tips-events.js`).PowerChat follow/host/channel-points/subscription notices are not forwarded by anyone.--- **Chat**: `TIPS_CHAT_ADAPTER=chat` needs the Network to grant `tips` `chat.message.send` and-- `chat.event.publish` (audience `openvibe.chat`) and `identity.subject.resolve`. Paid media requests have-- no delivery route (Chat does not own the media queue): with `chat` they are recorded failed.++- **Paid media requests** have no delivery route (Chat does not own the media queue): with `chat` they are++ recorded failed.- **Refunds of paid media requests** that never played (Billing's `POST /transfers/:id/refund`) are notoffered in Tips yet; a refund made elsewhere arrives as `billing.transaction.reversed` and is applied.- Legal pages use the shared `ugc` profile, which does not describe payments.@@@ -428,16 +425,15 @@ Production deploys with `sudo ovhost deploy tips` on the host (strategy `git-chefast-forward `/opt/openvibe.tips`, install on a lockfile change, restart, wait for `/api/ready`).The unit is `openvibe-tips.service` on `127.0.0.1:4610`, the env file `/etc/openvibe/tips.env`. State lives in`/var/lib/openvibe-tips`. The vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf)--waits for the launch: `openvibe.tips` serves the Sites placeholder.++serves `openvibe.tips` since the launch (2026-10-17).Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after therestart; afterwards `sudo ovhost rollback tips --to <sha>`. Migrations are expand-only until a`contract` migration, which waits out the 7-day N-1 window.## Launch rule--This repository does not make the product real, and the domain keeps its placeholder page on--[OpenVibers/OpenVibe.Sites](https://github.com/OpenVibers/OpenVibe.Sites) until all of the following--exist here (plan §12.12):++Held on 2026-10-17, when `openvibe.tips` launched (openvibe-contracts 0.200.0 made Tips `live`; Network stopped++parking the domain). The rule, as written before the launch (plan §12.12):1. an owning runtime with health/readiness endpoints and observability — ✔ `/api/health`, `/api/ready`(openvibe-shared/ready: the database required and reporting the store that answered; Valkey, the@@@ -446,15 +442,14 @@ exist here (plan §12.12):2. canonical identity/auth integration (Network subjects, scoped service principals) — ✔; the `tips`principal is provisioned on the host;3. server-rendered public routes useful without JavaScript — ✔;--4. real persistence and end-to-end workflows — ✔ against stubs; not yet against the real Billing and-- Events (Billing is in shadow and has sent no events; production has no creator profile yet);++4. real persistence and end-to-end workflows — ✔, against the real Billing and Events since the cutover++ (2026-10-17);5. capability and event registration against OpenVibe.Contracts — ✔ v0.15.0, payload schemas in v0.30.2 and v0.32.0 (v0.79.0 pinned);6. a migration/seed strategy ✔, a written threat review ✔ ([docs/threat-review.md](docs/threat-review.md),internal; an independent review is still due), and sitemap/robots ✔ (no feed);7. acceptance tests proving the advertised functionality — ✔ (table above).--The launch release removes the domain from `OpenVibe.Sites/sites.json`, switches routing and registers--maturity in the ecosystem registry atomically. A placeholder is never counted as an implemented service.++A placeholder is never counted as an implemented service.---@@@ -7,14 +7,15 @@"adr": "ADR-012","authoritative": false,"deployed": true,-- "deployment": "Deployed internally, not launched: deployed with `sudo ovhost deploy tips`, /opt/openvibe.tips, unit openvibe-tips, 127.0.0.1:4610 loopback only; https://openvibe.tips still serves the OpenVibe.Sites placeholder. Principal tips; Events subscriptions billing.transaction.* and billing.receipt.* -> /internal/events (secret rotated 2026-09-24); TIPS_CHAT_ADAPTER is empty (no chat side effects); TIPS_CHAT_ADAPTER=chat delivers through OpenVibe.Chat's ingress once tips is granted chat.message.send, chat.event.publish and identity.subject.resolve.",++ "deployment": "Launched 2026-10-17 at https://openvibe.tips (openvibe-contracts 0.200.0 made Tips live; vhost deploy/nginx/openvibe.tips.conf installed): deployed with `sudo ovhost deploy tips`, /opt/openvibe.tips, unit openvibe-tips, 127.0.0.1:4610 behind nginx. Principal tips; Events subscriptions billing.transaction.* and billing.receipt.* -> /internal/events; TIPS_CHAT_ADAPTER=chat (chat lines and alerts through OpenVibe.Chat). OpenVibe.Live subscribes to tips.interaction.ready for its channel goal and tip history.","database": "PostgreSQL 18 through PgBouncer (transaction mode) as the system of record, Valkey 9 for shared state (per-actor limits, overlay fan-out, overlay stream slots), ADR-035: database ov_tips from OpenVibe.Host's data role, schema in migrations/ (0001_initial expand, 0002_drop_legacy_import contract), async on openvibe-sdk/db v0.28.0, money paths serializable with row locks, PostgreSQL outbox and inbox.","contracts": "openvibe-contracts v0.200.0","sdk": "openvibe-sdk v0.50.1","shared": "openvibe-shared v4.3.0",-- "notes": "Runtime, API, SSR pages, overlays, the Billing settlement consumer and the events outbox are built, tested and deployed, together with /metrics (loopback only), truthful /api/ready (Billing and Events checks), supporter privacy (anonymous, hidden amount, private message), goal and supporter-page settings, export and erasure (tips.interaction.erased), moderation (word filter, hide/show, invited moderators, tips.interaction.moderated) and per-actor limits. Capabilities (18 tips.*) and payload schemas are in openvibe-contracts. No billing.* event had arrived: Billing runs in shadow. A written internal threat review (docs/threat-review.md) with its fixes and test/security.test.js. Not done: an independent security review; the openvibe.tips launch. Live stays the place tips happen until the Billing cutover (blocked on the owner re-pointing the PowerChat webhook) and the launch rule in README.md holds.",++ "notes": "Runtime, API, SSR pages, overlays, the Billing settlement consumer and the events outbox are built, tested and deployed, together with /metrics (loopback only), truthful /api/ready (Billing and Events checks), supporter privacy (anonymous, hidden amount, private message), goal and supporter-page settings, export and erasure (tips.interaction.erased), moderation (word filter, hide/show, invited moderators, tips.interaction.moderated) and per-actor limits. Capabilities (18 tips.*) and payload schemas are in openvibe-contracts. Billing is the money ledger since the cutover (2026-10-17). A written internal threat review (docs/threat-review.md) with its fixes and test/security.test.js. Paid sounds (creators upload up to 12, supporters pay to play one on the overlay) since 2026-10-17. Not done: an independent security review; a PowerChat checkout link for tips made on openvibe.tips (TIPS_POWERCHAT_LINK_TEMPLATE unset: supporters there pay with Vibes credit).","features": ["tips, paid messages, TTS and media requests settled by OpenVibe.Billing (never Tips' own money)",++ "paid sounds: creators upload up to 12 sounds, supporters pay to play one on the overlay, chat names it","goals counted from settled payments only","overlays with revocable scoped tokens and replay without recharging","EXTERNAL PowerChat tips from billing.receipt.external",
@@ -2,11 +2,13 @@
@@ -2,11 +2,13 @@
> Creator support: tips, goals, paid messages, TTS, media requests and paid sounds, overlays.
> Creator support: tips, goals, paid messages, TTS, media requests and paid sounds, overlays.
-**Status:** alpha — runtime built and tested against stubs (roadmap Wave 9). Deployed internally, not
-launched: running on the host since 2026-09-23 on `127.0.0.1:4610` only, with no
-creator profile yet, with no public route. OpenVibe.Live remains where tips happen until the Billing cutover (see *What waits*).
+**Status:** alpha — **launched 2026-10-17** at [openvibe.tips](https://openvibe.tips) (openvibe-contracts 0.200.0), right
+after the Billing cutover made OpenVibe.Billing the money ledger. Tips posts its chat lines and alerts through
+OpenVibe.Chat (`TIPS_CHAT_ADAPTER=chat`), records a streamer's own PowerChat tips from Billing, and OpenVibe.Live
+moves its channel goal and tip history from `tips.interaction.ready`. Paid sounds since the same day. On launch day
+production held the 139 interactions imported from Live and no creator profile yet.
Data: PostgreSQL through PgBouncer, and Valkey for shared state ([ADR-035](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-035-postgresql-and-valkey.md));
Data: PostgreSQL through PgBouncer, and Valkey for shared state ([ADR-035](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-035-postgresql-and-valkey.md));
-**Domain:** `openvibe.tips` (keeps its OpenVibe.Sites placeholder until the launch rule below holds)
+**Domain:** `openvibe.tips`
**Port / service id:** 4610 / `tips`
**Port / service id:** 4610 / `tips`
**Decision:** [ADR-012](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-012-economic-classification.md) — Tips never moves money; Billing does.
**Decision:** [ADR-012](https://github.com/OpenVibers/OpenVibe.Contracts/blob/main/docs/adr/ADR-012-economic-classification.md) — Tips never moves money; Billing does.
**Plan:** OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026), §11.2; roadmap Wave 9, §15.11, §29.
**Plan:** OpenVibe End-to-End Realignment & Implementation Plan, revision 3 (20 Sep 2026), §11.2; roadmap Wave 9, §15.11, §29.
@@ -83,10 +85,9 @@ npm run test:pg # every test file through PgBouncer and Valkey
@@ -83,10 +85,9 @@ npm run test:pg # every test file through PgBouncer and Valkey
npm run subscribe # create the billing.transaction.* and billing.receipt.* subscriptions in OpenVibe.Events
npm run subscribe # create the billing.transaction.* and billing.receipt.* subscriptions in OpenVibe.Events
```
```
-Production (deployed, loopback only): `/opt/openvibe.tips`, env `/etc/openvibe/tips.env`, unit
-[deploy/systemd/openvibe-tips.service](deploy/systemd/openvibe-tips.service) (state in `/var/lib/openvibe-tips`).
-The vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf) is not installed yet:
-`openvibe.tips` still serves the Sites placeholder.
+Production: `/opt/openvibe.tips`, env `/etc/openvibe/tips.env`, unit
+[deploy/systemd/openvibe-tips.service](deploy/systemd/openvibe-tips.service) (state in `/var/lib/openvibe-tips`),
+vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf) (installed 2026-10-17: `openvibe.tips` serves Tips).
## Design
## Design
@@ -328,10 +329,9 @@ minutes); a creator with no Live account fails at once. The body is rebuilt on e
@@ -328,10 +329,9 @@ minutes); a creator with no Live account fails at once. The body is rebuilt on e
interaction's current public view, so a word-filter change between attempts makes Chat answer 409, which
interaction's current public view, so a word-filter change between attempts makes Chat answer 409, which
fails the effect. A job carries the interaction's public view and `privacy`: "Anonymous" and no subject
fails the effect. A job carries the interaction's public view and `privacy`: "Anonymous" and no subject
for an anonymous supporter, `amount: null` and a line without the amount when it is hidden, no private
for an anonymous supporter, `amount: null` and a line without the amount when it is hidden, no private
-message. `test` records jobs in memory (development; simulations always use it). `none` (the production
-default) creates no chat effects, and it is what production runs. To enable delivery: grant the `tips`
-principal the three capabilities above, then set `TIPS_CHAT_ADAPTER=chat` (and `TIPS_CHAT_URL` when Chat
-is not on `127.0.0.1:4400`).
+message. `test` records jobs in memory (development; simulations always use it). `none` (the default) creates
+no chat effects. Production runs `chat` since the launch (2026-10-17): the `tips` principal holds the three
+capabilities above (`TIPS_CHAT_URL` only when Chat is not on `127.0.0.1:4400`).
## Pages (server-rendered, useful without JavaScript)
## Pages (server-rendered, useful without JavaScript)
@@ -406,18 +406,15 @@ With `VALKEY_URL` every process counts one caller together (`test/integration.te
@@ -406,18 +406,15 @@ With `VALKEY_URL` every process counts one caller together (`test/integration.te
## What waits
## What waits
-- **Billing cutover** (Billing README runbook): until Live's money writes go through Billing, real tips
- still happen on Live; Tips can only record them from Billing events once Live sends donations as
- Billing transfers. For PowerChat checkout, Billing answers with a `checkout_ref` and no URL — Tips needs
- `TIPS_POWERCHAT_LINK_TEMPLATE` or Billing returning the link.
-- **EXTERNAL PowerChat tips** arrive as `billing.receipt.external` once Billing is the authority. They need
- the `billing.receipt.*` subscription (`npm run subscribe`) and `TIPS_CHAT_ADAPTER=chat`; the chat
- adapter posts the chat line and plays the alert but does not advance **Live's own**
- `donation_goals` or send its `goal-update`/`goal-reached` frames (Tips' goals and overlay do advance).
+- **PowerChat checkout from openvibe.tips**: Billing answers a PowerChat checkout with a `checkout_ref` and no
+ URL, and `TIPS_POWERCHAT_LINK_TEMPLATE` is not set in production, so supporters on openvibe.tips pay with Vibes
+ credit. (Tips on a streamer's own PowerChat page do arrive: `billing.receipt.external`, see below.)
+- **EXTERNAL PowerChat tips** arrive as `billing.receipt.external` since the Billing cutover (2026-10-17), through
+ the `billing.receipt.*` subscription; the chat adapter posts the chat line and plays the alert, and Live advances
+ its own channel goal and tip history from `tips.interaction.ready` (OpenVibe.Live `server/tips/tips-events.js`).
PowerChat follow/host/channel-points/subscription notices are not forwarded by anyone.
PowerChat follow/host/channel-points/subscription notices are not forwarded by anyone.
-- **Chat**: `TIPS_CHAT_ADAPTER=chat` needs the Network to grant `tips` `chat.message.send` and
- `chat.event.publish` (audience `openvibe.chat`) and `identity.subject.resolve`. Paid media requests have
- no delivery route (Chat does not own the media queue): with `chat` they are recorded failed.
+- **Paid media requests** have no delivery route (Chat does not own the media queue): with `chat` they are
+ recorded failed.
- **Refunds of paid media requests** that never played (Billing's `POST /transfers/:id/refund`) are not
- **Refunds of paid media requests** that never played (Billing's `POST /transfers/:id/refund`) are not
offered in Tips yet; a refund made elsewhere arrives as `billing.transaction.reversed` and is applied.
offered in Tips yet; a refund made elsewhere arrives as `billing.transaction.reversed` and is applied.
- Legal pages use the shared `ugc` profile, which does not describe payments.
- Legal pages use the shared `ugc` profile, which does not describe payments.
@@ -428,16 +425,15 @@ Production deploys with `sudo ovhost deploy tips` on the host (strategy `git-che
@@ -428,16 +425,15 @@ Production deploys with `sudo ovhost deploy tips` on the host (strategy `git-che
fast-forward `/opt/openvibe.tips`, install on a lockfile change, restart, wait for `/api/ready`).
fast-forward `/opt/openvibe.tips`, install on a lockfile change, restart, wait for `/api/ready`).
The unit is `openvibe-tips.service` on `127.0.0.1:4610`, the env file `/etc/openvibe/tips.env`. State lives in
The unit is `openvibe-tips.service` on `127.0.0.1:4610`, the env file `/etc/openvibe/tips.env`. State lives in
`/var/lib/openvibe-tips`. The vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf)
`/var/lib/openvibe-tips`. The vhost [deploy/nginx/openvibe.tips.conf](deploy/nginx/openvibe.tips.conf)
-waits for the launch: `openvibe.tips` serves the Sites placeholder.
+serves `openvibe.tips` since the launch (2026-10-17).
Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the
Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the
restart; afterwards `sudo ovhost rollback tips --to <sha>`. Migrations are expand-only until a
restart; afterwards `sudo ovhost rollback tips --to <sha>`. Migrations are expand-only until a
`contract` migration, which waits out the 7-day N-1 window.
`contract` migration, which waits out the 7-day N-1 window.
## Launch rule
## Launch rule
-This repository does not make the product real, and the domain keeps its placeholder page on
-[OpenVibers/OpenVibe.Sites](https://github.com/OpenVibers/OpenVibe.Sites) until all of the following
-exist here (plan §12.12):
+Held on 2026-10-17, when `openvibe.tips` launched (openvibe-contracts 0.200.0 made Tips `live`; Network stopped
+parking the domain). The rule, as written before the launch (plan §12.12):
1. an owning runtime with health/readiness endpoints and observability — ✔ `/api/health`, `/api/ready`
1. an owning runtime with health/readiness endpoints and observability — ✔ `/api/health`, `/api/ready`
(openvibe-shared/ready: the database required and reporting the store that answered; Valkey, the
(openvibe-shared/ready: the database required and reporting the store that answered; Valkey, the
@@ -446,15 +442,14 @@ exist here (plan §12.12):
@@ -446,15 +442,14 @@ exist here (plan §12.12):
2. canonical identity/auth integration (Network subjects, scoped service principals) — ✔; the `tips`
2. canonical identity/auth integration (Network subjects, scoped service principals) — ✔; the `tips`
principal is provisioned on the host;
principal is provisioned on the host;
3. server-rendered public routes useful without JavaScript — ✔;
3. server-rendered public routes useful without JavaScript — ✔;
-4. real persistence and end-to-end workflows — ✔ against stubs; not yet against the real Billing and
- Events (Billing is in shadow and has sent no events; production has no creator profile yet);
+4. real persistence and end-to-end workflows — ✔, against the real Billing and Events since the cutover
+ (2026-10-17);
5. capability and event registration against OpenVibe.Contracts — ✔ v0.15.0, payload schemas in v0.30.2 and v0.32.0 (v0.79.0 pinned);
5. capability and event registration against OpenVibe.Contracts — ✔ v0.15.0, payload schemas in v0.30.2 and v0.32.0 (v0.79.0 pinned);
6. a migration/seed strategy ✔, a written threat review ✔ ([docs/threat-review.md](docs/threat-review.md),
6. a migration/seed strategy ✔, a written threat review ✔ ([docs/threat-review.md](docs/threat-review.md),
internal; an independent review is still due), and sitemap/robots ✔ (no feed);
internal; an independent review is still due), and sitemap/robots ✔ (no feed);
7. acceptance tests proving the advertised functionality — ✔ (table above).
7. acceptance tests proving the advertised functionality — ✔ (table above).
-The launch release removes the domain from `OpenVibe.Sites/sites.json`, switches routing and registers
-maturity in the ecosystem registry atomically. A placeholder is never counted as an implemented service.
+A placeholder is never counted as an implemented service.
---
---
@@ -7,14 +7,15 @@
@@ -7,14 +7,15 @@
"adr": "ADR-012",
"adr": "ADR-012",
"authoritative": false,
"authoritative": false,
"deployed": true,
"deployed": true,
- "deployment": "Deployed internally, not launched: deployed with `sudo ovhost deploy tips`, /opt/openvibe.tips, unit openvibe-tips, 127.0.0.1:4610 loopback only; https://openvibe.tips still serves the OpenVibe.Sites placeholder. Principal tips; Events subscriptions billing.transaction.* and billing.receipt.* -> /internal/events (secret rotated 2026-09-24); TIPS_CHAT_ADAPTER is empty (no chat side effects); TIPS_CHAT_ADAPTER=chat delivers through OpenVibe.Chat's ingress once tips is granted chat.message.send, chat.event.publish and identity.subject.resolve.",
+ "deployment": "Launched 2026-10-17 at https://openvibe.tips (openvibe-contracts 0.200.0 made Tips live; vhost deploy/nginx/openvibe.tips.conf installed): deployed with `sudo ovhost deploy tips`, /opt/openvibe.tips, unit openvibe-tips, 127.0.0.1:4610 behind nginx. Principal tips; Events subscriptions billing.transaction.* and billing.receipt.* -> /internal/events; TIPS_CHAT_ADAPTER=chat (chat lines and alerts through OpenVibe.Chat). OpenVibe.Live subscribes to tips.interaction.ready for its channel goal and tip history.",
"database": "PostgreSQL 18 through PgBouncer (transaction mode) as the system of record, Valkey 9 for shared state (per-actor limits, overlay fan-out, overlay stream slots), ADR-035: database ov_tips from OpenVibe.Host's data role, schema in migrations/ (0001_initial expand, 0002_drop_legacy_import contract), async on openvibe-sdk/db v0.28.0, money paths serializable with row locks, PostgreSQL outbox and inbox.",
"database": "PostgreSQL 18 through PgBouncer (transaction mode) as the system of record, Valkey 9 for shared state (per-actor limits, overlay fan-out, overlay stream slots), ADR-035: database ov_tips from OpenVibe.Host's data role, schema in migrations/ (0001_initial expand, 0002_drop_legacy_import contract), async on openvibe-sdk/db v0.28.0, money paths serializable with row locks, PostgreSQL outbox and inbox.",
"contracts": "openvibe-contracts v0.200.0",
"contracts": "openvibe-contracts v0.200.0",
"sdk": "openvibe-sdk v0.50.1",
"sdk": "openvibe-sdk v0.50.1",
"shared": "openvibe-shared v4.3.0",
"shared": "openvibe-shared v4.3.0",
- "notes": "Runtime, API, SSR pages, overlays, the Billing settlement consumer and the events outbox are built, tested and deployed, together with /metrics (loopback only), truthful /api/ready (Billing and Events checks), supporter privacy (anonymous, hidden amount, private message), goal and supporter-page settings, export and erasure (tips.interaction.erased), moderation (word filter, hide/show, invited moderators, tips.interaction.moderated) and per-actor limits. Capabilities (18 tips.*) and payload schemas are in openvibe-contracts. No billing.* event had arrived: Billing runs in shadow. A written internal threat review (docs/threat-review.md) with its fixes and test/security.test.js. Not done: an independent security review; the openvibe.tips launch. Live stays the place tips happen until the Billing cutover (blocked on the owner re-pointing the PowerChat webhook) and the launch rule in README.md holds.",
+ "notes": "Runtime, API, SSR pages, overlays, the Billing settlement consumer and the events outbox are built, tested and deployed, together with /metrics (loopback only), truthful /api/ready (Billing and Events checks), supporter privacy (anonymous, hidden amount, private message), goal and supporter-page settings, export and erasure (tips.interaction.erased), moderation (word filter, hide/show, invited moderators, tips.interaction.moderated) and per-actor limits. Capabilities (18 tips.*) and payload schemas are in openvibe-contracts. Billing is the money ledger since the cutover (2026-10-17). A written internal threat review (docs/threat-review.md) with its fixes and test/security.test.js. Paid sounds (creators upload up to 12, supporters pay to play one on the overlay) since 2026-10-17. Not done: an independent security review; a PowerChat checkout link for tips made on openvibe.tips (TIPS_POWERCHAT_LINK_TEMPLATE unset: supporters there pay with Vibes credit).",
"features": [
"features": [
"tips, paid messages, TTS and media requests settled by OpenVibe.Billing (never Tips' own money)",
"tips, paid messages, TTS and media requests settled by OpenVibe.Billing (never Tips' own money)",
+ "paid sounds: creators upload up to 12 sounds, supporters pay to play one on the overlay, chat names it",
"goals counted from settled payments only",
"goals counted from settled payments only",
"overlays with revocable scoped tokens and replay without recharging",
"overlays with revocable scoped tokens and replay without recharging",
"EXTERNAL PowerChat tips from billing.receipt.external",
"EXTERNAL PowerChat tips from billing.receipt.external",