Menu
Public repository / c3ef99b092caa55fb6a3eed9d3e776734cc99e97
AkurAI-Mail / docs/framework-migration.md
Latest change c3ef99b092caa55fb6a3eed9d3e776734cc99e97 - OLI-241: framework migration plan; shortcuts slice onto AkurAI-Framework signals runtime by Ólafur Búi Ólafsson
# Webmail UI → AkurAI-Framework migration plan (OLI-241) Framework client runtime (AkurAI-Framework `site/frontend`): native ES modules, **no build step, no npm deps**. `signals.js` (signal/effect + `data-*` directives), `islands.js` (`registerIsland`, hydrate server-rendered markup), `spa.js` (router), `akurai-client.js` (typed auto-API client), `ai/components` (chat/tool UI), server-side templates. Source of truth checked: AkurAI-Framework@d506ed5. ## Inventory and mapping | Current (SvelteKit) | Size | Framework equivalent | Migration step | |---|---|---|---| | `src/lib/webmail/shortcuts.ts` + toggle in `+page.svelte` | 36 | `signals.js` + plain ESM | **Done in OLI-241** → `src/framework/shortcuts.js` | | `filters.ts`, `folders.ts`, `threads.ts`, `virtual.ts`, `recipients.ts`, `compose.ts`, `session.ts` (pure logic + tests) | ~380 | Plain ESM + JSDoc, tests stay on `bun test` | Rename `.ts`→`.js` with JSDoc types; no framework API needed. Wave 1. | | `sync.ts`, `sync.svelte.ts` (rune store) | 91 | `signals.js` `signal`/`effect` | Wave 1 (replace runes with signals) | | `SignalBadge`, `SyncBanner`, `SettingsDrawer` | 231 | Islands (`registerIsland`) over server-rendered markup | Wave 2 | | `RecipientCombobox`, `RichTextEditor`, `ComposeDialog` | 212 | Islands; editor needs a framework rich-text component (gap G4) | Wave 3 | | `MessageList.svelte` (virtual list, threads, chips) | 605 | Island + `data-for`; virtualization needs gap G3 | Wave 3 | | `MessageReader.svelte` | 381 | Island; sanitized-HTML render | Wave 3 | | `src/routes/webmail/+page.svelte` (state, actions, layout, CSS) | 1727 | Server template + `spa.js` route + one top-level island holding a signal store | Wave 4, last (decompose first) | | `src/routes/webmail/+page.ts` (auth gate + load) | 18 | Framework auth/sessions (`/docs/auth`) + `akurai-client.js` | Wave 4 | | `src/lib/api.ts` | 23 | `akurai-client.js` | Wave 4; keep `api.test.ts` green by porting 1:1 | Order rationale: leaf logic first (no UI risk), then components bottom-up, page last. Each wave ships behind green `bun test ./src` and `scripts/webmail-shortcuts-e2e.ts`-style browser checks. ## Wave 0 (this issue): shortcuts slice - `src/framework/shortcuts.js`: `resolveKey` keymap, `createShortcuts` (signal-driven listener + persisted toggle), `scrollSelectedIntoView`. - `src/framework/vendor/signals.js`: vendored framework runtime (see G1/G2). - `+page.svelte` now only maps actions to its own state; the keymap, toggle state and scroll helper live in the framework module. - Tests: `src/framework/shortcuts.test.js` (ported from OLI-239, written red first), plus `scripts/webmail-shortcuts-e2e.ts` (headless chromium against a mock API: Enter opens, `#` prompts delete, `j` scrolls selection into view, toggle persists and silences keys). - Behaviour note: the OLI-239 `shortcuts.ts` was only partially wired (page had its own handler with extra keys R/f/s/u/!/Delete/arrows). The framework module is now the single keymap and covers all of them; behaviour is unchanged. ## Framework gaps (to file as AkurAI-Framework issues) | # | Gap | Why mail needs it | Proposed owner | |---|---|---|---| | G1 | `signals.js` touches `document` at import time → cannot be imported under `bun test`/SSR | Unit-testing any framework module; vendored copy carries a one-line guard | Framework dev (Dev Lead to file) | | G2 | No installable/versioned client package (files are served from the site only) | We vendor-copy `signals.js`, which can drift; need a pinned import path (npm tarball or `/vendor/akurai@x.y.z/`) | Platform Engineer + Framework | | G3 | No virtualized list / windowing primitive for `data-for` | Inbox lists reach thousands of rows (`virtual.ts` today) | Framework dev | | G4 | No rich-text editor component | Compose (`RichTextEditor.svelte`) | Framework dev | | G5 | No keyboard-shortcut/hotkey helper or focus-scope utility | Generic version of today's `src/framework/shortcuts.js`; upstream it | Mail Dev (extract) → Framework | | G6 | `data-*` directives use `new Function`/`with`; mail renders untrusted content so only island JS (not directives) may touch message data | CSP and XSS posture for message bodies | SecOps Engineer review | | G7 | No typed (`.d.ts`) surface for signals/islands/client; we use JSDoc + `checkJs` | TypeScript-checked consumers | Framework dev | | G8 | Framework SPA router vs. IdP return_to redirect flow (`loginUrl`) undocumented | Page auth gate migration (Wave 4) | Framework dev + IDP owner | ## Risks - Tooling: `package.json` still pins SvelteKit/Vite; the Svelte page imports the framework module through Vite until Wave 4 removes Svelte. - `bun` is resolved via mise `latest` — pin before wave 1 (Dev Lead). - Do not deploy mid-migration waves without the browser check passing.