尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证AI travel assistant that creates personalized day-by-day itineraries, ticket plans, and budgets. Customize trips by duration, group size, and style, with credit-based payments built in.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗A modern, full-stack SaaS application for planning travel itineraries using AI technology. Built with Next.js, TypeScript, Tailwind CSS, Shadcn UI, and Framer Motion.
src/
├── app/ # Next.js App Router
│ ├── api/ # API routes
│ │ ├── generate-itinerary/ # AI itinerary generation
│ │ ├── credits/ # Credit management
│ │ └── save-itinerary/ # Save/retrieve itineraries
│ ├── auth/ # Authentication pages
│ ├── dashboard/ # Main app with sidebar
│ ├── layout.tsx # Root layout
│ └── page.tsx # Landing page
├── components/ # Reusable components
│ ├── ui/ # Shadcn UI components
│ └── landing/ # Landing page sections
│ ├── hero-section.tsx
│ ├── features-section.tsx
│ ├── testimonials-section.tsx
│ ├── pricing-section.tsx
│ ├── cta-section.tsx
│ └── footer.tsx
├── lib/ # Utility functions
└── styles/ # Global styles
/ - Landing page with hero, features, testimonials, pricing/auth - Authentication (login/signup)/dashboard - Trip planner/dashboard/itinerary/[id] - Itinerary, budget, bookings, stays, essentials, checklist/dashboard/book - Booking hub/trip/[id]?t=… - Public, read-only shared itinerary (signed link)/api/generate-itinerary - POST endpoint for AI itinerary generation/api/user/credits - GET the signed-in user's credit balance/api/checkout - POST { planId } to start a Dodo Payments checkout/api/webhooks/dodo - Dodo Payments webhook (adds or removes credits)/api/payments - GET the signed-in user's purchases/api/save-itinerary - GET/POST endpoints for saving itinerariesDefined once in src/lib/plans.ts and used across the site. 1 credit = 1 itinerary; credits never expire.
git clone <repository-url>
cd goroam
npm install
npm run dev
Besides DATABASE_URL and DIRECT_URL (see Database schema), NEXTAUTH_SECRET (also signs share links), NEXTAUTH_URL, the Google OAuth keys and OPENAI_API_KEY, these optional affiliate IDs are appended to booking links when set:
NEXT_PUBLIC_BOOKING_AID - Booking.com affiliate idNEXT_PUBLIC_GYG_PARTNER_ID - GetYourGuide partner idNEXT_PUBLIC_SKYSCANNER_ASSOCIATE - Skyscanner associate idSet NEXT_PUBLIC_GOOGLE_MAPS_API_KEY to turn on the live, dark, zoomable Google map in each day of an itinerary, and Google Places photos for every stop. In Google Cloud, enable Maps JavaScript API and Places API (New), turn on billing, and restrict the key to your domains (HTTP referrers). The server sends your site's address as the referrer, so the same key works for photo lookups. GOOGLE_PLACES_API_KEY (a server-only key) is used instead if you'd rather keep them separate. Optional: NEXT_PUBLIC_GOOGLE_MAPS_MAP_ID for your own cloud-styled map.
Without a key, days show the illustrated route and photos come from Wikipedia, Wikimedia Commons and Openverse. Found photos are saved on each trip, so every later view is a plain database read.
Set NEXT_PUBLIC_POSTHOG_KEY (project API key) to record page views, page leaves, clicks and GoRoam events (trip_generated, itinerary_viewed, package_impression, package_viewed, package_customized, booking_partner_clicked, directions_clicked, share_link_created, pdf_downloaded, calendar_downloaded, checkout_started). Signed-in travellers are identified by their GoRoam id only. Events go through /ingest on your own domain; set NEXT_PUBLIC_POSTHOG_HOST (e.g. https://eu.i.posthog.com) for an EU project. Without a key, PostHog never loads.
The ready-made trips in Dashboard → Travel packages are defined in src/lib/packages.ts and stored in src/data/packages/. To add or rebuild one (uses OPENAI_API_KEY):
npx tsx --env-file=.env.local scripts/generate-packages.ts # build any missing packages
npx tsx --env-file=.env.local scripts/generate-packages.ts rome-5-days
npx tsx --env-file=.env.local scripts/generate-packages.ts --photos # re-find photos only
Credit packs are sold through Dodo Payments hosted checkout. Credits are added only by the webhook, never by the redirect back to the site.
src/lib/plans.ts: Starter $9.99, Explorer $24.99, Adventurer $69.99.https://<your-domain>/api/webhooks/dodo subscribed to payment.succeeded, refund.succeeded and dispute.lost, and copy its signing secret.DODO_PAYMENTS_API_KEY - API keyDODO_PAYMENTS_WEBHOOK_KEY - webhook signing secretDODO_PAYMENTS_ENVIRONMENT - test_mode (default) or live_modeDODO_PRODUCT_STARTER, DODO_PRODUCT_EXPLORER, DODO_PRODUCT_ADVENTURER - the product ids (pdt_…)The Payment table is created automatically on the next deploy — see Database schema below.
Until the API key and all three product ids are set, the buy buttons show "Online checkout isn't available yet." When going live, switch to live-mode keys, live product ids and a live webhook secret together.
There's no migrations folder: the build script itself runs prisma db push ("vercel-build" in package.json), so every deploy syncs the live database to whatever is in schema.prisma. Editing that file is enough — you don't need to run anything by hand.
The one exception is a change that would drop or truncate a column with data in it (e.g. deleting a field, changing its type). db push refuses those instead of applying them silently, so the build fails loudly with a "data loss" error rather than deploying and quietly deleting something. If that happens, resolve it locally (DIRECT_URL="<prod-session-url>" npx prisma db push, which shows the same warning and lets you decide) before pushing again.
Two database URLs. Vercel runs every function as its own short-lived instance, so the app connects through Supabase's pooler in transaction mode; session mode caps out at 15 clients and fails with EMAXCONNSESSION under load. Set both in Vercel (and in .env / .env.local locally):
DATABASE_URL - the Transaction pooler string (port 6543) with ?pgbouncer=true&connection_limit=1. Used by the app at runtime.DIRECT_URL - the Session pooler string (port 5432). Used only by prisma db push during the build, which can't run through the transaction pooler.Both are under Supabase → Project Settings → Database → Connection string. If DIRECT_URL is missing, the build fails at prisma db push.
Public, indexable pages (statically generated, with JSON-LD):
/itineraries and /itineraries/[slug]: the trip gallery. Data lives in src/lib/packages.ts (trip facts), src/lib/packages-seo.ts (search title, intro, FAQs) and src/data/packages/<slug>.json (the full plan). Hand-written trips are generated by python3 scripts/content/itineraries.py./destinations and /destinations/[slug]: destination guides in src/lib/destination-guides.ts./sitemap.xml and /robots.txt are generated from the same data. Bump UPDATED in src/app/sitemap.ts when content changes.Google Search Console
https://goroam.world, choose HTML tag verification and copy the content value.NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION=<that value> in Vercel and redeploy, then click Verify. (Or verify the whole domain with a DNS TXT record instead.)sitemap.xml. Use URL inspection → Request indexing for the most important pages.Email (Resend): RESEND_API_KEY and EMAIL_FROM="GoRoam <[email protected]>". Verify goroam.world in Resend (it gives DNS records to add). Used for email sign-in links (the "or with email" option appears on /auth only once these are set), the welcome email on sign-up, and emailing an itinerary. For local testing, EMAIL_DEV_LOG=1 prints emails to the dev-server console instead of sending.
Guest first trip: signed-out visitors who type a trip in the landing hero get it planned without an account (/api/guest-itinerary, the GuestTrip model), see Day 1 at /try/[id], and sign in to claim the rest. Limits: one per device and three per IP a day, plus GUEST_DAILY_LIMIT (default 300) across everyone.
npm run dev - Start development servernpm run build - Build for productionnpm run start - Start production servernpm run lint - Run ESLintThis project uses Shadcn UI. To add new components:
npx shadcn@latest add [component-name]
#f5f1ea), ink (#15130f) and the brand orange from the logo (#d95501) — defined as tokens in src/app/globals.css (bg-paper, text-ink, text-brand, …)prefers-reduced-motionsrc/components/scenes/ renders every destination as a layered, animated SVG scene — monuments in monuments.ts, compositions in scenes.tsx. sceneForDestination() in src/lib/destinations.ts picks a poster for any tripPOST /api/generate-itinerary
{
"destination": "Paris, France",
"duration": "5 days",
"preferences": ["culture", "food", "museums"]
}
GET /api/user/credits // → { credits }
POST /api/checkout // { planId: "starter" | "explorer" | "adventurer" } → { url }
POST /api/webhooks/dodo // signed by Dodo; payment.succeeded / refund.succeeded / dispute.lost
GET /api/payments // → purchase history
POST /api/save-itinerary
{
"userId": "user_123",
"itineraryData": {...}
}
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ for travelers worldwide. Start planning your next adventure with GoRoam!