Files

1 line
16 KiB
JSON
Raw Permalink 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.
{"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"}}}}