> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anyshift.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Backstage setup

> Install and configure read-only Anyshift production context in Backstage.

The Anyshift Backstage integration adds live infrastructure context to the software catalog you already use. It connects one Anyshift project to:

* A global Anyshift dashboard at `/anyshift`
* An **Anyshift** tab on matching catalog entities
* Optional infrastructure Resources and evidence-backed relations in the catalog

Your Anyshift project ID and API token stay in the Backstage backend. The browser sends authenticated requests only to Backstage and never receives the Anyshift token.

<Warning>
  The integration is currently in beta and is published under the `next` npm
  tag. It supports Backstage's new frontend and backend systems. There is no
  legacy frontend entry point.
</Warning>

## Before You Start

You need:

* A Backstage application using the new frontend system
* Backstage 1.52 or 1.53
* One Anyshift project with graph data
* An API token that can read that project
* A Backstage permission policy

## Install the Core Integration

Install the frontend plugin in your app workspace and the backend plugin in your backend workspace:

```bash theme={null}
yarn workspace app add @anyshift/backstage-plugin-anyshift@next
yarn workspace backend add @anyshift/backstage-plugin-anyshift-backend@next
```

Register the backend plugin in `packages/backend/src/index.ts`:

```ts theme={null}
backend.add(import("@anyshift/backstage-plugin-anyshift-backend"));
```

The frontend package is discoverable. Enable package discovery in your Backstage configuration:

```yaml theme={null}
app:
  packages: all
```

You do not need to edit `App.tsx` or `EntityPage.tsx`. Backstage discovers the global page, navigation item, API factory, and entity content from the installed package.

## Configure Anyshift

Add one Anyshift project to your Backstage configuration:

```yaml theme={null}
anyshift:
  baseUrl: https://graph.anyshift.io
  projectId: ${ANYSHIFT_PROJECT_ID}
  token: ${ANYSHIFT_TOKEN}
  timeout: 60s
  cache:
    ttl: 60s
  query:
    enabled: false
  catalog:
    mode: disabled
```

Set `ANYSHIFT_PROJECT_ID` and `ANYSHIFT_TOKEN` in the environment used by your Backstage backend. Do not put the token in frontend configuration or commit it to your repository.

The query console is disabled by default. Leave it disabled unless users need to run deterministic, read-only Graph queries from Backstage.

## Configure Permissions

The backend enforces three permissions:

| Permission              | Grants                                                                       |
| ----------------------- | ---------------------------------------------------------------------------- |
| `anyshift.view`         | Read the dashboard and entity-specific infrastructure context                |
| `anyshift.query`        | Run deterministic, read-only Graph queries when the query console is enabled |
| `anyshift.catalog.sync` | Start an immediate catalog reconciliation                                    |

Install the common package directly in the backend workspace if your permission policy imports these constants:

```bash theme={null}
yarn workspace backend add @anyshift/backstage-plugin-anyshift-common@next
```

Import the permissions into your existing Backstage policy:

```ts theme={null}
import { AuthorizeResult } from "@backstage/plugin-permission-common";
import {
  anyshiftCatalogSyncPermission,
  anyshiftQueryPermission,
  anyshiftViewPermission,
} from "@anyshift/backstage-plugin-anyshift-common";
```

For a read-only rollout, grant `anyshift.view` to the intended users and deny `anyshift.query` and `anyshift.catalog.sync`. A typical policy decision inside `handle()` looks like this:

```ts theme={null}
if (request.permission.name === anyshiftViewPermission.name) {
  return {
    result: user ? AuthorizeResult.ALLOW : AuthorizeResult.DENY,
  };
}

if (request.permission.name === anyshiftQueryPermission.name) {
  return { result: AuthorizeResult.DENY };
}

if (request.permission.name === anyshiftCatalogSyncPermission.name) {
  const isOperator = user?.info.ownershipEntityRefs.includes(
    "group:default/platform-operators",
  );
  return {
    result: isOperator ? AuthorizeResult.ALLOW : AuthorizeResult.DENY,
  };
}
```

Replace `group:default/platform-operators` with the group that operates your catalog. The frontend hides actions a user cannot perform, but the backend permission checks remain authoritative.

<Note>
  An allow-all Backstage policy grants all three permissions to every signed-in
  user. Replace it with an explicit production policy before enabling the query
  console or manual reconciliation.
</Note>

## Match Catalog Entities

The Anyshift tab appears on entities with either of these annotations:

* `anyshift.io/target`
* `github.com/project-slug`

When `anyshift.io/target` is absent, the plugin uses the repository name from `github.com/project-slug` as the runtime target. Add an explicit target when the repository and deployed workload use different names:

```yaml theme={null}
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: checkout
  annotations:
    github.com/project-slug: example-org/checkout
    anyshift.io/target: checkout-api
spec:
  type: service
  lifecycle: production
  owner: group:default/checkout-team
```

After the entity is ingested, open it in the catalog and select the **Anyshift** tab.

## Synchronize Infrastructure Resources

Catalog synchronization is optional. Use it when you want infrastructure Resources and runtime relations next to the Components already owned by GitHub.

Install the catalog module:

```bash theme={null}
yarn workspace backend add @anyshift/backstage-plugin-catalog-backend-module-anyshift@next
```

Register it in `packages/backend/src/index.ts`:

```ts theme={null}
backend.add(
  import("@anyshift/backstage-plugin-catalog-backend-module-anyshift"),
);
```

### Start in Shadow Mode

Shadow mode reads the graph and reports proposed matches, collisions, and Resources without writing them to the catalog:

```yaml theme={null}
anyshift:
  baseUrl: https://graph.anyshift.io
  projectId: ${ANYSHIFT_PROJECT_ID}
  token: ${ANYSHIFT_TOKEN}
  catalog:
    mode: shadow
    fallbackOwner: group:default/anyshift-unowned
    relationshipConcurrency: 25
    inventoryTypes: [deployment, statefulset, configmap]
    workloadTypes: [deployment]
    resourceNamePatterns: []
    schedule:
      frequency: 30m
      timeout: 5m
```

Review the `Anyshift catalog sync report` entries in your Backstage logs. Confirm that component targets, owners, proposed Resources, and collisions are correct before enabling writes.

Set `fallbackOwner` to a Group that exists in your catalog. The example uses a dedicated holding group for infrastructure that does not yet have an evidence-backed owner.

### Enable Active Mode Gradually

Switch to active mode with a reviewed target allowlist:

```yaml theme={null}
anyshift:
  baseUrl: https://graph.anyshift.io
  projectId: ${ANYSHIFT_PROJECT_ID}
  token: ${ANYSHIFT_TOKEN}
  catalog:
    mode: active
    fallbackOwner: group:default/anyshift-unowned
    inventoryTypes: [deployment, statefulset, configmap]
    workloadTypes: [deployment]
    activeTargets: [checkout-api, payments-api]
    schedule:
      frequency: 30m
      timeout: 5m
```

`activeTargets` limits Component enrichment to the listed runtime targets. Omit it only when every matched Component should be eligible. If you configure it, the list must contain at least one target.

Mark an individual Component as intentionally unmanaged when it should never be synchronized:

```yaml theme={null}
metadata:
  annotations:
    anyshift.io/catalog-sync: excluded
```

### Cloud Resource Types

The default inventory types are Kubernetes-oriented. For an AWS-backed project, select the resource labels you want to publish:

```yaml theme={null}
anyshift:
  catalog:
    mode: shadow
    inventoryTypes:
      - ECS_SERVICE
      - ECS_CLUSTER
      - LAMBDA_FUNCTION
      - RDS_DB
      - DYNAMODB_TABLE
      - S3_BUCKET
      - SQS_QUEUE
      - SNS_TOPIC
      - ECR_REPOSITORY
      - ELASTICLOADBALANCING_LOADBALANCER
    workloadTypes: [ECS_SERVICE, LAMBDA_FUNCTION]
```

Use `resourceNamePatterns` to limit the imported inventory further with case-insensitive regular expressions.

## Ownership and Failure Behavior

GitHub remains authoritative for Components, Users, Groups, owners, lifecycle, and repository metadata. The Anyshift module:

* Creates infrastructure Resources
* Adds relations supported by graph evidence
* Enriches matched Components without recreating them
* Preserves the previous complete Resource set when a synchronization attempt fails

Generated Resources carry the `anyshift.io/managed-by: catalog-provider` annotation. In active mode, the module also maintains `resource:default/anyshift-catalog-sync`, which records the result, trigger, completion time, and a bounded failure reason for the latest attempt.

Users with `anyshift.catalog.sync` can select **Reconcile now** on the global Anyshift page. Scheduled and manual requests that overlap are combined into one provider run.

## Verify the Installation

1. Start the Backstage backend with the Anyshift environment variables set.
2. Sign in as a user with `anyshift.view`.
3. Open `/anyshift` and confirm the global dashboard loads.
4. Open a Component with `anyshift.io/target` or `github.com/project-slug`.
5. Select the **Anyshift** tab and confirm the runtime target resolves.
6. If catalog synchronization is enabled, review the sync report and the `anyshift-catalog-sync` Resource before moving from `shadow` to `active`.

## Troubleshooting

<AccordionGroup>
  <Accordion title="The Anyshift page does not appear">
    Confirm that the frontend package is installed in the app workspace, the
    app uses Backstage's new frontend system, and `app.packages` is set to
    `all`. Restart the frontend after changing dependencies or configuration.
  </Accordion>

  <Accordion title="The entity does not have an Anyshift tab">
    Add `anyshift.io/target` or `github.com/project-slug` to the entity
    annotations. Use `anyshift.io/target` when the repository name does not match
    the runtime workload.
  </Accordion>

  <Accordion title="A request returns 403 Forbidden">
    Check your Backstage permission policy. Dashboard and entity data require
    `anyshift.view`, queries require `anyshift.query`, and manual reconciliation
    requires `anyshift.catalog.sync`.
  </Accordion>

  <Accordion title="The catalog contains no Anyshift Resources">
    Confirm that the catalog module is installed and registered. `disabled`
    creates nothing, while `shadow` reports proposed changes without applying
    them. In `active`, verify that `inventoryTypes`, `activeTargets`, and
    `resourceNamePatterns` include the intended resources.
  </Accordion>

  <Accordion title="A synchronization attempt fails">
    Find the latest `Anyshift catalog sync report` in the backend logs and
    inspect `resource:default/anyshift-catalog-sync`. A failed attempt leaves
    the last complete infrastructure Resource set in place.
  </Accordion>
</AccordionGroup>

## Packages

The beta packages are available from npm:

* [`@anyshift/backstage-plugin-anyshift`](https://www.npmjs.com/package/@anyshift/backstage-plugin-anyshift)
* [`@anyshift/backstage-plugin-anyshift-backend`](https://www.npmjs.com/package/@anyshift/backstage-plugin-anyshift-backend)
* [`@anyshift/backstage-plugin-anyshift-common`](https://www.npmjs.com/package/@anyshift/backstage-plugin-anyshift-common)
* [`@anyshift/backstage-plugin-catalog-backend-module-anyshift`](https://www.npmjs.com/package/@anyshift/backstage-plugin-catalog-backend-module-anyshift)

For direct TypeScript access to the same infrastructure graph, see the [Graph SDK guide](/pages/product/integration/sdk).
