Part 3|第 11/30 篇
今日要做的事: 把 Day 9 的 Stitch 三頁交給 Antigravity,做成行動版網頁,接到既有 Firebase:先 Auth,再 daily、再 pantry;推薦卡先用本地 mock。
今天要解決的目的: 按鈕後面的路徑要寫對。看了一張推薦卡,冰箱不能自己少半盒豆腐。
Day 9 的畫面 21 秒能點到 Result,那是原型。好看,但按下去不會寫進我的 Firebase。
今天若只顧「AI 幫我把 App 生出來」,它很可能很順、也很會提早扣庫存。
我不追「模型已經會推薦」。我先追:昨天那三頁真的接到登入的人,寫得進、讀得回,而且狀態沒有說謊。
| 項目 | 內容 |
|---|---|
| 產出 | 網頁 MVP:版面跟 Stitch 三頁對得上;登入、daily 讀寫、pantry 讀寫、mock 推薦卡 |
| 工具 | Google Stitch(畫面規格)、Antigravity(寫網頁)、既有 Firebase Auth/Firestore、Firebase Web SDK |
| 不使用 | 原生 App、回 Stitch 重畫成桌面版、真 Gemini 推薦、關 Rules 換 demo、Admin SDK |
| 完成條件 | 登入後寫進自己的 uid;外食不推薦、不扣庫存;家裡煮採用也不扣 |
程式在 material/code/day10,沿用 Day 8 的 .env。key 留在檔案裡。
先在 Stitch 把三頁畫好,並建立 API 金鑰。接著打開 Antigravity IDE,專案指到 day10,裝上 Stitch MCP,金鑰只貼進 IDE。IDE 依那個畫面寫出網頁之後,我在瀏覽器點一遍;不對就再改,這圈今天轉了好幾次(表單太丑、外食還在推薦家裡菜)。畫面對了,才到 Firestore 看豆腐的 qty 和 daily 有沒有真的寫進去。

Day 7 已經證明 uid-A 讀不到 uid-B。今天不是重寫 Rules,是確認 AI 寫的網頁沒有繞過那條路徑,也沒有把「我看看這道菜」當成「我已經煮完」。

外食記一筆 → 寫 today_meals,pantry 不動
採用自煮推薦 → 只記「我想做」,pantry 不動
煮完(Outflow) → 才寫 cook_runs、更新 qty、把成品寫進 today_meals
少了這道閘門,隔天的推薦會從一份已經說謊的冰箱出發。
閉環就是按下去的事要在 Firestore 對得上,而且冰箱沒有自己變少。登入寫得進、讀得回;外食只記一筆、不扣豆腐;家裡煮按了「採用」也只是記下「我想做」。這圈合上,才叫閉環。推薦先說真話,是示意卡不能宣稱冰箱裡沒有的肉,外食也不該再端出家裡菜。真的會推薦是後面的事,今天先不要。
主路徑只有這四段,而且是行動版網頁,不是再做一個上架 App:
Firebase Auth
→ users/{uid}/daily/{yyyy-mm-dd}
→ users/{uid}/pantry_items/{itemId}
→ 本地 mock 推薦卡(標示 mock)
uid 只來自登入,不接受網址或表單自稱。Day 7 已經擋過別人的 uid。今天這筆豆腐,就是寫進登入這個帳號的文件。qty。中途曾經冒出 quantity,我沒讓它留在文件裡。food_source === "home" 而且事件是 cook_completed 才扣。function shouldApplyPantryDelta(source, event) {
return source === "home" && event === "cook_completed";
}
自煮扣庫存若要做,三件事放同一個 transaction:cook_runs、pantry qty、today_meals。失敗就整筆回滾,不能只扣冰箱、戰報卻沒寫。
兩天其實是同一件事的前後段。Stitch 不進 Runtime,它昨天把「累的人願意按的三頁」畫出來。Antigravity 今天負責把那三頁做成瀏覽器打得開的網頁,並接到 Day 6–8 那個 Firebase。結合的方式不是把 Stitch 再改成桌面網站,也不是在 Antigravity 裡從零重畫一張工程師表單。

手機外框留著沒關係。我要的一直是直向網頁:下班用手機瀏覽器打開,不上架。外框是預覽,不是叫我去做原生 App。
官方接法不是把截圖丟進對話,是 Stitch MCP:Antigravity 直接讀 Stitch 專案。Codelab 裡的 LaunchPad、React 行銷頁不要照做,我要拉的是已經畫好的三頁。
Stitch 右上角大頭貼 → Stitch 設定 → API 金鑰。一開始沒有可顯示的金鑰。黃條寫:濫用偵測關掉時,公開的 key 會被自動停用。所以這把鑰匙只留在自己電腦的 MCP 設定。

按「建立金鑰」,展開 設定 MCP,IDE 選 Antigravity。它給出本機要用的設定:serverUrl 是 https://stitch.googleapis.com/mcp,header 是 X-Goog-Api-Key。金鑰和信箱沒有進文章。

這段 JSON 我沒有貼進對話。真正接上是在 Antigravity IDE:MCP Store 搜尋 Stitch → Install → 金鑰貼進欄位 → Save。截圖裡的輸入框是空的。紅框是當時要看的兩個位置。

存完之後,在 day10 的對話打了 List my Stitch projects. 它找到的專案叫 DishFlow 行動網頁。列表有一套設計系統,加上 4 個手機畫面。Day 9 鎖的是 Today/Strategy/Result,多出來的那一頁我沒做成第四個主頁。

同一則對話再叫它把這個專案抽成 DESIGN.md。色票、字體、三頁名稱都對,第四個畫面也乖乖寫成備註。

抽出來的區塊跟 Day 9 對不上,不能照著寫程式:
food_source、記一筆餐。我改了 DESIGN.md 的第 2、3 節再讓它寫網頁。色票留著。按鈕文案和間距後來都在 Antigravity 裡改,沒有回 Stitch 重畫。
這步其實做在接 MCP 之前。資料夾先定好,後面的網頁才寫得進同一包。
我沒有下「幫我做一個完整 AI App」,也沒有用 Quick Start。Quick Start 沒有固定資料夾,文章會對不到檔案。
外掛只留兩個:Modern Web Guidance、Firebase。Android 和 Flutter 是上架那條路,今天用不到。

截圖當下框還沒勾,後來只開了這兩個。
接著建專案,按的是 Create a Project,不是 Quick Start。

資料夾只給今天這包:
material/code/day10
沒有選整個 IT_2026,也沒有選 day8。昨天的上傳還能跑,今天另開資料夾才不會改壞。Firebase 仍是同一個專案,.env 從 Day 8 複製過來。

我要它守的只有這幾條:登入後的 uid 來自 Auth;daily 與 pantry_items 寫在這個 uid 底下,庫存欄位是 qty;Result 用本地 mock,不接 Gemini;外食和「採用」都不能扣 qty。Rules 沒有關掉。
我以為 Stitch MCP 一接上,昨天那三支手機畫面會直接變成 CSS。登入成功、欄位也在,打開 Today 卻是一張工程師表單:下拉選單寫著 home,餐點欄位用英文 placeholder,底下是一顆很寬的橘色按鈕。

資料契約沒壞。丑的原因比較單純:DESIGN.md 只交了色票和「這頁要有哪些欄位」,我沒叫它去讀 Stitch 畫面上的卡片跟文案。模型就用那包色票,認真做了一張能用的表單。
所以不是重做 Firebase,是把同一頁的外觀打回去:
畫面不像 Stitch。請用 Stitch MCP 讀取專案「DishFlow 行動網頁」裡 Today、Strategy、Result 三個畫面的 HTML 和截圖,把現有 index.html 和 style.css 改到接近那些畫面。
不要重寫 Firebase、不要重做登入、不要改 .env、不要改 Rules、不要底部 Tab。
欄位仍以 DESIGN.md 為準:預算、時間、food_source 用中文選項不要只顯示 home、記一筆餐、pantry 的 qty、Strategy 可略過、Result 是 2~3 張示意卡。
Stitch 上若有人數、營養環、卡路里,不要跟著做回來。
改完用瀏覽器打開 localhost:3000 對一下三頁。
第二版 Today 就比較像會拿給人看的頁:區塊有圖示、來源寫「家裡煮 (Home)」、按鈕寫「下一步:略過 Strategy」。登入和 Firestore 那層沒有拆掉重來。

它還不是 Day 9 那張一比一的畫面。MCP 不會自動把設計稿搬完。我得講「照這三個畫面改」,不然只會得到一套穿著 Stitch 色票的表單。
Today 選了外食。紅字也寫了「只記錄,不改家中庫存」。冰箱裡只有剛新增的豆腐,Firestore 對得上:qty 是 1。


按下去之後,Result 還是兩張家裡菜,而且食材是編的:豬絞肉、番茄罐頭、洋蔥、蝦米。理由還說「消耗快過期的番茄」。冰箱裡沒有番茄。外食這條路不該出現「採用」。

「示意資料」四個字沒有救它。示意可以假,但不能在人已經說不煮的時候,端出一道要用冰箱裡沒有的肉的菜。外食、超商、超市只記 today_meals;只有家裡煮才看 pantry、才有示意卡。
food_source 不是 home 時,不要顯示推薦卡。
外食、超商、超市:儲存 Today 後略過 Strategy,Result 只顯示一張狀態卡:「這餐已記錄,不推薦家裡的菜,冰箱不會少。」不要採用按鈕,不要寫 recommendation_adopted,不要改 pantry qty。
只有 home 才顯示 Result 示意卡。食材只能來自 pantry_items 裡真實存在的項目(現在是豆腐),不要編豬絞肉、番茄罐頭、蝦米。保留「示意資料」。採用仍只寫 recommendation_adopted,不准扣 qty。
不要改登入、Rules、.env。
打回去之後,外食的 Result 不再有菜卡,也沒有「採用」。只留一句:這餐已記錄,不推薦家裡的菜,冰箱不會少。

家裡煮才進示意卡。這次兩張都只用冰箱裡的豆腐:紅燒豆腐、一鍋到底蔥燒豆腐。沒有接 Gemini,卡上仍標「示意資料」。

按「採用」之後,畫面寫「已記錄我想做,庫存尚未扣減」,按鈕改成已採用。

Firestore 對得上。豆腐那筆 qty 還是 1。daily/2026-09-25 多了 recommendation_adopted: true 和 adopted_recipe_id,today_meals 裡是鴨腿便當、food_source 是 home。沒有 cook_runs,也沒有把 qty 改掉。Console 上方那個「查詢效能」是它自己跳的,跟這次寫入無關。


今天的閉環到這裡。煮完才扣的 Outflow 還沒做,那是後面的事。
| 案例 | daily | pantry |
|---|---|---|
| 登入後新增豆腐 | 寫在這個 uid 底下 | qty: 1 |
| 外食 | Result 不出現推薦卡 | qty 仍是 1 |
| 家裡煮採用紅燒豆腐 | recommendation_adopted: true |
qty 仍是 1 |
| 煮完 Outflow | 今天沒做 | 這時才准扣 |
未登入沒有另測。Day 7 的 Rules 已經是只有本人能寫 users/{uid},而 2026-09-25 這筆豆腐和採用紀錄,都落在登入那個 uid 裡。外食與家裡煮採用對過了。
recommendation_adopted,豆腐 qty 仍是 1。今天沒接 Gemini,也還沒做煮完才扣的 Outflow。material/code/day10,外掛只留 Modern Web Guidance 和 Firebase。下一篇: 把 Strategy 的口號變成可編譯的 hard/soft/context ID,先存下來,還不生成菜。
金鑰沒有貼進對話。下面三段是依序貼的。
List my Stitch projects.
看得到 DishFlow 行動網頁 之後,在同一則對話貼:
Use the Stitch MCP to fetch the "DishFlow 行動網頁" project.
這是 DishFlow 的 Today、Strategy、Result 三頁,不是新的行銷網站。
列表裡若有第 4 個手機畫面,寫進 DESIGN.md 註明即可,不要做成第四個主頁。
抽出色彩、字體、每頁區塊,在這個資料夾寫 DESIGN.md。
不要新建 LaunchPad,不要改成桌面版,不要開始寫 Firebase。
DESIGN.md 確認是三頁晚餐流程之後,再貼:
現在依 DESIGN.md 和 Stitch 上的三頁,在這個資料夾做 DishFlow 行動版網頁,並接上既有 Firebase Web 專案。
手機外框只是設計預覽,產物是瀏覽器裡的直向網頁,不是原生 App,不要做上架流程。
用 Vite + Firebase Web SDK,不要改成 React 行銷站。
讀 .env,不要把 key 寫進程式常數,也不要在回覆裡印出 key。
資料模型叫 LifeFlow。沿用專案裡的 Firebase Web 設定(.env),不要把 key 寫進程式常數後貼到文章。
範圍:
1. Firebase Authentication。未登入不可讀寫 users/{uid}/...。
2. 讀寫 users/{uid}/daily/{yyyy-mm-dd}。
3. 列出、新增 users/{uid}/pantry_items/{itemId}。
4. Result 用本地 mock JSON,畫面上標示 mock,不接 Gemini。
契約:
- pantry 用 qty,不要 quantity / amount。
- today_meals 有 label、food_source、tags。不新增 confidence。
- food_source 不是 home 時,可以寫 today_meals,pantry 不得變。
- home 的 recommendation_adopted 不得扣 pantry。
- 只有 home + cook_completed 才能扣庫存。
- 若做 Outflow,用 transaction 一起寫 cook_runs、today_meals、pantry qty。
安全:
- uid 只取自 Auth。
- 不要 Admin SDK,不要關掉 Firestore Rules。
- 不要把 Gemini key 或 service account 放進前端。
請先列出要改的檔案與資料流,再逐步做。每一步說明我怎麼在瀏覽器與 Firestore 驗收。