openvibers/openvibe.contracts Commits

v0.25.0: OpenVibe.Coupons is alpha (coupons.* capabilities)

OP OpenVibers committed 23 Sept 2026 · 1818bfbd93 · 8 files, +171 −8


Changes

ddiff --git a/manifests/capabilities/coupons.coupon.lookup.json b/manifests/capabilities/coupons.coupon.lookup.json
nnew file mode 100644
iindex 00000000..676be487
---- /dev/null
++++ b/manifests/capabilities/coupons.coupon.lookup.json
@@@ -0,0 +1,21 @@
++{
++ "id": "coupons.coupon.lookup",
++ "version": "1.0",
++ "owner": "coupons",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Read a merchant's active codes (status, confidence, report aggregates, restrictions, expiry or unknown, evidence) or one code. Public data only, the same response for every caller; anonymous callers may use the routes with tighter rate limits. The charter's coupons.lookup.",
++ "permissions": [
++ "coupons:read"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "coupons-lookup",
++ "events": [],
++ "implementedBy": [
++ "GET /api/v1/merchants/:id/coupons",
++ "GET /api/v1/merchants/:id",
++ "GET /api/v1/coupons/:id"
++ ]
++}
ddiff --git a/manifests/capabilities/coupons.coupon.submit.json b/manifests/capabilities/coupons.coupon.submit.json
nnew file mode 100644
iindex 00000000..43095fc2
---- /dev/null
++++ b/manifests/capabilities/coupons.coupon.submit.json
@@@ -0,0 +1,25 @@
++{
++ "id": "coupons.coupon.submit",
++ "version": "1.0",
++ "owner": "coupons",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Submit a coupon code for a merchant (by merchant id, host or URL) on behalf of a person (X-OV-Subject) or as AI output (X-OV-Origin: ai, held for staff review). The code starts with status unknown; a status, confidence or 'verified' field is refused. A site no merchant covers becomes a pending merchant for staff review. The charter's coupons.submit.",
++ "permissions": [
++ "coupons:write"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "coupons-write",
++ "events": [
++ "coupons.coupon.created",
++ "coupons.coupon.updated",
++ "coupons.confidence.changed",
++ "coupons.index_document.upserted",
++ "coupons.index_document.deleted"
++ ],
++ "implementedBy": [
++ "POST /api/v1/coupons/submit"
++ ]
++}
ddiff --git a/manifests/capabilities/coupons.merchant.manage.json b/manifests/capabilities/coupons.merchant.manage.json
nnew file mode 100644
iindex 00000000..6fcfd5f3
---- /dev/null
++++ b/manifests/capabilities/coupons.merchant.manage.json
@@@ -0,0 +1,25 @@
++{
++ "id": "coupons.merchant.manage",
++ "version": "1.0",
++ "owner": "coupons",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Create merchants with their domain rules (never on a public suffix), add domain rules, and approve or disable merchants. Approving a pending merchant publishes the codes members submitted for it; disabling one takes its codes out of active results and Search.",
++ "permissions": [
++ "coupons:moderate"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "coupons-write",
++ "events": [
++ "coupons.coupon.updated",
++ "coupons.index_document.upserted",
++ "coupons.index_document.deleted"
++ ],
++ "implementedBy": [
++ "POST /api/v1/merchants",
++ "POST /api/v1/merchants/:id/domains",
++ "POST /api/v1/merchants/:id/status"
++ ]
++}
ddiff --git a/manifests/capabilities/coupons.merchant.resolve.json b/manifests/capabilities/coupons.merchant.resolve.json
nnew file mode 100644
iindex 00000000..8c1b5f2d
---- /dev/null
++++ b/manifests/capabilities/coupons.merchant.resolve.json
@@@ -0,0 +1,19 @@
++{
++ "id": "coupons.merchant.resolve",
++ "version": "1.0",
++ "owner": "coupons",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Resolve a hostname to an active merchant (normalized host, eTLD+1 from a bundled public-suffix subset, subdomain rules; path rules never match host-only lookups). Public data only; anonymous callers may use the route with tighter rate limits.",
++ "permissions": [
++ "coupons:read"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "coupons-lookup",
++ "events": [],
++ "implementedBy": [
++ "GET /api/v1/merchants/resolve?host="
++ ]
++}
ddiff --git a/manifests/capabilities/coupons.report.create.json b/manifests/capabilities/coupons.report.create.json
nnew file mode 100644
iindex 00000000..d83fcbd7
---- /dev/null
++++ b/manifests/capabilities/coupons.report.create.json
@@@ -0,0 +1,24 @@
++{
++ "id": "coupons.report.create",
++ "version": "1.0",
++ "owner": "coupons",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Report that a code worked or failed, on behalf of a person (X-OV-Subject). One report per person, code and UTC day; only the latest per person counts; rate-limited per person; AI output (X-OV-Origin: ai) is refused. The response carries aggregates only, never a reporter. The charter's coupons.report.",
++ "permissions": [
++ "coupons:report"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "coupons-report",
++ "events": [
++ "coupons.report.created",
++ "coupons.coupon.updated",
++ "coupons.confidence.changed",
++ "coupons.index_document.upserted"
++ ],
++ "implementedBy": [
++ "POST /api/v1/coupons/:id/report"
++ ]
++}
ddiff --git a/manifests/capabilities/coupons.status.update.json b/manifests/capabilities/coupons.status.update.json
nnew file mode 100644
iindex 00000000..29fa410f
---- /dev/null
++++ b/manifests/capabilities/coupons.status.update.json
@@@ -0,0 +1,26 @@
++{
++ "id": "coupons.status.update",
++ "version": "1.0",
++ "owner": "coupons",
++ "status": "active",
++ "visibility": "first-party",
++ "description": "Moderate a code: disable it, mark it expired, or return it to active results (its status is then recomputed from people's reports and time). reported_working and reported_failed cannot be set by anyone.",
++ "permissions": [
++ "coupons:moderate"
++ ],
++ "resourceConstraints": [
++ "none"
++ ],
++ "quotaClass": "coupons-write",
++ "events": [
++ "coupons.coupon.disabled",
++ "coupons.coupon.expired",
++ "coupons.coupon.updated",
++ "coupons.confidence.changed",
++ "coupons.index_document.upserted",
++ "coupons.index_document.deleted"
++ ],
++ "implementedBy": [
++ "POST /api/v1/coupons/:id/status"
++ ]
++}
ddiff --git a/manifests/services/coupons.json b/manifests/services/coupons.json
iindex e4fe308f..ee4ea35c 100644
---- a/manifests/services/coupons.json
++++ b/manifests/services/coupons.json
@@@ -1,16 +1,39 @@
{
"version": "0.1.0",
"contractRanges": {
-- "openvibe-contracts": "^0.1.0"
++ "openvibe-contracts": ">=0.19.0 <1.0.0"
},
"id": "coupons",
"name": "OpenVibe.Coupons",
-- "status": "placeholder",
++ "status": "alpha",
"repository": "OpenVibers/OpenVibe.Coupons",
-- "domains": [],
-- "capabilities": [],
-- "eventsProduced": [],
++ "domains": [
++ "openvibe.coupons"
++ ],
++ "publicOrigin": "https://openvibe.coupons",
++ "health": "/api/health",
++ "ready": "/api/ready",
++ "capabilities": [
++ "coupons.coupon.submit",
++ "coupons.report.create",
++ "coupons.merchant.resolve",
++ "coupons.coupon.lookup",
++ "coupons.status.update",
++ "coupons.merchant.manage"
++ ],
++ "eventsProduced": [
++ "coupons.coupon.created",
++ "coupons.coupon.updated",
++ "coupons.coupon.expired",
++ "coupons.coupon.disabled",
++ "coupons.report.created",
++ "coupons.confidence.changed",
++ "coupons.index_document.upserted",
++ "coupons.index_document.deleted"
++ ],
"eventsConsumed": [],
-- "namespacesOwned": [],
-- "notes": "Coupon codes with merchant matching, restrictions, expiry and real-people validity reports. Charter only; no runtime."
++ "namespacesOwned": [
++ "coupons.*"
++ ],
++ "notes": "Port 4850. Owns coupon_merchants, coupon_merchant_domains, coupons, coupon_sources, coupon_restrictions, coupon_validation_reports, coupon_status_history, coupon_application_hints, coupon_watches in its own SQLite, plus extension_installs (cpx_ browser-helper tokens, scopes coupons.lookup and coupons.report, hashed, revocable). Consumes OpenVibe.Network (SSO, JWKS) and OpenVibe.Sources (sources.item.read, category coupons); publishes through OpenVibe.Events (events.event.publish); OpenVibe.Search reads coupons.index_document.* from Events. The browser helper lives in OpenVibers/OpenVibe.Extensions (ADR-023)."
}
ddiff --git a/package.json b/package.json
iindex c110e96e..86be7387 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-contracts",
-- "version": "0.24.0",
++ "version": "0.25.0",
"description": "Machine-readable contracts for the OpenVibe network: schemas, manifests, ids, error envelope, capability checks.",
"main": "index.js",
"types": "generated/typescript/index.d.ts",