interacmanagernew / ICC_Technical_Flow.md
MichaelEdou
Initial commit โ€” ICC Interac Manager full-stack app
149698e

ICC Interac Manager โ€” Complete Technical Flow

Every technology, every AI model, every data transformation โ€” fully detailed
Last updated: February 2026


1. System Architecture โ€” Full Technology Map

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                         USER'S BROWSER                                   โ”‚
โ”‚                                                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
โ”‚  โ”‚  VITE 6 + REACT 19 SPA                                            โ”‚ โ”‚
โ”‚  โ”‚  TypeScript 5 ยท Tailwind CSS 4 ยท shadcn/ui                        โ”‚ โ”‚
โ”‚  โ”‚                                                                    โ”‚ โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ Login    โ”‚ โ”‚Dashboard โ”‚ โ”‚ Scan     โ”‚ โ”‚ Settings โ”‚ โ”‚Reports โ”‚ โ”‚ โ”‚
โ”‚  โ”‚  โ”‚ Page     โ”‚ โ”‚ Page     โ”‚ โ”‚ Page     โ”‚ โ”‚ Page     โ”‚ โ”‚ Page   โ”‚ โ”‚ โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚
โ”‚  โ”‚       โ”‚             โ”‚            โ”‚             โ”‚            โ”‚      โ”‚ โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”โ”‚ โ”‚
โ”‚  โ”‚  โ”‚  State Management Layer                                        โ”‚โ”‚ โ”‚
โ”‚  โ”‚  โ”‚  Zustand (global) ยท TanStack Query v5 (server/cache)          โ”‚โ”‚ โ”‚
โ”‚  โ”‚  โ”‚  React Hook Form + Zod (forms) ยท Socket.io-client (realtime)  โ”‚โ”‚ โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚ โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ”‚                                 โ”‚ HTTP + WebSocket                       โ”‚
โ”‚              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                    โ”‚
โ”‚              โ”‚  Vite Dev Proxy (port 5173)          โ”‚                    โ”‚
โ”‚              โ”‚  /api/* โ†’ localhost:3001             โ”‚                    โ”‚
โ”‚              โ”‚  /ws    โ†’ ws://localhost:3001        โ”‚                    โ”‚
โ”‚              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                  โ”‚
                                  โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      EXPRESS.JS 5 BACKEND (port 3001)                    โ”‚
โ”‚                      Node.js 20 LTS ยท TypeScript 5                       โ”‚
โ”‚                                                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  MIDDLEWARE LAYER                                                 โ”‚   โ”‚
โ”‚  โ”‚  JWT Auth ยท CORS ยท express-rate-limit ยท Helmet CSP ยท Pino logger โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”‚
โ”‚  โ”‚ Auth     โ”‚ โ”‚ Scan     โ”‚ โ”‚ Txns     โ”‚ โ”‚ Receipts โ”‚ โ”‚ Settings โ”‚    โ”‚
โ”‚  โ”‚ Routes   โ”‚ โ”‚ Routes   โ”‚ โ”‚ Routes   โ”‚ โ”‚ Routes   โ”‚ โ”‚ Routes   โ”‚    โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜    โ”‚
โ”‚       โ”‚             โ”‚            โ”‚             โ”‚            โ”‚           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”     โ”‚
โ”‚  โ”‚  SERVICE LAYER                                                 โ”‚     โ”‚
โ”‚  โ”‚                                                                โ”‚     โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ Gmail       โ”‚  โ”‚ Scan Engine  โ”‚  โ”‚ AI Provider Pool      โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ Service     โ”‚  โ”‚ (pipeline)   โ”‚  โ”‚ (auto-switcher)       โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ”‚             โ”‚  โ”‚              โ”‚  โ”‚                       โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ googleapis  โ”‚  โ”‚ Fetchโ†’Parse  โ”‚  โ”‚ Groq โ†โ†’ Mistral      โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ OR imapflow โ”‚  โ”‚ โ†’Routeโ†’Save  โ”‚  โ”‚ (9 free model slots)  โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚     โ”‚
โ”‚  โ”‚                                                                โ”‚     โ”‚
โ”‚  โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ Routing     โ”‚  โ”‚ PDF Service  โ”‚  โ”‚ Export Service        โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ Service     โ”‚  โ”‚ PDFKit /     โ”‚  โ”‚ SheetJS (xlsx)        โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ”‚ branch map  โ”‚  โ”‚ react-pdf    โ”‚  โ”‚ CSV (built-in)        โ”‚โ”‚     โ”‚
โ”‚  โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”‚     โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚
โ”‚                                                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  DATA LAYER                                                       โ”‚   โ”‚
โ”‚  โ”‚  Drizzle ORM ยท PostgreSQL 16 ยท Redis + BullMQ (job queue)        โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                                                                         โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  WEBSOCKET LAYER (Socket.io)                                      โ”‚   โ”‚
โ”‚  โ”‚  scan:progress ยท scan:completed ยท transaction:new ยท ai:switcher   โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
         โ”‚                    โ”‚                     โ”‚
         โ–ผ                    โ–ผ                     โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ PostgreSQL 16โ”‚    โ”‚    Redis 7   โ”‚      โ”‚  External AI APIs    โ”‚
โ”‚              โ”‚    โ”‚              โ”‚      โ”‚                      โ”‚
โ”‚ users        โ”‚    โ”‚ BullMQ jobs  โ”‚      โ”‚ api.groq.com         โ”‚
โ”‚ transactions โ”‚    โ”‚ scan queue   โ”‚      โ”‚ api.mistral.ai       โ”‚
โ”‚ branch_configโ”‚    โ”‚ rate limiter โ”‚      โ”‚ (free tier, $0)      โ”‚
โ”‚ scan_logs    โ”‚    โ”‚              โ”‚      โ”‚                      โ”‚
โ”‚ ai_settings  โ”‚    โ”‚              โ”‚      โ”‚ [Optional paid:]     โ”‚
โ”‚ ai_switcher  โ”‚    โ”‚              โ”‚      โ”‚ api.anthropic.com    โ”‚
โ”‚ _logs        โ”‚    โ”‚              โ”‚      โ”‚ api.openai.com       โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

2. Complete Scan Pipeline โ€” Step by Step

This is the exact sequence of events when a user clicks "Scanner maintenant".

Phase 0: User Initiates Scan

USER ACTION                         TECHNOLOGY INVOLVED
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
1. User clicks "Scanner aujourd'hui"  React onClick handler
2. Frontend sends POST /api/scan/start  Axios / fetch (TanStack Query mutation)
   Body: { preset: "today" }
3. Backend receives request              Express.js route handler
4. JWT middleware validates token         jsonwebtoken (JWT verify)
5. Creates BullMQ job in Redis           BullMQ + Redis
6. Returns { jobId: "scan_abc123" }      Express response
7. Frontend opens WebSocket              Socket.io-client
   Listens for scan:progress events

Phase 1: Email Discovery (Gmail API)

STEP    ACTION                          TECHNOLOGY            TIME
โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€
1.1     Resolve date range:              resolveScanDates()    <1ms
        "today" โ†’ midnightโ†’now           (shared util)

1.2     Build Gmail search query:        buildGmailQuery()     <1ms
        "from:notify@payments.           (server util)
        interac.ca after:2026/2/22
        before:2026/2/24"

1.3     Call Gmail API: list messages    googleapis npm        200ms
        GET gmail/v1/users/me/messages   (google-auth-library
        ?q={query}&maxResults=500         + googleapis)

        OAuth token from DB:             Drizzle ORM โ†’ PG
        users.access_token (AES-256      crypto.decipher
        encrypted) โ†’ decrypt

        If token expired:                google-auth-library
        auto-refresh with                OAuth2Client
        users.refresh_token              .refreshAccessToken()

1.4     Receive message ID list:         Gmail API response    โ€”
        ["msg_001", "msg_002", ...]
        (just IDs, not full emails)

1.5     Deduplication check:             Drizzle ORM โ†’ PG      50ms
        SELECT email_id FROM             SQL query
        transactions WHERE               (parameterized,
        email_id IN (...)                indexed)

1.6     Filter: skip existing IDs        JavaScript Set         <1ms
        Result: newIds[] (emails
        to process)

1.7     WebSocket emit:                  Socket.io              <1ms
        scan:started {
          jobId, totalEmails,
          newEmails, skipped,
          dateRange
        }

PHASE 1 TOTAL:  ~300ms for discovery

Phase 2: Parallel Fetch (Gmail API โ€” 10 concurrent)

STEP    ACTION                          TECHNOLOGY            TIME
โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€
2.1     Create concurrency limiter:      p-limit npm           <1ms
        gmailLimit = pLimit(10)          (10 concurrent)

2.2     For each newId, launch           Promise + p-limit     โ€”
        concurrent fetch:

        โ”Œโ”€โ”€โ”€โ”€ gmailLimit(async () => {
        โ”‚
        โ”‚  2.3  GET gmail/v1/users/me/   googleapis            100ms
        โ”‚       messages/{id}             (full MIME format)    each
        โ”‚       ?format=full
        โ”‚
        โ”‚  2.4  Extract email body:       Custom MIME parser    <1ms
        โ”‚       - Find text/html part     (base64 decode)
        โ”‚       - Base64 decode
        โ”‚       - Strip HTML tags
        โ”‚       - Extract plain text
        โ”‚
        โ”‚  2.5  Extract email metadata:   MIME header parse     <1ms
        โ”‚       - Date header
        โ”‚       - From header
        โ”‚       - Subject header
        โ”‚
        โ””โ”€โ”€โ”€โ”€ return { emailId, body, metadata } })

        With 10 concurrent: 50 emails fetched in ~500ms
                            200 emails in ~2 seconds
                            1000 emails in ~10 seconds

PHASE 2 TOTAL:  ~100ms per email, 10 concurrent = ~10ms effective per email

Phase 3: AI Parsing (Auto-Switcher โ€” up to 15 concurrent on Groq)

This is where the AI models do the work. Every email body goes through the AIProviderPool.

STEP    ACTION                          TECHNOLOGY            TIME
โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€
3.1     AIProviderPool receives          aiProviderPool.ts     <1ms
        email body text

3.2     Select best available slot:      getNextAvailableSlot  <1ms
        Check priority order:            ()
        1. groq:gpt-oss-20b
        2. groq:llama4-scout
        3. groq:llama31-8b
        ...
        7. mistral:small-3.2
        ...

3.3     Enforce rate delay:              enforceRateDelay()    0-2000ms
        Groq: 60s/30RPM = 2s delay      (per slot)
        Mistral: 60s/2RPM = 30s delay

3.4     Build AI request:                                      <1ms
        โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚ {                                               โ”‚
        โ”‚   model: "openai/gpt-oss-20b",                 โ”‚
        โ”‚   messages: [                                   โ”‚
        โ”‚     { role: "system",                           โ”‚
        โ”‚       content: EXTRACTION_SYSTEM_PROMPT },      โ”‚
        โ”‚     { role: "user",                             โ”‚
        โ”‚       content: "Extract transaction             โ”‚
        โ”‚        details:\n\n{EMAIL_BODY}" }              โ”‚
        โ”‚   ],                                            โ”‚
        โ”‚   temperature: 0.0,                             โ”‚
        โ”‚   max_tokens: 500,                              โ”‚
        โ”‚   response_format: { type: "json_object" }      โ”‚
        โ”‚ }                                               โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

3.5     Send to AI provider:             fetch() or openai     150-800ms
                                         npm package

        โ”Œโ”€โ”€โ”€ IF GROQ: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚ POST https://api.groq.com/openai/v1/            โ”‚
        โ”‚      chat/completions                            โ”‚
        โ”‚ Headers:                                         โ”‚
        โ”‚   Authorization: Bearer gsk_xxxxx                โ”‚
        โ”‚   Content-Type: application/json                 โ”‚
        โ”‚                                                  โ”‚
        โ”‚ Speed: 500-1000 tokens/sec                       โ”‚
        โ”‚ Typical response: 150-300ms                      โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

        โ”Œโ”€โ”€โ”€ IF MISTRAL: โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
        โ”‚ POST https://api.mistral.ai/v1/                 โ”‚
        โ”‚      chat/completions                            โ”‚
        โ”‚ Headers:                                         โ”‚
        โ”‚   Authorization: Bearer xxxxx                    โ”‚
        โ”‚   Content-Type: application/json                 โ”‚
        โ”‚                                                  โ”‚
        โ”‚ Speed: 100-300 tokens/sec                        โ”‚
        โ”‚ Typical response: 300-800ms                      โ”‚
        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

3.6     IF 429 RATE LIMIT:              Auto-switcher         <1ms
        - Mark current slot as           logic in pool
          rate_limited
        - Set cooldownUntil from
          retry-after header
        - WebSocket emit ai:switcher
        - Jump to next priority slot
        - RETRY from step 3.2

3.7     Receive AI response:             JSON.parse()          <1ms
        {
          "sender": "Jean Tremblay",
          "amount": 150.00,
          "currency": "CAD",
          "reference": "CA1b2c3d4e5f",
          "message": "Dรฎme mars 2025",
          "recipient_email": "montreal.finances@iccameriques.org",
          "date": "2026-02-23T14:30:00Z",
          "status": "deposited"
        }

3.8     Validate with Zod schema:        zod npm               <1ms
        InteracTransactionSchema
        .parse(parsed)

        If validation fails:
        - Log warning
        - Retry with different model
        - Or mark as needs_review

PHASE 3 TOTAL:  ~200-800ms per email depending on provider
                With Groq 15 concurrent: ~15ms effective per email

Phase 4: Branch Routing (No AI โ€” Pure Logic)

STEP    ACTION                          TECHNOLOGY            TIME
โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€
4.1     Look up recipient_email in       BRANCH_MAPPING        <1ms
        branch mapping:                  (shared constant)

        "montreal.finances               JavaScript object
        @iccameriques.org"               lookup, O(1)
        โ†’ "ICC Montrรฉal"

4.2     If no match found:               Fallback logic        <1ms
        โ†’ "Non classifiรฉ"

4.3     Attach branch to transaction:    Object assign         <1ms
        transaction.branch =
        "ICC Montrรฉal"

PHASE 4 TOTAL:  <1ms (no network, no AI, pure in-memory lookup)

Phase 5: Database Save (Batch INSERT)

STEP    ACTION                          TECHNOLOGY            TIME
โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€
5.1     Buffer parsed transaction        Array.push            <1ms
        into saveBuffer[]

5.2     When buffer reaches 25:          Drizzle ORM           5-15ms
        Batch INSERT INTO                โ†’ PostgreSQL
        transactions (                   (parameterized)
          email_id, user_id, date,
          sender, amount, currency,
          reference, message,
          recipient_email, branch,
          status, raw_email,
          parsed_at, reviewed
        ) VALUES (...), (...), ...

        โ˜… Single INSERT for 25 rows
        is 10-20x faster than 25
        individual INSERTs

5.3     WebSocket emit per row:          Socket.io             <1ms
        transaction:new {                (per transaction)
          transaction: {...}
        }

        Dashboard receives and
        auto-adds to TanStack Table

5.4     Update scan_logs:                Drizzle ORM โ†’ PG      2ms
        UPDATE scan_logs SET
        emails_parsed = emails_parsed + 25
        WHERE id = {scanLogId}

PHASE 5 TOTAL:  ~15ms per batch of 25 transactions

Phase 6: Completion

STEP    ACTION                          TECHNOLOGY            TIME
โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€
6.1     Flush remaining buffer           Drizzle โ†’ PG          5ms
        (< 25 transactions)

6.2     Write final scan log:            Drizzle โ†’ PG          2ms
        UPDATE scan_logs SET
        finished_at = NOW(),
        emails_found = {n},
        emails_parsed = {n},
        errors = {n}

6.3     Write switcher logs:             Drizzle โ†’ PG          2ms
        INSERT INTO ai_switcher_logs
        (batch of all switch events)

6.4     WebSocket emit:                  Socket.io             <1ms
        scan:completed {
          jobId,
          summary: { found, parsed,
            skipped, errors },
          dateRange,
          duration: "45s"
        }

6.5     Frontend shows toast:            Sonner (toast lib)    โ€”
        "47 nouveaux virements
        importรฉs en 45 secondes"

6.6     Dashboard auto-refreshes         TanStack Query        โ€”
        transaction list                 invalidateQueries()
        (already live via WebSocket,     (backup full refresh)
        but also invalidates cache)

3. AI Model Connection Map

Exactly which AI model does what, and where in the code it connects.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                                          โ”‚
โ”‚  WHAT AI DOES IN THIS PROJECT:                                           โ”‚
โ”‚                                                                          โ”‚
โ”‚  AI has ONE job: Parse raw Interac email text โ†’ structured JSON          โ”‚
โ”‚                                                                          โ”‚
โ”‚  AI does NOT do:                                                         โ”‚
โ”‚  โœ— Branch routing (pure lookup table, no AI)                            โ”‚
โ”‚  โœ— PDF generation (PDFKit / @react-pdf/renderer, no AI)                 โ”‚
โ”‚  โœ— Export CSV/Excel (SheetJS, no AI)                                    โ”‚
โ”‚  โœ— Dashboard charts (Recharts, no AI)                                   โ”‚
โ”‚  โœ— Authentication (Google OAuth, no AI)                                 โ”‚
โ”‚  โœ— Email fetching (Gmail API / IMAP, no AI)                             โ”‚
โ”‚  โœ— Database queries (Drizzle ORM / SQL, no AI)                          โ”‚
โ”‚  โœ— Real-time updates (WebSocket, no AI)                                 โ”‚
โ”‚                                                                          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Where Each Model Connects

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  FILE: packages/server/src/services/aiProviderPool.ts                    โ”‚
โ”‚  CLASS: AIProviderPool                                                   โ”‚
โ”‚  METHOD: parse(emailBody: string) โ†’ InteracTransaction                   โ”‚
โ”‚                                                                         โ”‚
โ”‚  This is the ONLY place AI is called in the entire application.          โ”‚
โ”‚  Everything below is managed by the auto-switcher inside this method.    โ”‚
โ”‚                                                                         โ”‚
โ”‚  SLOT 1 โ”€โ”€โ”€ groq:gpt-oss-20b โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Groq                                                      โ”‚
โ”‚  โ”‚  Model:    openai/gpt-oss-20b                                        โ”‚
โ”‚  โ”‚  API:      POST https://api.groq.com/openai/v1/chat/completions      โ”‚
โ”‚  โ”‚  SDK:      openai npm (baseURL override)                             โ”‚
โ”‚  โ”‚  File:     packages/server/src/providers/groq.ts                     โ”‚
โ”‚  โ”‚  Auth:     GROQ_API_KEY env var (free, no credit card)               โ”‚
โ”‚  โ”‚  Speed:    1,000 tokens/sec ยท response in ~150ms                     โ”‚
โ”‚  โ”‚  Free:     30 RPM ยท 7,000 req/day ยท 500K tokens/day                 โ”‚
โ”‚  โ”‚  Input:    ~800 tokens (system prompt + email body)                   โ”‚
โ”‚  โ”‚  Output:   ~200 tokens (JSON transaction object)                      โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜† (good at structured extraction)                    โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 2 โ”€โ”€โ”€ groq:llama4-scout โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Groq                                                      โ”‚
โ”‚  โ”‚  Model:    meta-llama/llama-4-scout-17b-16e-instruct                 โ”‚
โ”‚  โ”‚  API:      POST https://api.groq.com/openai/v1/chat/completions      โ”‚
โ”‚  โ”‚  SDK:      openai npm (same Groq adapter)                            โ”‚
โ”‚  โ”‚  Speed:    594 tokens/sec                                            โ”‚
โ”‚  โ”‚  Free:     30 RPM ยท 1,000 req/day ยท 500K tokens/day                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…ยฝโ˜†                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 3 โ”€โ”€โ”€ groq:llama31-8b โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Groq                                                      โ”‚
โ”‚  โ”‚  Model:    llama-3.1-8b-instant                                      โ”‚
โ”‚  โ”‚  API:      POST https://api.groq.com/openai/v1/chat/completions      โ”‚
โ”‚  โ”‚  Speed:    840 tokens/sec ยท response in ~100ms                       โ”‚
โ”‚  โ”‚  Free:     30 RPM ยท 14,400 req/day ยท 500K tokens/day                โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜†โ˜† (simpler extraction, may miss edge cases)          โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜†โ˜†                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 4 โ”€โ”€โ”€ groq:qwen3-32b โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Groq                                                      โ”‚
โ”‚  โ”‚  Model:    qwen/qwen3-32b                                            โ”‚
โ”‚  โ”‚  Speed:    662 tokens/sec                                            โ”‚
โ”‚  โ”‚  Free:     30 RPM ยท 1,000 req/day ยท 500K tokens/day                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜† (strong multilingual)                              โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 5 โ”€โ”€โ”€ groq:llama4-maverick โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Groq                                                      โ”‚
โ”‚  โ”‚  Model:    meta-llama/llama-4-maverick-17b-128e-instruct             โ”‚
โ”‚  โ”‚  Speed:    562 tokens/sec                                            โ”‚
โ”‚  โ”‚  Free:     30 RPM ยท 1,000 req/day ยท 500K tokens/day                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 6 โ”€โ”€โ”€ groq:gpt-oss-120b โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Groq                                                      โ”‚
โ”‚  โ”‚  Model:    openai/gpt-oss-120b                                       โ”‚
โ”‚  โ”‚  Speed:    500 tokens/sec                                            โ”‚
โ”‚  โ”‚  Free:     30 RPM ยท 1,000 req/day ยท 100K tokens/day                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜… (best reasoning on Groq)                           โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  โ”€โ”€โ”€โ”€โ”€โ”€ PROVIDER BOUNDARY: Groq โ†’ Mistral โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚
โ”‚                                                                         โ”‚
โ”‚  SLOT 7 โ”€โ”€โ”€ mistral:small-3.2 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Mistral AI                                                โ”‚
โ”‚  โ”‚  Model:    mistral-small-3.2-24b-instruct                            โ”‚
โ”‚  โ”‚  API:      POST https://api.mistral.ai/v1/chat/completions           โ”‚
โ”‚  โ”‚  SDK:      fetch() (OpenAI-compatible)                               โ”‚
โ”‚  โ”‚  File:     packages/server/src/providers/mistral.ts                  โ”‚
โ”‚  โ”‚  Auth:     MISTRAL_API_KEY env var (free, no credit card)            โ”‚
โ”‚  โ”‚  Speed:    ~200 tokens/sec ยท response in ~400ms                      โ”‚
โ”‚  โ”‚  Free:     2 RPM ยท ~2,880 req/day ยท 1B tokens/month                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜† (excellent structured extraction)                  โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜… (built by French company, native French)           โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 8 โ”€โ”€โ”€ mistral:medium-3.1 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Mistral AI                                                โ”‚
โ”‚  โ”‚  Model:    mistral-medium-3.1                                        โ”‚
โ”‚  โ”‚  Speed:    ~150 tokens/sec                                           โ”‚
โ”‚  โ”‚  Free:     2 RPM ยท ~2,880 req/day ยท 1B tokens/month                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜…โ˜… (highest accuracy)                                 โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜…                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ”‚  SLOT 9 โ”€โ”€โ”€ mistral:ministral-8b โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚
โ”‚  โ”‚  Provider: Mistral AI                                                โ”‚
โ”‚  โ”‚  Model:    ministral-8b-2512                                         โ”‚
โ”‚  โ”‚  Speed:    ~300 tokens/sec                                           โ”‚
โ”‚  โ”‚  Free:     2 RPM ยท ~2,880 req/day ยท 1B tokens/month                 โ”‚
โ”‚  โ”‚  Quality:  โ˜…โ˜…โ˜…โ˜†โ˜†                                                    โ”‚
โ”‚  โ”‚  French:   โ˜…โ˜…โ˜…โ˜…โ˜†                                                    โ”‚
โ”‚  โ”‚                                                                      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

4. Technology โ†’ Purpose Map (Every Library)

Frontend (packages/web)

Technology Version What It Does in This Project Touches AI?
Vite 6 Dev server, HMR, production bundler No
React 19 Component rendering, UI framework No
TypeScript 5 Type safety across all code No
Tailwind CSS 4 Utility-first styling for all components No
shadcn/ui latest Pre-built components: Button, Dialog, DatePicker, Table, Toggle, Toast No
React Router v7 Page routing: /login, /dashboard, /scan, /settings, /reports No
Zustand latest Global state: auth user, scan status, provider pool status No
TanStack Query v5 Server state: transactions list, scan history, settings (auto-cache, refetch) No
TanStack Table v8 Dashboard transaction table: sort, filter, paginate, select, expand No
React Hook Form latest Settings forms: AI config, branch config, scan date range No
Zod latest Frontend validation: date ranges, settings input No
Socket.io-client latest Real-time: scan:progress, transaction:new, ai:switcher events No
Recharts latest Reports page: bar charts, line charts, pie charts No
@react-pdf/renderer latest Client-side PDF receipt generation (single transaction) No
SheetJS latest Client-side Excel/CSV export No
date-fns latest Date formatting with fr-CA locale No
Lucide React latest Icons throughout the UI No
Sonner latest Toast notifications ("47 virements importรฉs") No
react-i18next latest French UI translations No
p-limit latest Used in scan progress UI for throttled updates No

Backend (packages/server)

Technology Version What It Does in This Project Touches AI?
Express.js 5 HTTP API server, route handling No
TypeScript 5 Type safety across all server code No
googleapis latest Gmail API: fetch message IDs, fetch full MIME emails No
google-auth-library latest OAuth 2.0: token exchange, refresh, consent URL No
imapflow latest IMAP fallback: connect to Gmail via IMAP if API unavailable No
openai (npm) latest Groq adapter: same SDK, different baseURL โ†’ api.groq.com YES
fetch (built-in) โ€” Mistral adapter: direct HTTP to api.mistral.ai YES
@anthropic-ai/sdk latest Claude adapter (optional paid): api.anthropic.com YES
Drizzle ORM latest Database queries: all CRUD, batch inserts, migrations No
PostgreSQL driver (pg) latest Database connection pooling No
Redis (ioredis) latest BullMQ backend, rate limit counters, session cache No
BullMQ latest Background job queue: scan jobs run async, not blocking API No
Socket.io latest WebSocket server: push scan progress + provider switches to UI No
jsonwebtoken latest JWT: issue access tokens (15 min) + refresh tokens (7 day) No
PDFKit latest Server-side batch PDF receipt generation No
Pino latest Structured JSON logging No
Helmet latest Security headers (CSP, HSTS, etc.) No
cors latest CORS policy: restrict to known frontend origins No
express-rate-limit latest API rate limiting (prevent abuse of scan endpoints) No
p-limit latest Concurrency control: 10 Gmail fetches, 15 Groq parses No
Zod latest Server-side validation: AI output JSON, API request bodies No
crypto (built-in) โ€” AES-256 encryption: OAuth tokens at rest in PostgreSQL No

Shared (packages/shared)

Technology What It Does
TypeScript types InteracTransaction, ScanDateRange, ProviderSlot, SwitcherEvent
BRANCH_MAPPING 48 emailโ†’branch lookup pairs (no AI needed)
resolveScanDates() Presetโ†’date range helper
Zod schemas InteracTransactionSchema for validating AI output

5. AI Data Flow โ€” Input โ†’ Output

What Goes INTO the AI

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘  SYSTEM PROMPT (~350 tokens, same for every email, cached)          โ•‘
โ•‘                                                                     โ•‘
โ•‘  "You are a financial data extraction assistant. Given the raw      โ•‘
โ•‘  text/HTML of an Interac e-Transfer notification email from         โ•‘
โ•‘  notify@payments.interac.ca, extract the following fields into      โ•‘
โ•‘  a JSON object:                                                     โ•‘
โ•‘                                                                     โ•‘
โ•‘  - sender: The name of the person who sent the money                โ•‘
โ•‘  - amount: The dollar amount (numeric, no $ sign)                   โ•‘
โ•‘  - currency: Always "CAD"                                           โ•‘
โ•‘  - reference: The Interac reference number                          โ•‘
โ•‘  - message: The personal message/memo (null if none)                โ•‘
โ•‘  - recipient_email: The email the transfer was sent TO              โ•‘
โ•‘  - date: The date/time in ISO 8601 format                           โ•‘
โ•‘  - status: One of deposited, pending, expired, cancelled            โ•‘
โ•‘                                                                     โ•‘
โ•‘  Return ONLY valid JSON, no markdown, no explanation."              โ•‘
โ• โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•ฃ
โ•‘  USER MESSAGE (~450 tokens, unique per email)                        โ•‘
โ•‘                                                                     โ•‘
โ•‘  "Extract transaction details:                                      โ•‘
โ•‘                                                                     โ•‘
โ•‘  INTERAC e-Transfer                                                 โ•‘
โ•‘  Bonjour, vous avez reรงu un virement Interac de Jean Tremblay.     โ•‘
โ•‘  Montant : 150,00 $ (CAD)                                          โ•‘
โ•‘  Numรฉro de rรฉfรฉrence: CA1b2c3d4e5f                                  โ•‘
โ•‘  Message de l'expรฉditeur : Dรฎme mars 2025                           โ•‘
โ•‘  Ce virement a รฉtรฉ automatiquement dรฉposรฉ dans le compte de:        โ•‘
โ•‘  montreal.finances@iccameriques.org                                 โ•‘
โ•‘  Date: 23 fรฉvrier 2026 14:30                                        โ•‘
โ•‘  ..."                                                               โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Total input: ~800 tokens

What Comes OUT of the AI

โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
โ•‘  AI RESPONSE (~200 tokens)                                           โ•‘
โ•‘                                                                     โ•‘
โ•‘  {                                                                  โ•‘
โ•‘    "sender": "Jean Tremblay",                                       โ•‘
โ•‘    "amount": 150.00,                                                โ•‘
โ•‘    "currency": "CAD",                                               โ•‘
โ•‘    "reference": "CA1b2c3d4e5f",                                     โ•‘
โ•‘    "message": "Dรฎme mars 2025",                                     โ•‘
โ•‘    "recipient_email": "montreal.finances@iccameriques.org",         โ•‘
โ•‘    "date": "2026-02-23T14:30:00Z",                                  โ•‘
โ•‘    "status": "deposited"                                            โ•‘
โ•‘  }                                                                  โ•‘
โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Total output: ~200 tokens
Total per email: ~1,000 tokens

What Happens AFTER AI (No AI Involved)

AI Output (JSON)
      โ”‚
      โ–ผ
Zod Validation โ”€โ”€โ”€โ”€ FAIL? โ†’ log warning, retry with next model, or flag as needs_review
      โ”‚
      โœ… PASS
      โ”‚
      โ–ผ
Branch Routing โ”€โ”€โ”€โ”€ BRANCH_MAPPING["montreal.finances@iccameriques.org"] โ†’ "ICC Montrรฉal"
      โ”‚               (pure JavaScript lookup, no AI)
      โ”‚
      โ–ผ
PostgreSQL INSERT โ”€โ”€ Drizzle ORM โ†’ INSERT INTO transactions (...)
      โ”‚
      โ–ผ
WebSocket Push โ”€โ”€โ”€โ”€ Socket.io โ†’ transaction:new { ... }
      โ”‚
      โ–ผ
React Dashboard โ”€โ”€โ”€ TanStack Table auto-adds row to table
      โ”‚
      โ–ผ
User Sees New Row โ”€โ”€ "Jean Tremblay | 150,00 $ | ICC Montrรฉal | Dรฉposรฉ"

6. Speed Optimization โ€” Why It's Fast

Old Architecture (Sequential)

Email 1: [Fetch 100ms] โ†’ [AI Parse 300ms] โ†’ [Save 5ms] = 405ms
Email 2:                                                    [Fetch] โ†’ [Parse] โ†’ [Save]
Email 3:                                                                            [Fetch] โ†’ ...
Total for 50 emails: 50 ร— 405ms = 20,250ms = ~20 seconds

New Architecture (Parallel Pipeline)

Time โ†’   0ms    100ms    200ms    300ms    400ms    500ms
         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”
Fetch:   โ”‚E1-E10โ”‚E11-20โ”‚E21-30โ”‚E31-40โ”‚E41-50โ”‚      โ”‚  (10 concurrent)
Parse:   โ”‚      โ”‚P1-P15โ”‚P16-30โ”‚P31-45โ”‚P46-50โ”‚      โ”‚  (15 concurrent)
Save:    โ”‚      โ”‚      โ”‚S1-S25โ”‚      โ”‚S26-50โ”‚      โ”‚  (batch 25)
         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Total for 50 emails: ~500ms for fetches + ~700ms for parses = ~1.2 seconds
                     (stages overlap, so total < sum)

Concurrency Budget Per Free Tier

                           GROQ                    MISTRAL
RPM (requests/minute):     30                      2
Safe concurrency:          15 concurrent calls     1 sequential call
Time per AI call:          ~150ms (Groq is fast)   ~400ms
Emails parsed per minute:  ~30 (RPM-limited)       ~2 (RPM-limited)
Emails parsed per hour:    ~1,800                  ~120

WITH AUTO-SWITCHER (all 6 Groq + 3 Mistral):
Effective RPM:             30 + 30 + 30 + 30 + 30 + 30 + 2 + 2 + 2 = 186 RPM*
                           (*until individual daily limits hit)

First hour throughput:     ~180 emails/min = ~10,800 emails/hour

Speed Benchmarks (Revised with Pipeline)

Scan Type Emails Time (Pipeline + Auto-Switcher)
Today 50 ~12 seconds
7 Days 200 ~35 seconds
Custom (1 month) 1,000 ~3 minutes
Custom (6 months) 5,000 ~15 minutes
Custom (1 year) 10,000 ~30 minutes

7. Non-AI Technology Flows

PDF Receipt Generation (No AI)

User clicks "Gรฉnรฉrer reรงu" on a transaction row
      โ”‚
      โ–ผ
CLIENT-SIDE (single receipt):
  @react-pdf/renderer builds PDF in browser
  Template: ICC logo + transaction details + branch info + date
  Downloads immediately as "recu_CA1b2c3d4e5f.pdf"

SERVER-SIDE (batch receipts):
  POST /api/receipts/batch { transactionIds: [...] }
      โ”‚
      โ–ผ
  PDFKit generates PDF per transaction
  Merges into single ZIP file
  Returns ZIP for download

CSV/Excel Export (No AI)

User clicks "Exporter" โ†’ selects CSV or Excel
      โ”‚
      โ–ผ
CLIENT-SIDE:
  SheetJS (xlsx npm) builds file from TanStack Table data
  Columns: Date | Expรฉditeur | Montant | Rรฉfรฉrence | Succursale | Statut
  fr-CA formatting: "1 500,00 $" not "$1,500.00"
  Downloads immediately

Reports & Charts (No AI)

User navigates to /reports
      โ”‚
      โ–ผ
  GET /api/transactions/stats?from=2026-01-01&to=2026-02-23
      โ”‚
      โ–ผ
  PostgreSQL aggregation queries:
    - SUM(amount) GROUP BY month โ†’ bar chart (Recharts)
    - COUNT(*) GROUP BY status โ†’ pie chart (Recharts)
    - COUNT(*) GROUP BY branch โ†’ top branches table
    - SUM(amount) over time โ†’ trend line chart (Recharts)
      โ”‚
      โ–ผ
  React renders charts with Recharts
  No AI involved โ€” pure SQL aggregation + charting library

Real-Time Dashboard Updates (No AI)

Server saves new transaction to PostgreSQL
      โ”‚
      โ–ผ
  Socket.io server emits:
    transaction:new { transaction: {...} }
      โ”‚
      โ–ผ
  Socket.io client receives event
      โ”‚
      โ–ผ
  Zustand store updates transaction list
      โ”‚
      โ–ผ
  TanStack Table re-renders with new row
  (animated row insertion at top of table)
      โ”‚
      โ–ผ
  SummaryBar recalculates totals
  (no page refresh, no API call needed)

8. Security Flow (No AI)

1. User clicks "Se connecter avec Google"
2. Frontend redirects to Google OAuth consent URL
   (scopes: gmail.readonly, userinfo.email, userinfo.profile)
3. User approves โ†’ Google redirects to /api/auth/google/callback?code=xxx
4. Backend exchanges auth code for access_token + refresh_token
   (google-auth-library)
5. Backend encrypts tokens with AES-256 (crypto module)
6. Backend stores encrypted tokens in PostgreSQL (users table)
7. Backend issues JWT: { userId, email, role, exp: 15min }
   (jsonwebtoken)
8. Frontend stores JWT in httpOnly secure cookie
9. Every API request includes JWT in Authorization header
10. Backend middleware verifies JWT on every request
    (jsonwebtoken.verify)
11. If JWT expired โ†’ frontend calls POST /api/auth/refresh
    with refresh token โ†’ new JWT issued

This document is a companion to the ICC Interac Manager Build Prompt and the FREE AI Models Guide. Together, the three documents provide everything needed to build the complete system.