Files
gitlab-instance-0a899031_cn…/cursor.md
2026-06-07 21:02:57 -05:00

441 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NomadCNA — Cursor 项目上下文报告
> 生成日期2026-06-07
> 用途:为 Cursor AI 助手提供项目全貌、架构约定与开发指引。
> 生产站点https://nomadro.cn
---
## 1. 项目简介
**NomadCNA游牧中国** 是面向数字游民的生活操作系统,单仓 Monorepo 包含:
- **主站**:城市探索、下一站决策、活动、社区、支付、统计等
- **Digital 子站**`/digital`):指南、课程、电子书、远程工作、个人资料
- **FastAPI 后端**:认证、业务 API、支付回调、PocketBase 集成
- **外部服务**PocketBase、MinIO、MiroTalk P2P、The Lounge + Ergo IRC
| 模块 | 说明 |
|------|------|
| 城市探索 | 18 城静态数据 + API生活成本/网速/安全等指标 |
| 下一站决策 | `/dashboard`,预算/气候/标签推荐 |
| 活动 | 线上/线下/混合MiroTalk 视频 + Web 群聊 |
| 社区 | 交友匹配、讨论、任务赏金、反馈 |
| 会员与支付 | ZPay / XorPay加入表单 + VIP 状态 |
| Digital 子站 | 课程章节、电子书 Markdown、资源导航 |
| 媒体 | MinIO 上传 + 远程媒体代理缓存 |
---
## 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 |
| 支付 | ZPay / XorPay 适配层 | — |
| 包管理 | pnpm | 10.25.0 |
| Node 生产版本 | — | v22.13.1 |
路径别名:`@/*` → 项目根目录(见 `tsconfig.json`)。
---
## 3. 架构总览
```mermaid
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 --> MiroTalk
Next --> Lounge
Lounge --> Ergo
```
### API 路由分流(关键)
`next.config.ts`**除 `digital` 和 `media` 外** 的所有 `/api/*` 转发到 FastAPI
```ts
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. 目录结构
```text
.
├── app/
│ ├── [locale]/ # 主站多语言页面49 个 page.tsx
│ │ └── digital/ # Digital 子站页面路由
│ ├── api/
│ │ ├── digital/ # Digital 认证、支付、上传、VIP13 个 route
│ │ └── media/proxy/ # 远程媒体代理
│ ├── components/ # 主站通用组件Navbar、Hero、AuthModal 等)
│ ├── context/ # LocaleContext、ThemeContext
│ ├── data/ # cities.ts、map-cities.ts、mock.ts
│ ├── digital/ # Digital 子站组件、lib、context与主站平行
│ └── lib/ # api-client、payment、meetups、pocketbase、charts
├── backend/
│ ├── main.py # FastAPI 入口(~50 个端点)
│ ├── settings.py # 环境变量
│ ├── pb_client.py # PocketBase HTTP 客户端
│ ├── payment.py # ZPay / XorPay
│ └── minio_storage.py # MinIO 上传
├── config/
│ ├── site.config.ts # 主站 SEO
│ ├── nav.config.ts # 顶部导航
│ ├── home.config.ts # 首页静态内容
│ ├── services.config.ts # 主站服务配置
│ └── digital/ # Digital 子站专属配置
├── i18n/
│ ├── routing.ts # locales: zh/en, default: zh
│ └── navigation.ts # 语言感知 Link/Router 导出
├── messages/ # zh.json、en.json 主站文案
├── content/digital/ # Digital 主题数据tools.json 等)
├── public/ # 静态资源
├── next.config.ts
├── package.json
└── pnpm-workspace.yaml
```
### 主站 vs Digital 子站代码边界
| 区域 | 路径 | 说明 |
|------|------|------|
| 主站页面 | `app/[locale]/*` | 城市、活动、社区等 |
| 主站组件 | `app/components/` | Navbar、Sidebar、CityCard 等 |
| 主站工具 | `app/lib/` | api-client、meetups、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`Digital 另有 `content/digital/themes/.../messages/`
- 运行时 i18n`LocaleContext` + `t("key.path")` 点分键
- 语言感知导航:**必须**使用 `i18n/navigation.ts` 导出的 `Link``useRouter`
```tsx
// ✅ 正确
import { Link, useRouter, useTranslation } from "@/i18n/navigation";
// ❌ 避免直接用 next/link会丢失 locale 前缀)
import Link from "next/link";
```
新页面流程:
1.`app/[locale]/` 下创建 `page.tsx`
2.`messages/zh.json``messages/en.json` 补充文案键
3. 如需导航入口,更新 `config/nav.config.ts`
---
## 6. API 端点速查
### 6.1 Next.js Route Handlers`app/api/digital/`
| 路径 | 作用 |
|------|------|
| `auth/login``register``logout``me``sync-session` | Digital 认证 |
| `join` | 加入申请表单 → PocketBase |
| `pay``pay/status``pay/confirm` | Digital 支付 |
| `vip/check` | VIP 状态 |
| `upload-media` | 媒体上传 MinIO |
| `jobs` | 远程工作列表 |
| `media/proxy` | 远程媒体抓取缓存 |
### 6.2 FastAPI`backend/main.py`
| 分类 | 端点示例 |
|------|----------|
| 健康 | `GET /api/health` |
| 认证 | `POST /api/auth/email``/google``GET /api/auth/me` |
| 加入/支付 | `POST /api/join``/api/pay``GET /api/pay/status` |
| 城市/内容 | `GET /api/cities``/api/content/home``POST /api/content/submissions` |
| 活动 | `GET/POST /api/meetups` |
| 社区 | `GET/POST /api/discussions``/api/gigs``/api/profiles``/api/matches/swipes` |
| 通知 | `GET/POST /api/notifications/*` |
| 统计 | `GET /api/stats/member-map``/overview``/city-ranking` |
| 推荐 | `POST /api/recommendations/next-stop` |
| 其他 | `POST /api/feedback``POST /api/ai/assistant`(占位) |
| 支付回调 | `/cnomadcna/zpay_order_status``/cnomadcna/xorpay_notify` |
---
## 7. 核心业务模块指引
### 7.1 城市探索
- 静态数据:`app/data/cities.ts`18 城)
- 首页:`app/[locale]/page.tsx` + `FilterBar``CityCard``CityModal`
- 详情:`app/[locale]/city/[slug]/page.tsx`
- API 补充:`GET /api/cities``/api/cities/{slug}`
### 7.2 活动 / 视频 / 群聊
- 页面:`app/[locale]/meetups/``meetups/host/`
- 核心逻辑:`app/lib/meetups.ts`
- MiroTalk 房间 slug 生成:`createMiroTalkRoomSlug()`
- 默认视频地址:`NEXT_PUBLIC_MIROTALK_URL`
- 默认群聊地址:`NEXT_PUBLIC_LOUNGE_URL`
- 线上/混合活动展示 MiroTalk iframe + The Lounge 入口
### 7.3 支付
- 前端:`app/lib/payment/`client、config、usePayStatusPoll
- Digital 平行:`app/digital/lib/payment/`
- 后端:`backend/payment.py`ZPayProvider、XorPayProvider
- 配置:`config/services.config.ts``config/digital/services.config.ts`
### 7.4 认证
- 主站 Cookie`app/lib/auth-cookie.ts`
- PocketBase 封装:`app/lib/pocketbase/auth.ts`
- FastAPI 会话:`backend/pb_client.py`
### 7.5 图表与年报
- `app/lib/charts/`ECharts 封装ReportChart、MembersMap
- 页面:`app/[locale]/report/``report/data/`
---
## 8. 配置系统
| 文件 | 用途 |
|------|------|
| `config/site.config.ts` | 主站标题、描述、SEO |
| `config/nav.config.ts` | 顶部导航链接 |
| `config/home.config.ts` | 首页成员头像、路线、统计 |
| `config/footer.config.ts` | 页脚链接 |
| `config/filter.config.ts` | 城市筛选选项 |
| `config/services.config.ts` | 主站 PocketBase/支付/MinIO |
| `config/runtime-env.ts` | `APP_ENV` 运行时判断 |
| `config/digital/site.config.ts` | Digital 功能开关、主题 |
| `config/digital/course.ts` | 课程模块数据 |
| `config/digital/lessons.ts` | 课程章节内容 |
| `config/digital/domain.config.ts` | 域名与服务地址推导 |
环境判断:`IS_DEVELOPMENT` / `IS_PRODUCTION` 来自 `config/runtime-env.ts`
---
## 9. 开发命令
```bash
# 安装
pnpm install
# 前端开发(端口 3001非 README 中的 3000
pnpm dev
# 后端开发
python3 -m venv backend/.venv
# Windows: backend\.venv\Scripts\activate
pip install -r backend/requirements.txt
uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
# 质量检查
pnpm lint
pnpm exec tsc --noEmit --pretty false
# 生产构建
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
pnpm start
```
本地需同时运行 **Next.js (:3001)****FastAPI (:8000)** 才能完整调试 API。
---
## 10. 环境变量要点
> ⚠️ 切勿将 `.env.local`、`backend/.env` 或真实密钥提交到 Git。
> `.env.example` 中可能含示例/历史值,生产密钥应通过 systemd Environment 或服务器私密配置管理。
### 前端(`.env.local`
| 变量 | 说明 |
|------|------|
| `APP_ENV` / `NEXT_PUBLIC_APP_ENV` | development / production |
| `NEXT_PUBLIC_SITE_URL` | 站点根地址 |
| `NEXT_PUBLIC_API_BASE_URL` | API 基础路径,生产通常为 `/api` |
| `NEXT_PUBLIC_POCKETBASE_URL` | 浏览器可访问的 PocketBase |
| `NEXT_PUBLIC_MIROTALK_URL` | MiroTalk P2P |
| `NEXT_PUBLIC_LOUNGE_URL` | The Lounge Web 群聊 |
| `NEXT_PUBLIC_MINIO_PUBLIC_URL` | MinIO 公开文件地址 |
### 后端(`backend/.env`
| 变量 | 说明 |
|------|------|
| `PB_URL` / `POCKETBASE_URL` | PocketBase 内网地址 |
| `PB_ADMIN_EMAIL` / `PB_ADMIN_PASSWORD` | 管理员凭据 |
| `FRONTEND_ORIGINS` | CORS 白名单 |
| `PAYMENT_PROVIDER` | zpay 或 xorpay |
| `MINIO_*` | MinIO 连接与桶配置 |
| `DEV_AUTO_PAY` | 开发环境自动完成支付 |
---
## 11. AI 编码约定
修改代码时请遵循以下原则:
### 必须遵守
1. **最小改动**:只改与任务相关的文件,不重构无关代码
2. **匹配现有风格**命名、import 路径(`@/`)、组件结构与服务作者一致
3. **国际化**:新 UI 文案走 `messages/*.json`,使用 `t()` 而非硬编码中文/英文
4. **路由**:新页面放 `app/[locale]/`,链接用 `@/i18n/navigation``Link`
5. **API 调用**:主站用 `app/lib/api-client.ts``apiFetch`
6. **配置分离**:主站配置 → `config/`Digital → `config/digital/`
7. **媒体**:上传/代理优先走 MinIO 相关模块
8. **支付**:复用 `app/lib/payment``backend/payment.py`,不重复实现
9. **活动**:视频/群聊逻辑复用 `app/lib/meetups.ts`
10. **不提交密钥**`.env*`、凭据文件永不入库
### 文件选择决策树
```
新功能属于 Digital 子站?
├── 是 → app/[locale]/digital/ + app/digital/ + config/digital/
└── 否 → app/[locale]/ + app/components/ + config/
需要新 API
├── Digital 专属 → app/api/digital/
├── 媒体代理 → app/api/media/
└── 主站业务 → backend/main.pyFastAPI
需要新文案?
├── 主站 → messages/zh.json + messages/en.json
└── Digital → content/digital/themes/.../messages/ 或 messages/
```
### TypeScript 约定
- `strict: true`,避免 `any`
- 客户端组件文件首行 `"use client"`
- Server Component 默认,仅在需要 hooks/事件时使用 client
### Python 约定
- Pydantic `BaseModel` 做请求体验证
- PocketBase 操作统一走 `pb_client.py`
- 新端点加在 `backend/main.py`,配置放 `settings.py`
---
## 12. 生产部署架构
| 域名 | 上游 | 服务 |
|------|------|------|
| nomadro.cn | :4002 | Next.jscnomadcna.service |
| api.nomadro.cn | :8000 | FastAPI |
| pocketbase.nomadro.cn | :8090 | PocketBase |
| minio.nomadro.cn | :9100/9101 | MinIO API/Console |
| mirotalk.nomadro.cn | :9300 | MiroTalk P2P |
| lounge.nomadro.cn | :9000 | The Lounge |
| ergo.nomadro.cn | HTTPS 重定向 | → loungeIRC 仅本机 :6667 |
生产代码目录:`/home/ubuntu/gitlab-instance-0a899031_cnomadcna`
上线前端:
```bash
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
systemctl restart cnomadcna.service
```
---
## 13. 常见陷阱
| 问题 | 说明 |
|------|------|
| dev 端口 | `pnpm dev` 监听 **3001**,不是 3000 |
| API 分流 | `/api/digital/*` 不走 FastAPI rewrite |
| 双套 lib | 主站 `app/lib/` 与 Digital `app/digital/lib/` 各自独立 |
| 静态 vs API 数据 | 城市等仍以 `app/data/` 静态为主,部分模块接 FastAPI |
| Ergo 公网 | `ergo.nomadro.cn` 不开放 IRC 端口,仅 The Lounge 内网连接 |
| PROJECT_ANALYSIS_REPORT | 2026-06-06 报告认为旧 `app/api` 应逐步替换;当前仓库已并存 FastAPI + Next digital API |
| 密钥泄露 | `.env.example` 含历史示例值,生产必须使用独立密钥 |
---
## 14. 关键文件索引
| 场景 | 文件 |
|------|------|
| 新增主站页面 | `app/[locale]/``messages/*.json` |
| 新增 Digital 页面 | `app/[locale]/digital/``app/digital/components/` |
| 调用后端 | `app/lib/api-client.ts` |
| 活动视频链接 | `app/lib/meetups.ts` |
| 支付流程 | `app/lib/payment/``backend/payment.py` |
| 主题切换 | `app/context/ThemeContext.tsx` |
| 导航配置 | `config/nav.config.ts` |
| API 代理规则 | `next.config.ts` |
| 后端入口 | `backend/main.py` |
| PocketBase 客户端 | `backend/pb_client.py` |
| 完整运维文档 | `README.md` |
| 前端专项分析 | `PROJECT_ANALYSIS_REPORT.md` |
---
## 15. 相关文档
- `README.md` — 完整业务介绍、部署、服务运维、安全注意事项
- `PROJECT_ANALYSIS_REPORT.md` — 前端模块梳理与后续开发方向2026-06-06
- `app/lib/charts/README.md` — 图表组件使用说明
- `.env.example` / `backend/.env.example` — 环境变量模板
---
*本文件供 Cursor AI 在编辑 NomadCNA 代码库时快速建立上下文。重大架构变更后请同步更新此文档。*