System scoring logo

Backstage System scoring Plugin

Created by Oriflame

System scoring gives you a clear way to track the health and maturity of your software. It looks at the things that matter in day to day work. Code quality. Test coverage. Operations readiness. Documentation. Security. The goal is not a perfect score. The goal is to show where to focus next and to make progress visible over time.

The System scoring Backstage plugin brings those scores into your portal. It works with any catalog entity. You get a score board to scan many entities at once. You get a table view that is easy to sort or filter. On each entity page you can open a detailed card. It shows the total score and the pieces that make it up. It explains why a rule passed or failed. It can point the team to a simple todo so action is clear.

Common use cases are production readiness checks and audit prep. Teams use it to keep standards in view during migrations. Leaders use it to spot risk across a large catalog. The data model is simple. Scores come from JSON that your pipeline or process updates on a schedule. The plugin reads that data and renders it in Backstage.

If you run a self hosted Backstage, this plugin turns your standards into a living view that teams will actually use.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the package

Copy
# from your Backstage root directory
yarn add --cwd packages/app @oriflame/backstage-plugin-score-card

Add the Score board page route

Edit packages/app/src/App.tsx

Copy
import React from 'react';
import { Route } from 'react-router-dom';
import { FlatRoutes } from '@backstage/core-app-api';
import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card';

export const AppRoutes = () => (
  <FlatRoutes>
    {/* your existing routes */}
    <Route path="/score-board" element={<ScoreBoardPage />} />
  </FlatRoutes>
);

Edit packages/app/src/components/Root/Root.tsx

Copy
import React, { PropsWithChildren } from 'react';
import { SidebarPage, Sidebar, SidebarGroup, SidebarItem, SidebarScrollWrapper } from '@backstage/core-components';
import MenuIcon from '@material-ui/icons/Menu';
import Score from '@material-ui/icons/Score';

export const Root = ({ children }: PropsWithChildren<{}>) => (
  <SidebarPage>
    <Sidebar>
      <SidebarGroup label="Menu" icon={<MenuIcon />}>
        <SidebarScrollWrapper>
          {/* your existing items */}
          <SidebarItem icon={Score} to="score-board" text="Score board" />
        </SidebarScrollWrapper>
      </SidebarGroup>
    </Sidebar>
    {children}
  </SidebarPage>
);

Add a Score tab on the Entity page

This shows a score view for the current entity.

Edit packages/app/src/components/catalog/EntityPage.tsx

Copy
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { EntityLayout } from '@backstage/plugin-catalog';
import { EntityScoreCardContent } from '@oriflame/backstage-plugin-score-card';

export const serviceEntityPage = (
  <EntityLayout>
    <EntityLayout.Route path="/" title="Overview">
      {/* your overview content */}
    </EntityLayout.Route>

    <EntityLayout.Route path="/score" title="Score">
      <Grid container spacing={3} alignItems="stretch">
        <Grid item xs={12}>
          <EntityScoreCardContent />
        </Grid>
      </Grid>
    </EntityLayout.Route>
  </EntityLayout>
);

Optional table view inside an entity

If you want a table of scores for child entities under a parent entity like a system

Copy
import React from 'react';
import Grid from '@material-ui/core/Grid';
import { EntityLayout } from '@backstage/plugin-catalog';
import { EntityScoreCardTable } from '@oriflame/backstage-plugin-score-card';

export const systemEntityPage = (
  <EntityLayout>
    <EntityLayout.Route path="/" title="Overview">
      {/* your overview content */}
    </EntityLayout.Route>

    <EntityLayout.Route path="/score" title="Score">
      <Grid container spacing={3} alignItems="stretch">
        <Grid item xs={12}>
          <EntityScoreCardTable />
        </Grid>
      </Grid>
    </EntityLayout.Route>
  </EntityLayout>
);

Configure where the plugin reads JSON data

You can set a single source for all entities or set it per entity with annotations.

App level config

Edit app-config.yaml

Copy
scorecards:
  jsonDataUrl: https://raw.githubusercontent.com/Oriflame/backstage-plugins/main/plugins/score-card/sample-data/

backend:
  csp:
    default-src: ["'self'", 'raw.githubusercontent.com']

Your data server must return the Access-Control-Allow-Origin header that allows your Backstage web origin.

Per entity config with annotations

Add this to your entity yaml

Copy
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: my-service
  annotations:
    github.com/project-slug: my-org/my-repo
    scorecard/jsonDataUrl: https://github.com/oriflame/backstage-plugins/blob/master/results.json
spec:
  type: service
  owner: my-team
  lifecycle: production

If you point to a private GitHub repo then set up GitHub auth in your Backstage app. The user token will be used to fetch the file.

Data files layout

The client loads JSON files from the url you set.

Per entity files follow this pattern

Copy
{jsonDataUrl}/{namespace}/{kind}/{name}.json

Example path

Copy
https://example.com/score-data/default/component/my-service.json

You can keep a file with all entities if you need it

Copy
{jsonDataUrl}/all.json

Optional config flags

Edit app-config.yaml to tune behavior

Copy
scorecards:
  # set true to load all entities first then filter them in memory
  fetchAllEntities: true

  # customize a link in the detail view using fields from the score entry
  wikiLinkTemplate: "https://company/wiki/{id}"

Changelog

This changelog is produced from commits made to the System scoring plugin since a year ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Features

  • Add display policy to hide or show owner and kind columns in the score cards table. #296 merged 8 months ago

Documentation

  • Update docs for the new display policy. #296 merged 8 months ago

Set up Backstage in minutes with Roadie