AI Customer Service Platform
A multi-tenant support platform where several businesses share one deployment: a unified conversation inbox across WhatsApp and Telegram, an AI assistant grounded in each tenant's own knowledge base, and an admin surface for the teams running it.

Product Context
context.mdA customer-service workspace that collects messages from WhatsApp and Telegram into one inbox, with an AI assistant that drafts replies from the tenant's knowledge base.
Support agents handling day-to-day conversations, and the admins who configure channels, articles and team access for each tenant.
Customers already message businesses on chat apps. Consolidating those threads and grounding answers in real documentation is what makes small teams able to keep up.
The Challenge
04 constraints- 01Tenant isolation the UI can be trusted onEvery request, cache entry and socket subscription has to be scoped to the active tenant. A single stale cache key is a data-leak bug, not a rendering bug.
- 02Live conversation stateMessages arrive from external channels at any moment while an agent is typing, filtering or switching threads. Optimistic updates must reconcile with server order.
- 03Grounding AI answersA generic model answer is worse than none. Replies need retrieval over the tenant's own content and a visible trail back to the source passage.
- 04Channel differencesWhatsApp and Telegram differ in message types, delivery semantics and attachment handling. The UI needs one mental model without lying about what a channel supports.
My Role
Frontend architecture, end to end.
I owned the Angular application and worked down the stack into the Rust API where the frontend's data shape demanded it.
Feature boundaries, tenant-scoped store design, routing and the shared component layer.
The assistant panel: suggestion states, streaming output, source citations and failure handling.
Defined the response shapes with the backend and implemented parts of the Axum service and its queries.
Accessibility for the inbox keyboard flow, render performance on long threads, and the testing strategy.
Architecture
06 layersTechnical Decisions
04 recordsEach decision below records what it cost as well as what it bought.
Knowledge Base
Answers are only as good as the source.
Each tenant curates its own articles. Documents are chunked and embedded on ingest, and every assistant reply surfaces the passages it drew from, so an agent can verify before sending.

Admin & Tenants

Switching tenant is a hard reset, by design.
Changing tenant tears down feature state and re-subscribes rather than merging caches. It costs a refetch and removes an entire class of cross-tenant bug.
Engineering Quality
08 dimensionsKeyboard navigation across inbox, thread and composer; live regions announce new messages; visible focus throughout.
Virtualised message lists, OnPush components, and lazily loaded feature routes.
Unit tests on reducers and selectors, component contract tests, Playwright on the send-and-reply path.
Typed failure states for send, retrieval and model timeouts, each with a recovery action rather than a toast.
One direction of data flow; derived data via selectors; no component reaching into another's state.
Standalone components split into container and presentational roles with typed inputs and outputs.
Three-pane desktop layout collapses to a stacked, one-view-at-a-time flow on small screens.
Feature-sliced folders, shared design-system primitives, and lint rules that block cross-feature imports.