openvibers/openvibe.deals Commits
README and STATUS.json are current (roadmap WS-U task 3): a Capabilities section lists the twelve capabilities Deals implements and the grants it uses at Network, Events, Sources and Community; Deploy says production deploys with sudo ovhost deploy deals (unit, port, env file, rollback) and keeps the first-install steps; Security points to SECURITY.md; Depends on names the current pins (publishing v0.4.0, contracts v0.53.0, shared v1.22.0, sdk v0.12.0). STATUS.json gains contracts, features, the current package list and updated 2026-09-28.
Changes
@@@ -246,10 +246,10 @@ render time, so the cache stays short); signed-in views, forms, API responses, e## Depends on--- **Packages** (pinned release tarballs): `openvibe-publishing` v0.2.1 (seo gate, JSON-LD, feeds,-- sitemaps, index-hooks, discussion, ssr), `openvibe-contracts` v0.33.0, `openvibe-shared` v1.5.1-- (chrome, app icon, footer, legal, release, metrics, ready), `openvibe-sdk` v0.5.0 (outbox, inbox,-- webhook signatures v2, service tokens).++- **Packages** (pinned release tarballs): `openvibe-publishing` v0.4.0 (seo gate, JSON-LD, feeds,++ sitemaps, index-hooks, discussion, ssr), `openvibe-contracts` v0.53.0, `openvibe-shared` v1.22.0++ (chrome, app icon, footer, legal, release, metrics, ready), `openvibe-sdk` v0.12.0 (outbox, inbox,++ webhook signatures v2, service tokens, per-actor limits).- **OpenVibe.Network:** SSO (OAuth client `deals`, registered in production), JWKS,`identity.subject.resolve`.- **OpenVibe.Sources:** `sources.item.read`; a `deals`-category source must be registered and enabled@@@ -274,6 +274,19 @@ Each grant is `[client, capability, audience]`:- For OpenVibe.AI enrichment (later): `[ai, deals.offer.update, openvibe.deals]`- For a future Network notification consumer that reads watches: `[network, deals.watch.read, openvibe.deals]`++## Capabilities++++Implemented here (the service manifest's `capabilities`, audience `openvibe.deals`, one per route; the++route table is under [API](#api-apiv1-problemjson-errors)): `deals.offer.submit`, `deals.offer.update`,++`deals.offer.expire`, `deals.offer.merge`, `deals.offer.moderate`, `deals.vote.set`,++`deals.vote.remove`, `deals.watch.create`, `deals.watch.read`, `deals.watch.delete`,++`deals.product.resolve` and `deals.flag.create`.++++Called elsewhere, as the service principal `deals`: `identity.subject.resolve` (Network),++`events.event.publish` and, once, `events.subscription.manage` (Events), `sources.item.read`++(Sources), `community.comment.write` and optionally `community.comment.moderate` (Community). The++full list with audiences is under [Grants the Network must hold](#grants-the-network-must-hold).++## Acceptance (automated: `npm test`)| Charter / roadmap requirement | Test |@@@ -315,6 +328,8 @@ from sources registered in OpenVibe.Sources.## Security and threat review++Reporting a vulnerability: [SECURITY.md](SECURITY.md).++- **Identity:** only verified Network JWTs (offline RS256 against JWKS) and service tokens for audience`openvibe.deals`; a bad service token is refused, never downgraded to anonymous; identity nevercomes from a body or query; `X-OV-*` headers are ignored for browsers; pages ignore service tokens.@@@ -353,6 +368,15 @@ fnm exec --using=22.22.1 npm run dev # http://localhost:4840 (set OV_OAUTH## Deploy (for the lead)++Production deploys with `sudo ovhost deploy deals` on the host (strategy `git-checkout`: fetch,++fast-forward `/opt/openvibe.deals`, install on a lockfile change, restart, wait for `/api/ready`).++The unit is `openvibe-deals.service` on `127.0.0.1:4840`, the env file `/etc/openvibe/deals.env`.++Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the++restart; afterwards `sudo ovhost rollback deals --to <sha>`. Nothing blocks a rollback: the schema++code only adds tables and columns.++++First install (done once; kept for a rebuild):++1. **Code and config:** put the code at `/opt/openvibe.deals` and run `npm ci --omit=dev` on Node 22(on the host, npm 9 may rewrite `package-lock.json`; restore it with `git checkout -- package-lock.json`).Create `/etc/openvibe/deals.env` (0600) from `.env.example`; set `OV_OAUTH_CLIENT_SECRET`,@@@ -7,12 +7,8 @@"runtime": "node 22, express 4, better-sqlite3 11","port": 4840,"domain": "openvibe.deals",-- "packages": [-- "openvibe-publishing v0.2.1",-- "openvibe-contracts v0.33.0",-- "openvibe-shared v1.5.1",-- "openvibe-sdk v0.5.0"-- ],++ "contracts": "openvibe-contracts v0.53.0",++ "packages": ["openvibe-publishing v0.4.0", "openvibe-contracts v0.53.0", "openvibe-shared v1.22.0", "openvibe-sdk v0.12.0"],"capabilities": ["deals.offer.submit","deals.offer.update",@@@ -33,7 +29,21 @@"sourcesImport": "code and tests; the sources.item.read grant exists in production, but no deals-category source is enabled in OpenVibe.Sources (the seeded dealnews-daily is disabled), so nothing has been imported","watchNotifications": "deals.watch.matched events only; OpenVibe.Network's notification consumer does not exist yet","deployed": true,-- "deployment": "openvibe-ovh, unit openvibe-deals, 127.0.0.1:4840 loopback only (release e72aeec); /api/ready 200 with every check ok; Network OAuth client deals and its grants exist; production database holds 0 offers. Deployed internally, not launched: openvibe.deals still serves the OpenVibe.Sites placeholder until a person verifies a deals source's terms and enables it in Sources",++ "deployment": "Deployed with `sudo ovhost deploy deals`: unit openvibe-deals, 127.0.0.1:4840 loopback only; Network OAuth client deals and its grants exist; on 2026-09-23 /api/ready answered 200 and the production database held 0 offers. Deployed internally, not launched: openvibe.deals still serves the OpenVibe.Sites placeholder until a person verifies a deals source's terms and enables it in Sources","placeholderInSites": true,-- "updated": "2026-09-23"++ "updated": "2026-09-28",++ "features": [++ "offers with timestamped price observations shown \"as of\" and stale labels",++ "unknown prices stay unknown in pages, JSON, JSON-LD, feeds and Search",++ "server-authoritative votes and deterministic hotness (hot@1)",++ "duplicate merge and unmerge without losing votes or history",++ "watches and saved searches (deals.watch.matched events; no delivery yet)",++ "vote abuse controls and moderation queue",++ "OpenVibe.Sources deals import with review",++ "Community comment threads",++ "server-rendered pages, feeds and sitemaps useful without JavaScript",++ "/api/v1 by capability",++ "SDK outbox events and Search index documents",++ "per-actor limits (openvibe-sdk/limits)"++ ]}
@@ -246,10 +246,10 @@ render time, so the cache stays short); signed-in views, forms, API responses, e
@@ -246,10 +246,10 @@ render time, so the cache stays short); signed-in views, forms, API responses, e
## Depends on
## Depends on
-- **Packages** (pinned release tarballs): `openvibe-publishing` v0.2.1 (seo gate, JSON-LD, feeds,
- sitemaps, index-hooks, discussion, ssr), `openvibe-contracts` v0.33.0, `openvibe-shared` v1.5.1
- (chrome, app icon, footer, legal, release, metrics, ready), `openvibe-sdk` v0.5.0 (outbox, inbox,
- webhook signatures v2, service tokens).
+- **Packages** (pinned release tarballs): `openvibe-publishing` v0.4.0 (seo gate, JSON-LD, feeds,
+ sitemaps, index-hooks, discussion, ssr), `openvibe-contracts` v0.53.0, `openvibe-shared` v1.22.0
+ (chrome, app icon, footer, legal, release, metrics, ready), `openvibe-sdk` v0.12.0 (outbox, inbox,
+ webhook signatures v2, service tokens, per-actor limits).
- **OpenVibe.Network:** SSO (OAuth client `deals`, registered in production), JWKS,
- **OpenVibe.Network:** SSO (OAuth client `deals`, registered in production), JWKS,
`identity.subject.resolve`.
`identity.subject.resolve`.
- **OpenVibe.Sources:** `sources.item.read`; a `deals`-category source must be registered and enabled
- **OpenVibe.Sources:** `sources.item.read`; a `deals`-category source must be registered and enabled
@@ -274,6 +274,19 @@ Each grant is `[client, capability, audience]`:
@@ -274,6 +274,19 @@ Each grant is `[client, capability, audience]`:
- For OpenVibe.AI enrichment (later): `[ai, deals.offer.update, openvibe.deals]`
- For OpenVibe.AI enrichment (later): `[ai, deals.offer.update, openvibe.deals]`
- For a future Network notification consumer that reads watches: `[network, deals.watch.read, openvibe.deals]`
- For a future Network notification consumer that reads watches: `[network, deals.watch.read, openvibe.deals]`
+## Capabilities
+
+Implemented here (the service manifest's `capabilities`, audience `openvibe.deals`, one per route; the
+route table is under [API](#api-apiv1-problemjson-errors)): `deals.offer.submit`, `deals.offer.update`,
+`deals.offer.expire`, `deals.offer.merge`, `deals.offer.moderate`, `deals.vote.set`,
+`deals.vote.remove`, `deals.watch.create`, `deals.watch.read`, `deals.watch.delete`,
+`deals.product.resolve` and `deals.flag.create`.
+
+Called elsewhere, as the service principal `deals`: `identity.subject.resolve` (Network),
+`events.event.publish` and, once, `events.subscription.manage` (Events), `sources.item.read`
+(Sources), `community.comment.write` and optionally `community.comment.moderate` (Community). The
+full list with audiences is under [Grants the Network must hold](#grants-the-network-must-hold).
+
## Acceptance (automated: `npm test`)
## Acceptance (automated: `npm test`)
| Charter / roadmap requirement | Test |
| Charter / roadmap requirement | Test |
@@ -315,6 +328,8 @@ from sources registered in OpenVibe.Sources.
@@ -315,6 +328,8 @@ from sources registered in OpenVibe.Sources.
## Security and threat review
## Security and threat review
+Reporting a vulnerability: [SECURITY.md](SECURITY.md).
+
- **Identity:** only verified Network JWTs (offline RS256 against JWKS) and service tokens for audience
- **Identity:** only verified Network JWTs (offline RS256 against JWKS) and service tokens for audience
`openvibe.deals`; a bad service token is refused, never downgraded to anonymous; identity never
`openvibe.deals`; a bad service token is refused, never downgraded to anonymous; identity never
comes from a body or query; `X-OV-*` headers are ignored for browsers; pages ignore service tokens.
comes from a body or query; `X-OV-*` headers are ignored for browsers; pages ignore service tokens.
@@ -353,6 +368,15 @@ fnm exec --using=22.22.1 npm run dev # http://localhost:4840 (set OV_OAUTH
@@ -353,6 +368,15 @@ fnm exec --using=22.22.1 npm run dev # http://localhost:4840 (set OV_OAUTH
## Deploy (for the lead)
## Deploy (for the lead)
+Production deploys with `sudo ovhost deploy deals` on the host (strategy `git-checkout`: fetch,
+fast-forward `/opt/openvibe.deals`, install on a lockfile change, restart, wait for `/api/ready`).
+The unit is `openvibe-deals.service` on `127.0.0.1:4840`, the env file `/etc/openvibe/deals.env`.
+Rollback: ovhost puts the previous sha back by itself when `/api/ready` does not answer 2xx after the
+restart; afterwards `sudo ovhost rollback deals --to <sha>`. Nothing blocks a rollback: the schema
+code only adds tables and columns.
+
+First install (done once; kept for a rebuild):
+
1. **Code and config:** put the code at `/opt/openvibe.deals` and run `npm ci --omit=dev` on Node 22
1. **Code and config:** put the code at `/opt/openvibe.deals` and run `npm ci --omit=dev` on Node 22
(on the host, npm 9 may rewrite `package-lock.json`; restore it with `git checkout -- package-lock.json`).
(on the host, npm 9 may rewrite `package-lock.json`; restore it with `git checkout -- package-lock.json`).
Create `/etc/openvibe/deals.env` (0600) from `.env.example`; set `OV_OAUTH_CLIENT_SECRET`,
Create `/etc/openvibe/deals.env` (0600) from `.env.example`; set `OV_OAUTH_CLIENT_SECRET`,
@@ -7,12 +7,8 @@
@@ -7,12 +7,8 @@
"runtime": "node 22, express 4, better-sqlite3 11",
"runtime": "node 22, express 4, better-sqlite3 11",
"port": 4840,
"port": 4840,
"domain": "openvibe.deals",
"domain": "openvibe.deals",
- "packages": [
- "openvibe-publishing v0.2.1",
- "openvibe-contracts v0.33.0",
- "openvibe-shared v1.5.1",
- "openvibe-sdk v0.5.0"
- ],
+ "contracts": "openvibe-contracts v0.53.0",
+ "packages": ["openvibe-publishing v0.4.0", "openvibe-contracts v0.53.0", "openvibe-shared v1.22.0", "openvibe-sdk v0.12.0"],
"capabilities": [
"capabilities": [
"deals.offer.submit",
"deals.offer.submit",
"deals.offer.update",
"deals.offer.update",
@@ -33,7 +29,21 @@
@@ -33,7 +29,21 @@
"sourcesImport": "code and tests; the sources.item.read grant exists in production, but no deals-category source is enabled in OpenVibe.Sources (the seeded dealnews-daily is disabled), so nothing has been imported",
"sourcesImport": "code and tests; the sources.item.read grant exists in production, but no deals-category source is enabled in OpenVibe.Sources (the seeded dealnews-daily is disabled), so nothing has been imported",
"watchNotifications": "deals.watch.matched events only; OpenVibe.Network's notification consumer does not exist yet",
"watchNotifications": "deals.watch.matched events only; OpenVibe.Network's notification consumer does not exist yet",
"deployed": true,
"deployed": true,
- "deployment": "openvibe-ovh, unit openvibe-deals, 127.0.0.1:4840 loopback only (release e72aeec); /api/ready 200 with every check ok; Network OAuth client deals and its grants exist; production database holds 0 offers. Deployed internally, not launched: openvibe.deals still serves the OpenVibe.Sites placeholder until a person verifies a deals source's terms and enables it in Sources",
+ "deployment": "Deployed with `sudo ovhost deploy deals`: unit openvibe-deals, 127.0.0.1:4840 loopback only; Network OAuth client deals and its grants exist; on 2026-09-23 /api/ready answered 200 and the production database held 0 offers. Deployed internally, not launched: openvibe.deals still serves the OpenVibe.Sites placeholder until a person verifies a deals source's terms and enables it in Sources",
"placeholderInSites": true,
"placeholderInSites": true,
- "updated": "2026-09-23"
+ "updated": "2026-09-28",
+ "features": [
+ "offers with timestamped price observations shown \"as of\" and stale labels",
+ "unknown prices stay unknown in pages, JSON, JSON-LD, feeds and Search",
+ "server-authoritative votes and deterministic hotness (hot@1)",
+ "duplicate merge and unmerge without losing votes or history",
+ "watches and saved searches (deals.watch.matched events; no delivery yet)",
+ "vote abuse controls and moderation queue",
+ "OpenVibe.Sources deals import with review",
+ "Community comment threads",
+ "server-rendered pages, feeds and sitemaps useful without JavaScript",
+ "/api/v1 by capability",
+ "SDK outbox events and Search index documents",
+ "per-actor limits (openvibe-sdk/limits)"
+ ]
}
}