From 750c9f25ffe0efd73426596ba7e77b056c9ffc10 Mon Sep 17 00:00:00 2001 From: tegwick Date: Wed, 29 Apr 2026 14:53:19 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20add=20new-hub-quickstart.md=20=E2=80=94?= =?UTF-8?q?=20two-pattern=20domain=20hub=20guide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Covers Pattern A (API consumer, any language, start today) and Pattern B (IHP extension hub, Haskell, shares haskelseed build infra). Includes honest Haskell/IHP assessment, build-time estimates, hub-core sketch, and a concrete checklist. References existing domain-hub-extension-guide.md for type vocabulary registration. Co-Authored-By: Claude Sonnet 4.6 --- docs/new-hub-quickstart.md | 275 +++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 docs/new-hub-quickstart.md diff --git a/docs/new-hub-quickstart.md b/docs/new-hub-quickstart.md new file mode 100644 index 0000000..fa78f68 --- /dev/null +++ b/docs/new-hub-quickstart.md @@ -0,0 +1,275 @@ +# New Domain Hub — Quickstart Guide + +**Audience:** A developer starting a new domain hub (dev-hub, ops-hub, fin-hub, etc.) +that will live in its own repository and use inter-hub as the governance substrate. + +**Current state:** inter-hub v0.2.0-alpha.1 is running at `http://192.168.178.135:8080`. + +--- + +## Two Patterns — Choose One + +### Pattern A: API Consumer Hub (any language, start today) + +Your hub is a standalone application that talks to inter-hub via REST API. +No Haskell required. Full framework services available from day one. + +**Best for:** Hubs that already have a tech stack (Node, Python, Go, etc.), +prototypes, or teams that want zero build overhead. + +### Pattern B: IHP Extension Hub (Haskell, shares build infra) + +Your hub is a separate IHP project that runs alongside inter-hub, sharing +the same Nix/GHC installation on haskelseed and optionally the same +PostgreSQL cluster (different schema or database). + +**Best for:** Hubs that need server-rendered UI, deep governance integration, +or type-safe access to inter-hub's data model. + +--- + +## Pattern A — API Consumer Hub + +### 1. Create an API consumer in inter-hub + +Go to `http://192.168.178.135:8080/ApiConsumers` → New. + +Fill in: +- **Name:** `dev-hub` (or your hub name) +- **Contact:** your team email +- **Description:** what this hub does + +After creating the consumer, go to **API Keys → New** and generate a key +for this consumer. Copy the key — it is shown only once. + +### 2. Register your hub + +```bash +curl -X POST http://192.168.178.135:8080/api/v2/hubs \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Dev Hub", + "slug": "dev-hub", + "domain": "dev.example.com", + "hubKind": "domain" + }' +``` + +Save the returned `id` — this is your `hubId` for all subsequent calls. + +### 3. Register your type vocabulary + +Before creating widgets with domain-specific types, register them via the +inter-hub UI at `/HubCapabilityManifests` → New → select your hub. + +In the manifest editor, declare your types: +```json +["dev-pipeline-run", "dev-pr-review", "dev-build-status"] +``` + +Click **Activate**. See `docs/domain-hub-extension-guide.md` for the full +naming rules and conflict-resolution workflow. + +### 4. Register widgets + +```bash +curl -X POST http://192.168.178.135:8080/api/v2/widgets \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Pipeline Status Panel", + "widgetType": "dev-pipeline-run", + "hubId": "", + "viewContext": "pipeline-dashboard" + }' +``` + +### 5. Record interaction events + +```bash +curl -X POST http://192.168.178.135:8080/api/v2/interaction-events \ + -H "Authorization: Bearer " \ + -H "Content-Type: application/json" \ + -d '{ + "widgetId": "", + "eventType": "clicked", + "userId": "", + "payload": {"button": "retry", "pipeline": "main-ci"} + }' +``` + +### 6. What you get for free + +Once events are flowing, the inter-hub framework automatically provides: +- Annotation collection on any widget +- Requirement candidate escalation from annotations +- Triage queue and governance lifecycle (Requirement → Decision → Deployment) +- AI-assisted requirement drafting (if AgentRegistration is configured) +- Outcome signals and regression detection +- Widget marketplace discovery + +Your hub only needs to POST events. Everything downstream is managed by +inter-hub. + +--- + +## Pattern B — IHP Extension Hub (Haskell) + +### Prerequisites + +The same build infrastructure used for inter-hub works directly: +- haskelseed VM (`192.168.178.135`) with GHC 9.10.3 in the Nix store +- `devenv` for reproducible environments +- The painful one-time Nix setup is already done — a new IHP project reuses + the same Nix store + +### Bootstrap a new hub repo + +```bash +# On your workstation (Nix must be installed) +nix profile install nixpkgs#ihp-new +ihp-new dev-hub +cd dev-hub + +# Edit devenv.nix to pin to the same IHP version as inter-hub (1.5.0) +# Then: +devenv up +``` + +The first `devenv up` on a fresh machine takes 20–40 min to fetch Nix +dependencies. On haskelseed, most dependencies are already in the Nix store +and the setup takes ~2 minutes. + +### Connect to inter-hub's API + +Add the inter-hub API client to your hub. The simplest approach: + +```haskell +-- Application/Helper/InterHubClient.hs +module Application.Helper.InterHubClient where + +import IHP.Prelude +import Network.HTTP.Simple + +postEvent :: Text -> Text -> Text -> Value -> IO () +postEvent apiKey widgetId eventType payload = do + let req = setRequestMethod "POST" + $ setRequestHeader "Authorization" ["Bearer " <> cs apiKey] + $ setRequestHeader "Content-Type" ["application/json"] + $ setRequestBodyJSON (object + [ "widgetId" .= widgetId + , "eventType" .= eventType + , "payload" .= payload + ]) + $ parseRequest_ "http://192.168.178.135:8080/api/v2/interaction-events" + void $ httpLBS req +``` + +### Shared database (optional) + +If your hub needs read access to inter-hub's tables (e.g., to join against +`requirements` or `decision_records`), connect to the same PostgreSQL: + +```bash +# In your hub's .env: +DATABASE_URL=postgresql://ihp:ihp@192.168.178.135/interhub +``` + +Your IHP app can then use `query @DecisionRecord` directly without going +through the API. This is appropriate for tightly-coupled hubs that are +part of the same operational boundary. + +For loosely-coupled hubs (separate teams, separate deploy cadence), use +the API only — do not share the database. + +### How fast is the Haskell build for a new hub? + +A fresh IHP project with 10 controllers and 20 views compiles to ~150 +modules (vs inter-hub's 616). With the Nix store already populated on +haskelseed: + +| Stage | Time | +|-------|------| +| First `devenv up` (Nix fetch) | ~2 min (store populated) | +| First GHCi load (150 modules) | ~3–5 min | +| Incremental reload (1 module changed) | ~5–15 s | +| Adding a new controller+view pair | ~10–30 s compile time | + +This is practical for active development. The painful build experience with +inter-hub was caused by its scale (616 modules, 12 phases worth of code) +and the Alpine setup being done from scratch. A new hub starts small. + +--- + +## Honest Assessment: Is IHP a Good Framework for Domain Hubs? + +**Yes, with caveats.** + +**Strengths:** +- Type safety catches integration errors at compile time, not at 2am +- Server-rendered HSX views are fast to write once you know IHP conventions +- The query builder and auto-generated types eliminate a whole class of SQL bugs +- IHP's code generator scaffolds a controller+4 views in seconds +- Once the Nix environment is set up, it is reproducible — no "works on my machine" + +**Caveats:** +- The initial Nix setup is still painful on a new machine (~1h) +- GHC error messages for type inference failures are dense +- No hot-reload for Haskell (GHCi restart is fast, but not instant) +- The `hub-core` shared library is planned but not yet implemented — + each new hub currently duplicates boilerplate for API client setup, + hub registration, and event posting + +**Bottom line:** If you are already comfortable with Haskell and IHP, +building domain hubs in the same stack is efficient and the type safety +pays dividends quickly. If your team is not Haskell-native, Pattern A +(API consumer) is the pragmatic choice — the API surface is stable and +well-documented, and you can add a lightweight web layer in whatever +language fits your team. + +--- + +## What hub-core Would Provide + +The planned `hub-core` Haskell library (not yet implemented) would give +every domain hub: + +- `HubRegistration` typeclass — register with inter-hub on startup +- `WidgetEnvelope` helpers — consistent widget wrapping across hubs +- `InterHubClient` — typed API client with retry and auth built in +- `HubCapabilityManifest` bootstrap — auto-activate manifest on startup +- Shared `defaultLayout` with inter-hub navigation integration + +Until `hub-core` exists, copy the client helper above and the 3-step +registration pattern into your new hub. It is ~50 lines of boilerplate. + +--- + +## Checklist for a New Hub + +- [ ] Create ApiConsumer + ApiKey in inter-hub UI +- [ ] Record your hub ID and API key in the new hub's `.env` +- [ ] Register HubCapabilityManifest with domain type vocabulary +- [ ] Activate the manifest (validates no naming conflicts) +- [ ] Create at least one Widget per meaningful UI surface +- [ ] Instrument interactions with POST to `/api/v2/interaction-events` +- [ ] Verify events appear in inter-hub at `/InteractionEvents` +- [ ] (Optional) Configure AgentRegistration and ModelRoutingPolicy for + AI-assisted requirement drafting +- [ ] (Optional) Set up HubRoutingRules to route annotations to your hub's + triage queue + +--- + +## Reference + +| Resource | Location | +|----------|----------| +| API reference (OpenAPI) | `http://192.168.178.135:8080/api/v2/openapi.json` | +| Type registry browser | `http://192.168.178.135:8080/TypeRegistries/WidgetTypes` | +| Domain hub extension guide | `docs/domain-hub-extension-guide.md` | +| IHP data and queries | `docs/ihp-data-and-queries.md` | +| IHP controllers and views | `docs/ihp-controllers-views-forms.md` | +| Functional module maturity | `docs/functional-modules.md` | +| IHF v0.2 specification | `specs/InteractionHubFrameworkSpecification_v0.2.md` |