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

15 KiB
Raw Blame History

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. 架构总览

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.tsdigitalmedia 的所有 /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.tsapiFetch() / apiUrl() 调用后端。


4. 目录结构

.
├── 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.jsonmessages/en.jsonDigital 另有 content/digital/themes/.../messages/
  • 运行时 i18nLocaleContext + t("key.path") 点分键
  • 语言感知导航:必须使用 i18n/navigation.ts 导出的 LinkuseRouter
// ✅ 正确
import { Link, useRouter, useTranslation } from "@/i18n/navigation";

// ❌ 避免直接用 next/link会丢失 locale 前缀)
import Link from "next/link";

新页面流程:

  1. app/[locale]/ 下创建 page.tsx
  2. messages/zh.jsonmessages/en.json 补充文案键
  3. 如需导航入口,更新 config/nav.config.ts

6. API 端点速查

6.1 Next.js Route Handlersapp/api/digital/

路径 作用
auth/loginregisterlogoutmesync-session Digital 认证
join 加入申请表单 → PocketBase
paypay/statuspay/confirm Digital 支付
vip/check VIP 状态
upload-media 媒体上传 MinIO
jobs 远程工作列表
media/proxy 远程媒体抓取缓存

6.2 FastAPIbackend/main.py

分类 端点示例
健康 GET /api/health
认证 POST /api/auth/email/googleGET /api/auth/me
加入/支付 POST /api/join/api/payGET /api/pay/status
城市/内容 GET /api/cities/api/content/homePOST /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/feedbackPOST /api/ai/assistant(占位)
支付回调 /cnomadcna/zpay_order_status/cnomadcna/xorpay_notify

7. 核心业务模块指引

7.1 城市探索

  • 静态数据:app/data/cities.ts18 城)
  • 首页:app/[locale]/page.tsx + FilterBarCityCardCityModal
  • 详情: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.pyZPayProvider、XorPayProvider
  • 配置:config/services.config.tsconfig/digital/services.config.ts

7.4 认证

  • 主站 Cookieapp/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. 开发命令

# 安装
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.localbackend/.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/navigationLink
  5. API 调用:主站用 app/lib/api-client.tsapiFetch
  6. 配置分离:主站配置 → config/Digital → config/digital/
  7. 媒体:上传/代理优先走 MinIO 相关模块
  8. 支付:复用 app/lib/paymentbackend/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

上线前端:

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 代码库时快速建立上下文。重大架构变更后请同步更新此文档。