The E10 developer portal for the kaddy platform — a Backstage app that turns kaddy's Crossplane self-service capability into a self-service experience.
Design intent: the portal is a projection of the platform API, not a copy of it. The scaffolder form is auto-generated from the kaddy
WebsiteXRD; the portal authors Git (opens a PR) and never mutates the cluster. See kaddyopenspec/changes/e10-portal-stretch/and ADRs 0107, 0109, 0111.
This repo holds the Backstage app source (it builds the container image).
The GitOps deployment wiring (Deployment, read-only RBAC, NetworkPolicy,
Dex client Secret, ArgoCD Application) lives in the kaddy repo under
deploy/portal/ — that is a follow-up, not in this repo.
| Path | How | Mutates? |
|---|---|---|
| Write (self-service) | kubernetes-ingestor (TeraSky) auto-generates a scaffolder template per Website XRD from its OpenAPI schema; the template's publishPhase opens a PR against PlatformRelay/Kaddy → deploy/workloads/ |
No — Git PR only |
| Read (visibility) | crossplane-resources (TeraSky) graph, Backstage kubernetes, and ArgoCD (community) plugins render live status on the entity page |
No — read-only |
| Auth | auth.providers.oidc → Dex (ADR-0107); Dex fronts a GitHub connector. Issuer in the kind lab: https://dex.kaddy.local:30443 |
— |
The write path touches only Git; the read path holds read-only credentials
(a get/list/watch-only ServiceAccount + a read-only ArgoCD account) and never
mutates. These two paths are kept strictly distinct (decision D-029).
All environment-specific and secret values are ${ENV} placeholders — no
secrets are committed. Key blocks in app-config.yaml (dev) /
app-config.production.yaml (cluster):
auth.providers.oidc— Dex OIDC (AUTH_OIDC_METADATA_URL,AUTH_OIDC_CLIENT_ID,AUTH_OIDC_CLIENT_SECRET). The guest provider module is loaded only whenNODE_ENV !== production(gated inpackages/backend/src/index.ts), so in the cluster only Dex OIDC remains and every protected route redirects to Dex (REQ-E10-S01-02). Backstage config deep-merges and cannot delete a config key, so the module gate — notapp-config— is the real lever.kubernetes— read-only cluster access (KUBERNETES_URL,KUBERNETES_SA_TOKEN,KUBERNETES_CA_DATA) surfacingWebsite/HTTPRoute/CertificateGVKs.argocd+proxy./argocd/api— read-only ArgoCD account (ARGOCD_URL,ARGOCD_AUTH_TOKEN).crossplane— the read-path resource-graph plugin.kubernetesIngestor— the write path.publishPhasetargets a GitHub PR againstgithub.com?owner=PlatformRelay&repo=Kaddy,targetBranch: main,allowRepoSelection: false. The per-XRD target path (deploy/workloads/{namespace}/website/) is set via annotations on theWebsiteXRD itself in the kaddy repo, not here.catalog— staticcatalog/kaddy-platform.yamlfor the 4 platform Components (clubhouse,marshal,mulligan,scorecard); liveWebsiteXRs are ingested automatically (ingestAllClaims).
| Plugin | Version | Role | kaddy use |
|---|---|---|---|
@terasky/backstage-plugin-kubernetes-ingestor |
4.0.0 | backend | write-path template-gen + XR ingestion |
@terasky/backstage-plugin-scaffolder-backend-module-terasky-utils |
2.9.0 | backend module | scaffolder actions for generated templates |
@terasky/backstage-plugin-crossplane-resources-frontend |
2.19.1 | frontend | XR → managed-resource graph |
@terasky/backstage-plugin-crossplane-resources-backend |
1.18.0 | backend | serves the graph (read-only) |
@terasky/backstage-plugin-crossplane-permissions-backend |
1.1.18 | backend | permission integration for the graph |
@backstage-community/plugin-argocd |
2.9.0 | frontend | ArgoCD sync/health card |
@backstage/plugin-kubernetes(-backend) |
0.12.x / 0.21.x | both | workload health (ships with create-app) |
@backstage/plugin-auth-backend-module-oidc-provider |
0.4.x | backend | Dex OIDC provider |
Third-party OSS plugins are pinned (exact versions) and should be Renovate-tracked and enumerated in the kaddy E11 audit (ADR-0111).
Uses Yarn 4 (bundled at .yarn/releases/, pinned via packageManager — no
corepack needed):
yarn install
yarn start # dev (guest login enabled)
yarn tsc # typecheck
yarn build:backend # backend bundle → containerThe container image is built from packages/backend/Dockerfile (standard
Backstage host build).
This is an honest foundation, not a running portal. A fully-running portal with real OIDC + live plugin data is an explicit follow-up.
Working now
- Backstage app scaffolds and typechecks clean (
yarn tsc→ exit 0) with all kaddy plugins added and pinned. - Full, non-broken
app-configfor Dex OIDC, kubernetes (read-only), crossplane, argocd, and thekubernetesIngestorPR write path — all values via env placeholders, no secrets committed. - Backend wires the OIDC provider, kubernetes-ingestor (template-gen + XR ingestion), crossplane-resources + permissions backends, and the terasky scaffolder-utils module.
- Frontend wires the crossplane-resources graph plugin (new frontend system).
- Static catalog for the 4 platform Components. Guest sign-in is gated to
non-production (
NODE_ENV), so a deployed portal is OIDC-only.
TODO / follow-up (deferred)
- ArgoCD frontend card is not wired:
@backstage-community/plugin-argocd@2.9.0's/alphaentrypoint exports only translations (no new-frontend-system feature), so it needs a legacy-compat wrapper. Config (argocd+ proxy) is already present. Tracked as aTODOinpackages/app/src/App.tsx. - Backend does not run under Node 26: the native module
isolated-vm@6.1.2(used by the scaffolder for sandboxed template evaluation) fails to compile against Node 26's V8 API. Run the backend on Node ≤ 22 (or a patchedisolated-vm). This is an environment caveat, not a config error — install and typecheck both succeed. - Real OIDC / live plugin data requires the kaddy-side wiring: a Backstage
static client in Dex (
deploy/identity/dex), the read-only ServiceAccount + ArgoCD account, and thedeploy/portal/GitOps Application. None of that is in this repo (and the kaddy repo must not be edited from here). - Website XRD annotations (
terasky.backstage.io/target-path,create-kustomization-file) that steer the generated PR path live on the XRD in the kaddy repo — documented as comments here, applied there. - Chainsaw/meta tests for the portal (
tests/portal/*,tests/chainsaw/portal/*in the E10 spec) are kaddy-repo concerns and out of scope for this app repo.