# API Contracts and Gateway Architecture

**Purpose:** Clarify how OpenAPI/contracts relate to the Caddy gateway and external clients (frontend, MCP, CLI), and how internal services communicate.

---

## Short answer

**No.** The OpenAPI and other contracts are **not** generated from the Caddy API. They are generated **from each backend** (Go and Python). Caddy does not expose an OpenAPI spec; it is a reverse proxy only.

- **External clients** can use a **single entrypoint** (Caddy on port 4000) when configured with `VITE_API_URL=http://localhost:4000` (frontend) or the equivalent gateway URL for MCP/CLI.
- **Contracts** used by those clients today are the **backend** contracts: `openapi/go-api.json` and `openapi/python-api.json`. Types and clients are generated from these two specs, not from a unified “gateway” spec.
- **Internal** cross-communication is **structured**: Go owns most of `/api/v1/*` and delegates to Python (AI, specs, execution, workflows, chaos) via `PythonServiceClient`; Python uses `GO_BACKEND_URL` for health and other calls. So there are clear sub-APIs by service, but there is **no single gateway contract** that documents the full external surface and routing in one place for audit.

---

## Configured behaviour (gateway-only, CORS, gRPC/buf)

- **External clients** use **only the gateway** (Caddy :4000): frontend `getBackendURL()` always returns `VITE_API_URL` (default `http://localhost:4000`); MCP/CLI use gateway URL.
- **CORS** is restricted to gateway + frontend origins (no wildcards): `CORS_ALLOWED_ORIGINS` (Go) and `CORS_ORIGINS` (Python). **Production:** set these to your real gateway and frontend origins only (no `*`).
- **Gateway contract:** `openapi/gateway-api.json` is generated by merging the backend spec **files** (`openapi/go-api.json` and `openapi/python-api.json`). Those files are produced from **source** (no running servers): run `bun run generate:openapi` then `bun run generate:openapi:gateway`, or `bun run generate:all`.
- **gRPC** (port 9091) is **internal-only** (not on Caddy). Proto codegen prefers **buf** (`buf generate`); fallback: `scripts/generate-grpc.sh`.

---

## Current architecture

### 1. Where contracts come from

| Source | Contract | Used by |
|--------|----------|--------|
| **Go backend** (swag) | `openapi/go-api.json` | Frontend (go-api.ts), CLI (go_api_client) |
| **Python backend** (FastAPI) | `openapi/python-api.json` | Frontend (python-api.ts), CLI (python_api_client) |
| **Caddy** | None | N/A – no OpenAPI generated from Caddy |

So the **only** contracts in use are the **backend** contracts (Go + Python). There is no “Caddy API” contract.

### 2. How external clients reach the system

| Client | Configuration | Contract |
|--------|---------------|----------|
| **Frontend** | `getBackendURL()` always returns `VITE_API_URL` (default `http://localhost:4000`). No direct backend URLs in dev or prod. | Types from backend specs; single baseUrl = gateway. |
| **MCP** | `TRACERTM_MCP_BASE_URL=http://localhost:4000/api/v1/mcp` so MCP uses gateway. | Backend (Python) paths via gateway. |
| **CLI** | Set base URL to gateway (e.g. `GATEWAY_PUBLIC_URL`) when using generated clients. | `gateway-api.json` or backend specs with gateway baseUrl. |

All external traffic goes through the gateway; CORS allows only gateway + frontend origins.

### 3. Caddy routing (single entrypoint behavior)

From `Caddyfile.dev`:

- `/health`, `/health/` → Caddy (200 OK)
- `/api/v1/mcp/*` → **Python** (:8000)
- `/api/v1/notifications` and `/api/v1/notifications/*` → **Python** (:8000)
- `/api/v1/*` → **Go** (:8080)
- `/api/py/*` → **Python** (:8000)
- `/ws/*` → Go
- `/docs*` → Go
- Frontend → Vite (:5173)

So when external clients use **only** the gateway:

- All “main” API traffic (`/api/v1/*` except `/api/v1/mcp/*`) goes to **Go**.
- Go then **delegates** some of that to Python (AI, specs, execution, workflows, chaos) via `PythonServiceClient` (e.g. `DelegateRequest`). So internal cross-usage is **by design**: sub-APIs by service, with Go as the facade for most of `/api/v1/*`.

### 4. Internal cross-communication (audit-friendly?)

- **Go → Python**  
  - **Mechanism:** `PythonBackendURL` + `PythonServiceClient` (AI, SpecAnalytics, Execution, Workflow, Chaos clients).  
  - **Paths:** Well-defined delegation to Python’s API (e.g. `/api/v1/ai/...`, workflows, etc.).  
  - **Audit:** Yes – explicit client wrappers and config; no ad-hoc URLs.

- **Python → Go**  
  - **Mechanism:** `GO_BACKEND_URL` (health, and any other HTTP calls to Go).  
  - **Audit:** Yes – single env-driven base URL; usage is explicit in code.

So internal usage is **tightly knit** and **sub-API by service**: Go exposes most of `/api/v1/*` and delegates a defined set of domains to Python; Python calls Go only where configured. There is no “messy” untyped cross-usage; the main gap for audit is that **no single document** (e.g. one OpenAPI or gateway spec) describes the **entire** external surface and routing.

---

## Gaps vs “only gateway contract + clean audit”

If the target is:

1. **OpenAPI/other contracts from the Caddy API are the only ones used by ext clients**, and  
2. **Built from Py/Go/other internal services with clear sub-APIs and auditable cross-usage**,

then today:

| Aspect | Current | To fully match target |
|--------|---------|------------------------|
| Single contract for external clients | No – two backend specs (Go + Python) | Add a **gateway-level** contract: e.g. merged OpenAPI or spec generated from Caddy routing + backend specs, and have frontend/MCP/CLI use only that. |
| External clients use only gateway | Frontend: yes in prod when `VITE_API_URL` is gateway; in dev can hit backends directly. MCP/CLI: configurable | Standardize all ext clients on gateway URL only (dev and prod); remove or discourage direct backend URLs. |
| Internal sub-APIs, no messy cross-usage | Yes – Go↔Python is explicit and scoped | Already aligned; optionally document “internal service API” (Go↔Python) in one place for audit. |

---

## Summary

- **Contracts:** OpenAPI and other contracts are **not** generated from Caddy; they are generated from **Go** and **Python** backends. So the **only** contracts used by ext clients (frontend, MCP, CLI) today are the **backend** contracts, not a single “Caddy API” contract.
- **Single entrypoint:** When configured to use the gateway (e.g. `VITE_API_URL=http://localhost:4000`), external clients **do** use a single entrypoint (Caddy), but they still rely on the **same** backend OpenAPI specs for types and behavior.
- **Internal design:** Py/Go/other internal services are wired with **clear sub-APIs** and **explicit** cross-calls (Go→Python via `PythonServiceClient`, Python→Go via `GO_BACKEND_URL`), so there is **no messy cross-usage that doesn’t audit**; the missing piece for a full audit is a **single gateway-level contract** that describes the whole external surface and routing.

To make “OpenAPI/other contracts from the Caddy API the only ones used by ext clients” true, you’d add a **gateway-derived or gateway-merged** contract and point frontend, MCP, and CLI only at that and at the gateway URL.
