first commit

This commit is contained in:
2026-07-17 21:48:37 +05:30
commit f85599dac5
124 changed files with 10775 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
---
name: features-and-modes
description: The full Slack-grade feature set, the two backend modes, and how to run IIOS live
metadata:
type: project
---
**Two backend modes** (env `BFF_BACKEND` in `apps/web/.env.local`, read server-side):
- `mock` (default) — rich in-memory JSON workspace; every feature works & persists in-process.
Best for demos. Data in `apps/web/lib/mock/data.ts` + `store.ts`.
- `iios` — proxies the live IIOS NestJS service (real Postgres). Seeded via
`node scripts/seed-iios.mjs` which writes `apps/web/lib/iios/seed-manifest.json` (real thread
ids → channel directory). Bootstrap/channels come from the manifest; messages/inbox/tickets
from IIOS live. Verified: 5 channels + 6 users + messages render through the app BFF.
**Running IIOS live (no Docker):** native PostgreSQL 18, role `iios`/`iios`, db `iios` on 5432
(a separate 5434 cluster crashes under the sandbox's process limits). `packages/iios-service/.env`
`DATABASE_URL=postgresql://iios:iios@localhost:5432/iios?schema=public`, `IIOS_DEV_TOKENS=1`.
Build: allow prisma/esbuild in `D:\iios\pnpm-workspace.yaml`, `pnpm install && pnpm -r build`,
prisma `generate` + `migrate deploy`, `node packages/iios-service/dist/main.js`. Redis NOT needed
(in-memory socket adapter without `REDIS_URL`). Full steps: `docs/IIOS_INTEGRATION.md`.
**Slack-grade features (all working, verified via Playwright):** channels/DMs/threads;
WYSIWYG composer (bold/italic/code/lists); **@mention + #channel autocomplete** (typing pops a
picker; rendered as blue chips by `lib/rich-text.tsx`); **full searchable emoji picker** (168,
categorized, `lib/emoji.ts`) in composer + reactions + status; **`:shortcode:` → emoji** (`:tick:`
→ ✅); reactions (hover picker fixed); pins; **save** (+ Saved page); **message edit + delete**;
**attachment upload** (file → data-URL preview → send → image preview + Open/Download); scheduled
send; huddles; **status** (emoji picker + clear-after incl. custom datetime); **avatar change**
(color swatches + image upload); **copy message link + jump-to-message** (scroll); **thread "also
send to channel"**; command palette (⌘K, arrow-nav); notifications; sidebar collapse; inbox;
Support Center; light/dark + live theming.
**AI + translation (Gemini, server-side only):** `apps/web/lib/gemini.ts` calls Gemini
(`?key=` auth, model `gemini-2.0-flash`) and returns a discriminated result so 429/errors degrade
gracefully. Two BFF routes: `POST /api/bff/ai` (assistant) and `POST /api/bff/translate`. Client
methods `client.ai(prompt, context?)` / `client.translate(text, lang)` use `reqSoft` (does NOT
throw on non-2xx — returns the `{ok:false,error}` body so the UI shows a clean message). UI:
`AiPanel` right-drawer (open via `openAi({context})` from a message's ✨ toolbar button; quick
actions Summarize / What-should-I-reply / Improve / Explain + free prompt); per-message Translate
(`LanguageMenu` searchable dropdown → inline translated card w/ "Show original"); whole-chat
Translate (header ✈ button → banner + `autoTranslateTo` prop on every MessageItem); composer
translate-before-send (✈ toolbar btn → pick language → preview popover → "Use translation" replaces
draft). Flags `aiAssist` + `translation`. **KEY is server-side only** (`GEMINI_API_KEY`, no
`NEXT_PUBLIC_`; verified not in client bundle). The provided free-tier key is **quota-exhausted
(429)** — wiring is proven end-to-end; real output needs a fresh/paid key.
**More Slack features added:** presence toggle Active/Away/DND (ProfileDrawer → Availability →
`client.updateMe({presence})`); typing indicator moved to a fixed bar ABOVE the composer (incl.
DMs); channel create — **public adds the whole team automatically, private shows a multi-user
selector**; invite modal turns emails into **chips** on `,`/Enter; thread composer is the FULL
editor, thread replies have edit/delete; editor lists: Enter=new bullet (doesn't send), Tab/Shift-
Tab indent/outdent; cross-view live sync via `notifyChannelChanged` mutation bus (delete + also-
send reflect without refresh); `threadRootId` "Replied to a thread → open" chip; copy-message
toolbar button.
**Jump-to-message flash (working in a production build):** `pnpm --filter @lynkd/web build` +
`start`; StrictMode double-mount is gone so the WAAPI amber `animate()` on `[data-mid-body]` fires.
ChannelView reads `?msg` via `useSearchParams()` (`jumpMsg`) and the effect is keyed on
`[hasMessages, channelId, jumpMsg]` — **gate on the boolean `hasMessages = messages.length>0`, NOT
the raw count**, or every send/incoming message re-fires the jump and yanks the viewport back to
the old message. As soon as the target resolves (or after ~2.5s of not finding it) the effect
strips `?msg` with `router.replace(pathname,{scroll:false})` so it's one-shot AND re-clicking the
same result re-fires (identical-URL push is a no-op otherwise). **Search + notification results now
deep-link with `?msg=`** (CommandPalette.go, NotificationsPanel; Notification/mock data gained an
optional `messageId`; the Liam-mention notif/inbox point at `m_21` in `d_liam`, not `m_23` which is
`d_ava`). A **search hit on a thread reply** (msg with `parentId`) opens the thread panel
(`openThread`) instead of a `?msg=` jump that would never find a main-list node — `SearchResult`
gained `parentId`. In dev the flash is unreliable (node churn); the scroll always works.
**Editor lists:** inside a list BOTH Enter (native) and Shift+Enter (`execCommand insertParagraph`)
make the next bullet/number; Tab/Shift-Tab indent 3 levels. Outside a list Enter sends, Shift+Enter
soft-newlines. **Composer has a visible amber "✨ AI" button** (`flags.aiAssist`) → `openAi()`.
**Gotchas:** `reactStrictMode:false` in next.config. Bump `__lynkdStore_vN` in `store.ts` after
adding store methods (HMR singleton). See [[qa-and-fixes]], [[iios-relationship]], [[architecture-decisions]].