昨天確認了 Manifest、Service Worker 與離線提示,也在 Android 模擬器從主畫面啟動了 WorkCafe。恢復連線、版本更新與實體手機測試還需要繼續確認。
今天先準備 Cloud Run 部署環境,調整建置方式並送出網站建置。公開網址的部署與驗證接到 Day 29 繼續。
這次部署的是 Laravel+Inertia+React 整個應用。首頁需要 Laravel 讀取 Firestore,不能只把前端 build 檔案放上靜態網站空間,就當作部署完成。
這次選擇 GCP,部署方案採 Cloud Run:把 Laravel 與前端建置產物包成容器,映像存到 Artifact Registry,再由 Cloud Run 提供 HTTPS 網址。
先沿用已確認的 GCP 專案與 Firestore 資料庫,不重新建立資料庫。確認專案計費、Cloud Run、Cloud Build、Artifact Registry 與 Secret Manager 所需服務及權限,再選擇合適區域。網站後端改用 Firestore REST API,以 HTTPS 讀取資料。Cloud Run 只執行網站程式,資料仍存在 Firestore;正式映像不再編譯 gRPC,也不需要另外建立 PHP+gRPC 基底。
這次以現有探索首頁為主,保留示範資料標示。自然語言解析、評論摘要與 Work Score 等 /test/* 頁面繼續留在本機,不因為要上線就一起公開。登入、收藏或 AI 搜尋是否納入,先核對實際程式與公開規格,不能只看到圖示就認定功能完整。
先在 Antigravity 貼上:
請盤點 WorkCafe 部署到 GCP Cloud Run 的需求,先列計畫,不修改或部署。
採 Cloud Build 建置容器、Artifact Registry 儲存映像、Cloud Run 執行服務。
沿用現有 GCP 專案與 Firestore;實際 Project ID 只在私下設定,不寫入文件。
閱讀 README、docs/ CURRENT 規格、composer.json、composer.lock、
package.json、鎖定檔、Vite 設定、Laravel 設定與路由。
只核對環境變數名稱和用途,不輸出 .env 值、金鑰、憑證內容或 Project ID。
這是 Laravel+Inertia+React 應用,首頁由 Laravel 讀取 Firestore,
不能只部署前端靜態檔案。
列出 PHP 與擴充需求、Firestore REST 與 ADC 驗證需求、Node 建置需求、
web root、持久化儲存、session/cache,以及是否真的需要 queue 或 scheduler。
依目前程式列出:
1. 本次可公開的功能。
2. 僅限 local/testing 的 /test/* 路由。
3. 未完成或尚未驗證的功能,不自行補做登入、收藏或 AI 功能。
列出伺服器必要設定、Maps 瀏覽器金鑰限制、
Firestore 唯讀身分,以及部署、健康檢查、回復前一版的順序。
網站不配置測試資料匯入身分,不執行 seed 或自動寫入 Firestore。
採 Cloud Run 提供的 HTTPS 網址開始驗證。
專案、區域、Repository、服務名稱與部署權限未確認時列為待提供。
檢查 Firestore 程式能否使用 Application Default Credentials,
改由 Cloud Run 專用服務帳戶取得身分,不打包 JSON 金鑰。
產出 docs/DEPLOYMENT_CHECKLIST.md 的草稿內容,
只含檢查項目、設定名稱、狀態和未完成事項。
不要把預期結果寫成已通過,不自動 commit、push 或部署。
平台與公開範圍確定後,再貼準備指令:
依已確認的 GCP Cloud Run 部署計畫,準備 WorkCafe 發布版本。
準備 Dockerfile、.dockerignore 與 Cloud Build 所需設定,
用正式 HTTP server 執行 Laravel,不使用 php artisan serve 作為正式 server。
監聽 0.0.0.0 的 PORT(預設 8080),web root 指向 public。
排除 .env、憑證、node_modules、public/hot 與本機測試產物。
不要把正式環境設定快取或秘密烘焙進映像。
APP_KEY 由 Secret Manager 注入;只授予指定 secret 的存取權。
Cloud Run runtime 身分使用專用服務帳戶,Firestore 授予所需唯讀權限,
例如 Cloud Datastore Viewer;建置、部署與執行身分分開處理。
Firestore 透過 google/auth 取得 ADC 權杖,以 REST 讀取並處理分頁與型別。
正式 composer install --no-dev 不得安裝 gRPC 相依套件;本機匯入工具留在開發環境。
容器磁碟不當作持久儲存;依現況選擇可用的 session/cache 策略,
不得依賴本機 SQLite 或檔案 session 跨實例保存。
日誌輸出到 stdout/stderr,核對 HTTPS 代理、cookie 與 URL 產生設定。
提出最小實例數、最大實例數、記憶體與逾時設定,不承諾零費用。
先核對 Git 工作狀態與部署版本,保留既有未提交修改。
完成必要的部署設定與 docs/DEPLOYMENT_CHECKLIST.md,
每一項標明已確認、待設定、待驗證或不適用,不猜測狀態。
正式環境使用 APP_ENV=production、APP_DEBUG=false 與正確 HTTPS APP_URL。
APP_KEY 使用正式環境固定值,不在每次部署時重新產生。
只列出設定名稱與是否齊備,不回傳任何秘密值。
Web root 指向 Laravel public,.env 與服務帳戶憑證不可公開下載。
Firestore 使用唯讀身分;不部署 importer 憑證,不執行資料匯入。
依實際 session/cache driver 準備持久化與權限。
若需要 migration,先列出用途、影響與備份方式,不直接執行。
前端只能包含必要的公開設定。VITE_* 不得放伺服器秘密。
Maps 瀏覽器金鑰限制正式網站來源與必要 API;
後端金鑰與服務帳戶憑證只留在伺服器。
未公開的 AI/Places 測試功能不要求配置其秘密。
依鎖定檔安裝依賴並建置,確認沒有 public/hot 或 localhost HMR 依賴。
依專案可用指令執行 typecheck、build 與相關測試。
配置快取必須在正式環境變數到位後建立;
正式路由快取要在 production 環境產生,不沿用 local 的快取。
確認 /test/* 不出現在正式路由,Service Worker 不替它回傳假成功頁。
保留 PWA 靜態快取白名單,不快取店家回應、地圖圖磚或 API 資料。
檢查 sw.js、manifest、icons、offline.html 的路徑與更新策略。
回報變更檔案、實際檢查結果、平台專用部署命令、
發布後驗證方式及回復前一版的方法。
不要自動 commit、push、建立付費資源或部署。
這次建置曾停在 gRPC 編譯,延長到一小時仍逾時。因此改成由 Laravel 透過 HTTPS 讀取 Firestore,保留原本資料與前端功能。
正式網站使用 google/auth 取得服務帳戶權杖,依 IAM 唯讀權限讀取 cafes。程式會接續讀完分頁,轉換數字、布林、日期與巢狀欄位;連線或權限失敗時回報錯誤,不補上假資料。
舊的 Firestore SDK 只留給本機資料匯入工具,歸在開發相依套件;正式映像使用 composer install --no-dev,且 production 環境禁止執行匯入。Dockerfile 不再編譯 gRPC 或 Protobuf,獨立基底建置流程已移除,Cloud Build 回到預設機型。
完整測試共 83 項通過(416 個斷言),其中本次相關的 24 項涵蓋 REST 分頁、型別、空資料、權限及連線失敗、匯入保護、PWA 與情境排序。這些測試使用模擬回應;REST 的實際雲端身分、容器啟動與公開網址仍待部署驗證。
檢查表也要使用 REST 版。先前截圖中「安裝 gRPC/Protobuf」的內容已不適用,替換成最新檢查表後再放入文章。
程式與設定修改完成後,依序處理下面的雲端設定;本機 Docker 尚無法連線,容器建置留待 Cloud Build 驗證。以下名稱是本文範例;若專案已有相同用途的資源,就沿用並核對設定。
在 Google Cloud Console 上方選擇目前存放 Firestore 的專案,確認已連結計費帳戶。進入「API 和服務 → 程式庫」,依序確認以下服務已啟用:
沿用既有 Firestore 資料庫,核對程式使用的資料庫 ID。部署區域先選定並記錄,後續 repository 與 Cloud Run 使用相同區域,例如 asia-east1;實際選擇仍要考量資料庫位置。
進入「Artifact Registry → Repositories → Create repository」,名稱填 workcafe-repo,格式選 Docker、模式選 Standard,位置選前面決定的區域。
接著進入「IAM 與管理 → 服務帳戶」,建立 workcafe-runtime,作為網站執行時的身分。授予它讀取現有 Firestore 所需的 Cloud Datastore Viewer(roles/datastore.viewer)權限,不配置匯入資料的寫入身分,也不下載 JSON 金鑰。
Cloud Build 使用另一個建置身分。先確認此次建置實際使用哪個服務帳戶,再授予必要的儲存庫寫入、建置來源讀取及日誌寫入權限,不假設一定使用舊版預設帳戶。執行部署的人也需要 Cloud Run 部署權限,以及使用指定 runtime 服務帳戶的權限。
本次按照 WorkCafe 首次部署到 Cloud Run 的流程,建立一把固定的正式環境金鑰。
步驟 1:開啟專案終端機
在 Antigravity 開啟終端機,切換到 WorkCafe 專案:
cd C:\ServBay\www\workcafe
步驟 2:產生 APP_KEY
執行:
php artisan key:generate --show
複製終端機顯示的完整一行,包含開頭的 base64:。這個指令只顯示新金鑰,不會修改本機 .env。
步驟 3:建立密鑰
這一把就是正式環境固定使用的 APP_KEY。金鑰值不放入文章、截圖或對話;後續更新網站版本都沿用它,不重新產生。
步驟 4:複製服務帳戶的完整電子郵件地址
授權欄位需要完整電子郵件地址,不能只填 workcafe-runtime。直接複製服務帳戶清單中的地址,不自行拼接。
步驟 5:授權服務帳戶讀取密鑰
完成後繼續建置映像;Day 29 建立 Cloud Run 服務時,再把這個密鑰接到 APP_KEY。
先把檢查表中的必要項目補齊:
| 項目 | 要確認的內容 |
|---|---|
| Laravel | production、關閉 debug、固定 APP_KEY、正確 APP_URL |
| 容器 | PHP 與擴充符合鎖定檔,模板與目錄齊備,網站根目錄指向 public |
| Firestore | 專案與資料庫設定正確,runtime 身分可唯讀存取 |
| 地圖 | 瀏覽器金鑰與 Map ID 已提供,金鑰限制必要來源及 API |
| 前端 | VITE_* 公開建置值齊備,沒有 HMR 或伺服器秘密 |
| 儲存 | session 不依賴容器檔案跨實例保存;cache 用途與暫存限制已確認 |
| 公開範圍 | /test/* 不公開,示範資料標示保留 |
| 版本 | 使用明確映像標籤,記錄建置版本與 image digest |
📸 圖片 1-1|部署前盤點 GCP 資源與執行身分
📸 圖片 1-2|核對 Laravel 容器與執行環境
📸 圖片 1-3|區分環境變數、Secret Manager 與前端建置參數
📸 圖片 1-4|REST 版存取限制、資源設定與待驗證項目
步驟 1:開啟 PowerShell 並登入
在 Antigravity 開啟終端機,執行:
cd C:\ServBay\www\workcafe
gcloud --version
gcloud init
gcloud init 會引導登入 Google 帳號並選擇專案。選擇現有 Firestore 所在專案,完成後核對:
gcloud config get-value account
gcloud config get-value project
電腦尚未安裝 gcloud 時,先依 Google Cloud CLI 的 Windows 安裝說明完成安裝,再重新開啟終端機。帳號與專案資訊不用放進文章截圖。
步驟 2:填寫前端公開設定
在專案根目錄將 .env.build.example 複製為 .env.build。依本機 .env 的同名欄位填入 VITE_APP_NAME、Maps 瀏覽器金鑰、Map ID,以及現有 Firebase 前端設定,然後儲存。只使用範本列出的欄位,不把 APP_KEY、服務帳戶 JSON 或後端金鑰放進去。
VITE_* 會在前端打包時寫入產物,所以要在建置前填好;只在 Cloud Run 補上同名變數,不會改變已完成的前端檔案。
步驟 3:先檢查設定格式
./scripts/submit-cloud-build.ps1 -CheckOnly
看到「前端設定格式通過」後再繼續。這個模式不送出建置,也不檢查雲端權限。
步驟 4:送出網站建置
./scripts/submit-cloud-build.ps1
指令會自動讀取 .env.build、產生日期時間版本標籤,並使用 cloudbuild.yaml 上傳及建置網站。不再手動組合 workcafeSubstitutions,也不執行舊的 cloudbuild.base.yaml。
目前設定使用 asia-east1 的 workcafe-repo,網站映像名稱為 workcafe-app。Cloud Build 使用預設機型與 60 分鐘上限;移除 gRPC 編譯不代表零費用,也尚未量測這版的實際建置時間。
今天完成了 Firestore REST 讀取改版、相關自動測試與建置設定調整,也已送出網站建置。由於建置等待時間較長,今天先做到這裡,尚未完成部署驗證。
Day 29 會先確認 Cloud Build 的建置結果,再接續 Cloud Run 部署、網站功能檢查與截圖。建置失敗就先查看日誌並修正,再繼續部署。
參考:Firestore REST API、Google Cloud CLI 安裝、Cloud Run 容器部署、Laravel 部署文件、Google Maps 金鑰安全設定。