Octonode Playbook

Custom analytics architecture

Canonical Octonode repository documentation.

Custom analytics architecture

Outcome

Each project gets a separate Analytics Studio tab. A user can create dashboards, choose approved run-stat sources, render them as stats/area/bar/pie charts, and reorder widgets with pointer drag-and-drop or keyboard controls. Saved dashboards are private to that user inside the selected workspace and project.

Monitoring remains the fixed production-health view. Custom analytics is a composition layer over the same persisted run data; it does not add another telemetry pipeline or analytics database.

Package boundary

@octonode/schema remains the wire-contract owner for dashboard definitions and validated mutation inputs. @octonode/analytics is a small reusable package with:

  • transport-independent CRUD/query operation types;
  • layout helpers and the approved widget-source catalogue;
  • a @octonode/analytics/react export that turns injected operations into React Query options.

The package does not know about Hono, filesystem paths, Durable Objects, the generated Studio client, Recharts, or Octonode styling. Studio injects generated-client operations and owns the branded editor/chart renderers. A shared visual component can be added when a second consumer proves that its rendering requirements match Studio's.

Ownership and flow

Studio Analytics tab
  -> generated OpenAPI client
  -> local server controller OR hosted workspace gateway
  -> authenticated user + selected project scope
  -> FsStorageProvider OR existing per-workspace ProjectDataTablesObject

Widget rendering
  -> saved dashboard definition
  + existing GET /projects/:projectId/analytics?days=...
  -> approved source selector
  -> Recharts/stat renderer
  • Local authority: the selected project's .octonode/ store, scoped by the provider identity.
  • Hosted authority: the existing workspace Durable Object, scoped by the gateway principal.
  • Storage keys, absolute paths, and owner IDs stay private at the response boundary.
  • Updates carry revision; stale writes return 409 rather than silently overwriting.
  • Viewers may read their dashboards; dashboard mutations require project write permission.

Initial contract

A dashboard has id, name, optional description, a days value of 7/14/30, ordered widgets, timestamps, and a numeric revision. Each widget has id, title, visualization, source, and width. The first source catalogue is intentionally bounded to fields already returned by project analytics:

  • stats: total, successful, failed, success rate, average duration, p50, p95, node runs;
  • area: daily execution volume;
  • bar: workflow volume;
  • pie: status distribution.

Arbitrary SQL, user expressions, and custom data-table joins are out of the browser contract. Add a versioned, cost-bounded query registry only when measured dashboard use identifies another source.

API

GET    /api/projects/:projectId/analytics/dashboards
POST   /api/projects/:projectId/analytics/dashboards
GET    /api/projects/:projectId/analytics/dashboards/:dashboardId
PATCH  /api/projects/:projectId/analytics/dashboards/:dashboardId
DELETE /api/projects/:projectId/analytics/dashboards/:dashboardId

The existing project-analytics endpoint supplies all initial widget data in one bounded request. Dashboard definitions are small and capped at 24 widgets, so no paging or separate layout service is needed in the first version.

Delivery

  1. T158: contracts, package boundary, injected React Query operations, and layout checks.
  2. T159: local/hosted per-user persistence, revision conflicts, OpenAPI, and isolation tests.
  3. T160: Studio Analytics tab, chart editor, accessible reordering, stories, and visual checks.
  4. T161: governed additional sources after usage demonstrates what is missing.

On this page