尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證AI shipment booking and pre-flight checker for Indian exporters (Gemini, Neon, Resend, Vercel)
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Live demo: https://saathifly.vercel.app (no login; the earlier addresses prefly-app.vercel.app and shipsaathi-mj-3d6b.vercel.app still work). Try the chat on New Shipment, or upload the sample workbook with planted mistakes on Upload Excel.
SaathiFly helps Indian manufacturers and sellers book pallet shipments from the UK to Germany, France and the Netherlands without the small mistakes that get goods held at customs or turned away at a warehouse.
SaathiFly does not book carriers. There's no carrier integration: a confirmed booking is the seller's confirmed proposal. The ten checks catch common mistakes. They are not a full customs, dangerous-goods or export-compliance review.
Seller chat ─┐ ┌─> Issue report (Red / Amber / review + fixes)
├─> one Booking model ─> validation engine ─┤
Excel upload ┘ (src/lib/domain) (pure TypeScript) └─> Carrier eligibility + priority ranking
│
seller review / edit / confirm <────┘ ──> optional email (Resend)
persisted in Neon Postgres (bookings, items, results, events)
| Layer | Where | Notes |
|---|---|---|
| Data model | src/lib/domain/types.ts | Both entry paths produce the same Booking. null = not provided, never a guess. |
| Parsing | normalize.ts, dates.ts, excel.ts | Same parsers for Excel cells, chat values and form edits. |
| Rules | validation.ts | One pure function per rule (ruleR01 … ruleR10), plus data-quality checks. |
| Prohibited goods | hazmat.ts (+ server/hazard-ai.ts) | Deterministic keyword screen. Gemini can only escalate an item to human review. |
| Carriers | carriers.ts | Route + pallet-weight filter, priority ranking, ties, balanced score. |
| Chat logic | conversation.ts | Applies the model's proposed changes, works out missing fields and next questions. |
| Gemini | server/llm.ts, server/extract.ts | Structured JSON output. Keys stay on the server. |
| API | src/app/api/* | Server re-validates everything. Client results are never trusted. |
| UI | src/app/*, src/components/* | Next.js 16 App Router, Tailwind v4. |
The rate card and rulebook live in src/data/rate-card.json and src/data/rulebook.json. They are generated from the supplied workbook (npm run extract:reference), not typed by hand. If an uploaded workbook includes a Carrier options sheet that differs from the template, its rates are used for that upload and the UI says so.
All numeric checks are deterministic code. None of them use AI judgement.
| Rule | Severity | Formula / logic |
|---|---|---|
| R-01 | Red | HS code digits (ignoring ., space, -) must be numeric and ≥ 6. Blank fails. A 5-digit code gets a note that Excel may have dropped a leading zero. |
| R-02 | Red | Let S = Σ(quantity × unit price). Pass when ` |
| R-03 | Red | For each item: units per carton × cartons = quantity (exact). |
| R-04 | Red | booking cartons = Σ item cartons (exact). |
| R-05 | Red | gross weight ÷ pallets ≤ max kg/pallet of the chosen carrier. Chosen = the seller's selected carrier, otherwise the carrier their priority picks from the route. If it fails, the fix offers the cheapest eligible alternative or the pallet count that would fit. Missing or zero pallets fail. |
| R-06 | Red | Keyword screen for lithium batteries, aerosols and flammable liquids, with negations ("non-flammable", "batteries not included") removed first. Clear hits are Red. Ambiguous ones (e.g. "battery", "perfume", "laptop", "spray") and anything Gemini flags become Needs review. They block dispatch until the seller confirms the item is safe. A Red hit can't be acknowledged away. |
| R-07 | Amber | gross weight ≥ Σ(unit weight × quantity). |
| R-08 | Amber | Destination type Warehouse ⇒ delivery appointment must be Yes. |
| R-09 | Amber | Every item has a country of origin. |
| R-10 | Amber | Ready date ≥ today, using the calendar date in Europe/London (goods are collected in the UK). Today itself passes. |
Booking status
The server refuses to confirm anything that is Blocked or Needs review.
gross ÷ pallets ≤ max weight per pallet.pallets × price per pallet (GBP, from the rate card).score = 0.40·cost + 0.30·speed + 0.30·reliability. Cost gets the biggest weight because on this rate card the faster services are also the more reliable ones, so equal weights would count that premium twice. For UK → Germany with 3 pallets: A 0.40, B 0.65, C 0.60.Requirements: Node 20+ (tested on Node 24), npm.
npm install
cp .env.example .env.local
Fill in .env.local:
| Variable | Needed for | Notes |
|---|---|---|
DATABASE_URL | saving bookings, reports, history | Neon pooled connection string |
GEMINI_API_KEY or OPENROUTER_API_KEY | chat, AI hazard review, plain-English summary | A Google AI Studio key calls Gemini directly. An OpenRouter key calls google/gemini-* through OpenRouter. |
GEMINI_MODEL | optional | Defaults: gemini-2.5-flash (Google) / google/gemini-3.5-flash (OpenRouter) |
RESEND_API_KEY | Without a verified domain, Resend only delivers to the Resend account owner's address. | |
RESEND_FROM | Defaults to SaathiFly <[email protected]> |
Create the tables (safe to re-run):
psql "$DATABASE_URL" -f db/schema.sql
psql "$DATABASE_URL" -f db/seed-carriers.sql
Start the dev server:
npm run dev
Other scripts:
npm test
npm run typecheck
npm run extract:reference
npx tsx scripts/make-sample.ts rebuilds public/templates/SaathiFly_Sample_With_Mistakes.xlsx, a demo upload with deliberate mistakes for every rule (sample input only, not real bookings).
The app degrades gracefully. Without Gemini, the chat says so and the editable form still works. Without a database, uploads are validated but not saved. Without Resend, email shows a clear "not configured" error.
/api/health reports which integrations are configured, without revealing any values.The app needs no login. All database access goes through server routes with input validation (zod), size limits and per-IP rate limits. No secrets reach the browser.
npm test runs 115 unit tests covering:
Checked by hand in the browser: a full chat booking including a mid-conversation weight change and "add a pallet", saving, confirming (and the server refusing a booking with a Red error), email failure feedback, uploading the sample workbook, and phone-width layout (375px) on every page with no sideways scroll.