From 99ebbed799e3fe87574f64db028be0e18a821f79 Mon Sep 17 00:00:00 2001 From: eric Date: Sat, 29 Aug 2026 05:02:29 -0500 Subject: [PATCH] Refresh README for plan/compare sync, native deploy, and product funnel. Co-authored-by: Cursor --- README.md | 306 ++++++++++++++++++++++-------------------------------- 1 file changed, 123 insertions(+), 183 deletions(-) diff --git a/README.md b/README.md index 283e764..035c0e0 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,62 @@ # nomadro · 数字游民旅居平台 -全栈数字游民旅居指南,采用 **Next.js + FastAPI + PocketBase** 架构。 -品牌:**nomadro** — 用一行代码环游世界 🌏 +全栈数字游民旅居指南,品牌 **nomadro** — 用一行代码环游世界 🌏 + +**线上:** [https://nomadweb.nomadro.com](https://nomadweb.nomadro.com) + +核心产品闭环:**发现目的地 → 智能匹配 / 城市对比 → 旅居计划中心 → 登录云端同步** ## 技术栈 | 层级 | 技术 | 说明 | |------|------|------| -| 前端 | Next.js 16 + React 19 | SSR/ISR、组件化 UI、Turbopack | -| 后端 | FastAPI | REST API、业务逻辑 | -| 数据库 | PocketBase | 数据持久化、管理后台 | -| 图表 | Chart.js (CDN) | 数据可视化 | -| 部署 | Vercel + Railway + Docker | 前后端分离部署 | +| 前端 | Next.js 16 + React 19 | App Router、ISR、Turbopack、standalone | +| 后端 | FastAPI | REST API、业务逻辑、账号计划同步 | +| 数据 | PocketBase + Mock 降级 | 内容库;用户收藏/计划可落盘 | +| 部署 | Caddy + systemd(原生优先) | 生产非 Docker 跑 Web/API | ## 项目结构 ``` 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 +├── frontend/ # Next.js +│ ├── src/app/ # 路由:/ /plan /compare /tools /profile … +│ ├── src/components/ # UI 与工具组件 +│ └── src/lib/ # API、auth、trip/plan 存储与同步 +├── backend/ # FastAPI +│ ├── app/routers/ # API 路由 +│ ├── app/services/ # PocketBase、Auth(含计划同步) +│ └── app/data/ # Mock 降级 + user_store(运行时) +├── deploy/ # Caddy、systemd 单元 +├── scripts/ # 本地开发、生产部署脚本 +├── pocketbase/ # PocketBase 数据目录 +└── docker-compose*.yml # 本地 / 备选生产 Compose ``` ## 快速开始 -### 方式一:本地开发(推荐) +### 1. PocketBase(可选) -**1. 启动 PocketBase(可选)** +不启动则 API 自动使用 `backend/app/data/mock_data.py`。 ```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 数据)。 +管理后台:http://localhost:8090/_/ -**2. 启动 FastAPI 后端** +### 2. FastAPI ```bash cd backend pip install -r requirements.txt -cp .env.example .env # 按需修改 +cp .env.example .env uvicorn app.main:app --reload --port 8000 ``` -API 文档: http://localhost:8000/docs +文档:http://localhost:8000/docs -**3. 启动 Next.js 前端** +### 3. Next.js ```bash cd frontend @@ -66,144 +65,86 @@ npm install --legacy-peer-deps npm run dev ``` -访问 http://localhost:3000 +访问:http://localhost:3000 -### 方式二:一键脚本(Windows) +### 其他方式 ```powershell -.\scripts\dev.ps1 +.\scripts\dev.ps1 # Windows 一键 +docker compose up -d # Compose 全栈 ``` -### 方式三:Docker Compose +## 核心产品 -```bash -docker compose up -d -``` +| 能力 | 路径 / 入口 | 说明 | +|------|-------------|------| +| 🗺️ 地图 & 目的地 | `/#map` `/#destinations` | 筛选、收藏、勾选对比(最多 4 城) | +| 🎯 智能匹配 | FAB / `M` | 4 步问卷;偏好本地保存;Top 结果可写入计划 / 对比 | +| ⚖️ 城市对比台 | `/compare` | 可分享 `?cities=`;指标并排;写入计划 | +| 🗓️ 旅居计划中心 | `/plan` | 多城时间轴、出发月、预算、站内备注、签证方案与超期提醒、就绪清单、MD / ICS 导出、分享链接 | +| ☁️ 账号同步 | `/login?next=/plan` | 登录后合并本机与云端计划;收藏同步;服务重启落盘保留 | +| 👤 个人中心 | `/profile` | 计划仪表盘、就绪度、收藏写入计划、成就 | -| 服务 | 地址 | -|------|------| -| 前端 | http://localhost:3000 | -| API | http://localhost:8000/docs | -| PocketBase | http://localhost:8090/_/ | +演示账号:`demo@nomadro.com` / `demo123` -## 功能特性 +## 首页与工具箱 -### 首页核心板块 +首页仍聚合大量旅居工具(按视口懒加载),完整列表见 `/tools` 与 `/changelog`。常见能力包括: -| 板块 | 说明 | -|------|------| -| 🗺️ 世界地图 | 交互式 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 | 搜索 + 展开/收起全部 | +- 费用计算器、多币种、启动金 / 跑道、落地首月成本 +- 时区看板、会议重叠、日照办公窗、时差估算 +- 签证指南 + 停留倒计时、保险、税居天数 +- 联合办公、住宿、SIM、电源、紧急联系、防坑与取现 +- 行李清单、到站清单、专注时钟、博客与 FAQ 等 -### 交互与体验 +导航、Hero、快捷条、底栏与新手引导优先导向 **计划 / 对比**,小工具集中在工具箱。 -- ✨ 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`。 +- 首屏:地图 + 目的地;中屏及以下 `WhenVisible` + 动态拆包 +- Outfit 自托管;中文系统字体;缩短 Loader;粒子延后、无连线 +- 深浅色主题、`Ctrl+K` 全局搜索、Toast、Cookie 提示 +- 响应式布局;`.section` 使用 `content-visibility` ## 页面路由 | 路径 | 说明 | |------|------| -| `/` | 首页(全部板块) | -| `/login` | 登录 / 注册 | +| `/` | 首页 | +| `/plan` | 旅居计划中心 | +| `/compare` | 城市对比台 | +| `/tools` | 工具箱 | +| `/destinations/[slug]` | 目的地详情(画像、停留月数、加入计划) | +| `/login` | 登录 / 注册(`?next=` 回流,默认 `/plan`) | | `/profile` | 用户中心 | -| `/destinations/[slug]` | 目的地详情(城市画像、加入计划) | -| `/plan` | 旅居计划中心(时间轴 / 预算 / 清单 / 分享) | -| `/compare` | 城市对比台(可分享 URL → 写入计划) | -| `/tools` | 工具箱聚合 | -| `/blog/[slug]` | 博客详情(阅读进度) | +| `/blog/[slug]` | 博客 | +| `/about` `/privacy` `/changelog` | 关于 / 隐私 / 更新日志 | +| `/sitemap.xml` | 含 `/plan`、`/compare` 等 | + +## 后端 API(节选) + +| 端点 | 方法 | 说明 | +|------|------|------| +| `/api/v1/destinations` | GET | 列表(region / search / sort) | +| `/api/v1/destinations/{slug}` | GET | 详情 | +| `/api/v1/destinations/compare` | POST | 按 slug 取城 | +| `/api/v1/calculator` | POST | 费用估算 | +| `/api/v1/search` | GET | 全局搜索 | +| `/api/v1/visas` 等 | GET | 签证 / FAQ / 博客 / 图表 | +| `/api/v1/auth/register` | POST | 注册 | +| `/api/v1/auth/login` | POST | 登录 | +| `/api/v1/auth/demo` | GET | 演示登录 | +| `/api/v1/auth/favorites` | GET/POST | 收藏 | +| `/api/v1/auth/plan` | GET/PUT | **旅居计划云端读写** | +| `/api/v1/auth/profile/stats` | GET | 个人统计 | +| `/api/v1/subscribe` | POST | 邮件订阅 | +| `/api/v1/health` | GET | 健康检查 | + +PocketBase 不可用时内容接口降级 Mock。用户收藏与计划写入 `backend/app/data/user_store.json`(运行时生成,勿提交密钥与生产数据)。 ## 环境变量 -### Backend (`backend/.env`) +**Backend `backend/.env`** ```env POCKETBASE_URL=http://127.0.0.1:8090 @@ -212,79 +153,78 @@ POCKETBASE_ADMIN_PASSWORD=admin123456 CORS_ORIGINS=http://localhost:3000 ``` -### Frontend (`frontend/.env.local`) +**Frontend `frontend/.env.local`** ```env NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1 +NEXT_PUBLIC_SITE_URL=http://localhost:3000 +``` + +生产前端构建时: + +```env +NEXT_PUBLIC_API_URL=https://nomadweb.nomadro.com/api/v1 +NEXT_PUBLIC_SITE_URL=https://nomadweb.nomadro.com ``` ## 部署 -### 生产环境(已上线) +### 生产(已上线) | 项目 | 地址 | |------|------| | 网站 | 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 | +| 仓库 | 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` +**架构(原生 systemd,Caddy 反代):** -**更新部署(推荐):** +| 进程 | 地址 | +|------|------| +| Caddy | HTTPS → 见 `deploy/caddy/nomadweb.caddy` | +| `nomadro-web` | `127.0.0.1:3055`(Next standalone) | +| `nomadro-api` | `127.0.0.1:8055`(uvicorn) | +| PocketBase | `127.0.0.1:8090` | + +单元:`deploy/systemd/nomadro-web.service`、`nomadro-api.service`。 + +**推荐更新:** ```bash +# 需能 git pull 到 origin/dev1 时 python scripts/deploy_update.py ``` -脚本会:`git pull` → 按变更增量 `npm run build` / `pip install` → `systemctl restart`,并自动停掉占用端口的旧 Docker 前后端容器。仅前端改动时通常明显快于镜像重建。 +拉取 → 按变更增量构建前后端 → `systemctl restart`;会停掉占用端口的旧 Docker Web/API 容器。 -单元文件:`deploy/systemd/nomadro-web.service`、`deploy/systemd/nomadro-api.service`。 - -**备选:Docker Compose** +**Gitea 不可用 / 仅本地有最新提交时:** ```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 +python scripts/deploy_direct_sync.py ``` -### 本地 Docker Compose +SFTP 同步变更文件 → 重建前端(并重启 API)→ 健康检查。 -```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` 自动部署 +**备选 Docker Compose:** 见 `docker-compose.prod.yml`(生产默认以原生为准)。 ## 快捷键 | 按键 | 功能 | |------|------| | `Ctrl+K` | 全局搜索 | -| `M` | 智能目的地匹配 | +| `M` | 智能匹配 | +| `P` | 打开旅居计划中心 | +| `T` | 打开工具箱 | +| `G` | 命运转盘(首页) | | `?` | 快捷键帮助 | | `Esc` | 关闭弹窗 | +## 相关文档 + +- 产品迭代:[`/changelog`](https://nomadweb.nomadro.com/changelog) +- 本地变更记录:`frontend/src/app/changelog/page.tsx` + ## License MIT