The engineering companion · Design v1.0 把小熊的想法, 變成清晰的工程藍圖。 Technical design / 技術設計工作台
從開發前置條件到資料模型、畫面流程與服務合約,讓產品、工程及營運使用同一份設計。
填寫開發前置設定 ↓ DESIGN ONLY iOS + Android 先準備,再開發。 本頁是設計文件與設定筆記。App 畫面按鈕只示範流程。QBear schema 及設定表已建立;開發前置設定登入後儲存到 Supabase。
QBear 資料庫 schema 名稱
7 畫面線框
3,600 首次啟動贈送秒數
01 系統架構 02 前置設定 03 資料庫 04 畫面及按鈕 05 API 與交易 06 工程交付
01 / SYSTEM ARCHITECTURE 一隻公仔,一個獨立的時間錢包。 延續項目手冊架構 :Flutter 手機 App、Supabase 身份與資料庫、受控 Voice Gateway。公仔是角色與 QR 載體;手機收音及播放是 MVP 假設,硬件語音另行設計。
Flutter App iOS / Android 家長登入 · QR · 語音介面 · IAP →
業務 API + Voice Gateway 身份與所有權 · 限速 · 冪等 媒體控制 · 安全攔截 · 可信計時 →
Supabase / Provider Auth + PostgreSQL「QBear」 核准語音供應商 · 商店驗證 App 的責任 畫面、登入狀態、相機/咪高峰權限、商店購買及顯示伺服器餘額。UI 不自行加減秒數,也不直接更新 ownership 或 ledger。
後端的責任 從已驗證 JWT 取家長身份;每次檢查公仔所有權、同意及限時。交易統一鎖序;Gateway 只可在有效租約內傳送及生成音訊。
設計基線:廣東話優先、每隻公仔獨立額度、家長付款。年齡範圍、推出地區、供應商資格與兒童資料處理條件需先確認。Supabase 資料推送與供應商的即時語音服務是不同服務。
02 / BEFORE YOU BUILD 開發前置條件與設定筆記 填入非機密設定與負責人,登入授權帳戶後儲存到 Supabase。每個環境獨立版本,可從其他瀏覽器登入載入。
設定儲存在 QBear.project_configuration;不是 App 已部署或資格已驗證。不要輸入 API secret、service_role key、資料庫密碼或付款憑據;只記錄 secret manager 項目名稱。勾選為使用者自行確認,並非本頁已驗證連線、DNS 或資格。所有欄位、確認清單及決策筆記一併保存;匯出 JSON 可作備份。
Supabase 設定編輯帳戶 使用此專案的 Supabase Auth 電郵/密碼登入。只有 QBear.configuration_editors 內的帳戶可讀寫;此登入只用於設計設定。
登出設定編輯 尚未登入。密碼不會儲存在配置內。
03 / DATABASE BLUEPRINT 專案資料庫 namespace:QBear 在指定 Supabase 專案的 PostgreSQL 建立 schema,並非另建 database。保留精確名稱 QBear:所有 SQL 引用用 "QBear".table_name;未加引號會轉為小寫。
狀態:QBear schema 與設定資料表已建立。 已部署 configuration_editors 及 project_configuration,並初始化 planning、development、staging、production 四個環境。下方 App 業務表仍為後續設計,未建立。
Schema 建立紀錄(已執行,節錄)
BEGIN;
CREATE SCHEMA IF NOT EXISTS "QBear";
COMMENT ON SCHEMA "QBear" IS
'QBear project: parents, dolls, wallets and voice-session accounting';
REVOKE ALL ON SCHEMA "QBear" FROM PUBLIC, anon;
-- Configuration access is restricted by editor-membership RLS.
GRANT USAGE ON SCHEMA "QBear" TO authenticated, service_role;
COMMIT;
-- Verify after execution; expected result: QBear
SELECT nspname FROM pg_namespace WHERE nspname = 'QBear';複製 schema SQL
MVP 建議保持 QBear 不暴露於 Data API,App 經業務 API 存取。service_role 只放後端且須驗證所有權。未來直讀需要 exposed schema、逐表 SELECT grant 與 ownership RLS;App 不直接寫餘額。Supabase custom schemas 官方文件 。
已建立:BEFORE YOU BUILD 設定儲存 資料表 保存內容 存取 QBear.configuration_editorsuser_id → auth.users、created_at 管理員配置授權名單;登入者只讀自己的資格,不可自行授權。 QBear.project_configurationenvironment 主鍵、settings JSONB(全部 30 欄)、revision、updated_at、updated_by 僅指定編輯者可讀寫;server timestamp/revision;版本衝突拒絕覆蓋。
透過 public.qbear_load_configuration / qbear_save_configuration 讀寫,兩者均 SECURITY INVOKER,保留 RLS。QBear 無需加入 exposed schemas;匿名使用者不能呼叫或存取設定。Secrets 只記錄參照名稱。
App 業務資料表與約束(設計,未建立) QBear 資料表 欄位與關係 約束及存取
parents / consentsparents.id → auth.users.id;status;consents.parent_id、version、accepted_at、revoked_at 只設家長身份;版本化同意;停用/撤回立即阻止新 session。
dollsid UUID PK、serial、owner_id → parents、character_id、state serial UNIQUE;只讀自己公仔;綁定經 redeem。
walletsdoll_id → dolls(PK)、balance_seconds bigint、reserved_seconds bigint、revision CHECK balance ≥ reserved ≥ 0;available = balance − reserved。
sessionsid、doll_id → dolls、parent_id、state、fence_epoch、started_at、closed_at partial UNIQUE(doll_id) WHERE state IN ('connecting','active','paused');timestamptz 時間戳。
leasesid、session_id → sessions、granted_seconds、settled_seconds、expires_at、state 每 session 一個 open lease;0 ≤ settled ≤ granted ≤ 15;到期硬停止。
ledgerid、doll_id → dolls、session_id、delta_seconds、kind、dedupe_key、created_at dedupe_key UNIQUE;追加式,不覆寫;補償用新分錄。
purchasesid、parent_id、doll_id、store、environment、transaction_key、product_id、state UNIQUE(store, environment, transaction_key);驗證完成才加額。
qr_codesid、doll_id、token_hash、pepper_version、redeemed_at、revoked_at token_hash UNIQUE;HMAC 雜湊;App 不讀;原碼不進 log。
outbox / auditid、event_key、actor、resource、狀態、重試/審計時間 event_key UNIQUE;outbox 隨交易提交;不存原始語音或 QR secret。
索引與不變量 owner_id、parent_id 等外鍵查詢欄位建索引;ledger(doll_id, created_at)、leases(state, expires_at)。UUID 作 ID、bigint 作整數秒。餘額以帳本核對,不得負可用額度。
隔離與保留 每表啟用 RLS 作額外防線;使用者可讀資料與秘密/付款原文分開。如增加直讀,以 auth.uid() 與 owner 限制行;UPDATE 同時有 USING + WITH CHECK。保留期限由前置設定決策落實。
依據:Supabase RLS 官方文件 。完整 migration、policy 及刪除方案留待後續開發,需將原手冊 SQL 基線 的物件與關聯一致遷移到 "QBear",不能混用 public 版本。
04 / SCREENS & INTERACTIONS 畫面線框與使用流程 點選畫面或線框內的按鈕查看流向。示範資料固定,沒有登入、相機、語音或付款功能。
首頁另有「增值」及「家長設定」分支。額度不足 → 家長增值 → 商店驗證 → 返回首頁。撤回同意 → 停止語音 → 重新同意。
01 登入/同意 02 QR 啟動 03 首頁 04 語音 05 結算 06 增值 07 家長設定
ʕ •ᴥ•ʔ
你好,我是 QBear。 由家長登入,陪好奇心一起長大。
家長電郵 · 模擬輸入欄
① 發送登入驗證碼 家長同意/私隱摘要 AI 身份 · 咪高峰用途 · 可隨時停止
② 同意並繼續(示範) 01 / 身份與家長同意 家長是帳戶持有人;兒童無獨立登入。已有登入及有效同意可直接到首頁。
① 驗證碼: 真正 App 驗證電郵、限速及 resend cooldown;OTP 驗證成功才完成登入。② 繼續: 需完成登入及明確同意,再送 consent version 及 server timestamp;進掃碼或首頁。UI states / 例外 格式錯誤、OTP 過期、網絡失敗及未同意:停留原畫面並提供修正/重試,不建立 session。
Auth → POST /v1/consents → GET /v1/dolls
啟動你的 QBear 掃描包裝內防拆標籤的秘密碼。
相機預覽區 QR 對準框(非真實相機)
① 開啟相機掃碼 ② 手動輸入啟動碼 · 模擬欄位
首次啟動:贈送 3,600 秒 只可綁定一次
③ 確認綁定(成功示範) ④ 啟動遇到問題 02 / QR 綁定與啟動 入口 URL 的 GET 不直接兌換;公仔外部入口與防拆秘密碼分開。碼至少 128 bit CSPRNG;只存帶 pepper 的 HMAC 雜湊。
① 掃碼: 申請相機權限,拒絕轉手動;原 token 不進 log。② 輸入: 供相機失敗使用;確認前只做格式檢查。③ 綁定: 顯示角色與贈送額度;後端一次交易綁定、加額、寫 ledger 與標記兌換,成功到首頁。④ 支援: 無效/已領只顯示泛化錯誤,不洩漏其他家長身份。UI states / 例外 無效碼、已兌換、429、回應遺失:同冪等鍵重試;同家長同碼返回原結果,不重複贈送。
POST /v1/activations/redeem
我的 QBear ① 小熊 Sunny ▾ · 切換公仔 ʕ •ᴥ•ʔ
可用陪伴時間60:00 3,600 秒 · 此公仔專用(示例)
② 開始傾偈 ③ 家長增值 ④ 加入另一隻 QBear ⑤ 家長設定 小熊 · 時間錢包 · 家長
03 / 公仔首頁與餘額 每隻公仔獨立錢包;available = balance − reserved。
① 切換: 只列本家長公仔;重新讀角色與 wallet revision。② 開始: 檢查同意、網絡、咪高峰及秒數;建立 connecting,等 Gateway ready。③ 增值: 通過家長確認,指定當前公仔再購買。④ 加入: 回掃碼,不合併額度。⑤ 設定: 家長區管理限時、同意及刪除。UI states / 例外 無公仔 → 啟動提示;0 秒 → 禁止開始及提供家長增值;已有 session → 返回現有對話;載入失敗 → 重試,不把快取餘額作權威值。
GET /v1/dolls · /v1/dolls/{id}/wallet
與 Sunny 傾偈 AI 陪伴 · 時間為固定示例
剩餘時間58:42 狀態:聆聽中(示範)
◖ ▂ ▅ ▇ ▅ ▂ ◗
你可以問:「今天有甚麼小故事?」
① 暫停(示範) ② 結束對話 ③ 回報不合適內容 04 / 語音與可信計時 connecting → ready/listening ↔ speaking → paused → closing → closed。咪高峰有明確指示;背景立即停止媒體。
① 暫停/繼續: 停止音訊與計時,結算並釋放;恢復重新檢查同意、額度與租約。② 結束: 防重複點擊,關閉、結算並取得權威餘額後到摘要。③ 回報: 中斷輸出,提交 session/event ID 與類別,不自動存原始語音。UI states / 例外 權限拒絕、逾時、供應商故障、0 秒、安全 gate 或 lease 到期:停止聲音並說明原因。20 秒無互動自動暫停;App heartbeat 不延長租約。
POST /v1/sessions · /pause · /resume · /close
下次再傾! ʕ •ᴥ•ʔ
本次使用:1 分 18 秒 剩餘:58 分 42 秒 結算:完成(固定示例)
① 返回小熊首頁 ② 家長增值 ③ 查看時間紀錄 05 / 結算與時間紀錄 使用量、餘額與 revision 由 close API 回傳,不能以畫面倒數推算。
① 返回: 首頁重讀權威 wallet。② 增值: 家長確認後購買;不向兒童催購。③ 紀錄: 家長看日期、秒數、贈送、購買與補償,不顯示原始對話。UI states / 例外 close 回應遺失 → 結算中;同冪等鍵重試或讀 session。不得本地重扣,pending 不顯示完成。
POST /v1/sessions/{id}/close · GET /v1/dolls/{id}/ledger
家長增值時間 指定公仔:Sunny 先完成家長身份確認
① 商品:60 分鐘 · 示例 價格:由 App Store/Google Play 提供
② 確認並開啟商店購買 ③ 檢查未完成交易 ④ 返回首頁 驗證成功才加額;pending 不加秒。
06 / IAP 增值與對帳 purchase intent 綁定家長、公仔與商品,再開商店原生 sheet;App 回傳成功不代表後端已驗證。
① 商品: 秒數由後端映射;價格由商店本地化,不寫死貨幣。② 確認: intent → 原生商店 → server verify → 唯一 credit ledger → wallet。③ 查交易: 重送未完成憑據並對帳;秒數包為消耗型,不承諾恢復已消耗時間。④ 返回: 保留 pending,等待驗證/通知。UI states / 例外 取消、pending、驗證失敗、重複通知及退款。退款追加補償分錄;不足額時停用待營運處理,不造成負可用秒數。
POST /v1/purchase-intents · /v1/purchases/verify
家長守護 ① 每日上限 · 20 分鐘(示例)
內容語言 · 廣東話 年齡分組 · 待確認
② 儲存家長設定 ③ 查看/撤回同意 ④ 支援與私隱 ⑤ 申請刪除帳戶 ⑥ 返回首頁 07 / 家長控制與資料權利 敏感操作重新驗證家長;上限由後端按家庭時區與帳本計算,不能以手機時鐘繞過。
①/② 設定: 驗證範圍及 version;伺服器以額度與家長上限較小者限制。③ 同意: 展示版本;撤回即停止現有媒體、釋放並禁止新 session。④ 支援: 附 request ID,不附秘密或兒童內容。⑤ 刪除: 重新登入、說明保留義務、二次確認;202 排程並即時停用,合法保留去識別帳本及 audit。⑥ 返回: 刷新設定及 wallet。UI states / 例外 更新衝突 → 重讀;刪除 pending → 顯示狀態。不能只刪 auth user 留有效 session;後端即時查停用狀態。
PATCH /v1/parent-settings · POST /v1/consents · DELETE /v1/account
目前:01 登入/同意。點選可看流程,不執行 App 功能。
05 / SERVICE CONTRACTS 如何實作:API、交易與失敗處理 API 前綴為設定的 API URL + /v1。HTTPS、驗證家長 JWT、從 token 取身份;body 的 parent_id 不作授權。寫操作有 request_id、Idempotency-Key 與 body hash;同鍵不同 body 回 409。
方法與路徑 輸入 → 輸出 規則
GET /dolls GET /dolls/{id}/wallet GET /dolls/{id}/ledgerJWT/公仔 → 公仔、balance/reserved/available/revision、分頁帳本 每次檢查 ownership;跨家庭不可見。
POST /activations/redeemqr_token、consent_version → doll_id、granted_seconds、revision 一次綁定並送 3,600 秒。
POST /sessionsdoll_id、device_nonce → session_id、Gateway token、protocol、expires_at connecting 不扣額;30 秒未 ready 清理;每公仔一個 session。
POST /sessions/{id}/pause POST /sessions/{id}/resume POST /sessions/{id}/close冪等鍵 → state、settled_seconds、wallet revision pause/close 停媒體、結算、釋放;resume 重查限制並發新 token/lease。
POST /purchase-intents POST /purchases/verifydoll_id、store、product_id → intent;intent_id+receipt → pending/credited 交易身份去重;正式/sandbox 分開。
GET /parent-settings PATCH /parent-settings上限、家庭時區、version → 新設定/version 家長驗證;版本衝突 409;後端 enforcement。
POST /consents POST /safety-reports DELETE /account同意/撤回、event ID/類別、重新驗證 → 狀態或 202 job 停用優先於媒體;安全回報最小資料。
POST /internal/leases/* POST /webhooks/apple POST /webhooks/google可信累積用量/平台通知 → 結算/接受事件 Gateway mTLS/服務簽章;webhook 驗簽去重;不給 App。
核心原子交易 1. 啟動 驗同意 → HMAC → 鎖 QR → wallet → 綁 owner → +3,600 → 唯一 ledger → redeemed → outbox → commit。鎖序由 QR(如有)→ wallet → session → lease,所有交易一致。同家長同碼返回原結果。
2. 扣秒 Gateway ready 預留最多 15 秒,每 5 秒提交可信累積毫秒;檢查 fence、期限及 event 去重。消耗同時減 balance 與 reserved,釋放只減 reserved;每 session 一個 open lease。
3. 付款 intent → 商店 → server verify → 鎖 wallet → 去重 purchase → 加額 → ledger → outbox → commit。取消、pending、驗證失敗不加額。
計時與故障 累積毫秒中途 floor、最終一次 ceil;跨租約留餘數。到期/DB 故障/gate 不可用即停媒體。只扣持久化可信證據,未知尾段由營運承擔。
錯誤語意 401 登入;403 / 404 不可存取;402 秒數不足;409 綁定、version 或冪等衝突;422 修正輸入;429 按 retry-after;503 暫停後重試。逾時不代表交易失敗,用相同冪等鍵或查狀態;只對可重試錯誤採有抖動的退避。
Flutter 實作邊界(後續開發) Feature 分為 auth / activation / dolls / voice / wallet / purchases / parent,各有 screen、狀態控制器、repository 與 typed DTO。共用 HTTP client 處理 JWT refresh、request ID 與錯誤映射;repository 為資料入口。voice 狀態機驅動 UI,與音訊 transport 分離;開發時確認並鎖定 Flutter/SDK 版本。
06 / IMPLEMENTATION HANDOFF 後續開發順序與驗收 目前已交付設計 HTML、QBear schema 及雲端設定儲存;Flutter App、語音、付款與業務資料表尚未開發。
01 · 資格與準備 市場、供應商、兒童資料、商店 QR 審批及前置設定。證據:資格確認及決策紀錄。
02 · 資料與交易 開發環境建立 QBear、表、權限及原子交易。證據:並發、去重及家庭隔離測試。
03 · App 閉環 依線框完成 Flutter、Gateway、安全及 IAP sandbox。證據:啟動→語音→結算→付款。
04 · 試點與營運 還原、告警、客服、刪除與安全評審後家庭試點。證據:驗收與回滾演練。
驗收必須涵蓋 同 QR 兩人並發,只一人成功;首次贈送一次。 跨家庭讀寫拒絕;App 無法改 balance、owner、QR 或 lease。 0 秒、最後不足 15 秒、多裝置及 Gateway 崩潰不造成負額度。 權限拒絕、背景、斷網及 gate 故障有清楚 UI 與立即停止。 付款 pending、取消、重複通知、退款及遺失回應不重複加秒。 撤回/刪除即停用;保留與備份刪除期限可核實。 廣東話、打斷及兒童風險實測;log 無原碼與兒童語音。 wallet 對帳、備份還原及供應商停用演練有紀錄。 返回手冊的工程交付與責任分工 →
QBear · Technical design v1.0 · 2026 年 10 月 9 日 · 設計稿/QBear 雲端設定已啟用