first commit
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
# 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).
|
||||
Reference in New Issue
Block a user