# Dialectic.Backend — v2 (Go) Greenfield Go rewrite of the Python v1 backend. Agent-native debate platform per [`/home/hzhang/arch/DIALECTIC-V2-DESIGN.md`](../DIALECTIC-V2-DESIGN.md). Python v1 history is preserved on branch `archive/python-v1`. ## What's here (Phase 2A + 2B + 2C, 2026-05-23) | Subsystem | Status | |-----------|--------| | HTTP server (`chi` router) | ✅ | | Config from env (`internal/config`) | ✅ | | MySQL via `sqlx` + embedded SQL migrations | ✅ | | Schema: `topics`, `signups`, `camps`, `rounds`, `arguments`, `verdicts`, `agent_keys`, `system_keys`, `verdict_schemas` | ✅ | | Auth middlewares: agent bearer (real), OIDC browser (Phase 2 stub w/ dev bypass) | ✅ | | `/api/healthz` | ✅ | | `/api/topics` list / get / create / set-visibility | ✅ | | `/api/topics/{id}/signups` list / create (agent self-enroll) | ✅ | | Orchestration engine (camp allocation, round driver, judge invocation) | ⬜ Phase 2D | | SSE live transcripts | ⬜ Phase 2D | | Full OIDC + Keycloak JWKS verification | ⬜ Phase 4 | | Nginx + CF Origin Cert on server.t3 | ⬜ Phase 2E | ## Layout ``` main.go entrypoint (load → wire → serve) go.mod Dockerfile docker-compose.dev.yml backend + mysql for local iteration internal/ config/ 12-factor env loader db/ db.go sqlx + embedded migration runner migrations/001_init.sql v2 schema, idempotent models/ entity types (sqlx + json tags) store/ query layer (per-entity) auth/ agent api-key + oidc middlewares httpapi/ routes.go chi router + auth chains handlers/ per-endpoint handlers ``` ## Run locally ``` docker compose -f docker-compose.dev.yml up --build # backend on http://localhost:8090 curl http://localhost:8090/api/healthz ``` Env vars (see `internal/config/config.go` for the full list): | Var | Default (dev) | Required in prod | |-----|---------------|-------------------| | `ENV_MODE` | `dev` | must be `prod` | | `HTTP_ADDR` | `0.0.0.0:8090` | — | | `CORS_ALLOW_ORIGINS` | `*` | concrete list (no `*`) | | `DB_HOST/PORT/NAME/USER/PASSWORD` | dev defaults | ✓ password required | | `AGENT_API_KEY_PEPPER` | — | ✓ | | `OIDC_ISSUER` / `OIDC_CLIENT_ID` | — | ✓ | | `OIDC_DEV_BYPASS_TOKEN` | unset | ignored in prod | | `SYSTEM_API_KEY` | unset | populate when announce-channel push lands | ## Dev bypass for browser routes In `ENV_MODE=dev` with `OIDC_DEV_BYPASS_TOKEN=` set: ``` curl -H "x-dev-bypass: " http://localhost:8090/api/topics # attached as user 'dev-operator' with role 'dialectic-admin' ``` In `prod`, this header is ignored regardless of value. ## Agent bearer for plugin routes The OpenClaw plugin (`Dialectic.OpenclawPlugin`, Phase 3) calls with: ``` Authorization: Bearer ``` The key is hashed with `AGENT_API_KEY_PEPPER` and matched against `agent_keys.key_hash`. To provision an agent's key (Phase 3 will add a proper `hf user create-dialectic-key` CLI; for now, manual SQL): ```sql INSERT INTO agent_keys (agent_id, key_hash) VALUES ('manager', SHA2(CONCAT(':', ''), 256)); ``` ## What's next - **Phase 2D**: camp allocation algorithm + round driver + judge invocation. Wired to Fabric announce channel (via system-api-key) + the Dialectic.OpenclawPlugin's tool for agent argument submission. - **Phase 2E**: nginx config + CF Origin Cert + deploy to server.t3. - **Phase 3**: Dialectic.OpenclawPlugin — agent-facing tools. - **Phase 4**: frontend rewrite (STYLE.md + real Keycloak OIDC + visibility toggle UI). - **Phase 5**: end-to-end integration with `analyze-intel` workflow.