guildhall/CLAUDE.md
Tyler J King 03e0567341 docs: add CLAUDE.md for guildhall project context
Covers architecture, auth flow, database schema, gRPC services,
routes, schematic templates, and K8s manifests so future sessions
can orient without re-discovering the codebase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Tyler J King <tking@guildhouse.dev>
2026-05-15 15:05:03 -04:00

130 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Guildhall — Claude Context
## What this is
Phoenix umbrella app — ceremony orchestrator + governance UI for the Guildhouse platform. Onboards guilds (MSP/ISV/NSP organizations), deploys founding schematics via gRPC, and manages membership with ceremony-engine approval flows.
## Architecture
```
guildhall/
├── apps/
│ ├── guildhall_ops_db — Ecto schemas + contexts (Postgres)
│ ├── guildhall_orchestrator — gRPC clients, GenServers, template engine
│ ├── guildhall_web — Phoenix LiveView UI + OIDC auth
│ ├── guildhall_chronicle — Chronicle event consumer (stub)
│ └── guildhall_graph_bridge — Microsoft Graph reconciler (stub)
├── config/ — dev.exs, runtime.exs (env-var driven)
└── k8s/ — Kubernetes manifests (00-93, numeric order)
```
## External services (gRPC)
| Service | Port | Proto | Client module |
|---------|------|-------|---------------|
| ceremony-service (Rust) | 50053 | `ceremony.v1.CeremonyService` | `Guildhall.Orchestrator.CeremonyClient` |
| ffc-schematic-server (Rust) | 9091 | `schematic.v1.SchematicsService` + `FfcSchematicService` | `Guildhall.Orchestrator.SchematicClient` |
Env vars: `CEREMONY_SERVICE_URL`, `SCHEMATIC_SERVICE_URL`, `FFC_SCHEMATIC_SERVICE_URL`. In-cluster DNS: `<name>.guildhall.svc.cluster.local:<port>`.
## Auth
Keycloak OIDC at `auth.guildhouse.dev/realms/guildhouse`, client `guildhall-web`. Env vars: `OIDC_ISSUER`, `OIDC_CLIENT_ID`, `OIDC_CLIENT_SECRET`, `OIDC_REDIRECT_URI`.
- `GuildhallWeb.Plugs.Auth``fetch_current_user/2` plug (reads session)
- `GuildhallWeb.AuthController` — login/callback/logout controller
- `GuildhallWeb.AuthHooks` — LiveView `on_mount(:require_auth)`
- User stored in session as map: `%{"did" => "did:web:...", "email" => ..., "name" => ..., "sub" => ..., "preferred_username" => ...}`
- DID format: `did:web:guildhouse.dev:user:<preferred_username>`
- Hub operator DID: `did:web:guildhouse.dev:user:tking`
## Database tables (guildhall_ops_db)
Pre-existing: `governed_artifacts`, `deployment_states`, `verification_results`
New guild tables:
- **guilds** — `guild_id` (10-bit, 0x0100x3FF), `slug`, `guild_type` (msp/isv/nsp), `status` (pending_approval/approved/denied/active/suspended), `registration_ceremony_id`, `trust_domain`, `registrant_did`, `contact_did`
- **guild_schematics** — FK to guilds, `template_name`, `schematic_name`, `schematic_version`, `realization_id`, `status` (pending/forked/binding_created/realizing/realized/failed), `realization_snapshot` (map)
- **guild_memberships** — FK to guilds, `user_did`, `role` (apprentice/journeyman/master), `status` (pending/approved/denied/active/suspended/removed), `membership_ceremony_id`, unique on (guild_id, user_did)
## Key flows
### Guild registration
1. User fills form at `/guilds/register` → creates guild row (status: pending_approval) + ceremony via `CeremonyClient.create_guild_registration_ceremony`
2. Hub operator (tking) sees pending guild at `/guilds/:slug`, clicks Approve → `CeremonyClient.approve_ceremony` + `Guilds.approve_guild/1` (Ecto.Multi: updates guild to "approved" + creates registrant as guild master)
### Schematic deployment
1. Guild master visits `/guilds/:slug/schematic` → loads TOML template for guild type from `priv/schematic_templates/`
2. Click Deploy → `SchematicClient.fork_schematic``create_deployment_binding``realize_ffc_schematic`
3. Creates `guild_schematics` row, starts `RealizationPoller.watch/2`
4. `/guilds/:slug/realization` shows 7 reconciler sections via PubSub live updates
### Member onboarding
1. User visits `/guilds/:slug/join` → creates membership (pending) + ceremony for guild master approval
2. Guild master at `/guilds/:slug/members` → approve/deny via ceremony engine, manage roles
## Routes
All guild routes are under authenticated `live_session :authenticated`:
```
/ DashboardLive
/guilds GuildLive.Index
/guilds/register GuildLive.Register
/guilds/:slug GuildLive.Show
/guilds/:slug/schematic GuildLive.Schematic
/guilds/:slug/realization GuildLive.Realization
/guilds/:slug/join GuildLive.Join
/guilds/:slug/members GuildLive.Members
/ceremonies CeremonyLive.Index
/artifacts ArtifactLive.Index
```
Public: `/auth/login`, `/auth/callback`, `/auth/logout`, `/health`
## Orchestrator supervision tree
- `Guildhall.Orchestrator.CeremonyOrchestrator` — existing ceremony workflow coordinator
- `Guildhall.Orchestrator.RealizationPoller` — GenServer, polls realization status every 5s for watched IDs, broadcasts on `"realization:#{guild_slug}"` PubSub topic
## Schematic templates
TOML files in `apps/guildhall_orchestrator/priv/schematic_templates/`:
- `msp-founding.toml` — attestation tier 2, MFA, single_approval
- `isv-founding.toml` — attestation tier 1, no MFA, single_approval
- `nsp-founding.toml` — attestation tier 3, MFA + hardware, multi_party quorum 2
`SchematicTemplate.render_template/2` substitutes `{{guild_slug}}`, `{{guild_name}}`, `{{trust_domain}}`, `{{registrant_did}}`.
## Generated protobuf modules
In `apps/guildhall_orchestrator/lib/guildhall/orchestrator/proto/`:
- `ceremony/v1/ceremony.pb.ex``Ceremony.V1.CeremonyService.Stub`
- `schematic/v1/schematics.pb.ex``Schematic.V1.SchematicsService.Stub`
- `schematic/v1/ffc_schematic.pb.ex``Schematic.V1.FfcSchematicService.Stub`
These were generated with `protoc --elixir_out=plugins=grpc`. Re-generate if protos change.
## K8s manifests
Files in `k8s/` applied in numeric order. Key additions:
- `90-ceremony-service-deployment.yaml` + `91-*-service.yaml` — ClusterIP on 50053
- `92-schematic-server-deployment.yaml` + `93-*-service.yaml` — ClusterIP on 9091
- `70-guildhall-deployment.yaml` — includes OIDC + gRPC env vars
- Secrets created imperatively (see `50-guildhall-secrets-template.yaml`)
## Commands
```bash
mix deps.get # fetch deps
mix ecto.migrate # run migrations
mix compile # verify compilation
mix phx.server # start dev server (localhost:4000)
mix test # run tests
```
## Commit convention
Sign commits as `tking@guildhouse.dev`:
```bash
git -c user.email=tking@guildhouse.dev commit -s -m "message"
```