This commit is contained in:
eric
2026-06-07 23:57:52 -05:00
parent 6d479c9f94
commit 47b1ae8514
56 changed files with 4163 additions and 874 deletions

146
README.md
View File

@@ -20,8 +20,10 @@ NomadCNA 的目标用户是正在中国或亚洲范围内长期旅居、远程
| --- | --- |
| 城市探索 | 展示中国数字游民城市数据,包括生活成本、网络、温度、社群密度、安全、文化等指标。 |
| 下一站决策 | 根据预算、网络、气候、标签偏好生成城市推荐。 |
| 线上/线下活动 | 支持公开、登录成员、VIP、主持人等权限层级线上混合活动进入 MiroTalk 视频房。 |
| Web 群聊 | 使用 The Lounge + Ergo IRC Server 提供数字游民 Web 群组聊天,活动参与人可进入群聊。 |
| 线上/线下活动 | 支持公开、登录成员、VIP、主持人等权限层级线上/混合活动进入 **统一活动间**MiroTalk 视频 + The Lounge 群聊分屏),账户昵称自动带入视频房。 |
| Web 群聊 | The Lounge + Ergo IRC;每活动可配置 `loungeChannel`(如 `#nomadcna-20260608`),默认频道 `#nomadcna,#online-events`。 |
| 访谈视频 | `/videos` 博主访谈列表,`/videos/[slug]` 单条详情;首页「访谈视频」链到列表页。 |
| 社区匹配 | `/dating` 滑动匹配:意图 Tab、城市筛选、互赞、每日额度、高级筛选、撤销滑动。 |
| 会员加入与支付 | 支持加入表单、支付订单、支付状态轮询、VIP/会员写入。 |
| Digital 子站 | `/digital` 是内容专题站,包含数字游民指南、课程、电子书、资源、工作机会、个人资料等。 |
| 媒体与内容 | 支持图片/视频上传、远程媒体代理缓存、内容投稿、博客、电子书、视频等内容页面。 |
@@ -58,6 +60,8 @@ NomadCNA 的目标用户是正在中国或亚洲范围内长期旅居、远程
│ └── lib/ # API、支付、媒体、活动、PocketBase 等工具
├── backend/ # FastAPI 后端
├── config/ # 主站和 Digital 子站配置
│ └── remote-services.ts # 线上服务地址、Windows 远程开发模式
├── scripts/ # dev-tunnel.py、dev-windows.ps1
├── i18n/ # 路由和国际化导航封装
├── messages/ # zh/en 文案
├── public/ # 静态资源
@@ -73,9 +77,13 @@ NomadCNA 的目标用户是正在中国或亚洲范围内长期旅居、远程
- `/zh``/en`:首页与城市探索
- `/zh/dashboard`:下一站决策仪表盘
- `/zh/meetups`:线上/线下活动,含 MiroTalk 视频房和 Web 群聊入口
- `/zh/meetups`:线上/线下活动列表与详情弹窗
- `/zh/meetups/host`:活动发布页
- `/zh/dating`:社区交友/匹配
- `/zh/meetups/[id]/live`**统一活动间**(内嵌 MiroTalk + The Lounge需权限
- `/zh/videos`:博主访谈视频列表
- `/zh/videos/[slug]`:单条访谈详情
- `/zh/dating`:社区滑动匹配(意图、城市、互赞、额度)
- `/zh/join`:成员加入(城市、寻找意图、资料)
- `/zh/discuss`:讨论
- `/zh/gigs`:任务赏金
- `/zh/tools`:工具箱
@@ -154,13 +162,17 @@ FastAPI 入口为 `backend/main.py`,配置读取在 `backend/settings.py`。
| `/cnomadcna/*_notify` | 支付网关回调 |
| `/api/cities``/api/cities/{slug}` | 城市数据 |
| `/api/content/*` | 首页内容、内容投稿、内容详情 |
| `/api/videos` | 访谈视频列表(`type=video` 的 content_items |
| `/api/notifications/*` | 通知、回执、偏好 |
| `/api/recommendations/next-stop` | 下一站推荐 |
| `/api/meetups` | 活动列表与活动创建 |
| `/api/meetups` | 活动列表与创建 |
| `/api/meetups/{id}` | 单个活动详情 |
| `/api/meetups/{id}/session` | 活动间会话:权限校验、视频/群聊 URL、社区昵称 |
| `/api/matches/*` | 匹配候选、滑动、互赞、额度、撤销、我的资料 |
| `/api/discussions` | 讨论列表与创建 |
| `/api/gigs` | 任务赏金列表、创建、申请 |
| `/api/profiles``/api/matches/swipes` | 资料与匹配 |
| `/api/feedback` | 用户反馈 |
| `/api/profiles` | 资料列表 |
| `/api/feedback` | 用户反馈(支持 `?type=report` 预填) |
| `/api/stats/*` | 成员地图、概览、城市排行 |
| `/api/services``/api/services/leads` | 增值服务与线索 |
| `/api/ai/assistant` | AI 助手占位接口 |
@@ -170,31 +182,68 @@ FastAPI 入口为 `backend/main.py`,配置读取在 `backend/settings.py`。
- `backend/pb_client.py`PocketBase HTTP 客户端
- `backend/payment.py`ZPay / XorPay 支付适配
- `backend/minio_storage.py`MinIO 上传
- `backend/meetup_live.py`:活动间 URL 生成、权限判断MiroTalk / Lounge
- `backend/avatar_assets.py`与前端同步的头像池seed 用)
- `backend/init_db.py``seed_data.py``enhanced_seed.py`:初始化与种子数据
- `backend/settings.py`:环境变量读取
- `backend/settings.py`:环境变量读取(含 `MIROTALK_URL``LOUNGE_URL`
### 活动、视频与群聊源码
### 活动、视频与群聊(深度融合)
活动相关逻辑主要在
相关文件
- `app/[locale]/meetups/page.tsx`
- `app/[locale]/meetups/host/page.tsx`
- `app/lib/meetups.ts`
| 文件 | 作用 |
| --- | --- |
| `app/[locale]/meetups/page.tsx` | 活动列表、详情弹窗、「进入活动间」入口 |
| `app/[locale]/meetups/[id]/live/page.tsx` | 统一活动间页面 |
| `app/components/meetups/EventLiveRoom.tsx` | 分屏 UI视频 iframe + 群聊 iframe |
| `app/[locale]/meetups/host/page.tsx` | 发起活动 |
| `app/lib/meetups.ts` | MiroTalk/Lounge URL、房间 slug、`loungeChannel`、权限工具 |
| `backend/meetup_live.py` | 后端同名逻辑,供 `/api/meetups/{id}/session` 使用 |
`app/lib/meetups.ts` 负责:
- MiroTalk 默认地址:`https://mirotalk.nomadro.cn`
- MiroTalk 房间名规范化
- MiroTalk 入会链接生成
- Lounge 默认地址:`https://lounge.nomadro.cn`
- Web 群聊服务标签:`The Lounge + Ergo IRC`
- MiroTalk 默认地址:`NEXT_PUBLIC_MIROTALK_URL`(生产 `https://mirotalk.nomadro.cn`
- MiroTalk 房间名规范化`buildMiroTalkJoinUrl(meetup, displayName)`
- Lounge 默认地址:`NEXT_PUBLIC_LOUNGE_URL`(生产 `https://lounge.nomadro.cn`
- 活动专属 IRC 频道:`loungeChannel` 字段,或从 `mirotalkRoom` 推导
- 群聊 deep link`buildMeetupChatUrl(meetup)``lounge.nomadro.cn/#/chan-#频道`
- 活动间路径:`buildMeetupLivePath(id)``/meetups/{id}/live`
线上/混合活动详情页会展示:
**账户打通**`GET /api/meetups/{id}/session` 读取 PocketBase 登录态,校验 `public/members/vip/hosts`,将社区昵称写入 MiroTalk `name=` 参数。
- MiroTalk P2P 视频入口
- 页面内 iframe 打开视频房
- The Lounge Web 群聊入口
- 信令/中继服务器和群聊入口域名
PocketBase `meetups` 集合字段(线上活动相关):
- `mode``offline` / `online` / `hybrid`
- `accessLevel``public` / `members` / `vip` / `hosts`
- `meetingProvider`:如 `mirotalk`
- `mirotalkRoom`:视频房间 slug
- `loungeChannel`IRC 频道,如 `#nomadcna-20260608`
- `features`JSON`group_video``screen_share`
### 访谈视频
- 列表:`app/[locale]/videos/page.tsx`,数据来自 `GET /api/videos`
- 详情:`app/[locale]/videos/[slug]/page.tsx`
- 首页右侧「访谈视频」卡片链到 `/videos`(非单条 slug
### 社区匹配Dating
- 页面:`app/[locale]/dating/page.tsx`
- 组件:`app/[locale]/dating/components/``IntentTabs``CityFilter``SwipeStack``LikesPanel``MatchModal``AdvancedFilters``SwipeQuota` 等)
- 工具:`app/[locale]/dating/utils.ts``constants.ts``types.ts`
- 头像池:`app/data/avatars.ts`Unsplash 人像,与 `backend/avatar_assets.py` 同步)
匹配 API均需登录部分需 VIP
- `GET /api/matches/candidates` — 候选列表(意图、城市、性别筛选)
- `POST /api/matches/swipes` — 左滑/右滑/超级赞
- `POST /api/matches/swipes/undo` — 撤销上一次滑动
- `GET /api/matches/likes``/mutual``/quota``/profile/me`
### 媒体代理
- `app/lib/media.ts`:封面 URL 规范化Unsplash 直连、MinIO 相对路径补全)
- `app/api/media/proxy/route.ts`远程媒体抓取MinIO 失败时直返图片
### 配置与国际化
@@ -205,6 +254,7 @@ FastAPI 入口为 `backend/main.py`,配置读取在 `backend/settings.py`。
| `config/footer.config.ts` | 页脚 |
| `config/services.config.ts` | 主站支付配置 |
| `config/runtime-env.ts` | 运行环境判断 |
| `config/remote-services.ts` | 线上域名、MinIO/PocketBase 解析、远程开发模式 |
| `config/digital/*` | Digital 子站主题、服务、课程、域名配置 |
| `messages/zh.json``messages/en.json` | 中英文文案 |
| `i18n/routing.ts` | 语言列表与默认语言 |
@@ -226,6 +276,41 @@ FastAPI 入口为 `backend/main.py`,配置读取在 `backend/settings.py`。
pnpm install
```
### Windows 本地连线上服务
典型配置见 `.env.example` / `.env.local`
1. PocketBase 用公网 `https://pocketbase.nomadro.cn`
2. MinIO S3 API 用 SSH 隧道映射到本机 `9100`
```powershell
python scripts/dev-tunnel.py
```
3. 本地跑 Next.js + FastAPI
```powershell
pnpm dev
# 另开终端
backend\.venv\Scripts\uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
```
或一键脚本:
```powershell
powershell -ExecutionPolicy Bypass -File scripts/dev-windows.ps1
```
服务地址推导见 `config/remote-services.ts`
### 初始化数据库
```bash
python -m backend.init_db
```
会创建/补全 PocketBase 集合字段,并 upsert 城市、活动、内容、资料等种子数据。
### 前端开发
```bash
@@ -275,6 +360,7 @@ APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
| `NEXT_PUBLIC_SITE_URL` | 站点根地址 |
| `NEXT_PUBLIC_SITE_ID` | 站点 ID用于会员/VIP 隔离 |
| `NEXT_PUBLIC_API_BASE_URL` | API 基础地址,生产通常为 `/api` |
| `FASTAPI_PROXY_TARGET` | Next.js rewrite 转发 FastAPI 的目标(本地 `http://127.0.0.1:8000` |
| `NEXT_PUBLIC_POCKETBASE_URL` | 浏览器可访问 PocketBase 地址 |
| `NEXT_PUBLIC_MIROTALK_URL` | MiroTalk P2P 服务地址 |
| `NEXT_PUBLIC_LOUNGE_URL` | The Lounge Web 群聊地址 |
@@ -304,6 +390,8 @@ APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
| `MINIO_UPLOAD_PREFIX` | 上传路径前缀 |
| `FRONTEND_ORIGINS` | FastAPI CORS 白名单 |
| `UPLOAD_DIR` | 后端本地上传目录 |
| `MIROTALK_URL` / `LOUNGE_URL` | 后端生成活动间 URL默认同公网域名 |
| `DEV_SSH_HOST` / `DEV_SSH_PASSWORD` | Windows SSH 隧道(仅本地,勿提交) |
## 生产服务器支持
@@ -484,7 +572,7 @@ curl -I https://mirotalk.nomadro.cn/join?room=nomadcna-healthcheck
- 只监听 `127.0.0.1:9000`
- Nginx 通过 `https://lounge.nomadro.cn` 反代
- 默认网络锁定到本机 Ergo`127.0.0.1:6667`
- 默认加入频道:`#nomadcna,#online-events`
- 默认加入频道:`#nomadcna,#online-events`(可按活动追加,如 `#nomadcna-20260608`
- 文件上传关闭
- The Lounge 自身消息持久化关闭Ergo 保留内存历史
@@ -578,11 +666,17 @@ curl -I https://ergo.nomadro.cn/
### 活动视频房如何生成?
`app/lib/meetups.ts` 会根据活动城市日期时间ID 生成 MiroTalk room slug。如果活动有自定义 `meetingUrl`,则优先使用自定义链接
`app/lib/meetups.ts` 会根据活动 `mirotalkRoom`、或城市/日期/时间/ID 生成 room slug。登录用户通过 `/api/meetups/{id}/session` 获取带 `name=` 的入会 URL
### 如何进入统一活动间?
活动详情弹窗点 **「进入活动间」** → `/meetups/{id}/live`。页面内分屏嵌入 MiroTalk 与 The Lounge也可新窗口单独打开。
### 群聊频道如何进入?
The Lounge public mode 的默认网络已锁定到 Ergo并默认加入 `#nomadcna``#online-events`。活动详情页的“进入群聊”按钮指向 `https://lounge.nomadro.cn`
- 全局:`https://lounge.nomadro.cn`(默认 `#nomadcna``#online-events`
- 单活动:`buildMeetupChatUrl(meetup)``lounge.nomadro.cn/#/chan-#频道`
- PocketBase 活动记录可设 `loungeChannel` 字段
## 维护命令速查