openvibers/openvibe.zone AGENTS.md

AGENTS.md

main 6.0 KB · 107 lines · markdown

AGENTS.md — OpenVibe.Zone

Project overview

OpenVibe.Zone (https://openvibe.zone) provides private S3-compatible storage zones for OpenVibe
projects: one named object zone per project environment (sandbox or production), reached by any S3 tool
at https://s3.openvibe.media (path style; https://s3.openvibe.network is the same surface behind
Cloudflare). The design is ADR-031. Zone owns the zone record and control API; Media owns everything
inside a zone
.

  • Entry: server/index.js; app server/app.js; port 5050, service id zone.
  • API: server/http/api.js (/api/v1), events.js (/internal/events, v2-signed,
    loopback-only), pages.js (console + docs), discovery.js, principal.js, caller-limits.js.
  • Domain: server/zone/ — zones.js (records, names, revisions, provisioning, deletion, the job),
    usage.js (Media's hourly rollups, kept and summed), clients.js (Media provision/report/keys and
    Network roles/projects), media-limits.js.
  • Pages: server/render/ (layout.js, html.js, markdown.js, short.js); CSS in public/css.
    Console changes are same-origin forms; no SPA.
  • Secrets: an access key's secret is shown once and never stored here (Media keeps it encrypted).

Owns, does not own

Owns the zone record: its name (never reused), environment, state, description, per-zone quota; the
control API and console; its metered usage as Media reports it (zone_usage); the resource index/control
views. Tables in ov_zone (migrations below).

Does not own: Media owns the objects, bytes, replicas, S3/native data APIs, access keys, quota
enforcement, usage counting and the one deletion path.
Zone never lists keys, never holds bytes and
never counts. Identity/projects are Network's; the price comparison is Host's.

Capabilities and API

Base https://openvibe.zone/api/v1 (and https://api.openvibe.zone/api/v1). A caller is either a
developer app of the project with the route's capability for audience openvibe.zone (a sandbox app
reaches only the sandbox), or a project member (any role reads; admins/owners change).

| Route | Capability |
|---|---|
| POST /projects/:project_id/zones (Idempotency-Key) | zone.zone.create |
| GET /projects/:project_id/zones | zone.zone.list |
| GET /zones/:zone_id | zone.zone.read |
| PATCH /zones/:zone_id | zone.zone.manage |
| DELETE /zones/:zone_id?recursive=true | zone.zone.delete |
| GET /zones/:zone_id/usage | zone.usage.read |
| GET /resources, /resources/:ovrn | zone.resource.read (first-party) |
| POST /resources/control | zone.resource.control (first-party) |

Grants Zone holds: media.zone.provision and media.access_key.manage (audience openvibe.media),
network.project.member.read, and events.subscription.manage (the media.usage.recorded
subscription). SDK openvibe-sdk/zone is the client surface.

Database and migrations

PostgreSQL ov_zone through openvibe-sdk/db (PgBouncer for the app, owner role for migrations):
0001 initial, 0002 usage, 0003 telemetry, 0004 account data, 0005–0007 sharing/defaults.
Applied at boot; never edit a migration that has run. Telemetry is aggregated by route template,
method and status class (never raw URL), with 14-day retention; /shared, static assets, health,
readiness and /metrics are not counted.

Auth and security

Network RS256 JWTs (JWKS) for apps/members; /internal/events answers only on loopback (nginx 404s
it), requires a valid v2 signature (ZONE_EVENTS_SECRET) and refuses a request through a proxy. Every
console change is a same-origin form; only a project's admins and owners change zones and keys. Media's
S3 answers are private, no-store with CDN no-store, so no edge keeps them. Never log or store an
access-key secret; no shared loopback key exists (tested by grep and at runtime). Account export/
deletion covers every table with a person column or exempts it with a reason.

Deploy

sudo ovhost deploy zone: unit openvibe-zone.service on 127.0.0.1:5050, database ov_zone, env
/etc/openvibe/zone.env (with EVENTS_URL and ZONE_EVENTS_SECRET for the usage subscription), nginx
deploy/nginx/openvibe.zone.conf on openvibe.zone's own certificate; migrations run at boot. Rollback
with sudo ovhost rollback zone --to <sha>.

Commands and tests

npm ci
npm run dev                  # http://127.0.0.1:5050
npm test                     # every test/*.test.js, temp PGlite + mock Network
npm test -- login            # only matching files
npm run test:pg              # the same on PostgreSQL

test/run.js uses openvibe-shared/test-runner; temp PGlite and an in-process Network mock, never the
network. Coverage includes zone names/revisions/provisioning/deletion, usage rollups, app vs member
authorization, the S3 surface/limits, nginx auth limits, the no-internal-key and secrets checks,
session/redirect security, account data and the pages.

Conventions and pitfalls

  • CommonJS, 4-space indent, single quotes, semicolons; problem+json errors; escaped HTML.
  • Zone is metadata only. Do not add an object list, byte store, replica, key listing or a second
    delete path — that is Media's, and a duplicate would drift. Operations call Media with Zone's own
    grants.
  • A zone name is never reused, even after deletion; a rename does not change the S3 bucket identity.
  • The secret is shown once. A key response may carry it that one time; never persist, log or
    re-render it. Media holds the encrypted key.
  • Idempotency: create carries Idempotency-Key; a retry must return the same zone, not a second one.
  • Sandbox apps reach only the sandbox, and only their project; a member check is Network's answer,
    never a client claim.
  • The usage is Media's: keep the media.usage.recorded rollups and sum them; never estimate or
    count a byte locally.
  • No SQL migration may block a rollback, and one with a person column must be covered by account
    data or exempted in server/account-data.js with a reason.