openvibers/openvibe.contracts Commits
Activate network project read capability (#20)
Changes
@@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) thfrom `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,the notes were in the tag and commit messages (`git tag -n1`).++## Unreleased++++- `network.project.read` is active, implemented by OpenVibe.Network `GET /internal/projects/:project_id`.++## 0.87.0 — 2026-10-03**Host git sources** (plan T12 Stage B): a Host site may name a public Git source — provider, repository URL and branch;@@@ -2787,6 +2787,16 @@"status": "active","adr": "ADR-005"},++ {++ "id": "network.project-read-result",++ "version": "1.0.0",++ "owner": "network",++ "schema": "network/project-read-result.v1.json",++ "visibility": "first-party",++ "compatibility": "backward",++ "status": "active",++ "adr": "ADR-014"++ },{"id": "network.project-usage-result","version": "1.0.0",nnew file mode 100644@@@ -0,0 +1,82 @@++{++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/network/project-read-result.v1.json",++ "title": "NetworkProjectReadResult",++ "description": "network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.",++ "type": "object",++ "required": ["project", "allowance", "quotas", "apps", "grants"],++ "additionalProperties": false,++ "properties": {++ "project": {++ "type": "object",++ "required": ["id", "name", "owner", "environment_policy", "home_cell", "residency", "preferred_regions", "archived_at", "created_at"],++ "additionalProperties": false,++ "properties": {++ "id": { "type": "string", "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$" },++ "name": { "type": "string" },++ "owner": {++ "type": "object",++ "required": ["type", "id"],++ "additionalProperties": false,++ "properties": {++ "type": { "const": "user" },++ "id": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$" }++ }++ },++ "environment_policy": { "type": "string" },++ "home_cell": { "type": ["string", "null"] },++ "residency": { "type": ["string", "null"] },++ "preferred_regions": { "type": "array", "items": { "type": "string" } },++ "archived_at": { "type": ["string", "null"] },++ "created_at": { "type": "string" }++ }++ },++ "allowance": { "type": "array", "items": { "type": "string" } },++ "quotas": {++ "type": "array",++ "items": {++ "type": "object",++ "required": ["capability", "limit", "window", "unit", "enforced_by"],++ "additionalProperties": false,++ "properties": {++ "capability": { "type": "string" },++ "limit": { "type": "number", "minimum": 0 },++ "window": { "type": "string" },++ "unit": { "type": "string" },++ "enforced_by": { "type": ["string", "null"] }++ }++ }++ },++ "apps": {++ "type": "array",++ "items": {++ "type": "object",++ "required": ["id", "name", "environment", "status", "created_at", "revoked_at"],++ "additionalProperties": false,++ "properties": {++ "id": { "type": "string", "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$" },++ "name": { "type": "string" },++ "environment": { "type": "string" },++ "status": { "enum": ["active", "revoked"] },++ "created_at": { "type": "string" },++ "revoked_at": { "type": ["string", "null"] }++ }++ }++ },++ "grants": {++ "type": "array",++ "items": {++ "type": "object",++ "required": ["app_id", "capability", "audience", "status", "decided_at"],++ "additionalProperties": false,++ "properties": {++ "app_id": { "type": "string", "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$" },++ "capability": { "type": "string" },++ "audience": { "type": "string" },++ "status": { "enum": ["requested", "approved", "denied", "revoked"] },++ "decided_at": { "type": ["string", "null"] }++ }++ }++ }++ }++}nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "project": {++ "id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "name": "Example",++ "owner": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },++ "environment_policy": "production",++ "home_cell": null,++ "residency": null,++ "preferred_regions": [],++ "archived_at": null,++ "created_at": "2026-10-03T00:00:00Z"++ },++ "allowance": [],++ "quotas": [],++ "apps": [{ "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ", "name": "App", "environment": "production", "status": "active", "created_at": "2026-10-03T00:00:00Z", "revoked_at": null, "client_secret": "must never be exposed" }],++ "grants": []++}nnew file mode 100644@@@ -0,0 +1,17 @@++{++ "project": {++ "id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "name": "Example",++ "owner": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },++ "environment_policy": "production",++ "home_cell": null,++ "residency": null,++ "preferred_regions": [],++ "archived_at": null,++ "created_at": "2026-10-03T00:00:00Z"++ },++ "allowance": [],++ "quotas": [],++ "apps": [],++ "grants": []++}nnew file mode 100644@@@ -0,0 +1,25 @@++{++ "project": {++ "id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "name": "Tenancy",++ "owner": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },++ "environment_policy": "sandbox",++ "home_cell": "cel_01JAB2C3D4E5F6G7H8J9K0MNPQ",++ "residency": "eu-west",++ "preferred_regions": [],++ "created_at": "2026-10-03T00:00:00Z",++ "archived_at": null++ },++ "allowance": ["media.object.read", "media.object.upload"],++ "quotas": [++ { "capability": "media.object.upload", "limit": 1073741824, "window": "total", "unit": "bytes", "enforced_by": "openvibe.media" }++ ],++ "apps": [++ { "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ", "name": "Uploader", "environment": "sandbox", "status": "active", "created_at": "2026-10-03T00:00:00Z", "revoked_at": null },++ { "id": "app_01JAB2C3D4E5F6G7H8J9K0MPRQ", "name": "Reader", "environment": "sandbox", "status": "revoked", "created_at": "2026-10-03T00:00:00Z", "revoked_at": "2026-10-03T01:00:00Z" }++ ],++ "grants": [++ { "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ", "capability": "media.object.upload", "audience": "openvibe.media", "status": "approved", "decided_at": "2026-10-03T00:30:00Z" },++ { "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MPRQ", "capability": "media.object.read", "audience": "openvibe.media", "status": "revoked", "decided_at": "2026-10-03T01:00:00Z" }++ ]++}@@@ -28442,6 +28442,222 @@}}},++ "network.project-read-result": {++ "version": "1.0.0",++ "owner": "network",++ "status": "active",++ "schema": {++ "$schema": "https://json-schema.org/draft/2020-12/schema",++ "$id": "https://openvibe.network/contracts/network/project-read-result.v1.json",++ "title": "NetworkProjectReadResult",++ "description": "network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.",++ "type": "object",++ "required": [++ "project",++ "allowance",++ "quotas",++ "apps",++ "grants"++ ],++ "additionalProperties": false,++ "properties": {++ "project": {++ "type": "object",++ "required": [++ "id",++ "name",++ "owner",++ "environment_policy",++ "home_cell",++ "residency",++ "preferred_regions",++ "archived_at",++ "created_at"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "name": {++ "type": "string"++ },++ "owner": {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "user"++ },++ "id": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ }++ },++ "environment_policy": {++ "type": "string"++ },++ "home_cell": {++ "type": [++ "string",++ "null"++ ]++ },++ "residency": {++ "type": [++ "string",++ "null"++ ]++ },++ "preferred_regions": {++ "type": "array",++ "items": {++ "type": "string"++ }++ },++ "archived_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "created_at": {++ "type": "string"++ }++ }++ },++ "allowance": {++ "type": "array",++ "items": {++ "type": "string"++ }++ },++ "quotas": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "capability",++ "limit",++ "window",++ "unit",++ "enforced_by"++ ],++ "additionalProperties": false,++ "properties": {++ "capability": {++ "type": "string"++ },++ "limit": {++ "type": "number",++ "minimum": 0++ },++ "window": {++ "type": "string"++ },++ "unit": {++ "type": "string"++ },++ "enforced_by": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ },++ "apps": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "id",++ "name",++ "environment",++ "status",++ "created_at",++ "revoked_at"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "name": {++ "type": "string"++ },++ "environment": {++ "type": "string"++ },++ "status": {++ "enum": [++ "active",++ "revoked"++ ]++ },++ "created_at": {++ "type": "string"++ },++ "revoked_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ },++ "grants": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "app_id",++ "capability",++ "audience",++ "status",++ "decided_at"++ ],++ "additionalProperties": false,++ "properties": {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "capability": {++ "type": "string"++ },++ "audience": {++ "type": "string"++ },++ "status": {++ "enum": [++ "requested",++ "approved",++ "denied",++ "revoked"++ ]++ },++ "decided_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ }++ }++ }++ },"network.project-usage-result": {"version": "1.0.0","owner": "network",@@@ -103,8 +103,8 @@"service": "network","name": "OpenVibe.Network","origin": "https://openvibe.network",-- "operations": 36,-- "capabilities": 25++ "operations": 37,++ "capabilities": 26},{"service": "news",@@@ -1900,6 +1900,62 @@}}},++ "/internal/projects/{project_id}": {++ "get": {++ "operationId": "get_internal_projects_project_id",++ "summary": "Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas.",++ "description": "**network.project.read** (first-party): Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas. Services use it to key tenancy by project_id and to enforce the quotas Network records (ADR-014). Never grantable to apps.",++ "tags": [++ "network.project"++ ],++ "x-openvibe-capabilities": [++ "network.project.read"++ ],++ "x-openvibe-visibility": [++ "first-party"++ ],++ "x-openvibe-quota-class": "projects-read",++ "security": [++ {++ "openvibeToken": [++ "network.project.read"++ ]++ }++ ],++ "parameters": [++ {++ "name": "project_id",++ "in": "path",++ "required": true,++ "schema": {++ "type": "string"++ }++ }++ ],++ "responses": {++ "2XX": {++ "description": "Success",++ "content": {++ "application/json": {++ "schema": {++ "$ref": "#/components/schemas/network.project-read-result.v1"++ }++ }++ }++ },++ "default": {++ "description": "An error (RFC 9457 problem details)",++ "content": {++ "application/problem+json": {++ "schema": {++ "$ref": "#/components/schemas/errors.problem.v1"++ }++ }++ }++ }++ }++ }++ },"/internal/registry/instances/report": {"post": {"operationId": "post_internal_registry_instances_report",@@@ -3927,6 +3983,215 @@}}},++ "network.project-read-result.v1": {++ "title": "NetworkProjectReadResult",++ "description": "network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.",++ "type": "object",++ "required": [++ "project",++ "allowance",++ "quotas",++ "apps",++ "grants"++ ],++ "additionalProperties": false,++ "properties": {++ "project": {++ "type": "object",++ "required": [++ "id",++ "name",++ "owner",++ "environment_policy",++ "home_cell",++ "residency",++ "preferred_regions",++ "archived_at",++ "created_at"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "name": {++ "type": "string"++ },++ "owner": {++ "type": "object",++ "required": [++ "type",++ "id"++ ],++ "additionalProperties": false,++ "properties": {++ "type": {++ "const": "user"++ },++ "id": {++ "type": "string",++ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"++ }++ }++ },++ "environment_policy": {++ "type": "string"++ },++ "home_cell": {++ "type": [++ "string",++ "null"++ ]++ },++ "residency": {++ "type": [++ "string",++ "null"++ ]++ },++ "preferred_regions": {++ "type": "array",++ "items": {++ "type": "string"++ }++ },++ "archived_at": {++ "type": [++ "string",++ "null"++ ]++ },++ "created_at": {++ "type": "string"++ }++ }++ },++ "allowance": {++ "type": "array",++ "items": {++ "type": "string"++ }++ },++ "quotas": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "capability",++ "limit",++ "window",++ "unit",++ "enforced_by"++ ],++ "additionalProperties": false,++ "properties": {++ "capability": {++ "type": "string"++ },++ "limit": {++ "type": "number",++ "minimum": 0++ },++ "window": {++ "type": "string"++ },++ "unit": {++ "type": "string"++ },++ "enforced_by": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ },++ "apps": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "id",++ "name",++ "environment",++ "status",++ "created_at",++ "revoked_at"++ ],++ "additionalProperties": false,++ "properties": {++ "id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "name": {++ "type": "string"++ },++ "environment": {++ "type": "string"++ },++ "status": {++ "enum": [++ "active",++ "revoked"++ ]++ },++ "created_at": {++ "type": "string"++ },++ "revoked_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ },++ "grants": {++ "type": "array",++ "items": {++ "type": "object",++ "required": [++ "app_id",++ "capability",++ "audience",++ "status",++ "decided_at"++ ],++ "additionalProperties": false,++ "properties": {++ "app_id": {++ "type": "string",++ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"++ },++ "capability": {++ "type": "string"++ },++ "audience": {++ "type": "string"++ },++ "status": {++ "enum": [++ "requested",++ "approved",++ "denied",++ "revoked"++ ]++ },++ "decided_at": {++ "type": [++ "string",++ "null"++ ]++ }++ }++ }++ }++ }++ },"network.registry-read-result.v1": {"title": "NetworkRegistryReadResult","description": "network.registry-read-result@1: the answer of GET /internal/url-registry/resolved on OpenVibe.Network (capability network.registry.read): { ok: true, registry } — every site's resolved base URLs, keyed by setting name, that the shared navbar and service clients use. Secret-typed entries (deploy tokens) and sensitive keys are filtered out, so a caller never gets a credential. The keys are open (the registry grows with the sites); a failure is { ok: false, error }.",@@@ -33396,6 +33396,50 @@ export interface NetworkRealtimeTicketResult {subject: string;}++/** [email protected] (owner: network) */++/**++ * network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.++ */++export interface NetworkProjectReadResult {++ project: {++ id: string;++ name: string;++ owner: {++ type: "user";++ id: string;++ };++ environment_policy: string;++ home_cell: string | null;++ residency: string | null;++ preferred_regions: string[];++ archived_at: string | null;++ created_at: string;++ };++ allowance: string[];++ quotas: {++ capability: string;++ limit: number;++ window: string;++ unit: string;++ enforced_by: string | null;++ }[];++ apps: {++ id: string;++ name: string;++ environment: string;++ status: "active" | "revoked";++ created_at: string;++ revoked_at: string | null;++ }[];++ grants: {++ app_id: string;++ capability: string;++ audience: string;++ status: "requested" | "approved" | "denied" | "revoked";++ decided_at: string | null;++ }[];++}++/** [email protected] (owner: network) *//*** network.project-usage-result@1 (roadmap WS-N task 4, ADR-014): what GET /api/v1/projects/:project/usage?days=&env= on OpenVibe.Network answers a project's owner or admin (or staff): the project's usage per day, service, capability and unit, added up from the <service>.usage.recorded rollups (common.usage-recorded@1) the owning services emit after each hour closes; the project's recorded quotas with what the current window has used; and its recent failures with their codes and trace ids. Counts only, never who did what: no subject id, address, input or content.@@@ -2,7 +2,7 @@"id": "network.project.read","version": "1.0","owner": "network",-- "status": "planned",++ "status": "active","visibility": "first-party","description": "Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas. Services use it to key tenancy by project_id and to enforce the quotas Network records (ADR-014). Never grantable to apps.","permissions": [@@@ -14,6 +14,8 @@"quotaClass": "projects-read","events": [],"implementedBy": [-- "GET /internal/projects/:project_id (planned)"-- ]++ "GET /internal/projects/:project_id"++ ],++ "inputSchema": "common.no-body@1",++ "outputSchema": "network.project-read-result@1"}
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
@@ -4,6 +4,10 @@ All notable changes to `openvibe-contracts`. Releases are git tags (`vX.Y.Z`) th
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
from `https://codeload.github.com/OpenVibers/OpenVibe.Contracts/tar.gz/refs/tags/<tag>`. Before v0.30.0,
the notes were in the tag and commit messages (`git tag -n1`).
the notes were in the tag and commit messages (`git tag -n1`).
+## Unreleased
+
+- `network.project.read` is active, implemented by OpenVibe.Network `GET /internal/projects/:project_id`.
+
## 0.87.0 — 2026-10-03
## 0.87.0 — 2026-10-03
**Host git sources** (plan T12 Stage B): a Host site may name a public Git source — provider, repository URL and branch;
**Host git sources** (plan T12 Stage B): a Host site may name a public Git source — provider, repository URL and branch;
@@ -2787,6 +2787,16 @@
@@ -2787,6 +2787,16 @@
"status": "active",
"status": "active",
"adr": "ADR-005"
"adr": "ADR-005"
},
},
+ {
+ "id": "network.project-read-result",
+ "version": "1.0.0",
+ "owner": "network",
+ "schema": "network/project-read-result.v1.json",
+ "visibility": "first-party",
+ "compatibility": "backward",
+ "status": "active",
+ "adr": "ADR-014"
+ },
{
{
"id": "network.project-usage-result",
"id": "network.project-usage-result",
"version": "1.0.0",
"version": "1.0.0",
new file mode 100644
new file mode 100644
@@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/network/project-read-result.v1.json",
+ "title": "NetworkProjectReadResult",
+ "description": "network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.",
+ "type": "object",
+ "required": ["project", "allowance", "quotas", "apps", "grants"],
+ "additionalProperties": false,
+ "properties": {
+ "project": {
+ "type": "object",
+ "required": ["id", "name", "owner", "environment_policy", "home_cell", "residency", "preferred_regions", "archived_at", "created_at"],
+ "additionalProperties": false,
+ "properties": {
+ "id": { "type": "string", "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$" },
+ "name": { "type": "string" },
+ "owner": {
+ "type": "object",
+ "required": ["type", "id"],
+ "additionalProperties": false,
+ "properties": {
+ "type": { "const": "user" },
+ "id": { "type": "string", "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$" }
+ }
+ },
+ "environment_policy": { "type": "string" },
+ "home_cell": { "type": ["string", "null"] },
+ "residency": { "type": ["string", "null"] },
+ "preferred_regions": { "type": "array", "items": { "type": "string" } },
+ "archived_at": { "type": ["string", "null"] },
+ "created_at": { "type": "string" }
+ }
+ },
+ "allowance": { "type": "array", "items": { "type": "string" } },
+ "quotas": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": ["capability", "limit", "window", "unit", "enforced_by"],
+ "additionalProperties": false,
+ "properties": {
+ "capability": { "type": "string" },
+ "limit": { "type": "number", "minimum": 0 },
+ "window": { "type": "string" },
+ "unit": { "type": "string" },
+ "enforced_by": { "type": ["string", "null"] }
+ }
+ }
+ },
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": ["id", "name", "environment", "status", "created_at", "revoked_at"],
+ "additionalProperties": false,
+ "properties": {
+ "id": { "type": "string", "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$" },
+ "name": { "type": "string" },
+ "environment": { "type": "string" },
+ "status": { "enum": ["active", "revoked"] },
+ "created_at": { "type": "string" },
+ "revoked_at": { "type": ["string", "null"] }
+ }
+ }
+ },
+ "grants": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": ["app_id", "capability", "audience", "status", "decided_at"],
+ "additionalProperties": false,
+ "properties": {
+ "app_id": { "type": "string", "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$" },
+ "capability": { "type": "string" },
+ "audience": { "type": "string" },
+ "status": { "enum": ["requested", "approved", "denied", "revoked"] },
+ "decided_at": { "type": ["string", "null"] }
+ }
+ }
+ }
+ }
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "project": {
+ "id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "name": "Example",
+ "owner": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
+ "environment_policy": "production",
+ "home_cell": null,
+ "residency": null,
+ "preferred_regions": [],
+ "archived_at": null,
+ "created_at": "2026-10-03T00:00:00Z"
+ },
+ "allowance": [],
+ "quotas": [],
+ "apps": [{ "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ", "name": "App", "environment": "production", "status": "active", "created_at": "2026-10-03T00:00:00Z", "revoked_at": null, "client_secret": "must never be exposed" }],
+ "grants": []
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,17 @@
@@ -0,0 +1,17 @@
+{
+ "project": {
+ "id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "name": "Example",
+ "owner": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
+ "environment_policy": "production",
+ "home_cell": null,
+ "residency": null,
+ "preferred_regions": [],
+ "archived_at": null,
+ "created_at": "2026-10-03T00:00:00Z"
+ },
+ "allowance": [],
+ "quotas": [],
+ "apps": [],
+ "grants": []
+}
new file mode 100644
new file mode 100644
@@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
+{
+ "project": {
+ "id": "prj_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "name": "Tenancy",
+ "owner": { "type": "user", "id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPQ" },
+ "environment_policy": "sandbox",
+ "home_cell": "cel_01JAB2C3D4E5F6G7H8J9K0MNPQ",
+ "residency": "eu-west",
+ "preferred_regions": [],
+ "created_at": "2026-10-03T00:00:00Z",
+ "archived_at": null
+ },
+ "allowance": ["media.object.read", "media.object.upload"],
+ "quotas": [
+ { "capability": "media.object.upload", "limit": 1073741824, "window": "total", "unit": "bytes", "enforced_by": "openvibe.media" }
+ ],
+ "apps": [
+ { "id": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ", "name": "Uploader", "environment": "sandbox", "status": "active", "created_at": "2026-10-03T00:00:00Z", "revoked_at": null },
+ { "id": "app_01JAB2C3D4E5F6G7H8J9K0MPRQ", "name": "Reader", "environment": "sandbox", "status": "revoked", "created_at": "2026-10-03T00:00:00Z", "revoked_at": "2026-10-03T01:00:00Z" }
+ ],
+ "grants": [
+ { "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MNPQ", "capability": "media.object.upload", "audience": "openvibe.media", "status": "approved", "decided_at": "2026-10-03T00:30:00Z" },
+ { "app_id": "app_01JAB2C3D4E5F6G7H8J9K0MPRQ", "capability": "media.object.read", "audience": "openvibe.media", "status": "revoked", "decided_at": "2026-10-03T01:00:00Z" }
+ ]
+}
@@ -28442,6 +28442,222 @@
@@ -28442,6 +28442,222 @@
}
}
}
}
},
},
+ "network.project-read-result": {
+ "version": "1.0.0",
+ "owner": "network",
+ "status": "active",
+ "schema": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "$id": "https://openvibe.network/contracts/network/project-read-result.v1.json",
+ "title": "NetworkProjectReadResult",
+ "description": "network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.",
+ "type": "object",
+ "required": [
+ "project",
+ "allowance",
+ "quotas",
+ "apps",
+ "grants"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "project": {
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "owner",
+ "environment_policy",
+ "home_cell",
+ "residency",
+ "preferred_regions",
+ "archived_at",
+ "created_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owner": {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "user"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ }
+ },
+ "environment_policy": {
+ "type": "string"
+ },
+ "home_cell": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "residency": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "preferred_regions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "archived_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ }
+ }
+ },
+ "allowance": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "quotas": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "capability",
+ "limit",
+ "window",
+ "unit",
+ "enforced_by"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "capability": {
+ "type": "string"
+ },
+ "limit": {
+ "type": "number",
+ "minimum": 0
+ },
+ "window": {
+ "type": "string"
+ },
+ "unit": {
+ "type": "string"
+ },
+ "enforced_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ },
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "environment",
+ "status",
+ "created_at",
+ "revoked_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "name": {
+ "type": "string"
+ },
+ "environment": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "active",
+ "revoked"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "revoked_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ },
+ "grants": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "app_id",
+ "capability",
+ "audience",
+ "status",
+ "decided_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "capability": {
+ "type": "string"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "requested",
+ "approved",
+ "denied",
+ "revoked"
+ ]
+ },
+ "decided_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"network.project-usage-result": {
"network.project-usage-result": {
"version": "1.0.0",
"version": "1.0.0",
"owner": "network",
"owner": "network",
@@ -103,8 +103,8 @@
@@ -103,8 +103,8 @@
"service": "network",
"service": "network",
"name": "OpenVibe.Network",
"name": "OpenVibe.Network",
"origin": "https://openvibe.network",
"origin": "https://openvibe.network",
- "operations": 36,
- "capabilities": 25
+ "operations": 37,
+ "capabilities": 26
},
},
{
{
"service": "news",
"service": "news",
@@ -1900,6 +1900,62 @@
@@ -1900,6 +1900,62 @@
}
}
}
}
},
},
+ "/internal/projects/{project_id}": {
+ "get": {
+ "operationId": "get_internal_projects_project_id",
+ "summary": "Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas.",
+ "description": "**network.project.read** (first-party): Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas. Services use it to key tenancy by project_id and to enforce the quotas Network records (ADR-014). Never grantable to apps.",
+ "tags": [
+ "network.project"
+ ],
+ "x-openvibe-capabilities": [
+ "network.project.read"
+ ],
+ "x-openvibe-visibility": [
+ "first-party"
+ ],
+ "x-openvibe-quota-class": "projects-read",
+ "security": [
+ {
+ "openvibeToken": [
+ "network.project.read"
+ ]
+ }
+ ],
+ "parameters": [
+ {
+ "name": "project_id",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "2XX": {
+ "description": "Success",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/network.project-read-result.v1"
+ }
+ }
+ }
+ },
+ "default": {
+ "description": "An error (RFC 9457 problem details)",
+ "content": {
+ "application/problem+json": {
+ "schema": {
+ "$ref": "#/components/schemas/errors.problem.v1"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/internal/registry/instances/report": {
"/internal/registry/instances/report": {
"post": {
"post": {
"operationId": "post_internal_registry_instances_report",
"operationId": "post_internal_registry_instances_report",
@@ -3927,6 +3983,215 @@
@@ -3927,6 +3983,215 @@
}
}
}
}
},
},
+ "network.project-read-result.v1": {
+ "title": "NetworkProjectReadResult",
+ "description": "network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.",
+ "type": "object",
+ "required": [
+ "project",
+ "allowance",
+ "quotas",
+ "apps",
+ "grants"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "project": {
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "owner",
+ "environment_policy",
+ "home_cell",
+ "residency",
+ "preferred_regions",
+ "archived_at",
+ "created_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^prj_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "name": {
+ "type": "string"
+ },
+ "owner": {
+ "type": "object",
+ "required": [
+ "type",
+ "id"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "type": {
+ "const": "user"
+ },
+ "id": {
+ "type": "string",
+ "pattern": "^usr_[0-9A-HJKMNP-TV-Z]{26}$"
+ }
+ }
+ },
+ "environment_policy": {
+ "type": "string"
+ },
+ "home_cell": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "residency": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "preferred_regions": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "archived_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ }
+ }
+ },
+ "allowance": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "quotas": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "capability",
+ "limit",
+ "window",
+ "unit",
+ "enforced_by"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "capability": {
+ "type": "string"
+ },
+ "limit": {
+ "type": "number",
+ "minimum": 0
+ },
+ "window": {
+ "type": "string"
+ },
+ "unit": {
+ "type": "string"
+ },
+ "enforced_by": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ },
+ "apps": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "environment",
+ "status",
+ "created_at",
+ "revoked_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "name": {
+ "type": "string"
+ },
+ "environment": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "active",
+ "revoked"
+ ]
+ },
+ "created_at": {
+ "type": "string"
+ },
+ "revoked_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ },
+ "grants": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "required": [
+ "app_id",
+ "capability",
+ "audience",
+ "status",
+ "decided_at"
+ ],
+ "additionalProperties": false,
+ "properties": {
+ "app_id": {
+ "type": "string",
+ "pattern": "^app_[0-9A-HJKMNP-TV-Z]{26}$"
+ },
+ "capability": {
+ "type": "string"
+ },
+ "audience": {
+ "type": "string"
+ },
+ "status": {
+ "enum": [
+ "requested",
+ "approved",
+ "denied",
+ "revoked"
+ ]
+ },
+ "decided_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
"network.registry-read-result.v1": {
"network.registry-read-result.v1": {
"title": "NetworkRegistryReadResult",
"title": "NetworkRegistryReadResult",
"description": "network.registry-read-result@1: the answer of GET /internal/url-registry/resolved on OpenVibe.Network (capability network.registry.read): { ok: true, registry } — every site's resolved base URLs, keyed by setting name, that the shared navbar and service clients use. Secret-typed entries (deploy tokens) and sensitive keys are filtered out, so a caller never gets a credential. The keys are open (the registry grows with the sites); a failure is { ok: false, error }.",
"description": "network.registry-read-result@1: the answer of GET /internal/url-registry/resolved on OpenVibe.Network (capability network.registry.read): { ok: true, registry } — every site's resolved base URLs, keyed by setting name, that the shared navbar and service clients use. Secret-typed entries (deploy tokens) and sensitive keys are filtered out, so a caller never gets a credential. The keys are open (the registry grows with the sites); a failure is { ok: false, error }.",
@@ -33396,6 +33396,50 @@ export interface NetworkRealtimeTicketResult {
@@ -33396,6 +33396,50 @@ export interface NetworkRealtimeTicketResult {
subject: string;
subject: string;
}
}
+/** [email protected] (owner: network) */
+/**
+ * network.project-read-result@1: the service-facing answer from OpenVibe.Network GET /internal/projects/:project_id (network.project.read). It carries project tenancy, allowances, quotas, apps and each app's grants (requested, approved, denied or revoked) without credentials or member identities beyond the owner.
+ */
+export interface NetworkProjectReadResult {
+ project: {
+ id: string;
+ name: string;
+ owner: {
+ type: "user";
+ id: string;
+ };
+ environment_policy: string;
+ home_cell: string | null;
+ residency: string | null;
+ preferred_regions: string[];
+ archived_at: string | null;
+ created_at: string;
+ };
+ allowance: string[];
+ quotas: {
+ capability: string;
+ limit: number;
+ window: string;
+ unit: string;
+ enforced_by: string | null;
+ }[];
+ apps: {
+ id: string;
+ name: string;
+ environment: string;
+ status: "active" | "revoked";
+ created_at: string;
+ revoked_at: string | null;
+ }[];
+ grants: {
+ app_id: string;
+ capability: string;
+ audience: string;
+ status: "requested" | "approved" | "denied" | "revoked";
+ decided_at: string | null;
+ }[];
+}
+
/** [email protected] (owner: network) */
/** [email protected] (owner: network) */
/**
/**
* network.project-usage-result@1 (roadmap WS-N task 4, ADR-014): what GET /api/v1/projects/:project/usage?days=&env= on OpenVibe.Network answers a project's owner or admin (or staff): the project's usage per day, service, capability and unit, added up from the <service>.usage.recorded rollups (common.usage-recorded@1) the owning services emit after each hour closes; the project's recorded quotas with what the current window has used; and its recent failures with their codes and trace ids. Counts only, never who did what: no subject id, address, input or content.
* network.project-usage-result@1 (roadmap WS-N task 4, ADR-014): what GET /api/v1/projects/:project/usage?days=&env= on OpenVibe.Network answers a project's owner or admin (or staff): the project's usage per day, service, capability and unit, added up from the <service>.usage.recorded rollups (common.usage-recorded@1) the owning services emit after each hour closes; the project's recorded quotas with what the current window has used; and its recent failures with their codes and trace ids. Counts only, never who did what: no subject id, address, input or content.
@@ -2,7 +2,7 @@
@@ -2,7 +2,7 @@
"id": "network.project.read",
"id": "network.project.read",
"version": "1.0",
"version": "1.0",
"owner": "network",
"owner": "network",
- "status": "planned",
+ "status": "active",
"visibility": "first-party",
"visibility": "first-party",
"description": "Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas. Services use it to key tenancy by project_id and to enforce the quotas Network records (ADR-014). Never grantable to apps.",
"description": "Read a developer project as an owning service: its apps and their revocation state, approved grants, environment policy and quotas. Services use it to key tenancy by project_id and to enforce the quotas Network records (ADR-014). Never grantable to apps.",
"permissions": [
"permissions": [
@@ -14,6 +14,8 @@
@@ -14,6 +14,8 @@
"quotaClass": "projects-read",
"quotaClass": "projects-read",
"events": [],
"events": [],
"implementedBy": [
"implementedBy": [
- "GET /internal/projects/:project_id (planned)"
- ]
+ "GET /internal/projects/:project_id"
+ ],
+ "inputSchema": "common.no-body@1",
+ "outputSchema": "network.project-read-result@1"
}
}