AI-powered invoice ingestion and inventory management for liquor retailers.
- Invoice Ingestion – Scan distributor invoices with your camera; AI extracts all line items using Google Cloud Vision + OpenAI
- SKU Normalization – AI maps distributor shortcodes ("PATRN SLV") to canonical product names ("Patrón Silver 750ml")
- Inventory Tracking – Real-time stock levels per SKU with low-stock alerts and reorder thresholds
- Shelf Audit – Count items aisle-by-aisle; detect shrinkage and variances automatically
- Cost Analytics – Track price changes across distributors; see which SKUs increased in cost this month
- Multi-location – Manage multiple store locations under one account
- Supabase Auth – Secure authentication with persistent sessions and store-scoped RLS
StockIQ/
├── app/ # Expo Router file-based screens
│ ├── _layout.tsx # Root layout with auth guard
│ ├── (auth)/ # Authentication screens
│ │ ├── login.tsx
│ │ ├── register.tsx
│ │ ├── sign-in.tsx
│ │ ├── sign-up.tsx
│ │ └── forgot-password.tsx
│ └── (tabs)/ # Main tab navigation
│ ├── _layout.tsx # Tab bar configuration
│ ├── invoices/ # Invoice management
│ │ ├── index.tsx # Invoice list
│ │ ├── scan.tsx # Camera scanner
│ │ └── [id].tsx # Invoice review
│ ├── inventory/ # Inventory view
│ │ └── index.tsx
│ ├── audit/ # Shelf audit
│ │ └── index.tsx
│ └── dashboard/ # Cost & margin dashboard
│ └── index.tsx
├── src/
│ ├── components/ # Reusable UI components
│ │ ├── InvoiceCard.tsx
│ │ ├── InvoiceStatusBadge.tsx
│ │ ├── LiquorSkuRow.tsx
│ │ ├── CostChangeAlert.tsx
│ │ └── StatusBadge.tsx
│ ├── context/
│ │ ├── AuthContext.tsx
│ │ └── StoreContext.tsx # Selected store state
│ ├── hooks/
│ │ ├── useInvoices.ts
│ │ ├── useInventory.ts
│ │ ├── useCostDashboard.ts
│ │ └── useShelfAudit.ts
│ ├── services/
│ │ ├── invoiceService.ts
│ │ ├── skuService.ts
│ │ ├── inventoryService.ts
│ │ ├── auditService.ts
│ │ └── storeService.ts
│ ├── lib/
│ │ ├── supabase.ts # Supabase client
│ │ ├── constants.ts # Colors, spacing, liquor categories
│ │ └── analytics.ts # Event tracking
│ └── types/
│ └── database.ts # Database type definitions
├── types/
│ └── index.ts # Shared TypeScript types
├── supabase/
│ ├── functions/
│ │ ├── process-invoice-upload/ # OCR + AI invoice parsing
│ │ └── normalize-sku/ # AI SKU normalization
│ └── migrations/
│ ├── 010_liquor_schema.sql # Full StockIQ schema
│ └── 011_liquor_rls.sql # Store-scoped RLS policies
├── app.json # Expo configuration
├── package.json
├── tsconfig.json
└── .env.example # Environment variable template
- Node.js 18+
- Expo CLI:
npm install -g expo-cli - Supabase CLI:
npm install -g supabase - Expo Go app on your phone (for testing)
-
Clone & install dependencies
npm install
-
Configure environment
cp .env.example .env # Edit .env with your Supabase project URL and anon key -
Set up Supabase database
supabase db push # Or run migrations manually: # supabase migration up
-
Configure Edge Function secrets
supabase secrets set OPENAI_API_KEY=sk-... supabase secrets set GOOGLE_VISION_API_KEY=AIza...
-
Deploy Edge Functions
supabase functions deploy process-invoice-upload supabase functions deploy normalize-sku
-
Start the development server
npm start
- Session persisted via AsyncStorage through Supabase auth client
- Root
_layout.tsxredirects unauthenticated users to/login - All database access is scoped to the authenticated user's stores via RLS
| Layer | Purpose |
|---|---|
app/ |
Screens and navigation (Expo Router) |
src/components/ |
Reusable UI components |
src/hooks/ |
Stateful business logic |
src/services/ |
All Supabase/API calls, no UI logic |
src/lib/ |
Shared config, constants, and Supabase client |
src/context/ |
Global state (auth, selected store) |
types/ |
Shared TypeScript interfaces |
supabase/functions/ |
Deno Edge Functions (OCR, AI) |
supabase/migrations/ |
Database schema and RLS policies |
bourbon · whiskey · scotch · vodka · gin · tequila · rum · brandy · wine_red · wine_white · wine_rose · champagne · beer · cider · rtd · liqueur · uncategorized
- Store owner scans a paper invoice with the camera
- Image uploaded to Supabase Storage
process-invoice-uploadEdge Function runs OCR (Google Vision) + AI parsing (OpenAI)- Parsed line items appear in the Invoice Review screen
- User normalizes SKUs (calls
normalize-skuedge function) and approves the invoice - Approved invoices update inventory levels and cost history
- All tables have RLS enabled
- Data is scoped by
store_idwhich is restricted tostores.owner_id = auth.uid() - Edge Functions validate JWT on every request
liquor_itemsanddistributorsare read-only for regular users; write access requires admin role