Skip to content

BFF APIs

Target Architecture — Final-State Design

This page describes the final-state Backend-for-Frontend (BFF) tier of the Factory Studio. The .NET ASP.NET Core BFF pattern, the SignalR substrate (ConnectSoft.Extensions.Saas.AspNetCore.SignalR), and OpenIddict-validated auth are implemented today; the 8 ConnectSoft.Factory.Studio.* services below are the designed end state.

The Factory Studio is served by a tier of 8 microservices in the ConnectSoft.Factory.Studio.* namespace, built on .NET 10 ASP.NET Core and following the Clean Architecture layering of the microservice template. They implement the Backend-for-Frontend (BFF) pattern: each service shapes data specifically for the experience, aggregating multiple source-of-truth platform APIs into a single, tenant-scoped, view-shaped response so the Blazor microfrontends stay thin and chatty round-trips stay off the browser.

The 8 microservices

Service Namespace Responsibility Aggregates / owns
Studio BFF ConnectSoft.Factory.Studio.StudioBff The primary edge BFF and composition gateway. Fronts the shell, routes to the specialized BFFs, and aggregates cross-cutting reads. Fans out to all platforms and to the other Studio services
Studio Notification Service ConnectSoft.Factory.Studio.StudioNotificationService Owns in-app, digest, and escalation notifications scoped to tenant, project, and role. Owns StudioNotification
Studio Realtime Gateway ConnectSoft.Factory.Studio.StudioRealtimeGateway SignalR hub host. Subscribes to factory events and pushes authorized live updates to browsers. Owns no domain state; owns connection/group state in Redis
Review Center Service ConnectSoft.Factory.Studio.ReviewCenterService The human-in-the-loop engine. Manages review queue, decisions, escalation, and override. Owns ReviewRequest, ReviewDecision
Dashboard Aggregation Service ConnectSoft.Factory.Studio.DashboardAggregationService Assembles dashboard views from multiple platform sources; caches hot dashboards. Owns DashboardView; reads Control Plane + Observability
Artifact Preview Service ConnectSoft.Factory.Studio.ArtifactPreviewService Produces render-ready artifact previews, diffs, and lineage over Knowledge artifact memory. Owns ArtifactPreviewSession; reads Knowledge Platform
Knowledge Explorer BFF ConnectSoft.Factory.Studio.KnowledgeExplorerBff Serves bounded, access-checked knowledge graph neighbourhoods to the explorer. Reads Knowledge Platform graph
Agent Flow Visualization Service ConnectSoft.Factory.Studio.AgentFlowVisualizationService Projects Agent Mesh task graphs and executions into render-ready flow view models. Reads Agent Mesh
flowchart TB
    Shell["Blazor MFE Shell"]
    Shell -->|"REST/gRPC"| Bff["StudioBff"]
    Shell -->|"SignalR"| Rtg["StudioRealtimeGateway"]

    Bff --> Dash["DashboardAggregationService"]
    Bff --> Review["ReviewCenterService"]
    Bff --> Preview["ArtifactPreviewService"]
    Bff --> KExp["KnowledgeExplorerBff"]
    Bff --> Flow["AgentFlowVisualizationService"]
    Bff --> Notif["StudioNotificationService"]

    Dash --> CP["Control Plane API"]
    Dash --> OBS["Observability API"]
    Review --> CP
    Review --> GOV["Governance API"]
    Preview --> KP["Knowledge API"]
    KExp --> KP
    Flow --> AM["Agent Mesh API"]
    Bff --> MKT["Marketplace API"]

    Rtg -->|subscribe| Bus["Azure Service Bus"]
    CP -->|events| Bus
    AM -->|events| Bus
    OBS -->|signals| Bus
    Notif -->|notify events| Bus
Hold "Alt" / "Option" to enable pan & zoom

BFF aggregation patterns

The Studio BFF tier applies a consistent set of patterns so the experience stays fast, governed, and decoupled from source-platform internals:

  • View-shaped aggregation. A single BFF endpoint fans out to several platform APIs in parallel and returns one response shaped for a specific module/view, eliminating browser-side orchestration and N+1 calls.
  • Tenant scoping at the edge. Every BFF resolves tenantId from the OpenIddict access token (never from the request body) and stamps it on every downstream call and cache key. See Security.
  • Read-model caching. Hot, expensive aggregations (dashboards, graph neighbourhoods) are cached in Redis keyed by tenantId + view + filter hash, with event-driven invalidation from the realtime stream.
  • Backend service composition. StudioBff is the only service the shell calls for cross-cutting reads; it composes the specialized BFFs (dashboard, review, preview, graph, flow) rather than the browser calling each directly.
  • Resilience and degradation. Downstream calls use timeouts, retries with jitter, and circuit breakers; a slow or failing source degrades gracefully (partial view + staleness indicator) rather than failing the whole page.
  • Command pass-through with authority. Writes (review decisions, overrides, install intents) are validated, authorized, audited, and forwarded to the owning platform as VerbNoun commands; the BFF never mutates source-of-truth state itself.
  • Idempotency. State-changing endpoints accept an idempotency key so retried submissions (e.g. a double-clicked approval) are safe, consistent with the metadata schema idempotency rules.

Real-time updates via SignalR

Live awareness is delivered by the StudioRealtimeGateway, a SignalR hub host built on ConnectSoft.Extensions.Saas.AspNetCore.SignalR. It is the bridge between the factory's event stream and the browser.

flowchart LR
    Bus["Azure Service Bus<br/>canonical envelope events"] -->|subscribe| Rtg["StudioRealtimeGateway"]
    Rtg -->|"authorize + map"| ViewModel["Realtime View Model"]
    Rtg -->|"group: tenant:project:role"| Hub["SignalR Hub"]
    Hub -->|"push"| Browser["Connected MFE Clients"]
    Rtg -->|"connection + group state"| Redis[("Redis backplane")]
Hold "Alt" / "Option" to enable pan & zoom
  • Event-sourced fan-out. The gateway subscribes to factory events (e.g. AgentTaskCompleted, DeploymentPromoted, ReviewRequested, RuntimeSignalRaised) on Azure Service Bus and translates each into a compact realtime view-model update.
  • Authorized groups. Clients join SignalR groups keyed by tenantId, projectId, and role. The gateway only pushes an event to a group whose members are authorized to see it — tenant isolation and RBAC apply to the stream exactly as they apply to REST.
  • Redis backplane. Connection and group state lives in Redis so the gateway scales out horizontally across instances while preserving delivery.
  • Targeted invalidation, not data dumps. Updates are small "what changed" signals carrying traceId/correlationId; the client either patches its view model or re-requests the affected BFF read model, keeping payloads tiny.
  • Trace continuity. Every pushed update carries the originating traceId, so a live tile remains click-through traceable to its source lifecycle in the Knowledge Graph Explorer and Observability.

Request + push sequence

sequenceDiagram
    participant MFE as Browser MFE
    participant BFF as StudioBff
    participant DASH as DashboardAggregationService
    participant CP as Control Plane API
    participant KP as Knowledge API
    participant RTG as StudioRealtimeGateway
    participant BUS as Azure Service Bus

    MFE->>BFF: GET /studio/dashboards/project-overview (Bearer token)
    BFF->>BFF: Resolve tenantId + RBAC from token
    BFF->>DASH: Compose project overview (tenantId)
    par Parallel aggregation
        DASH->>CP: GET /projects/{id}/state
    and
        DASH->>KP: GET /artifacts/summary?project={id}
    end
    CP-->>DASH: Project + workflow state
    KP-->>DASH: Artifact + lineage summary
    DASH-->>BFF: DashboardView read model (cached in Redis)
    BFF-->>MFE: 200 view model

    MFE->>RTG: Connect SignalR + join tenant:project group
    CP->>BUS: AgentTaskCompleted (envelope)
    BUS->>RTG: deliver event
    RTG->>RTG: Authorize for group + map to update
    RTG-->>MFE: push DashboardTileUpdated (traceId)
    MFE->>BFF: GET /studio/dashboards/project-overview (refresh changed tile)
    BFF-->>MFE: 200 patched view model
Hold "Alt" / "Option" to enable pan & zoom

Representative BFF endpoints

All endpoints are versioned (/v1), require an OpenIddict bearer token, resolve tenantId from the token, and follow the REST resource path conventions.

Studio BFF — composed project overview

GET /v1/studio/dashboards/project-overview?projectId=proj-booking-saas
Authorization: Bearer <token>
{
  "viewId": "dash-projoverview-9f1c",
  "tenantId": "connectsoft",
  "projectId": "proj-booking-saas",
  "generatedAt": "2026-06-11T18:04:00Z",
  "traceId": "trace-9f1c2b7d",
  "tiles": [
    { "key": "activeAgents", "value": 7, "source": "agent-mesh", "trend": "up" },
    { "key": "pendingReviews", "value": 3, "source": "studio-review", "severity": "warn" },
    { "key": "openIncidents", "value": 0, "source": "observability" },
    { "key": "monthlyCostUsd", "value": 1840.55, "source": "observability-finops" }
  ],
  "staleSources": [],
  "links": { "knowledgeGraph": "/studio/knowledge-graph?focus=proj-booking-saas" }
}

Dashboard Aggregation Service — saved dashboard view

GET /v1/studio/dashboards/{dashboardViewId}
{
  "dashboardViewId": "dash-booking-exec",
  "tenantId": "connectsoft",
  "ownerUserId": "user-amelia",
  "layout": "grid-3col",
  "widgets": [
    { "widgetId": "w-runs", "type": "workflow-throughput", "source": "control-plane", "range": "7d" },
    { "widgetId": "w-quality", "type": "quality-gates", "source": "observability" }
  ],
  "refreshPolicy": { "mode": "event-driven", "fallbackIntervalSeconds": 30 }
}

Review Center Service — review queue and decision

GET /v1/studio/reviews?status=pending
{
  "tenantId": "connectsoft",
  "items": [
    {
      "reviewRequestId": "rev-3a6e1d40",
      "subjectType": "Artifact",
      "subjectId": "art-domainmodel-7c",
      "projectId": "proj-booking-saas",
      "raisedBy": "agent:ConnectSoft.Agent.SolutionArchitect",
      "priority": "high",
      "slaDueAt": "2026-06-11T20:00:00Z",
      "status": "Pending",
      "traceId": "trace-9f1c2b7d"
    }
  ],
  "page": { "size": 25, "next": null }
}
POST /v1/studio/reviews/rev-3a6e1d40/decisions
Idempotency-Key: dec-amelia-rev-3a6e1d40
Content-Type: application/json
{
  "decision": "Approved",
  "reviewerUserId": "user-amelia",
  "rationale": "Domain model matches blueprint; aggregates and invariants correct.",
  "conditions": []
}
{
  "reviewDecisionId": "decn-7b21",
  "reviewRequestId": "rev-3a6e1d40",
  "decision": "Approved",
  "decidedAt": "2026-06-11T18:42:00Z",
  "emittedEvent": "ReviewApproved",
  "traceId": "trace-9f1c2b7d"
}

Artifact Preview Service — open a preview session

POST /v1/studio/artifacts/art-domainmodel-7c/preview-sessions
Content-Type: application/json
{ "version": "1.4.0", "renderKind": "diff", "compareToVersion": "1.3.0" }
{
  "sessionId": "prev-5e10",
  "artifactId": "art-domainmodel-7c",
  "version": "1.4.0",
  "renditions": [
    { "renditionId": "rd-diff-1", "renderKind": "diff", "contentType": "application/x-cs-diff", "redacted": false }
  ],
  "lineage": [
    { "from": "art-domainmodel-7c", "to": "task-4d21", "relationship": "producedBy" }
  ],
  "expiresAt": "2026-06-11T19:00:00Z"
}

Knowledge Explorer BFF — bounded graph neighbourhood

GET /v1/studio/knowledge-graph?focus=proj-booking-saas&depth=2&trace=trace-9f1c2b7d
{
  "viewId": "kg-proj-booking-2",
  "focusNodeId": "proj-booking-saas",
  "depth": 2,
  "nodes": [
    { "nodeId": "proj-booking-saas", "nodeType": "Project", "label": "Booking SaaS", "truncated": false },
    { "nodeId": "module-reservations-api", "nodeType": "Module", "label": "Reservations API", "truncated": false },
    { "nodeId": "art-domainmodel-7c", "nodeType": "Artifact", "label": "Domain Model", "classification": "internal" }
  ],
  "edges": [
    { "edgeId": "e1", "sourceNodeId": "proj-booking-saas", "targetNodeId": "module-reservations-api", "relationship": "contains" },
    { "edgeId": "e2", "sourceNodeId": "module-reservations-api", "targetNodeId": "art-domainmodel-7c", "relationship": "produces" }
  ]
}

Agent Flow Visualization Service — flow graph

GET /v1/studio/agent-flows/{workflowId}
{
  "workflowId": "wf-booking-build",
  "tenantId": "connectsoft",
  "status": "Running",
  "nodes": [
    { "taskId": "task-4d21", "agent": "ConnectSoft.Agent.SolutionArchitect", "state": "Completed" },
    { "taskId": "task-4d22", "agent": "ConnectSoft.Agent.BackendEngineer", "state": "Running" }
  ],
  "edges": [
    { "from": "task-4d21", "to": "task-4d22", "relationship": "dependsOn" }
  ],
  "traceId": "trace-9f1c2b7d"
}

Studio Notification Service — notifications

GET /v1/studio/notifications?unreadOnly=true
{
  "tenantId": "connectsoft",
  "items": [
    {
      "notificationId": "ntf-88a1",
      "kind": "ReviewEscalated",
      "subjectId": "rev-3a6e1d40",
      "severity": "high",
      "createdAt": "2026-06-11T18:55:00Z",
      "read": false
    }
  ]
}

Realtime gateway — SignalR hub contract

The gateway exposes a SignalR hub rather than REST. Clients invoke and receive:

Direction Member Purpose
Client → Hub JoinProject(projectId) Join the tenant-scoped project group (server re-checks authorization).
Client → Hub LeaveProject(projectId) Leave a project group.
Hub → Client DashboardTileUpdated(update) A dashboard tile changed; carries traceId.
Hub → Client ReviewQueueChanged(update) A review item was added, escalated, or decided.
Hub → Client AgentFlowAdvanced(update) An agent task state changed in a watched flow.
Hub → Client RuntimeSignalRaised(update) A runtime/health signal for a watched environment.
Hub → Client NotificationReceived(notification) A new in-app notification for the user.