Compare commits
11 Commits
d6aae828e9
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b93d5ca135 | |||
| beb52eba4c | |||
| df1b5bed9b | |||
| 1958c3f01a | |||
| 6dfa36c1cb | |||
| 2d571cfd52 | |||
| 34b4706d00 | |||
| 89b8e8f343 | |||
| 1c1fe6f651 | |||
| 4f2907eb93 | |||
| 7bd96ef092 |
@@ -28,3 +28,6 @@ yarn-error.log
|
|||||||
/frontend/.env
|
/frontend/.env
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# graphify 知識圖譜輸出(可由 graphify 重建,graph.json 每次整份重寫)
|
||||||
|
/graphify-out
|
||||||
|
|||||||
@@ -213,3 +213,13 @@
|
|||||||
- 發現問題直接說,不要繞彎
|
- 發現問題直接說,不要繞彎
|
||||||
- 有不確定的地方,明確標注「我不確定,需要你確認」
|
- 有不確定的地方,明確標注「我不確定,需要你確認」
|
||||||
- 不要重複確認已經決定的技術選擇
|
- 不要重複確認已經決定的技術選擇
|
||||||
|
|
||||||
|
## graphify
|
||||||
|
|
||||||
|
This project has a knowledge graph at graphify-out/ with god nodes, community structure, and cross-file relationships.
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- When graphify-out/graph.json exists, run `graphify query "<question>"` before your first grep, search or source-file read for a codebase question, and put this rule in every subagent prompt that explores code. Read raw files only for lines the graph or an earlier read already located. Use `graphify path "<A>" "<B>"` for relationships and `graphify explain "<concept>"` for focused concepts. These return a scoped subgraph, usually much smaller than GRAPH_REPORT.md or raw grep output.
|
||||||
|
- If graphify-out/wiki/index.md exists, use it for broad navigation instead of raw source browsing.
|
||||||
|
- Read graphify-out/GRAPH_REPORT.md only for broad architecture review or when query/path/explain do not surface enough context.
|
||||||
|
- After modifying code, run `graphify update .` to keep the graph current (AST-only, no API cost).
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# graphify 知識圖譜操作筆記
|
||||||
|
|
||||||
|
graphify 把專案的程式碼、OpenSpec 文件、設定檔轉成可查詢的知識圖譜,輸出在 `graphify-out/`。
|
||||||
|
該目錄被 `.gitignore` 忽略(`graph.json` 每次重建都整份重寫,進版控只會產生無意義 diff),換機器或清掉後需自行重建。
|
||||||
|
|
||||||
|
規則(先 query 再 grep、改完程式碼跑 `graphify update .`)見根目錄 `CLAUDE.md`,此處不重複。
|
||||||
|
|
||||||
|
## 建置紀錄(2026-10-29)
|
||||||
|
|
||||||
|
- 規模:2429 節點、4369 邊、約 117 個社群
|
||||||
|
- 來源:253 個程式碼檔以 AST 抽取;218 份文件與 5 張圖片以子代理做語意抽取
|
||||||
|
- 語意抽取沒有設 `GEMINI_API_KEY`,由 Claude Code 的子代理擔任 LLM
|
||||||
|
|
||||||
|
## 安裝與重建
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv tool install --upgrade graphifyy # 安裝(Windows,graphify 位於 uv tool 目錄)
|
||||||
|
/graphify . # 在 Claude Code 內完整建置
|
||||||
|
graphify update . # 只重新處理變更的檔案(AST 免費,語意抽取才耗 token)
|
||||||
|
graphify query "<問題>" # 查詢既有圖譜
|
||||||
|
```
|
||||||
|
|
||||||
|
完整建置的語意抽取需派約 15 個子代理,**同時最多 4 個**(超過會被拒絕),要分批派。
|
||||||
|
|
||||||
|
## 已知限制與踩過的坑
|
||||||
|
|
||||||
|
| 項目 | 說明 | 處理 |
|
||||||
|
|------|------|------|
|
||||||
|
| enum case 引用 | AST 只看得到類別被引用,看不到 `BookingStatus::Pending` 這類 case 的使用處,所以 `Pending`/`Confirmed`/`Completed` 在圖上看起來孤立 | 查 enum case 的使用處改用 grep |
|
||||||
|
| 腳本檔名 | 輔助腳本不可命名為 `ast.py`,會遮蔽標準函式庫造成循環匯入 | 換名稱,並用 `python -I` 執行 |
|
||||||
|
| 二進位檔覆蓋率 | PNG 沒有「行數」,覆蓋率檢查會誤報 partial(`hero.png`) | 可忽略 |
|
||||||
|
| 子代理只讀檔頭 | `.pi/agents/` 三個檔案只讀了檔頭,未寫入 manifest | 與 `.claude/agents/` 僅工具名稱寫法不同,已決定不補 |
|
||||||
|
| 同端點邊合併 | YAML 中重複的鍵(如 `steps` 底下多個 `name`)會被合併成一條邊 | 正常現象,不是圖損壞 |
|
||||||
|
|
||||||
|
## 社群命名
|
||||||
|
|
||||||
|
graphify 預設以「連線最多的節點名稱 + cluster」命名社群。前 16 大社群已手動改名(依成員與所在資料夾判斷):
|
||||||
|
|
||||||
|
| 編號 | 名稱 |
|
||||||
|
|------|------|
|
||||||
|
| 0 | 預約狀態機與生命週期測試 |
|
||||||
|
| 1 | 預約通知(Notification 類別) |
|
||||||
|
| 2 | 早期 OpenSpec 設計文件(預約/評價/會員入口) |
|
||||||
|
| 3 | 教練端前端(排程/評價/個人檔案) |
|
||||||
|
| 4 | 預約即時訊息(Reverb 事件) |
|
||||||
|
| 5 | 認證強化 spec(鎖定/OAuth state/稽核補強) |
|
||||||
|
| 6 | 課程排程與預約 API |
|
||||||
|
| 7 | 會員端前端(我的預約/課程列表) |
|
||||||
|
| 8 | AuthController 認證 |
|
||||||
|
| 9 | 前端與根目錄 package.json |
|
||||||
|
| 10 | 課程詳情頁前端(評價/預約) |
|
||||||
|
| 11 | 前端 Pinia 狀態與通知 |
|
||||||
|
| 12 | 評價功能測試 |
|
||||||
|
| 13 | Docker Compose 服務 |
|
||||||
|
| 14 | Feature 測試基底與授權測試 |
|
||||||
|
| 15 | 管理後台前端 |
|
||||||
|
|
||||||
|
社群編號可能隨重建而改變,此表只對 2026-10-29 這次建置有效;重建後需重新核對。
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# CFDivePlatform K8s 本機模擬待辦
|
||||||
|
|
||||||
|
> 記錄日期:2026-10-29
|
||||||
|
> 狀態:**僅記錄,尚未規劃、尚未動工**(Hank 指示「先記待辦」)。
|
||||||
|
> 範圍:在本機以 Docker Desktop Kubernetes 模擬部署,驗證 manifest 與流程;`docker-compose.yml` 維持本地開發用,不更動。
|
||||||
|
> 實作原則:涉及行為或部署流程變更,先走 OpenSpec(`/opsx:propose`);本文的決策與清單是規劃輸入,不是 spec。
|
||||||
|
> 搭配閱讀:`docs/analysis/2026-10-14-project-review-todo.md`(M6、M8 與本項有相依)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 已做的決策(2026-10-29 討論)
|
||||||
|
|
||||||
|
| 項目 | 決策 | 理由 |
|
||||||
|
|---|---|---|
|
||||||
|
| 模擬環境 | Docker Desktop 內建 Kubernetes,**Kubeadm(單節點)模式** | 目的是驗證 manifest 與部署流程,不需要多節點;設定最簡單 |
|
||||||
|
| 與 Compose 的關係 | Compose 照舊作為本地開發環境,K8s 另放獨立目錄(暫定 `k8s/`) | 兩邊互不影響,避免動到現有 `deploy.yml` |
|
||||||
|
| image | 沿用現有 `Dockerfile` 的 `app`、`web` 兩個 target | 與正式環境的 compose(不含 `compose.override.yml`)同一種形態,落差最小 |
|
||||||
|
| 隔離 | 每個專案一個 namespace | 另一個 .NET 專案會一起模擬 |
|
||||||
|
| 上機器的時機 | 本機模擬驗證完成後,再決定實際叢集 | VPS 資源不足,見下節 |
|
||||||
|
|
||||||
|
## 為什麼不直接在現有 VPS 上裝 K3s
|
||||||
|
|
||||||
|
2026-10-29 實測:2 核、1.9GB RAM(可用約 770MB)、磁碟剩 9.2GB(72%),且已跑 13 個容器(含 Gitea、Gitea runner、Nginx Proxy Manager)。
|
||||||
|
K3s 單節點自身約需 0.5–1GB,會讓 OOM 風險落在現有正式站與 CI。若之後要上實體叢集,建議另租至少 2 核 4GB、40GB 磁碟的機器。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 總覽
|
||||||
|
|
||||||
|
| # | 項目 | 依賴 | 是否走 OpenSpec |
|
||||||
|
|---|------|------|----------------|
|
||||||
|
| K1 | 決定 Ingress controller | — | 否(決策) |
|
||||||
|
| K2 | 盤點 CFDive 的 K8s 資源清單 | — | 否(盤點) |
|
||||||
|
| K3 | 撰寫 CFDive manifest(`k8s/`) | K1、K2 | 是 |
|
||||||
|
| K4 | 本機部署與驗證 | K3 | 是(含驗證項目) |
|
||||||
|
| K5 | 另一個 .NET 專案納入同一叢集 | K1、K4 | 另案(該專案的 repo) |
|
||||||
|
| K6 | 上傳檔案切 S3/R2 | 外部帳號 | 是(既有暫緩項目) |
|
||||||
|
| K7 | 上實體叢集前的差距清單 | K4 | 否(文件) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## K1 決定 Ingress controller
|
||||||
|
|
||||||
|
**現況**
|
||||||
|
Docker Desktop 沒有內建 Ingress。K3s 預設是 Traefik;原本考慮的 ingress-nginx,**據我所知 Kubernetes 社群已宣布它在 2026 年 3 月退役,此點為記憶,尚未查證**。
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] 查證 ingress-nginx 目前的維護狀態(官方公告)
|
||||||
|
- [ ] 在 Traefik 與 Gateway API 實作之間決定(暫定傾向 Traefik:與 K3s 預設一致,之後搬 K3s 的 manifest 改動最少)
|
||||||
|
- [ ] 確認 Reverb(WebSocket)在所選 Ingress 上的路由與逾時設定
|
||||||
|
|
||||||
|
## K2 盤點 CFDive 的 K8s 資源清單
|
||||||
|
|
||||||
|
**現況(依 `docker-compose.yml` 服務名稱,2026-10-29 核對)**
|
||||||
|
`app`、`nginx`、`frontend`、`db`、`scheduler`、`queue-worker`、`redis`、`reverb`。volumes 為 `mysql-data`、`redis-data`、`storage-app-public`。
|
||||||
|
|
||||||
|
**暫定對應(未驗證)**
|
||||||
|
- `app`、`nginx`、`frontend`、`queue-worker`、`reverb`:各一個 Deployment+必要的 Service
|
||||||
|
- `scheduler`:Deployment,**副本固定 1**(多副本會讓排程重複執行)
|
||||||
|
- migration/cache/swagger:目前在 `deploy.yml`,需改為 Job(或 initContainer)
|
||||||
|
- `.env`:拆成 ConfigMap(非機密)與 Secret(機密);`env_file:` 在 K8s 沒有對等物
|
||||||
|
- `db`、`redis`:本機模擬時先決定放叢集內,或沿用 Compose 容器經 `host.docker.internal` 連線
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] 逐一核對各服務的 port、healthcheck、啟動指令、依賴順序
|
||||||
|
- [ ] 決定 MySQL/Redis 放叢集內還是沿用 Compose(叢集內較貼近正式環境,Compose 較省事)
|
||||||
|
- [ ] 注意 `tests/bootstrap.php` 的覆蓋清單:擴大環境變數注入範圍時需同步檢查(見專案記憶中 `env_file` 事件)
|
||||||
|
|
||||||
|
## K3 撰寫 CFDive manifest
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] 目錄結構(`k8s/` 下用 Kustomize 或純 YAML,擇一)
|
||||||
|
- [ ] 各 Deployment 的探針(readiness/liveness)對應現有 healthcheck
|
||||||
|
- [ ] 加上 `requests`/`limits`,總量抓接近目標機器(例如 4GB 節點),避免本機資源充裕而漏掉 OOM 問題
|
||||||
|
- [ ] Secret 結構與正式環境相同,本機只用假值
|
||||||
|
- [ ] 環境值用正式設定:`APP_ENV=production`、`APP_DEBUG=false`、MySQL `8.0`、Redis `alpine`
|
||||||
|
- [ ] 不帶入 `compose.override.yml` 的 bind mount
|
||||||
|
|
||||||
|
## K4 本機部署與驗證
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] Docker Desktop 啟用 Kubernetes(Kubeadm 模式),確認 `kubectl` 指向正確 context
|
||||||
|
- [ ] 本機 build `app`、`web`、`frontend` image,`imagePullPolicy` 設為 `IfNotPresent`(或 `Never`)
|
||||||
|
- [ ] 驗證:登入、預約、評價主流程;Reverb 即時訊息(WebSocket 經 Ingress);queue job 實際被消化;scheduler 只有一個實例
|
||||||
|
- [ ] 驗證:migration Job 失敗時的行為(不應讓新版本 Pod 起來)
|
||||||
|
- [ ] 驗證:滾動更新與回滾(`kubectl rollout`)
|
||||||
|
- [ ] 記錄與 Compose 行為不一致之處
|
||||||
|
|
||||||
|
## K5 另一個 .NET 專案納入同一叢集
|
||||||
|
|
||||||
|
**注意事項(屬該專案 repo,這裡只記備忘)**
|
||||||
|
- ASP.NET Core(.NET 8 以後)官方 image 預設非 root、監聽 8080,Service 的 `targetPort` 要對
|
||||||
|
- 巢狀設定以環境變數覆蓋時用雙底線,例如 `ConnectionStrings__Default`
|
||||||
|
- 需自行提供健康檢查端點供探針使用
|
||||||
|
- EF migration 用 Job,不要在應用啟動時跑
|
||||||
|
- 多副本時需處理 Data Protection 金鑰共用,否則副本間 cookie/antiforgery 互相無法解密
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] 兩個專案用不同 namespace 與 hostname(例如 `cfdive.localhost`、`other.localhost`),共用同一個 Ingress controller
|
||||||
|
|
||||||
|
## K6 上傳檔案切 S3/R2
|
||||||
|
|
||||||
|
**現況**
|
||||||
|
`storage:migrate-to-s3` 指令與 `FILESYSTEM_DISK` 設定已完成(PR #55、#56),但 R2/S3 帳號尚未申請,VPS 仍是 `FILESYSTEM_DISK=local`,上傳檔案存在具名 volume `storage-app-public`。
|
||||||
|
多副本時 ReadWriteMany 儲存是最大阻礙;**本機 hostpath 單機無法代表這個問題**,所以這項要在上實體叢集前完成。
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] 取得 S3 相容服務帳號後,另開 OpenSpec change 接續(不要回頭改已歸檔的 `cloud-ready-s3-storage`)
|
||||||
|
|
||||||
|
## K7 上實體叢集前的差距清單
|
||||||
|
|
||||||
|
本機模擬**無法**驗證的項目,上實體叢集後需另外確認:
|
||||||
|
|
||||||
|
| 項目 | 原因 |
|
||||||
|
|---|---|
|
||||||
|
| 多節點調度、節點故障 | Kubeadm 模式為單節點 |
|
||||||
|
| 檔案儲存的 ReadWriteMany | 本機 hostpath 僅單機 |
|
||||||
|
| TLS/憑證、真實網域 | 本機用 `*.localhost`,無 Let's Encrypt |
|
||||||
|
| 真實流量與資源競爭 | 本機資源充裕 |
|
||||||
|
| Gitea Actions 到叢集的部署流程 | 需等有目標叢集;另需 image registry(目前 image 在 VPS 上 build,是否有 registry 未確認) |
|
||||||
|
|
||||||
|
**待辦**
|
||||||
|
- [ ] 確認 VPS 現行部署是否有 image registry;沒有的話,上叢集前要決定放哪裡
|
||||||
|
- [ ] 決定實體叢集(另租 K3s 機器,或雲端託管)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 開放問題
|
||||||
|
|
||||||
|
- 本機機器規格(Docker Desktop 分配給 WSL2 的記憶體)未確認;兩個專案加 MySQL/Redis 同時跑,建議 8GB 以上
|
||||||
|
- Kubeadm 模式下本機 image 是否可直接被 Pod 使用,依記憶判斷為可,**尚未在實際版本驗證**
|
||||||
|
- Ingress 最終選哪個(K1)
|
||||||
Reference in New Issue
Block a user