Validation: feat: dev environment — ephemeral DB, shared Keycloak, dev URL, migration practices, port convention

validation-86-2026-07-18 Doc

validation pass

Verdict: PASS

Ticket

ldraney/intelligentstaffingsystems#86 — Dev environment setup: shared Keycloak auth config, ephemeral DB via make reset, dev URL hostname allowlisting, migration practices documentation, and port convention (9999 dev / 3000 prod).
Merged PR: #94

Environment

Production cluster (k3s, archbox node), namespace intelligentstaffingsystems. URL: https://intelligentstaffingsystems.ai. ArgoCD-managed deployment.

Checks

# Criterion How Verified Result Evidence
1 CI pipeline green for merge commit Woodpecker pipeline #116 (push event, branch main) PASS Pipeline #116 status: success, message: "feat: dev environment — shared Keycloak, ephemeral DB, dev URL, migration docs (#94)"
2 Image tag propagated to running pod <code>kubectl get pods -n intelligentstaffingsystems -o jsonpath='{.items[*].spec.containers[*].image}'</code> PASS <code>harbor.tail5b443a.ts.net/intelligentstaffingsystems/app:dc97ba0a017aad90140d68fcd41267197433e716</code> — matches merge commit dc97ba0
3 Pod running and ready, 0 restarts <code>kubectl get pods -n intelligentstaffingsystems</code> PASS intelligentstaffingsystems-5ddd4556dd-nbbjd 1/1 Running 0 6h53m
4 Health endpoint returns 200 <code>curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/up</code> PASS HTTP 200
5 ArgoCD sync and health <code>kubectl get application -n argocd intelligentstaffingsystems</code> PASS sync.status: Synced, health.status: Healthy
6 Production root URL responds <code>curl -s -o /dev/null -w "%{http_code}" https://intelligentstaffingsystems.ai/</code> PASS HTTP 200
7 dev.intelligentstaffingsystems.ai in config.hosts (production.rb) File inspection: config/environments/production.rb line 88 PASS <code>config.hosts &lt;&lt; "dev.intelligentstaffingsystems.ai"</code> present
8 Port convention: dev on 9999, prod on 3000 docker-compose.yml port mapping + kubectl svc PASS docker-compose: ports 9999:9999; k8s svc: ClusterIP 3000/TCP
9 .env.development.example exists with Keycloak vars File inspection PASS File present with KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET placeholders
10 make reset target for ephemeral DB Makefile inspection PASS <code>reset: $(RUN) rails db:drop db:create db:migrate db:seed</code>

Tiers Executed

  • Tier 1 (Local): SKIPPED — Docker tests hang locally (known issue #65). CI pipeline #116 green serves as equivalent (runs full test suite in containerized CI).
  • Tier 3 (Production): PASS — Pod deployed with correct image, health endpoint healthy, ArgoCD synced and healthy.

Regression Check

Production app continues to serve at https://intelligentstaffingsystems.ai/ (200). No crash loops, 0 restarts on the pod. ArgoCD reports Healthy state. The only production code change was a single line adding dev.intelligentstaffingsystems.ai to the Rails allowed hosts list — no logic changes that could regress existing functionality.

Discovered Issues

dev.intelligentstaffingsystems.ai TLS handshake failure: DNS resolves correctly to 178.156.129.142 (Hetzner edge), but the TLS handshake fails with "tlsv1 alert internal error". The Caddy reverse proxy on the edge VPS does not have a certificate provisioned for this subdomain. HTTP returns 308 (redirect to HTTPS), confirming the vhost exists but lacks TLS. This is an infrastructure-level issue (Caddy cert config) outside the scope of this Rails ticket, which correctly added the hostname to config.hosts. Recommend creating a separate infra ticket for Caddy TLS provisioning on the dev subdomain.