Files
mcq/CLAUDE.md
Kyle Isom b48fcc8465 sso: public MCIAS authorize URL + docs
Add [sso].public_url so the browser SSO authorize redirect uses the
public MCIAS hostname while the code exchange stays on the internal
address (mcdsl v1.9.0). Document the SSO URL split and the rootless-podman
/ unikernel-eligibility rules in CLAUDE.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 11:20:50 -07:00

3.9 KiB

CLAUDE.md

Overview

MCQ (Metacircular Document Queue) is a reading queue service. Documents (raw markdown) are pushed via API from inside the infrastructure, then read through a mobile-friendly web UI from anywhere. MCIAS authenticates all access — any user (including guest) can read, any user (including system accounts) can push.

Build Commands

make all         # vet → lint → test → build
make mcq         # build binary with version injection
make build       # go build ./...
make test        # go test ./...
make vet         # go vet ./...
make lint        # golangci-lint run ./...
make proto       # regenerate gRPC code from .proto files
make proto-lint  # buf lint + buf breaking
make devserver   # build and run locally against srv/mcq.toml
make clean       # remove binaries

Run a single test:

go test ./internal/db/ -run TestPutDocument

Architecture

Single binary, three concerns:

  • REST API (/v1/*) — CRUD for documents, MCIAS Bearer token auth
  • gRPC API (:9443) — same operations, MCIAS interceptor auth
  • Web UI (/, /d/{slug}, /login) — goldmark-rendered reader, MCIAS session cookies

Documents keyed by slug (unique). PUT upserts — same slug replaces content.

Project Structure

cmd/mcq/              CLI entry point (server subcommand)
internal/
  db/                 SQLite schema, migrations, document CRUD
  server/             REST API routes and handlers
  grpcserver/         gRPC server, interceptors, service handlers
  webserver/          Web UI routes, templates, session management
  render/             goldmark markdown-to-HTML renderer
proto/mcq/v1/         Protobuf definitions
gen/mcq/v1/           Generated Go code (do not edit)
web/                  Embedded templates + static files
deploy/               systemd, examples

Shared Library

MCQ uses mcdsl (git.wntrmute.dev/mc/mcdsl) for: auth, db, config, httpserver, grpcserver, csrf, web (session cookies, auth middleware, template rendering).

Critical Rules

  1. REST/gRPC sync: Every REST endpoint has a corresponding gRPC RPC.
  2. gRPC interceptor maps: New RPCs must be added to the correct map.
  3. No test frameworks: stdlib testing only, real SQLite in t.TempDir().
  4. CSRF on all web mutations: double-submit cookie pattern.
  5. Session cookies: HttpOnly, Secure, SameSite=Strict.

SSO (public vs internal MCIAS URLs)

MCQ is reachable publicly (mcq.metacircular.net), so its SSO uses two MCIAS URLs (via mcdsl/sso ≥ v1.9.0):

  • [mcias].server_url — the internal address (https://mcias.svc.mcp.metacircular.net:8443) used for the server-to-server authorization-code exchange. Efficient and does not depend on the public edge.
  • [sso].public_url — the public, browser-facing MCIAS base URL (https://mcias.metacircular.net) used to build the authorize redirect, so end-user browsers (which can't resolve the internal name) can reach it.
  • [sso].redirect_uri must be the public callback (https://mcq.metacircular.net/sso/callback) and must match the redirect_uri registered for the mcq SSO client in MCIAS (mciasctl sso update --client-id mcq --redirect-uri ...).

If public_url is empty the authorize redirect falls back to server_url (tailnet-only SSO). The startup log prints both authorize_url and exchange_url so you can confirm the split.

Deployment / runtime

  • Containers run rootless under MCP. Dockerfiles must NOT declare VOLUME /srv/mcq, pre-create/chown the data dir, or set USER — MCP bind-mounts /srv/mcq and runs --user 0:0. See ../engineering-standards.md → Containerization.
  • Not unikernel-eligible (yet). MCQ writes a SQLite DB to /srv/mcq; the unikernel runtime currently bakes config/certs read-only and has no writable host mount, so MCQ stays a container until 9p/virtio-blk storage lands. See docs/unikernels.md in the workspace root.