साथी — companion · partner · friend on the journey
Nobody flies alone.
The open-source matchmaking platform for cross-border family travel.
Every diaspora family knows the call: a parent flying alone, a long layover, an unfamiliar terminal, a language they only half-speak. We wait for them to message that they've found the gate. We don't sleep until they do.
There are tens of thousands of solo travellers on the same flight, doing nothing in particular for those eight hours. Saathi puts those two people in touch a few weeks before the flight, sets up an introduction, and lets the family stop holding their breath at 3 AM.
We don't run the trip. We don't take a cut. We make the introduction, then get out of the way.
- Match by flight leg, not the whole trip — Someone only flying Doha→Amsterdam can still help with that layover. We're not picky about where they started.
- Language matters more than everything else — A Bengali-speaking companion beats a same-day English-only one. Your mom doesn't need someone who can't understand her panic.
- Just enough verification, not a background check — WhatsApp OTP + a LinkedIn link. Enough to trust them with your parent, not enough to scare away normal humans.
- Top 3-5 matches, not Tinder for flights — We show you the best people for your exact flight. No swiping, no endless scrolling, no "maybe this one?"
- Private until you say yes — Contact details stay locked until both sides agree. No creeps sliding into DMs before the match.
- Smart notifications that don't spam — Daily digest, not 47 emails. Popular routes won't flood your inbox at 3 AM.
# 1. Use the pinned Node version (.nvmrc → 20.18.x)
nvm use
# 2. Install
corepack enable
pnpm install
# 3. Copy env and fill in at minimum: Clerk + Supabase keys
cp .env.example .env.local
# 4. Run
pnpm dev # http://localhost:3000Optional env vars (Sentry, Twilio, PostHog, Resend, AirLabs, OpenAI) are read lazily — features that depend on a missing key disable themselves rather than crash. See .env.example for the full list and what each one unlocks.
sequenceDiagram
participant Family
participant Saathi
participant Companion
participant Flight
Note over Family: 1. Post a request
Family->>Saathi: Route, date, languages<br/>Help needed (wheelchair, translation, etc.)
Note over Companion: 2. Companion matches
alt Companion already posted offer
Saathi->>Family: Show companion in shortlist
else Family finds companion
Family->>Saathi: Send intro request
end
Note over Family,Companion: 3. Agree on handoff
Saathi->>Family: Unlock WhatsApp + Email
Saathi->>Companion: Unlock WhatsApp + Email
Family->>Companion: Where we'll meet, what mom looks like
Companion-->>Family: Confirms plan, shares landmarks
Note over Saathi: Saathi steps back
Note over Flight: 4. The flight happens
Companion->>Flight: Walk parent through immigration
Companion->>Flight: Sit with them at boarding
Companion->>Flight: Help find luggage at arrivals
Flight->>Family: Parent arrives safely ✓
Note over Family: Family stops holding their breath
graph LR
Browser([Browser])
subgraph Vercel["Next.js 15 on Vercel"]
App[App Router · Server Actions<br/>shadcn/ui · Tailwind · Zod]
Matches["/trip/:id/matches<br/>shortlist page"]
Cron[Vercel Cron<br/>every minute / daily]
end
subgraph Supabase["Supabase · Postgres + RLS"]
DB[(trips · matches · trip_legs<br/>pending_notifications<br/>FOR UPDATE SKIP LOCKED)]
end
Clerk[Clerk<br/>auth · JWT]
subgraph External["External services"]
Resend[Resend · email digests]
Twilio[Twilio · WhatsApp OTP + Lookup]
AirLabs[AirLabs · flight routes]
OpenAI[OpenAI · moderation]
end
Observability[Sentry · errors<br/>PostHog · flags<br/>Vercel Analytics]
Browser --> App
Browser --> Matches
App -->|sign-in JWT| Clerk
Clerk -->|verified JWT| DB
App -->|RLS-gated queries| DB
App -->|enqueue pending_notifications| DB
App -->|OTP verify| Twilio
App -->|moderate notes + intros| OpenAI
App -->|cache miss| AirLabs
Cron -->|claim + dispatch| DB
Cron -->|send| Resend
App -.-> Observability
Tooling: pnpm · Vitest · ESLint · Prettier · Husky · commitlint.
| Script | What it does |
|---|---|
pnpm dev |
Next.js dev server |
pnpm build |
Production build (uploads Sentry source maps if configured) |
pnpm lint |
ESLint |
pnpm format / pnpm format:check |
Prettier write / check |
pnpm typecheck |
tsc --noEmit |
pnpm test |
Vitest run (pnpm test:watch for watch mode) |
pnpm db:types |
Regenerate types/db.ts from linked Supabase project |
pnpm db:reset |
Reset local Supabase + re-apply migrations |
pnpm db:push |
Push pending migrations to remote |
Saathi is open source and contributions are warmly welcome — code, design, copy edits, translations, bug reports, all of it.
Before a non-trivial change, open an issue (or comment on an existing one) so we can sanity-check direction together. Saves wasted work on either side.
Conventions:
- Trunk-based. PRs target
main. No long-lived branches. - Conventional Commits. Enforced by
commitlintvia a Huskycommit-msghook. - Tests where they matter. Pure logic (matching, parsing) gets unit tests. UI changes are validated locally.
- One thing per PR. Small PRs land faster.
Run the floor before pushing:
pnpm typecheck && pnpm lint && pnpm test && pnpm buildThe live code-review + issue tracker lives in bugs/, and the UX design anchor in docs/UX_MATCHMAKING.md.
Apache License 2.0 — see LICENSE for the full text. Use, modify, and ship Saathi freely; please keep the copyright and license notice on derivative work.
Saathi (साथी) in Hindi, Bengali, Marathi, Punjabi, and several other Indian languages means companion, partner, friend on the journey. It's the word a parent might use for the person who walks them through a confusing terminal.
That's the whole product.
Built for the daughter who can't sleep until her mother's text comes through. For the student on the same plane who would have helped, had anyone asked. Saathi just makes the introduction — and then gets out of the way.
साथी मिल गया। घर पहुँच गए। ❤️

