尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
A full-stack trip-planning app: travelers build day-by-day itineraries from a shared,
crowdsourced attraction database, schedule them on a per-day calendar (including flights,
accommodation stays, and free-form time slots), track a multi-currency budget, and
collaborate on a trip with other users.
Live app: https://trip-planner-beta-dusky.vercel.app/
API docs: /api-docs (Swagger UI) — see also swagger.yaml
See also: SPEC.md (system spec, ERD, full endpoint table), PRD.md
(product requirements), DESIGN.md, FLOWS.md,
WIREFRAMES.md, PRESENTATION.md.查看完整 README ↗A full-stack trip-planning app: travelers build day-by-day itineraries from a shared, crowdsourced attraction database, schedule them on a per-day calendar (including flights, accommodation stays, and free-form time slots), track a multi-currency budget, and collaborate on a trip with other users.
Live app: https://trip-planner-beta-dusky.vercel.app/
API docs: /api-docs (Swagger UI) — see also swagger.yaml
See also: SPEC.md (system spec, ERD, full endpoint table), PRD.md
(product requirements), DESIGN.md, FLOWS.md,
WIREFRAMES.md, PRESENTATION.md.
TripPlanner is built around one idea: attractions are global, shared, crowdsourced objects (name, location, category, "mood" tags), while trips are where an attraction gets a schedule (planned date/time, duration, and — for residences — trip-specific stay dates and price). The same museum can be linked into many different users' trips without duplicating its data; only the per-trip scheduling is trip-specific.
Core features:
CalendarSection) that places
attractions, flights, and free-form time slots on a timeline, including overnight-spanning
blocks (e.g. a hotel stay or overnight flight) and an auto-fit day window.Attraction document, while
stay dates/price/notes live on the trip's schedule entry so the same residence can be
reused across trips with different dates each time./analytics page./admin,
restricted to users with role: "admin".Next.js 16 (App Router) serves as both frontend and backend — there is no separate
Node server. Pages under src/app/** are the frontend; route handlers under
src/app/api/** are the REST API, backed by MongoDB via Mongoose. See
PRESENTATION.md for the full architecture writeup.
DESIGN.md), Context API for auth/attraction-taxonomy state, Leaflet for
maps.api/trips, api/attractions, api/auth, api/users, api/attraction-types,
api/attraction-categories, api/mood-tags, api/analytics, api/explore, plus
api/geo and api/route proxies for map boundary/routing lookups). Business logic for
the two largest domains (trips, attractions) lives in src/lib/services/; every route is
wrapped in a shared error-handling/logging/CORS layer (src/lib/withApiHandler.ts).src/models/*.ts). See SPEC.md for the
full ERD.jsonwebtoken) + bcrypt-hashed passwords (bcryptjs). Sessions are a
7-day JWT in Authorization: Bearer <token>; there is no server-side session store.Map features are built from four external services, proxied through Next.js API routes
(api/geo/*, api/route/*) to avoid CORS and to attach required headers (e.g. a custom
User-Agent, which these free public instances require):
GET /api/geo/city and GET /api/geo/country
(src/app/api/geo/{city,country}/route.ts).GET /api/route/valhalla (src/app/api/route/valhalla/route.ts), which actually calls
OSRM instances at routing.openstreetmap.de (the public Valhalla demo is unreliable).
Returns turn-by-turn geometry and duration.GET /api/route/transit (src/app/api/route/transit/route.ts). Returns
itineraries with per-leg transit lines and encoded polylines; falls back to Valhalla
walk, then car, when no transit route is available.Client-side consumers: src/services/geo.service.ts (boundaries) and
src/services/routeTransit.service.ts (point-to-point routing, exposing fetchRouteLeg
and fetchAirportLeg).
User 1──N Trip (owner) Trip N──N User (collaborators)
Trip N──N Attraction (attractionIds, shared/global entity)
Trip 1──N ScheduleEntry (Trip.schedules — keyed by attractionId, or a synthetic
"cs-*"/"fl-*" id for schedule-only custom-slots/flights)
Attraction N──N AttractionType ──1 AttractionCategory
Full field-level ERD: SPEC.md.
npm install
cp .env.example .env.local # then fill in the values below
npm run dev
Open http://localhost:3000.
See .env.example — the app reads exactly these:
| Variable | Required | Description |
|---|---|---|
MONGODB_URI | Yes | MongoDB connection string. Read at import time by src/lib/mongoose.ts — the app throws on startup if missing. |
JWT_SECRET | Yes | Secret used to sign/verify session JWTs (src/lib/auth.ts). |
ALLOWED_ORIGINS | No | Comma-separated extra origins allowed to call the API cross-origin (src/lib/cors.ts). Empty = same-origin only (the default; the app serves its own frontend and API). |
Attraction categories, attraction types, and mood tags are shared reference data (used to tag attractions and trips). Two admin-only endpoints seed sensible defaults on a fresh database — call them once, authenticated as an admin user:
POST /api/mood-tags/seedPOST /api/attraction-categories/seed-from-types| Command | What it does |
|---|---|
npm run dev | Start the Next.js dev server |
npm run build | Production build (also type-checks) |
npm run start | Run the production build |
npm run lint | ESLint |
MONGODB_URI and
JWT_SECRET as project environment variables.Dockerfile and
render.yaml are included for deploying to Render/Railway/Fly.io instead.
next.config.ts sets output: "standalone" to keep the Docker image minimal.Full OpenAPI 3.0 spec: swagger.yaml, served live at
/api-docs via Swagger UI
(src/app/api-docs/, backed by GET /api/openapi). See SPEC.md
for a condensed endpoint table.
Commit history to date is linear on master (no feature-branch/PR workflow has been used
yet) — noted here rather than glossed over, since accurate documentation matters more than
a tidy story.