{"slug":"business/FEATURE_ACTIVATION_SIMPLE","title":"Feature Activation: After OAuth, Everything is Available","section":"business","sectionLabel":"Business","status":"unclassified","type":"document","path":"business/FEATURE_ACTIVATION_SIMPLE.mdx","bytes":7065,"description":null,"updated":null,"source":"integratewise/Integratewise-docs-wiki","content":"\n\n> **Tier C — Historical.** This document is a point-in-time snapshot preserved for reference. For current architecture, see [CANONICAL_PLATFORM_ARCHITECTURE.md](../architecture/CANONICAL_PLATFORM_ARCHITECTURE.md).\n\n## Binary State Logic\n\n```\nNOT CONNECTED:\n  ├─ Show: \"Connect IntegrateWise\" button\n  └─ Click: Redirect to OAuth → Continue flow\n\nCONNECTED (Valid JWT):\n  ├─ Show: All 8 workbench projections\n  ├─ Show: Spine data (accounts, opportunities, invoices, etc.)\n  ├─ Show: Agent Lee recommendations\n  ├─ Show: Shared memory\n  ├─ Show: Decision logs\n  └─ Show: Task creation interface\n```\n\n---\n\n## Implementation\n\n### 1. Frontend: Check Token on Load\n\n**File**: `frontends/workbench/src/hooks/useAuth.ts`\n\n```typescript\n  const [isConnected, setIsConnected] = useState(false);\n  const [loading, setLoading] = useState(true);\n\n  useEffect(() => {\n    // Check localStorage for JWT token\n    const token = localStorage.getItem('integratewise_token');\n    \n    if (!token) {\n      setIsConnected(false);\n      setLoading(false);\n      return;\n    }\n\n    // Validate token with server\n    fetch('https://gateway.integratewise.com/api/v1/health', {\n      headers: { Authorization: `Bearer ${token}` }\n    })\n      .then(res => {\n        if (res.ok) {\n          setIsConnected(true);\n        } else {\n          localStorage.removeItem('integratewise_token');\n          setIsConnected(false);\n        }\n      })\n      .catch(() => {\n        setIsConnected(false);\n      })\n      .finally(() => setLoading(false));\n  }, []);\n\n  return { isConnected, loading };\n}\n```\n\n### 2. Frontend: Render Based on State\n\n**File**: `frontends/workbench/src/app/page.tsx`\n\n```typescript\n\n  const { isConnected, loading } = useAuth();\n\n  if (loading) return <div>Loading...</div>;\n\n  if (!isConnected) {\n    return (\n      <div className=\"h-screen flex items-center justify-center\">\n        <div className=\"text-center\">\n          <h1 className=\"text-4xl font-bold mb-4\">IntegrateWise</h1>\n          <p className=\"text-lg text-gray-600 mb-8\">\n            Connect your business systems\n          </p>\n          <ConnectButton />\n        </div>\n      </div>\n    );\n  }\n\n  // Connected: Show full workbench\n  return <Workbench />;\n}\n```\n\n### 3. Connect Button: Redirect to OAuth\n\n**File**: `frontends/workbench/src/components/ConnectButton.tsx`\n\n```typescript\n  const handleConnect = () => {\n    const redirect_uri = window.location.origin + '/auth/callback';\n    const app = detectPlatform(); // 'claude', 'chatgpt', etc.\n    const email = prompt('Your work email:');\n    const org_name = prompt('Organization name:');\n\n    if (!email || !org_name) return;\n\n    // Redirect to OAuth\n    window.location.href = \n      `https://integratewise.com/auth/authorize?` +\n      `app=${app}&` +\n      `redirect_uri=${encodeURIComponent(redirect_uri)}&` +\n      `email=${encodeURIComponent(email)}&` +\n      `org_name=${encodeURIComponent(org_name)}`;\n  };\n\n  return (\n    <button\n      onClick={handleConnect}\n      className=\"px-8 py-3 bg-blue-600 text-white rounded-lg font-semibold\"\n    >\n      Connect IntegrateWise\n    </button>\n  );\n}\n```\n\n### 4. OAuth Callback Handler\n\n**File**: `frontends/workbench/src/app/auth/callback/page.tsx`\n\n```typescript\n\n  const router = useRouter();\n\n  useEffect(() => {\n    // Get token from URL query params\n    const { token, tenant_id } = router.query;\n\n    if (!token) {\n      // No token, something went wrong\n      router.push('/');\n      return;\n    }\n\n    // Store token locally\n    localStorage.setItem('integratewise_token', token as string);\n    localStorage.setItem('tenant_id', tenant_id as string);\n\n    // Redirect to dashboard (triggers useAuth re-check, shows full workbench)\n    router.push('/');\n  }, [router]);\n\n  return <div>Connecting...</div>;\n}\n```\n\n---\n\n## API Routes: Protected with JWT\n\n### All Gateway Routes Require Valid Token\n\n**Pattern**:\n\n```typescript\n\nconst router = Router();\n\n// All routes require JWT + feature gate\nrouter.use(validateJWT);\nrouter.use(featureGate);\n\n// Now all routes have access to req.tenant_id, req.user_id\nrouter.get('/api/v1/spine/:entity', (req, res) => {\n  // req.tenant_id = 'tenant_id'\n  // Scope all queries by tenant_id automatically\n  \n  const { entity } = req.params;\n  \n  db.query(`\n    SELECT * FROM ${entity}\n    WHERE tenant_id = ?\n  `, [req.tenant_id])\n    .then(data => res.json(data))\n    .catch(err => res.status(500).json({ error: err.message }));\n});\n```\n\n---\n\n## Feature Visibility\n\n### Before OAuth\n\n```\nHome\n├─ \"Connect IntegrateWise\" button\n└─ Learn more...\n\nThat's it.\n```\n\n### After OAuth (Valid JWT)\n\n```\nHome (Workbench)\n├─ Sales Projection\n│  ├─ Pipeline\n│  ├─ Deals\n│  └─ Forecasts\n├─ Finance Projection\n│  ├─ AR/AP\n│  ├─ Cash Runway\n│  └─ Revenue Recognition\n├─ Customer Success Projection\n│  ├─ Health Scores\n│  ├─ Churn Risk\n│  └─ Expansion Opportunities\n├─ Agent Lee\n│  ├─ Ask a question\n│  └─ Get recommendations\n├─ Shared Memory\n│  ├─ Search past decisions\n│  └─ View similar scenarios\n├─ Decision Log\n│  ├─ View all decisions\n│  └─ Export audit trail\n└─ Tasks\n   ├─ Create task\n   └─ Sync to Jira/Asana\n```\n\n---\n\n## Multi-Frontend Consistency\n\nAll frontends see the same features because:\n\n1. ✅ OAuth handled by Continuity Bridge (one place)\n2. ✅ JWT validation happens in Gateway (one place)\n3. ✅ All frontends use same APIs (one place)\n4. ✅ Tenant scoping automatic (one place)\n\n**Result**: \n- Claude sees everything\n- ChatGPT sees everything\n- Perplexity sees everything\n- Replit sees everything\n- Lovable sees everything\n\nSame Spine. Same features. Different projection lens.\n\n---\n\n## Deployment\n\n- [ ] OAuth callback handler deployed\n- [ ] Token storage (localStorage) verified\n- [ ] JWT validation on all API routes\n- [ ] Feature gate on all routes\n- [ ] Test: Click connect → OAuth → Token stored → Workbench shows\n- [ ] Test: All 5 frontends see same features\n- [ ] Test: Logout → Token cleared → Show \"Connect\" button again\n\n---\n\n## Success\n\nUser perspective:\n- ❌ Click marketplace app → See \"Connect\" button\n- ✅ Click connect → OAuth → Redirected back with token\n- ✅ Token stored → All features available\n- ✅ Switch platforms → Same features, different lens\n\nEngineer perspective:\n- One OAuth endpoint\n- One JWT validation\n- One feature gate\n- Tenant scoping automatic\n- Binary state: connected or not connected\n\nThat's it.\n"}