npm package: @karimov-labs/backstage-plugin-devxp
Description: Backstage frontend plugin for developer intelligence — masked identity management, CSV upload, and unmask tooling.
Author: karimov-labs
Latest version: 1.3.1

# @karimov-labs/backstage-plugin-devxp

A Backstage frontend plugin that provides a **Developer Intelligence** dashboard for managing masked developer identities. It lets platform teams populate a real-name → masked-hash mapping database via CSV upload or automatic GitHub organization sync, and look up or verify masked identities — all without exposing real names to third-party analytics tools.

This plugin is the UI counterpart to [`@karimov-labs/backstage-plugin-devxp-backend`](https://www.npmjs.com/package/@karimov-labs/backstage-plugin-devxp-backend), which must be installed alongside it.

Built for use with the [DevXP](https://devxp.net) developer analytics platform.

---

## Features

- **Dashboard tab**
  - Configuration health indicators (salt, API token, endpoint, project ID)
  - Total mapping count
  - GitHub Auto-Sync Configurations table — shows all registered GitHub Apps with status and last-sync timestamp
  - Inline unmask tester — enter a 16-char hex hash, get the real name back instantly
  - Triggers automatic GitHub member sync on page load (throttled to once per 24 hours server-side)
- **Settings tab**
  - **GitHub Organization Auto-Sync** — register a GitHub App (github.com or GitHub Enterprise Server) to automatically pull all organization members and store their hashed identities
    - Collapsible setup guide with a pre-configured GitHub App creation link
    - Per-config activate/deactivate toggle and manual sync button
    - Full CRUD: register, activate, deactivate, delete
  - **CSV Upload** — upload a plain-text file with one real developer name per line to bulk-import mappings
  - **Mappings Table** — browse all stored pairs (masked hash → real name) with per-row delete
- Hashing algorithm matches [dev-xp-analyzer](https://github.com/karimov-labs/dev-xp-analyzer): `SHA-256(salt + realName)`, first 16 hex chars

---

## Requirements

| Dependency | Version |
|---|---|
| Backstage | >= 1.30 |
| `@karimov-labs/backstage-plugin-devxp-backend` | `^1.1.0` |
| React | `^18` |

---

## Installation

### 1. Install the packages

```bash
# yarn (Backstage default)
yarn workspace app add @karimov-labs/backstage-plugin-devxp
yarn workspace backend add @karimov-labs/backstage-plugin-devxp-backend

# npm
npm install @karimov-labs/backstage-plugin-devxp
npm install @karimov-labs/backstage-plugin-devxp-backend
```

---

### 2. Add the frontend plugin to your app

Edit `packages/app/src/App.tsx`:

```tsx
import devxpPlugin from '@karimov-labs/backstage-plugin-devxp';

export default createApp({
  features: [
    // ... other plugins
    devxpPlugin,
  ],
});
```

---

### 3. Add a sidebar navigation item

In your sidebar component (e.g. `packages/app/src/modules/nav/Sidebar.tsx`), add:

```tsx
import AssessmentIcon from '@material-ui/icons/Assessment';

// inside your sidebar menu group:
<SidebarItem icon={AssessmentIcon} to="/devxp" text="Dev Intelligence" />
```

---

### 4. Register the backend plugin

Edit `packages/backend/src/index.ts`:

```ts
backend.add(import('@karimov-labs/backstage-plugin-devxp-backend'));
```

---

### 5. Configure app-config.yaml

```yaml
devxp:
  # Salt used for SHA-256 hashing — must match the salt used in dev-xp-analyzer
  salt: ${DEVXP_SALT}

  # Whether developer names are masked in the analytics tool
  masked: true

  # dev-xp-analyzer API credentials (optional — only needed if calling the analyzer API)
  apiToken: ${DEVXP_API_TOKEN}
  apiEndpoint: ${DEVXP_API_ENDPOINT}
  projectId: ${DEVXP_PROJECT_ID}
```

Set the corresponding environment variables before starting Backstage:

```bash
export DEVXP_SALT="your-secret-salt"
export DEVXP_API_TOKEN="your-api-token"       # optional
export DEVXP_API_ENDPOINT="https://..."        # optional
export DEVXP_PROJECT_ID="your-project-id"     # optional
```

> **Security note:** The salt, API token, and GitHub App private keys are consumed exclusively by the backend and are never sent to the browser.

---

## Usage

Navigate to `/devxp` in your Backstage instance.

### Dashboard tab

| Section | Description |
|---|---|
| Configuration Status | Green/red indicators for salt, API token, endpoint, and project ID |
| Developer Mappings | Total count of stored masked ↔ real name pairs |
| GitHub Auto-Sync Configurations | Read-only list of all registered GitHub Apps — organization, hostname, client ID, active status, and last-sync time |
| Unmask Tester | Enter a 16-character hex masked name and press Enter (or click Unmask) to look up the real name |

The Dashboard also silently triggers a background auto-sync of all active GitHub configurations when the page is first loaded. The server throttles this to at most once every 24 hours per backend process.

### Settings tab

#### GitHub Organization Auto-Sync

Register one or more GitHub Apps to automatically pull your organization's member list and store hashed mappings.

| Section | Description |
|---|---|
| Setup guide | Collapsible step-by-step instructions with a pre-configured GitHub App creation link (permissions pre-filled) |
| Register GitHub App | Form to add a new sync configuration (see below) |
| Configuration table | Lists all registered apps; click the status chip to toggle active/inactive; use the sync icon to trigger an immediate sync; use the delete icon to remove |

**Registration form fields:**

| Field | Description |
|---|---|
| GitHub Org Name | The login name of your GitHub organization (e.g. `acme-corp`) |
| GitHub Hostname | `github.com` for GitHub.com, or your GitHub Enterprise Server hostname (e.g. `github.acme.com`) |
| App Client ID | Shown on the GitHub App's General settings tab (e.g. `Iv1.a1b2c3d4e5f67890`) |
| App Private Key (PEM) | Full contents of the `.pem` file downloaded from the GitHub App's Private keys section |

**Setting up a GitHub App (quick start):**

1. Click **"Click here to pre-configure and create your GitHub App"** in the setup guide — this opens GitHub with the app name and `Members: Read-only` permission pre-filled.
2. Scroll to *Organization permissions* and confirm **Members → Read-only** is checked.
3. After creating the app, copy the **Client ID** from the General tab.
4. Scroll to *Private keys* and click **Generate a private key**; paste the downloaded `.pem` contents into the form.
5. [Install the app](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app) in your GitHub organization.

#### CSV Upload

Upload a plain-text file with one real developer name per line. The plugin hashes each name with `SHA-256(salt + name)` and stores the mapping. A header row of `name` (case-insensitive) is automatically skipped.

#### Developer Mappings Table

Lists all stored hash → real-name pairs with per-row delete buttons. This table reflects both CSV-imported and GitHub-synced entries.

---

## API

The frontend communicates with the backend via the Backstage discovery API at `/api/devxp/`. See the [`@karimov-labs/backstage-plugin-devxp-backend` README](https://www.npmjs.com/package/@karimov-labs/backstage-plugin-devxp-backend) for full endpoint documentation.

---

## License

Apache-2.0