{"slug":"architecture/l1-reality-check","title":"L1 Reality Check — Current Codebase vs. Canonical Architecture","section":"architecture","sectionLabel":"Architecture","status":"unclassified","type":"document","path":"architecture/l1-reality-check.mdx","bytes":15442,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n**Version:** 1.0.0-REALITY  \n**Date:** 2026-07-02  \n**Purpose:** Brutal audit of the actual `integratewiseosmain` codebase against the FINAL_E2E_SYSTEM.md canonical architecture. Flags every live conflict, maps audit findings to §14/§15 blockers, and defines the fork-vs-rewrite decision.\n\n---\n\n## 1. The Audit Summary (171d Ago v0 Session)\n\n| Finding                                | Count       | Canonical Rule                | Status          |\n| -------------------------------------- | ----------- | ----------------------------- | --------------- |\n| Total pages                            | 83          | ~25 (core app only)           | **Bloat**       |\n| Marketing pages                        | 50+         | Should be on Webflow          | **Scope creep** |\n| Duplicate layouts                      | 7           | 5 max                         | **Debt**        |\n| Tables with RLS enabled, ZERO policies | 30+         | D1 + `WHERE tenant_id = ?`    | **§14.1 Live**  |\n| Hardcoded hex colors                   | 40+ files   | CSS variables / design tokens | **Debt**        |\n| `@iw/*` namespace                      | 25+ files   | `@integratewise/*`            | **Drift**       |\n| Missing SpeedInsights                  | 1           | Standard L1 feature           | **Incomplete**  |\n| Missing demo seeds                     | 0 scripts   | Required for onboarding       | **Incomplete**  |\n| Missing unified theme                  | 1           | 7× UI agnostic moat           | **Blocks moat** |\n| `tsconfig.json` JSX mode               | `react-jsx` | `preserve` (Next.js req)      | **Fixed**       |\n| `.npmrc` / pnpm config                 | Incomplete  | `shamefully-hoist=true`       | **Fixed**       |\n\n---\n\n## 2. The Canonical Conflicts That Are Still Live\n\n### §14.1: Storage/Runtime — 4 Backends (SUPERSEDED BUT NOT IMPLEMENTED)\n\n**Canon (§20.2 FINAL):** 100% Cloudflare — D1, DO, KV, R2, Vectorize, AI Search, Queues. No Supabase / Vercel / AWS / Neon.\n\n**Actual codebase:**\n\n- Next.js 16 + `tsconfig.json` with JSX `preserve` → **Vercel**\n- `supabase` import in `tsconfig.json` paths → **Supabase**\n- 30+ RLS-enabled tables with auth.users references → **Supabase Auth + PostgreSQL**\n- `middleware.ts` with Supabase session validation → **Supabase Auth**\n- `page.tsx` files with `supabase.from('table').select()` → **Supabase client**\n\n**Verdict:** The FINAL decision says \"Supabase removed\" but the codebase is **deeply entangled** with Supabase Auth, RLS, and PostgreSQL queries. This is the #1 blocker.\n\n**Options:**\n\n| Option                                                | Effort           | Risk                                                                    | Template Timeline |\n| ----------------------------------------------------- | ---------------- | ----------------------------------------------------------------------- | ----------------- |\n| A. In-place migration (Supabase → D1)                 | 2–3 months       | High — every query, every auth flow, every RLS policy must be rewritten | Month 4+          |\n| B. **Fork: new Vite workbench + keep legacy Next.js** | 1 month parallel | Low — CZ stays running, new repo is clean                               | Month 2–3         |\n| C. Keep Supabase, call it \"provider-agnostic\"         | 0 months         | Fatal — contradicts DECISION 22, template teaches wrong architecture    | Never             |\n\n**Recommendation: Option B.**\n\n### §14.2: Auth Model — Clerk vs Stack vs Descope vs JWT (SUPERSEDED BUT NOT IMPLEMENTED)\n\n**Canon (§20.2 FINAL):** API Keys (external) + JWT (internal). Clerk/Stack/Descope **removed**.\n\n**Actual codebase:**\n\n- `middleware.ts` with `supabase.auth.getSession()`\n- `auth/callback/route.ts` with Supabase OAuth\n- `auth/confirm/route.ts` with Supabase email verification\n- RLS policies expecting `auth.uid()` — but **zero policies written**\n\n**Verdict:** Auth is still Supabase Auth. The \"thrashed\" Clerk/Stack/Descope migration never reached this repo — it went from Supabase to nothing else. But Supabase Auth is **not** the canonical JWT Gateway auth.\n\n**Fix for legacy repo:** Wrap Supabase Auth in a Gateway JWT facade. The Next.js app receives a Gateway JWT (from `gateway` Worker), validates it, and maps `tenant_id` from the JWT claim. Supabase becomes a **data store** only, not the auth source.\n\n**Fix for new repo:** `apps/workbench` uses Gateway JWT directly. No Supabase Auth SDK.\n\n### §14.3: Frontend Host — Replit vs Vite vs Next.js/Vercel (SUPERSEDED BUT NOT IMPLEMENTED)\n\n**Canon (§20.2 FINAL):** `apps/web` = Vite + React + shadcn/ui on Cloudflare Pages. Not Next.js. Not Vercel. Not Replit.\n\n**Actual codebase:** Next.js 16 + Vercel + `app/` directory + Server Components.\n\n**Verdict:** This is the **deepest entanglement**. Next.js App Router + Server Components + Supabase RLS is a completely different paradigm from the Vite + React + Cloudflare Pages architecture in the FINAL spec.\n\n**Decision:** The existing Next.js app is **not** the canonical workbench. It is a **legacy surface** that will consume the Bridge via SDK. The canonical workbench is built fresh in `apps/workbench` (Vite + React + shadcn/ui).\n\n### §14.6: Capability-First APIs (GREENFIELD — NOT YET BUILT)\n\n**Actual codebase:** Conventional Next.js API routes (`/api/ai/insights`, `/api/ai/analyze`). No capability registry. No Discovery endpoint. No `iw.*` SDK facade.\n\n**Verdict:** The entire capability-first layer is **greenfield**. It doesn't exist yet in any form. This is not a conflict — it's a missing feature.\n\n### §14.8: Twin Model Provider (RESOLVED IN CODE?)\n\n**Actual codebase:** `useAIInsights.ts` and `useAIAgent.ts` call `gpt-4o` directly via OpenAI SDK. No OpenRouter. No model swappability.\n\n**Verdict:** Direct OpenAI calls, not OpenRouter. Not gpt-5-mini. The model layer is **hardcoded**.\n\n---\n\n## 3. The P0 Blockers — Which Are Real in the Codebase\n\n| P0 # | Description                  | Present in Codebase? | Evidence                                                                                     |\n| ---- | ---------------------------- | -------------------- | -------------------------------------------------------------------------------------------- |\n| 1    | Cross-tenant data leak       | **YES**              | 30+ tables with RLS enabled but **zero policies** — any authenticated user can read all rows |\n| 2    | Tenant-id spoofing           | **YES**              | `supabase.from('table').select()` — no `tenant_id` filtering in most queries                 |\n| 3    | Tenant middleware no-op      | **YES**              | `middleware.ts` validates session but does not enforce `tenant_id` scoping on requests       |\n| 4    | HITL DO global ID            | **N/A**              | No Durable Objects in codebase — this is a Cloudflare-only concern                           |\n| 5    | Invitation cross-tenant scan | **LIKELY**           | `auth/invites` logic not audited in snippet                                                  |\n| 6    | Hardcoded secrets            | **CHECK**            | `.env` files not visible in audit; need to verify git history                                |\n| 7    | `.env` committed             | **CHECK**            | Need to verify git history                                                                   |\n| 8    | SQL injection in shims       | **PARTIAL**          | `supabase.from()` is parameterized, but raw SQL in `db.sql` file not audited                 |\n| 9    | MCP-JWT bypass               | **YES**              | No MCP server exists in codebase at all                                                      |\n| 10   | Auth root thrashing          | **PARTIAL**          | Auth is Supabase (stable), but not the canonical Gateway JWT                                 |\n\n**Critical finding: P0 #1 is catastrophic.** 30+ tables with RLS enabled but zero policies means **any authenticated user can read any other tenant's data**. This is not a theoretical risk — it's a live vulnerability.\n\n---\n\n## 4. The Fork Decision — Canonical vs. Legacy\n\nGiven the depth of entanglement, the only viable path is a **dual-repo strategy**:\n\n### Repo A: `integratewise-continuity-bridge` (NEW — Canonical Template)\n\n```\nintegratewise-continuity-bridge/\n├── apps/\n│   ├── gateway/              ← NEW — Hono + JWT + service bindings\n│   ├── workbench/            ← NEW — Vite + React + shadcn/ui + 8 projections\n│   └── mcp-server/           ← NEW — Inbound MCP Pool\n├── packages/\n│   ├── spine-schema/         ← NEW — Drizzle + D1 + withTenant()\n│   ├── normalizer/           ← NEW — NA0–NA5 skeleton\n│   ├── sdk/                  ← NEW — @integratewise/sdk\n│   └── ...\n├── services/                 ← NEW — 26 Cloudflare Worker stubs\n└── infra/                    ← NEW — wrangler.toml, D1 migrations, KV, Queues\n```\n\n**This is the publishable template.** It matches FINAL_E2E_SYSTEM.md exactly.\n\n### Repo B: `integratewiseosmain` (EXISTING — Legacy CZ Surface)\n\n```\nintegratewiseosmain/\n├── Next.js 16 + Vercel       ← KEEP (CZ runs here)\n├── Supabase                  ← WRAP (don't rip out yet)\n├── 83 pages                  ← DELETE 50+ marketing pages\n└── ...\n```\n\n**This becomes a consumer of the Bridge.** Gradually migrate:\n\n1. **Week 1–2:** Wrap Supabase queries in `@integratewise/sdk` calls. The SDK talks to the Bridge; the Bridge talks to Supabase (temporary adapter).\n2. **Week 3–4:** Move auth from Supabase Auth to Gateway JWT. Supabase becomes read-only data store.\n3. **Month 2:** Once D1 has all data, cut Supabase reads. Supabase is removed.\n\n---\n\n## 5. Immediate Actions (This Week)\n\n### 5.1 Security — Close P0 #1 (Cross-Tenant Leak)\n\nEven if you keep Supabase temporarily, add `tenant_id` filtering to every query:\n\n```typescript\n// BEFORE (vulnerable — any user reads all rows)\nconst { data } = await supabase.from(\"accounts\").select(\"*\");\n\n// AFTER (scoped — user reads only their tenant)\nconst tenantId = jwt.tenant_id; // from Gateway JWT\nconst { data } = await supabase.from(\"accounts\").select(\"*\").eq(\"tenant_id\", tenantId);\n```\n\n**All 30+ tables need this fix.** No exceptions.\n\n### 5.2 Scope — Delete 50+ Marketing Pages\n\n```bash\n# Remove from integratwiseosmain\nrm -rf app/blog\nrm -rf app/case-studies\nrm -rf app/company\nrm -rf app/docs\nrm -rf app/platform\nrm -rf app/pricing\nrm -rf app/resources\nrm -rf app/security\nrm -rf app/solutions\n```\n\nThese belong on Webflow (§17 GTM). They're not part of the Continuity Bridge. The remaining 25 pages should be:\n\n- User Workbench (dashboard, accounts, deals, tasks)\n- Twin Workbench (AI reasoning, proposals)\n- My Desk (approvals, governance)\n- Settings (connector management, tenant config)\n- Admin (tenant mgmt — if admin role)\n\n### 5.3 Namespace — Finish `@iw/` → `@integratewise/` Migration\n\n```bash\n# Find all remaining @iw/ references\ngrep -r \"@iw/\" --include=\"*.ts\" --include=\"*.tsx\" --include=\"*.json\" .\n\n# Replace\nsed -i '' 's/@\\b iw\\b /@integratewise/g' $(grep -rl \"@iw/\" --include=\"*.ts\" --include=\"*.tsx\" --include=\"*.json\" .)\n```\n\nUpdate `tsconfig.json` paths:\n\n```json\n{\n  \"compilerOptions\": {\n    \"paths\": {\n      \"@integratewise/*\": [\"./src/*\"],\n      \"@integratewise/types\": [\"./types/*\"],\n      \"@integratewise/ui\": [\"./components/ui/*\"]\n    }\n  }\n}\n```\n\n### 5.4 Auth — Wrap Supabase in Gateway JWT\n\n```typescript\n// middleware.ts — BEFORE (Supabase session)\nconst {\n  data: { session },\n} = await supabase.auth.getSession();\n\n// middleware.ts — AFTER (Gateway JWT)\nconst jwt = await verifyGatewayJWT(req.headers.get(\"Authorization\"));\nconst tenantId = jwt.tenant_id; // extracted from claim, not client payload\nreq.headers.set(\"x-tenant-id\", tenantId);\n```\n\nThe Supabase session is **not** the source of truth. The Gateway JWT is.\n\n---\n\n## 6. What This Means for the Template\n\n| Milestone                                          | Blocked By                               | ETA       |\n| -------------------------------------------------- | ---------------------------------------- | --------- |\n| Publish `integratewise-continuity-bridge` template | P0 #1–10 in NEW repo                     | Month 2–3 |\n| Close P0 #1 in legacy repo                         | Add `tenant_id` to all 30+ tables        | This week |\n| Close P0 #9 (MCP-JWT)                              | Build `apps/mcp-server` in new repo      | Month 1   |\n| Close P0 #10 (Auth freeze)                         | Remove Supabase Auth, deploy Gateway JWT | Month 1   |\n| De-Supabase (DECISION 22)                          | Migrate data from Supabase → D1          | Month 2–3 |\n\n**The template is NOT a fork of the current codebase.** The template is a **new repo** built to the canonical spec. The current codebase is the **legacy surface** that will gradually consume the Bridge.\n\n---\n\n## 7. The Honest Assessment\n\n| Claim                                | Reality                         | Gap         |\n| ------------------------------------ | ------------------------------- | ----------- |\n| \"100% Cloudflare\"                    | Next.js + Vercel + Supabase     | **Massive** |\n| \"26 services, service bindings\"      | 0 Cloudflare Workers            | **Massive** |\n| \"MCP-first ingress\"                  | 0 MCP server code               | **Massive** |\n| \"Gateway JWT\"                        | Supabase Auth                   | **Large**   |\n| \"Capability-first APIs\"              | Conventional Next.js API routes | **Large**   |\n| \"One full UI, 8 projections\"         | 83 pages, 50+ marketing pages   | **Medium**  |\n| \"@integratewise/sdk\"                 | `@iw/*` in 25+ files            | **Small**   |\n| \"Design tokens, no hardcoded colors\" | 40+ hardcoded hex files         | **Medium**  |\n\n**The architecture is 6–12 months ahead of the codebase.** This is not a criticism — it's a common pattern for ambitious systems. The FINAL spec is the **target**; the L1 audit is the **baseline**. The gap is the work.\n\n**The only question:** Do you build the template from the current codebase (Option A: 3-month rewrite), or do you fork (Option B: parallel build)?\n\nGiven the 83-page bloat, the Supabase entanglement, and the Next.js/Vercel lock-in, **Option B is the only viable path.** The current codebase is a valuable Customer-Zero deployment. The new repo is the canonical future.\n\n---\n\n## 8. Next Steps\n\n1. **This week:** Close P0 #1 (cross-tenant leak) in legacy repo. Add `tenant_id` to all 30+ Supabase queries.\n2. **This week:** Delete 50+ marketing pages. Consolidate to 25 core pages.\n3. **Week 2:** Create `integratewise-continuity-bridge` repo. Scaffold `apps/gateway`, `apps/workbench`, `apps/mcp-server`.\n4. **Week 3:** Deploy Gateway JWT. Wrap Supabase Auth in legacy repo.\n5. **Month 1:** Build MCP server with JWT guard. Test inbound MCP with Cursor.\n6. **Month 2:** Build D1 schema, migrate one table (e.g., `accounts`), test `withTenant()`.\n7. **Month 3:** Full de-Supabase. Template publish.\n\n---\n\n**END OF DOCUMENT**\n\n_This is the companion reality check to FINAL_E2E_SYSTEM.md. It exists to prevent the template from being built on fiction. The architecture is correct. The codebase is real. The gap is the work._\n"}