Spaces:
Running
Running
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.