{"slug":"internal/architecture/ARCHITECTURE_DECISIONS","title":"Architecture Decisions — IntegrateWise","section":"internal","sectionLabel":"Internal","status":"unclassified","type":"document","path":"internal/architecture/ARCHITECTURE_DECISIONS.mdx","bytes":5293,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n> Key decisions behind the Knowledge Workspace built on the Spine, powered by AI.\n\n---\n\n## Current Surface-Binding Doctrine\n\n- Operational Workbench = the primary work surface; left sidebar nav; Twin sidebar pops out when needed.\n- Twin Workbench = full AI ecosystem surface (skills, knowledge, agents, prompts, conversational library).\n- Governance is embedded at every layer — not a separate workbench.\n- OpenWebUI is not the customer-facing product shell.\n- Twin / OpenWebUI runtime surfaces use the canonical Forest + Paper system language.\n- Midnight Executive is investor-deck / fundraising language only.\n\nUse older L1/L2 / workspace / knowledge-UI language in this file through that boundary if any historical phrasing remains.\n\n---\n\n## ADR-1: Why Cloudflare Workers (Not AWS Lambda / GCP Functions)\n\n| Factor              | Cloudflare Workers | AWS Lambda          |\n| ------------------- | ------------------ | ------------------- |\n| Cold start          | 0 ms (V8 isolates) | 100–800 ms          |\n| Edge locations      | 300+ PoPs          | ~30 regions         |\n| Pricing at scale    | $0.50/M requests   | $0.20/M + duration  |\n| KV + D1 co-location | Native             | Requires VPC config |\n\n**Decision:** Every pipeline stage (Loader, Normalizer, Resolver, Router, Writer, Assembler, Trigger, Notifier) runs as an independent Worker. V8 isolates give us sub-millisecond cold starts, which matters when a single account sync fans out across 8 stages. We avoid container orchestration entirely.\n\n**Trade-off accepted:** 128 MB memory cap per Worker. We compensate by streaming large payloads through R2 and keeping each stage stateless.\n\n---\n\n## ADR-2: Why Spine DB (Not Raw Postgres / Firebase)\n\n- Row-Level Security (RLS) gives us tenant isolation without application-layer middleware.\n- Realtime subscriptions power the CSM Hub live-update feed without polling.\n- PostgREST auto-generates REST endpoints from schema — our \"schema-as-backend-IP\" principle.\n- Auth integrates with our Identity Resolution layer for HITL approval flows.\n\n**Decision:** Spine DB is the persistence layer for Spine. Every entity write lands in Spine DB with RLS enforcing workspace-level isolation. The schema itself encodes business logic (check constraints, triggers, computed columns), making the database the source of truth — not application code.\n\n---\n\n## ADR-3: Why Schema-as-Backend-IP\n\nTraditional SaaS puts business logic in API handlers. We push it into the schema:\n\n- **Entity types** are Postgres enums — adding a new entity type is a migration, not a code change.\n- **Confidence scores** are `CHECK (confidence >= 0 AND confidence <= 1)` — enforced at the DB level.\n- **Merge rules** are stored as JSONB in `identity_rules` table — the Twin reads them, never invents them.\n\nThis means our backend IP is portable, auditable, and version-controlled via migrations.\n\n---\n\n## ADR-4: Why an 8-Stage Pipeline\n\n```\nOAuth → Loader → Normalizer → Resolver → Router → Writer → Assembler → Trigger\n```\n\nEach stage has a single responsibility and communicates via Cloudflare Queue. Benefits:\n\n1. **Retry isolation** — a Normalizer failure doesn't re-fetch from the source API.\n2. **Stage-level metrics** — we know exactly where latency lives.\n3. **Independent scaling** — Resolver (identity matching) is CPU-heavy; Writer is I/O-heavy.\n4. **DLQ per stage** — dead letters are tagged with the failing stage for fast triage.\n\n---\n\n## ADR-5: Why Entity 360 Is the Single Read Surface for Twin\n\nThe Twin Trigger Engine never reads raw Spine tables. It reads the Entity 360 assembled view.\n\n| Concern    | Spine (Write)   | Entity 360 (Read)   | Twin (Reason)  |\n| ---------- | --------------- | ------------------- | -------------- |\n| Owns       | Raw entity rows | Assembled profiles  | Trigger logic  |\n| Reads from | Queues          | Spine tables        | Entity 360 API |\n| Writes to  | Spine DB        | Nothing (read-only) | Insight store  |\n\nThis boundary ensures the Twin cannot corrupt source data and always reasons over a consistent, assembled entity — not partial writes.\n\n---\n\n## ADR-6: Why Flow C Never Writes to Spine\n\nFlow C (Twin → Insight → UI) is a read-only reasoning path:\n\n1. Twin evaluates triggers against Entity 360 snapshots.\n2. Insights are written to `twin_insights` table (separate from Spine entity tables).\n3. UI reads insights via the Insight API.\n\n**Why:** If the Twin could write back to Spine, we'd create feedback loops — an insight could change an entity, which fires a new trigger, which generates a new insight. By keeping Flow C write-isolated from Spine, we guarantee convergence.\n\n---\n\n## Decision Log\n\n| ADR                           | Date    | Status   | Owner        |\n| ----------------------------- | ------- | -------- | ------------ |\n| ADR-1 Cloudflare Workers      | 2025-01 | Accepted | Platform     |\n| ADR-2 Spine DB                | 2025-01 | Accepted | Platform     |\n| ADR-3 Schema-as-IP            | 2025-02 | Accepted | Architecture |\n| ADR-4 8-Stage Pipeline        | 2025-02 | Accepted | Architecture |\n| ADR-5 Entity 360 Read Surface | 2025-03 | Accepted | Architecture |\n| ADR-6 Flow C Isolation        | 2025-03 | Accepted | Architecture |\n"}