Files
message-inbox-web-frontend-sdk/docs/ARCHITECTURE.md
T
2026-07-17 21:48:37 +05:30

96 lines
6.4 KiB
Markdown

# Architecture
## The one idea
Three product surfaces — **Messaging**, **Inbox**, **Support** — are built on **one kernel**:
a headless React SDK talking to a **BFF**. Everything a user sees is a projection of the same
data model, exactly like the IIOS "everything is an interaction" spine (see
[`IIOS_INTEGRATION.md`](IIOS_INTEGRATION.md)).
```
┌──────────────────────────────────────────────────────────────────────┐
│ Browser (Next.js app · apps/web) │
│ │
│ Components (nav / message / inbox / support / overlays) │
│ │ use hooks, never fetch directly │
│ ┌────▼───────────────────────────────────────────┐ │
│ │ @lynkd/messaging-inbox-sdk │ │
│ │ Provider · hooks · theme · feature flags │ │
│ │ BffClient ────────────────┐ │ │
│ └──────────────────────────────┼───────────────────┘ │
└──────────────────────────────────┼─────────────────────────────────────┘
│ fetch /api/bff/** (the ONLY seam)
┌──────────────────────────────────▼─────────────────────────────────────┐
│ BFF (Next.js route handlers · apps/web/app/api/bff/**) │
│ bootstrap · channels · messages · threads · reactions · inbox · │
│ support/tickets · search · notifications │
│ │ │
│ ┌────▼─────────────────────────┐ (swap this box for real) │
│ │ Mock store (in-memory) │ ──► IIOS service / NestJS / Supabase │
│ └──────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘
```
## Layers
### 1. SDK — `packages/messaging-inbox-sdk`
Framework-agnostic-ish React layer (needs React 18/19). No knowledge of Next.js, no backend
coupling.
- **`types.ts`** — the domain model. `User`, `Channel` (channel/private/dm/group_dm),
`Message` (+ parts, reactions, attachments, thread metadata), `InboxItem`, `Ticket`,
`Notification`, `SearchResult`, `Bootstrap`.
- **`config.ts`** — `FeatureFlags` + `ThemeConfig` + `resolveConfig()` (defaults → env → props).
- **`theme.ts`** — turns a `ThemeConfig` into CSS variables and applies them to `<html>`.
- **`client.ts`** — `BffClient`: one typed method per BFF endpoint. **The only place that
does `fetch`.**
- **`provider.tsx`** — `<MessagingInboxProvider>` holds config, the client, bootstrap data,
and theme/scheme state. Exposes `useSdk`, `useFeature(s)`, `useTheme`.
- **`hooks.ts`** — data hooks: `useChannels`, `useMessages`, `useThread`, `useInbox`,
`useTickets`, `useTicket`, `useSearch`, `useNotifications`, `useAvailability`, `useTyping`.
### 2. BFF — `apps/web/app/api/bff/**`
Next.js **Route Handlers**. This *is* the Backend-For-Frontend: it shapes data specifically
for this UI, keeps secrets/tokens server-side, and decouples the client from the real backend.
Today each handler calls the in-memory **mock store**; each maps 1:1 to a `BffClient` method.
### 3. Mock store — `apps/web/lib/mock/`
`data.ts` is the seed (a full LynkedUp-flavoured workspace). `store.ts` is a mutable singleton
(persists across requests in one Node process) implementing send/react/pin/save/patch/reply/
search. **This is the box you replace to go real** — nothing above it changes.
### 4. App shell + components — `apps/web/components`
- `nav/``WorkspaceRail` (Slack-style far-left), `Sidebar` (sectioned channels + user card),
`Header` (title + search + theme + notifications + user).
- `message/``ChannelView`, `MessageItem`, `Composer`, `ThreadPanel`, `EmojiPicker`.
- `inbox/``InboxView`.
- `support/``SupportView` (master-detail console).
- `overlays/``CommandPalette`, `NotificationsPanel`, `ProfileDrawer`, `ThemingPanel`,
`HuddleBar`.
- `ui/primitives.tsx``Avatar`, `PresenceDot`, `CountBadge`, `Chip`, `IconButton`.
- `AppShell.tsx` composes rail + sidebar + main + thread panel + overlays.
## Request lifecycle (send a message)
1. `Composer` calls `send(body)` from `useMessages(channelId)`.
2. The hook calls `client.sendMessage(channelId, body)``POST /api/bff/channels/:id/messages`.
3. The route handler calls `store.send(...)`, which appends a `Message` and bumps thread/channel
metadata, and returns it.
4. The hook appends the returned message to local state → it renders instantly.
Reactions, pins, saves, inbox transitions, and ticket replies follow the same shape.
## Config lifecycle (flags + theme)
1. `app/layout.tsx` (server) calls `getServerConfig()``resolveConfig({ env: process.env })`.
2. The resolved **plain** `SdkConfig` is passed to `<Providers config=…>` (client) and the
theme is inlined into `<head>` for a flash-free first paint.
3. `MessagingInboxProvider` applies theme vars to `<html>`, manages light/dark, and exposes
flags via `useFeature`.
## Why these choices
See [`../.claude/memory/architecture-decisions.md`](../.claude/memory/architecture-decisions.md)
for the rationale (workspace layout, BFF seam, server-resolved config, CSS-variable theming,
data-driven flags, and why the NestJS/DB backend is documented rather than built for this demo).