Commit Graph

27 Commits

Author SHA1 Message Date
王性驊 36214e0de0 add fix eage case 2026-05-28 14:51:25 +08:00
王性驊 b754a2d07d 修正 dev 登入與管理後台:ZITADEL Sessions 驗密、bootstrap admin、角色指派 UX。
ZITADEL v2 不支援 password grant,改優先走 Sessions API 以恢復 Email 登入;
dev-up 自動 seed 權限與 admin@k6.local,並改善使用者角色頁在無角色時仍可指派。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 14:45:11 +08:00
王性驊 43c5a015ca add fix eage case 2026-05-28 13:53:33 +08:00
王性驊 9dd8287777 add fix eage case 2026-05-27 17:28:13 +08:00
王性驊 93e94e8c5d Merge pull request 'feat/env' (#1) from feat/env into main
Reviewed-on: #1
2026-05-26 17:11:13 +00:00
王性驊 55e0e5c85b feat: k6 test 2026-05-27 01:10:32 +08:00
王性驊 d845ef45fd feat(auth): 登入 MFA、忘記/改密碼與註冊恢復流程
補齊平台帳號(platform_native)的密碼自助能力,並讓未完成 Email 驗證的使用者可恢復註冊;OIDC/LDAP/SCIM 帳號禁止在本系統變更密碼。登入若已啟用 TOTP 改為兩階段驗證,OTP 重送加入 60 秒冷卻;同步調整 golangci 排除路徑與 zitadel lint 修正。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-27 00:55:37 +08:00
王性驊 ffd60206d0 add fix eage case 2026-05-26 17:32:32 +08:00
王性驊 1f660b547a add fix eage case 2026-05-26 14:05:33 +08:00
王性驊 9616969fd0 test(e2e): 加 banner / e2e-list / k6 風格 user journey
讓「我有哪些測試、現在在測什麼」一眼看得到,並補上跨 endpoint 的狀態流測試:

每個測試開頭印中文 banner
- 新增 e2eStep(t, id, method, path, desc) helper(test/e2e/setup_test.go)
- 17 個 contract test 開頭加 banner,go test -v 會逐個顯示
    ▶ [M-01] GET /api/v1/members/me — 讀 profile(tenant/uid/status)
- 對外 ID 與 docs/e2e-testing.md 的測試覆蓋矩陣對齊

新增 make e2e-list
- scripts/e2e-list.sh 掃 _test.go,分兩節印 contract tests + journeys;
  每個 journey 列出所有 step ID + 描述(Step 用 ▶、SkipStep 用 ⊘)

scripts 彩色 step banner + optional MailHog
- scripts/e2e-lib.sh 抽共用 helpers(e2e_step/info/ok/warn、e2e_print_services)
- e2e-run.sh / e2e-up.sh 改用 step banner + 服務面板(執行完印出 Mongo/Redis/
  Gateway/MailHog 的 URL)
- E2E_WITH_SMTP=1 會額外起 MailHog(http://localhost:8025),方便肉眼確認流程

k6 風格 user journey
- 新增 test/e2e/journey.go:NewJourney + Step + SkipStep + Summary,
  任一步 fail 自動 skip 後續,輸出 ▶ [J-x.y] 階層 banner
- J-1 Tenant Owner 入職第一天(12 steps):/me → PATCH → email verify
  → phone verify → TOTP enroll/verify/replay/disable
- J-2 Tenant Admin 建 qa_engineer 角色 → 指派 → 二人視角驗證 → 撤銷(8 steps)
- J-3 Session 生命週期 refresh → /me → logout → 舊 token 401(4 steps,ZZZ 排最後)
- J-4 完整註冊 → 登入(5 steps stub,標 SkipStep;接 ZITADEL container 後改 Step 即可)
- make e2e-journey / make test-e2e-journey 拆獨立 target;e2e-run.sh 透過
  E2E_MODE=journey + E2E_TEST_PATTERN_ZZZ 切換

docs/e2e-testing.md
- 首節改為「我現在有哪些測試?make e2e-list」並附 banner 範例輸出
- 加 Journeys 章節:journey 列表、執行範例、失敗時的輸出、寫新 journey 範本
- 補 e2e-journey / test-e2e-journey / E2E_WITH_SMTP 環境變數

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 17:18:36 +08:00
王性驊 55446b9060 docs: 統整模組 README ↔ SDD 分工,砍重複內容
讓「找規格」跟「日常速查」兩種需求各有歸宿,避免同樣資訊散落多處:

- 改寫 docs/identity-member-design.md:從 Big5 亂碼的 2673 行設計草稿
  → ~200 行 UTF-8 跨模組總覽(架構決策、模組依賴、UID、JWT、Casbin、
  Pub/Sub、Notification 全部一頁看完),不再跟模組 README 重疊
- 新增 internal/model/auth/README.md:合併原 auth-unified-registration
  + auth/SDD 的高層概念,留 SDD 給規格細節
- 精簡 member / permission / notification README:保留 sequence diagram、
  curl、ServiceContext wiring 等日常開發要的東西;逐欄位 schema / Redis
  key TTL / API endpoint list 等規格細節改指向各模組 SDD.md
- 每個 README 頂部加「規格 vs 速查」一行指路,找欄位 → SDD,找流程 → README
- root README 同步補上各模組 README + SDD 並列連結
- code comment 裡的 internal/model/{member,permission}/SDD.md §X.Y 引用
  全部對齊新章節編號

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-22 17:18:08 +08:00
王性驊 1f3eb3c992 add member totp 2026-05-22 07:52:39 +08:00
王性驊 bdeb7e8263 refactor(middleware): wire AuthJWT + CasbinRBAC via .api middleware directive
Stop relying on a global server.Use(CloudEPJWT) that was invisible from
the .api source. Protected routes now declare middleware explicitly in
each @server block and goctl chains them into routes.go — the .api file
is the single source of truth for "who needs Bearer / who needs RBAC".

Concretely:

- Rewrite middleware to go-zero's standard struct + Handle() pattern.
  AuthJWT becomes strict: missing/invalid Bearer returns 28501000 (was
  soft passthrough). CasbinRBAC stays nil-tolerant so dev/test boots
  without a policy.
- Files renamed to goctl's stringx convention (authjwt_middleware.go,
  casbinrbac_middleware.go) so future `make gen-api` runs see them as
  already-generated and skip the empty stub.
- Move actor context helpers (Actor, WithActor, ActorFromContext) into
  internal/library/actor so middleware and BOTH logic packages share
  one context key. Previously each logic package had its own private
  actorKey struct{}, so an actor injected for member was invisible to
  permission — the permission RBAC chain would always see "missing
  actor". member/permission actor.go are now thin type-alias shims.
- .api files declare middleware per group:
    auth.api (public)         → no middleware (register/login/token/...)
    auth.api (logout)         → middleware: AuthJWT
    member.api                → middleware: AuthJWT
    permission.api (catalog,me) → middleware: AuthJWT
    permission.api (admin ops) → middleware: AuthJWT,CasbinRBAC
    normal.api (/health)      → no middleware
- ServiceContext exposes AuthJWT / CasbinRBAC as rest.Middleware; the
  global server.Use(...) in gateway.go is removed.
- Document the pattern in AGENTS.md (cross-agent rules) and
  generate/api/README.md (detailed examples + filename rules) so any
  future AI agent or human follows the same convention.

make gen-api / gen-doc / lint / build all pass.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 17:30:50 +08:00
王性驊 4590f1c951 docs(api): group OpenAPI by tags + add Chinese field descriptions and enums
Make the generated docs/openapi/gateway.yaml usable by adding three things
go-doc parses out of the .api source:

- @server tags + summary on every block → Swagger UI groups endpoints
  (Auth / Member / Permission / Normal) instead of dumping everything
  under "default".
- backtick end-of-line // 中文 on every Request field → property
  descriptions in the schema. go-doc only reads the trailing comment,
  not the line above, so all comments are placed on the same line as
  the tag.
- options=A|B|C in json/form tags wherever validate:"oneof=..." exists
  → enum dropdowns. The validate tag is kept for runtime validation;
  go-zero also enforces options= at bind time.

Codify the rules in generate/api/README.md (tags / 行末註解 / options=)
and add AGENTS.md at repo root so any AI agent (Claude / Cursor / Codex)
picks them up automatically when working on the project.

types.go regenerated via make gen-api to keep json tags in sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 17:15:25 +08:00
王性驊 fa50c64ee4 feat(permission): add RBAC module with Casbin enforcement and policy reload
- Multi-tenant RBAC: permission catalog, roles, role-permission mapping,
  user-role assignment, and external IdP role mapping (zitadel/ldap/scim).
- Casbin enforcer with Redis-backed adapter and Pub/Sub reload for
  multi-instance policy sync; HTTP middleware enforces (tenant, role,
  path, method) with platform admin bypass.
- /api/v1/permissions routes: catalog, me, policy/reload, roles CRUD,
  role permissions, user roles, role mappings.
- New error scope (31) for Permission and biz code descriptions.
- Wire Permission module into ServiceContext, config, mongo-index, and
  add cmd/permission-seed CLI plus etc/rbac.conf model.
- Redis client gains lazy PubSubClient helper (go-zero wrapper lacks Subscribe).
- Rewrite internal/model/member/README to cover Tenant/Member/Identity.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 16:47:35 +08:00
王性驊 713a81f70b feat(auth): add unified registration/login module with Zitadel + lint cleanup
- Introduce auth module: handlers, logic, domain/repository/usecase, JWT
  middleware, and Zitadel OIDC client (password + authorization code +
  userinfo + JWKS verification)
- Wire member rate-limit, structured errors, and refactored member/
  notification usecases (introduce shared errors, drop repo_errors.go)
- Bring the codebase to zero golangci-lint issues:
  * goimports formatting
  * errcheck on io.ReadAll/Unlock cleanup paths
  * contextcheck: HandlerContext now takes (ctx, *http.Request)
  * gocritic: rename shadowed `max`, use http.NoBody
  * goconst: extract test fixtures and bsonOpSet
  * testifylint: switch to assert inside httptest handlers

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 14:45:35 +08:00
王性驊 2ae86e9002 add member totp 2026-05-21 07:51:22 +08:00
王性驊 240fa92f6f add member totp 2026-05-20 21:03:59 +08:00
王性驊 3afe3f9502 fix error msg 2026-05-20 17:32:22 +08:00
王性驊 35c6577ac8 chore: gitignore local gateway.dev.yaml and add example template
Stop tracking personal dev config (ports, credentials). Developers copy
etc/gateway.dev.example.yaml to etc/gateway.dev.yaml locally.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 15:14:44 +08:00
王性驊 49e7099bf2 add notification and member modules with local dev stack
Implement outbound notification (sync/async, idempotency, quota, DLQ),
member OTP/verification, SMTP/SES/Mitake providers, shared Redis wiring,
docker-compose for Mongo/Redis, and gateway config documentation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-20 15:01:08 +08:00
王性驊 1274c56cb5 add member design 2026-05-20 01:04:26 +08:00
王性驊 67afbf6c5d add member design 2026-05-19 21:56:59 +08:00
王性驊 04077a0fcb add lib mongo 2026-05-19 21:33:04 +08:00
王性驊 fb5ac4b09f add lint 2026-05-19 21:15:18 +08:00
王性驊 79c12702ec add validate 2026-05-19 20:56:32 +08:00
王性驊 ea4f45f949 init project 2026-05-19 19:00:28 +08:00