昨天我們還在整理文件,聊「黃金守則」,把挑選、壓縮、多專家模式都搬出來,像個在工地外指指點點的監工。但話說回來,光有藍圖和安全帽,工地還是一片空地。
今天,終於動工。
目標很簡單卻也很關鍵:把系統最基礎的 CRUD 先打通。因為任何再宏偉的架構,最後都要回歸到「能不能新增一筆資料,能不能查得到它,能不能修改,能不能刪掉」。
這就像蓋大樓,先把水電管線接起來,不然什麼豪華裝潢都是空談。
先從最底層的 Postgres schema 開始:
companies
:公司基本資料users
:使用者,掛在公司底下projects
:專案,連到公司與使用者bots
:Teams Bot 資訊bot_installations
:Bot 的安裝紀錄destinations
:通知的發送目標notifications
:通知紀錄billing_plans
:計費方案usage_records
:使用紀錄audit_logs
:稽核紀錄system_logs
:系統層級 logsystem_settings
:系統設定feature_flags
:功能開關整個 schema 就像大樓的基樁,每個表格是鋼筋水泥,FK 則是鋼梁的連結。
在這一步,我們還做了一個 init.sql,放了種子資料:
這樣之後測試時不用每次都從空白開始。算是工地裡的「臨時水電」。
Repository 負責對應每個資料表的操作,單純負責收貨、出貨,完全不干涉上層邏輯。
今天完成了:
CompanyRepository
UserRepository
ProjectRepository
BotRepository
BotInstallationRepository
DestinationRepository
NotificationRepository
每個 Repository 的介面都包含基本 CRUD,外加一些查詢方法。比如 FindByCompanyID
、ListByProject
這類。
這層做完,就等於工地有了倉庫:磚瓦可以收進去,水泥可以領出來。
Service 負責業務邏輯,把 Repository 的操作串起來。今天最大的亮點是 NotificationService。
但這裡馬上踩到一個坑:
CreateNotification
時,要同時新增通知紀錄,並且為每個目的地插入子紀錄。這就像大樓蓋到 20 樓突然停電,結果 18 樓有牆、19 樓沒牆、20 樓只有鋼筋。住戶會崩潰,DBA 也會崩潰。
所以這裡被我列入 TODO:下一步一定要補上 transaction。
接下來是 Gin Handler 與 API Route:
POST /companies
POST /users
POST /projects
POST /bots
POST /bot-installations
POST /destinations
POST /notifications
這就是 API 的最小七龍珠:收集齊了,就能召喚第一個 smoke test。
Handler 做的事不多:接收 request、呼叫對應 Service、回傳 JSON。乾淨俐落,不摻雜太多邏輯。
最後是 HTTP server:
internal/api/server.go
註冊所有 middleware:CORS、RequestLogger。cmd/server/main.go
初始化 DB 連線,把 Repository、Service、Handler 全部串起來。這一刻,API 服務算是「電燈通了」。
雖然屋子裡還沒裝家具,但至少一開燈開關,會亮。
寫完 API,當然不能光看 log 自嗨,要做 smoke test。
於是寫了一個 scripts/curl_smoke.sh
,流程如下:
第一次跑,卡在 ID 格式。因為 JSON key 大寫小寫不一致,結果整個流程爆掉。
修正後,用 here-doc 傳 JSON,並用 jq
抓 ID,成功跑通。
再跑一次,結果依舊正確,代表 idempotency 還算穩定。
這感覺就像工地第一次通水:水龍頭一打開,水真的流出來,而且沒爆管。
雖然 CRUD 打通,但整個流程還有不少缺陷:
JSON Tag 缺失
PascalCase
,API 文件是 snake_case
。json
tag,或定義 DTO。Transaction 缺失
測試不足
go test ./...
雖然能跑,但沒有實際測試檔。今天的進展很關鍵,因為這是專案第一次從「文件」跨到「程式」。
總結一下:
雖然還是個半成品,但至少今天可以很驕傲地說:
👉 工地開始冒煙,API 真的跑起來了。
接下來的任務:
✍️ Day11 收工感言:
今天是 milestone:API 工地正式開張,第一次跑通一條龍 CRUD。雖然有不少缺陷,但這種「看到結果真的跑起來」的成就感,遠比文件更爽。