Deployment: westside-admin
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:<sha></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_appPostgres role with read+write grants only (no CREATE/ALTER/DROP). Limits blast radius if pod is compromised. Provisioned byforgejo_admin/pal-e-platform#302via 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 projectwestside-admin, image pathharbor.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 infeedback_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-levelsecurityContextperforgejo_admin/pal-e-deployments#141. Dockerfile usesUSER node(UID 1000) so the manifest assertion holds at runtime. System-wide PSA hardening tracked inforgejo_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 persop-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).
Related
arch-domain-westside-admin— sibling: what entitiesarch-dataflow-westside-admin— sibling: how data flowsarch-scoped-db-westside-admin— sub-component: tenant-scoping query layerproject-westside-admin— parent project pagesop-network-security— network policy rulesfeedback_harbor_project_naming— image registry convention (Harbor project = service key, NOT Forgejo owner)feedback_funnel_requires_auth— funnel safety rule