24 KiB
游牧中国 NomadCNA
NomadCNA 是面向数字游民的生活操作系统,用一个站点承载城市决策、会员加入、线上/线下活动、视频会议、Web 群聊、内容资源、任务赏金、支付和媒体存储等能力。
生产站点:
- 主站:https://nomadro.cn
- API:https://api.nomadro.cn
- PocketBase:https://pocketbase.nomadro.cn
- MinIO:https://minio.nomadro.cn
- MiroTalk P2P 视频房:https://mirotalk.nomadro.cn
- Web 群聊:https://lounge.nomadro.cn
- IRC 服务名:https://ergo.nomadro.cn
业务介绍
NomadCNA 的目标用户是正在中国或亚洲范围内长期旅居、远程工作、寻找社群和机会的数字游民。业务上分为以下几条主线:
| 模块 | 说明 |
|---|---|
| 城市探索 | 展示中国数字游民城市数据,包括生活成本、网络、温度、社群密度、安全、文化等指标。 |
| 下一站决策 | 根据预算、网络、气候、标签偏好生成城市推荐。 |
| 线上/线下活动 | 支持公开、登录成员、VIP、主持人等权限层级;线上/混合活动进入 统一活动间(MiroTalk 视频 + The Lounge 群聊分屏),账户昵称自动带入视频房。 |
| Web 群聊 | The Lounge + Ergo IRC;每活动可配置 loungeChannel(如 #nomadcna-20260608),默认频道 #nomadcna,#online-events。 |
| 访谈视频 | /videos 博主访谈列表,/videos/[slug] 单条详情;首页「访谈视频」链到列表页。 |
| 社区匹配 | /dating 滑动匹配:意图 Tab、城市筛选、互赞、每日额度、高级筛选、撤销滑动。 |
| 会员加入与支付 | 支持加入表单、支付订单、支付状态轮询、VIP/会员写入。 |
| Digital 子站 | /digital 是内容专题站,包含数字游民指南、课程、电子书、资源、工作机会、个人资料等。 |
| 媒体与内容 | 支持图片/视频上传、远程媒体代理缓存、内容投稿、博客、电子书、视频等内容页面。 |
| 社区与增长 | 包含讨论、交友匹配、任务赏金、反馈、通知、站内消息、服务线索。 |
技术栈
| 层级 | 技术 |
|---|---|
| Web 前端 | Next.js 16 App Router、React 19、TypeScript、Tailwind CSS 4 |
| API | Next.js Route Handlers、FastAPI、PocketBase SDK/HTTP |
| 数据 | PocketBase、静态数据、MinIO 对象存储 |
| 支付 | ZPay / XorPay 适配层 |
| 视频会议 | MiroTalk P2P,Nginx HTTPS 反代 |
| Web 群聊 | The Lounge 4.5.0 + Ergo IRC Server 2.18.0 |
| 部署 | systemd、Nginx、Certbot、Docker |
| 包管理 | pnpm 10.25.0 |
生产服务器当前 Node.js 版本为 v22.13.1。
源码解析
顶层结构
.
├── app/ # Next.js App Router 主目录
│ ├── [locale]/ # 中文/英文路由,默认 zh
│ ├── api/ # Next.js Route Handlers
│ ├── components/ # 主站通用组件
│ ├── context/ # Locale、Theme 等上下文
│ ├── data/ # 城市、地图、mock 数据
│ ├── digital/ # Digital 子站组件、配置、数据和工具
│ └── lib/ # API、支付、媒体、活动、PocketBase 等工具
├── backend/ # FastAPI 后端
├── config/ # 主站和 Digital 子站配置
│ └── remote-services.ts # 线上服务地址、Windows 远程开发模式
├── scripts/ # dev-tunnel.py、dev-windows.ps1
├── i18n/ # 路由和国际化导航封装
├── messages/ # zh/en 文案
├── public/ # 静态资源
├── cnomadcna.sh # 生产 Next.js 启动脚本
├── next.config.ts # Next.js 配置与 API rewrites
├── package.json # 前端依赖与脚本
└── tsconfig.json # TypeScript 配置
Next.js 页面结构
主站所有面向用户的页面位于 app/[locale],路由强制带语言前缀:
/zh、/en:首页与城市探索/zh/dashboard:下一站决策仪表盘/zh/meetups:线上/线下活动列表与详情弹窗/zh/meetups/host:活动发布页/zh/meetups/[id]/live:统一活动间(内嵌 MiroTalk + The Lounge,需权限)/zh/videos:博主访谈视频列表/zh/videos/[slug]:单条访谈详情/zh/dating:社区滑动匹配(意图、城市、互赞、额度)/zh/join:成员加入(城市、寻找意图、资料)/zh/discuss:讨论/zh/gigs:任务赏金/zh/tools:工具箱/zh/report、/zh/report/data:统计与年报/zh/digital:Digital 子站入口
通用布局与组件:
app/layout.tsx:根布局app/[locale]/layout.tsx:语言布局app/components/Navbar.tsx、Footer.tsx、Sidebar.tsx:主站导航与外壳app/context/LocaleContext.tsx:运行时文案读取app/context/ThemeContext.tsx:亮色/暗色主题
Digital 子站
Digital 子站代码集中在 app/digital 与 app/[locale]/digital:
app/[locale]/digital/page.tsx:专题首页app/[locale]/digital/course:课程页app/[locale]/digital/course/[moduleIndex]/[lessonIndex]:课程章节app/[locale]/digital/ebook:电子书app/[locale]/digital/jobs:远程工作app/[locale]/digital/join:加入/申请app/[locale]/digital/profile:用户资料
配置在 config/digital:
site.config.ts:专题主题、功能开关、课程/电子书/加入等能力services.config.ts:PocketBase、支付、MinIO 配置读取domain.config.ts:域名和服务地址推导course.ts、lessons.ts:课程数据
API 分层
本项目有两层 API:
- Next.js 内置 API:
app/api/* - FastAPI 后端:
backend/main.py
next.config.ts 将大多数 /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
Next.js API
| 路径 | 作用 |
|---|---|
app/api/digital/auth/* |
Digital 子站登录、退出、当前用户、注册、跨站同步 |
app/api/digital/join |
Digital 加入/申请表单写入 PocketBase |
app/api/digital/pay/* |
Digital 支付创建、确认、状态查询 |
app/api/digital/upload-media |
媒体上传到 MinIO |
app/api/digital/vip/check |
VIP 状态检查 |
app/api/media/proxy |
远程媒体抓取、校验、缓存到 MinIO 后跳转公开 URL |
FastAPI 后端
FastAPI 入口为 backend/main.py,配置读取在 backend/settings.py。核心能力:
| API | 作用 |
|---|---|
/api/health |
健康检查 |
/api/auth/email、/api/auth/google、/api/auth/me |
主站认证 |
/api/join、/api/join/status |
加入表单与状态 |
/api/upload-media |
后端媒体上传 |
/api/pay、/api/pay/status |
支付创建与查询 |
/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/{id} |
单个活动详情 |
/api/meetups/{id}/session |
活动间会话:权限校验、视频/群聊 URL、社区昵称 |
/api/matches/* |
匹配候选、滑动、互赞、额度、撤销、我的资料 |
/api/discussions |
讨论列表与创建 |
/api/gigs |
任务赏金列表、创建、申请 |
/api/profiles |
资料列表 |
/api/feedback |
用户反馈(支持 ?type=report 预填) |
/api/stats/* |
成员地图、概览、城市排行 |
/api/services、/api/services/leads |
增值服务与线索 |
/api/ai/assistant |
AI 助手占位接口 |
后端辅助模块:
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:环境变量读取(含MIROTALK_URL、LOUNGE_URL)
活动、视频与群聊(深度融合)
相关文件:
| 文件 | 作用 |
|---|---|
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 默认地址:
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= 参数。
PocketBase meetups 集合字段(线上活动相关):
mode:offline/online/hybridaccessLevel:public/members/vip/hostsmeetingProvider:如mirotalkmirotalkRoom:视频房间 slugloungeChannel:IRC 频道,如#nomadcna-20260608features: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 失败时直返图片
配置与国际化
| 文件 | 作用 |
|---|---|
config/site.config.ts |
主站 SEO 与站点基础信息 |
config/nav.config.ts |
顶部导航 |
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 |
语言列表与默认语言 |
i18n/navigation.ts |
语言路由 Link / Router 封装 |
本地开发
环境要求
- Node.js 20+,生产当前使用 Node.js 22.13.1
- pnpm 10+
- Python 3.12+
- PocketBase
- 可选:MinIO、ZPay/XorPay 测试配置
安装依赖
pnpm install
Windows 本地连线上服务
典型配置见 .env.example / .env.local:
- PocketBase 用公网
https://pocketbase.nomadro.cn - MinIO S3 API 用 SSH 隧道映射到本机
9100:
python scripts/dev-tunnel.py
- 本地跑 Next.js + FastAPI:
pnpm dev
# 另开终端
backend\.venv\Scripts\uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
或一键脚本:
powershell -ExecutionPolicy Bypass -File scripts/dev-windows.ps1
服务地址推导见 config/remote-services.ts。
初始化数据库
python -m backend.init_db
会创建/补全 PocketBase 集合字段,并 upsert 城市、活动、内容、资料等种子数据。
前端开发
pnpm dev
默认启动在:
http://localhost:3001
FastAPI 后端开发
python3 -m venv backend/.venv
source backend/.venv/bin/activate
pip install -r backend/requirements.txt
uvicorn backend.main:app --host 127.0.0.1 --port 8000 --reload
构建与启动
pnpm build
pnpm start
常用检查
pnpm lint
pnpm exec tsc --noEmit --pretty false
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
环境变量
不要把真实密钥提交到 Git。.env.example 只放示例值,生产值放 .env.local、backend/.env 或 systemd Environment。
前端公开变量
| 变量 | 说明 |
|---|---|
APP_ENV |
development / production |
NEXT_PUBLIC_APP_ENV |
浏览器可见运行环境 |
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 群聊地址 |
NEXT_PUBLIC_MINIO_PUBLIC_URL |
MinIO 文件公开地址 |
后端和服务端变量
| 变量 | 说明 |
|---|---|
POCKETBASE_URL |
服务端访问 PocketBase 的内网地址 |
POCKETBASE_EMAIL |
PocketBase 管理员邮箱 |
POCKETBASE_PASSWORD |
PocketBase 管理员密码 |
PAYMENT_API_URL |
支付 API 地址 |
PAYMENT_PROVIDER |
zpay 或 xorpay |
PAYMENT_DEFAULT_AMOUNT |
默认支付金额 |
PAYMENT_JOIN_AMOUNT |
加入场景金额 |
PAYMENT_JOIN_TYPE |
加入场景订单类型 |
ZPAY_PID、ZPAY_KEY |
ZPay 商户配置 |
XORPAY_AID、XORPAY_SECRET |
XorPay 商户配置 |
MINIO_ENDPOINT |
MinIO 内网端点 |
MINIO_PORT |
MinIO 端口 |
MINIO_USE_SSL |
是否对 MinIO 内网连接启用 SSL |
MINIO_BUCKET |
存储桶 |
MINIO_ACCESS_KEY |
MinIO Access Key |
MINIO_SECRET_KEY |
MinIO Secret Key |
MINIO_REGION |
MinIO 区域 |
MINIO_UPLOAD_PREFIX |
上传路径前缀 |
FRONTEND_ORIGINS |
FastAPI CORS 白名单 |
UPLOAD_DIR |
后端本地上传目录 |
MIROTALK_URL / LOUNGE_URL |
后端生成活动间 URL(默认同公网域名) |
DEV_SSH_HOST / DEV_SSH_PASSWORD |
Windows SSH 隧道(仅本地,勿提交) |
生产服务器支持
生产代码目录:
/home/ubuntu/gitlab-instance-0a899031_cnomadcna
域名与服务映射
| 域名 | 上游 | 说明 |
|---|---|---|
nomadro.cn / www.nomadro.cn |
127.0.0.1:4002 |
Next.js 主站,cnomadcna.service |
api.nomadro.cn |
127.0.0.1:8000 |
FastAPI |
pocketbase.nomadro.cn |
127.0.0.1:8090 |
PocketBase |
minio.nomadro.cn |
127.0.0.1:9100 / 9101 |
MinIO API / Console |
mirotalk.nomadro.cn |
127.0.0.1:9300 |
MiroTalk P2P |
lounge.nomadro.cn |
127.0.0.1:9000 |
The Lounge Web IRC |
ergo.nomadro.cn |
HTTPS redirect | 跳转到 lounge.nomadro.cn;IRC 后端只内网监听 |
ntfy.nomadro.cn |
127.0.0.1:9180 |
ntfy 通知服务 |
systemd 服务
| 服务 | 作用 | 当前策略 |
|---|---|---|
cnomadcna.service |
Next.js 生产服务 | enabled,监听 0.0.0.0:4002 |
mirotalk-p2p.service |
MiroTalk P2P | enabled,监听 127.0.0.1:9300 |
ergo.service |
Ergo IRC Server | enabled,监听 127.0.0.1:6667 和 [::1]:6667 |
thelounge.service |
The Lounge Web IRC | enabled,监听 127.0.0.1:9000 |
常用命令:
systemctl status cnomadcna.service
systemctl status mirotalk-p2p.service
systemctl status ergo.service
systemctl status thelounge.service
journalctl -u cnomadcna.service -n 100 --no-pager
journalctl -u mirotalk-p2p.service -n 100 --no-pager
journalctl -u ergo.service -n 100 --no-pager
journalctl -u thelounge.service -n 100 --no-pager
Docker 服务
当前生产容器:
| 容器 | 镜像 | 端口 |
|---|---|---|
nomadro-minio |
minio/minio:latest |
127.0.0.1:9100->9000,127.0.0.1:9101->9001 |
nomadro-ntfy |
binwiederhier/ntfy:latest |
127.0.0.1:9180->80 |
检查:
docker ps
docker logs nomadro-minio --tail 100
docker logs nomadro-ntfy --tail 100
Nginx
Nginx vhost 目录:
/www/server/panel/vhost/nginx
关键配置:
www.nomadro.cn.conf:主站api.nomadro.cn.conf:FastAPImirotalk.nomadro.cn.conf:MiroTalklounge.nomadro.cn.conf:The Lounge + Ergo redirectminio.nomadro.cn.conf:MinIOpocketbase.nomadro.cn.conf:PocketBase
常用命令:
nginx -t
nginx -s reload
HTTPS 证书
证书由 Certbot 管理。lounge.nomadro.cn 证书包含两个域名:
lounge.nomadro.cn
ergo.nomadro.cn
当前证书路径:
/etc/letsencrypt/live/lounge.nomadro.cn/fullchain.pem
/etc/letsencrypt/live/lounge.nomadro.cn/privkey.pem
检查:
certbot certificates
MiroTalk P2P
安装目录:
/opt/nomadro-services/mirotalk
运行方式:
- systemd:
mirotalk-p2p.service - 内网端口:
127.0.0.1:9300 - 公网入口:
https://mirotalk.nomadro.cn - 活动页自动生成链接:
https://mirotalk.nomadro.cn/join?room=...&name=...
健康检查:
curl -I https://mirotalk.nomadro.cn/join?room=nomadcna-healthcheck
Ergo IRC Server
安装目录:
/opt/ergo
配置:
/etc/ergo/ircd.yaml
/etc/ergo/ergo.motd
/var/lib/ergo/ircd.db
当前策略:
- 网络名:
NomadCNA - 服务名:
ergo.nomadro.cn - 只监听本机
127.0.0.1:6667和[::1]:6667 - 不开放公网 IRC TLS
6697 ergo.nomadro.cn的 HTTPS 请求跳转到 The Lounge
本机 IRC 握手检查:
{ printf 'NICK health\r\nUSER health 0 * :NomadCNA Health\r\nJOIN #nomadcna\r\nQUIT :healthcheck\r\n'; sleep 1; } \
| timeout 5s nc 127.0.0.1 6667
The Lounge Web 群聊
安装目录:
/opt/nomadro-services/thelounge
配置:
/var/lib/thelounge/config.js
当前策略:
- public mode
- 只监听
127.0.0.1:9000 - Nginx 通过
https://lounge.nomadro.cn反代 - 默认网络锁定到本机 Ergo:
127.0.0.1:6667 - 默认加入频道:
#nomadcna,#online-events(可按活动追加,如#nomadcna-20260608) - 文件上传关闭
- The Lounge 自身消息持久化关闭,Ergo 保留内存历史
健康检查:
curl -I https://lounge.nomadro.cn/
curl 'https://lounge.nomadro.cn/socket.io/?EIO=4&transport=polling&t=health'
上线流程
前端上线
cd /home/ubuntu/gitlab-instance-0a899031_cnomadcna
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
systemctl restart cnomadcna.service
systemctl status cnomadcna.service --no-pager
后端上线
FastAPI 当前运行在 127.0.0.1:8000。更新后需重启对应 uvicorn 进程或其 systemd 服务。如果后续为 FastAPI 增加 systemd 单元,建议命名为:
cnomadcna-api.service
Nginx 配置变更
nginx -t
nginx -s reload
服务健康检查
curl -I https://nomadro.cn/zh/meetups
curl -I https://api.nomadro.cn/api/health
curl -I https://mirotalk.nomadro.cn/join?room=nomadcna-healthcheck
curl -I https://lounge.nomadro.cn/
curl -I https://ergo.nomadro.cn/
数据与备份
建议纳入备份的内容:
| 路径/服务 | 说明 |
|---|---|
.env.local、backend/.env |
生产环境变量和密钥 |
| PocketBase 数据目录 | 用户、会员、订单、内容、活动等业务数据 |
| MinIO 数据卷 | 上传媒体、远程媒体缓存 |
/var/lib/ergo |
Ergo IRC 数据库 |
/var/lib/thelounge |
The Lounge 配置、VAPID key、包配置 |
/opt/nomadro-services/mirotalk |
MiroTalk 源码部署目录 |
/www/server/panel/vhost/nginx/*.conf |
Nginx vhost 配置 |
/etc/systemd/system/*.service |
systemd 单元 |
安全注意事项
- README 不应包含真实密钥、管理员密码、支付密钥或 MinIO Secret。
.env.local和backend/.env不应提交到 Git。- The Lounge 当前为 public mode,适合活动公开群聊;如需长期身份和历史,可切换 private mode 并创建用户账号。
- Ergo 原生 IRC 公网端口当前不开放,这是有意设计;需要原生 IRC 客户端时再开放
6697并配置 TLS。 - 内部服务优先绑定
127.0.0.1,统一通过 Nginx HTTPS 暴露。 - 修改 Nginx 前必须先
nginx -t。 - 更新证书后确认 SAN 包含对应域名。
开发约定
- 新页面优先放入
app/[locale],并补充messages/zh.json、messages/en.json。 - 需要语言感知链接时使用
i18n/navigation.ts导出的Link。 - 调用后端 API 使用
app/lib/api-client.ts。 - 主站通用配置放
config/*,Digital 子站配置放config/digital/*。 - 媒体上传和远程媒体代理优先走 MinIO。
- 支付相关逻辑优先复用
app/lib/payment、backend/payment.py和config/*/services.config.ts。 - 线上活动相关逻辑优先复用
app/lib/meetups.ts。
常见问题
为什么 ergo.nomadro.cn 不直接打开 IRC?
ergo.nomadro.cn 是 IRC 服务名,但原生 IRC 端口没有对公网开放。用户从浏览器进入 lounge.nomadro.cn,The Lounge 在服务器本机连接 Ergo。这样能减少公网攻击面,同时满足 Web 群聊需求。
为什么 /api/digital/* 没有转发到 FastAPI?
next.config.ts 明确排除了 digital 和 media 两类 API,它们由 Next.js Route Handlers 直接处理。其他 /api/* 才会转发到 FastAPI。
活动视频房如何生成?
app/lib/meetups.ts 会根据活动 mirotalkRoom、或城市/日期/时间/ID 生成 room slug。登录用户通过 /api/meetups/{id}/session 获取带 name= 的入会 URL。
如何进入统一活动间?
活动详情弹窗点 「进入活动间」 → /meetups/{id}/live。页面内分屏嵌入 MiroTalk 与 The Lounge;也可新窗口单独打开。
群聊频道如何进入?
- 全局:
https://lounge.nomadro.cn(默认#nomadcna、#online-events) - 单活动:
buildMeetupChatUrl(meetup)→lounge.nomadro.cn/#/chan-#频道 - PocketBase 活动记录可设
loungeChannel字段
维护命令速查
# 构建并重启主站
APP_ENV=production NEXT_PUBLIC_APP_ENV=production NODE_ENV=production pnpm build
systemctl restart cnomadcna.service
# 查看服务
systemctl status cnomadcna.service --no-pager
systemctl status mirotalk-p2p.service --no-pager
systemctl status ergo.service --no-pager
systemctl status thelounge.service --no-pager
# 查看日志
journalctl -u cnomadcna.service -n 100 --no-pager
journalctl -u mirotalk-p2p.service -n 100 --no-pager
journalctl -u ergo.service -n 100 --no-pager
journalctl -u thelounge.service -n 100 --no-pager
# Nginx
nginx -t
nginx -s reload
# 端口
ss -ltnp | rg ':4002|:8000|:8090|:9000|:9300|:9100|:9101|:6667|:6697'
# Docker
docker ps
# HTTPS
certbot certificates