# Caddy reverse proxy for the Zopu VDS staging agent stack.
#
# This is the ONLY public ingress to the single agents Node process (see
# docs/DEPLOYMENT_PLAN.md §"Public surface"). It terminates TLS for
# agents.zopu.puter.wtf — the Flue callback hostname Convex reaches — then
# forwards ONLY the documented worker paths to the internal `agents` service at
# 127.0.0.1:3000.
#
# Hard rules this file enforces:
#   - No generic /api/* proxy and no browser-to-Flue traffic (DEPLOYMENT_PLAN.md
#     line 86). Browsers talk only to Convex.
#   - Only the paths the Convex backend actually calls are routed:
#       /health                            liveness probe
#       /internal/project-setup            single-call project setup coordinator
#       /internal/agents/<agentId>/events  agent event dispatch callback
#   - The AgentOS registry runs in-process as a native envoy (Rivet Mode A),
#     so there is no /internal/rivet/* route to expose. Exposing a private
#     worker protocol publicly would widen the attack surface needlessly.
#   - Former routes (/agents/zopu/*, /internal/work-attempts/*, /workflows/*,
#     /api/rivet/*) are intentionally absent: they are stale and not part of the
#     current Convex→agents contract.
#   - Everything else returns 404. The private worker protocol stays narrow.
#
# TLS certs persist in Caddy's data directory. Caddy serves its own ACME
# HTTP-01 challenge responses on :80 automatically, so the :80 block only
# redirects everything else to HTTPS — worker traffic is never served over
# plain HTTP.
#
# Install/update: see the "Caddy" section of deploy/vds/README.md. In short,
# copy this file to /etc/caddy/Caddyfile, then:
#   sudo caddy validate --config /etc/caddy/Caddyfile
#   sudo systemctl reload caddy

agents.zopu.puter.wtf {
	encode zstd gzip

	# Explicit route block pins directive order: path-matched proxies run
	# first, then the terminal 404 fallback. No directive is left to the
	# default sort.
	route {
		# Liveness probe (CI healthcheck). Routed to the real worker so a failed
		# process is not masked by a synthetic success.
		reverse_proxy /health 127.0.0.1:3000

		# Single-call project setup coordinator. Requires the internalRoute bearer.
		reverse_proxy /internal/project-setup 127.0.0.1:3000

		# Agent event dispatch callback. Requires the internalRoute bearer.
		reverse_proxy /internal/agents/* 127.0.0.1:3000

		# Everything else is not part of the private worker protocol.
		respond 404
	}
}

# HTTP → HTTPS redirect (Caddy still answers ACME challenges on :80).
:80 {
	redir https://{host}{uri} permanent
}
