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>
101 lines
3.9 KiB
Markdown
101 lines
3.9 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:
|
|
```bash
|
|
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.
|