Integrate
Backstage plugin
Render ScaleQuality's measured signals as an entity card in Backstage: AI durability, engineering maturity, code maturity and your tech radar, for the org, business unit or team the entity maps to. One click deep-links back into ScaleQuality for the full story.
What the card shows
One card, four signals, each read live for the scope the entity is annotated with. The card is theme-aware, so it stays legible in both Backstage themes.
| Signal | Source | Provenance |
|---|---|---|
| AI durability, survival rate and the rework it implies | git-attributed telemetry | MEASURED |
| Engineering maturity, L1 to L5 | assessment scorecards | MEASURED |
| Code maturity, a score out of 100 with sub-scores | zero-config Diagnosis | MEASURED |
| Tech radar, counted by ring | configured technology landscape | DECLARED |
The card reads the public read-only Platform API through the Backstage backend proxy, so your org-scoped key is injected server-side and never reaches the browser.
Before you start
What you need
- A Backstage app you can edit and redeploy.
- Permission to create an API key in ScaleQuality, which means owner or admin.
- A place to keep that key in your Backstage backend environment or secret store.
- At least one scope measured in ScaleQuality, otherwise every tile renders empty.
This guide targets @scalequality/backstage-plugin 0.1.4, the version currently published on npm.
Install and configure
Five steps: add the package, create the key, configure the proxy, add the card, and tell Backstage which ScaleQuality scope each entity belongs to.
Install the plugin
Add the package to your Backstage frontend app.
# from your Backstage app root yarn --cwd packages/app add @scalequality/backstage-plugin@^0.1.4
Create an API key in ScaleQuality
The key is scoped to your organization and read-only: it can read summaries for your org and nothing else. Name it after where it runs, so a rotation later is obvious.
- In ScaleQuality, open Developers.
- Press Create key and give it a name, for example Backstage production.
- Copy the key. It starts with sq_live_.
Store it as SCALEQUALITY_API_KEY in the environment of your Backstage backend, or in whatever secret store that backend already reads. It must never be part of the frontend bundle.
Configure the backend proxy
Add the proxy endpoint to your app config. The plugin calls it by the id scalequality.
proxy:
endpoints:
'/scalequality':
target: https://app.scalequality.io/v1
changeOrigin: true
headers:
Authorization: 'Bearer ${SCALEQUALITY_API_KEY}'Add the card to your entity page
Render the card wherever the entity overview lives. It sizes itself to the grid item you give it.
import { EntityScaleQualityCard } from '@scalequality/backstage-plugin';
// inside the entity page grid, e.g. the overview content:
<Grid item md={6}>
<EntityScaleQualityCard />
</Grid>Map entities to a ScaleQuality scope
The card needs to know which scope an entity represents. Annotate the Component or Group with the matching ScaleQuality id.
metadata:
annotations:
scalequality.io/team-id: <team-uuid>
# or: scalequality.io/bu-id: <bu-uuid>
# or: scalequality.io/org-id: <org-uuid>The most specific annotation wins: team over business unit over org. An entity with none of them renders the missing-annotation empty state rather than a number that belongs to somebody else.
The ids come from the catalog endpoint, or from the URL of the corresponding page in ScaleQuality.
curl https://app.scalequality.io/v1/catalog \ -H "Authorization: Bearer sq_live_..."
API reference
Everything the plugin reads is public, read-only and gated by the API key. The same endpoints back any other internal developer portal, Port included.
| Endpoint | Returns |
|---|---|
GET /v1/catalog | Your org, its business units and its teams, with the ids you use in the annotations. |
GET /v1/entity/:scope/:id | Every signal for one entity in a single response. This is what the card reads. |
GET /v1/summary/:scope/:id | One compact headline for the scope, with provenance and a deep link. |
GET /v1/eng-maturity/:scope/:id | Engineering maturity level, with its breakdown. |
GET /v1/code-maturity/:scope/:id | Code maturity score and sub-scores from the zero-config Diagnosis. |
GET /v1/durability/:scope/:id | AI durability: survival rate, human baseline and the rework it implies. |
GET /v1/radar/:scope/:id | Technology landscape, counted by ring. |
GET /v1/entities | Every org, business unit and team with all of its signals, in one array. Built for bulk sync. |
scope is one of org, bu or team, and id is the uuid from the catalog. A key only reads inside its own organization: an id from another tenant answers 403, an id that does not exist answers 404, and any other scope value answers 400.
Response shape
Every endpoint answers with the same envelope: the subject, when it was measured, and one entry per signal carrying the value, its unit, a status, its provenance and a deep link back into ScaleQuality.
{
"subject": { "type": "team", "id": "...", "name": "Payments" },
"measuredAt": "2026-08-14T09:12:44.108Z",
"signals": {
"durability": { "value": 89, "unit": "%", "status": "ok",
"provenance": "MEASURED", "data": { ... }, "deepLinkUrl": "..." },
"engMaturity": { "value": 3, "unit": "level", "status": "warn",
"provenance": "MEASURED", "data": { ... }, "deepLinkUrl": "..." },
"codeMaturity": { "value": 74, "unit": "score", "status": "warn",
"provenance": "MEASURED", "data": { ... }, "deepLinkUrl": "..." },
"techRadar": { "value": 42, "unit": "count", "status": "ok",
"provenance": "DECLARED", "data": { ... }, "deepLinkUrl": "..." }
}
}status is one of ok, warn, risk or unknown. provenance is part of the contract, not decoration: MEASURED means the number came out of your environment, DECLARED means somebody configured it. A null value means it has not been measured yet, and the card renders a dash for it.
Troubleshooting
Almost every failed install lands on one of these.
| What you see | What it means | Fix |
|---|---|---|
| The card shows a missing-annotation empty state | The entity carries none of the three ScaleQuality annotations. | Add scalequality.io/team-id, scalequality.io/bu-id or scalequality.io/org-id to the entity and reload the catalog. |
| 401 from the proxy | The key was revoked or rotated, or SCALEQUALITY_API_KEY is not set in the backend environment. | Confirm the variable exists in the backend that serves the proxy, and that the key is still active under Developers. |
| 403 for an id that exists | That id belongs to a different organization than the key does. | Take the ids from the catalog endpoint called with this key, not from another tenant. |
| Every tile renders a dash | The scope resolves, but nothing has been measured for it yet. | Run a diagnosis, complete an assessment, or connect an AI provider for that scope. The card fills in as measurements land. |
| The request never leaves Backstage | The proxy id does not match. The plugin calls the endpoint registered as scalequality. | Keep the key in app-config exactly as it appears in step 3, slash scalequality. |