135 lines
6.2 KiB
Markdown
135 lines
6.2 KiB
Markdown
# Wiring the demo to the real IIOS service
|
|
|
|
This app talks to a pluggable **BFF backend**. Today it defaults to the in-memory mock; an
|
|
**IIOS adapter is implemented** and switches on with one env var. This doc explains what's built,
|
|
how to turn it on, and what still needs IIOS-side endpoints.
|
|
|
|
> Reference: `D:\iios\docs\IIOS_API_AND_SDK_GUIDE.md` (endpoints, auth, DTOs).
|
|
|
|
## The seam
|
|
|
|
Every BFF route calls `getBackend()` — never the store directly. `BFF_BACKEND` picks the impl:
|
|
|
|
```
|
|
apps/web/lib/backend/
|
|
Backend.ts the interface every route uses (all async)
|
|
mock.ts MockBackend — wraps the in-memory store (default)
|
|
iios.ts IiosBackend — proxies the real IIOS service
|
|
index.ts getBackend() → mock | iios (from BFF_BACKEND)
|
|
apps/web/lib/iios/
|
|
client.ts server-only IIOS REST client (dev-token auth, lazy token mint)
|
|
map.ts IIOS → SDK type mappers (toMessage / toInboxItem / toTicket)
|
|
```
|
|
|
|
The SDK, hooks, and every UI component are unchanged between mock and IIOS — all translation lives
|
|
in `lib/iios/map.ts`.
|
|
|
|
## Turn it on
|
|
|
|
1. **Run IIOS** (from `D:\iios`, needs Docker for Postgres):
|
|
```bash
|
|
docker compose up -d # Postgres on :5434
|
|
pnpm install
|
|
pnpm -F @insignia/iios-service prisma:generate
|
|
pnpm -F @insignia/iios-service prisma:migrate
|
|
cd packages/iios-service && IIOS_DEV_TOKENS=1 pnpm start # → :3200
|
|
```
|
|
2. **Point this app at it** (`apps/web/.env.local`):
|
|
```bash
|
|
BFF_BACKEND="iios"
|
|
IIOS_URL="http://localhost:3200"
|
|
IIOS_APP_ID="portal-demo"
|
|
IIOS_USER_ID="james"
|
|
IIOS_ORG_ID="org_A"
|
|
```
|
|
3. `pnpm dev` → the BFF now mints a dev token and proxies IIOS. `IIOS_*` are **server-only**
|
|
(no `NEXT_PUBLIC_`), so the token never reaches the browser.
|
|
|
|
## ✅ Verified live (no Docker required)
|
|
|
|
The IIOS path has been run **end-to-end** against a real IIOS service + real Postgres, and the
|
|
round-trip through this app's BFF was confirmed (a real ingested message came back through
|
|
`GET /api/bff/channels/:threadId/messages`, and `/api/bff/support/tickets` returned IIOS's real
|
|
data instead of the mock set). Docker isn't needed — a native PostgreSQL works.
|
|
|
|
Exact steps that worked on Windows (PostgreSQL 18 already installed):
|
|
|
|
```bash
|
|
# 1. Create the iios role + database on the existing Postgres (port 5432)
|
|
# (as the postgres superuser)
|
|
psql -U postgres -c "CREATE ROLE iios LOGIN PASSWORD 'iios' CREATEDB;"
|
|
psql -U postgres -c "CREATE DATABASE iios OWNER iios;"
|
|
|
|
# 2. Point IIOS at it — packages/iios-service/.env
|
|
# DATABASE_URL="postgresql://iios:iios@localhost:5432/iios?schema=public"
|
|
# (the repo default is :5434 via docker-compose; :5432 is fine too)
|
|
# JWT_SECRET=... · APP_SECRETS={"portal-demo":"dev-secret"} · IIOS_DEV_TOKENS=1
|
|
|
|
# 3. From D:\iios — allow prisma/esbuild builds in pnpm-workspace.yaml, then:
|
|
pnpm install
|
|
pnpm -r build
|
|
node packages/iios-service/node_modules/prisma/build/index.js generate --schema packages/iios-service/prisma/schema.prisma
|
|
node packages/iios-service/node_modules/prisma/build/index.js migrate deploy --schema packages/iios-service/prisma/schema.prisma
|
|
node packages/iios-service/dist/main.js # → iios-service listening on :3200
|
|
|
|
# 4. Point THIS app at it — apps/web/.env.local
|
|
BFF_BACKEND=iios
|
|
IIOS_URL=http://localhost:3200
|
|
# then `pnpm dev` (restart) — the BFF now mints a dev token and proxies IIOS.
|
|
```
|
|
|
|
> The mapper in `map.ts` was validated against the real IIOS message shape
|
|
> (`{interactionId, actorId, occurredAt, parts:[{kind,bodyText}]}`). A **fresh IIOS DB is empty**
|
|
> and IIOS has no channel-directory endpoint, so `bootstrap`/`listChannels` stay on mock (the demo
|
|
> keeps its rich sidebar) while messages/inbox/tickets read from IIOS. Seed IIOS (via
|
|
> `POST /v1/interactions/ingest` or its smoke scripts) to see live data flow through.
|
|
|
|
## What's wired vs. delegated
|
|
|
|
| BFF method | IIOS backing | Notes |
|
|
|---|---|---|
|
|
| `channelMessages` / `thread` | `GET /v1/threads/:id/messages` | maps parts→body, parent links |
|
|
| `send` | `POST /v1/threads/:id/messages` (+ `idempotency-key`) | |
|
|
| `listInbox` / `patchInbox` | `GET`/`PATCH /v1/inbox/items` | |
|
|
| `listTickets` / `getTicket` / `patchTicket` | `/v1/support/tickets` | `getTicket` lists+finds (no single-GET documented) |
|
|
| `replyTicket` | `POST` to the ticket's linked thread | |
|
|
| `bootstrap` / `listChannels` / `createChannel` | **delegated to mock** | IIOS has no portal/channel-directory endpoint yet; build one, or compose from `/v1/threads` |
|
|
| `react` / `pin` / `save` | **delegated to mock** | IIOS has no reaction/pin/save endpoints; keep local or add them |
|
|
| `search` / `notifications` / `availability` | **delegated to mock** | add IIOS endpoints then swap |
|
|
|
|
Delegating keeps the UI fully functional while you fill the gaps — each is a small, isolated change
|
|
in `iios.ts`.
|
|
|
|
## Auth
|
|
|
|
`lib/iios/client.ts#mintToken()` calls `POST /v1/dev/token` and caches the JWT (~100 min). For
|
|
production, replace `mintToken()` with a real Session-Broker exchange (PPT), keep it server-side,
|
|
and attach `Authorization: Bearer …` exactly as now.
|
|
|
|
## Shape mapping
|
|
|
|
Keep this app's `types.ts` as the UI contract; translate in `map.ts` (already defensive about field
|
|
names). Example:
|
|
|
|
```ts
|
|
export function toMessage(m: any, channelId: string): Message {
|
|
const text = m.content ?? m.body ?? m.parts?.find(p => (p.kind ?? p.partType) === "TEXT")?.bodyText ?? "";
|
|
return { id: String(m.id ?? m.interactionId), channelId,
|
|
authorId: String(m.senderActorId ?? m.actorId ?? "unknown"),
|
|
ts: Date.parse(m.sentAt ?? m.occurredAt) || Date.now(),
|
|
body: String(text), parentId: m.parentInteractionId ?? null, reactions: [], deliveryState: "sent" };
|
|
}
|
|
```
|
|
|
|
## Tenancy & safety (carried by IIOS)
|
|
|
|
IIOS enforces tenant isolation (cross-tenant → 403), fail-closed policy/consent gates, and
|
|
idempotency. The BFF just forwards the scoped token — don't reimplement those client-side. The UI's
|
|
optimistic updates already tolerate a rejected write (surface an error, refetch).
|
|
|
|
## Realtime (optional upgrade)
|
|
|
|
Swap the mock `useTyping` + refetch for the IIOS Socket.IO client (`iios-kernel-client`'s
|
|
`MessageSocket`) and feed `message`/`receipt` events into the same hook state. The component tree
|
|
doesn't change.
|