diff --git a/.github/workflows/GCE_DEPLOY.md b/.github/workflows/GCE_DEPLOY.md index 5bd7efe..e8820d9 100644 --- a/.github/workflows/GCE_DEPLOY.md +++ b/.github/workflows/GCE_DEPLOY.md @@ -187,8 +187,9 @@ cd ~ git clone https://github.com/YOUR_USERNAME/auto-refactor-agent.git cd auto-refactor-agent -# 建立 .env.prod 檔案 -cat > .env.prod << 'EOF' +# 建立 backend/.env 檔案(API 容器會讀取) +mkdir -p backend +cat > backend/.env << 'EOF' # MongoDB MONGODB_URL=mongodb://mongodb:27017 MONGODB_DATABASE=refactor_agent @@ -207,7 +208,8 @@ ANTHROPIC_API_KEY=YOUR_ANTHROPIC_API_KEY_HERE # Docker DOCKER_BASE_IMAGE=refactor-base:latest DOCKER_NETWORK=refactor-network -DOCKER_VOLUME_PREFIX=/var/refactor-workspaces +# 專案 workspace 在 API 容器內的根目錄(host 端目錄由 compose 的 WORKSPACE_HOST_DIR 控制) +DOCKER_VOLUME_PREFIX=/tmp/refactor-workspaces # Container resources CONTAINER_CPU_LIMIT=2.0 @@ -222,10 +224,10 @@ LOG_LEVEL=INFO EOF # 設定權限 -chmod 600 .env.prod +chmod 600 backend/.env ``` -⚠️ **重要**:請修改 `.env.prod` 中的以下變數: +⚠️ **重要**:請修改 `backend/.env` 中的以下變數: - `JWT_SECRET_KEY` - 生產環境務必使用安全的隨機字串 - `ANTHROPIC_API_KEY` - 填入你的 Anthropic API Key @@ -238,17 +240,17 @@ docker network create refactor-network #### 4.6 測試部署 ```bash -# 手動拉取映像測試 -docker pull us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-base:latest - -# 啟動服務 -docker-compose -f devops/docker-compose.prod.yml up -d +# 設定部署必要環境變數(用於組成 image name) +export REGISTRY_HOST="us-central1-docker.pkg.dev" +export GCP_PROJECT_ID="$PROJECT_ID" +export GAR_REPOSITORY="images" +export IMAGE_TAG="latest" -# 檢查狀態 -docker-compose -f devops/docker-compose.prod.yml ps +# (可選) host 端 workspace 目錄 +export WORKSPACE_HOST_DIR="/var/lib/refactor-workspaces" -# 查看日誌 -docker-compose -f devops/docker-compose.prod.yml logs -f api +# 一鍵拉取並啟動服務 +./scripts/deploy-prod.sh ``` --- @@ -333,7 +335,7 @@ EXTERNAL_IP=$(gcloud compute instances describe refactor-agent-prod \ echo "Instance IP: $EXTERNAL_IP" # 測試 API health endpoint -curl http://$EXTERNAL_IP:8000/health +curl http://$EXTERNAL_IP:8000/api/v1/health # 測試 Frontend curl -I http://$EXTERNAL_IP:80 @@ -420,7 +422,7 @@ docker ps -a docker logs refactor-api --tail 50 # 檢查網路連接 -docker exec refactor-api curl -f http://localhost:8000/health +docker exec refactor-api curl -f http://localhost:8000/api/v1/health # 檢查防火牆 sudo iptables -L -n @@ -438,15 +440,15 @@ ValueError: PostgreSQL URL is required # SSH 到 GCE gcloud compute ssh refactor-agent-prod --zone=us-central1-a -# 檢查 .env.prod -cat ~/auto-refactor-agent/.env.prod | grep POSTGRES_URL +# 檢查 backend/.env +cat ~/auto-refactor-agent/backend/.env | grep POSTGRES_URL # 確保 PostgreSQL 容器正在運行 docker ps | grep postgres # 重啟服務 cd ~/auto-refactor-agent -docker-compose -f devops/docker-compose.prod.yml restart api +docker compose -f devops/docker-compose.prod.yml restart api ``` --- @@ -469,17 +471,16 @@ docker pull us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-base:$OLD_TAG docker pull us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-api:$OLD_TAG docker pull us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-frontend:$OLD_TAG -# Tag 為 latest -docker tag us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-base:$OLD_TAG refactor-base:latest -docker tag us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-api:$OLD_TAG refactor-api:latest -docker tag us-central1-docker.pkg.dev/$PROJECT_ID/images/refactor-frontend:$OLD_TAG refactor-frontend:latest +# 使用舊 tag 重新啟動(確保 docker compose 變數對應) +export REGISTRY_HOST="us-central1-docker.pkg.dev" +export GCP_PROJECT_ID="$PROJECT_ID" +export GAR_REPOSITORY="images" +export IMAGE_TAG="$OLD_TAG" -# 重啟服務 -docker-compose -f devops/docker-compose.prod.yml down -docker-compose -f devops/docker-compose.prod.yml up -d +./scripts/deploy-prod.sh # 驗證 -docker-compose -f devops/docker-compose.prod.yml ps +docker compose -f devops/docker-compose.prod.yml ps ``` --- diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 94471b2..4cf6512 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -169,7 +169,7 @@ Actions > CI/CD Pipeline > Run workflow ```bash # 啟動服務 -docker-compose -f devops/docker-compose.yml up -d postgres mongodb +docker compose -f devops/docker-compose.yml up -d postgres mongodb # 設定環境變數 export MONGODB_URL="mongodb://localhost:27017" @@ -312,9 +312,9 @@ gh pr create --base main - [Docker Compose 配置](../../devops/docker-compose.yml) - [Backend 測試指南](../../backend/tests/QUICK_START.md) - [Frontend 測試配置](../../frontend/vitest.config.ts) -- [環境變數配置](../../ENV_UPDATE_SUMMARY.md) +- [環境變數配置](../../docs/CONFIGURATION.md) --- -**最後更新**: 2026-02-06 +**最後更新**: 2026-02-08 **維護者**: Development Team diff --git a/CLAUDE.md b/CLAUDE.md index 3a9b4f8..0eb64fb 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,7 +37,7 @@ AI 舊程式碼智能重構系統 - 一個前後端分離的大型專案,提 ### 資料模型設計 -- **Project** - 專案基本資訊 (repo_url, branch, init_prompt, status, container_id, owner_id) +- **Project** - 專案基本資訊 (repo_url, branch, spec, status, container_id, owner_id) - **AgentRun** - Agent 執行記錄 (project_id, iteration_index, phase, status, artifacts_path) - **User** - 使用者帳號 (email, hashed_password, JWT 認證) @@ -68,19 +68,19 @@ docker build -t refactor-base:latest -f devops/base-image/Dockerfile . docker run --rm refactor-base:latest ls -la /workspace/agent/ # 啟動所有服務 (MongoDB + API + Frontend) -docker-compose -f devops/docker-compose.yml up -d +docker compose -f devops/docker-compose.yml up -d # 查看服務狀態 -docker-compose -f devops/docker-compose.yml ps +docker compose -f devops/docker-compose.yml ps # 查看 API 日誌 -docker-compose -f devops/docker-compose.yml logs -f api +docker compose -f devops/docker-compose.yml logs -f api # 停止服務 -docker-compose -f devops/docker-compose.yml down +docker compose -f devops/docker-compose.yml down # 停止並清除資料 -docker-compose -f devops/docker-compose.yml down -v +docker compose -f devops/docker-compose.yml down -v ``` **API 層級控制**: diff --git a/README.md b/README.md index 906c816..e42c3a5 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ AI Refactoring. Measured. Continuous. - Docker & Docker Compose - Git -- (開發環境) Python 3.11+, Node.js 18+ +- (開發環境) Python 3.11+, Node.js 20+ ### 環境設定 @@ -25,10 +25,11 @@ cp .env.example .env 必要配置項: - `JWT_SECRET_KEY` - JWT 簽名金鑰(生產環境務必更換) - `MONGODB_URL` - MongoDB 連接字串 +- `POSTGRES_URL` - PostgreSQL 連接字串(必填,Agent 會話持久化) - `DOCKER_BASE_IMAGE` - Base Docker Image 名稱 - `DOCKER_NETWORK` - Docker 網路名稱 -**注意**: LLM API Key(如 `ANTHROPIC_API_KEY`)由容器內的 AI Server 自行管理,不需要在後端 `.env` 中設定 +**注意**: `ANTHROPIC_API_KEY` 會由後端讀取後注入到每個專案的 Project Container 中使用;未設定時,Project Container 將無法使用 Anthropic/Claude。 2. **建立 Base Image** @@ -47,16 +48,16 @@ Dockerfile 位置: ```bash # 啟動所有服務(PostgreSQL + MongoDB + Backend API + Frontend) -docker-compose -f devops/docker-compose.yml up -d +docker compose -f devops/docker-compose.yml up -d --build # 查看服務狀態 -docker-compose -f devops/docker-compose.yml ps +docker compose -f devops/docker-compose.yml ps # 查看日誌 -docker-compose -f devops/docker-compose.yml logs -f api +docker compose -f devops/docker-compose.yml logs -f api # 停止服務 -docker-compose -f devops/docker-compose.yml down +docker compose -f devops/docker-compose.yml down ``` **GCE 單機(正式環境)** @@ -73,8 +74,8 @@ docker-compose -f devops/docker-compose.yml down **本地開發模式** ```bash -# 1. 啟動 MongoDB -docker run -d --name mongodb -p 27017:27017 mongo:7 +# 1. 啟動 PostgreSQL + MongoDB(推薦直接用 compose) +docker compose -f devops/docker-compose.yml up -d postgres mongodb # 2. 啟動 Backend cd backend @@ -99,10 +100,10 @@ curl -X POST http://localhost:8000/api/v1/auth/register \ -H "Content-Type: application/json" \ -d '{"email":"user@example.com","username":"testuser","password":"password123"}' -# 登入 +# 登入(使用 username) curl -X POST http://localhost:8000/api/v1/auth/login \ -H "Content-Type: application/json" \ - -d '{"email":"user@example.com","password":"password123"}' + -d '{"username":"testuser","password":"password123"}' ``` ### 2. 建立專案 @@ -112,9 +113,10 @@ curl -X POST http://localhost:8000/api/v1/projects \ -H "Authorization: Bearer YOUR_TOKEN" \ -H "Content-Type: application/json" \ -d '{ - "repo_url": "https://github.com/yourusername/your-repo.git", + "project_type": "REFACTOR", + "repo_url": "https://github.com/your-org/your-repo.git", "branch": "main", - "init_prompt": "分析此專案並生成重構計劃" + "spec": "分析此專案並生成可量化的重構計劃" }' ``` @@ -144,12 +146,14 @@ curl -N http://localhost:8000/api/v1/projects/{project_id}/agent/runs/{run_id}/s ## 測試 ```bash -# 執行完整 E2E 測試 -./test_cloud_run_e2e_v2.sh +# Backend +cd backend +python -m pytest tests/ -v -# 測試 base image 建置 -export ANTHROPIC_API_KEY=your-api-key -./test_base_image.sh +# Frontend +cd frontend +npm ci +npm run test -- --run ``` ## 系統架構 @@ -191,6 +195,9 @@ export ANTHROPIC_API_KEY=your-api-key - **[docs/API.md](./docs/API.md)** - REST API 完整規格 - **[docs/BACKEND.md](./docs/BACKEND.md)** - 後端技術文件 +- **[docs/GETTING_STARTED.md](./docs/GETTING_STARTED.md)** - 啟動與開發入門 +- **[docs/USAGE.md](./docs/USAGE.md)** - 使用流程(UI/API) +- **[docs/DEPLOYMENT.md](./docs/DEPLOYMENT.md)** - 部署說明 - **[docs/guides/](./docs/guides/)** - 使用指南 - **[docs/testing/](./docs/testing/)** - 測試文件 - **[CLAUDE.md](./CLAUDE.md)** - Claude Code 專案指引 @@ -208,13 +215,13 @@ docker images | grep refactor-base 1. 檢查容器內 AI Server 的 LLM API Key 設定 2. 查看容器日誌:`docker logs refactor-project-{project_id}` -3. 檢查 API 日誌:`docker-compose -f devops/docker-compose.yml logs -f api` +3. 檢查 API 日誌:`docker compose -f devops/docker-compose.yml logs -f api` ### 如何清理測試資料? ```bash # 停止並移除所有容器和資料 -docker-compose -f devops/docker-compose.yml down -v +docker compose -f devops/docker-compose.yml down -v # 清理專案容器 docker ps -a | grep refactor-project | awk '{print $1}' | xargs docker rm -f diff --git a/backend/=3.3.0 b/backend/=3.3.0 deleted file mode 100644 index e69de29..0000000 diff --git a/cli.py b/cli.py index 3cb172e..a8a20f9 100644 --- a/cli.py +++ b/cli.py @@ -90,7 +90,7 @@ async def register(self, email: str, password: str, username: Optional[str] = No # 註冊成功後自動登入取得 token self.print_info("正在自動登入...") - return await self.login(email, password) + return await self.login(username, password) else: self.print_error(f"註冊失敗: {response.text}") return False @@ -98,19 +98,25 @@ async def register(self, email: str, password: str, username: Optional[str] = No self.print_error(f"註冊錯誤: {e}") return False - async def login(self, email: str, password: str) -> bool: + async def login(self, username: str, password: str) -> bool: """登入""" try: + # 後端登入以 username 為主;若使用者輸入 email,嘗試推導 username。 + if "@" in username: + derived = username.split("@", 1)[0] + self.print_info(f"登入使用 username,已由 email 推導為: {derived}") + username = derived + async with httpx.AsyncClient() as client: response = await client.post( f"{self.api_base_url}/api/v1/auth/login", - json={"email": email, "password": password} + json={"username": username, "password": password} ) if response.status_code == 200: data = response.json() self.token = data["access_token"] - self.print_success(f"登入成功!使用者: {email}") + self.print_success(f"登入成功!使用者: {username}") return True else: self.print_error(f"登入失敗: {response.text}") @@ -124,7 +130,7 @@ async def create_project( name: str, repo_url: str, branch: str = "main", - init_prompt: str = "請分析此專案並提供重構建議" + spec: str = "請分析此專案並提供重構建議" ) -> Optional[str]: """建立新專案""" if not self.token: @@ -136,9 +142,11 @@ async def create_project( response = await client.post( f"{self.api_base_url}/api/v1/projects", json={ + "title": name, + "project_type": "REFACTOR", "repo_url": repo_url, "branch": branch, - "init_prompt": init_prompt + "spec": spec }, headers={"Authorization": f"Bearer {self.token}"} ) @@ -544,6 +552,7 @@ async def interactive_mode(): # 預設測試帳號 DEFAULT_EMAIL = "test@example.com" + DEFAULT_USERNAME = "test" DEFAULT_PASSWORD = "testpass123" print(""" @@ -555,27 +564,30 @@ async def interactive_mode(): # 1. 登入或註冊 while not cli.token: cli.print_header("步驟 1: 登入/註冊") - cli.print_info(f"預設測試帳號: {DEFAULT_EMAIL} / {DEFAULT_PASSWORD}") + cli.print_info(f"預設測試帳號: {DEFAULT_USERNAME} / {DEFAULT_PASSWORD} (註冊 email: {DEFAULT_EMAIL})") action = input("請選擇 (1=登入, 2=註冊, d=使用預設帳號登入, Enter=使用預設帳號登入): ").strip() # 預設選項或使用預設帳號 if action == "" or action.lower() == "d": - email = DEFAULT_EMAIL + username = DEFAULT_USERNAME password = DEFAULT_PASSWORD - cli.print_info(f"使用預設帳號: {email}") + email = DEFAULT_EMAIL + cli.print_info(f"使用預設帳號: {username}") # 嘗試登入,失敗則自動註冊 - success = await cli.login(email, password) + success = await cli.login(username, password) if not success: cli.print_info("預設帳號不存在,自動註冊...") - success = await cli.register(email, password) + success = await cli.register(email, password, username=username) else: - email = input("Email (Enter=使用預設): ").strip() or DEFAULT_EMAIL - password = input("Password (Enter=使用預設): ").strip() or DEFAULT_PASSWORD - if action == "1": - success = await cli.login(email, password) + username = input("Username (或 Email, Enter=使用預設): ").strip() or DEFAULT_USERNAME + password = input("Password (Enter=使用預設): ").strip() or DEFAULT_PASSWORD + success = await cli.login(username, password) elif action == "2": - success = await cli.register(email, password) + email = input("Email (Enter=使用預設): ").strip() or DEFAULT_EMAIL + username = input("Username (Enter=由 email 推導): ").strip() or None + password = input("Password (Enter=使用預設): ").strip() or DEFAULT_PASSWORD + success = await cli.register(email, password, username=username) else: cli.print_error("無效選項") continue @@ -649,7 +661,7 @@ async def create_new_project(cli: RefactorCLI) -> Optional[str]: DEFAULT_NAME = "測試專案" DEFAULT_REPO = "https://github.com/emilybache/Racing-Car-Katas.git" DEFAULT_BRANCH = "main" - DEFAULT_PROMPT = "分析此專案並生成重構計劃,請專注在 /Python 的資料夾,我想要把裡面的python 轉成 go lang,並存入 ./memory/plan.md 檔案,不需要使用者確認後就直接執行所有的計劃,把它完整重構完成" + DEFAULT_SPEC = "分析此專案並生成重構計劃,請專注在 /Python 的資料夾,我想要把裡面的python 轉成 go lang,並存入 ./memory/plan.md 檔案,不需要使用者確認後就直接執行所有的計劃,把它完整重構完成" cli.print_info(f"預設測試 Repository: {DEFAULT_REPO}") use_default = input("是否使用預設測試專案?(Enter=是, n=自訂): ").strip().lower() @@ -658,15 +670,15 @@ async def create_new_project(cli: RefactorCLI) -> Optional[str]: name = DEFAULT_NAME repo_url = DEFAULT_REPO branch = DEFAULT_BRANCH - init_prompt = DEFAULT_PROMPT + spec = DEFAULT_SPEC cli.print_success(f"使用預設專案: {name}") else: name = input("專案名稱: ").strip() repo_url = input("Repository URL: ").strip() branch = input("Branch (預設 main): ").strip() or "main" - init_prompt = input("初始提示詞 (Enter=使用預設): ").strip() or DEFAULT_PROMPT + spec = input("重構規格 spec (Enter=使用預設): ").strip() or DEFAULT_SPEC - return await cli.create_project(name, repo_url, branch, init_prompt) + return await cli.create_project(name, repo_url, branch, spec) def main(): diff --git a/docs/API.md b/docs/API.md index f544840..a2471aa 100644 --- a/docs/API.md +++ b/docs/API.md @@ -4,7 +4,7 @@ **Base URL**: `http://localhost:8000` (開發環境) **API Version**: v1 -**最後更新**: 2026-02-02 +**最後更新**: 2026-02-08 --- @@ -31,6 +31,11 @@ - [GET /api/v1/projects/{id}/agent/runs](#get-apiv1projectsidagentruns) - [GET /api/v1/projects/{id}/agent/runs/{run_id}](#get-apiv1projectsidagentrunsrun_id) - [GET /api/v1/projects/{id}/agent/runs/{run_id}/stream](#get-apiv1projectsidagentrunsrun_idstream) +- [Chat API](#chat-api) + - [POST /api/v1/projects/{id}/chat](#post-apiv1projectsidchat) + - [GET /api/v1/projects/{id}/chat/sessions](#get-apiv1projectsidchatsessions) + - [GET /api/v1/projects/{id}/chat/sessions/{thread_id}/history](#get-apiv1projectsidchatsessionsthread_idhistory) + - [GET /api/v1/projects/{id}/chat/{task_id}/stream](#get-apiv1projectsidchattask_idstream) --- @@ -142,7 +147,7 @@ Authorization: Bearer ```json { - "email": "user@example.com", + "username": "testuser", "password": "password123" } ``` @@ -151,7 +156,7 @@ Authorization: Bearer | 欄位 | 類型 | 必填 | 說明 | |------|------|------|------| -| email | string | ✅ | 用戶 Email | +| username | string | ✅ | 用戶名稱 | | password | string | ✅ | 密碼 | #### Response (200 OK) @@ -174,10 +179,10 @@ Authorization: Bearer #### 錯誤回應 -**401 Unauthorized** - Email 或密碼錯誤 +**401 Unauthorized** - Username 或密碼錯誤 ```json { - "detail": "Incorrect email or password" + "detail": "Incorrect username or password" } ``` @@ -228,9 +233,11 @@ Authorization: Bearer ```json { + "title": "My Refactor Project", + "project_type": "REFACTOR", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "請分析這個專案並提出重構建議" + "spec": "請先掃描專案並提出可量化的重構計劃" } ``` @@ -238,18 +245,25 @@ Authorization: Bearer | 欄位 | 類型 | 必填 | 預設值 | 說明 | |------|------|------|--------|------| -| repo_url | string | ✅ | - | Git Repository URL | +| title | string | ❌ | - | 專案標題(未填可由後端推導)| +| description | string | ❌ | - | 專案描述 | +| project_type | string | ❌ | "REFACTOR" | 專案類型:REFACTOR / SANDBOX | +| repo_url | string | 條件式 | - | Git Repository URL(REFACTOR 必填) | | branch | string | ❌ | "main" | Git 分支名稱 | -| init_prompt | string | ✅ | - | Agent 初始提示(任務描述)| +| spec | string | ❌ | "" | 重構規格說明(Agent 主要輸入)| #### Response (201 Created) ```json { "id": "507f1f77bcf86cd799439011", + "title": "My Refactor Project", + "description": null, + "project_type": "REFACTOR", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "請分析這個專案並提出重構建議", + "spec": "請先掃描專案並提出可量化的重構計劃", + "refactor_thread_id": null, "status": "CREATED", "container_id": null, "created_at": "2026-02-02T12:00:00Z", @@ -301,7 +315,7 @@ GET /api/v1/projects?skip=0&limit=10 "id": "507f1f77bcf86cd799439011", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "重構建議", + "spec": "重構建議", "status": "READY", "container_id": "abc123def456", "created_at": "2026-02-02T12:00:00Z", @@ -345,7 +359,7 @@ GET /api/v1/projects/507f1f77bcf86cd799439011?include_docker_status=true "id": "507f1f77bcf86cd799439011", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "重構建議", + "spec": "重構建議", "status": "READY", "container_id": "abc123def456", "created_at": "2026-02-02T12:00:00Z", @@ -409,7 +423,7 @@ GET /api/v1/projects/507f1f77bcf86cd799439011?include_docker_status=true ```json { "branch": "develop", - "init_prompt": "新的任務描述" + "spec": "新的任務描述" } ``` @@ -418,9 +432,11 @@ GET /api/v1/projects/507f1f77bcf86cd799439011?include_docker_status=true | 欄位 | 類型 | 限制 | 說明 | |------|------|------|------| | repo_url | string | ⚠️ Provision 後無法修改 | Git Repository URL | +| title | string | - | 專案標題 | +| description | string | - | 專案描述 | | branch | string | - | Git 分支名稱 | -| init_prompt | string | - | Agent 初始提示 | -| status | string | - | 專案狀態 | +| spec | string | - | 重構規格說明 | +| status | string | - | 專案狀態(通常由系統流程更新,不建議手動改) | #### Response (200 OK) @@ -429,7 +445,7 @@ GET /api/v1/projects/507f1f77bcf86cd799439011?include_docker_status=true "id": "507f1f77bcf86cd799439011", "repo_url": "https://github.com/user/repo.git", "branch": "develop", - "init_prompt": "新的任務描述", + "spec": "新的任務描述", "status": "CREATED", "container_id": null, "created_at": "2026-02-02T12:00:00Z", @@ -647,7 +663,7 @@ data: keep-alive "id": "507f1f77bcf86cd799439011", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "重構建議", + "spec": "重構建議", "status": "STOPPED", "container_id": "abc123def456", "created_at": "2026-02-02T12:00:00Z", @@ -941,6 +957,126 @@ data: {"status": "success", "message": "分析完成", "artifacts": ["plan.json" --- +## Chat API + +聊天模式會呼叫 Project Container 內的 AI Server `/chat`,並以 `thread_id` 維持多輪對話上下文。 + +### POST /api/v1/projects/{id}/chat + +發送聊天訊息,啟動聊天任務(背景執行)。 + +**認證**: 🔒 需要 Bearer Token + +**前置條件**: 專案狀態必須為 `READY` + +#### Request Body + +```json +{ + "message": "Hello! Please list the files in /workspace", + "thread_id": null, + "verbose": true, + "model": null +} +``` + +| 欄位 | 類型 | 必填 | 說明 | +|------|------|------|------| +| message | string | ✅ | 使用者訊息 | +| thread_id | string | ❌ | 對話 ID(不提供則自動生成)| +| verbose | boolean | ❌ | 是否輸出較多日誌(預設 true)| +| model | string | ❌ | 模型 ID(選用)| + +#### Response (200 OK) + +```json +{ + "task_id": "task_abc123xyz", + "thread_id": "chat-507f1f77bcf86cd799439011-uuid", + "project_id": "507f1f77bcf86cd799439011", + "status": "RUNNING", + "message": "聊天任務已啟動,正在背景執行" +} +``` + +#### 錯誤回應 + +**400 Bad Request** - 專案狀態不正確 +```json +{ + "detail": "專案狀態必須為 READY,目前為 CREATED" +} +``` + +### GET /api/v1/projects/{id}/chat/sessions + +列出專案的聊天會話(依最後訊息時間排序)。 + +**認證**: 🔒 需要 Bearer Token + +#### Response (200 OK) + +```json +{ + "total": 1, + "sessions": [ + { + "thread_id": "chat-507f1f77bcf86cd799439011-uuid", + "project_id": "507f1f77bcf86cd799439011", + "title": "Hello! Please list the files in /workspace", + "created_at": "2026-02-02T12:00:00Z", + "last_message_at": "2026-02-02T12:01:00Z" + } + ] +} +``` + +### GET /api/v1/projects/{id}/chat/sessions/{thread_id}/history + +取得聊天歷史(轉發 Project Container AI Server)。 + +**認證**: 🔒 需要 Bearer Token + +#### Response (200 OK) + +```json +{ + "thread_id": "chat-507f1f77bcf86cd799439011-uuid", + "messages": [ + { + "id": "msg_1", + "role": "user", + "content": "Hello", + "timestamp": "2026-02-02T12:00:00Z" + } + ] +} +``` + +### GET /api/v1/projects/{id}/chat/{task_id}/stream + +SSE 串流聊天回應(直接轉發容器的 task stream)。 + +**認證**: 🔒 需要 Bearer Token + +#### Request + +```http +GET /api/v1/projects/507f1f77bcf86cd799439011/chat/task_abc123xyz/stream +Accept: text/event-stream +``` + +#### Response (200 OK) + +``` +Content-Type: text/event-stream + +event: text_delta +data: {"delta": "Hello"} +``` + +--- + ## 附錄 ### 範例:完整流程 @@ -959,7 +1095,7 @@ curl -X POST http://localhost:8000/api/v1/auth/register \ TOKEN=$(curl -X POST http://localhost:8000/api/v1/auth/login \ -H "Content-Type: application/json" \ -d '{ - "email": "dev@example.com", + "username": "developer", "password": "secure123" }' | jq -r '.access_token') @@ -968,9 +1104,10 @@ PROJECT_ID=$(curl -X POST http://localhost:8000/api/v1/projects \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ + "project_type": "REFACTOR", "repo_url": "https://github.com/user/legacy-code.git", "branch": "main", - "init_prompt": "分析專案並提出重構建議" + "spec": "分析專案並提出重構建議" }' | jq -r '.id') # 4. Provision 專案 @@ -1011,9 +1148,10 @@ const api = axios.create({ // 建立專案 const { data: project } = await api.post('/api/v1/projects', { + project_type: 'REFACTOR', repo_url: 'https://github.com/user/repo.git', branch: 'main', - init_prompt: '重構建議' + spec: '重構建議' }); // Provision 專案 diff --git a/docs/BACKEND.md b/docs/BACKEND.md index 7dd91ce..824a9c6 100644 --- a/docs/BACKEND.md +++ b/docs/BACKEND.md @@ -165,9 +165,13 @@ class ProjectStatus(str, Enum): class Project(BaseModel): id: str # MongoDB _id - repo_url: str # Git Repository URL + title: Optional[str] # 專案標題(選填) + description: Optional[str] # 專案描述(選填) + project_type: str # 專案類型:REFACTOR / SANDBOX + repo_url: Optional[str] # Git Repository URL(SANDBOX 可為空) branch: str = "main" # Git Branch - init_prompt: str # Agent 初始提示 + spec: str # 重構規格說明(原 init_prompt) + refactor_thread_id: Optional[str] # 重構會話 ID(持久化用) status: ProjectStatus # 專案狀態 container_id: Optional[str] # Docker 容器 ID owner_id: str # 擁有者用戶 ID @@ -197,7 +201,7 @@ CREATED → PROVISIONING → READY → RUNNING → READY ```python class User(BaseModel): id: Optional[str] # MongoDB _id - email: EmailStr # 唯一,用於登入 + email: EmailStr # 唯一,用於識別/聯絡 username: str # 用戶名稱 password_hash: str # bcrypt hash is_active: bool = True # 帳號啟用狀態 @@ -243,7 +247,7 @@ class User(BaseModel): ```json // Request { - "email": "user@example.com", + "username": "testuser", "password": "securepassword" } @@ -279,9 +283,10 @@ class User(BaseModel): ```json // Request { + "project_type": "REFACTOR", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "請分析這個專案並提出重構建議" + "spec": "請分析這個專案並提出重構建議" } // Response (201 Created) @@ -289,7 +294,7 @@ class User(BaseModel): "id": "507f1f77bcf86cd799439011", "repo_url": "https://github.com/user/repo.git", "branch": "main", - "init_prompt": "請分析這個專案並提出重構建議", + "spec": "請分析這個專案並提出重構建議", "status": "CREATED", "container_id": null, "owner_id": "507f191e810c19729de860ea", @@ -345,13 +350,13 @@ Query 參數: ```json // Request { - "init_prompt": "新的提示內容" + "spec": "新的提示內容" } // Response { "id": "507f1f77bcf86cd799439011", - "init_prompt": "新的提示內容", + "spec": "新的提示內容", ... } ``` @@ -883,38 +888,39 @@ LOG_LEVEL=INFO ``` **說明**: -- LLM 相關配置 (如 `ANTHROPIC_API_KEY`, `LLM_PROVIDER`, `GCP_PROJECT_ID` 等) 由容器內的 AI Server 自行處理,不需要在後端 `.env` 中設定 +- `ANTHROPIC_API_KEY` 由 Backend 讀取後,會注入到每個 Project Container 中使用(未設定時,Project Container 無法使用 Anthropic/Claude)。 +- `GCP_PROJECT_ID` / `GOOGLE_APPLICATION_CREDENTIALS` 等 Vertex AI 相關設定也由 Backend 讀取,用於掛載/轉交 credentials 到 Project Container。 ### Docker Compose 部署 **檔案**: -- 開發版:`devops/docker-compose.dev.yml`(本機 build + volume mount) -- 正式版:`devops/docker-compose.prod.yml`(從 Artifact Registry 拉取映像) +- 開發/測試:`devops/docker-compose.yml`(本機 build + volume mount) +- 正式環境:`devops/docker-compose.prod.yml`(從 Artifact Registry 拉取映像) -**啟動指令(開發版)**: +**啟動指令(開發/測試)**: ```bash # 啟動所有服務 -docker-compose -f devops/docker-compose.dev.yml up -d +docker compose -f devops/docker-compose.yml up -d --build # 查看日誌 -docker-compose -f devops/docker-compose.dev.yml logs -f api +docker compose -f devops/docker-compose.yml logs -f api # 停止服務 -docker-compose -f devops/docker-compose.dev.yml down +docker compose -f devops/docker-compose.yml down ``` -**啟動指令(正式版)**: +**啟動指令(正式環境)**: ```bash -# 需先設定環境變數(Artifact Registry 映像) -export AR_API_IMAGE=us-central1-docker.pkg.dev/PROJECT/REPO/refactor-api:latest -export AR_FRONTEND_IMAGE=us-central1-docker.pkg.dev/PROJECT/REPO/refactor-frontend:latest -export AR_BASE_IMAGE=us-central1-docker.pkg.dev/PROJECT/REPO/refactor-base:latest +# 需先設定環境變數(用於組成 image name) +export REGISTRY_HOST="us-central1-docker.pkg.dev" +export GCP_PROJECT_ID="your-project-id" +export GAR_REPOSITORY="images" +export IMAGE_TAG="latest" -# 可選:指定主機資料/工作區路徑 -export HOST_DATA_DIR=/opt/refactor/data -export HOST_WORKSPACE_DIR=/opt/refactor/workspaces +# (可選) host 端 workspace 目錄 +export WORKSPACE_HOST_DIR="/var/lib/refactor-workspaces" -docker-compose -f devops/docker-compose.prod.yml up -d +./scripts/deploy-prod.sh ``` ### 本地開發 @@ -946,13 +952,14 @@ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ### 健康檢查 -**端點**: `GET /health` +**端點**: `GET /api/v1/health` ```json // Response { - "status": "healthy", - "timestamp": "2026-02-02T12:00:00Z" + "status": "ok", + "timestamp": "2026-02-02T12:00:00Z", + "database": "healthy" } ``` diff --git a/docs/CONFIGURATION.md b/docs/CONFIGURATION.md new file mode 100644 index 0000000..ed11a87 --- /dev/null +++ b/docs/CONFIGURATION.md @@ -0,0 +1,90 @@ +# Configuration + +本專案主要透過 `backend/.env` 控制行為。請以 `backend/.env.example` 為來源,將必要值填入 `backend/.env`。 + +## 必填 (核心功能) + +### MongoDB + +- `MONGODB_URL`: MongoDB 連線字串 +- `MONGODB_DATABASE`: DB 名稱 + +Docker Compose 開發環境預設為: + +- `MONGODB_URL=mongodb://mongodb:27017` +- `MONGODB_DATABASE=refactor_agent` + +本機執行 Backend 時常用: + +- `MONGODB_URL=mongodb://localhost:27017` + +### PostgreSQL (必填) + +- `POSTGRES_URL`: Agent/LangGraph 會話持久化用資料庫 + +Docker Compose 開發環境預設為: + +- `POSTGRES_URL=postgresql://langgraph:langgraph_secret@postgres:5432/langgraph` + +本機執行 Backend 時常用: + +- `POSTGRES_URL=postgresql://langgraph:langgraph_secret@localhost:5432/langgraph` + +### JWT + +- `JWT_SECRET_KEY`: JWT 簽名密鑰 (生產環境務必替換為安全隨機值) +- `JWT_ALGORITHM`: 預設 `HS256` +- `JWT_ACCESS_TOKEN_EXPIRE_HOURS`: token 有效期 (小時) + +### LLM (Anthropic/Claude) + +- `ANTHROPIC_API_KEY`: 會由 Backend 注入到專案容器 (Project Container) 中使用 + +若未設定,Backend 仍可啟動,但專案容器無法使用 Anthropic 模型,且你會在後端日誌看到警告。 + +## Docker/容器相關 + +### Base image + +- `DOCKER_BASE_IMAGE`: 預設 `refactor-base:latest` + +此 image 用來建立每個 Project 的隔離容器,請先建置: + +```bash +docker build -t refactor-base:latest -f devops/base-image/Dockerfile . +``` + +### Network / Volumes + +- `DOCKER_NETWORK`: 預設 `refactor-network` +- `DOCKER_VOLUME_PREFIX`: 預設 `/tmp/refactor-workspaces` + +Backend 會在 `${DOCKER_VOLUME_PREFIX}/${project_id}/` 建立工作目錄,並掛載到專案容器: + +- `/workspace/repo` +- `/workspace/artifacts` + +## 可選: Vertex AI + +若要在專案容器使用 Vertex AI 相關模型: + +- `GCP_PROJECT_ID` +- `GCP_LOCATION` (例如 `us-central1`) +- `GOOGLE_APPLICATION_CREDENTIALS` (選填) + +行為概要: + +- 若設定 `GOOGLE_APPLICATION_CREDENTIALS` 且檔案存在,Backend 會將其複製到 workspace volume 並掛載進專案容器。 +- 否則 Backend 會嘗試使用 API 容器中的 ADC 檔案 (`/root/.config/gcloud/application_default_credentials.json`)。 + +細節請看 `docs/VERTEX_AI.md`。 + +## 可選: 容器資源限制 + +- `CONTAINER_CPU_LIMIT` (例如 `4.0`) +- `CONTAINER_MEMORY_LIMIT` (例如 `8g`) + +## 可選: Git + +- `GIT_CLONE_TIMEOUT` +- `GIT_DEPTH` diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..d99366b --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,79 @@ +# Deployment + +本專案的生產環境通常是: + +- GitHub Actions: 建置並推送 images 到 Google Artifact Registry (GAR) +- GCE: 使用 `devops/docker-compose.prod.yml` 以 image tag 拉取並啟動 + +細節流程與 GitHub 設定請看: + +- `.github/workflows/README.md` +- `.github/workflows/GCE_DEPLOY.md` + +## Production Compose 概念 + +`devops/docker-compose.prod.yml` 會啟動: + +- `postgres` (5432) +- `mongodb` (27017) +- `api` (host 8000 -> container 8000) +- `frontend` (host 80 -> container 80, Nginx 反向代理 `/api` 到 `api:8000`) + +因此常見對外入口是: + +- `http://YOUR_HOST/` (Frontend) +- `http://YOUR_HOST/api/v1/...` (透過 Nginx 反向代理到 API) + +同時 API 也會直接暴露 `http://YOUR_HOST:8000` (如不希望對外開放,可再調整 compose)。 + +## 在主機上手動啟用 (不透過 GitHub Actions) + +適合:你已經手動把 image 推到 GAR,想在主機上拉取並啟動。 + +### 1) 準備 `backend/.env` + +在主機的 repo 目錄中建立 `backend/.env` (可由 `backend/.env.example` 複製),至少要有: + +- `POSTGRES_URL` (在 compose 中通常用 `postgres` hostname) +- `MONGODB_URL` (在 compose 中通常用 `mongodb` hostname) +- `JWT_SECRET_KEY` +- `ANTHROPIC_API_KEY` (如需 Anthropic) + +### 2) 設定必要環境變數 + +`devops/docker-compose.prod.yml` 需要這些變數才能組成 image name: + +```bash +export REGISTRY_HOST="us-central1-docker.pkg.dev" +export GCP_PROJECT_ID="your-project-id" +export GAR_REPOSITORY="images" +export IMAGE_TAG="latest" # 或使用 Git SHA 短碼,例如 abc1234 +``` + +可選: + +```bash +export WORKSPACE_HOST_DIR="/var/lib/refactor-workspaces" +``` + +### 3) 執行部署腳本 + +```bash +./scripts/deploy-prod.sh +``` + +此腳本會: + +- 拉取 base image 並標記為 `refactor-base:latest` (供 Project Container 使用) +- `docker compose pull` 拉取 `api` 與 `frontend` images +- `docker compose up -d` 啟動 prod stack + +## 防火牆與連線 + +最少需要對外開放: + +- TCP 80 (Frontend) + +如要直接對外打 API (非必要): + +- TCP 8000 diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..800c4dd --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,101 @@ +# Getting Started + +本文檔提供本專案最常見的兩種啟動方式: + +1. Docker Compose (推薦): 一次啟動資料庫 + API + 前端 +2. 本地開發: DB 用 Docker 跑,API/Frontend 在本機跑 + +## 前置需求 + +- Docker Desktop (或 Docker Engine) + Docker Compose v2 (`docker compose`) +- Git +- (本地開發) Python 3.11+、Node.js 20+ + +## 方式 A: Docker Compose (推薦) + +### 1) 建立 `backend/.env` + +```bash +cp backend/.env.example backend/.env +``` + +至少請確認以下變數已設定為正確值: + +- `POSTGRES_URL` +- `MONGODB_URL` +- `JWT_SECRET_KEY` (生產環境務必替換) +- `ANTHROPIC_API_KEY` (若要使用 Anthropic/Claude) + +注意:`ANTHROPIC_API_KEY` 由 Backend 讀取後,會注入到每個專案的「Project Container」中使用;未設定時,專案容器將無法使用 Anthropic 模型。 + +### 2) 建置 Project Base Image (必須) + +專案會為每個 Project 建立隔離容器,這些容器使用 base image `refactor-base:latest`。 + +```bash +docker build -t refactor-base:latest -f devops/base-image/Dockerfile . +``` + +### 3) 啟動服務 + +```bash +docker compose -f devops/docker-compose.yml up -d --build +docker compose -f devops/docker-compose.yml ps +``` + +服務端點: + +- Frontend: `http://localhost:5173` +- Backend API: `http://localhost:8000` +- Swagger/OpenAPI: `http://localhost:8000/docs` + +### 4) 停止與清理 + +```bash +docker compose -f devops/docker-compose.yml down +``` + +若要連資料一起清: + +```bash +docker compose -f devops/docker-compose.yml down -v +``` + +## 方式 B: 本地開發 (API/Frontend 在本機跑) + +### 1) 先啟動資料庫 (Docker) + +```bash +docker compose -f devops/docker-compose.yml up -d postgres mongodb +``` + +### 2) 啟動 Backend (本機) + +```bash +python -m venv backend/.venv +source backend/.venv/bin/activate +pip install -r backend/requirements.txt + +export MONGODB_URL="mongodb://localhost:27017" +export MONGODB_DATABASE="refactor_agent" +export POSTGRES_URL="postgresql://langgraph:langgraph_secret@localhost:5432/langgraph" +export JWT_SECRET_KEY="dev-secret-key" +export ANTHROPIC_API_KEY="your-api-key" + +cd backend +uvicorn app.main:app --reload --port 8000 +``` + +### 3) 啟動 Frontend (本機) + +```bash +cd frontend +npm ci +npm run dev +``` + +## 下一步 + +- 使用流程請看 `docs/USAGE.md` +- 環境變數請看 `docs/CONFIGURATION.md` +- 部署請看 `docs/DEPLOYMENT.md` diff --git a/docs/OVERVIEW.md b/docs/OVERVIEW.md new file mode 100644 index 0000000..8d3935d --- /dev/null +++ b/docs/OVERVIEW.md @@ -0,0 +1,31 @@ +# Overview + +Reforge (auto-refactor-agent) 是一套「以隔離容器執行」的程式碼分析與重構服務。 + +核心概念: + +- 使用者在前端建立 Project,並提供 repo 與重構規格 (`spec`) +- Backend 會為每個 Project 建立獨立的 Docker container (Project Container) +- Project Container 內執行 AI Server + Agent,並在隔離環境中 clone repo、跑工具、產出 artifacts + +## 系統組成 + +- Frontend: React/Vite,提供 UI +- Backend API: FastAPI,負責專案管理、認證、容器生命週期、轉發日誌串流 +- MongoDB: 專案/使用者等資料 +- PostgreSQL: Agent/LangGraph 會話持久化 +- Project Container: 以 `refactor-base:latest` 為基底,執行 AI Server (`agent/ai_server.py`) + +## 高層資料流 + +1. 使用者透過 UI/API 建立專案 (Project) +2. Provision 時 Backend 會建立 Project Container 並準備 workspace +3. Run Agent 時 Backend 呼叫 Project Container 內的 AI Server `/run` +4. Backend 轉發 Project Container 的日誌串流到 `.../stream` 端點供前端顯示 + +## 關鍵文件 + +- 啟動與開發: `docs/GETTING_STARTED.md` +- 使用流程: `docs/USAGE.md` +- 部署: `docs/DEPLOYMENT.md` +- 詳細 API: `docs/API.md` 或 `http://localhost:8000/docs` diff --git a/docs/README.md b/docs/README.md index eab2c78..e774166 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,126 +1,35 @@ # 文件索引 -> AI 舊程式碼智能重構系統 - 完整文件導覽 +本目錄是 Reforge (auto-refactor-agent) 的主要文件入口。若你要快速啟動與部署,先看本頁的「入門」與「部署」。 ---- +## 入門 (推薦先讀) -## 📚 核心文件 +- `docs/OVERVIEW.md`: 系統概念與高層架構 +- `docs/GETTING_STARTED.md`: 本機啟動 (Docker Compose / 本地開發) 的最短路徑 +- `docs/CONFIGURATION.md`: `backend/.env` 變數說明與必要設定 +- `docs/USAGE.md`: UI/API 的基本使用流程 (建立專案 -> provision -> run agent -> 串流日誌) -### [API.md](./API.md) -**REST API 完整規格** +## 執行與維運 -詳細記錄所有 API 端點的: -- Request Payload 結構 -- Response 格式 -- 認證機制 -- 錯誤處理 -- 使用範例(curl, JavaScript/TypeScript) +- `docs/RUN_AND_DEV.md`: 常用腳本、開發模式、base image 相關操作 +- `docs/DEPLOYMENT.md`: GCE/Prod 啟用與部署重點 +- `docs/VERTEX_AI.md`: Vertex AI 設定(選用) +- `docs/TROUBLESHOOTING.md`: 常見問題與排除 -適合:前端開發、API 整合、第三方串接 +## 參考文件 (需要細節時再查) ---- +- `docs/API.md`: REST API 規格 (也可直接用 `http://localhost:8000/docs`) +- `docs/BACKEND.md`: 後端架構/模組/資料模型 +- `docs/guides/`: CLI 使用指南 +- `docs/testing/`: 測試相關文件 -### [BACKEND.md](./BACKEND.md) -**後端技術文件** +## CI/CD 與部署工作流程 -包含: -- 架構總覽(技術棧、系統架構圖、資料流) -- 核心模組(目錄結構、關鍵檔案說明) -- 資料模型(Project, User, ProjectStatus) -- 服務層設計(ProjectService, ContainerService, AuthService) -- 認證機制(JWT 流程、權限控制) -- 開發模式(DEV_MODE 配置) -- 錯誤處理(失敗回滾、狀態一致性) -- 部署配置(環境變數、Docker Compose、測試) +GitHub Actions 說明與 GCE 部署細節: -適合:後端開發、系統維護、架構理解 +- `.github/workflows/README.md` +- `.github/workflows/GCE_DEPLOY.md` ---- +## 歷史與封存 -## 📖 使用指南 - -### [guides/CLI_MENU_GUIDE.md](./guides/CLI_MENU_GUIDE.md) -**CLI 主選單模式使用指南** - -互動式 CLI 工具完整操作說明: -- 主選單功能介紹 -- 專案管理流程 -- Agent 執行與監控 -- 快捷鍵與操作技巧 - -適合:CLI 用戶、本地開發測試 - ---- - -### [guides/CLI_USAGE.md](./guides/CLI_USAGE.md) -**CLI 命令列使用說明** - -CLI 指令模式操作: -- 指令語法 -- 參數說明 -- 常用場景範例 - -適合:腳本自動化、CI/CD 整合 - ---- - -## 🧪 測試文件 - -### [testing/QUICK_TEST.md](./testing/QUICK_TEST.md) -**快速測試指南** - -一鍵測試流程和常見測試場景。 - ---- - -### [testing/TEST_REPROVISION.md](./testing/TEST_REPROVISION.md) -**Reprovision 測試指南** - -測試停止專案重新 Provision 的流程。 - ---- - -### [testing/TEST_SSE_GUIDE.md](./testing/TEST_SSE_GUIDE.md) -**SSE 串流測試指南** - -測試 Server-Sent Events 日誌串流功能。 - ---- - -## 📦 歷史文件 - -### [archives/](./archives/) -存放臨時變更日誌和開發筆記: -- `CHANGELOG_SSE_FIX.md` - SSE Stream 修復記錄 -- `CLI_UPDATE.md` - CLI 工具更新記錄 - -這些文件保留作為開發歷史參考,不建議依賴其內容。 - ---- - -## 🔍 快速查找 - -### 我想... - -- **整合 API** → [API.md](./API.md) -- **了解後端架構** → [BACKEND.md](./BACKEND.md) -- **使用 CLI 工具** → [guides/CLI_MENU_GUIDE.md](./guides/CLI_MENU_GUIDE.md) -- **執行測試** → [testing/QUICK_TEST.md](./testing/QUICK_TEST.md) -- **設定開發環境** → [BACKEND.md#部署配置](./BACKEND.md#部署配置) -- **理解認證機制** → [API.md#認證機制](./API.md#認證機制) -- **查詢資料模型** → [BACKEND.md#資料模型](./BACKEND.md#資料模型) - ---- - -## 📝 文件維護 - -**重要**:當後端程式碼(`backend/` 目錄)有任何更新時,請同步更新相關文件: - -- API 端點變更 → 更新 `API.md` -- 架構或服務層變更 → 更新 `BACKEND.md` -- CLI 功能變更 → 更新 `guides/CLI_*.md` - ---- - -**文件版本**: v1.0.0 -**最後更新**: 2026-02-02 +過去的變更記錄、一次性報告、開發筆記放在 `docs/archives/`。這些內容保留作為參考,不建議作為最新行為的依據。 diff --git a/docs/RUN_AND_DEV.md b/docs/RUN_AND_DEV.md new file mode 100644 index 0000000..7728d05 --- /dev/null +++ b/docs/RUN_AND_DEV.md @@ -0,0 +1,56 @@ +# Run And Dev + +本文整理常用的啟動、檢查、以及開發時需要知道的操作點。 + +## 常用腳本 + +### 開發環境一鍵啟動 + +```bash +./scripts/deploy-dev.sh +``` + +需求: + +- Docker daemon 可用 +- `backend/.env` 已存在 (可由 `backend/.env.example` 複製) + +### 環境健檢 + +```bash +./scripts/check-env.sh +``` + +此腳本會檢查: + +- Docker daemon +- `refactor-base:latest` 是否存在 +- `refactor-network` 是否存在 +- MongoDB/API/Frontend 是否可連 +- `backend/.env` 是否有必要變數 + +## Base Image (Project Container) + +每個 Project 都會建立隔離的 Docker container,使用 `DOCKER_BASE_IMAGE` (預設 `refactor-base:latest`)。 + +當你更新 `agent/` 或 `devops/base-image/Dockerfile` 時,通常需要重新建置 base image: + +```bash +docker build -t refactor-base:latest -f devops/base-image/Dockerfile . +``` + +## 工作目錄與檔案掛載 + +Backend 會在 `${DOCKER_VOLUME_PREFIX}/${project_id}/` 建立資料夾,並掛載到專案容器: + +- `${...}/${project_id}/repo` -> `/workspace/repo` +- `${...}/${project_id}/artifacts` -> `/workspace/artifacts` + +開發用 docker compose 預設把 host 的 `/tmp/refactor-workspaces` 掛到 API 容器,並由 API 再建立專案 workspace。 + +## 本機開發建議 + +1. DB 用 Compose 跑:`docker compose -f devops/docker-compose.yml up -d postgres mongodb` +2. Backend/Frontend 用本機跑:可快速迭代、也較好除錯 + +詳細流程可回看 `docs/GETTING_STARTED.md`。 diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000..9240803 --- /dev/null +++ b/docs/TROUBLESHOOTING.md @@ -0,0 +1,59 @@ +# Troubleshooting + +## Provision 失敗 / Agent 無法執行 + +常見原因: + +- `POSTGRES_URL` 沒有設定或連不到 (Backend 會在建立 Project Container 時直接拒絕) +- `refactor-base:latest` 不存在 +- `refactor-network` 不存在或 Backend 容器不在該 network + +建議先跑: + +```bash +./scripts/check-env.sh +``` + +## Base image 不存在 + +```bash +docker build -t refactor-base:latest -f devops/base-image/Dockerfile . +``` + +## Docker network 不存在 + +開發環境用 compose 啟動會自動建立: + +```bash +docker compose -f devops/docker-compose.yml up -d +``` + +若你不是用 compose,手動建立: + +```bash +docker network create refactor-network +``` + +## API health check 不通 + +```bash +curl -v http://localhost:8000/api/v1/health +docker logs refactor-api +``` + +## 前端打不到 API + +開發環境前端預設直接打 `http://localhost:8000` (由 `devops/docker-compose.yml` 設定 `VITE_API_BASE_URL`)。 + +生產環境前端會走 Nginx 反向代理: + +- `http://YOUR_HOST/api/...` -> `api:8000` (見 `devops/frontend/nginx.conf`) + +## Vertex AI 相關錯誤 + +先確認 API 容器內是否存在 credentials: + +- `/root/.config/gcloud/application_default_credentials.json` (ADC) +- 或 `GOOGLE_APPLICATION_CREDENTIALS` 指向的檔案 + +細節請看 `docs/VERTEX_AI.md`。 diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 0000000..322e695 --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,115 @@ +# Usage + +本專案主要流程: + +1. 註冊/登入 (取得 JWT) +2. 建立專案 (Project) +3. Provision (建立並啟動專案容器、clone repo 等) +4. 啟動 Agent (在專案容器內執行) +5. 串流查看執行日誌 + +本文以 API 範例為主。你也可以直接使用前端 UI 操作。 + +## 1) 註冊 / 登入 + +### 註冊 + +```bash +curl -X POST http://localhost:8000/api/v1/auth/register \ + -H "Content-Type: application/json" \ + -d '{"email":"user@example.com","username":"testuser","password":"password123"}' +``` + +### 登入 (注意: 使用 username 登入) + +```bash +TOKEN=$( + curl -sS -X POST http://localhost:8000/api/v1/auth/login \ + -H "Content-Type: application/json" \ + -d '{"username":"testuser","password":"password123"}' \ + | python -c 'import json,sys; print(json.load(sys.stdin)["access_token"])' +) +echo "$TOKEN" +``` + +## 2) 建立專案 + +### REFACTOR 專案 (需要 repo_url) + +`spec` 是 Agent 的重構規格說明 (可先填簡短描述,之後可更新)。 + +```bash +curl -X POST http://localhost:8000/api/v1/projects \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "title": "My Refactor Project", + "project_type": "REFACTOR", + "repo_url": "https://github.com/your-org/your-repo.git", + "branch": "main", + "spec": "請先掃描專案並提出可量化的重構計劃,優先處理測試與風險控管。" + }' +``` + +### SANDBOX 專案 (repo_url 可不填) + +```bash +curl -X POST http://localhost:8000/api/v1/projects \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "title": "Sandbox", + "project_type": "SANDBOX", + "spec": "用於驗證 agent 能否正常執行" + }' +``` + +## 3) Provision 專案 + +```bash +curl -X POST http://localhost:8000/api/v1/projects/{project_id}/provision \ + -H "Authorization: Bearer $TOKEN" +``` + +Provision 完成後,專案狀態應該會進入 `READY` 才能啟動 Agent。 + +## 4) 啟動 Agent + +```bash +curl -X POST http://localhost:8000/api/v1/projects/{project_id}/agent/run \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{}' +``` + +若要指定模型 (若後端/agent 支援): + +```bash +curl -X POST http://localhost:8000/api/v1/projects/{project_id}/agent/run \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"model":"claude-sonnet"}' +``` + +回應會包含 `run_id`,用於查詢狀態與串流日誌。 + +## 5) 查詢狀態 / 串流日誌 + +### 查詢單次 Run 狀態 + +```bash +curl http://localhost:8000/api/v1/projects/{project_id}/agent/runs/{run_id} \ + -H "Authorization: Bearer $TOKEN" +``` + +### SSE 串流日誌 + +```bash +curl -N http://localhost:8000/api/v1/projects/{project_id}/agent/runs/{run_id}/stream \ + -H "Authorization: Bearer $TOKEN" +``` + +## 參考 + +- Swagger/OpenAPI: `http://localhost:8000/docs` +- API 規格文件: `docs/API.md` diff --git a/docs/VERTEX_AI.md b/docs/VERTEX_AI.md new file mode 100644 index 0000000..da8fe38 --- /dev/null +++ b/docs/VERTEX_AI.md @@ -0,0 +1,60 @@ +# Vertex AI (Optional) + +本專案支援在「Project Container」中使用 Vertex AI 相關模型。重點在於: + +1. Backend API 容器必須能存取 GCP credentials (ADC 或 Service Account JSON) +2. Backend 會把 credentials 轉掛載進每個 Project Container + +## 本機 (Docker Compose 開發) + +`devops/docker-compose.yml` 會把你本機的 ADC 檔案掛進 API 容器: + +- host: `${HOME}/.config/gcloud/application_default_credentials.json` +- container: `/root/.config/gcloud/application_default_credentials.json` + +你需要先在本機產生 ADC: + +```bash +gcloud auth application-default login +``` + +然後在 `backend/.env` 設定: + +```bash +GCP_PROJECT_ID=your-gcp-project-id +GCP_LOCATION=us-central1 +``` + +若你想用顯式路徑,也可加上: + +```bash +GOOGLE_APPLICATION_CREDENTIALS=/root/.config/gcloud/application_default_credentials.json +``` + +## 生產環境 (GCE/VM) + +建議使用 Service Account JSON 或 VM 的預設服務帳號。 + +### 選項 A: 掛載 Service Account JSON (最直覺) + +1. 把 SA JSON 放到主機上,例如 `/etc/reforge/sa.json` +2. 在 production compose 的 `api` service 增加 volume 掛載 (自行調整): + +```yaml +volumes: + - /etc/reforge/sa.json:/run/secrets/gcp-sa.json:ro +``` + +3. 在 `backend/.env` 設定: + +```bash +GCP_PROJECT_ID=your-gcp-project-id +GCP_LOCATION=us-central1 +GOOGLE_APPLICATION_CREDENTIALS=/run/secrets/gcp-sa.json +``` + +Backend 會將該檔案複製到 workspace volume,並掛載到 Project Container 內使用。 + +### 選項 B: 使用 ADC (若主機有 gcloud / 或透過其他方式提供 ADC) + +確保 API 容器內有 `/root/.config/gcloud/application_default_credentials.json`,Backend 會自動偵測並轉掛載。 diff --git a/docs/TESTING_UX_IMPROVEMENTS.md b/docs/archives/notes/TESTING_UX_IMPROVEMENTS.md similarity index 99% rename from docs/TESTING_UX_IMPROVEMENTS.md rename to docs/archives/notes/TESTING_UX_IMPROVEMENTS.md index cedbb7d..afe8389 100644 --- a/docs/TESTING_UX_IMPROVEMENTS.md +++ b/docs/archives/notes/TESTING_UX_IMPROVEMENTS.md @@ -265,7 +265,7 @@ setTimeout(() => toast.error('通知 3'), 1000) ### Q2: 重連失敗 **檢查**: - 容器是否正在運行: `docker ps` -- Backend API 是否正常: `curl http://localhost:8000/health` +- Backend API 是否正常: `curl http://localhost:8000/api/v1/health` - 瀏覽器 Network 分頁查看 SSE 連線狀態 ### Q3: 日誌不更新 diff --git a/docs/UX_IMPROVEMENTS.md b/docs/archives/notes/UX_IMPROVEMENTS.md similarity index 100% rename from docs/UX_IMPROVEMENTS.md rename to docs/archives/notes/UX_IMPROVEMENTS.md diff --git a/docs/VERTEX_AI_INTEGRATION.md b/docs/archives/notes/VERTEX_AI_INTEGRATION.md similarity index 100% rename from docs/VERTEX_AI_INTEGRATION.md rename to docs/archives/notes/VERTEX_AI_INTEGRATION.md diff --git a/CHANGELOG_UX_IMPROVEMENTS.md b/docs/archives/reports/CHANGELOG_UX_IMPROVEMENTS.md similarity index 98% rename from CHANGELOG_UX_IMPROVEMENTS.md rename to docs/archives/reports/CHANGELOG_UX_IMPROVEMENTS.md index 750e47d..8a7bf6d 100644 --- a/CHANGELOG_UX_IMPROVEMENTS.md +++ b/docs/archives/reports/CHANGELOG_UX_IMPROVEMENTS.md @@ -34,12 +34,12 @@ - 重連狀態提示 ### Documentation -5. **`docs/UX_IMPROVEMENTS.md`** +5. **`docs/archives/notes/UX_IMPROVEMENTS.md`** - 詳細的功能說明文件 - 使用範例和技術細節 - 未來改進方向 -6. **`docs/TESTING_UX_IMPROVEMENTS.md`** +6. **`docs/archives/notes/TESTING_UX_IMPROVEMENTS.md`** - 完整的測試指南 - 10 個測試案例 - 測試報告模板 diff --git a/ENV_UPDATE_SUMMARY.md b/docs/archives/reports/ENV_UPDATE_SUMMARY.md similarity index 100% rename from ENV_UPDATE_SUMMARY.md rename to docs/archives/reports/ENV_UPDATE_SUMMARY.md diff --git a/POSTGRES_MIGRATION_SUMMARY.md b/docs/archives/reports/POSTGRES_MIGRATION_SUMMARY.md similarity index 100% rename from POSTGRES_MIGRATION_SUMMARY.md rename to docs/archives/reports/POSTGRES_MIGRATION_SUMMARY.md diff --git a/TEST_RESULTS.md b/docs/archives/reports/TEST_RESULTS.md similarity index 100% rename from TEST_RESULTS.md rename to docs/archives/reports/TEST_RESULTS.md diff --git a/docs/testing/CHAT_FEATURE_TEST.md b/docs/testing/CHAT_FEATURE_TEST.md index 84e705e..9bff24f 100644 --- a/docs/testing/CHAT_FEATURE_TEST.md +++ b/docs/testing/CHAT_FEATURE_TEST.md @@ -19,7 +19,7 @@ docker build -t refactor-base:latest -f devops/base-image/Dockerfile . ### 2. 啟動所有服務 ```bash -docker-compose -f devops/docker-compose.dev.yml up -d +docker compose -f devops/docker-compose.yml up -d --build ``` 這會啟動: @@ -32,7 +32,7 @@ docker-compose -f devops/docker-compose.dev.yml up -d ```bash # 檢查 PostgreSQL 是否正常運行 -docker-compose -f devops/docker-compose.dev.yml logs postgres +docker compose -f devops/docker-compose.yml logs postgres # 連接到 PostgreSQL docker exec -it refactor-postgres psql -U langgraph -d langgraph @@ -60,7 +60,7 @@ docker exec -it refactor-postgres psql -U langgraph -d langgraph # 1. 登入獲取 token TOKEN=$(curl -s -X POST "http://localhost:8000/api/v1/auth/login" \ -H "Content-Type: application/json" \ - -d '{"email": "test@example.com", "password": "password123"}' | jq -r '.access_token') + -d '{"username": "testuser", "password": "password123"}' | jq -r '.access_token') # 2. 建立 Sandbox 專案 PROJECT_ID=$(curl -s -X POST "http://localhost:8000/api/v1/projects" \ @@ -68,7 +68,7 @@ PROJECT_ID=$(curl -s -X POST "http://localhost:8000/api/v1/projects" \ -H "Content-Type: application/json" \ -d '{ "project_type": "SANDBOX", - "init_prompt": "Hello, list the files in the current directory" + "spec": "Hello, list the files in the current directory" }' | jq -r '.id') echo "Project ID: $PROJECT_ID" @@ -116,7 +116,7 @@ SELECT thread_id, checkpoint_id, created_at FROM checkpoints ORDER BY created_at 1. 在聊天中進行幾輪對話 2. 記下 thread_id -3. 重啟容器:`docker-compose -f devops/docker-compose.dev.yml restart` +3. 重啟服務:`docker compose -f devops/docker-compose.yml restart` 4. 使用相同的 thread_id 繼續對話 5. 驗證 AI 能記住之前的上下文 @@ -158,5 +158,5 @@ docker exec refactor-project- env | grep POSTGRES ### 對話沒有保存 1. 確認使用了正確的 thread_id -2. 檢查 PostgreSQL 日誌:`docker-compose -f devops/docker-compose.dev.yml logs postgres` +2. 檢查 PostgreSQL 日誌:`docker compose -f devops/docker-compose.yml logs postgres` 3. 確認 `langgraph-checkpoint-postgres` 套件已安裝 diff --git a/docs/testing/POSTGRES_PERSISTENCE_VERIFICATION.md b/docs/testing/POSTGRES_PERSISTENCE_VERIFICATION.md index 9f3688d..9ecbbf9 100644 --- a/docs/testing/POSTGRES_PERSISTENCE_VERIFICATION.md +++ b/docs/testing/POSTGRES_PERSISTENCE_VERIFICATION.md @@ -57,7 +57,7 @@ PostgreSQL Database (langgraph schema) ```bash # 1. 確保 PostgreSQL 正在運行 -docker-compose -f devops/docker-compose.yml up -d postgres +docker compose -f devops/docker-compose.yml up -d postgres # 2. 設定環境變數 export POSTGRES_URL="postgresql://langgraph:langgraph_secret@localhost:5432/langgraph" @@ -92,7 +92,7 @@ open htmlcov/index.html ```bash # 啟動 PostgreSQL -docker-compose -f devops/docker-compose.yml up -d postgres +docker compose -f devops/docker-compose.yml up -d postgres # 等待服務就緒 sleep 5 @@ -176,7 +176,7 @@ curl -X POST http://localhost:8000/chat \ #### 3.2 重啟容器 ```bash -docker-compose -f devops/docker-compose.yml restart api +docker compose -f devops/docker-compose.yml restart api ``` #### 3.3 發送第二條訊息(應記得之前的對話) diff --git a/docs/testing/QUICK_TEST.md b/docs/testing/QUICK_TEST.md index 0bccfdf..3b7c40f 100644 --- a/docs/testing/QUICK_TEST.md +++ b/docs/testing/QUICK_TEST.md @@ -81,7 +81,7 @@ python3 cli.py # 檢查 Backend 是否運行 curl http://localhost:8000/api/v1/auth/login -X POST \ -H "Content-Type: application/json" \ - -d '{"email":"test@example.com","password":"testpass123"}' + -d '{"username":"test","password":"testpass123"}' ``` ### 2. Provision 失敗 diff --git a/docs/testing/TEST_REPROVISION.md b/docs/testing/TEST_REPROVISION.md index 055da73..b2d3753 100644 --- a/docs/testing/TEST_REPROVISION.md +++ b/docs/testing/TEST_REPROVISION.md @@ -49,7 +49,7 @@ python3 cli.py # 1. 登入取得 token curl -X POST http://localhost:8000/api/v1/auth/login \ -H "Content-Type: application/json" \ - -d '{"email":"test@example.com","password":"testpass123"}' + -d '{"username":"testuser","password":"testpass123"}' # 儲存 token export TOKEN="your_access_token" @@ -59,9 +59,10 @@ PROJECT_RESPONSE=$(curl -X POST http://localhost:8000/api/v1/projects \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ + "project_type":"REFACTOR", "repo_url":"https://github.com/octocat/Hello-World.git", "branch":"main", - "init_prompt":"分析程式碼" + "spec":"分析程式碼" }') PROJECT_ID=$(echo $PROJECT_RESPONSE | jq -r '.id') @@ -85,8 +86,8 @@ curl "http://localhost:8000/api/v1/projects/$PROJECT_ID" \ -H "Authorization: Bearer $TOKEN" | jq '.status' # 應顯示: "STOPPED" -# 5. 重新 Provision(測試新功能) -curl -X POST "http://localhost:8000/api/v1/projects/$PROJECT_ID/provision" \ +# 5. Reprovision(測試新功能:刪除容器並重新 provision) +curl -X POST "http://localhost:8000/api/v1/projects/$PROJECT_ID/reprovision" \ -H "Authorization: Bearer $TOKEN" # 查詢狀態 diff --git a/scripts/check-env.sh b/scripts/check-env.sh index e3202cc..2ca5043 100644 --- a/scripts/check-env.sh +++ b/scripts/check-env.sh @@ -215,7 +215,7 @@ check_env_file() { fi # JWT_SECRET_KEY - if [ -n "$JWT_SECRET_KEY" ] && [ "$JWT_SECRET_KEY" != "your-super-secret-jwt-key-change-this-in-production" ]; then + if [ -n "$JWT_SECRET_KEY" ] && [ "$JWT_SECRET_KEY" != "your-secret-key-change-in-production-please" ]; then print_success "JWT_SECRET_KEY 已設定" else print_warning "JWT_SECRET_KEY 使用預設值(不安全)" diff --git a/scripts/deploy-prod.sh b/scripts/deploy-prod.sh index 29bd5dc..37097c9 100755 --- a/scripts/deploy-prod.sh +++ b/scripts/deploy-prod.sh @@ -23,6 +23,10 @@ BASE_IMAGE_TAG=${BASE_IMAGE_TAG:-$IMAGE_TAG} WORKSPACE_HOST_DIR=${WORKSPACE_HOST_DIR:-/var/lib/refactor-workspaces} COMPOSE_FILE="devops/docker-compose.prod.yml" +# docker compose 需要讀取這些環境變數來組成 image name 與 volume path +export IMAGE_TAG BASE_IMAGE_TAG WORKSPACE_HOST_DIR +export REGISTRY_HOST GCP_PROJECT_ID GAR_REPOSITORY + if ! command -v docker >/dev/null 2>&1; then echo "Docker not found. Please install Docker." >&2 exit 1 diff --git a/scripts/verify-deployment.sh b/scripts/verify-deployment.sh index 94e7313..6da3965 100755 --- a/scripts/verify-deployment.sh +++ b/scripts/verify-deployment.sh @@ -1,55 +1,63 @@ -#!/bin/bash -# 快速驗證 GCE 部署狀態 +#!/usr/bin/env bash +# 快速驗證 GCE 部署狀態(以環境變數控制目標) set -euo pipefail -PROJECT_ID="tsmccareerhack2026-tsid-grp4" -INSTANCE="gce-instance" -ZONE="us-central1-a" +PROJECT_ID="${GCP_PROJECT_ID:-}" +INSTANCE="${GCE_INSTANCE:-}" +ZONE="${GCE_ZONE:-}" -echo "🔍 驗證 GCE 部署狀態..." -echo "" +if [[ -z "$PROJECT_ID" || -z "$INSTANCE" || -z "$ZONE" ]]; then + echo "Missing required env vars. Example:" >&2 + echo " export GCP_PROJECT_ID=your-project-id" >&2 + echo " export GCE_INSTANCE=refactor-agent-prod" >&2 + echo " export GCE_ZONE=us-central1-a" >&2 + exit 1 +fi + +echo "Verifying GCE deployment..." # 檢查容器狀態 -echo "📊 容器狀態:" -gcloud compute ssh $INSTANCE \ - --zone=$ZONE \ - --project=$PROJECT_ID \ +echo "" +echo "Container status:" +gcloud compute ssh "$INSTANCE" \ + --zone="$ZONE" \ + --project="$PROJECT_ID" \ --command="sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'" echo "" -echo "🔍 端口佔用檢查:" -gcloud compute ssh $INSTANCE \ - --zone=$ZONE \ - --project=$PROJECT_ID \ - --command="sudo netstat -tulpn | grep -E '(5432|5433|27017|8000|80)' || echo '無端口衝突'" +echo "Port check:" +gcloud compute ssh "$INSTANCE" \ + --zone="$ZONE" \ + --project="$PROJECT_ID" \ + --command="(command -v ss >/dev/null 2>&1 && sudo ss -tulpn || sudo netstat -tulpn) | grep -E '(5432|27017|8000|80)' || echo 'No port conflicts found'" echo "" -echo "🏥 健康檢查:" +echo "Health check:" # 取得外部 IP -EXTERNAL_IP=$(gcloud compute instances describe $INSTANCE \ - --zone=$ZONE \ - --project=$PROJECT_ID \ +EXTERNAL_IP=$(gcloud compute instances describe "$INSTANCE" \ + --zone="$ZONE" \ + --project="$PROJECT_ID" \ --format='get(networkInterfaces[0].accessConfigs[0].natIP)') -echo "外部 IP: $EXTERNAL_IP" +echo "External IP: $EXTERNAL_IP" # 測試 API (通過 Nginx) -echo -n "API (/api/v1/health): " -if curl -sf "http://${EXTERNAL_IP}:80/api/v1/health" > /dev/null 2>&1; then - echo "✅ OK" +echo -n "API (/api/v1/health via port 80): " +if curl -sf "http://${EXTERNAL_IP}:80/api/v1/health" >/dev/null 2>&1; then + echo "OK" else - echo "❌ FAILED" + echo "FAILED" fi # 測試 Frontend -echo -n "Frontend (/): " -if curl -sf "http://${EXTERNAL_IP}:80" > /dev/null 2>&1; then - echo "✅ OK" +echo -n "Frontend (/ via port 80): " +if curl -sf "http://${EXTERNAL_IP}:80" >/dev/null 2>&1; then + echo "OK" else - echo "❌ FAILED" + echo "FAILED" fi echo "" -echo "✅ 驗證完成" +echo "Done."