Skip to content

Document New Frontend System installation in the Backstage Integration Admin Guide #35

Description

@EstoesMoises

Summary

The Backstage Integration Admin Guide documents frontend installation for the legacy Backstage frontend architecture only. Backstage's New Frontend System (NFS) is a different installation path, and customers on it currently have nothing to follow.

Support for NFS is being added in #34 via a new /alpha entry point. This issue tracks getting that into the official documentation. Until that happens, the instructions below are the interim reference — please link customers here.

The enhancement

Update the Admin Guide's frontend installation section to cover both architectures:

  • Add a "New Frontend System" installation path alongside the existing legacy one
  • Make it obvious up front which path a reader needs, and how to tell which system their app uses
  • Document the extensions the plugin contributes and how to configure or disable them via app.extensions
  • Call out that the NFS install needs no Root.tsx edits, unlike the legacy one
  • Note the stackoverflow.redirectUri / hub path relationship, since it is a common source of OAuth failures
  • Add the troubleshooting notes below

Interim guide: installing on the New Frontend System

Do I need this page?

If your app is built with createApp from @backstage/frontend-defaults and registers functionality through features and extensions, you are on the New Frontend System — follow this page.

If your app uses createApp from @backstage/app-defaults with a <FlatRoutes> element tree, you are on the legacy system — follow the existing Admin Guide instead. Nothing has changed for you.

Prerequisites

The backend setup is identical for both systems. Install and configure these first, per the existing Admin Guide:

  • @stackoverflow/backstage-plugin-stack-overflow-teams-backend
  • @stackoverflow/backstage-stack-overflow-teams-collator (for search indexing)
  • The stackoverflow section in app-config.yaml

1. Install the package

yarn --cwd packages/app add @stackoverflow/backstage-plugin-stack-overflow-teams

2. Add the feature

// packages/app/src/index.tsx
import { createApp } from '@backstage/frontend-defaults';
import stackOverflowTeamsPlugin from '@stackoverflow/backstage-plugin-stack-overflow-teams/alpha';

const app = createApp({
  features: [stackOverflowTeamsPlugin],
});

export default app.createRoot();

Note the /alpha import path — the default entry point is the legacy plugin and is not a FrontendFeature.

If your app discovers features automatically through app.packages config, no code change is needed at all; the package is picked up on its own.

That is the whole installation. Do not add sidebar items or route elements by hand — everything below comes from the plugin.

What you get

Extension ID What it does
page:stack-overflow-teams The Stack Internal hub, at /stack-overflow-teams
page:stack-overflow-teams/ask-question Trigger route for the ask-a-question modal
nav-item:stack-overflow-teams "Stack Internal" sidebar item
nav-item:stack-overflow-teams/ask-question "Ask a Question" sidebar item
api:stack-overflow-teams API client, talking to the backend plugin
search-result-list-item:stack-overflow-teams Renders indexed questions on the search page
search-filter-result-type:stack-overflow-teams Adds "Stack Internal" to the search result type filter
app-root-element:stack-overflow-teams/ask-question-modal Mounts the ask-a-question modal at the app root

All are enabled by default.

Configuration

Extensions are configured under app.extensions in app-config.yaml:

app:
  extensions:
    # Serve the hub from a different path
    - page:stack-overflow-teams:
        config:
          path: /stack-internal
    # Opt out of a sidebar item
    - nav-item:stack-overflow-teams/ask-question: false

Important

The hub path is also the OAuth redirect target. If you change it, update stackoverflow.redirectUri to match and update the redirect URI registered on your Stack Internal OAuth application. A mismatch between these three is the most common cause of a failed login.

Opening the ask-a-question modal from your own UI

The modal listens for a window event, so you can trigger it from anywhere:

<button onClick={() => window.dispatchEvent(new Event('openAskQuestionModal'))}>
  Ask a question
</button>

Worked example

packages/app-next in this repository is a complete, runnable app on the new frontend system with the plugin installed. Run it with yarn start:next.


Troubleshooting

"The plugin's route registration was never established"

This happens when the page component is rendered through a hand-written route:

// Don't do this — it bypasses route registration
<Route path="/stack-overflow-teams" element={<StackOverflowTeamsPage />} />

Add the plugin to features instead. It registers its own routes.

convertLegacyPlugin does not expose a routable extension

It is not needed. Import the native plugin from /alpha.

Where is the callback/authentication route?

There isn't a separate one. The hub page detects the ?code= query parameter returned by the OAuth flow and renders the callback handler itself. Mounting page:stack-overflow-teams is all that is required.

HTTP 500 after the authorization redirect

The response body is a fixed generic string; the actual cause is only in the backend logs, under Failed to exchange code for token. Check there first.

The usual cause is a redirect_uri mismatch. The token exchange re-sends redirect_uri, and Stack Internal compares it byte-for-byte against the authorize request. Verify all three agree:

  1. stackoverflow.redirectUri in app-config.yaml
  2. the redirect URI registered on the Stack Internal OAuth application
  3. the path the browser actually lands on

A different 500, clientId and redirectUri are required for authentication, means stackoverflow.clientId or stackoverflow.redirectUri is missing or failed environment variable substitution.

AuthenticationError: Missing credentials from the backend

The Backstage identity token is not being attached, which is an app-level auth problem rather than a plugin one. A stale @backstage/core:SignInPage:provider entry in localStorage with no live session will do it — clear site data and sign in again.


References

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions