Deployment: westside-admin

arch-deployment-westside-admin Architecture

architecture active

Deployment: westside-admin

Diagram

Components

Component arch: label Purpose Notes
Tailscale Funnel <code>arch:tailscale-funnel</code> Public hostname + TLS Annotation <code>tailscale.com/funnel: "true"</code>. Hostname <code>westside-admin.tail5b443a.ts.net</code>.
Ingress (tailscale) <code>arch:k8s-deploy</code> Routes traffic to service ingressClassName: tailscale. tls.hosts[0]: westside-admin.
Service <code>arch:k8s-deploy</code> ClusterIP for the pod Port 3000 → containerPort 3000.
Deployment <code>arch:k8s-deploy</code> SvelteKit adapter-node container Image: <code>harbor.tail5b443a.ts.net/westside-admin/app:&lt;sha&gt;</code> (Harbor project = service key per <code>feedback_harbor_project_naming</code>; NOT <code>forgejo_admin/...</code>). Single replica v1.
Postgres (basketball-api/postgres) <code>arch:postgres</code> Data source Cross-namespace via service DNS: postgres.basketball-api.svc.cluster.local:5432. Pod connects as dedicated <code>admin_app</code> user.
Keycloak <code>arch:keycloak</code> Identity provider Same realm/client used by westside-app + westside-contracts. New OIDC client <code>westside-admin</code>.
k8s Secret: westside-admin-secrets <code>arch:k8s-deploy</code> Holds DATABASE_URL, KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY SOPS-encrypted in pal-e-deployments.
Harbor registry <code>arch:harbor</code> Container image storage Project name = <code>westside-admin</code> (matches service key per <code>feedback_harbor_project_naming</code>). Provisioned by pal-e-services terraform onboarding (<code>forgejo_admin/pal-e-services#64</code>).
Woodpecker CI <code>arch:ci-pipeline</code> Build + push pipeline Builds on push to main, tags by commit sha, updates kustomize image tag.
ArgoCD <code>arch:k8s-deploy</code> Continuous deployment Watches pal-e-deployments, syncs westside-admin overlay.

Key Decisions

  • Public funnel chosen over tailnet-only. User accessibility (Lucas + Marcus from any device, no Tailscale install required for Marcus). Per feedback_funnel_requires_auth, this is permitted only because Keycloak admin role gate is airtight + documented.
  • Separate namespace. westside-admin gets its own ns rather than sharing basketball-api. Cleaner RBAC, cleaner network policy, cleaner ArgoCD app boundary.
  • Cross-namespace Postgres access. Pod connects to postgres.basketball-api.svc.cluster.local. Network policy explicitly allows this egress.
  • Separate DB user, not the basketball superuser. Pod uses a dedicated admin_app Postgres role with read+write grants only (no CREATE/ALTER/DROP). Limits blast radius if pod is compromised. Provisioned by forgejo_admin/pal-e-platform#302 via k8s Job.
  • SvelteKit adapter-node. Drizzle requires server runtime; adapter-static is incompatible. Container runs node build/index.js.
  • Image registry follows feedback_harbor_project_naming. Harbor project = service key = image repo prefix. westside-admin uses Harbor project westside-admin, image path harbor.tail5b443a.ts.net/westside-admin/app:<sha>. Owner namespace (forgejo_admin) is NOT part of the path. This convention came from the 36-hour outage cited in feedback_harbor_project_naming.
  • Service onboarding via pal-e-services terraform. Harbor project + CI robot account are provisioned declaratively by an entry in pal-e-services/terraform/k3s.tfvars (forgejo_admin/pal-e-services#64). NOT created out-of-band.
  • Single replica v1. No HPA. Admin tool has low concurrent users. Add HPA when more than one admin uses it simultaneously and load matters.
  • PSA-restricted namespace. Namespace labeled pod-security.kubernetes.io/enforce: restricted. Deployment overlay supplies pod-level + container-level securityContext per forgejo_admin/pal-e-deployments#141. Dockerfile uses USER node (UID 1000) so the manifest assertion holds at runtime. System-wide PSA hardening tracked in forgejo_admin/pal-e-deployments#140.
  • Hybrid Secret ownership (post-2026-05-03 convention). App-level Secrets (KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY, DATABASE_URL bundled into westside-admin-secrets) are SOPS-encrypted in pal-e-deployments and applied by ArgoCD via the CMP plugin. Harbor pull credentials (harbor-creds) are terraform-managed by pal-e-services per sop-harbor-creds-migration. Salt pillars handle pre-cluster secrets (Tailscale OAuth, Harbor admin, GPG keys). Three layers, three owners — different lifecycle for different concerns. Origin: forgejo_admin/pal-e-deployments#143 (first migration) and #144 (platform-wide rollout).
  • arch-domain-westside-admin — sibling: what entities
  • arch-dataflow-westside-admin — sibling: how data flows
  • arch-scoped-db-westside-admin — sub-component: tenant-scoping query layer
  • project-westside-admin — parent project page
  • sop-network-security — network policy rules
  • feedback_harbor_project_naming — image registry convention (Harbor project = service key, NOT Forgejo owner)
  • feedback_funnel_requires_auth — funnel safety rule