# Slip Scanner Backend (FastAPI) FastAPI service exposing a /scan endpoint to process receipt images: - Validates Supabase user via Authorization: Bearer - Detects edges and crops the receipt (OpenCV, perspective transform) - Performs OCR via Hugging Face Inference API (TrOCR) - Uploads the cropped image to Supabase Storage - Inserts a row into the slips table with extracted metadata ## Prerequisites - Python 3.11+ - Supabase project with Storage and Postgres - Hugging Face account and API token ## Environment Variables Create a .env file in backend/ with: SUPABASE_URL=... SUPABASE_ANON_KEY=... SUPABASE_SERVICE_ROLE_KEY=... SUPABASE_STORAGE_BUCKET=slips HUGGINGFACE_API_TOKEN=... HF_OCR_MODEL=microsoft/trocr-base-printed FRONTEND_CORS_ORIGIN=http://localhost:3000 Notes: - Use the Service Role key server-side only. Never expose it to the frontend. - If you prefer signed URLs, adjust upload_bytes_to_supabase_storage accordingly and do not make the bucket public. ## Install & Run (Windows PowerShell) cd backend python -m venv .venv . .venv\Scripts\Activate.ps1 pip install -r requirements.txt uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000 ## API ### Health GET http://localhost:8000/health ### Scan POST http://localhost:8000/scan Authorization: Bearer Content-Type: multipart/form-data file=@/path/to/receipt.jpg cURL example: curl -X POST http://localhost:8000/scan \ -H "Authorization: Bearer $SUPABASE_JWT" \ -F "file=@receipt.jpg" Response: { "ok": true, "slip": { "id": "...", "user_id": "...", "image_url": "https://...", "amount": 250.0, "category": "Food", "raw_text": "...", "created_at": "2025-09-15T10:00:00Z", "crop_confidence": 0.8 } } ## Supabase Setup ### Storage Bucket (public or signed) - Create bucket slips. - For public previews, enable public read on the bucket or a specific folder per user. Alternatively, keep private and generate signed URLs server-side. ### Table Create table slips (adjust types as desired): create table if not exists public.slips ( id uuid primary key default gen_random_uuid(), user_id uuid not null, image_path text not null, image_url text, raw_text text, amount numeric, category text, crop_confidence real, created_at timestamptz not null default now() ); alter table public.slips enable row level security; RLS policies (only owner reads/writes their slips): create policy "slips select own" on public.slips for select using (auth.uid() = user_id); create policy "slips insert own" on public.slips for insert with check (auth.uid() = user_id); create policy "slips update own" on public.slips for update using (auth.uid() = user_id); ### Frontend Config In Next.js .env.local: NEXT_PUBLIC_API_URL=http://localhost:8000 NEXT_PUBLIC_SUPABASE_URL=... NEXT_PUBLIC_SUPABASE_ANON_KEY=... From the client, include the Supabase session JWT as the Authorization header when calling /scan. ## Design Notes (rules.md alignment) - Mobile-first UX is handled in the Next.js app; backend is stateless and fast. - No sensitive keys in frontend; backend uses Service Role for Storage/DB. - Performance: edge detection and OCR happen server-side; images are resized and optimized. - Security: RLS ensures users only see their own slips; Storage access can be scoped. ## Dev Tips - OpenAPI docs: http://localhost:8000/docs - If HF model cold-starts and returns 503, retry the request after a few seconds.