16 KiB
NomadCNA — Cursor 项目上下文报告
更新日期:2026-06-08
用途:为 Cursor AI 助手提供项目全貌、架构约定与开发指引。
生产站点:https://nomadro.cn
1. 项目简介
NomadCNA(游牧中国) 是面向数字游民的生活操作系统,单仓 Monorepo 包含:
- 主站:城市探索、下一站决策、活动、社区匹配、支付、统计、访谈视频等
- Digital 子站(
/digital):指南、课程、电子书、远程工作、个人资料 - FastAPI 后端:认证、业务 API、支付回调、PocketBase 集成
- VPS 自建开源服务:MiroTalk P2P(视频)、The Lounge + Ergo IRC(Web 群聊)
| 模块 | 说明 |
|---|---|
| 城市探索 | 18 城静态数据 + API,生活成本/网速/安全等指标 |
| 下一站决策 | /dashboard,预算/气候/标签推荐 |
| 活动 | 线上/线下/混合;统一活动间 /meetups/[id]/live 深度融合 MiroTalk + Lounge |
| 访谈视频 | /videos 列表 + /videos/[slug] 详情 |
| 社区匹配 | /dating 滑动匹配、意图/城市筛选、互赞、额度、撤销 |
| 会员与支付 | ZPay / XorPay,加入表单 + VIP 状态 |
| Digital 子站 | 课程章节、电子书 Markdown、资源导航 |
| 媒体 | MinIO 上传 + app/lib/media.ts + /api/media/proxy |
2. 技术栈
| 层级 | 技术 | 版本 |
|---|---|---|
| 前端框架 | Next.js App Router | 16.1.6 |
| UI | React + TypeScript | 19.2.3 / TS 5 |
| 样式 | Tailwind CSS | 4 |
| 图表 | ECharts | 6 |
| Markdown | marked, react-markdown, highlight.js | — |
| 后端 | FastAPI + uvicorn | ≥0.115 |
| 数据库 | PocketBase | SDK 0.27 |
| 对象存储 | MinIO | Node + Python SDK |
| 视频会议 | MiroTalk P2P | VPS :9300 |
| Web 群聊 | The Lounge 4.5 + Ergo IRC 2.18 | VPS :9000 / :6667 |
| 支付 | ZPay / XorPay 适配层 | — |
| 包管理 | pnpm | 10.25.0 |
| Node 生产版本 | — | v22.13.1 |
路径别名:@/* → 项目根目录(见 tsconfig.json)。
3. 架构总览
flowchart TB
subgraph Client["浏览器"]
Next["Next.js 16<br/>:3001 dev / :4002 prod"]
end
subgraph APIs["API 层"]
NextAPI["Next Route Handlers<br/>/api/digital/*<br/>/api/media/*"]
FastAPI["FastAPI<br/>:8000<br/>/api/*"]
end
subgraph Data["数据与服务"]
PB["PocketBase :8090"]
MinIO["MinIO :9100"]
MiroTalk["MiroTalk P2P :9300"]
Lounge["The Lounge :9000"]
Ergo["Ergo IRC :6667"]
end
Client --> Next
Next -->|"rewrite 排除 digital/media"| FastAPI
Next --> NextAPI
NextAPI --> PB
NextAPI --> MinIO
FastAPI --> PB
FastAPI --> MinIO
Next -->|"活动间 iframe"| MiroTalk
Next -->|"活动间 iframe"| Lounge
Lounge --> Ergo
API 路由分流(关键)
next.config.ts 将 除 digital 和 media 外 的所有 /api/* 转发到 FastAPI:
source: "/api/:path((?!(?:digital|media)(?:$|/.*)).*)"
destination: "http://127.0.0.1:8000/api/:path*"
| 路径前缀 | 处理方 |
|---|---|
/api/digital/* |
Next.js Route Handlers |
/api/media/* |
Next.js Route Handlers |
其他 /api/* |
FastAPI(经 rewrite 代理) |
前端统一通过 app/lib/api-client.ts 的 apiFetch() / apiUrl() 调用后端。
4. 目录结构
.
├── app/
│ ├── [locale]/ # 主站多语言页面(~54 个 page.tsx)
│ │ ├── dating/ # 匹配页 + components/
│ │ ├── meetups/ # 活动列表、host、[id]/live 活动间
│ │ ├── videos/ # 访谈列表 + [slug] 详情
│ │ └── digital/ # Digital 子站页面路由
│ ├── api/
│ │ ├── digital/ # Digital 认证、支付、上传、VIP
│ │ └── media/proxy/ # 远程媒体代理
│ ├── components/
│ │ └── meetups/EventLiveRoom.tsx # 活动间分屏 UI
│ ├── context/ # LocaleContext、ThemeContext
│ ├── data/ # cities.ts、avatars.ts、mock.ts
│ ├── digital/ # Digital 子站组件、lib、context
│ └── lib/ # api-client、meetups、media、payment、pocketbase
├── backend/
│ ├── main.py # FastAPI 入口(~70 个端点)
│ ├── meetup_live.py # 活动间 URL / 权限
│ ├── avatar_assets.py # 头像池(与前端 avatars.ts 同步)
│ ├── settings.py # 环境变量
│ ├── pb_client.py # PocketBase HTTP 客户端
│ ├── payment.py # ZPay / XorPay
│ ├── minio_storage.py # MinIO 上传
│ ├── init_db.py # 集合 schema + seed
│ └── seed_data.py # 种子数据
├── config/
│ ├── remote-services.ts # 线上服务地址、Windows 远程开发
│ ├── site.config.ts # 主站 SEO
│ ├── nav.config.ts # 顶部导航
│ └── digital/ # Digital 子站专属配置
├── scripts/
│ ├── dev-tunnel.py # SSH 隧道:MinIO → localhost:9100
│ └── dev-windows.ps1 # Windows 一键开发
├── i18n/ # routing.ts、navigation.ts
├── messages/ # zh.json、en.json 主站文案
└── next.config.ts
主站 vs Digital 子站代码边界
| 区域 | 路径 | 说明 |
|---|---|---|
| 主站页面 | app/[locale]/* |
城市、活动、匹配、视频等 |
| 主站组件 | app/components/ |
Navbar、EventLiveRoom 等 |
| 主站工具 | app/lib/ |
api-client、meetups、media、payment |
| Digital 页面 | app/[locale]/digital/* |
课程、电子书、工作等 |
| Digital 组件 | app/digital/components/ |
独立 Header、Hero、课程区块 |
| Digital 工具 | app/digital/lib/ |
平行的 payment、pocketbase、learning |
| Digital 配置 | config/digital/* |
课程、域名、视觉主题 |
两套代码 有意平行(非完全共享),修改时注意对应目录。
5. 路由与国际化
- 语言:
zh(默认)、en,路由 始终带前缀(/zh/...、/en/...) - 配置:
i18n/routing.ts - 文案:
messages/zh.json、messages/en.json - 语言感知导航:必须使用
i18n/navigation.ts的Link、useRouter、useTranslation
import { Link, useRouter, useTranslation } from "@/i18n/navigation";
新页面:在 app/[locale]/ 建 page.tsx → 补 messages/*.json → 必要时改 config/nav.config.ts。
6. API 端点速查
6.1 Next.js Route Handlers
| 路径 | 作用 |
|---|---|
app/api/digital/auth/* |
Digital 认证 |
app/api/digital/join、pay/*、vip/check |
加入、支付、VIP |
app/api/digital/upload-media |
媒体上传 MinIO |
app/api/media/proxy |
远程媒体抓取/缓存 |
6.2 FastAPI(backend/main.py)
| 分类 | 端点 |
|---|---|
| 健康/认证 | GET /api/health,`POST /api/auth/email |
| 加入/支付 | POST /api/join,POST /api/pay,GET /api/pay/status |
| 城市/内容 | GET /api/cities,GET /api/content/home,GET /api/content/{slug} |
| 视频 | GET /api/videos |
| 活动 | GET/POST /api/meetups,GET /api/meetups/{id},GET /api/meetups/{id}/session |
| 匹配 | `GET /api/matches/candidates |
| 社区 | GET/POST /api/discussions,/api/gigs,GET /api/profiles |
| 通知/统计 | /api/notifications/*,/api/stats/* |
| 其他 | POST /api/feedback,POST /api/recommendations/next-stop |
| 支付回调 | /cnomadcna/zpay_order_status,/cnomadcna/xorpay_notify |
注意:/api/videos 必须独立路由,不能走 /api/content/{slug}(slug=videos 会 404)。
7. 核心业务模块指引
7.1 城市探索
- 静态:
app/data/cities.ts(18 城) - 首页:
app/[locale]/page.tsx+ FilterBar、CityCard、CityModal - API:
GET /api/cities、/api/cities/{slug}
7.2 活动 / 视频 / 群聊(深度融合)
| 层级 | 文件 |
|---|---|
| 列表/弹窗 | app/[locale]/meetups/page.tsx |
| 活动间 | app/[locale]/meetups/[id]/live/page.tsx |
| UI 组件 | app/components/meetups/EventLiveRoom.tsx |
| 前端逻辑 | app/lib/meetups.ts |
| 后端逻辑 | backend/meetup_live.py |
| 会话 API | GET /api/meetups/{id}/session |
流程:
- 用户打开活动详情 → 「进入活动间」
- Live 页请求
/api/meetups/{id}/session(带 Cookie) - 返回
videoUrl(MiroTalk +name=)、chatUrl(Lounge channel deep link)、canJoin EventLiveRoom分屏 iframe 嵌入;支持只看视频/只看群聊
PocketBase meetups 关键字段:mode、accessLevel、mirotalkRoom、loungeChannel、features。
7.3 访谈视频
- 列表:
app/[locale]/videos/page.tsx→GET /api/videos - 详情:
app/[locale]/videos/[slug]/page.tsx - 首页 video 卡片
targetUrl固定/videos(见app/[locale]/page.tsx的normalizeHomeContentItem)
7.4 社区匹配(Dating)
- 页面:
app/[locale]/dating/page.tsx - 组件目录:
app/[locale]/dating/components/IntentTabs、CityFilter、SwipeStack、SwipeCardLikesPanel、MatchModal、AdvancedFilters、SwipeQuota
- 常量/类型:
constants.ts、types.ts、utils.ts - 头像:
app/data/avatars.ts↔backend/avatar_assets.py - Schema:
profiles(lookingFor、gender、citySlug)、swipes(intent)、match_connections
7.5 支付
- 前端:
app/lib/payment/ - Digital:
app/digital/lib/payment/ - 后端:
backend/payment.py - 配置:
config/services.config.ts、config/digital/services.config.ts
7.6 媒体
app/lib/media.ts:URL 规范化、Unsplash 直连、MinIO 公开路径app/api/media/proxy/route.ts:代理失败时 passthrough 原图
7.7 认证
- Cookie:
app/lib/auth-cookie.ts - PocketBase:
app/lib/pocketbase/auth.ts - FastAPI 会话:
backend/pb_client.py+current_user()
8. 配置系统
| 文件 | 用途 |
|---|---|
config/site.config.ts |
主站 SEO |
config/nav.config.ts |
顶部导航 |
config/home.config.ts |
首页静态块 |
config/remote-services.ts |
nomadro.cn 各服务 URL、MinIO/PB 解析、isRemoteDevMode() |
config/services.config.ts |
主站 PocketBase/支付/MinIO |
config/runtime-env.ts |
APP_ENV 判断 |
config/digital/* |
Digital 子站 |
9. 开发命令
pnpm install
pnpm dev # http://localhost:3001
# 后端(Windows)
python -m venv backend/.venv
backend\.venv\Scripts\pip install -r backend/requirements.txt
backend\.venv\Scripts\uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
# Windows 连线上 MinIO
python scripts/dev-tunnel.py
# 初始化 PocketBase 集合 + 种子
python -m backend.init_db
# 质量检查(上线前)
pnpm lint
pnpm exec tsc --noEmit --pretty false
PowerShell 不支持 &&,命令分步执行。
本地需 Next.js (:3001) + FastAPI (:8000) 同时运行。8000 端口若被多个旧 uvicorn 占用,新路由不会生效——先杀干净再启一个实例。
10. 环境变量要点
⚠️ 勿提交
.env.local、backend/.env或真实密钥。
前端(.env.local)
| 变量 | 说明 |
|---|---|
NEXT_PUBLIC_SITE_URL |
本地 http://localhost:3001 |
NEXT_PUBLIC_API_BASE_URL |
生产 /api;本地可留空走 rewrite |
FASTAPI_PROXY_TARGET |
rewrite 目标,默认 http://127.0.0.1:8000 |
NEXT_PUBLIC_POCKETBASE_URL |
PocketBase |
NEXT_PUBLIC_MIROTALK_URL |
MiroTalk |
NEXT_PUBLIC_LOUNGE_URL |
The Lounge |
NEXT_PUBLIC_MINIO_PUBLIC_URL |
MinIO 公开读 |
DEV_SSH_* |
dev-tunnel 用(勿提交密码) |
后端(backend/.env)
| 变量 | 说明 |
|---|---|
POCKETBASE_URL |
内网或公网 PB |
MIROTALK_URL / LOUNGE_URL |
活动间 URL 生成 |
MINIO_* |
对象存储 |
DEV_AUTO_PAY |
开发自动完成支付 |
完整列表见 .env.example 与 README.md。
11. AI 编码约定
必须遵守
- 最小改动:只改任务相关文件
- 匹配现有风格:
@/import、组件结构一致 - 国际化:UI 文案走
messages/*.json+t() - 路由:
app/[locale]/+@/i18n/navigation的Link - API:主站用
app/lib/api-client.ts的apiFetch - 活动:复用
app/lib/meetups.ts+backend/meetup_live.py - 媒体:复用
app/lib/media.ts - 支付:复用
app/lib/payment+backend/payment.py - 不提交密钥
文件选择决策树
新功能属于 Digital?
├── 是 → app/[locale]/digital/ + app/digital/ + config/digital/
└── 否 → app/[locale]/ + app/components/ + config/
需要新 API?
├── Digital → app/api/digital/
├── 媒体代理 → app/api/media/
└── 主站业务 → backend/main.py
线上活动?
├── 列表/弹窗 → meetups/page.tsx
├── 活动间 → meetups/[id]/live + EventLiveRoom.tsx
└── URL/权限 → meetups.ts + meetup_live.py + /session API
Python 约定
- 请求体用 Pydantic
BaseModel - PocketBase 走
pb_client.py - 新端点加
main.py,配置加settings.py
12. 生产部署架构
| 域名 | 上游 | 服务 |
|---|---|---|
| nomadro.cn | :4002 | Next.js(cnomadcna.service) |
| api.nomadro.cn | :8000 | FastAPI |
| pocketbase.nomadro.cn | :8090 | PocketBase |
| minio.nomadro.cn | :9100/9101 | MinIO |
| mirotalk.nomadro.cn | :9300 | MiroTalk P2P |
| lounge.nomadro.cn | :9000 | The Lounge |
| ergo.nomadro.cn | HTTPS 重定向 | → lounge(IRC 仅本机 :6667) |
VPS:82.157.112.245,代码目录 /home/ubuntu/gitlab-instance-0a899031_cnomadcna。
上线前端:
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
systemctl restart cnomadcna.service
活动间相关改动需同步部署 Next.js + FastAPI,VPS 上 MiroTalk/Lounge 配置变更需 systemctl restart。
13. 常见陷阱
| 问题 | 说明 |
|---|---|
| dev 端口 | pnpm dev → 3001,不是 3000 |
| API 分流 | /api/digital/*、/api/media/* 不走 FastAPI |
/api/videos |
独立路由;/api/content/videos 会 404 |
| 8000 多进程 | 多个 uvicorn 占端口时 session 等新路由可能不生效 |
| PowerShell | 不支持 &&,分步执行 |
| 双套 lib | app/lib/ vs app/digital/lib/ 各自独立 |
| MiroTalk embed | ALLOWED_EMBED_ORIGINS 需含 nomadro.cn 与 localhost:3001 |
| Ergo 公网 | 不开放 IRC 6697;仅 The Lounge 内网连 Ergo |
| 密钥 | .env.example 仅示例,生产用独立密钥 |
14. 关键文件索引
| 场景 | 文件 |
|---|---|
| 新增主站页面 | app/[locale]/、messages/*.json |
| 活动间 | meetups/[id]/live/page.tsx、EventLiveRoom.tsx、meetup_live.py |
| 活动 URL/权限 | app/lib/meetups.ts |
| 访谈视频 | videos/page.tsx、GET /api/videos |
| 社区匹配 | dating/page.tsx、dating/components/* |
| 调用后端 | app/lib/api-client.ts |
| 封面/媒体 URL | app/lib/media.ts |
| 头像池 | app/data/avatars.ts、backend/avatar_assets.py |
| 远程开发 | config/remote-services.ts、scripts/dev-tunnel.py |
| API 代理 | next.config.ts |
| 后端入口 | backend/main.py |
| DB 初始化 | backend/init_db.py、seed_data.py |
| 完整运维 | README.md |
15. 相关文档
README.md— 业务介绍、部署、MiroTalk/Lounge 运维、Windows 本地开发.env.example— 环境变量模板app/lib/charts/README.md— 图表组件
本文件供 Cursor AI 编辑 NomadCNA 时快速建立上下文。重大架构变更后请同步更新。