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>
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
- REST/gRPC sync: Every REST endpoint has a corresponding gRPC RPC.
- gRPC interceptor maps: New RPCs must be added to the correct map.
- No test frameworks: stdlib
testingonly, real SQLite in t.TempDir(). - CSRF on all web mutations: double-submit cookie pattern.
- 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_urimust be the public callback (https://mcq.metacircular.net/sso/callback) and must match theredirect_uriregistered for themcqSSO 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 setUSER— MCP bind-mounts/srv/mcqand 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. Seedocs/unikernels.mdin the workspace root.