- Health checks for local services dialed 127.0.0.1 from inside the backend
container — the host's published port is unreachable there. Service-bound
checks now resolve the service's DNS name on its project network (backend
joins on demand), falling back to the service's stored port. A resolver
failure surfaces as TARGET_UNRESOLVED instead of a fake loopback probe.
- Checks lived only in memory: a backend restart silently deleted every
configured health check. ha_health_checks table + write-through on
add/update/tick and hydrate-on-boot, matching the scaling-policy pattern.
- sqlc schema.sql gained the runtime columns added by later migrations —
the stale snapshot already caused one silently-dropped-column bug.
- OpenAPI: runtime response now documents ports and health fields; types
regenerated.
- Buttons no longer wrap ("+ new project" rendered on two lines).
Verified live: service check probes whoami-web:80 via DNS → healthy;
check survives a backend restart and rehydrates.
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: e2e QA hardening — honest runtime URLs, health, and read-only anon UI
Backend:
- managed DB provisioning: attach DB containers to the platform network and
probe the container IP, fixing the 127.0.0.1 reachability failure inside
the backend container; log provisioning failures
- stop fabricating connection URLs when provisioning produced none
- template deploys now carry port + health_check into service runtime fields
- service health probed over the project network (backend joins it) instead
of an in-container wget that fails on shell-less images
- runtime/public/connection URLs rewrite loopback to the request Host so
links are usable for LAN/remote clients
Frontend:
- service Networking panel shows real runtime URLs/ports/health instead of
hardcoded containr.dev + 8080->443
- anonymous views hide all mutation controls (new project, add service,
group, context menu)
- project cards: remove decorative svcN labels; badge says DOWN only when
zero services run, IDLE when empty, DEGRADED for partial
- mobile projects header no longer clips (fluid search width)
- unknown routes render a not-found page instead of silently redirecting
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: telemetry scope label, chunk split, remove stale vite artifacts
- /system/host now reports scope=host|docker-desktop-vm and the daemon OS;
Projects dashboard labels cards VM.* when the daemon is a Desktop VM so
memory/core numbers aren't mistaken for physical host values
- manualChunks: split @xyflow/react and recharts out of the main bundle;
removes the >1MB chunk warning
- drop tracked vite.config.js/.d.ts build artifacts that shadowed the real
vite.config.ts
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
* fix: persist service host port; demo-data scope for telemetry
Public URLs were ephemeral: every restart/redeploy rebound a random host
port, so endpoint links rotted. Persist published_port on the service and
prefer it for replica 0 on create. If the port is taken, fall back to
ephemeral and repersist the new assignment. Post-start the binding is
verified — Docker Desktop accepts a conflicting publish silently, which
previously left services running with no endpoint at all.
demo-data.ts gains the required scope field for HostMonitoring (CI fix).
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
---------
Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Backend:
- tolerate concurrent project-network creation (re-resolve on conflict)
- always publish an ephemeral host port when a port is configured, even
with a domain set — Traefik routes on top when the edge network exists
- public_url now prefers the configured domain, falls back to the first
published port
- service logs resolve replicas by containr.service label and merge all
replica streams — previously queried a nonexistent containr-<id> name
Canvas/detail:
- degraded status renders amber end-to-end (node card, detail badge,
status dot) instead of falling through to "Stopped"
- edges pick handle sides by relative node position — no more backward
loops when the source sits right of the target
- context menu gains Start for stopped services, Visit uses the
published URL when no domain is set, menu clamps to canvas bounds
- node cards show the image tag instead of a redundant hint
- scaling tab falls back to live runtime replica counts when no
autoscaler state exists; manual scale no longer requires it
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Services now reconcile into actual Docker containers instead of
bookkeeping rows:
- Per-project bridge network with service-name DNS aliases and
${{service.KEY}} env expansion (HOST/PORT builtins)
- Replicas, published ports, Traefik domain routing, health checks,
restart policies persisted on the service spec; spec-hash drift
recreates containers on redeploy
- Lifecycle API: start/stop/restart/redeploy, live runtime state,
real image rollback (replaces the fake sleep)
- Manual scale and PUT replicas reconcile live containers; service
and project delete remove their containers and the project network
- Canvas: real URLs, replica badges, env filter, right-click
deploy/restart/stop/delete menu, empty state
- Service detail: real lifecycle buttons, live replica/URL strip,
Networking editor, ${{ }} variable helper
- Fix prebuilt-image pulls racing the tag (drain the pull stream)
Generated with [Devin](https://devin.ai)
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>