Files
inter-hub/docs/new-hub-quickstart.md
tegwick 750c9f25ff
Some checks failed
Test / test (push) Has been cancelled
docs: add new-hub-quickstart.md — two-pattern domain hub guide
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 <noreply@anthropic.com>
2026-04-29 14:53:19 +02:00

276 lines
9.2 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.
# 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 <your-api-key>" \
-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 <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"name": "Pipeline Status Panel",
"widgetType": "dev-pipeline-run",
"hubId": "<your-hub-id>",
"viewContext": "pipeline-dashboard"
}'
```
### 5. Record interaction events
```bash
curl -X POST http://192.168.178.135:8080/api/v2/interaction-events \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"widgetId": "<widget-id>",
"eventType": "clicked",
"userId": "<optional-user-id>",
"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 2040 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) | ~35 min |
| Incremental reload (1 module changed) | ~515 s |
| Adding a new controller+view pair | ~1030 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` |