Vendor email / Excel price sheet → AI parses offers → human review → convert to order → track shipment → analytics dashboard.
- Offer parsing from email/spreadsheets — Paste vendor emails or upload
.eml/.txt/.xlsx; AI extracts vendor, terms, line items, pricing, MOQs, and lead time into structured data. - Order + shipment visibility — Pipeline board (New → Negotiating → Accepted → Ordered → In Transit → Delivered), shipment timeline, and Leaflet map with last known location.
- Multi-tenant security with RLS (Row Level Security) — All data scoped by
org_id; rolesadmin,broker, andviewer; only admin/broker create or convert offers; storage policies restrict documents to the org. - Edge Functions (Deno/TypeScript) business logic — Parsing, Excel import, offer-to-order conversion, mock shipment webhook, and KPI snapshot.
- Storage-backed documents + signed links — Original vendor emails and spreadsheets stored in a
documentsbucket; access via signed URLs and RLS. - Analytics for revenue/margin/vendor performance — Recharts dashboard: total revenue, conversion rate, avg lead time, top vendors by revenue and pie share.
┌─────────────────────────────────────────────────────────────────────────────┐
│ React (Vite + React Router) │
│ Offer Inbox │ Offer Review │ Pipeline │ Shipment View │ Analytics │
└───────────────────────────────┬───────────────────────────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌─────────────────┐ ┌─────────────────────┐
│ Supabase Auth │ │ PostgREST │ │ Edge Functions │
│ (magic link) │ │ (tables/views) │ │ (Deno/TypeScript) │
└───────────────┘ └─────────────────┘ │ • parse-offer-email │
│ │ │ • import-excel-offer │
│ │ │ • convert-offer- │
│ │ │ to-order │
│ │ │ • shipment-webhook- │
│ │ │ mock │
│ │ │ • kpi-snapshot │
│ │ └──────────┬──────────┘
│ │ │
│ │ ▼
│ │ ┌─────────────────────┐
│ │ │ OpenAI API │
│ │ │ (structured extract) │
│ │ └─────────────────────┘
│ │
│ ▼
│ ┌─────────────────────┐
│ │ Storage (documents) │
│ │ → signed URLs │
│ └─────────────────────┘
│
└──────────────► PostgreSQL + RLS (org_id isolation)
| Layer | Tech |
|---|---|
| Frontend | Vite, React 18, TypeScript, React Router, TanStack Query, Tailwind CSS, Recharts, Leaflet / react-leaflet |
| Backend | Supabase (Auth, PostgreSQL, Storage, Edge Functions) |
| AI | OpenAI API (GPT-4o-mini) for offer parsing |
| Excel | SheetJS (Edge Function) for price sheet import |
- Create a project at supabase.com.
- Run migrations (SQL Editor or CLI):
supabase/migrations/20250101000001_initial_schema.sqlsupabase/migrations/20250101000002_rls.sqlsupabase/migrations/20250101000003_storage.sqlsupabase/migrations/20250101000004_auth_profiles.sql
- Create the
documentsstorage bucket if not created by migration (Dashboard → Storage). - Set Edge Function secrets:
OPENAI_API_KEY(forparse-offer-email). - Deploy Edge Functions (see below).
cp .env.example .env
# Edit .env with VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY
npm install
npm run devOpen http://localhost:5173. Sign in with a magic link; the auth trigger creates a profile and default org and adds you as admin.
- Log in → land on Offer Inbox.
- Paste a messy vendor email (pricing + terms) → click Parse with AI.
- Review results on Offer Review, fix one field if needed, click Approve → Negotiating, then Mark as Accepted.
- Convert to order → order and shipment are created; offer moves to “Ordered”.
- Trigger mock webhook (e.g.
curl -X POST https://your-project.supabase.co/functions/v1/shipment-webhook-mock -H "Authorization: Bearer ANON_KEY" -H "Content-Type: application/json" -d '{}') → shipment timeline and map update. - Open Analytics → see revenue, top vendor chart, conversion rate, lead time.
- orgs, profiles, org_members — multi-tenant and roles.
- vendors, customers — CRM entities.
- offers, offer_items — parsed offers and line items.
- orders, order_items — orders created from offers.
- shipments, shipment_events — tracking and timeline.
- documents — metadata for files in Storage.
- All tables:
SELECTonly whereorg_id = auth.user_org_id(). - Writes: only for
auth.user_org_role()in('admin', 'broker'). - Storage: objects under path
{org_id}/...; only that org’s members can read/write.
| Function | Purpose |
|---|---|
parse-offer-email |
Fetches offer by offer_id, sends raw_content to OpenAI, returns normalized JSON; updates offers.parsed_json and offer_items. |
import-excel-offer |
Downloads file from Storage, parses with SheetJS, column matcher, upserts offer_items and offers.parsed_json. |
convert-offer-to-order |
Creates order + order_items from offer (transactional), creates shipment, sets offer status to ordered. |
shipment-webhook-mock |
Appends a shipment event and updates shipment status/location for demo (no real carrier). |
kpi-snapshot |
Returns aggregated metrics: total revenue, conversion rate, avg lead time, top vendors. |
- Bucket:
documents. Used for vendor emails, spreadsheets, PDFs. Signed URLs for download; RLS restricts byorg_idin path.
# Supabase CLI
supabase link --project-ref YOUR_REF
supabase functions deploy parse-offer-email --no-verify-jwt
supabase functions deploy import-excel-offer --no-verify-jwt
supabase functions deploy convert-offer-to-order --no-verify-jwt
supabase functions deploy shipment-webhook-mock --no-verify-jwt
supabase functions deploy kpi-snapshot --no-verify-jwtSet OPENAI_API_KEY in Dashboard → Edge Functions → Secrets for parse-offer-email.
MIT.