iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0

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 有沒有真的寫進去。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052FeYrUaJmPv.jpg

1. 問題:畫面順,不代表庫存還在

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052XE1ouuvQnS.jpg

外食記一筆        → 寫 today_meals,pantry 不動
採用自煮推薦      → 只記「我想做」,pantry 不動
煮完(Outflow)   → 才寫 cook_runs、更新 qty、把成品寫進 today_meals

少了這道閘門,隔天的推薦會從一份已經說謊的冰箱出發。


2. 設計:先閉環,推薦先說真話

閉環就是按下去的事要在 Firestore 對得上,而且冰箱沒有自己變少。登入寫得進、讀得回;外食只記一筆、不扣豆腐;家裡煮按了「採用」也只是記下「我想做」。這圈合上,才叫閉環。推薦先說真話,是示意卡不能宣稱冰箱裡沒有的肉,外食也不該再端出家裡菜。真的會推薦是後面的事,今天先不要。

主路徑只有這四段,而且是行動版網頁,不是再做一個上架 App:

Firebase Auth
  → users/{uid}/daily/{yyyy-mm-dd}
  → users/{uid}/pantry_items/{itemId}
  → 本地 mock 推薦卡(標示 mock)
  • uid 只來自登入,不接受網址或表單自稱。Day 7 已經擋過別人的 uid。今天這筆豆腐,就是寫進登入這個帳號的文件。
  • pantry 欄位是 qty。中途曾經冒出 quantity,我沒讓它留在文件裡。
  • Result 可以是寫死的 JSON,但畫面上要看得出這是示意,不是 Gemini 現算的。
  • 「採用」不能呼叫扣庫存。只有 food_source === "home" 而且事件是 cook_completed 才扣。
function shouldApplyPantryDelta(source, event) {
  return source === "home" && event === "cook_completed";
}

自煮扣庫存若要做,三件事放同一個 transaction:cook_runs、pantry qty、today_meals。失敗就整筆回滾,不能只扣冰箱、戰報卻沒寫。


3. Stitch 畫的,Antigravity 來接線

兩天其實是同一件事的前後段。Stitch 不進 Runtime,它昨天把「累的人願意按的三頁」畫出來。Antigravity 今天負責把那三頁做成瀏覽器打得開的網頁,並接到 Day 6–8 那個 Firebase。結合的方式不是把 Stitch 再改成桌面網站,也不是在 Antigravity 裡從零重畫一張工程師表單。

https://ithelp.ithome.com.tw/upload/images/20260925/201210521dISqWtRZZ.jpg

手機外框留著沒關係。我要的一直是直向網頁:下班用手機瀏覽器打開,不上架。外框是預覽,不是叫我去做原生 App。

官方接法不是把截圖丟進對話,是 Stitch MCP:Antigravity 直接讀 Stitch 專案。Codelab 裡的 LaunchPad、React 行銷頁不要照做,我要拉的是已經畫好的三頁。

Stitch 右上角大頭貼 → Stitch 設定 → API 金鑰。一開始沒有可顯示的金鑰。黃條寫:濫用偵測關掉時,公開的 key 會被自動停用。所以這把鑰匙只留在自己電腦的 MCP 設定。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052aw3294BQRg.png

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052f6zSBqV2HR.png

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052YykOKbYeg5.jpg

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052cy0hl1legF.jpg

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052W8JyMxpAIz.jpg

抽出來的區塊跟 Day 9 對不上,不能照著寫程式:

  • Today 被寫成人數、下廚意願、冰箱 stepper。Day 9 的 Today 是預算、時間、food_source、記一筆餐。
  • Strategy 被寫成慢燉跟風味。真正要的是可略過的 chips,而且不能關掉過敏。
  • Result 出現營養標籤。卡路里環昨天就刪了。卡片只要時間、大概多少錢、用到哪些庫存、一句為什麼,並標「示意資料」。
  • 檔尾寫「無 Firebase」。那只是這一步先不要接;留下這句,下一步它會拒絕登入。

我改了 DESIGN.md 的第 2、3 節再讓它寫網頁。色票留著。按鈕文案和間距後來都在 Antigravity 裡改,沒有回 Stitch 重畫。


4. Antigravity 專案指到 day10

這步其實做在接 MCP 之前。資料夾先定好,後面的網頁才寫得進同一包。

我沒有下「幫我做一個完整 AI App」,也沒有用 Quick Start。Quick Start 沒有固定資料夾,文章會對不到檔案。

外掛只留兩個:Modern Web Guidance、Firebase。Android 和 Flutter 是上架那條路,今天用不到。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052RsJbRXqQ9e.png

截圖當下框還沒勾,後來只開了這兩個。

接著建專案,按的是 Create a Project,不是 Quick Start。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052fhUlZ6tpSJ.png

資料夾只給今天這包:

material/code/day10

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052UuBuc1vRzL.png

我要它守的只有這幾條:登入後的 uid 來自 Auth;daily 與 pantry_items 寫在這個 uid 底下,庫存欄位是 qty;Result 用本地 mock,不接 Gemini;外食和「採用」都不能扣 qty。Rules 沒有關掉。


5. 翻車:色票過來了,畫面沒有

我以為 Stitch MCP 一接上,昨天那三支手機畫面會直接變成 CSS。登入成功、欄位也在,打開 Today 卻是一張工程師表單:下拉選單寫著 home,餐點欄位用英文 placeholder,底下是一顆很寬的橘色按鈕。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052ao5Eirtasr.png

資料契約沒壞。丑的原因比較單純: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 那層沒有拆掉重來。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052QDYH8xukA5.png

它還不是 Day 9 那張一比一的畫面。MCP 不會自動把設計稿搬完。我得講「照這三個畫面改」,不然只會得到一套穿著 Stitch 色票的表單。


6. 翻車:人去外食,畫面還叫我燉肉丸

Today 選了外食。紅字也寫了「只記錄,不改家中庫存」。冰箱裡只有剛新增的豆腐,Firestore 對得上:qty 是 1。

https://ithelp.ithome.com.tw/upload/images/20260925/20121052hm62IQZLJ4.png

https://ithelp.ithome.com.tw/upload/images/20260925/20121052RuT7sLLZWB.png

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052SeEx2Fbg2j.png

「示意資料」四個字沒有救它。示意可以假,但不能在人已經說不煮的時候,端出一道要用冰箱裡沒有的肉的菜。外食、超商、超市只記 today_meals;只有家裡煮才看 pantry、才有示意卡。

food_source 不是 home 時,不要顯示推薦卡。
外食、超商、超市:儲存 Today 後略過 Strategy,Result 只顯示一張狀態卡:「這餐已記錄,不推薦家裡的菜,冰箱不會少。」不要採用按鈕,不要寫 recommendation_adopted,不要改 pantry qty。
只有 home 才顯示 Result 示意卡。食材只能來自 pantry_items 裡真實存在的項目(現在是豆腐),不要編豬絞肉、番茄罐頭、蝦米。保留「示意資料」。採用仍只寫 recommendation_adopted,不准扣 qty。
不要改登入、Rules、.env。

打回去之後,外食的 Result 不再有菜卡,也沒有「採用」。只留一句:這餐已記錄,不推薦家裡的菜,冰箱不會少。

https://ithelp.ithome.com.tw/upload/images/20260925/201210526xr9fmGWFx.png

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052cPWkbaMEvs.png

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052nRcBu6tMNr.png

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

https://ithelp.ithome.com.tw/upload/images/20260925/20121052WTL1mhJT2g.jpg

https://ithelp.ithome.com.tw/upload/images/20260925/20121052sLYttORmXC.jpg

今天的閉環到這裡。煮完才扣的 Outflow 還沒做,那是後面的事。


7. 怎麼驗(點畫面,也對 Firestore)

案例 daily pantry
登入後新增豆腐 寫在這個 uid 底下 qty: 1
外食 Result 不出現推薦卡 qty 仍是 1
家裡煮採用紅燒豆腐 recommendation_adopted: true qty 仍是 1
煮完 Outflow 今天沒做 這時才准扣

未登入沒有另測。Day 7 的 Rules 已經是只有本人能寫 users/{uid},而 2026-09-25 這筆豆腐和採用紀錄,都落在登入那個 uid 裡。外食與家裡煮採用對過了。


8. 今日結論

  1. MVP 的第一關不是會推薦,是狀態轉移沒說謊。
  2. Stitch MCP 會把色票帶過來;沒講「照這三個畫面改」,第一版就是一張表單。重下那段提示後,同一頁才比較像人看的畫面。金鑰只留本機。
  3. 外食只記錄、不推薦。家裡煮的示意卡只用豆腐;按採用寫下 recommendation_adopted,豆腐 qty 仍是 1。今天沒接 Gemini,也還沒做煮完才扣的 Outflow。
  4. 專案資料夾是 material/code/day10,外掛只留 Modern Web Guidance 和 Firebase。

下一篇: 把 Strategy 的口號變成可編譯的 hard/soft/context ID,先存下來,還不生成菜。


附錄:當天貼給 Antigravity 的原文

金鑰沒有貼進對話。下面三段是依序貼的。

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 驗收。

上一篇
[Day 9] 三頁夠不夠把晚餐決策壓進 60 秒?Google Stitch AI 幫你把想法轉成實際畫面
下一篇
[Day 11] 系統不會讀心:先把飲食條件存成它讀得懂的 ID
系列文
DishFlow AI Agent:用 Google AI 打造 Eat-Cost Balance 的下一餐決策系統 共 12 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言