L3 Application BFF — Full API Reference — OpenAPI 1.0.0
<!-- GENERATED by scripts/render-platform-map-api-docs.mjs — do not hand-edit; edit apps/agent-bff/openapi/<spec>.json and re-run. --> Scope: The published reference for L3 Application BFF — Full API Reference. 18 paths — the measured spec-vs-implementation coverage lives in the complete API inventory. Status: rendered 2026-11-09 from the OpenAPI source for L3 Application BFF — Full API Reference — regenerate with node scripts/render-platform-map-api-docs.mjs. See also: the OpenAPI spec index.
Servers
| URL | Notes |
|---|---|
| http://127.0.0.1:3030 | Local development (DEV_SKIP_AUTH=1) |
| https://prod-bff.example.com | Production BFF endpoint |
Tags
| Tag | Summary |
|---|---|
| health | Health & readiness probes (unauthenticated) |
| auth | Authentication routes (mixed auth) |
| proxy | Generic CRUD & raw SQL proxy |
| domain | Domain routes — presence, scope presence |
| provenance | Message provenance and integrity chains |
| notifications | Notification enqueue and retrieval |
| forms | Form schema CRUD and attestation |
| users | User listing and management |
Paths — 18 paths / 23 operations
| Method | Path | Operation ID | Summary |
|---|---|---|---|
| GET | /health | getHealth | Detailed health check with L2 dependency cascade |
| GET | /ready | getReady | Readiness probe |
| GET | /live | getLive | Liveness probe |
| GET | /metrics | getMetrics | Prometheus-formatted metrics |
| POST | /v1/auth/login | postAuthLogin | Password login |
| POST | /v1/auth/register | postAuthRegister | Password registration |
| GET | /v1/auth/me | getAuthMe | Get current user info |
| POST | /v1/auth/verify | postAuthVerify | Token verification |
| GET | /v1/auth/validate-token | getAuthValidateToken | GET-friendly token validation |
| PUT | /v1/users/:userId/presence | putUserPresence | Upsert user global presence |
| GET | /v1/users/:userId/presence | getUserPresence | Get user global presence |
| GET | /v1/presence/:scope/:scopeId | getScopePresence | List presence in a scope |
| POST | /v1/notifications | postNotificationsEnqueue | Enqueue a notification |
| GET | /v1/notifications | getNotifications | Get pending notifications for a user |
| GET | /v1/provenance/:messageId | getProvenance | Get full provenance chain |
| GET | /v1/provenance/:messageId/verify | getProvenanceVerify | Verify message content integrity |
| GET | /v1/forms | getFormsList | List active form schemas |
| POST | /v1/forms | postFormsCreate | Create a new form schema |
| GET | /v1/forms/:schemaId | getFormSchema | Get a single form schema |
| PUT | /v1/forms/:schemaId | putFormSchema | Update form schema |
| DELETE | /v1/forms/:schemaId | deleteFormSchema | Soft-delete form schema |
| POST | /v1/forms/attest | postFormsAttest | Attest a form submission |
| GET | /v1/users | getUsersList | List users |
Operations
GET /health
Summary: Detailed health check with L2 dependency cascade Description: Returns service status, uptime, and dependency check latencies for SurrealDB, NATS, and L2 backend.
Tags: health Operation ID: getHealth Responses:
| Status | Meaning |
|---|---|
| 200 | Health check OK |
| 503 | Service not ready (L2 backend unreachable) |
GET /ready
Summary: Readiness probe Description: Fails if L2 backend or SurrealDB is unreachable. Used by orchestration systems.
Tags: health Operation ID: getReady Responses:
| Status | Meaning |
|---|---|
| 200 | Service ready |
| 503 | Service not ready |
GET /live
Summary: Liveness probe Description: Confirms the process is alive. Basic uptime check.
Tags: health Operation ID: getLive Responses:
| Status | Meaning |
|---|---|
| 200 | Service alive |
GET /metrics
Summary: Prometheus-formatted metrics Description: Returns Prometheus text-format metrics for monitoring systems.
Tags: health Operation ID: getMetrics Responses:
| Status | Meaning |
|---|---|
| 200 | Metrics output |
POST /v1/auth/login
Summary: Password login Description: Authenticate with email/password and return a session JWT.
Tags: auth Operation ID: postAuthLogin Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 200 | Login successful |
| 401 | Invalid credentials |
POST /v1/auth/register
Summary: Password registration Description: Register a new user account with email, password, and display name.
Tags: auth Operation ID: postAuthRegister Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 201 | Registration successful |
| 400 | Validation failed (e.g., duplicate email) |
GET /v1/auth/me
Summary: Get current user info Description: Returns the current user's identifier, provider, roles, and scopes from the session JWT.
Tags: auth Operation ID: getAuthMe Responses:
| Status | Meaning |
|---|---|
| 200 | User info retrieved |
| 401 | Missing or invalid auth token |
POST /v1/auth/verify
Summary: Token verification Description: Validate a session JWT or API key. Returns user context headers (X-Forwarded-User, X-Forwarded-Roles, X-Forwarded-Scopes).
Tags: auth Operation ID: postAuthVerify Request body:
Content type: application/json
| Field | Type | Notes |
|---|---|---|
| token | string | JWT token or API key |
Responses:
| Status | Meaning |
|---|---|
| 200 | Token valid |
| 401 | Invalid token or API key |
GET /v1/auth/validate-token
Summary: GET-friendly token validation Description: Validate a session JWT or API key via GET request. Returns simple validity status.
Tags: auth Operation ID: getAuthValidateToken Responses:
| Status | Meaning |
|---|---|
| 200 | Token validation result |
| 401 | Invalid token or API key |
PUT /v1/users/:userId/presence
Summary: Upsert user global presence Description: Upsert or create the user's global presence record with online status, optional status text, and GPS location.
Tags: domain Operation ID: putUserPresence
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| userId | path | yes | string | User identifier (e.g., user:123 or user:user@example.com) |
Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 200 | Presence updated |
| 400 | Invalid location coordinates (lat/lng out of range) |
| 401 | Authentication required |
GET /v1/users/:userId/presence
Summary: Get user global presence Description: Retrieve the user's current global presence record.
Tags: domain Operation ID: getUserPresence
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| userId | path | yes | string | User identifier |
Responses:
| Status | Meaning |
|---|---|
| 200 | Presence record retrieved |
| 404 | No presence record found for this user |
GET /v1/presence/:scope/:scopeId
Summary: List presence in a scope Description: List all user presence records within a given scope (e.g., portfolio:dev). Supports pagination.
Tags: domain Operation ID: getScopePresence
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| scope | path | yes | string | Scope name (e.g., portfolio) |
| scopeId | path | yes | string | Scope identifier (e.g., dev) |
| limit | query | no | int | Maximum number of records to return (default 50) |
| offset | query | no | int | Number of records to skip (default 0) |
Responses:
| Status | Meaning |
|---|---|
| 200 | Presence records list |
| 404 | Scope not found |
POST /v1/notifications
Summary: Enqueue a notification Description: Enqueue a notification for a user. Routes through NATS JetStream outbox. Triggers PoCE session if governance_path_spec_id is set.
Tags: notifications Operation ID: postNotificationsEnqueue Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 201 | Notification enqueued |
| 422 | Validation failed (e.g., environmentId missing from JWT) |
GET /v1/notifications
Summary: Get pending notifications for a user Description: Retrieve pending notifications for a user. Supports filtering by status and pagination.
Tags: notifications Operation ID: getNotifications
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| userId | path | yes | string | User identifier |
| limit | query | no | int | Maximum number of records to return (default 50) |
| offset | query | no | int | Number of records to skip (default 0) |
| status | query | no | string enum: pending, delivered, read | Filter by status (pending, delivered, read) |
Responses:
| Status | Meaning |
|---|---|
| 200 | Notifications list |
GET /v1/provenance/:messageId
Summary: Get full provenance chain Description: Retrieve the full provenance chain for a message, including metadata, attestation chain, parent chain, delivery timeline, and truth index reference.
Tags: provenance Operation ID: getProvenance
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| messageId | path | yes | string | Message identifier (e.g., notif:001 or msg:abc123) |
Responses:
| Status | Meaning |
|---|---|
| 200 | Provenance chain retrieved |
| 404 | Message not found |
GET /v1/provenance/:messageId/verify
Summary: Verify message content integrity Description: Re-compute SHA256 hash and compare against stored content_hash. Returns whether the content has been tampered with.
Tags: provenance Operation ID: getProvenanceVerify
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| messageId | path | yes | string | Message identifier |
Responses:
| Status | Meaning |
|---|---|
| 200 | Integrity verification result |
GET /v1/forms
Summary: List active form schemas Description: List all active form schemas. Supports optional category filtering and pagination.
Tags: forms Operation ID: getFormsList
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| category | query | no | string | Filter by category (optional) |
| limit | query | no | int | Maximum number of schemas to return (default 50) |
| offset | query | no | int | Number of schemas to skip (default 0) |
Responses:
| Status | Meaning |
|---|---|
| 200 | Schema summaries |
POST /v1/forms
Summary: Create a new form schema Description: Create a new form schema with definition, validation rules, and metadata. Bumps version to 1 on creation.
Tags: forms Operation ID: postFormsCreate Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 201 | Schema created |
| 400 | Validation failed (e.g., invalid field definition) |
GET /v1/forms/:schemaId
Summary: Get a single form schema Description: Retrieve a form schema by ID or name. Returns the full schema definition including fields, validation, and submit action.
Tags: forms Operation ID: getFormSchema
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| schemaId | path | yes | string | Schema identifier or name (e.g., form:contact-us or contact-us) |
Responses:
| Status | Meaning |
|---|---|
| 200 | Schema detail retrieved |
| 404 | Schema not found |
PUT /v1/forms/:schemaId
Summary: Update form schema Description: Update a form schema definition. Bumps version on successful update. Partial updates allowed.
Tags: forms Operation ID: putFormSchema
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| schemaId | path | yes | string | Schema identifier |
Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 200 | Schema updated |
| 404 | Schema not found |
DELETE /v1/forms/:schemaId
Summary: Soft-delete form schema Description: Soft-delete (deactivate) a form schema. The schema is marked inactive but not permanently removed.
Tags: forms Operation ID: deleteFormSchema
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| schemaId | path | yes | string | Schema identifier |
Responses:
| Status | Meaning |
|---|---|
| 200 | Schema deactivated |
POST /v1/forms/attest
Summary: Attest a form submission Description: Attest a form submission. Verifies session trust + optional MFA, then records attestation with PoCE integration if applicable.
Tags: forms Operation ID: postFormsAttest Request body:
Content type: application/json
| Field | Type | Notes |
|---|
Responses:
| Status | Meaning |
|---|---|
| 201 | Attestation recorded |
| 400 | Validation failed (e.g., invalid submission data) |
GET /v1/users
Summary: List users Description: List users from the user_profile table. Supports role filtering and pagination via query parameters.
Tags: users Operation ID: getUsersList
Parameters:
| Name | In | Required | Type | Notes |
|---|---|---|---|---|
| role | query | no | string | Filter by role (e.g., user). Optional. |
| limit | query | no | int | Maximum number of users to return (default 100) |
| offset | query | no | int | Number of users to skip (default 0) |
Responses:
| Status | Meaning |
|---|---|
| 200 | Users list |
| 400 | Invalid query parameters |
Full specification — verbatim source of truth
{
"openapi": "3.1.0",
"info": {
"title": "L3 Application BFF — Full API Reference",
"version": "1.0.0",
"description": "Full API reference for the L3 Application BFF (apps/app-bff, port :3030, Hono framework). All routes protected by Bearer JWT auth unless marked unauthenticated. Base URL: http://127.0.0.1:3030"
},
"servers": [
{
"url": "http://127.0.0.1:3030",
"description": "Local development (DEV_SKIP_AUTH=1)"
},
{
"url": "https://prod-bff.example.com",
"description": "Production BFF endpoint"
}
],
"tags": [
{
"name": "health",
"description": "Health & readiness probes (unauthenticated)"
},
{
"name": "auth",
"description": "Authentication routes (mixed auth)"
},
{
"name": "proxy",
"description": "Generic CRUD & raw SQL proxy"
},
{
"name": "domain",
"description": "Domain routes — presence, scope presence"
},
{
"name": "provenance",
"description": "Message provenance and integrity chains"
},
{
"name": "notifications",
"description": "Notification enqueue and retrieval"
},
{
"name": "forms",
"description": "Form schema CRUD and attestation"
},
{
"name": "users",
"description": "User listing and management"
}
],
"components": {
"schemas": {
"ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "Human-readable error description"
},
"code": {
"type": "string",
"description": "HTTP status code as string"
}
},
"required": [
"message",
"code"
]
}
},
"required": [
"error"
]
},
"SuccessResponse": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true for successful responses"
}
}
},
"HealthCheckResponse": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"ok",
"not_ready",
"degraded"
],
"description": "Overall health status"
},
"service": {
"type": "string",
"description": "Service name"
},
"version": {
"type": "string",
"description": "Service version"
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp"
},
"uptime_seconds": {
"type": "integer",
"description": "Process uptime in seconds"
},
"checks": {
"type": "object",
"properties": {
"l2_backend": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"up",
"down"
]
},
"latency_ms": {
"type": "integer",
"description": "Latency in milliseconds"
}
},
"required": [
"status",
"latency_ms"
]
},
"surreal": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"up",
"down"
]
},
"latency_ms": {
"type": "integer",
"description": "Latency in milliseconds"
}
},
"required": [
"status",
"latency_ms"
]
},
"nats": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": [
"up",
"down"
]
},
"latency_ms": {
"type": "integer",
"description": "Latency in milliseconds"
}
},
"required": [
"status",
"latency_ms"
]
}
},
"description": "L2 dependency cascade checks"
}
},
"required": [
"status",
"service",
"timestamp",
"uptime_seconds",
"checks"
]
},
"AuthLoginBody": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "User email address"
},
"password": {
"type": "string",
"description": "User password"
}
},
"required": [
"email",
"password"
],
"additionalProperties": false
},
"AuthLoginResponse": {
"type": "object",
"properties": {
"token": {
"type": "string",
"description": "JWT session token"
},
"user": {
"type": "object",
"properties": {
"sub": {
"type": "string",
"description": "User identifier (e.g., user:123 or user:user@example.com)"
},
"email": {
"type": "string",
"format": "email",
"description": "User email"
},
"name": {
"type": "string",
"description": "Display name"
},
"roles": {
"type": "array",
"items": {
"type": "string"
},
"description": "User roles"
},
"scopes": {
"type": "array",
"items": {
"type": "string"
},
"description": "User scopes"
}
},
"required": [
"sub",
"email",
"roles"
]
}
},
"required": [
"token",
"user"
]
},
"AuthRegisterBody": {
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email",
"description": "User email address"
},
"password": {
"type": "string",
"description": "User password"
},
"name": {
"type": "string",
"description": "Display name"
}
},
"required": [
"email",
"password"
],
"additionalProperties": false
},
"AuthMeResponse": {
"type": "object",
"properties": {
"sub": {
"type": "string",
"description": "User identifier"
},
"provider": {
"type": "string",
"description": "Authentication provider (e.g., password)"
},
"roles": {
"type": "array",
"items": {
"type": "string"
},
"description": "User roles"
},
"scopes": {
"type": "array",
"items": {
"type": "string"
},
"description": "User scopes"
}
},
"required": [
"sub",
"provider",
"roles"
]
},
"AuthVerifyResponse": {
"type": "object",
"properties": {
"valid": {
"type": "boolean",
"description": "Whether the token is valid"
},
"sub": {
"type": "string",
"description": "User identifier"
},
"roles": {
"type": "array",
"items": {
"type": "string"
},
"description": "User roles"
},
"scopes": {
"type": "array",
"items": {
"type": "string"
},
"description": "User scopes"
}
},
"required": [
"valid",
"sub",
"roles"
]
},
"PresenceLocation": {
"type": "object",
"properties": {
"lat": {
"type": "number",
"description": "Latitude in decimal degrees, range [-90, 90]"
},
"lng": {
"type": "number",
"description": "Longitude in decimal degrees, range [-180, 180]"
}
},
"required": [
"lat",
"lng"
],
"additionalProperties": false
},
"PresenceUpdateBody": {
"type": "object",
"properties": {
"online": {
"type": "boolean",
"description": "Whether the user is online"
},
"status": {
"type": "string",
"description": "User status (e.g., online, away, offline)"
},
"location": {
"$ref": "#/components/schemas/PresenceLocation",
"description": "Optional GPS location"
}
},
"required": [
"online",
"status"
],
"additionalProperties": false
},
"PresenceResponse": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "User identifier"
},
"online": {
"type": "boolean",
"description": "Whether the user is online"
},
"status": {
"type": "string",
"description": "User status"
},
"last_seen": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp of last seen activity"
}
},
"required": [
"user_id",
"online",
"status",
"last_seen"
]
},
"PresenceScopeEntry": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "User identifier"
},
"online": {
"type": "boolean",
"description": "Whether the user is online"
},
"status": {
"type": "string",
"description": "User status"
},
"last_seen": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp"
}
},
"required": [
"user_id",
"online",
"status",
"last_seen"
]
},
"ProvenanceResponse": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"message_id": {
"type": "string",
"description": "Message identifier"
},
"body": {
"type": "string",
"description": "Message content"
},
"content_hash": {
"type": "string",
"description": "SHA256 hash of message content"
},
"attestations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"attestor": {
"type": "string",
"description": "Attestor user identifier"
},
"role": {
"type": "string",
"description": "Attestor role"
},
"timestamp": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp"
},
"signature": {
"type": "string",
"description": "Attestation signature"
}
},
"required": [
"attestor",
"role",
"timestamp"
]
},
"description": "Attestation chain entries"
},
"parent_chain": {
"type": "array",
"items": {
"type": "object",
"properties": {
"parent_id": {
"type": "string",
"description": "Parent message ID"
},
"relationship": {
"type": "string",
"description": "Relationship type (e.g., reply_to)"
},
"timestamp": {
"type": "string",
"format": "date-time"
}
},
"required": [
"parent_id",
"relationship"
]
},
"description": "Parent message chain"
},
"delivery_timeline": {
"type": "object",
"properties": {
"sent": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp when sent"
},
"delivered": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp when delivered"
},
"read": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp when read (optional)"
}
},
"description": "Delivery timeline timestamps"
},
"truth_index_ref": {
"type": "string",
"description": "Truth graph index reference"
},
"scope": {
"type": "string",
"description": "Scope identifier (e.g., portfolio:dev)"
}
},
"required": [
"ok",
"message_id",
"body",
"content_hash",
"attestations",
"parent_chain",
"delivery_timeline",
"truth_index_ref"
]
},
"ProvenanceVerifyResponse": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"valid": {
"type": "boolean",
"description": "Whether content integrity is valid"
},
"message_id": {
"type": "string",
"description": "Message identifier"
},
"computed_hash": {
"type": "string",
"description": "Re-computed SHA256 hash"
},
"stored_hash": {
"type": "string",
"description": "Stored content_hash from provenance"
},
"reason": {
"type": "string",
"description": "Reason if invalid (optional)"
}
},
"required": [
"ok",
"valid",
"message_id",
"computed_hash",
"stored_hash"
]
},
"NotificationEnqueueBody": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "Target user identifier"
},
"type": {
"type": "string",
"enum": [
"general",
"alert",
"reminder",
"warning",
"success"
],
"description": "Notification type"
},
"title": {
"type": "string",
"description": "Notification title"
},
"body": {
"type": "string",
"description": "Notification body text"
},
"data": {
"type": "object",
"description": "Additional data key-value pairs"
}
},
"required": [
"user_id",
"type",
"title",
"body"
],
"additionalProperties": false
},
"NotificationEntry": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Notification ID (e.g., notif:001)"
},
"user_id": {
"type": "string",
"description": "Target user identifier"
},
"title": {
"type": "string",
"description": "Notification title"
},
"type": {
"type": "string",
"description": "Notification type"
},
"status": {
"type": "string",
"enum": [
"pending",
"delivered",
"read"
],
"description": "Current notification status"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 creation timestamp"
}
},
"required": [
"id",
"user_id",
"title",
"type",
"status",
"created_at"
]
},
"FormSchemaSummary": {
"type": "object",
"properties": {
"schema_id": {
"type": "string",
"description": "Form schema identifier (e.g., form:contact-us)"
},
"name": {
"type": "string",
"description": "Form schema name"
},
"version": {
"type": "integer",
"description": "Schema version (bumped on update)"
},
"is_active": {
"type": "boolean",
"description": "Whether the schema is active"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 creation timestamp"
}
},
"required": [
"schema_id",
"name",
"version",
"is_active"
]
},
"FormSchemaDetail": {
"type": "object",
"properties": {
"schema_id": {
"type": "string",
"description": "Form schema identifier"
},
"name": {
"type": "string",
"description": "Form schema name"
},
"version": {
"type": "integer",
"description": "Schema version"
},
"fields": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Field identifier"
},
"label": {
"type": "string",
"description": "Field display label"
},
"type": {
"type": "string",
"enum": [
"text",
"email",
"textarea",
"select",
"boolean",
"number"
],
"description": "Form field type"
},
"validation": {
"type": "object",
"description": "Validation rules for this field"
}
},
"required": [
"id",
"label",
"type"
]
},
"description": "Form fields definition"
},
"submit_action": {
"type": "string",
"description": "Action on form submission (e.g., enqueue_notification)"
},
"is_active": {
"type": "boolean",
"description": "Whether the schema is active"
}
},
"required": [
"schema_id",
"name",
"version",
"fields",
"submit_action",
"is_active"
]
},
"FormField": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Field identifier"
},
"label": {
"type": "string",
"description": "Field display label"
},
"type": {
"type": "string",
"enum": [
"text",
"email",
"textarea",
"select",
"boolean",
"number"
],
"description": "Form field type"
},
"validation": {
"type": "object",
"description": "Validation rules for this field"
}
},
"required": [
"id",
"label",
"type"
],
"additionalProperties": false
},
"FormSubmissionBody": {
"type": "object",
"properties": {
"schema_id": {
"type": "string",
"description": "Form schema identifier"
},
"submission_data": {
"type": "object",
"description": "Submitted form field values"
},
"attest_mfa": {
"type": "boolean",
"description": "Whether MFA attestation is required"
},
"user_context": {
"type": "string",
"description": "User identifier context"
}
},
"required": [
"schema_id",
"submission_data"
],
"additionalProperties": false
},
"FormAttestationResponse": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"attestation_id": {
"type": "string",
"description": "Attestation identifier (e.g., attest:001)"
},
"recorded_at": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp"
},
"PoCE": {
"type": "object",
"properties": {
"started": {
"type": "boolean",
"description": "Whether PoCE session was started"
},
"reason": {
"type": "string",
"description": "Reason if PoCE not started (optional)"
}
},
"description": "PoCE session status"
}
},
"required": [
"ok",
"attestation_id",
"recorded_at",
"PoCE"
]
},
"QueryBody": {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"select",
"insert",
"update",
"delete",
"upsert"
],
"description": "CRUD action to perform"
},
"table": {
"type": "string",
"description": "SurrealDB table name"
},
"filters": {
"type": "object",
"description": "Filter criteria for selecting records"
},
"limit": {
"type": "integer",
"description": "Maximum number of records to return (default 100)"
},
"offset": {
"type": "integer",
"description": "Number of records to skip (default 0)"
},
"sort": {
"type": "object",
"properties": {
"field": {
"type": "string",
"description": "Sort field"
},
"dir": {
"type": "string",
"enum": [
"ASC",
"DESC"
],
"description": "Sort direction"
}
},
"description": "Sort specification"
},
"data": {
"type": "object",
"description": "Data to insert/update (action: insert/upsert/update)"
}
},
"required": [
"action",
"table"
],
"additionalProperties": false
},
"QueryResponse": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"records": {
"type": "array",
"items": {
"type": "object",
"description": "Record object with id and data"
},
"description": "Array of matching records"
},
"total": {
"type": "integer",
"description": "Total number of matching records (across all pages)"
},
"limit": {
"type": "integer",
"description": "Page size used"
},
"offset": {
"type": "integer",
"description": "Offset used"
}
},
"required": [
"ok",
"records",
"total",
"limit",
"offset"
]
},
"SqlRequest": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "Raw SurrealQL string (plain text, not JSON)"
}
},
"required": [
"sql"
],
"additionalProperties": false
},
"SqlResponse": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"description": "Query result row(s)"
},
"description": "Array of result sets"
},
"takes": {
"type": "integer",
"description": "Execution time in milliseconds"
},
"type": {
"type": "string",
"enum": [
"select",
"update",
"delete",
"batch"
],
"description": "Type of SQL operation"
}
},
"required": [
"results",
"takes",
"type"
]
},
"UsersListResponse": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"users": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "User identifier (e.g., user:123)"
},
"email": {
"type": "string",
"format": "email",
"description": "User email"
},
"roles": {
"type": "array",
"items": {
"type": "string",
"description": "User role"
},
"description": "Array of roles"
},
"created_at": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 creation timestamp"
}
},
"description": "User summary object"
},
"description": "List of users"
},
"total": {
"type": "integer",
"description": "Total number of users available"
},
"limit": {
"type": "integer",
"description": "Page size used"
},
"offset": {
"type": "integer",
"description": "Page offset used"
}
},
"required": [
"ok",
"users",
"total",
"limit",
"offset"
]
}
},
"securitySchemes": {
"BearerJWT": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
},
"APIKey": {
"type": "apiKey",
"in": "header",
"name": "X-API-Key"
}
}
},
"security": [
{
"BearerJWT": []
}
],
"paths": {
"/health": {
"get": {
"tags": [
"health"
],
"summary": "Detailed health check with L2 dependency cascade",
"description": "Returns service status, uptime, and dependency check latencies for SurrealDB, NATS, and L2 backend.",
"operationId": "getHealth",
"responses": {
"200": {
"description": "Health check OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HealthCheckResponse"
}
}
}
},
"503": {
"description": "Service not ready (L2 backend unreachable)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/ready": {
"get": {
"tags": [
"health"
],
"summary": "Readiness probe",
"description": "Fails if L2 backend or SurrealDB is unreachable. Used by orchestration systems.",
"operationId": "getReady",
"responses": {
"200": {
"description": "Service ready",
"content": {
"application/json": {
"example": {
"status": "ok",
"service": "app-bff"
}
}
}
},
"503": {
"description": "Service not ready",
"content": {
"application/json": {
"example": {
"status": "not_ready",
"reason": "L2 backend not available",
"l2_status": "down"
}
}
}
}
}
}
},
"/live": {
"get": {
"tags": [
"health"
],
"summary": "Liveness probe",
"description": "Confirms the process is alive. Basic uptime check.",
"operationId": "getLive",
"responses": {
"200": {
"description": "Service alive",
"content": {
"application/json": {
"example": {
"status": "ok",
"uptime_seconds": 86400
}
}
}
}
}
}
},
"/metrics": {
"get": {
"tags": [
"health"
],
"summary": "Prometheus-formatted metrics",
"description": "Returns Prometheus text-format metrics for monitoring systems.",
"operationId": "getMetrics",
"responses": {
"200": {
"description": "Metrics output",
"content": {
"text/plain": {
"example": "# HELP bff_uptime_seconds Process uptime in seconds.\n# TYPE bff_uptime_seconds gauge\nbff_uptime_seconds 86400\n"
}
}
}
}
}
},
"/v1/auth/login": {
"post": {
"tags": [
"auth"
],
"summary": "Password login",
"description": "Authenticate with email/password and return a session JWT.",
"operationId": "postAuthLogin",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthLoginBody"
}
}
}
},
"responses": {
"200": {
"description": "Login successful",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthLoginResponse"
}
}
}
},
"401": {
"description": "Invalid credentials",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/auth/register": {
"post": {
"tags": [
"auth"
],
"summary": "Password registration",
"description": "Register a new user account with email, password, and display name.",
"operationId": "postAuthRegister",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthRegisterBody"
}
}
}
},
"responses": {
"201": {
"description": "Registration successful",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthLoginResponse"
}
}
}
},
"400": {
"description": "Validation failed (e.g., duplicate email)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/auth/me": {
"get": {
"tags": [
"auth"
],
"summary": "Get current user info",
"description": "Returns the current user's identifier, provider, roles, and scopes from the session JWT.",
"operationId": "getAuthMe",
"responses": {
"200": {
"description": "User info retrieved",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthMeResponse"
}
}
}
},
"401": {
"description": "Missing or invalid auth token",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
},
"security": [
{
"BearerJWT": []
}
]
}
},
"/v1/auth/verify": {
"post": {
"tags": [
"auth"
],
"summary": "Token verification",
"description": "Validate a session JWT or API key. Returns user context headers (X-Forwarded-User, X-Forwarded-Roles, X-Forwarded-Scopes).",
"operationId": "postAuthVerify",
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"token": {
"type": "string",
"description": "JWT token or API key"
}
},
"additionalProperties": false
}
}
}
},
"responses": {
"200": {
"description": "Token valid",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthVerifyResponse"
}
}
},
"headers": {
"X-Forwarded-User": {
"description": "Username from JWT"
},
"X-Forwarded-Roles": {
"description": "Comma-separated roles from JWT"
},
"X-Forwarded-Scopes": {
"description": "Comma-separated scopes from JWT"
}
}
},
"401": {
"description": "Invalid token or API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/auth/validate-token": {
"get": {
"tags": [
"auth"
],
"summary": "GET-friendly token validation",
"description": "Validate a session JWT or API key via GET request. Returns simple validity status.",
"operationId": "getAuthValidateToken",
"responses": {
"200": {
"description": "Token validation result",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AuthVerifyResponse"
}
}
}
},
"401": {
"description": "Invalid token or API key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/users/:userId/presence": {
"put": {
"tags": [
"domain"
],
"summary": "Upsert user global presence",
"description": "Upsert or create the user's global presence record with online status, optional status text, and GPS location.",
"operationId": "putUserPresence",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"description": "User identifier (e.g., user:123 or user:user@example.com)",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PresenceUpdateBody"
}
}
}
},
"responses": {
"200": {
"description": "Presence updated",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PresenceResponse"
}
}
}
},
"400": {
"description": "Invalid location coordinates (lat/lng out of range)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
},
"401": {
"description": "Authentication required",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
},
"security": [
{
"BearerJWT": []
}
]
},
"get": {
"tags": [
"domain"
],
"summary": "Get user global presence",
"description": "Retrieve the user's current global presence record.",
"operationId": "getUserPresence",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"description": "User identifier",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Presence record retrieved",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PresenceResponse"
}
}
}
},
"404": {
"description": "No presence record found for this user",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
},
"security": [
{
"BearerJWT": []
}
]
}
},
"/v1/presence/:scope/:scopeId": {
"get": {
"tags": [
"domain"
],
"summary": "List presence in a scope",
"description": "List all user presence records within a given scope (e.g., portfolio:dev). Supports pagination.",
"operationId": "getScopePresence",
"parameters": [
{
"name": "scope",
"in": "path",
"required": true,
"description": "Scope name (e.g., portfolio)",
"schema": {
"type": "string"
}
},
{
"name": "scopeId",
"in": "path",
"required": true,
"description": "Scope identifier (e.g., dev)",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "Maximum number of records to return (default 50)",
"schema": {
"type": "integer",
"default": 50
}
},
{
"name": "offset",
"in": "query",
"description": "Number of records to skip (default 0)",
"schema": {
"type": "integer",
"default": 0
}
}
],
"responses": {
"200": {
"description": "Presence records list",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/PresenceScopeEntry"
}
}
}
}
},
"404": {
"description": "Scope not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/notifications": {
"post": {
"tags": [
"notifications"
],
"summary": "Enqueue a notification",
"description": "Enqueue a notification for a user. Routes through NATS JetStream outbox. Triggers PoCE session if governance_path_spec_id is set.",
"operationId": "postNotificationsEnqueue",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NotificationEnqueueBody"
}
}
}
},
"responses": {
"201": {
"description": "Notification enqueued",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"notification_id": {
"type": "string",
"description": "Enqueued notification ID (e.g., notif:001)"
},
"queued_at": {
"type": "string",
"format": "date-time",
"description": "ISO-8601 timestamp when queued"
}
},
"required": [
"ok",
"notification_id",
"queued_at"
]
}
}
}
},
"422": {
"description": "Validation failed (e.g., environmentId missing from JWT)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"get": {
"tags": [
"notifications"
],
"summary": "Get pending notifications for a user",
"description": "Retrieve pending notifications for a user. Supports filtering by status and pagination.",
"operationId": "getNotifications",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"description": "User identifier",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "Maximum number of records to return (default 50)",
"schema": {
"type": "integer",
"default": 50
}
},
{
"name": "offset",
"in": "query",
"description": "Number of records to skip (default 0)",
"schema": {
"type": "integer",
"default": 0
}
},
{
"name": "status",
"in": "query",
"description": "Filter by status (pending, delivered, read)",
"schema": {
"type": "string",
"enum": [
"pending",
"delivered",
"read"
]
}
}
],
"responses": {
"200": {
"description": "Notifications list",
"content": {
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/NotificationEntry"
}
}
}
}
}
}
}
},
"/v1/provenance/:messageId": {
"get": {
"tags": [
"provenance"
],
"summary": "Get full provenance chain",
"description": "Retrieve the full provenance chain for a message, including metadata, attestation chain, parent chain, delivery timeline, and truth index reference.",
"operationId": "getProvenance",
"parameters": [
{
"name": "messageId",
"in": "path",
"required": true,
"description": "Message identifier (e.g., notif:001 or msg:abc123)",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Provenance chain retrieved",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProvenanceResponse"
}
}
}
},
"404": {
"description": "Message not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/provenance/:messageId/verify": {
"get": {
"tags": [
"provenance"
],
"summary": "Verify message content integrity",
"description": "Re-compute SHA256 hash and compare against stored content_hash. Returns whether the content has been tampered with.",
"operationId": "getProvenanceVerify",
"parameters": [
{
"name": "messageId",
"in": "path",
"required": true,
"description": "Message identifier",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Integrity verification result",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ProvenanceVerifyResponse"
}
}
}
}
}
}
},
"/v1/forms": {
"get": {
"tags": [
"forms"
],
"summary": "List active form schemas",
"description": "List all active form schemas. Supports optional category filtering and pagination.",
"operationId": "getFormsList",
"parameters": [
{
"name": "category",
"in": "query",
"description": "Filter by category (optional)",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "Maximum number of schemas to return (default 50)",
"schema": {
"type": "integer",
"default": 50
}
},
{
"name": "offset",
"in": "query",
"description": "Number of schemas to skip (default 0)",
"schema": {
"type": "integer",
"default": 0
}
}
],
"responses": {
"200": {
"description": "Schema summaries",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"schemas": {
"type": "array",
"items": {
"$ref": "#/components/schemas/FormSchemaSummary"
}
},
"total": {
"type": "integer",
"description": "Total number of schemas (across all pages)"
}
},
"required": [
"ok",
"schemas",
"total"
]
}
}
}
}
}
},
"post": {
"tags": [
"forms"
],
"summary": "Create a new form schema",
"description": "Create a new form schema with definition, validation rules, and metadata. Bumps version to 1 on creation.",
"operationId": "postFormsCreate",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FormSchemaCreateBody"
}
}
}
},
"responses": {
"201": {
"description": "Schema created",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"schema_id": {
"type": "string",
"description": "Created schema identifier"
},
"version": {
"type": "integer",
"description": "Schema version (1 on creation)"
}
},
"required": [
"ok",
"schema_id",
"version"
]
}
}
}
},
"400": {
"description": "Validation failed (e.g., invalid field definition)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/forms/:schemaId": {
"get": {
"tags": [
"forms"
],
"summary": "Get a single form schema",
"description": "Retrieve a form schema by ID or name. Returns the full schema definition including fields, validation, and submit action.",
"operationId": "getFormSchema",
"parameters": [
{
"name": "schemaId",
"in": "path",
"required": true,
"description": "Schema identifier or name (e.g., form:contact-us or contact-us)",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Schema detail retrieved",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FormSchemaDetail"
}
}
}
},
"404": {
"description": "Schema not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"put": {
"tags": [
"forms"
],
"summary": "Update form schema",
"description": "Update a form schema definition. Bumps version on successful update. Partial updates allowed.",
"operationId": "putFormSchema",
"parameters": [
{
"name": "schemaId",
"in": "path",
"required": true,
"description": "Schema identifier",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FormSchemaUpdateBody"
}
}
}
},
"responses": {
"200": {
"description": "Schema updated",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"schema_id": {
"type": "string",
"description": "Updated schema identifier"
},
"version": {
"type": "integer",
"description": "New schema version (bumped)"
}
},
"required": [
"ok",
"schema_id",
"version"
]
}
}
}
},
"404": {
"description": "Schema not found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
},
"delete": {
"tags": [
"forms"
],
"summary": "Soft-delete form schema",
"description": "Soft-delete (deactivate) a form schema. The schema is marked inactive but not permanently removed.",
"operationId": "deleteFormSchema",
"parameters": [
{
"name": "schemaId",
"in": "path",
"required": true,
"description": "Schema identifier",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Schema deactivated",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ok": {
"type": "boolean",
"description": "Always true"
},
"schema_id": {
"type": "string",
"description": "Deactivated schema identifier"
},
"deactivated": {
"type": "boolean",
"description": "Whether deactivation was successful"
}
},
"required": [
"ok",
"schema_id",
"deactivated"
]
}
}
}
}
}
}
},
"/v1/forms/attest": {
"post": {
"tags": [
"forms"
],
"summary": "Attest a form submission",
"description": "Attest a form submission. Verifies session trust + optional MFA, then records attestation with PoCE integration if applicable.",
"operationId": "postFormsAttest",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FormAttestationBody"
}
}
}
},
"responses": {
"201": {
"description": "Attestation recorded",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/FormAttestationResponse"
}
}
}
},
"400": {
"description": "Validation failed (e.g., invalid submission data)",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
},
"/v1/users": {
"get": {
"tags": [
"users"
],
"summary": "List users",
"description": "List users from the user_profile table. Supports role filtering and pagination via query parameters.",
"operationId": "getUsersList",
"parameters": [
{
"name": "role",
"in": "query",
"description": "Filter by role (e.g., user). Optional.",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"description": "Maximum number of users to return (default 100)",
"schema": {
"type": "integer",
"default": 100
}
},
{
"name": "offset",
"in": "query",
"description": "Number of users to skip (default 0)",
"schema": {
"type": "integer",
"default": 0
}
}
],
"responses": {
"200": {
"description": "Users list",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UsersListResponse"
}
}
}
},
"400": {
"description": "Invalid query parameters",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ErrorResponse"
}
}
}
}
}
}
}
}
}