SOP: Frontend Dev Overlay (k8s + Vite Hot Reload)

sop-frontend-dev-overlay Sop

sop active

SOP: Frontend Dev Overlay (k8s + Vite Hot Reload)

Purpose

Enable instant frontend iteration on phone by running a Vite dev server inside k8s alongside the production pod. Same Tailscale funnel pattern, same Keycloak auth — no new infra, no 3-minute image rebuild cycle.

When to Use

  • Porting a playground to SvelteKit (Stage 2 of sop-capacitor-mobile-lifecycle)
  • Iterating on frontend bugs that need phone verification
  • Any time the image-build-push-deploy cycle is too slow for the work

Pattern

Each frontend app gets two kustomize overlays in pal-e-deployments:
Dev and prod run side by side — different pod names, different Tailscale hostnames. They coexist in the same namespace.

Dev Overlay Anatomy

Four files, following the pattern established by mcd-tracker-app/dev/:
File Purpose
<code>kustomization.yaml</code> Resources list (deployment, service, ingress)
<code>deployment.yaml</code> node:22, hostPath volume to <code>~/project-app</code>, <code>npm run dev -- --host</code>, emptyDir for node_modules
<code>service.yaml</code> port 80 → targetPort (project's Vite port)
<code>ingress.yaml</code> Tailscale funnel with <code>tailscale.com/funnel: "true"</code> annotation

Key Design Decisions

  • node_modules on emptyDir — NOT hostPath. Prevents platform mismatch between host and container. Container runs npm install on startup into the emptyDir volume.
  • Own Tailscale hostname — dev gets {project}-dev.tail5b443a.ts.net. Never shares the prod hostname. Never uses the archbox hostname.
  • Same namespace as prod — both pods can reach the same cluster services (API, Keycloak, Postgres).
  • Memory limit 512Mi — Vite + npm install needs headroom beyond what a production nginx pod needs.
  • Readiness probe initialDelaySeconds 30 — npm install takes time on first run (node_modules emptyDir is fresh each pod restart).

Keycloak Considerations

The dev overlay gets its own Tailscale hostname, so the Keycloak client needs redirect URIs for both:
  • https://{project}.tail5b443a.ts.net/* (prod)
  • https://{project}-dev.tail5b443a.ts.net/* (dev)
  • capacitor://localhost/* (future mobile)
  • http://localhost/* (local dev without k8s)
For SPA apps using keycloak-js, the client must be public with PKCE enabled (no client secret).

Port Convention

From sop-capacitor-mobile-lifecycle:
Project Vite Port
mcd-tracker 5173
westside 5174
(next project) 5175

Workflow

  • Start dev mode: kubectl apply -k overlays/{app}/dev/
  • Edit locally: change .svelte files in ~/project-app/src/
  • Verify on phone: open {project}-dev.tail5b443a.ts.net — Vite hot reloads in <1s
  • Done iterating: push to git → CI builds image → ArgoCD syncs prod overlay
  • Tear down dev: kubectl delete -k overlays/{app}/dev/ (or leave running)

Validated By

  • mcd-tracker-app/dev/ — first implementation (2026-03-16)
  • westsidekingsandqueens/dev/ — second implementation (2026-03-17, pal-e-deployments #26)