Admin Guide

You are a platform admin. You've already installed the operator (see the Operator Guide); now you're using the dashboard day-to-day. This guide walks through the tasks you'll actually do, grouped by "what are you trying to accomplish".

Tour

The dashboard has two sidebar groups (both admin-only):

  • Platform — the app-platform CRDs. App Registrations and Operator

Configs control onboarding; Platform Secrets controls the ghcr-credentials fanout.

  • Flux — read-only views into GitRepositories, Kustomizations,

ImageRepositories/Policies/Automations. Useful when an app deploy looks wrong and you need to see which resource is stuck.

Above that, the per-app sidebar (populated once you select an app) has Deployments, Secrets, and Namespaces — scoped to whichever app is selected.

Onboard a new app

  1. Pick a name. Use kebab-case, no prefixes — the operator adds

the apps. / -platform bits.

  1. Create an AppPlatformRegistration. Either:

- Dashboard: *Platform → App Registrations → Create*, or - Git: commit a YAML file under appplatformregistrations/<app>.yaml in the flux repo. Sample:

apiVersion: labrats.work/v1alpha1
kind: AppPlatformRegistration
metadata:
  name: my-app
spec:
  displayName: My App
  namespaces: [my-app-prod]
  access:
    - { group: myapp-ops, role: admin }
  1. Wait for Ready=True on the APR. The operator creates the

GitHub platform repo, generates an age keypair + deploy key, and scaffolds the repo contents. The APR surfaces the SSH URL and deploy-key ID on status. OIDC clients are registered separately via labeled Secrets in the <app>-platform namespace (see the Developer Guide).

  1. Hook the app repo up. In apps.<app>, push images with

semver tags (no v prefix) and let image-automation in <app>-platform pick them up. See Developer Guide.

Rotate a secret

The operator-managed secrets (deploy key, age key, OIDC client hash) rotate automatically on re-reconcile. For upstream-sourced secrets (anything fanned out by a ClusterExternalSecret or pulled from the ESO store), the flow is:

  1. Rotate the value in the upstream store (1Password, whatever

the ClusterSecretStore points to).

  1. Hit *Platform → Platform Secrets → app-platform-ghcr-credentials

→ Force Sync*. This stamps the force-sync annotation and ESO refetches immediately (skipping the 1h refreshInterval).

  1. Roll dependent workloads if they don't auto-reload (most do).

For per-app managed secrets committed to the platform repo as platform/*-secret.sops.yaml, edit the SOPS file with sops, commit, and Flux reapplies within 5 minutes.

Force a sync

Several situations need an immediate reconcile:

  • After a Flux dep untangle. Annotate a Kustomization:

kubectl annotate kustomization <name> -n flux-system reconcile.fluxcd.io/requestedAt="$(date -u +%FT%TZ)" --overwrite. For ExternalSecrets, use the Force Sync button in the dashboard.

  • After rotating an upstream secret — see above.
  • After fixing a broken platform repo — edit the APR (even a

no-op annotation change) to trigger operator reconcile.

An app is broken. What do I look at?

In order, cheapest diagnostic first:

  1. App URL — curl it. 200 / 3xx is fine; 503 means the pod

isn't Running; 401/403 means Authelia redirect.

  1. Deployments panel on the app's dashboard page — read

top-to-bottom. The first non-green node is the problem. Green GitRepository → Kustomization → Deployment → Pods means the app is healthy.

  1. /api/apps/<app>/pods — via dashboard or curl. Shows

container state + last exit reason.

  1. /api/apps/<app>/events — recent Warning events scoped

to the app's namespaces. Usually tells you FailedToRetrieveImagePullSecret, PolicyViolation, CreateContainerConfigError, etc.

  1. Operator logs (kubectl logs -n app-platform deploy/app-platform)

filtered by app name — catches reconcile-level failures the pod events don't see.

  1. Flux Kustomization status (*Flux* sidebar → Kustomizations)

health check failed messages name the resource blocking the apply.

For everything else, the disaster-recovery runbook has ten symptom→fix entries for incidents we've actually hit.

Delete an app

  1. Delete the APR (dashboard or

kubectl delete appplatformregistration <app>).

  1. The operator finalizer runs best-effort cleanup: removes the

Authelia OIDC client, deletes the GitHub platform repo + deploy key + GHCR packages, drops the platform namespace + RBAC.

  1. App namespaces are preserved — only RBAC is stripped. If you

want the data gone too, delete each <app>-<env> namespace manually.

What you can't do from the dashboard (yet)

  • Create new GitRepositories / ImageRepositories — these are

scaffolded by the operator, read-only in the UI.

  • Rotate the cluster-wide age key. Requires rekeying every

per-app SOPS file. Contact the operator maintainers.

  • Promote a dev app to prod. Create a new APR in the prod instance

and cut over — there's no in-place switch.