# Preview URL routing for vibn-dev

Goal: every `dev_server.start` returns a URL like
`https://vite-mark-marketplace-7a3f.preview.vibnai.com` that works
end-to-end (TLS, HMR, websockets) without the user touching DNS or
Coolify config.

## Architecture

```
  Browser
    │  https://<sub>.preview.vibnai.com
    ▼
  Traefik (Coolify-managed)
    │  routes by Host header → matching docker label
    ▼
  vibn-dev container for project X
    │  HOST=0.0.0.0 PORT=3000
    ▼
  Vite / Next dev / etc.
```

Two pieces have to be true for this to work:

1. **DNS wildcard** — `*.preview.vibnai.com` must resolve to the
   Coolify host's public IP. Set this in Cloudflare / OpenSRS once.
2. **Traefik dynamic router** — for each running dev_server, attach
   docker labels to the vibn-dev container so Traefik picks up the
   subdomain → port mapping.

## DNS step (one-time)

In OpenSRS (or whichever DNS we use for vibnai.com):

```
*.preview.vibnai.com.  IN A  <coolify-host-ip>
```

Cert: Traefik will solve a wildcard via DNS-01 against the same DNS
provider. Add a DNS provider env to Coolify's Traefik:

```yaml
# already in our Coolify Traefik config
- "--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
- "--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=opensrs"
```

(Traefik supports OpenSRS via `OPENSRS_USERNAME` + `OPENSRS_PASSWORD`
env vars.)

## Traefik labels (per dev_server)

When a dev_server starts on port `P` with subdomain `S`, we update
the vibn-dev compose file with these labels and re-deploy the service:

```yaml
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.vibn-dev-${S}.rule=Host(`${S}.preview.vibnai.com`)"
  - "traefik.http.routers.vibn-dev-${S}.entrypoints=https"
  - "traefik.http.routers.vibn-dev-${S}.tls=true"
  - "traefik.http.routers.vibn-dev-${S}.tls.certresolver=letsencrypt"
  - "traefik.http.services.vibn-dev-${S}.loadbalancer.server.port=${P}"
```

## What's deferred

The current `dev_server.start` records the URL and PID but does NOT
yet update the Coolify compose to add the Traefik labels — that
requires an `updateService` call against Coolify's API with the
revised compose YAML, which round-trips through Coolify's deployment
pipeline (~30s). For week 1 we keep dev servers reachable from inside
the container (`shell.exec curl http://localhost:PORT`) so the AI can
verify they boot, and we'll wire the Traefik label injection in week 2
once we've decided whether to:

(a) bake the labels into the compose at `ensureDevContainer` time
    (one Traefik router per fixed port range, e.g. 3000-3010), OR
(b) hot-update the compose on each `dev_server.start` (more flexible
    but slower and racier).

Recommendation: (a) — pre-allocate router rules for ports 3000-3010
on container creation. Simpler, faster, no compose churn. Limit dev
servers per project to 10.

## Troubleshooting

- "Host header mismatch" → check the dev server is actually binding
  to 0.0.0.0 (not localhost). Some frameworks default to localhost
  even with `HOST=0.0.0.0` env; pass `--host 0.0.0.0` to the cli.
- HMR websocket fails → Vite needs `server.hmr.clientPort: 443` and
  `server.hmr.host: <subdomain>.preview.vibnai.com`. Document this in
  the AI system prompt for week 2.
- 404 from Traefik → labels didn't apply. Check `docker inspect
  vibn-dev-<projectSlug>` and verify the labels are present.
