interacmanagernew / files /README.md
MichaelEdou
Initial commit β€” ICC Interac Manager full-stack app
149698e

ICC Interac Manager β€” Scan Implementation

What This Fixes

The "Scanner maintenant" button now actually connects to Gmail, fetches Interac e-Transfer emails, parses them with AI (Groq/Mistral), and saves parsed transactions to the database β€” all with real-time progress via WebSocket.


File Map

icc-scan-impl/
β”œβ”€β”€ .env.example                          ← Copy to .env and fill in API keys
β”‚
β”œβ”€β”€ shared/                               ← Shared types & constants
β”‚   β”œβ”€β”€ types/
β”‚   β”‚   β”œβ”€β”€ scan.ts                       ← ScanPreset, ScanDateRange, resolveScanDates()
β”‚   β”‚   β”œβ”€β”€ transaction.ts                ← InteracTransaction schema
β”‚   β”‚   └── aiProvider.ts                 ← ProviderSlot, SwitcherEvent
β”‚   └── constants/
β”‚       └── branches.ts                   ← 48-branch emailβ†’city mapping
β”‚
β”œβ”€β”€ server/                               ← Backend (Express + SQLite)
β”‚   β”œβ”€β”€ index.ts                          ← Server entry point
β”‚   β”œβ”€β”€ db/
β”‚   β”‚   └── database.ts                   ← SQLite schema + operations
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   └── auth.ts                       ← JWT middleware
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ auth.ts                       ← Google OAuth routes
β”‚   β”‚   β”œβ”€β”€ scan.ts                       ← POST /api/scan/start
β”‚   β”‚   └── transactions.ts               ← GET /api/transactions
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   β”œβ”€β”€ gmailService.ts               ← Gmail API: query builder + email fetcher
β”‚   β”‚   β”œβ”€β”€ aiService.ts                  ← AI parsing: Groq + Mistral + auto-switcher
β”‚   β”‚   └── scanService.ts                ← Scan pipeline: Gmail β†’ AI β†’ DB
β”‚   └── websocket/
β”‚       └── setup.ts                      ← WebSocket server for progress events
β”‚
└── web/                                  ← Frontend (React)
    β”œβ”€β”€ services/
    β”‚   β”œβ”€β”€ api.ts                        ← HTTP client with auth
    β”‚   └── websocket.ts                  ← WebSocket client
    β”œβ”€β”€ hooks/
    β”‚   └── useEmailScan.ts               ← React hook for scan state + progress
    β”œβ”€β”€ components/scan/
    β”‚   └── ScanControls.tsx              ← β˜… THE scan button component
    └── pages/
        └── AuthCallback.tsx              ← Handles OAuth redirect

Setup Steps

1. Install Dependencies

In your packages/server/ directory:

npm install express cors helmet dotenv googleapis jsonwebtoken better-sqlite3 ws uuid p-limit zod
npm install -D typescript @types/express @types/cors @types/jsonwebtoken @types/better-sqlite3 @types/ws @types/uuid tsx

In your packages/web/ directory (most likely already installed):

npm install react-router-dom

2. Configure Google OAuth

  1. Go to Google Cloud Console
  2. Create a project (or use existing)
  3. Enable the Gmail API
  4. Create OAuth 2.0 Client ID (Web application)
  5. Add authorized redirect URI: http://localhost:3001/api/auth/google/callback
  6. Copy the Client ID and Client Secret

3. Get AI API Keys (Free)

Pick at least one:

4. Create .env File

cp .env.example .env
# Edit .env with your actual keys

5. Copy Files Into Your Project

Copy each file from this package into the corresponding location in your monorepo. The file paths in this package mirror the target paths in your project.

6. Add Vite Proxy (vite.config.ts)

Make sure your Vite dev server proxies API calls to the backend:

// packages/web/vite.config.ts
export default defineConfig({
  server: {
    proxy: {
      '/api': 'http://localhost:3001',
      '/ws': {
        target: 'ws://localhost:3001',
        ws: true,
      },
    },
  },
});

7. Add Route for Auth Callback

In your React Router config:

import AuthCallback from './pages/AuthCallback';

// Add this route:
<Route path="/auth/callback" element={<AuthCallback />} />

8. Wire Up ScanControls in Your Dashboard

Replace your current scan button section with the new ScanControls component:

import ScanControls from '@/components/scan/ScanControls';

function DashboardPage() {
  const { refetch } = useTransactions(); // your existing hook

  return (
    <div>
      <ScanControls
        onScanComplete={(result) => {
          // Refresh transaction table after scan completes
          refetch();
        }}
      />

      {/* ... rest of your dashboard ... */}
    </div>
  );
}

9. Start the Backend

cd packages/server
npx tsx src/index.ts

You should see:

πŸš€ ICC Interac Manager API running on http://localhost:3001
πŸ”— WebSocket available at ws://localhost:3001/ws
πŸ”‘ Google OAuth: http://localhost:3001/api/auth/google

10. Start the Frontend

cd packages/web
npm run dev

How It Works (Flow)

User clicks "Scanner maintenant"
         β”‚
         β–Ό
β”Œβ”€ ScanControls.tsx ──────────────────────────┐
β”‚ 1. Reads selected preset (today/7days/custom)β”‚
β”‚ 2. Calls api.startScan({ preset, dates })   β”‚
β”‚ 3. Connects to WebSocket for progress events β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚ POST /api/scan/start
                      β–Ό
β”Œβ”€ scan.ts (route) ──────────────────────────┐
β”‚ 1. Validates preset + dates                 β”‚
β”‚ 2. Calls scanService.executeScan()          β”‚
β”‚ 3. Returns immediately (async background)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      β”‚
                      β–Ό
β”Œβ”€ scanService.ts ───────────────────────────┐
β”‚ PHASE 1: DISCOVER                          β”‚
β”‚  β€’ Build Gmail query: from:notify@...      β”‚
β”‚  β€’ Fetch all matching message IDs          β”‚
β”‚  β€’ Deduplicate against existing DB records β”‚
β”‚                                            β”‚
β”‚ PHASE 2: PIPELINE (parallel)               β”‚
β”‚  β€’ 10x concurrent Gmail fetches            β”‚
β”‚  β€’ 5x concurrent AI parses                 β”‚
β”‚  β€’ Auto-switch Groq↔Mistral on rate limit  β”‚
β”‚  β€’ Batch INSERT 25 rows at a time          β”‚
β”‚  β€’ Emit scan:progress via WebSocket        β”‚
β”‚                                            β”‚
β”‚ PHASE 3: COMPLETE                          β”‚
β”‚  β€’ Flush remaining DB buffer               β”‚
β”‚  β€’ Emit scan:completed                     β”‚
β”‚  β€’ Update scan_logs table                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

WebSocket Events (Frontend receives these)

Event Data When
scan:started { jobId, totalEmails, newEmails, skipped } Scan begins
scan:progress { processed, total, errored, latest, currentProvider } Each email processed
scan:completed { jobId, summary: { found, parsed, skipped, errors } } Scan finished
scan:error { jobId, error } Scan failed
ai:switch { from, to, reason } AI provider auto-switched
transaction:new { transaction } New transaction saved

Troubleshooting

Issue Fix
"User has no Gmail tokens" User needs to log in via Google OAuth first: visit /api/auth/google
"No AI providers configured" Set GROQ_API_KEY and/or MISTRAL_API_KEY in .env
"All AI providers rate-limited" Wait 60s for cooldown, or add more API keys
Scan returns 0 emails Check Gmail query β€” make sure the connected account actually has emails from notify@payments.interac.ca
WebSocket not connecting Check Vite proxy config includes /ws β†’ ws://localhost:3001
"Invalid token" JWT expired β€” log in again via Google OAuth