1 line
16 KiB
JSON
1 line
16 KiB
JSON
{"repo": "1849083010n-cell/framene", "files": {"SYNC_GUIDE.md": {"ec26a11e1481739a43bfcc3f9771647862c4dfde": {"t": 1785746604.068498, "n": 6707, "h": "3dfd9334f2a1cbb0", "c": "# FrameNe 启动 & ngrok & API 测试指南\n\n> 每次需要启动 Web 端和 App 端的前后端时,按照此流程操作。\n\n## 目录\n\n1. [重启完整流程](#1-重启完整流程)\n2. [ngrok 隧道管理](#2-ngrok-隧道管理)\n3. [API 全面测试](#3-api-全面测试)\n4. [飞书重新授权](#4-飞书重新授权)\n5. [常见问题](#5-常见问题)\n\n---\n\n## 1. 重启完整流程\n\n### 1.1 杀掉旧进程\n\n```bash\n# 强制释放所有端口\nkill $(lsof -t -i :3000) 2>/dev/null\nkill $(lsof -t -i :5173) 2>/dev/null\nkill $(lsof -t -i :8080) 2>/dev/null\nkill $(pgrep -f \"ngrok http 3000\") 2>/dev/null\nsleep 1\n\n# 验证端口空闲\nlsof -i :3000 -P 2>/dev/null | grep LISTEN || echo \"3000 free\"\nlsof -i :5173 -P 2>/dev/null | grep LISTEN || echo \"5173 free\"\nlsof -i :8080 -P 2>/dev/null | grep LISTEN || echo \"8080 free\"\n```\n\n### 1.2 启动 ngrok 隧道\n\n```bash\nngrok http 3000 --log=stdout 2>&1 &\nsleep 3\n\n# 获取 ngrok 公网 URL\ncurl -s http://localhost:4040/api/tunnels | python3 -c \"import sys,json; print([x['public_url'] for x in json.load(sys.stdin).get('tunnels',[])][0])\"\n```\n\n**注意:** 如果 ngrok URL 变了,需要更新 `.env` 中的回调地址:\n```bash\n# 假设新URL为 https://xxx.ngrok-free.dev\nsed -i '' \"s|DINGTALK_CALLBACK_URL=.*|DINGTALK_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/dingtalk-callback|\" framene-server/.env\nsed -i '' \"s|FEISHU_CALLBACK_URL=.*|FEISHU_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/feishu-callback|\" framene-server/.env\nsed -i '' \"s|DINGTALK_CALLBACK_URL=.*|DINGTALK_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/dingtalk-callback|\" framene-server/scripts/.env\nsed -i '' \"s|FEISHU_CALLBACK_URL=.*|FEISHU_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/feishu-callback|\" framene-server/scripts/.env\n```\n\n### 1.3 启动后端 (Express, port 3000)\n\n```bash\ncd framene-server\n\n# 确保 .env 从 scripts/.env 同步\ncp scripts/.env .env 2>/dev/null\n\n# 启动(后台)\nnode index.js &\n\n# 等待启动完成\nsleep 3\n\n# 验证\ncurl -s http://localhost:3000/api/health\n# 应返回: {\"status\":\"ok\",\"timestamp\":\"...\"}\n```\n\n### 1.4 启动 Web 前端 (Vite, port 5173)\n\n```bash\ncd frame_app\n# 如果 node_modules 不存在则先安装\n# npm install\nnpm run dev &\n\nsleep 3\ncurl -s -o /dev/null -w \"HTTP %{http_code}\" http://localhost:5173\n# 应返回: HTTP 200\n```\n\n### 1.5 启动 App 前端 (Flutter Web, port 8080)\n\n```bash\ncd frame_app/flutter_oss_example\n\n# 如果 build 不存在或代码有变化需要先构建\n# flutter build web\n\ncd build/web && python3 -m http.server 8080 &\n\nsleep 2\ncurl -s -o /dev/null -w \"HTTP %{http_code}\" http://localhost:8080\n# 应返回: HTTP 200\n```\n\n---\n\n## 2. ngrok 隧道管理\n\n### 2.1 查看当前 ngrok URL\n\n```bash\ncurl -s http://localhost:4040/api/tunnels | python3 -c \"import sys,json; t=json.load(sys.stdin); print(t['tunnels'][0]['public_url'] if t['tunnels'] else 'no tunnel')\"\n```\n\n### 2.2 检查 ngrok 回调是否可达\n\n```bash\n# 获取 ngrok URL\nNGROK_URL=$(curl -s http://localhost:4040/api/tunnels | python3 -c \"import sys,json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])\")\n\n# 测试回调\ncurl -s -o /dev/null -w \"HTTP %{http_code}\" \"$NGROK_URL/api/health\"\n# 应返回: HTTP 200(通过 ngrok 代理访问后端)\n```\n\n### 2.3 检查 ngrok 代理的后端日志\n\n```bash\n# ngrok web 界面\nopen http://localhost:4040\n```\n\n---\n\n## 3. API 全面测试\n\n### 3.1 准备 JWT Token\n\n```bash\ncd /Users/erzhuonie/Documents/GitHub/framenee1/framene-server\nTOKEN=$(node -e \"const jwt=require('jsonwebtoken');console.log(jwt.sign({userId:5},'framene-dev-secret-key',{expiresIn:'1h'}));\")\n```\n\n### 3.2 旧 API 测试\n\n```bash\necho \"=== 旧 API ===\"\ncurl -s http://localhost:3000/api/health | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/me | head -c 60\ncurl -s http://localhost:3000/api/photos | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/events | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/members | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/feishu-auth-url | head -c 60\ncurl -s http://localhost:3000/api/auth/dingtalk-auth-url | head -c 60\n```\n\n### 3.3 新 Web API 测试\n\n```bash\necho \"=== Web API ===\"\ncurl -s http://localhost:3000/api/web/events | head -c 60\ncurl -s http://localhost:3000/api/web/events/completed-summary\ncurl -s http://localhost:3000/api/web/events/completed-records\ncurl -s http://localhost:3000/api/web/accounts\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"text\":\"明天早上八点去吃饭\",\"timezone\":\"Asia/Shanghai\",\"utcOffset\":480}' \\\n http://localhost:3000/api/web/events/parse-voice\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"items\":[{\"title\":\"test\",\"startAt\":\"2026-06-17T10:00:00Z\",\"endAt\":\"2026-06-17T10:30:00Z\"}]}' \\\n http://localhost:3000/api/web/events/voice-create\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"1849083010n@gmail.com\"}' \\\n http://localhost:3000/api/web/events/sync-from-account\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"user@example.com\",\"name\":\"test\"}' \\\n http://localhost:3000/api/web/accounts/sync\n```\n\n---\n\n## 4. 飞书重新授权\n\n当飞书 access_token 过期(2小时有效期)时,需要重新走 OAuth 授权流程:\n\n### 4.1 获取飞书授权 URL\n\n```bash\ncd /Users/erzhuonie/Documents/GitHub/framenee1/framene-server\nTOKEN=$(node -e \"const jwt=require('jsonwebtoken');console.log(jwt.sign({userId:5},'framene-dev-secret-key',{expiresIn:'1h'}));\")\nAUTH_URL=$(curl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/feishu-auth-url | python3 -c \"import sys,json;print(json.load(sys.stdin).get('auth_url',''))\")\necho \"$AUTH_URL\"\n# 在浏览器中打开此 URL\n```\n\n### 4.2 检查授权结果\n\n```bash\n# 确认飞书已连接\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/me | python3 -c \"import sys,json;d=json.load(sys.stdin);print('飞书连接:', d.get('feishu_calendar_connected'), '飞书用户:', d.get('feishu_name'))\"\n```\n\n### 4.3 测试飞书同步\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/events/sync/feishu | python3 -c \"import sys,json;d=json.load(sys.stdin);print('同步结果:', d.get('events_synced','错误'), d.get('error',''))\"\n```\n\n---\n\n## 5. 常见问题\n\n### 5.1 ngrok URL 变了\n\n每次重启 ngrok(如果免费版),URL 可能变化。更新 `.env` 和 `scripts/.env` 中的回调地址:\n- `DINGTALK_CALLBACK_URL`\n- `FEISHU_CALLBACK_URL`\n- `APP_URL` — 如果有需要\n\n### 5.2 .env 文件同步\n\n`framene-server/` 下有两个 `.env` 相关文件:\n- `framene-server/.env` — 后端启动时读取\n- `framene-server/scripts/.env` — 备份/模板\n\n启动后端时执行 `cp scripts/.env .env` 确保同步。\n\n### 5.3 DeepSeek API Key 格式\n\n正确的格式(dotenv 要求):\n```ini\nDEEPSEEK_API_KEY=sk-你的key\n```\n错误格式(不会被读取):\n```ini\nDeepseek api key = sk-xxx # ❌ 空格+大小写\nDeepSeek API Key = sk-xxx # ❌\n```\n\n### 5.4 JWT 认证\n\n测试需要 JWT token 的 API 时,使用 `framene-dev-secret-key`(默认密钥,如果 `.env` 中没有设置 `JWT_SECRET` 的话)。\n\n```bash\n# 生成测试 token(user_id=5)\nnode -e \"const jwt=require('jsonwebtoken');console.log(jwt.sign({userId:5},'framene-dev-secret-key',{expiresIn:'1h'}));\"\n```\n\n### 5.5 端口占用\n\n| 端口 | 服务 | 检查命令 |\n|------|------|----------|\n| 3000 | 后端 Express | `lsof -i :3000` |\n| 5173 | Web 前端 Vite | `lsof -i :5173` |\n| 8080 | App 前端 Flutter | `lsof -i :8080` |\n| 4040 | ngrok 管理界面 | `lsof -i :4040` |\n\n"}, "dab46bf62ef0295fb9904ed6c3285123e1f11db1": {"t": 1785766215.5967782, "n": 6707, "h": "3dfd9334f2a1cbb0", "c": "# FrameNe 启动 & ngrok & API 测试指南\n\n> 每次需要启动 Web 端和 App 端的前后端时,按照此流程操作。\n\n## 目录\n\n1. [重启完整流程](#1-重启完整流程)\n2. [ngrok 隧道管理](#2-ngrok-隧道管理)\n3. [API 全面测试](#3-api-全面测试)\n4. [飞书重新授权](#4-飞书重新授权)\n5. [常见问题](#5-常见问题)\n\n---\n\n## 1. 重启完整流程\n\n### 1.1 杀掉旧进程\n\n```bash\n# 强制释放所有端口\nkill $(lsof -t -i :3000) 2>/dev/null\nkill $(lsof -t -i :5173) 2>/dev/null\nkill $(lsof -t -i :8080) 2>/dev/null\nkill $(pgrep -f \"ngrok http 3000\") 2>/dev/null\nsleep 1\n\n# 验证端口空闲\nlsof -i :3000 -P 2>/dev/null | grep LISTEN || echo \"3000 free\"\nlsof -i :5173 -P 2>/dev/null | grep LISTEN || echo \"5173 free\"\nlsof -i :8080 -P 2>/dev/null | grep LISTEN || echo \"8080 free\"\n```\n\n### 1.2 启动 ngrok 隧道\n\n```bash\nngrok http 3000 --log=stdout 2>&1 &\nsleep 3\n\n# 获取 ngrok 公网 URL\ncurl -s http://localhost:4040/api/tunnels | python3 -c \"import sys,json; print([x['public_url'] for x in json.load(sys.stdin).get('tunnels',[])][0])\"\n```\n\n**注意:** 如果 ngrok URL 变了,需要更新 `.env` 中的回调地址:\n```bash\n# 假设新URL为 https://xxx.ngrok-free.dev\nsed -i '' \"s|DINGTALK_CALLBACK_URL=.*|DINGTALK_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/dingtalk-callback|\" framene-server/.env\nsed -i '' \"s|FEISHU_CALLBACK_URL=.*|FEISHU_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/feishu-callback|\" framene-server/.env\nsed -i '' \"s|DINGTALK_CALLBACK_URL=.*|DINGTALK_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/dingtalk-callback|\" framene-server/scripts/.env\nsed -i '' \"s|FEISHU_CALLBACK_URL=.*|FEISHU_CALLBACK_URL=https://xxx.ngrok-free.dev/api/auth/feishu-callback|\" framene-server/scripts/.env\n```\n\n### 1.3 启动后端 (Express, port 3000)\n\n```bash\ncd framene-server\n\n# 确保 .env 从 scripts/.env 同步\ncp scripts/.env .env 2>/dev/null\n\n# 启动(后台)\nnode index.js &\n\n# 等待启动完成\nsleep 3\n\n# 验证\ncurl -s http://localhost:3000/api/health\n# 应返回: {\"status\":\"ok\",\"timestamp\":\"...\"}\n```\n\n### 1.4 启动 Web 前端 (Vite, port 5173)\n\n```bash\ncd frame_app\n# 如果 node_modules 不存在则先安装\n# npm install\nnpm run dev &\n\nsleep 3\ncurl -s -o /dev/null -w \"HTTP %{http_code}\" http://localhost:5173\n# 应返回: HTTP 200\n```\n\n### 1.5 启动 App 前端 (Flutter Web, port 8080)\n\n```bash\ncd frame_app/flutter_oss_example\n\n# 如果 build 不存在或代码有变化需要先构建\n# flutter build web\n\ncd build/web && python3 -m http.server 8080 &\n\nsleep 2\ncurl -s -o /dev/null -w \"HTTP %{http_code}\" http://localhost:8080\n# 应返回: HTTP 200\n```\n\n---\n\n## 2. ngrok 隧道管理\n\n### 2.1 查看当前 ngrok URL\n\n```bash\ncurl -s http://localhost:4040/api/tunnels | python3 -c \"import sys,json; t=json.load(sys.stdin); print(t['tunnels'][0]['public_url'] if t['tunnels'] else 'no tunnel')\"\n```\n\n### 2.2 检查 ngrok 回调是否可达\n\n```bash\n# 获取 ngrok URL\nNGROK_URL=$(curl -s http://localhost:4040/api/tunnels | python3 -c \"import sys,json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])\")\n\n# 测试回调\ncurl -s -o /dev/null -w \"HTTP %{http_code}\" \"$NGROK_URL/api/health\"\n# 应返回: HTTP 200(通过 ngrok 代理访问后端)\n```\n\n### 2.3 检查 ngrok 代理的后端日志\n\n```bash\n# ngrok web 界面\nopen http://localhost:4040\n```\n\n---\n\n## 3. API 全面测试\n\n### 3.1 准备 JWT Token\n\n```bash\ncd /Users/erzhuonie/Documents/GitHub/framenee1/framene-server\nTOKEN=$(node -e \"const jwt=require('jsonwebtoken');console.log(jwt.sign({userId:5},'framene-dev-secret-key',{expiresIn:'1h'}));\")\n```\n\n### 3.2 旧 API 测试\n\n```bash\necho \"=== 旧 API ===\"\ncurl -s http://localhost:3000/api/health | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/me | head -c 60\ncurl -s http://localhost:3000/api/photos | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/events | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/members | head -c 60\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/feishu-auth-url | head -c 60\ncurl -s http://localhost:3000/api/auth/dingtalk-auth-url | head -c 60\n```\n\n### 3.3 新 Web API 测试\n\n```bash\necho \"=== Web API ===\"\ncurl -s http://localhost:3000/api/web/events | head -c 60\ncurl -s http://localhost:3000/api/web/events/completed-summary\ncurl -s http://localhost:3000/api/web/events/completed-records\ncurl -s http://localhost:3000/api/web/accounts\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"text\":\"明天早上八点去吃饭\",\"timezone\":\"Asia/Shanghai\",\"utcOffset\":480}' \\\n http://localhost:3000/api/web/events/parse-voice\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"items\":[{\"title\":\"test\",\"startAt\":\"2026-06-17T10:00:00Z\",\"endAt\":\"2026-06-17T10:30:00Z\"}]}' \\\n http://localhost:3000/api/web/events/voice-create\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"1849083010n@gmail.com\"}' \\\n http://localhost:3000/api/web/events/sync-from-account\ncurl -s -X POST -H \"Content-Type: application/json\" \\\n -d '{\"email\":\"user@example.com\",\"name\":\"test\"}' \\\n http://localhost:3000/api/web/accounts/sync\n```\n\n---\n\n## 4. 飞书重新授权\n\n当飞书 access_token 过期(2小时有效期)时,需要重新走 OAuth 授权流程:\n\n### 4.1 获取飞书授权 URL\n\n```bash\ncd /Users/erzhuonie/Documents/GitHub/framenee1/framene-server\nTOKEN=$(node -e \"const jwt=require('jsonwebtoken');console.log(jwt.sign({userId:5},'framene-dev-secret-key',{expiresIn:'1h'}));\")\nAUTH_URL=$(curl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/feishu-auth-url | python3 -c \"import sys,json;print(json.load(sys.stdin).get('auth_url',''))\")\necho \"$AUTH_URL\"\n# 在浏览器中打开此 URL\n```\n\n### 4.2 检查授权结果\n\n```bash\n# 确认飞书已连接\ncurl -s -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/auth/me | python3 -c \"import sys,json;d=json.load(sys.stdin);print('飞书连接:', d.get('feishu_calendar_connected'), '飞书用户:', d.get('feishu_name'))\"\n```\n\n### 4.3 测试飞书同步\n\n```bash\ncurl -s -X POST -H \"Authorization: Bearer $TOKEN\" http://localhost:3000/api/events/sync/feishu | python3 -c \"import sys,json;d=json.load(sys.stdin);print('同步结果:', d.get('events_synced','错误'), d.get('error',''))\"\n```\n\n---\n\n## 5. 常见问题\n\n### 5.1 ngrok URL 变了\n\n每次重启 ngrok(如果免费版),URL 可能变化。更新 `.env` 和 `scripts/.env` 中的回调地址:\n- `DINGTALK_CALLBACK_URL`\n- `FEISHU_CALLBACK_URL`\n- `APP_URL` — 如果有需要\n\n### 5.2 .env 文件同步\n\n`framene-server/` 下有两个 `.env` 相关文件:\n- `framene-server/.env` — 后端启动时读取\n- `framene-server/scripts/.env` — 备份/模板\n\n启动后端时执行 `cp scripts/.env .env` 确保同步。\n\n### 5.3 DeepSeek API Key 格式\n\n正确的格式(dotenv 要求):\n```ini\nDEEPSEEK_API_KEY=sk-你的key\n```\n错误格式(不会被读取):\n```ini\nDeepseek api key = sk-xxx # ❌ 空格+大小写\nDeepSeek API Key = sk-xxx # ❌\n```\n\n### 5.4 JWT 认证\n\n测试需要 JWT token 的 API 时,使用 `framene-dev-secret-key`(默认密钥,如果 `.env` 中没有设置 `JWT_SECRET` 的话)。\n\n```bash\n# 生成测试 token(user_id=5)\nnode -e \"const jwt=require('jsonwebtoken');console.log(jwt.sign({userId:5},'framene-dev-secret-key',{expiresIn:'1h'}));\"\n```\n\n### 5.5 端口占用\n\n| 端口 | 服务 | 检查命令 |\n|------|------|----------|\n| 3000 | 后端 Express | `lsof -i :3000` |\n| 5173 | Web 前端 Vite | `lsof -i :5173` |\n| 8080 | App 前端 Flutter | `lsof -i :8080` |\n| 4040 | ngrok 管理界面 | `lsof -i :4040` |\n\n"}}}} |