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>
130 lines
6.3 KiB
Markdown
130 lines
6.3 KiB
Markdown
# 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, 0x010–0x3FF), `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"
|
||
```
|