nomadweb/README.md
eric 9a6474a69a Wire plan to real visas (CN stay keys) and add ICS calendar export.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-29 03:37:52 -05:00

291 lines
9.8 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.

# nomadro · 数字游民旅居平台
全栈数字游民旅居指南,采用 **Next.js + FastAPI + PocketBase** 架构。
品牌:**nomadro** — 用一行代码环游世界 🌏
## 技术栈
| 层级 | 技术 | 说明 |
|------|------|------|
| 前端 | Next.js 16 + React 19 | SSR/ISR、组件化 UI、Turbopack |
| 后端 | FastAPI | REST API、业务逻辑 |
| 数据库 | PocketBase | 数据持久化、管理后台 |
| 图表 | Chart.js (CDN) | 数据可视化 |
| 部署 | Vercel + Railway + Docker | 前后端分离部署 |
## 项目结构
```
nomadweb/
├── frontend/ # Next.js 前端应用
│ ├── src/app/ # 页面路由 (App Router)
│ ├── src/components/ # UI 组件 (30+)
│ └── src/lib/ # API 客户端、Auth、Toast
├── backend/ # FastAPI 后端
│ ├── app/routers/ # API 路由
│ ├── app/services/ # PocketBase、Auth 服务
│ └── app/data/ # Mock 降级数据
├── pocketbase/ # PocketBase 数据目录
├── scripts/ # 开发启动脚本 (dev.ps1 / dev.sh)
├── docker-compose.yml # 一键启动全部服务
├── index.html # 原始静态版(保留)
└── README.md
```
## 快速开始
### 方式一:本地开发(推荐)
**1. 启动 PocketBase(可选)**
```bash
# 下载: https://pocketbase.io/docs/
# 或使用 Docker:
docker run -d -p 8090:8090 -v ./pocketbase/pb_data:/pb_data ghcr.io/muchobien/pocketbase:latest
```
访问 http://localhost:8090/_/ 创建管理员(可选,不启动则自动使用 Mock 数据)。
**2. 启动 FastAPI 后端**
```bash
cd backend
pip install -r requirements.txt
cp .env.example .env # 按需修改
uvicorn app.main:app --reload --port 8000
```
API 文档: http://localhost:8000/docs
**3. 启动 Next.js 前端**
```bash
cd frontend
cp .env.local.example .env.local
npm install --legacy-peer-deps
npm run dev
```
访问 http://localhost:3000
### 方式二:一键脚本(Windows)
```powershell
.\scripts\dev.ps1
```
### 方式三:Docker Compose
```bash
docker compose up -d
```
| 服务 | 地址 |
|------|------|
| 前端 | http://localhost:3000 |
| API | http://localhost:8000/docs |
| PocketBase | http://localhost:8090/_/ |
## 功能特性
### 首页核心板块
| 板块 | 说明 |
|------|------|
| 🗺️ 世界地图 | 交互式 SVG 热力图,点击查看城市详情 |
| 🌍 目的地 | 筛选/搜索/排序,收藏,最多 4 城对比 |
| 🎯 智能匹配 | 4 步问卷,推荐最适合的旅居城市 |
| 🕐 时区看板 | 实时时钟 + 与国内团队工作时间重叠分析 |
| 🗓️ 行程规划 | 首页快速规划;完整能力见「旅居计划中心」 |
| 🧮 费用计算器 | 按目的地、住宿档次、月数估算预算 |
| 💱 多币种换算 | CNY/USD/EUR/THB 等 8 种货币互转 |
| 📊 就绪度测评 | 5 题评估你的数字游民准备程度 |
| 💻 生活方式 | 交互式「游民一天」时间轴 |
| 📋 签证指南 | 难度筛选 + 签证智能匹配向导 |
| 💻 联合办公 | 精选 Co-working Space,城市/评分/网速排序 |
| 🌤️ 最佳月份 | 12 月气候适宜度热力表,避开雨季 |
| 🧳 行李清单 | 可勾选打包清单,localStorage 持久化 |
| 🎲 命运转盘 | 随机目的地抽选,趣味决策 |
| ✈️ 机票估算 | 出发城 × 季节 × 人数粗算往返票价 |
| 📅 活动日历 | Meetup / 工作坊 / 线上活动 |
| 📶 网速评级 | 远程办公 WiFi 评级与排行 |
| 🎯 启动金目标 | 存款进度追踪,预估出发时间 |
| 🚀 旅居跑道 | 存款 ÷ 月开销,算出还能飞多久 |
| 🤝 会议黄金时段 | 双时区工作重叠可视化 |
| ☀️ 日照办公窗 | 日出日落与深度工作建议 |
| ⚖️ 行李重量 | 对照航司限额估算装备重量 |
| 🛂 签证停留倒计时 | 入境日与剩余天数提醒 |
| 💼 办公点成本 | 月卡 vs 咖啡馆划算度对比 |
| 🛬 落地首月成本 | 房租押金 SIM 接机估算 |
| 📶 流量预算 | 月流量与套餐档建议 |
| ✨ 今日金句 | 每日游民灵感语录 |
| 😴 时差估算 | 时差跨度与恢复期建议 |
| 🏡 住宿指南 | Villa / Coliving / 公寓方案对比 |
| 🗣️ 生存短语 | 多语言常用语一键复制 |
| 💬 反馈入口 | 浮动反馈表单 |
| 🏥 保险指南 | 国际医疗保险方案对比 |
| 📒 支出账本 | 旅居花销分类记录与汇总 |
| 📱 上网方案 | 各城 SIM / eSIM 推荐 |
| 🌏 关于页 | `/about` 品牌介绍 |
| 🧾 税居天数 | 183 天规则停留天数追踪 |
| 🛬 到站清单 | 落地第一周按天勾选 |
| ☕ 咖啡馆 | 办公友好咖啡馆推荐 |
| 👋 新手引导 | 首次访问四步导览 |
| 🔌 电源插座 | 插头类型 / 电压 / 适配建议 |
| 🆘 紧急联系 | 急救、医院、领事馆速查 |
| 📝 城市笔记 | 按城本地记录避坑与灵感 |
| ⏱️ 专注时钟 | 番茄钟深度工作计时 |
| 🛠️ 工具箱页 | `/tools` 分类搜索全部工具 |
| 🗓️ 旅居计划中心 | `/plan` 时间轴、预算、签证方案、超期提醒、就绪清单、MD/ICS 导出;登录同步 |
| ⚖️ 城市对比台 | `/compare` 可分享多城对比,一键写入计划 |
| 📜 更新日志 | `/changelog` 迭代记录 |
| 🏧 取现避坑 | ATM / DCC / 换汇建议 |
| 🥗 饮食饮水 | 各城饮水与街头饮食注意 |
| ⚡ 工具快捷条 | 首页常用工具一键直达 |
| 🔍 搜索增强 | Ctrl+K 可搜工具与页面 |
| 📝 博客 | 标签筛选 + 阅读进度 + 相关推荐 + 分享 |
| ❓ FAQ | 搜索 + 展开/收起全部 |
### 交互与体验
- ✨ Canvas 粒子背景 + 品牌加载动画
- 🌓 深色/浅色主题切换(localStorage 持久化)
- 🔍 全局搜索 `Ctrl+K`(目的地/博客/签证/FAQ)
- 🧭 右侧浮动章节导航
- 📊 顶部滚动进度条
- ⚖️ 可视化城市对比(评分圆环 + 条形图)
- 🔔 全局 Toast 通知
- 💡 游民小贴士浮动提示
- 🍪 Cookie 同意横幅
- ⌨️ 快捷键:`M` 智能匹配、`G` 命运转盘、`?` 帮助面板
- 📱 响应式布局,移动端适配
- 🔒 隐私政策页 `/privacy`
### 用户系统
- 🔐 登录 / 注册 / 一键演示账号
- ❤️ 收藏目的地(同步 API)
- 👤 用户中心:统计、收藏、行程、成就徽章
- 演示账号:`demo@nomadro.com` / `demo123`
### 后端 API
| 端点 | 方法 | 说明 |
|------|------|------|
| `/api/v1/destinations` | GET | 目的地列表(region/search/sort) |
| `/api/v1/destinations/{slug}` | GET | 目的地详情 |
| `/api/v1/destinations/compare` | POST | 城市对比(2–4 城) |
| `/api/v1/calculator` | POST | 费用计算 |
| `/api/v1/search` | GET | 全局搜索 |
| `/api/v1/blog` | GET | 博客列表 |
| `/api/v1/blog/{slug}` | GET | 博客详情 |
| `/api/v1/auth/register` | POST | 注册 |
| `/api/v1/auth/login` | POST | 登录 |
| `/api/v1/auth/demo` | GET | 演示登录 |
| `/api/v1/auth/favorites` | GET/POST | 收藏管理 |
| `/api/v1/charts/*` | GET | 图表数据 |
| `/api/v1/subscribe` | POST | 邮件订阅 |
> PocketBase 不可用时,API 自动降级到 `backend/app/data/mock_data.py`。
## 页面路由
| 路径 | 说明 |
|------|------|
| `/` | 首页(全部板块) |
| `/login` | 登录 / 注册 |
| `/profile` | 用户中心 |
| `/destinations/[slug]` | 目的地详情(城市画像、加入计划) |
| `/plan` | 旅居计划中心(时间轴 / 预算 / 清单 / 分享) |
| `/compare` | 城市对比台(可分享 URL → 写入计划) |
| `/tools` | 工具箱聚合 |
| `/blog/[slug]` | 博客详情(阅读进度) |
## 环境变量
### Backend (`backend/.env`)
```env
POCKETBASE_URL=http://127.0.0.1:8090
POCKETBASE_ADMIN_EMAIL=admin@nomadro.com
POCKETBASE_ADMIN_PASSWORD=admin123456
CORS_ORIGINS=http://localhost:3000
```
### Frontend (`frontend/.env.local`)
```env
NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
```
## 部署
### 生产环境(已上线)
| 项目 | 地址 |
|------|------|
| 网站 | https://nomadweb.nomadro.com |
| API 健康检查 | https://nomadweb.nomadro.com/api/v1/health |
| API 文档 | https://nomadweb.nomadro.com/docs |
| Git 仓库 | https://gitea.dsx2020.com/eric/nomadweb |
**服务器架构(原生优先,非 Docker):**
- 服务器:`107.173.30.245`
- 反向代理:Caddy(自动 HTTPS)→ `deploy/caddy/nomadweb.caddy`
- 前端:`systemd` `nomadro-web` → `127.0.0.1:3055`(Next.js)
- 后端:`systemd` `nomadro-api` → `127.0.0.1:8055`(uvicorn)
- 数据库:主机 PocketBase → `127.0.0.1:8090`
**更新部署(推荐):**
```bash
python scripts/deploy_update.py
```
脚本会:`git pull` → 按变更增量 `npm run build` / `pip install` → `systemctl restart`,并自动停掉占用端口的旧 Docker 前后端容器。仅前端改动时通常明显快于镜像重建。
单元文件:`deploy/systemd/nomadro-web.service`、`deploy/systemd/nomadro-api.service`。
**备选:Docker Compose**
```bash
cd /opt/nomadweb
git fetch origin && git checkout -B dev1 origin/dev1
export DOMAIN=nomadweb.nomadro.com DOCKER_BUILDKIT=1
export NEXT_PUBLIC_API_URL=https://nomadweb.nomadro.com/api/v1
export NEXT_PUBLIC_SITE_URL=https://nomadweb.nomadro.com
export CORS_ORIGINS=https://nomadweb.nomadro.com
docker compose -f docker-compose.prod.yml up -d --build
```
### 本地 Docker Compose
```bash
docker compose up -d
```
### 前端 → Vercel
1. 导入 `frontend/` 目录
2. 环境变量:`NEXT_PUBLIC_API_URL=https://nomadweb.nomadro.com/api/v1`
3. 自动构建部署
### 后端 → Railway
1. 连接 `backend/` 目录
2. 配置 `POCKETBASE_URL`、`CORS_ORIGINS`
3. 读取 `railway.toml` 自动部署
## 快捷键
| 按键 | 功能 |
|------|------|
| `Ctrl+K` | 全局搜索 |
| `M` | 智能目的地匹配 |
| `?` | 快捷键帮助 |
| `Esc` | 关闭弹窗 |
## License
MIT