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

6.3 KiB
Raw Blame History

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.Authfetch_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:

  • guildsguild_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_schematiccreate_deployment_bindingrealize_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.exCeremony.V1.CeremonyService.Stub
  • schematic/v1/schematics.pb.exSchematic.V1.SchematicsService.Stub
  • schematic/v1/ffc_schematic.pb.exSchematic.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

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:

git -c user.email=tking@guildhouse.dev commit -s -m "message"