19 KiB
NomadCNA 前端项目分析报告
生成日期:2026-06-06
1. 分析范围与结论
本报告只分析当前仓库中的前端项目现状。仓库内虽然存在 app/api、PocketBase、支付、MinIO 等旧接口适配代码,但根据当前开发方向,这部分后端实现已隔离,后续应由 FastAPI + PocketBase 重新设计和实现。因此本文不会把旧 app/api 作为未来后端实现依据,只把它们作为“前端当前依赖的接口形状”记录,方便后续替换。
总体判断:
- 当前项目是一个 Next.js 16 App Router 前端应用,核心体验已经具备较完整的页面骨架和视觉资产。
- 主要业务数据仍以 TypeScript 静态数据、配置文件和页面内 mock 数据为主。
- 前端已覆盖城市探索、下一站决策、社区加入、会员支付入口、聚会、匹配、讨论、赏金、工具箱、年报、地图、内容页和法律页等模块。
- 后续真实开发重点不是重写 UI,而是抽离接口层、设计 PocketBase 数据模型、用 FastAPI 承接认证、业务规则、支付、上传、AI、统计等后端能力。
- 当前前端和旧后端存在耦合,需要在后续开发中集中替换为统一 API client 和清晰的数据契约。
2. 技术栈概览
2.1 主要依赖
来自 package.json:
- Next.js:
16.1.6 - React / React DOM:
19.2.3 - TypeScript:
^5 - Tailwind CSS:
^4 - ECharts:
^6.0.0 - PocketBase JS SDK:
^0.26.8 - MinIO SDK:
^8.0.7 - 包管理:
pnpm@10.25.0
2.2 运行脚本
pnpm dev:next dev -p 3001 -H 0.0.0.0pnpm build:生产构建pnpm start:生产启动pnpm lint:ESLint
注意:README.md 中写的是打开 http://localhost:3000,但实际 dev 脚本端口是 3001,文档需要同步。
3. 目录结构与职责
当前关键目录:
app/
[locale]/ 多语言页面路由
components/ 通用前端组件
context/ Locale / Theme Context
data/ 静态业务数据
lib/ 前端工具库、旧服务适配、图表组件
api/ 旧 Next API Route,后续不建议作为目标后端保留
config/ 站点、导航、首页、页脚、服务配置
i18n/ 本地化导航封装
messages/ zh / en 文案
public/ 静态资源
3.1 前端核心文件
app/layout.tsx:全局 HTML、主题脚本、ThemeProvider。app/[locale]/layout.tsx:语言路由布局,加载多语言消息,挂载 Navbar。app/[locale]/page.tsx:首页,包含 Hero、城市列表、筛选、热门路线、社区动态。app/globals.css:Tailwind 4 入口、深色模式、全局布局类、城市卡片和表单样式。app/context/LocaleContext.tsx:自定义 i18n Context 和路由跳转封装。app/context/ThemeContext.tsx:亮色/暗色主题,使用 localStorage 保存偏好。
3.2 配置文件
config/site.config.ts:站点标题、描述、口号。config/nav.config.ts:顶部导航入口。config/home.config.ts:首页成员头像、路线、热门话题、统计数据。config/footer.config.ts:页脚链接。config/services.config.ts、config/domain.config.ts:旧服务配置。未来后端重写时应重构为前端只保留NEXT_PUBLIC_API_BASE_URL等必要公开变量。
4. 页面模块梳理
当前 app/[locale] 下页面较完整,页面数量约 31 个。
4.1 首页与城市探索
相关文件:
app/[locale]/page.tsxapp/components/HeroSection.tsxapp/components/FilterBar.tsxapp/components/CityCard.tsxapp/components/CityModal.tsxapp/data/cities.ts
能力现状:
- 首页展示城市卡片网格,支持按标签筛选和按综合评分、费用、网速、安全、游民数量、温度排序。
- 城市数据来自
app/data/cities.ts,共 18 个城市。 CityCard提供卡片 hover 评分展示。CityModal提供接近 Nomad List 风格的城市详情弹窗,但大量 tab 内容仍是占位。- 首页的成员、路线、热门话题、社区动态来自
config/home.config.ts。
后续真实化方向:
- 城市、城市指标、标签、封面图、热度、评分、评论、气候、网速、生活成本应迁入 PocketBase。
- 首页统计、热门路线、成员头像、热门话题应改由 FastAPI 聚合返回。
- 筛选逻辑目前在前端内存完成;真实数据量上来后应由后端分页、排序、过滤。
4.2 下一站决策仪表盘
相关文件:app/[locale]/dashboard/page.tsx
能力现状:
- 用户可设置预算、最低网速、时区、签证偏好、希望认识的人群。
- 实际筛选只使用预算和网速,数据来自本地
cities。 - 成本曲线、游民密度热力图、AI 推荐等为占位。
后续真实化方向:
- 建立城市推荐 API,根据预算、网速、气候、社区密度、签证、职业偏好等返回排序结果。
- AI 推荐可以由 FastAPI 调用模型服务,结果落库便于复盘。
- 图表数据需要后端提供时间序列、城市指标、用户偏好权重。
4.3 加入社区与会员支付
相关文件:
app/[locale]/join/page.tsxapp/[locale]/join/paid/page.tsxapp/components/JoinModal.tsxapp/components/AuthModal.tsxapp/components/HeroSection.tsx
能力现状:
- 首页 Hero 支持输入邮箱并进入加入/支付流程。
/join是较完整的报名表单,包含昵称、性别、感情状态、职业、微信、手机、自我介绍、学历、毕业时间、头像/视频上传。- 当前页面会调用旧接口:
/api/auth/me、/api/join、/api/join/status、/api/vip/check、/api/upload-media、/api/pay/status、/api/meetup/*等。 - 支付成功页负责完成订单、同步登录态、设置改密状态等。
后续真实化方向:
- FastAPI 统一接管登录、报名、会员状态、订单创建、支付回调、支付状态查询、媒体上传。
- PocketBase 存储用户、资料、报名表、会员权益、订单、支付流水。
- 前端应只调用 FastAPI,不直接处理 PocketBase 管理员逻辑。
- 支付状态和订单状态需要明确状态机,例如
pending、paid、failed、expired、refunded。
4.4 社区、匹配、聚会、讨论、赏金
相关页面:
app/[locale]/dating/page.tsxapp/[locale]/meetups/page.tsxapp/[locale]/meetups/host/page.tsxapp/[locale]/discuss/page.tsxapp/[locale]/gigs/page.tsx
能力现状:
- 匹配页有 profile card、喜欢/不感兴趣按钮、匹配类型 tab,但使用页面内 mock。
- 聚会页有 upcoming / previous tab,聚会列表全部 hardcode。
- 发起聚会页有表单,文案明确“演示模式,数据不会保存”。
- 讨论页使用
MOCK_TOPICS,支持搜索过滤。 - 赏金墙使用
MOCK_GIGS。
后续真实化方向:
- 聚会:活动创建、审核、发布、报名、取消报名、参与者列表、城市筛选。
- 匹配:个人资料、目标类型、滑动记录、互相喜欢、举报/拉黑、推荐排序。
- 讨论:话题、评论、点赞、浏览数、标签、审核。
- 赏金:任务发布、接单、交付、评价、平台抽成、支付/托管。
4.5 工具箱、AI、年报、地图和数据报告
相关页面:
app/[locale]/tools/page.tsxapp/[locale]/ai/page.tsxapp/[locale]/report/page.tsxapp/[locale]/report/data/page.tsxapp/[locale]/map/page.tsxapp/lib/charts/*
能力现状:
- 工具箱包含静态汇率、税务估算、签证倒计时,FIRE 和气候查询为占位。
- AI 页面为即将上线状态。
- 年报页面是静态生成入口和展示样式。
- 地图和数据报告使用
MAP_CITIES静态城市坐标和 ECharts 地图组件。
后续真实化方向:
- 汇率、天气、气候、签证政策属于外部数据集成,应由 FastAPI 定时同步或按需代理。
- 年报依赖用户行程、城市停留、消费、活动报名、社区互动等真实数据。
- 地图应聚合匿名化成员城市分布,避免暴露个人精确位置。
- AI 需要用户上下文、城市数据和安全边界。
4.6 内容与静态信息页
相关页面:
blog、careers、press、helpabout、contact、supportterms、privacy、cookies、safety、guidelines
能力现状:
- 多数内容来自
app/data/mock.ts。 - 页面完成度适合 MVP 展示,但没有 CMS 或后台维护能力。
后续真实化方向:
- 内容可先继续静态化,后期迁入 PocketBase 作为轻量 CMS。
- 法律、隐私、帮助中心等应有版本号和更新时间。
- 招聘、媒体报道、博客需要 slug、SEO metadata、草稿/发布状态。
5. 数据来源现状
5.1 静态数据
app/data/cities.ts:18 个城市,含成本、网速、安全、温度、标签、封面、经纬度等。app/data/map-cities.ts:地图城市坐标和成员数。app/data/mock.ts:博客、招聘、媒体报道、帮助中心、安全指南、社区准则、联系信息、条款、隐私、Cookie。config/home.config.ts:首页社群头像、旅行中成员、聚会、热门话题、路线、统计。- 页面内 mock:聚会、匹配、讨论、赏金等。
5.2 多语言数据
messages/zh.jsonmessages/en.json
当前 i18n 是自定义 Context,不依赖 next-intl。优点是简单可控,缺点是类型约束弱,缺少自动 key 检查,也没有格式化复数、日期、变量插值的完整能力。
5.3 外部资源
当前大量图片来自:
i.pravatar.ccimages.unsplash.comapi.dicebear.comlogo.clearbit.com
这些适合原型阶段,但生产环境需要明确版权、可用性、缓存策略、头像隐私和图片优化策略。
6. 前端状态与交互方式
当前项目大量使用 client component:
useState管理表单、弹窗、tab、筛选、排序。useMemo做城市筛选、聚会分类。localStorage保存主题、旧 PocketBase token、用户信息、支付订单。document.cookie保存旧支付订单状态和服务端 session。createPortal实现 AuthModal、JoinModal、CityModal。window.location.href/replace用于语言切换、支付回跳和登录同步。
后续建议:
- 建立统一
app/lib/api-client.ts或app/services/*,集中处理 API base URL、鉴权、错误码、重试、超时。 - 把旧 PocketBase 前端 SDK 调用逐步移除,前端只通过 FastAPI 访问业务接口。
- 登录态统一为 httpOnly cookie +
/auth/me,避免前端长期保存敏感 token。 - 表单建议引入 schema 校验,例如 Zod;至少在前后端共享字段约束。
7. 当前主要风险
7.1 敏感信息风险
.env.example 和 .env.local 中存在 PocketBase 管理员邮箱和密码字段,并且当前样例包含明文值。即使这些只是旧后端配置,也应立即视为泄露风险:
- 从仓库中移除真实凭据。
- 轮换 PocketBase 管理员密码。
.env.example只保留占位符。- 后续 FastAPI 服务端使用 Secret Manager 或部署平台环境变量。
7.2 前端与旧后端耦合
多个核心前端组件直接调用旧路径:
Navbar:/api/auth/me、/api/auth/sync-sessionHeroSection:/api/auth/me、/api/meetup/check-user、/api/meetup/ensure-userJoinModal:/api/meetup/ensure-userjoin/page.tsx:/api/join、/api/join/status、/api/vip/check、/api/upload-mediajoin/paid/page.tsx:/api/meetup/complete-order、/api/auth/change-password- payment hooks:
/api/pay、/api/pay/status - charts:
/api/geo/china
这些路径后续需要迁移到 FastAPI,并通过统一 API client 映射。
7.3 大量业务仍为 mock
当前页面中明确存在“演示模式”“开发中”“即将上线”:
- 反馈提交
- 发起聚会
- 成员地图
- 数据报告
- AI
- FIRE 计算器
- 气候查询
- 仪表盘图表
这不是坏事,说明前端原型覆盖面广;但后续排期需要明确哪些 mock 优先变成真实闭环。
7.4 日期数据过期
当前日期为 2026-06-06,但聚会页仍把 2026-03 和 2026-04 的活动标记为“即将举办”。后续真实数据必须由后端按当前时间计算活动状态,不能依赖静态 isUpcoming。
7.5 文档与实际运行不一致
- README 写
localhost:3000,脚本实际是3001。 - README 写 Node.js 18+,但 Next.js 16 / React 19 的实际运行要求需要在开发环境中确认并统一。
7.6 UI 资产和图片生产化不足
- 大量使用第三方随机头像和远程图片。
- 未系统使用
next/image。 - 没有图片域名、尺寸、占位、失败回退策略。
8. 后续 FastAPI + PocketBase 目标架构建议
8.1 推荐边界
建议后续边界如下:
Next.js 前端
只负责页面、交互、渲染、调用 FastAPI
FastAPI
负责业务 API、认证会话、权限、支付、上传、AI、统计聚合、外部服务集成
PocketBase
负责数据存储、基础用户表、文件/记录管理、后台管理界面、必要的 realtime 能力
关键原则:
- 前端不要直接使用 PocketBase 管理员权限。
- 复杂业务规则放在 FastAPI,不散落在前端。
- PocketBase 作为数据和后台管理层,不承担所有业务流程。
- 支付回调、会员开通、退款、上传鉴权、AI 调用必须走 FastAPI。
8.2 建议数据模型
首批 PocketBase collections 可按以下方向设计:
users:用户基础账号,可使用 PocketBase auth collection。profiles:昵称、头像、职业、城市、简介、标签、匹配偏好。member_applications:加入社区报名表。memberships:会员等级、有效期、权益、状态。orders:订单号、用户、金额、渠道、状态、业务类型。payment_events:支付回调原始事件和处理状态。media_assets:上传文件、类型、归属用户、用途。cities:城市基础信息、slug、多语言名称、坐标、封面。city_metrics:成本、网速、气候、安全、社区密度等指标。city_guides:城市攻略、共享办公、社区推荐、tips。meetups:聚会活动。meetup_rsvps:活动报名关系。discussions:讨论话题。comments:评论。gigs:赏金任务。gig_applications:接单/投递。swipes:匹配滑动记录。matches:互相喜欢记录。feedback:建议与 Bug 反馈。annual_reports:年报生成结果和快照。
9. FastAPI API 清单草案
9.1 认证与用户
POST /auth/registerPOST /auth/loginPOST /auth/logoutGET /auth/mePOST /auth/change-passwordGET /users/me/profilePATCH /users/me/profile
9.2 加入社区与会员
GET /join/statusPOST /join/applicationsGET /memberships/mePOST /payments/checkoutGET /payments/{order_id}/statusPOST /payments/webhooks/{provider}
9.3 媒体上传
POST /media/uploadsGET /media/{id}DELETE /media/{id}
9.4 城市与推荐
GET /citiesGET /cities/{slug}GET /cities/{slug}/metricsGET /cities/{slug}/guidePOST /recommendations/next-stopGET /routes/hot
9.5 社区模块
GET /meetupsPOST /meetupsGET /meetups/{id}POST /meetups/{id}/rsvpDELETE /meetups/{id}/rsvpGET /discussionsPOST /discussionsGET /discussions/{id}/commentsPOST /discussions/{id}/comments
9.6 匹配模块
GET /matches/candidatesPOST /matches/swipesGET /matches/mePOST /reports/profilePOST /blocks/profile
9.7 赏金与反馈
GET /gigsPOST /gigsPOST /gigs/{id}/applyPOST /feedback
9.8 数据报告与 AI
GET /stats/member-mapGET /stats/city-rankingPOST /reports/annual/generateGET /reports/annual/{id}POST /ai/assistant
10. 前端改造路线
阶段 0:清理与契约冻结
- 移除仓库中的真实密钥,轮换泄露风险凭据。
- 明确旧
app/api全部为 legacy,不继续扩展。 - 建立
NEXT_PUBLIC_API_BASE_URL。 - 梳理当前前端调用接口,写成接口契约文档。
- 修正 README 端口和环境说明。
阶段 1:统一 API client
- 新增统一 API client,集中处理:
- base URL
- credentials
- JSON 解析
- 错误响应
- 登录失效
- loading / retry 策略
- 替换
fetch("/api/...")为领域服务函数,例如authApi.me()、joinApi.submit()。 - 前端保留 mock fallback,方便后端未完成时继续开发 UI。
阶段 2:认证、报名、支付闭环
优先原因:这是转化和会员收入核心链路。
- FastAPI 实现注册、登录、会话、改密。
- FastAPI 实现报名表提交。
- 实现支付下单、支付状态、支付回调、会员开通。
- 实现上传鉴权和媒体资产记录。
- 前端替换 Hero、JoinModal、JoinPage、JoinPaidPage、Navbar 的旧接口调用。
阶段 3:城市数据真实化
- 将
cities.ts迁入 PocketBase。 - 前端首页和仪表盘改为调用
/cities。 - 城市详情弹窗拆分真实字段和占位字段。
- 建立城市 slug,避免只用中文城市名作为业务 key。
阶段 4:社区功能真实化
- 聚会列表和发起聚会落库。
- 讨论和评论落库。
- 匹配候选人、滑动、match 记录落库。
- 赏金墙发布和接单落库。
阶段 5:AI、年报、统计
- 接入 AI 助手。
- 根据真实用户行为生成年度报告。
- 地图、城市排名、增长趋势改由后端聚合。
阶段 6:运营后台与权限
- 使用 PocketBase Admin 作为轻量后台。
- 增加内容审核、聚会审核、举报处理、会员管理、订单查询。
- FastAPI 增加管理员 API 或管理脚本。
11. 建议优先级
P0:
- 凭据清理与轮换。
- 统一 API base URL 和 API client。
- 认证、报名、支付、会员状态真实闭环。
- 上传链路真实化。
P1:
- 城市数据迁移 PocketBase。
- 首页、城市详情、仪表盘接入真实城市 API。
- 聚会列表和报名真实化。
- 反馈提交真实化。
P2:
- 匹配、讨论、赏金墙真实化。
- 地图和数据报告真实化。
- AI 助手上线。
P3:
- 内容 CMS 化。
- SEO metadata 完善。
- 图片优化和 CDN 策略。
- 自动化测试和监控。
12. 测试与验收建议
前端:
pnpm lintpnpm build- 首页、加入表单、登录弹窗、支付回跳、城市筛选、语言切换、暗色模式的 Playwright E2E。
- 移动端视口检查,尤其是首页网格、Join 表单、CityModal。
后端:
- FastAPI 单元测试:认证、报名、支付状态机、权限。
- 支付 webhook 幂等测试。
- PocketBase collection rule 测试。
- 媒体上传大小、类型、权限测试。
契约:
- OpenAPI 自动生成。
- 前端类型从 OpenAPI 生成或至少共享 DTO schema。
- mock server 保持和 OpenAPI 一致。
13. 总结
当前项目的价值主要在前端产品原型和页面覆盖度:导航、首页、城市探索、会员加入、社区、工具、内容页都已经成型。短板集中在数据真实性、后端契约、认证支付安全、mock 数据和旧接口耦合。
后续开发不建议在旧 app/api 上继续补功能。更稳妥的路线是保留当前 Next.js 前端体验,新增 FastAPI 后端,PocketBase 作为数据和后台管理层,然后按“认证/报名/支付 -> 城市数据 -> 社区互动 -> AI/统计”的顺序逐步替换 mock 和旧接口。