Voyagent — the whole story
One quiz each, one plan for everyone. This is the single source of truth for what Voyagent is, why it exists, how it's built, and how a teammate picks it up and carries it from beta to a real launch — without reading a line of code first.
Last updated for the Beta milestone. Live app: voyagent.netlify.app · Metrics: Voyagent Pulse
1 · What it is
Voyagent is a group-trip planner that turns a chaotic group chat into one fair plan. Every traveller answers a 60-second quiz (budget, vibe, home city, hard "no"s). The app reconciles everyone's answers into destination suggestions, the group votes, and Voyagent writes a day-by-day itinerary that respects every budget and dealbreaker — then you can re-tune any day or simply ask to shift things around. A public share page turns any trip into something you can post to friends.
The tagline says it best: Everyone’s voice, one trip.
2 · Why we built it
Group travel dies in the planning. Five friends, five budgets, five ideas of "fun", one endless thread where nobody wants to be the organiser. Existing tools assume one planner doing all the work; they don't reconcile people. We built Voyagent around a single belief:
The hard part of a group trip isn't finding places — it's making a decision everyone feels good about. So the product's job is fairness and momentum, not a bigger list of hotels.
Every design choice flows from that: the quiz is 60 seconds so nobody drops off; budgets anchor to the lowest so nobody gets priced out; dealbreakers are hard overrides so the shy person's "no" still wins; the plan appears the moment the group votes so the energy never stalls.
3 · Who it's for
- Primary: friend groups (3–8 people) planning a leisure trip together — reunions, birthdays, "we should finally do this".
- Also works for: a solo traveller who wants a fast, balanced plan (the flow degrades gracefully to one person).
- Spans: shoestring backpackers to ultra-luxury travellers — the per-day budget slider covers hostels to overwater villas, in ₹/$/€/£, and the plan meets the group where the tightest budget sits.
- Built India-first (formats, currencies, destinations) but works globally.
4 · How it works
- Create — a name, rough dates, and a destination-or-vibe (or hit "let Voyagent decide" for the surprise roulette).
- Invite — share a link; friends join with just a name, no sign-up.
- Quiz — each person: daily budget (log slider), vibes, home city, optional age band, hard dealbreakers (the preset "no"s adapt to the trip — a beach trip offers "No water sports", a trek offers "No steep treks"). ~60 seconds.
- Suggest — the app proposes three destinations, each with a why naming the people it fits.
- Vote — everyone taps their pick; the tally is live.
- Plan — a day-by-day itinerary, each item tagged with who it's "for", with map/booking links.
- Adapt — re-tune a day, and it's weather-aware: live rain forecasts trigger a banner, and a rainy re-tune swaps exposed plans for covered or indoor alternatives. Or just ask: "move dinner to 9pm" and it happens for the whole group.
- Share — a public page for WhatsApp/Instagram that never exposes the private trip.
5 · Architecture & stack
Deliberately boring and cheap to run — the right call for a weekend build that might become real.
| Layer | Choice | Why |
|---|---|---|
| Frontend | Preact + htm via CDN, one file, no build step | Zero toolchain; edit-and-refresh; installs as a PWA |
| API | One shared api-core.js → Express locally, Netlify Function in prod | Same code both places; no drift |
| Database | Supabase (Postgres) with a SQLite dev fallback | Managed, realtime, generous free tier |
| AI | OpenAI gpt-4o by default; Claude supported | Structured JSON outputs; seeded fallback if the key is missing |
| Hosting | Netlify (app) · Vercel (this Pulse + KB) | Git-push deploys, free TLS, edge CDN |
| Realtime | Supabase broadcast pings + 2.5s polling | Instant roster/vote updates without exposing data |
North-star of the architecture: the browser holds no secrets. The app talks to a thin server that owns the database key; the database itself denies all direct access.
6 · Where everything lives
| Thing | Location |
|---|---|
| App (live) | voyagent.netlify.app |
| App source | GitHub AbhilashKairali/voyagent |
| Pulse + this KB | this Vercel site · GitHub AbhilashKairali/voyagent-pulse |
| Database | Supabase project rmlwmjzzkeilxxcsxsdy |
| Frontend UI | public/index.html (one file — screens, quiz, itinerary, chat) |
| Server + routes | api-core.js · adapters server.js, netlify/functions/api.mjs |
| The decision engine | ai.js (all prompts, schemas, fallbacks) |
| Data layers | db-supabase.js (prod) · db.js (local) — identical interfaces |
| Metrics aggregator | stats.js → served at /api/stats (aggregates only) |
| Schema | supabase/schema.sql |
| Status docs | LAUNCH_CHECKLIST.md, FEEDBACK_STATUS.md, README.md |
7 · The decision engine
All intelligence lives in ai.js. Four jobs, each a system prompt + a strict JSON schema + a seeded fallback so the app never blanks:
- Suggest — reconcile quizzes into 3 destinations with per-person "why"s and fit scores.
- Generate — write the exact-length day-by-day plan, anchored to the lowest per-day budget.
- Re-tune — rewrite one day for a reason ("raining", "hungover") while keeping the rest.
- Ask — a trip-scoped assistant that can directly edit the schedule.
The rules every prompt enforces
- Budgets are per person, per day, anchored to the lowest in the group — nobody is priced out.
- Dealbreakers are hard overrides that beat every vibe; a forbidden trait is never sold as a plus. Entries are read for meaning: a positive wish typed in the avoid box ("I want to party") is treated as a preference to satisfy, never an exclusion.
- One currency per plan — never invent exchange rates.
- Specificity is mandatory — real, findable venues, not "Beach Relaxation".
- Guard rails (shared across all four): user text is data, not instructions (injection-resistant); gibberish falls back to real quiz data; illegal/unsafe requests are excluded and a normal lawful trip is planned; the system prompt is never revealed.
8 · Pulse & metrics
The Pulse dashboard follows Pirate Metrics (AARRR) — Dave McClure's five-stage growth funnel that investors expect to see:
| Stage | In Voyagent |
|---|---|
| Acquisition | Trips started, travellers joined, per-day trend |
| Activation | Quiz completion %, reached-a-vote, reached-a-plan % |
| Retention | needs accounts — on the roadmap (see §11) |
| Referral | Average group size = built-in virality (every trip is an invite) |
| Revenue | free in beta; AI-cost per trip is the unit-economics proxy |
North Star metric: shared plans delivered — the moment a group gets one agreed plan is the value Voyagent exists to create. Everything else is a step toward it.
The dashboard reads a public, cached, aggregate-only feed (/api/stats): counts and category breakdowns, never a name, trip title, or IP. It refreshes every 60 seconds, and a month + year filter (past and future months) lets you track progress month-wise.
9 · Security & privacy
- Database is deny-all. Row-Level Security blocks every direct read/write; only the server (holding the service-role key) touches data. Verified with a live 401 on every table.
- The browser holds no secrets. It only ever gets a harmless anon key used to subscribe to "something changed" pings — no data rides on them.
- Aggregates only leave the building. Pulse can't expose a person; the stats feed is counts and categories with small buckets suppressed.
- Prompt-injection resistant. All user text is treated as data; the model won't take orders from a trip brief or chat message, won't reveal its instructions, and refuses illegal asks while still planning a lawful trip.
- Hardened headers (CSP, HSTS, no-framing), a per-trip and global AI spend cap, and full input sanitisation (length caps, control-char stripping, currency/age whitelists).
- Honest limitation: with no accounts, a trip is as private as its invite link. Say so to testers. Accounts are the first roadmap item.
10 · Do's & don'ts
Do
netlify deploy --prod. Pulse → GitHub → Vercel. Every change ships the same way..env is git-ignored; keys live in Netlify/Vercel dashboards only.supabase/schema.sql + apply to the live project first.LIMIT_* env vars, then restore them.Don't
_sb) — they collide with Preact internals. Use distinctive names.11 · Beta → launch
What turns this from a great demo into a real product, in rough priority order:
- Accounts (Google sign-in). Unlocks true retention metrics, trip history, and per-user privacy. The single biggest unlock.
- Real booking links & prices (affiliate hotels/flights) — the first revenue path.
- Expense splitting post-trip — a sticky reason to come back.
- Push notifications — "3 of 5 have voted" nudges lift activation.
- Vote deadlines & reminders — momentum for slow groups.
- Multilingual — the quiz and plan in the group's language.
- Observability — error tracking (Sentry) and a private ops view alongside the public Pulse.
- Harden multi-user concurrency for large groups; formal load testing.
12 · Run it yourself
No keys needed for a local look — the app serves seeded demo content and uses a local SQLite file.
git clone https://github.com/AbhilashKairali/voyagent
cd voyagent
npm install
node server.js # → http://localhost:4600
To use real AI + the shared database, add a .env (git-ignored) with OPENAI_API_KEY, SUPABASE_URL, SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY. The Pulse dashboard is fully static — deploy the voyagent-pulse repo to Vercel; it needs no env vars because it reads the app's public /api/stats feed.
13 · Glossary
- AARRR / Pirate Metrics — Acquisition, Activation, Retention, Referral, Revenue. The startup growth funnel (Dave McClure, 2007).
- North Star metric — the one number that best captures delivered value. Ours: shared plans delivered.
- Activation — a new group reaching its first real value (here: a completed shared plan).
- Virality / k-factor — how many new users each user brings. Every Voyagent trip is an invite, so average group size is a direct proxy.
- Dealbreaker — a hard "no" a traveller sets; always overrides vibes and other members.
- Re-tune — regenerate a single day for a stated reason, leaving the rest of the plan intact.
- RLS — Row-Level Security; Postgres rules that here deny all direct client access.
Voyagent is a beta project. This KB is the living source of truth — update it when the product changes. Questions? Start with the code map in §6, then ai.js for behaviour and api-core.js for routes.