How it works

Build analytics once. Deliver them three ways.

GitHub → ingestion → Postgres → Embedded Canvas → public OpenDev, a customer product, and internal operations. OpenDev is the host. Embedded Canvas owns the semantic layer, the hosted runtime, and tenant isolation. The host source is on GitHub.

The pipeline

  1. GitHub public data is ingested by a worker into Postgres. Visitor page loads never call GitHub.
  2. Postgres is the warehouse: orgs, repos, PRs, issues, commits, reviews. Every fact row has org_id.
  3. Embedded Canvas connects to that warehouse, publishes Cube models (PullRequests, Issues, Commits, Contributors), and hosts Apache Superset for the dashboards this site embeds.
  4. Two read paths share those definitions: chromeless dashboards via @embeddedcanvas/embed-sdk, and a governed metrics API the host queries for the KPI cards above each chart. Neither path recomputes a metric in OpenDev.
  5. Host filters go out with every embed session: org_id plus a date range (30 / 90 / 365 days). Cube publishes both tenantId and org_id so embed RLS matches the warehouse column.
  6. Three audiences reuse the same dashboards: public OpenDev (unscoped session + host filters), DevMetrics customer (RLS on org_id), DevMetrics internal (skipTenantRls).

What each tab shows

  • Overview — launch KPIs from the governed metrics API, plus an embedded org dashboard.
  • Delivery — PR throughput as a hosted time-series (merge activity over the selected range).
  • Collaboration — first-review heatmap (weekday × hour) on PullRequests.
  • Issues — weekly intake stacked by bug vs other, with optional Prophet forecast in the hosted chart.
  • Contributors — active authors and top-10 concentration; embed is PR volume by author.
  • Repositories — catalog table plus an embed that can take a repo_id host filter when you select a row.

The same metrics, three surfaces

median_cycle_time

Median PR cycle time

percentile_cont(0.5) of (merged_at - created_at) in hours

Source pull_requests · measure PullRequests.medianCycleHours

Inclusion: merged_at is not null

  • OpenDev public
  • DevMetrics customer
  • DevMetrics internal

median_first_review

Median time to first review

percentile_cont(0.5) of (first_review_at - created_at) in hours

Source pull_requests · measure PullRequests.medianFirstReviewHours

Inclusion: first_review_at is not null

  • OpenDev public
  • DevMetrics customer
  • DevMetrics internal

prs_merged

PRs merged

count of pull requests where merged_at is not null

Source pull_requests · measure PullRequests.count over PullRequests.mergedAt

Inclusion: merged_at is not null

  • OpenDev public
  • DevMetrics customer
  • DevMetrics internal

Switch audience

Public product → customer view → internal view. Same deployment, same metric definitions, same analytics components, different security context.

Open DevMetrics as Vercel · Open internal operations · Back to public Vercel

Tenant isolation

Same dashboards. The BFF derives customerId from an HttpOnly cookie (customer) or sets skipTenantRls (internal). The forged body field is ignored.

Open a customer view first so the tenant cookie is set, then try forging another org id.

What this site proves

  • Native embedded analytics (chromeless, host-owned chrome)
  • Organization and date-range host filters on every public embed
  • Per-tab dashboards selected by embed tokens, not hardcoded chart SQL in the host
  • Same metric definitions on cards and charts
  • Host-rendered KPI cards served by the governed metrics API — cards resolve through the catalog, none are computed in the host
  • Customer tenant isolation (HttpOnly cookie → customerId)
  • Internal cross-customer analytics (skipTenantRls)

Want analytics like this inside your product?

OpenDev is a customer of Embedded Canvas: session mint from a BFF, chromeless @embeddedcanvas/embed-sdk, row-level security on org_id. The host app for this site is public on GitHub.

See the customer embed → · OpenDev source on GitHub → · Embedded Canvas →