LOOP VILLAGE / ENGINEERING FIELD NOTES
Loop Village 系統架構導覽
一個 tick、一趟交付、一次政策表決:畫面上的變化有後端依據。這裡呈現目前 0.3.1 的真實鏈路,不把規劃中的能力當成已完成的系統。
一筆交易,兩條讀取與發布路徑
瀏覽器命令
Cloudflare → Kong
VillageController
SimulationService
DB 交易
DB 交易
世界狀態、此次領域事件與對應 Outbox row 在同一個 MariaDB transaction 內寫入。公開入口由 Kong 限定 Village API;2026-09-03 實測主站流量未經 gate-proxy,不能把它當作公開安全邊界。
畫面分支 · DB → Snapshot → 地圖
buildSnapshot() 彙整居民、地點、資源、最近 30 筆事件與治理狀態。瀏覽器每 3 秒讀取 /api/village/snapshot,也在命令成功後使用回傳快照。
3D 地圖與說明卡投影後端座標與決策理由;不是 Kafka consumer,也不是 WebSocket 推播。
發布分支 · Outbox → Publisher → Kafka
Publisher 預設每 2 秒讀取最多 100 筆 PENDING;Kafka 確認後標記 PUBLISHED。失敗會記錄次數與錯誤,保留 PENDING 供下次嘗試。
發布成功但尚未標記時若程序中斷,事件可能重送;這不是端到端 exactly-once 保證。地圖不等待 Kafka 才更新。
展開一條真實旅程
這些是靜態程式導覽,不會發送命令或改變公開共用世界。
01 · 推進一個 tick
- 前端送出
POST /api/village/control,action 為STEP。 VillageSimulationService.control()進入交易,依固定 tick、角色與時間表執行advanceOneTick()。- 居民的位置、活動、體力與決策理由持久化;觸發領域動作時,
recordEvent()同時保存 world event 與 Outbox。 - 成功回傳快照後,地圖呈現新狀態。固定初始世界與相同命令順序可重現規則結果;不是逐位元一致的時間戳重播。
02 · 資源從產地交付到倉庫
- 工作與交付時段由 tick 決定;農夫、林務員與搬運者使用各自的明確規則。
- 一次交付先扣來源,再加目的地;庫存不足就只搬實際可用數量。交付不會憑空生產資源。
RESOURCE_DELIVERED保存來源、目的與數量,事件 ID 由 tick、居民與動作識別組成,同 ID 寫入 Outbox。- 整合測試逐角色比較交付前後數量,確認來源減量=目的增量。這是資源守恆,不是已實作的複式帳本。
03 · 政策表決,然後承擔後果
POST /api/village/governance/proposals/{id}/convene讓八位規則型居民依角色產生選票及理由;非 READY 的提案拒絕重複召開。- 通過的政策排到下一個 24-tick 邊界生效;被否決的政策不改變資源產出。
- 生效滿一天後,各居民保存一次回饋與 wellbeing 變化;既有 feedback 作為一次性評估的防重依據。
- 投票、生效與評估各有持久化事件及 Outbox 證據。公開世界的歷史 wellbeing 殘留仍待擁有者決定補償方式,這次沒有重寫歷史。
能力邊界,也是工程事實
居民是確定性規則角色,不是有意識或 LLM 驅動的 AI。村莊是公開共用世界,控制與 RESET 仍會影響其他訪客;請勿輸入真實個資。
目前以單一程序的 synchronized 協調呼叫,並非分散式鎖或 Village 樂觀鎖保證。事件不是完整 event-sourcing 重建日誌;Outbox 尚未建立完整下游 consumer 投影。這些限制不能用技術名詞掩蓋。
公開來源與模擬邊界 →