generated from coulomb/repo-seed
Some checks failed
Test / test (push) Has been cancelled
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>
276 lines
9.2 KiB
Markdown
276 lines
9.2 KiB
Markdown
# 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 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` |
|