PROJECT_INVENTORY
PROJECT_INVENTORY.md
Overview
This document maps the Alps codebase structure, key components, and recent architectural changes. <strong>Use this as context when reading specific files—do not read the whole tree.</strong>
Frontend Navigation & Shell Architecture
Migration Complete: Old SideBar → shadcn Sidebar-07
<strong>Status:</strong> ✅ Complete as of 2026-05-19
<strong>Old Pattern (DEPRECATED):</strong>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/components/SideBar.jsx</code> - Custom sidebar component (no longer used)
- Imported in 19+ page files with hardcoded ml-[250px] margins
- Status switching via localStorage and manual state updates
<strong>New Pattern (CANONICAL):</strong>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/</code> - shadcn sidebar-07 block with full backend integration
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/layout.js</code> - Wraps {children} with <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em"><ShellGate /></code> for route-based mounting
- Composable architecture: AppShell → AppSidebar → {TeamSwitcher, NavMain, NavUser}
- Real-time status, workspaces, notifications via Pusher + backend APIs
New Sidebar Components
| File | Purpose | Key Props/State |<br>|---|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/app-shell.tsx</code> | Root shell + backend wiring | Fetches user, workspaces, notifications; handles status/workspace updates |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/shell-gate.tsx</code> | Route-based conditional renderer | Allows: /inbox, /articles, /collections, /calls, /guides, /tickets, /reports, /workflows, /forms, /campaigns, /settings, /profile, /automation, /scribeReplica |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/app-sidebar.tsx</code> | Main sidebar orchestrator | Composes TeamSwitcher, NavMain, NavUser |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/team-switcher.tsx</code> | Workspace dropdown | teams[], activeIndex, onSelect, onAddTeam callbacks |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/nav-main.tsx</code> | Page navigation tree | Uses next/link, usePathname() for active state; auto-opens collapsibles |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/nav-user.tsx</code> | User dropdown + status switcher | 4-state radio group (online/away/busy/offline), notification badge, Account link |
Sidebar UI Primitives (Sandboxed)
All shadcn UI components live under <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/components/sidebar/ui/</code> to avoid conflicts with legacy <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/components/ui/*.jsx</code>:
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">sidebar.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">sheet.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">dropdown-menu.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">tooltip.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">collapsible.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">avatar.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">breadcrumb.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">skeleton.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">button.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">input.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">separator.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">card.tsx</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">tabs.tsx</code>
<strong>Why sandboxed:</strong> The codebase has legacy custom UI components (Button.jsx, etc.) in <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">asset/components/ui/</code>. The new shadcn primitives needed their own namespace to avoid file collision and ensure both systems can coexist during migration.
Backend Integration (AppShell)
<strong>API calls made on mount:</strong>
<strong>Real-time updates:</strong>
- Pusher subscription to <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">private-workspace-{workspaceId}-notifications</code> channel
- Increments/decrements notificationCount on <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">notification.new</code> / <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">notification.read</code> events
<strong>Status mapping (bidirectional):</strong>
<strong>Callbacks:</strong>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">switchWorkspace(workspaceId)</code> → updates localStorage, fires <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">alps:workspace-switched</code> event, reloads page
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">updateAgentStatus(status)</code> → calls backend, updates local state, Pusher broadcasts to team
Pages Updated (SideBar Removed)
All instances of <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">import SideBar from '@asset/components/SideBar'</code> and <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em"><SideBar /></code> removed from:
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/articles/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/collections/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/forms/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/guides/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/campaigns/page.jsx</code> (also removed ml-[250px] margin wrapper)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/workflows/page.jsx</code> (also removed ml-[250px] margin wrapper)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/reports/page.jsx</code> (also removed ml-[250px] margin wrapper)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/reports/help-center-analytics/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/reports/performance-metrics/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/reports/team-performance/page.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/ContactsPages/ContactsView.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/TicketsPages/Tickets.jsx</code> (layout changed from ml-[250px] to full-width)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/TicketsPages/EachTicket.jsx</code> (removed from 3 return statements)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/ContactsPages/ContactDetail.jsx</code> (removed from 3 return statements)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/CallsPages/Calls.jsx</code>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/CallsPages/CallDetail.jsx</code> (removed from 2 return statements)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/InboxPages/InboxContent.jsx</code> (removed ml-[250px] dynamic spacing)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/SettingsShell.jsx</code> (removed sidebarCollapsed state and callback)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/components/Profile.jsx</code> (removed ml-[250px] margin)
Path Aliases
Both <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/tsconfig.json</code> and <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/jsconfig.json</code> now define:
This enables shadcn CLI to generate components under <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">@/components/sidebar/</code> correctly.
Backend
Express API
| Thing | Detail |<br>|---|---|<br>| Entry point | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/server.js</code> |<br>| Port | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">process.env.PORT</code> (default 3030) |<br>| Start (prod) | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">npm start</code> → <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">node server.js</code> |<br>| Start (dev) | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">npm run dev</code> → <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">nodemon server.js</code> |<br>| Config | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/config/</code> + <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">.env</code> |<br>| Routes | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/routes/</code> - all mounted at <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">/api/v1/</code> |<br>| Controllers | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/controllers/</code> |<br>| Models | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/models/</code> - 17 Mongoose models (migrating to Firestore) |<br>| Services | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">workflowEngine.js</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">imapService.js</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">emailService.js</code> |<br>| Real-time | Socket.io (server.js) + Pusher (via frontend) |<br>| Workers | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">worker.js</code> (Heroku one-off), <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">clock.js</code> (scheduler), <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">scheduler.js</code> (cron) |<br>| Hosting | Heroku → migrating to Google Cloud Run |<br>| Database | MongoDB Atlas → Firebase Firestore |<br>| Auth | Firebase Authentication (migrating from custom JWT) |
<strong>Key env vars:</strong>
Key Backend Files
| File | Purpose |<br>|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/controllers/messageController.js</code> | Conversation inbox, send message, assign, priority, status, WhatsApp webhook |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/controllers/inbox.controller.js</code> | Inbox CRUD, channel add/remove (email → imapService), workspace settings |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/controllers/auth.controller.js</code> | Firebase Auth token verification, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">protect</code> middleware |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/controllers/contact.controller.js</code> | Contact CRUD |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/routes/message.route.js</code> | Routes: /customer (public), /send, /inbox, /conversations/:id/assign\|close\|status\|labels\|priority |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/services/imapService.js</code> | Singleton IMAP polling; <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">initializeAllActive()</code> on server start |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/services/emailService.js</code> | SMTP send via nodemailer |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/utils/firestore.js</code> | Firestore <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">db</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">getDoc</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">setDoc</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">serverTimestamp</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">arrayUnion</code>, <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">arrayRemove</code> |
Firebase Firestore Collections
| Collection | Replaces | Notes |<br>|---|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">users</code> | User | doc ID = Firebase Auth UID |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">workspaces</code> | Workspace | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">profiles</code> | Profile | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">domain</code> field drives *.tryalps.app |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">articles</code> | Article | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">categories</code> | Category | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">conversations</code> | Conversation | fields: workspaceId, inboxId, status, priority, assignedToId, labels[], customer{name,email}, lastMessageAt |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">messages</code> | Message | fields: conversationId, direction, senderType, isNote, content, read, createdAt (flat, not subcollection) |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">contacts</code> | Contact | linked to conversations |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">workflows</code> | Workflow | nodes array embedded |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">imapConfigs</code> | ImapConfig | per-workspace IMAP settings |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">inboxLabels</code> | InboxLabel | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">playlists</code> | Playlist | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">guides</code> | Guide | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">supportTickets</code> | SupportTicket | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">supportRequests</code> | SupportRequest | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">invoices</code> | Invoice | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">transactions</code> | Transaction | |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">emptySearches</code> | EmptySearches | |
Frontend Pages & Components
Key Frontend Files
| File | Purpose |<br>|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/InboxPages/DefaultView.jsx</code> | Conversation list + ChatBox layout; Pusher workspace channel |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/InboxPages/ChatBox.jsx</code> | Message thread, send reply, notes, Pusher conversation channel |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/InboxPages/UserDetails.jsx</code> | Right sidebar: contact info, priority, assign, recent convs, labels |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/InboxPages/InboxContent.jsx</code> | Wraps DefaultView, passes userData |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/services/request.js</code> | All Axios API calls - auth token from localStorage.getItem('alpsToken') |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/api/widget/widgetScript.js</code> | Full widget JS (~1992 lines) |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/api/widget/widget-content.js</code> | Widget HTML content helper |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">test-widget.html</code> | Dev test page |
Conversation Data Shape
Widget Identity Model
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">data-user-id</code> on script tag = <strong>widget key</strong> (inbox/channel key)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">data-user-name</code> / <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">data-user-email</code> = visitor identity if host app provides it
- localStorage <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">alps-visitor-{widgetKey}</code> = stored visitor identity for anonymous visitors
- Pre-chat form shown when neither script attrs nor localStorage has name+email
Configuration
Subdomain Routing (*.tryalps.app)
- Wildcard DNS (<code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">*.tryalps.app</code>) → Vercel
- Each user's <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">Profile.domain</code> = their slug
- Backend CORS allows any <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">*.tryalps.app</code> origin
- No subdomain routing in Next.js middleware; backend resolves identity from <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">Organization</code> header or profile slug lookup in Firestore
Firestore Indexes
<code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">getInbox</code> fetches without <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">orderBy</code> (avoids composite index) and sorts in memory.<br>When ready to deploy proper indexes: <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">firebase deploy --only firestore:indexes</code> using <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">firestore.indexes.json</code>.
Firebase Migration Status
<strong>Phase Progress:</strong>
- [x] Phase 1: Firebase project setup
- [x] Phase 2: Auth migration (JWT → Firebase Auth)
- [x] Phase 3: Database migration (Mongoose → Firestore)
- [x] Phase 4: Frontend auth update
- [x] Phase 5: Server hosting (Heroku → Cloud Run)
- [ ] Phase 6: Decommission MongoDB Atlas + Heroku
See <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/FIREBASE<em>SETUP.md</code> and <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/CLOUD</em>RUN_SETUP.md</code> for details.
knowledge-base/ App (Public Help Center)
<strong>Location:</strong> <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">Alps/knowledge-base/</code> (separate Next.js 16 app, deployed independently)
<strong>Purpose:</strong> Public-facing help center at <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">{slug}.tryalps.app</code> — no auth required, all data from Alps API.
Stack
- Next.js 16 (App Router, TypeScript, Turbopack)
- Tailwind CSS + @tailwindcss/typography
- No Shadcn (standalone app with custom CSS vars)
Three Themes (profile.themeType)
| Theme | Style | Key files |<br>|---|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">nexus</code> | Developer docs (Next.js docs style) — left sidebar nav | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">components/themes/nexus/</code> |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">clarity</code> | Help center (Notion/Intercom style) — sticky nav, full-width | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">components/themes/clarity/</code> |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">prism</code> | Modern bold (Linear/Vercel style) — dark header, numbered sections | <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">components/themes/prism/</code> |
API (all public, no auth)
| Endpoint | Purpose |<br>|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">GET /user/get-profile/:slug</code> | Workspace profile (colours, fonts, header, hero, footer, social) |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">GET /user/widget-data/:widgetKey</code> | Published categories + articles |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">PATCH /article/:id/views</code> | Track view (fire-and-forget) |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">PATCH /article/:id/upvote</code> | Upvote article |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">PATCH /article/:id/downvote</code> | Downvote article |
Key files
| File | Purpose |<br>|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">proxy.ts</code> | Subdomain middleware: extracts slug from host, sets <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">x-workspace-slug</code> header |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">app/layout.tsx</code> | Root layout: fetches profile, injects CSS vars, Google Fonts, favicon, GA4 |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">app/page.tsx</code> | Home: routes to NexusHome / ClarityHome / PrismHome by themeType |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">app/[categorySlug]/page.tsx</code> | Category detail page |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">app/[categorySlug]/[articleSlug]/page.tsx</code> | Article page (tracks view) |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">app/search/page.tsx</code> | Search results (client-side filter) |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">lib/api.ts</code> | fetch wrappers for all 5 endpoints |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">lib/types.ts</code> | Profile, Category, Article types |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">components/shared/ArticleVoting.tsx</code> | Client-side upvote/downvote widget |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">components/shared/SearchBar.tsx</code> | Client-side inline search with dropdown results |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">components/shared/SearchPage.tsx</code> | Full search page with URL sync |
Dev
AI Integration (New - May 2026)
<strong>Status</strong>: ✅ Phase 1 complete — Local Ollama + Chroma setup, AI routing in workflow engine
Infrastructure
- <strong>Ollama</strong> (local LLM inference): <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">http://localhost:11434</code>
- <strong>Chroma</strong> (vector database): <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">http://localhost:8000</code>
- <strong>Models</strong>:
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">nomic-embed-text</code> (embeddings, 275MB, ~100ms per request)<br> - <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">llama3.2:3b</code> (text generation, for future features)<br> - <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">mistral:7b</code> (optional, better quality)
Backend Files
| File | Purpose | Status |<br>|---|---|---|<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">services/aiService.js</code> | Ollama + Chroma client wrapper | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">controllers/ai.controller.js</code> | AI endpoints (embed, classify, route) | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">routes/ai.route.js</code> | POST /api/v1/ai/* routes | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">services/workflowEngine.js</code> | Added <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">ai_route</code> node type | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">scripts/embedConversations.js</code> | Batch export + embed conversations | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">docker-compose.yml</code> | Ollama + Chroma containers | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">AI_SETUP.md</code> | Installation & setup guide | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">AI_QUICKSTART.md</code> | 5-minute getting started | ✅ Complete |<br>| <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">AI_TESTING.md</code> | Testing & iteration guide | ✅ Complete |
Key Features (Live)
- <strong>Intelligent Inbox Routing</strong> via embedding-based similarity
- Workflow node: <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">ai_route</code><br> - Embed incoming message → find 3 most similar historical conversations → route to same inbox<br> - Fallback: continues to next workflow node if no matches
- <strong>AI Service Health Check</strong>: <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">GET /api/v1/ai/health</code>
- <strong>Embedding Status</strong>: <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">GET /api/v1/ai/embedding-status</code> (shows % of conversations embedded)
Usage
<strong>Enable in workflow</strong>:
- Create workflow node of type <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">ai_route</code>
- Node automatically routes based on conversation content
<strong>Batch embed conversations</strong> (data prep):
<strong>Monitor</strong>: Activity log shows routing confidence (e.g., "routed to inbox_billing (87.3% confidence)")
AI Settings & Configuration (NEW)
Purpose
Full UI for configuring AI agent personality, training data, data access permissions, and auto-escalation rules.
New Files Created
<strong>Frontend:</strong>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/app/settings/alps-ai/page.jsx</code> — Route entry point
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/index.jsx</code> — Main tabs component (owns data load/save + tab state)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/TrainTab.jsx</code> — Q&A, documents, websites, KB toggle
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/AgentTab.jsx</code> — Avatar upload, name, persona, business description
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/AccessTab.jsx</code> — Data permission toggles (conversations, contacts, location)
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/EscalationTab.jsx</code> — Auto-escalation toggles + inbox selector
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/components/ToggleRow.jsx</code> — Reusable toggle + label + description row
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/components/QnaPanel.jsx</code> — Q&A table + inline add form
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/components/DocumentsPanel.jsx</code> — File upload (.pdf/.docx/.txt) + status list
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/SettingsPages/AiAgentPage/components/WebsitesPanel.jsx</code> — URL input + crawl status list
<strong>Backend:</strong>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/controllers/ai.controller.js</code> — 9 new handlers: getAiSettings, updateAiSettings, addQna, deleteQna, uploadDocument, deleteDocument, addWebsite, deleteWebsite, uploadAgentAvatar
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">backend/routes/ai.route.js</code> — 9 new routes mounted under <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">/api/v1/ai/settings/*</code>
<strong>API Helpers (added to <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">frontend/asset/services/request.js</code>):</strong>
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">getAiSettings()</code> — Load full AI configuration
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">updateAiSettings(body)</code> — Save agent/access/escalation settings
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">addAiQna(qna)</code> / <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">deleteAiQna(id)</code> — Q&A CRUD
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">uploadAiDocument(file)</code> / <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">deleteAiDocument(id)</code> — Document upload + delete
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">addAiWebsite(url)</code> / <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">deleteAiWebsite(id)</code> — Website URL CRUD
- <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">uploadAgentAvatar(file)</code> — Avatar upload
Data Storage (Firestore)
<strong>Location:</strong> <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">workspace.aiSettings</code> nested field + <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">workspaces/{id}/ai<em>training</em>items</code> subcollection
<strong>Why subcollection:</strong> Training data (Q&A pairs, document metadata, website URLs) stored separately to avoid 1MB Firestore document size limit.
UI Integration
<strong>SettingsShell updates:</strong>
- Added "Alps AI" menu group between "Support Configurations" and "Help Center"
- New menu entry with Bot icon → navigates to <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em">/settings/alps-ai</code>
- New switch case rendering <code style="font-family:ui-monospace,monospace;background:#f1f5f9;color:#dc2626;padding:0.1em 0.35em;border-radius:3px;font-size:0.875em"><AiAgentPage /></code>
Next Steps (Roadmap)
- [ ] Sentiment analysis (auto-priority on angry customers)
- [ ] Suggested replies (AI copilot for agents)
- [ ] Conversation summarization (TL;DR button)
- [ ] Knowledge base RAG (AI bot answers from KB)
- [ ] Fine-tuning on real routing data (Tier 3, ~$5 via LoRA)
- [ ] Production deployment (Oracle Cloud Always Free or Hetzner ~€10/mo)
Dependencies Added
Environment Variables
Last Updated
- <strong>2026-05-27:</strong> AI integration Phase 1 — Ollama + Chroma local setup, semantic inbox routing, 15 planned use cases.
- <strong>2026-05-26:</strong> knowledge-base/ public help center app created (Next.js 16, 3 themes, no auth).
- <strong>2026-05-19:</strong> Sidebar migration complete - old SideBar removed from 19 files, new shadcn shell (AppShell → ShellGate) in place with full backend integration (workspaces, status switching, notifications via Pusher).
Did this answer your question?