#P-INFRA-1 · 報告頁雙向資料橋 · SHIPPED 🚀
Boss-AI Sync — 報告頁從硬編碼 → DB 雙向 + realtime
老闆 2026-05-16 問:「為什麼網頁是硬編碼?我希望裡面的東西都存到資料庫,AI 可以直接抓答案,不用等 Vercel deploy」
答案:YES,這份計劃做完,老闆按 radio → AI 立刻看到;AI 加新問題 → 老闆開頁面立刻有,不用等 deploy。
1. 為什麼做這個
老闆原話:
「現在的網頁是不是硬編碼?你沒有辦法直接讀取,一定要我匯出 JSON?如果我希望裡面的東西都存到資料庫你可以直接抓資料庫裡的答案是不是溝通起來更即時,也不用時常要等 vercel deploy?」
痛點:報告頁 / 計劃頁是純 HTML,所有 user state(許願、Q&A、checkbox、決策)都在瀏覽器 localStorage。AI 看不到 localStorage → 老闆要不斷 export JSON paste 給 AI。換瀏覽器資料消失。換手機資料沒帶過去。
解法:建「Boss-AI Sync」資料庫橋 + realtime push。
2. 架構
┌─────────────────────┐ user 改答案 ┌─────────────┐
│ report.html │ ──────────────────────→ │ Supabase │
│ plans/*.html │ │ boss_* 表 │
│ (Cloudflare Pages) │ ←── AI 提案 / 答覆 ──── │ │
└─────────────────────┘ └──────┬──────┘
↑ │
│ realtime push │
└────────────────────────────────────────────────┘
│
AI (Claude) 走 supabase MCP 直接 SQL 讀寫 ───────┘
3. 5 張 boss_* 表
| 表 | 取代 | 欄位 |
boss_wishes | localStorage report:wishlist | serial_id / text / status / added_at / last_exported_at / ai_reviewed_at / ai_note |
boss_qa_answers | report:qa-* | qa_id (H6/W2/W4/B2) / question_id / choice / note |
boss_dogfood_state | report:dogfood-* | card_id / step_index / checked / passed_at |
boss_plan_decisions | plan:*:decision | plan_id / choice / note / decided_at |
boss_track_assignments | report:item-track:* | item_id / track_id |
RLS:所有表 ENABLE ROW LEVEL SECURITY,policy user_profile_id IN (SELECT id FROM user_profiles WHERE auth_user_id = auth.uid())。
User 只能看 / 改自己的 row。Service role(AI)可繞過 RLS 直接 SQL。
4. 實作 Phase(全部已 ship)
1
DB schema + RLS + Realtime
DONE
migration 20260516003_boss_ai_sync.sql applied to dev。
5 張表 + RLS self-policy + auto-update trigger + 5 張表都加進 supabase_realtime publication。
2
boss-state.js helper(Supabase JS SDK + cache + realtime + auto-migration)
DONE
docs-site/public/boss-state.js 提供全域
window.bossState API:
bossState.wishes.{list,add,updateStatus,remove,markExported}
bossState.qa.{get,set}(qaId, qId, patch)
bossState.dogfood.{get,setStep,setPassed}
bossState.planDecisions.{get,set}
bossState.tracks.{get,set}
bossState.onChange(cb) 訂閱 realtime postgres_changes
bossState.migrateLocalStorageToDB() 首次登入自動把舊 localStorage 資料 upload
未登入時所有 API 自動 fallback 走 localStorage(graceful degradation)。
3
report.html 全部遷移 + login banner
DONE
頂端固定 banner 顯示登入狀態:未登入 → email input + 「送出登入連結」;
已登入 → 綠底「☁️ 已連線」+ 登出按鈕。
所有 wish / QA / dogfood / track 函式改 async + 走 bossState。
realtime onChange 監聽:另一裝置改了 → 本頁立刻 re-render。
4
plans/*.html 決策按鈕也遷移
DONE
plans/ai-native-pos-phase1.html 的 bossDecision() 改寫,
用 bossState.planDecisions.set(planId, choice) 寫 DB,get() 讀回。
5
Auto-migration on first login
DONE
Auto-migrate 進入 bossState.init() 流程:
首次登入時掃 localStorage 所有 report:* / plan:* key →
upload 到對應 boss_* 表 → 設 flag boss_state:migrated_to_db 防重跑。
6
Realtime push(postgres_changes channel)
DONE
supa.channel('boss-state-{user_profile_id}').on('postgres_changes', ...)
訂閱自家 user 的 5 張表變動 → callback 觸發 UI re-render。
效果:兩台手機同時開頁面,A 改答案 → B 不用 reload 就看到更新。
對 AI 的好處:AI commit 新 plan 內容 → 老闆無需 reload (push 推給 client);
老闆按 radio → AI 下次 SQL 讀 boss_qa_answers 立刻看到。
5. AI 如何讀 boss_state(給 AI 看)
-- AI 想看老闆對 W4 4 題答了什麼
SELECT question_id, choice, note, updated_at
FROM boss_qa_answers
WHERE user_profile_id = (SELECT id FROM user_profiles WHERE email = 'dadadadato@gmail.com')
AND qa_id = 'W4'
ORDER BY question_id;
-- 看老闆最新許願 (last_exported_at IS NULL = 還沒匯出過的新願望)
SELECT serial_id, text, status, added_at
FROM boss_wishes
WHERE user_profile_id = (SELECT id FROM user_profiles WHERE email = 'dadadadato@gmail.com')
AND last_exported_at IS NULL
ORDER BY serial_id DESC;
-- 看老闆對所有 dogfood card 通過進度
SELECT card_id, step_index, checked, passed_at
FROM boss_dogfood_state
WHERE user_profile_id = (...);
-- 看老闆對所有 plan 的決策
SELECT plan_id, choice, note, decided_at FROM boss_plan_decisions WHERE user_profile_id = (...);
6. 未來可以做的
- AI push 新願望 / 新 Q&A 到老闆的 boss_state — 老闆開頁面就有 realtime 通知
- 多用戶協作:開放 share token,老闆可以邀請夥伴看自己的報告頁進度
- Mobile push:boss_state 變更時推 native push 給 user(提醒老闆「AI 寫了新提案」)
- 對話化:把 boss_state 餵給 LLM context,做即時對話入口
✅ 本計劃全部 phase 完成。
打開 https://docs.chefsmate.app/report.html → 頂端 banner 輸入 email 收登入連結 → 點連結回來 → 從此資料寫 DB,AI 隨時 SQL 直接讀。