SOP: Frontend Dev Overlay (k8s + Vite Hot Reload)
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 installon 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
.sveltefiles 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)
Related
- SOP: Capacitor Mobile Lifecycle — the full pipeline (Stage 1–4)
- Phase 15: Production Port — first use for westside