Captures what IIOS is, the #1 generic-safety guardrail (no chat vocabulary in the kernel; meaning lives in OPA policy + opaque attributes + the app), the architecture (kernel + platform ports + fail-closed + outbox/projectors), tech stack, run/test commands (isolated iios_test DB, the replay.spec flake note), conventions (commit email, IIOS_DEV_TOKENS off in prod), and current build state. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.0 KiB
IIOS — Claude Code Rules
What IIOS is
IIOS (Insignia Interaction OS) is a generic, multi-tenant "interaction OS" — one
NestJS service (@insignia/iios-service) + a family of SDKs. Every interaction (a chat
message, a support ticket, a routed post, an AI suggestion, a meeting) is the same kernel
object inside a tenant scope, behind the same fail-closed gates (policy/consent),
emitting the same audit trail. Products (messaging, support, community, AI, meetings) are
thin specializations on top of the kernel — never the other way around.
chat-web (separate repo) is the reference consumer app.
THE #1 LOCKED RULE — generic-safety (read this before touching the kernel)
The kernel must never hardcode chat/domain vocabulary. No 'dm' / 'group' /
'reaction' / 'emoji' / 'mention' literals in kernel or messaging logic. If a reviewer
asked "is this a chat backend now?" the answer must stay no.
Domain meaning lives in three places, never the kernel:
- OPA policy (the policy plane —
DevOpaPortnow, real OPA later). The DM-cap, group-admin, governed-join, media-limit, and notification-trigger rules live here. - Opaque thread/interaction attributes the kernel stores but never interprets:
thread.metadata.membership('dm'|'group'), interaction annotations (opaqueannotationType+value→ the app writesreaction/pin/save),mentions[](an opaque userId notify-list the kernel fans out; it never parses@). - The app (chat-web) — rendering + product semantics.
Reading an opaque attribute inside a policy/notification gate (e.g. membership === 'dm'
in DevOpaPort or notification.projector.ts) is allowed — that file is the policy plane,
not the kernel. Everywhere else, keep it generic. Verify with a grep before committing:
grep -rniE "'dm'|'group'|reaction|emoji" packages/iios-service/src | grep -v spec — hits
should only be in the policy/notification/app-facing layers or comments.
pnpm boundary enforces the layer dependency law (specializations import the kernel, never
the reverse). Run it; don't break it.
Architecture
- Kernel primitives (generic):
IiosScope(six-vector: org/app/tenant/bu/…),IiosSourceHandle(externalId = userId; staysUNVERIFIEDuntil MDM resolves →canonicalEntityId),IiosActorRef,IiosThread(subject/metadata),IiosThreadParticipant,IiosInteraction(+parentInteractionIdreply link),IiosMessagePart(media ascontentRef),IiosInteractionAnnotation(generic). - Platform ports (
IiosPlatformPorts, DI tokenPLATFORM_PORTS; dev =LocalDevPorts): session, opa, cmp (consent), mdm, sas, capability — plus aStoragePort(media) andNotificationPort(push). Dev stubs → real adapters with zero consumer changes. Every op passesdecideOrThrow(ports, {action,…})fail-closed. - Session (auth):
SessionVerifierverifies (a) real OIDC tokens (Supabase/AUTH_ISSUERS) against the issuer JWKS (ES256, no secret), routed byiss→ per-issuerappIdscope; or (b) legacy dev HS256 app tokens (APP_SECRETS, keyed byappId).userId = emailfor OIDC. - Events: transactional outbox →
OutboxBus→ projectors (inbox, notifications). Projectors are idempotent (claim()onIiosProcessedEvent+ projection cursor). Delivery is at-least-once → clients dedupe by messageid. - Scope isolation: every row is tagged by
scopeId(org+app+tenant). By-id ops callassertOwns(tenant fence → 403). Alwaysselect/scope Prisma queries.
Tech stack
NestJS 11 · Prisma 6 / PostgreSQL 16 (docker iios-db on :5434, db iios) · Redis
(socket.io adapter, multi-replica) · socket.io (/message namespace) · Vitest · pnpm
monorepo (packages/*). iios-service is a modular monolith (HTTP + WS + relay +
projectors in one process).
Running & testing
docker start iios-db # Postgres :5434 (OrbStack; `open -a OrbStack` if down)
pnpm --filter @insignia/iios-service exec nest build
# run (dev auth via Supabase; media + notifications enabled):
SUPABASE_URL=https://<ref>.supabase.co REDIS_URL=redis://localhost:6379 PORT=3200 \
APP_SECRETS='{"portal-demo":"dev-secret"}' MEDIA_DIR=/tmp/iios-media \
VAPID_PUBLIC_KEY=… VAPID_PRIVATE_KEY=… VAPID_SUBJECT=mailto:dev@insignia \
node packages/iios-service/dist/main.js # → :3200 ; GET /health
pnpm test— Vitest. Runs against an isolatediios_testDB (globalSetup creates + migrates it;DATABASE_URLoverridden). It never wipes the deviiosDB. ~205 tests.- TDD: write the failing spec first (see
*.spec.tsnext to the code). DB specs useresetDb()+ real Postgres. - Flaky
outbox/replay.spec: it's clock/ordering-sensitive and pre-existing. If it fails in a full run,docker exec iios-db psql -U iios -d postgres -c "DROP DATABASE IF EXISTS iios_test WITH (FORCE)"then re-run — it's stale test-DB state, not a regression. pnpm boundary— import-boundary check (must stay OK).- Smokes:
packages/iios-service/scripts/smoke-*.mjs(run against a live service).
Conventions
- Commits: conventional (
feat:/fix:/docs:/chore:), git emailmaaz@insigniaconsultancy.com, and co-author every commit with Claude. Branch offmainbefore committing if asked; otherwise the session has committed directly tomain. - ⚠️
IIOS_DEV_TOKENSMUST be0/unset in production — it exposes/v1/dev/*(unauth token minting). Single most important prod flag. - New kernel capability = a generic primitive only (see the #1 rule). Add domain meaning in policy + app.
- Prisma: always
selectto avoid leakingpasswordHash/PII; org/tenant scope everywhere.
What's built (state)
P0–P8: kernel → messaging → inbox → support → adapters → routing → AI → calendar/meetings. Recent (the "P9 real-providers" era, mostly driven by the chat app):
- Real Supabase auth — multi-issuer JWKS verification (
SessionVerifier); first stubbed port turned real. - Reactions / pins / saves — one generic
IiosInteractionAnnotationprimitive (opaque type/value),annotatesocket event,GET /v1/threads/my-annotations. - @mentions → Inbox —
mentions[]on send →MENTIONinbox item (projector). - Media —
StoragePort(dev local disk → prod S3/Supabase), presigned upload/download, attachment onMessageDto. - Notifications — presence-gated Web Push:
NotificationProjector(policy/presence/mute gates) + swappableNotificationPort,focus_threadpresence signal, per-thread mute. senderId(stable externalId) on messages for reliable "is this mine?".
Docs (as-built)
docs/IIOS_API_AND_SDK_GUIDE.md— the as-built REST/socket/SDK reference (endpoints, shapes, env, vocab). Keep it current when adding endpoints.docs/DEPLOYMENT.md— deploy/topology/env/scaling.docs/IIOS_OVERVIEW_FOR_CEO.md— plain-language capability tour.