@dtd-dev/agent-kb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -0
- package/bin/cli.js +653 -0
- package/package.json +33 -0
- package/template/AGENTS.md +34 -0
- package/template/CLAUDE.md +4 -0
- package/template/GEMINI.md +6 -0
- package/template/_adr-skeleton.md +8 -0
- package/template/_agent-skeleton.md +21 -0
- package/template/_feature-skeleton/api.md +8 -0
- package/template/_feature-skeleton/design.md +6 -0
- package/template/_feature-skeleton/requirements.md +9 -0
- package/template/_feature-skeleton/test-cases.md +7 -0
- package/template/_skill-skeleton.md +16 -0
- package/template/_stacks/go.md +19 -0
- package/template/_stacks/java.md +19 -0
- package/template/_stacks/node.md +19 -0
- package/template/_stacks/php.md +18 -0
- package/template/_stacks/python.md +19 -0
- package/template/_stacks/react.md +20 -0
- package/template/_stacks/rust.md +18 -0
- package/template/ai/README.md +28 -0
- package/template/ai/agents/bug-fixer.md +23 -0
- package/template/ai/agents/feature-builder.md +18 -0
- package/template/ai/agents/reviewer.md +20 -0
- package/template/ai/agents/tester.md +21 -0
- package/template/ai/architecture.md +40 -0
- package/template/ai/core/coding-standards.md +28 -0
- package/template/ai/core/glossary.md +20 -0
- package/template/ai/core/tech-stack.md +19 -0
- package/template/ai/decisions/ADR-001-auth.md +9 -0
- package/template/ai/decisions/ADR-002-cache.md +9 -0
- package/template/ai/decisions/ADR-003-logging.md +9 -0
- package/template/ai/examples/api-example.md +31 -0
- package/template/ai/examples/coding-example.md +28 -0
- package/template/ai/examples/testing-example.md +32 -0
- package/template/ai/memory/common-bugs.md +11 -0
- package/template/ai/memory/lessons-learned.md +6 -0
- package/template/ai/memory/troubleshooting.md +19 -0
- package/template/ai/product/business-rules.md +19 -0
- package/template/ai/product/domain-model.md +22 -0
- package/template/ai/product/vision.md +8 -0
- package/template/ai/skills/backend/carepay-oncall-gen2.md +24 -0
- package/template/ai/skills/backend/carepay-request-gen2.md +23 -0
- package/template/ai/skills/backend/carepay-trigger-gen2.md +24 -0
- package/template/ai/skills/devops/deployment.md +29 -0
- package/template/ai/skills/devops/docker.md +24 -0
- package/template/ai/skills/devops/github-actions.md +26 -0
- package/template/ai/skills/frontend/carepay-firebase.md +25 -0
- package/template/ai/skills/frontend/react.md +24 -0
- package/template/ai/skills/frontend/ui-guideline.md +29 -0
- package/template/ai/specs/feature-a/api.md +26 -0
- package/template/ai/specs/feature-a/design.md +12 -0
- package/template/ai/specs/feature-a/requirements.md +13 -0
- package/template/ai/specs/feature-a/test-cases.md +12 -0
- package/template/ai/workflows/code-review.md +25 -0
- package/template/ai/workflows/create-feature.md +37 -0
- package/template/ai/workflows/fix-bug.md +16 -0
- package/template/ai/workflows/incident-response.md +19 -0
- package/template/ai/workflows/learn.md +24 -0
- package/template/ai/workflows/release.md +23 -0
- package/template/github/copilot-instructions.md +5 -0
- package/template/tools/pointer.md +5 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<!--PROJECT:{{PROJECT_NAME}}-->
|
|
2
|
+
# AGENTS.md
|
|
3
|
+
|
|
4
|
+
> File "cửa vào" chuẩn chung cho mọi AI agent (Codex, Cursor, Copilot, Gemini, Windsurf, Aider, Zed...).
|
|
5
|
+
> Đây là NGUỒN CHÂN LÝ duy nhất. Các file CLAUDE.md / GEMINI.md / copilot-instructions.md chỉ trỏ về đây.
|
|
6
|
+
> Mục tiêu: chỉ load đúng context cho từng task → tiết kiệm token.
|
|
7
|
+
|
|
8
|
+
## Luôn load (Tier 1 — context lõi, giữ nhỏ)
|
|
9
|
+
- `.ai/core/tech-stack.md`
|
|
10
|
+
- `.ai/core/coding-standards.md`
|
|
11
|
+
- `.ai/core/glossary.md`
|
|
12
|
+
|
|
13
|
+
## Router: task → file cần đọc thêm (Tier 2, on-demand)
|
|
14
|
+
| Khi bạn làm... | Đọc thêm |
|
|
15
|
+
|---|---|
|
|
16
|
+
| Tạo feature mới / sinh spec từ mô tả | `.ai/workflows/create-feature.md` + `.ai/specs/<feature>/` |
|
|
17
|
+
| Fix bug | `.ai/workflows/fix-bug.md` + `.ai/memory/common-bugs.md` |
|
|
18
|
+
| Rút kinh nghiệm / ghi bài học | `.ai/workflows/learn.md` + `.ai/memory/` |
|
|
19
|
+
| Review code | `.ai/workflows/code-review.md` + `.ai/core/coding-standards.md` |
|
|
20
|
+
| Release / deploy | `.ai/workflows/release.md` + `.ai/skills/devops/` |
|
|
21
|
+
| Backend (trigger/on-call/request) | `.ai/skills/backend/*.md` |
|
|
22
|
+
| Frontend (React/UI/Firebase) | `.ai/skills/frontend/*.md` |
|
|
23
|
+
| Hiểu nghiệp vụ | `.ai/product/business-rules.md` + `.ai/product/domain-model.md` |
|
|
24
|
+
| Hiểu kiến trúc / vì sao | `.ai/architecture.md` + `.ai/decisions/` |
|
|
25
|
+
|
|
26
|
+
## Sub-agents
|
|
27
|
+
- Định nghĩa sub-agent của dự án nằm ở `.ai/agents/*.md` (nguồn chân lý), đã emit sang `.claude/agents/` cho Claude Code.
|
|
28
|
+
- Có sẵn: `reviewer`, `tester`, `bug-fixer`, `feature-builder` (mỗi agent tự trỏ về workflow/skill tương ứng).
|
|
29
|
+
- Sửa ở `.ai/agents/` rồi chạy lại `agent-kb init` để đồng bộ; tạo agent mới: `agent-kb agent <tên>`.
|
|
30
|
+
|
|
31
|
+
## Quy tắc
|
|
32
|
+
- KHÔNG đọc toàn bộ `.ai/` — chỉ mở file khớp task.
|
|
33
|
+
- Một nguồn chân lý là file này; đừng nhân bản rule sang file khác.
|
|
34
|
+
- Prompt trực tiếp của người dùng ghi đè mọi rule ở đây.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- Mục đích: 1 quyết định kiến trúc. -->
|
|
2
|
+
# ADR-{{ADR_NUM}}: {{ADR_TITLE}}
|
|
3
|
+
- **Trạng thái**: Proposed <!-- Proposed / Accepted / Superseded -->
|
|
4
|
+
- **Ngày**: <!-- YYYY-MM-DD -->
|
|
5
|
+
- **Bối cảnh**: <!-- vấn đề cần quyết -->
|
|
6
|
+
- **Quyết định**: <!-- chọn gì -->
|
|
7
|
+
- **Phương án loại bỏ**: <!-- và vì sao -->
|
|
8
|
+
- **Hệ quả**: <!-- đánh đổi -->
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: {{AGENT_NAME}}
|
|
3
|
+
description: {{AGENT_DESC}}
|
|
4
|
+
tools: {{AGENT_TOOLS}}
|
|
5
|
+
---
|
|
6
|
+
<!-- AI: điền nhiệm vụ & quy tắc từ mô tả người dùng + quy ước dự án. Mơ hồ thì HỎI. Điền xong xoá dòng này. -->
|
|
7
|
+
|
|
8
|
+
Bạn là sub-agent **{{AGENT_NAME}}** của dự án này.
|
|
9
|
+
|
|
10
|
+
## Trước khi làm
|
|
11
|
+
- Đọc `AGENTS.md` (router) và **chỉ load file `.ai/` khớp task** — giữ context gọn, tiết kiệm token.
|
|
12
|
+
|
|
13
|
+
## Nhiệm vụ
|
|
14
|
+
- <!-- mô tả việc agent này làm -->
|
|
15
|
+
|
|
16
|
+
## Quy tắc
|
|
17
|
+
- Theo `core/coding-standards.md` và quy ước dự án.
|
|
18
|
+
- <!-- ràng buộc riêng của agent -->
|
|
19
|
+
|
|
20
|
+
## Tham chiếu
|
|
21
|
+
- <!-- workflow/skill/spec liên quan trong .ai/ -->
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!-- Mục đích: hợp đồng API của feature. -->
|
|
2
|
+
<!-- AI: điền theo convention ở examples/api-example.md; mã lỗi đặt tên máy đọc. Feature không có API thì để trống/xoá file. Mơ hồ thì HỎI. Điền xong xoá dòng này. -->
|
|
3
|
+
# {{FEATURE_NAME}} — API
|
|
4
|
+
## `<METHOD> /path`
|
|
5
|
+
- Mô tả: <!-- ... -->
|
|
6
|
+
- Request: <!-- ... -->
|
|
7
|
+
- Response: <!-- ... -->
|
|
8
|
+
- Lỗi: <!-- mã + ý nghĩa -->
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<!-- Mục đích: thiết kế kỹ thuật của feature. -->
|
|
2
|
+
<!-- AI: điền từ mô tả người dùng + domain-model.md/architecture.md. Quyết định lớn → đề xuất ADR. Mơ hồ thì HỎI, đừng bịa. Điền xong xoá dòng này. -->
|
|
3
|
+
# {{FEATURE_NAME}} — Design
|
|
4
|
+
- Tiếp cận: <!-- ... -->
|
|
5
|
+
- Thay đổi data model: <!-- ... -->
|
|
6
|
+
- Đánh đổi: <!-- ... -->
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- Mục đích: yêu cầu của feature. -->
|
|
2
|
+
<!-- AI: điền các mục dưới từ mô tả của người dùng + business-rules.md/domain-model.md/glossary.md. Mơ hồ thì HỎI, đừng bịa. Điền xong xoá dòng này. -->
|
|
3
|
+
# {{FEATURE_NAME}} — Requirements
|
|
4
|
+
- Mục tiêu: <!-- ... -->
|
|
5
|
+
- User story: Là <!-- vai trò -->, tôi muốn <!-- ... --> để <!-- ... -->
|
|
6
|
+
- Acceptance criteria:
|
|
7
|
+
- [ ] <!-- ... -->
|
|
8
|
+
- Ngoài phạm vi: <!-- ... -->
|
|
9
|
+
- Business rules liên quan: <!-- BR-001, ... -->
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<!-- Mục đích: test case của feature. -->
|
|
2
|
+
<!-- AI: phủ happy path + edge case + 1 ca cho mỗi BR liên quan ở requirements.md. Mơ hồ thì HỎI, đừng bịa. Điền xong xoá dòng này. -->
|
|
3
|
+
# {{FEATURE_NAME}} — Test Cases
|
|
4
|
+
| ID | Tình huống | Input | Kỳ vọng |
|
|
5
|
+
|----|-----------|-------|---------|
|
|
6
|
+
| TC-1 | <!-- happy path --> | | |
|
|
7
|
+
| TC-2 | <!-- edge case --> | | |
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!-- Mục đích: <điền mục đích skill>. Load khi task thuộc loại này. -->
|
|
2
|
+
<!-- AI: điền từ mô tả người dùng + code thật của dự án. Mơ hồ thì HỎI. Điền xong xoá dòng này. -->
|
|
3
|
+
# Skill: {{SKILL_NAME}}
|
|
4
|
+
|
|
5
|
+
## Khi nào dùng
|
|
6
|
+
<!-- task nào kích hoạt skill này -->
|
|
7
|
+
|
|
8
|
+
## Quy tắc / pattern
|
|
9
|
+
- <!-- bước hoặc nguyên tắc 1 -->
|
|
10
|
+
- <!-- bước 2 -->
|
|
11
|
+
|
|
12
|
+
## Cạm bẫy thường gặp
|
|
13
|
+
- <!-- lỗi hay mắc + cách tránh -->
|
|
14
|
+
|
|
15
|
+
## Tham chiếu
|
|
16
|
+
- <!-- link tới spec/ADR/example liên quan -->
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn code Go cho dự án. Load khi task đụng backend Go. -->
|
|
2
|
+
# Stack: Go
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **Lỗi tường minh**: trả `error`, bọc ngữ cảnh bằng `fmt.Errorf("...: %w", err)`; kiểm tra ngay, không nuốt.
|
|
6
|
+
- **`context.Context`** là tham số đầu cho I/O/handler; tôn trọng huỷ & timeout.
|
|
7
|
+
- **Interface nhỏ, định nghĩa ở nơi dùng** (consumer side); trả struct cụ thể, nhận interface.
|
|
8
|
+
- **Đồng thời an toàn**: goroutine phải có cách dừng; tránh rò; bảo vệ state dùng chung bằng mutex/channel; chạy test với `-race`.
|
|
9
|
+
- **`defer`** để đóng resource (file, rows, body). Kiểm lỗi của `Close` khi quan trọng.
|
|
10
|
+
- **Bố cục**: theo package theo domain, không "utils" khổng lồ; `internal/` cho code không export.
|
|
11
|
+
- **Format/lint**: `gofmt`/`goimports`, `go vet`, golangci-lint. Không tranh luận style tay.
|
|
12
|
+
|
|
13
|
+
## Cạm bẫy thường gặp
|
|
14
|
+
- Bỏ qua `err` (`_ = f()`) → lỗi ẩn.
|
|
15
|
+
- Bắt biến vòng lặp trong goroutine (trước Go 1.22) → dữ liệu sai.
|
|
16
|
+
- `panic` cho lỗi nghiệp vụ — chỉ panic cho lỗi lập trình thật sự.
|
|
17
|
+
|
|
18
|
+
## Tham chiếu
|
|
19
|
+
- `core/coding-standards.md` · `skills/devops/docker.md`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn code Java (Spring). Load khi task đụng backend Java. -->
|
|
2
|
+
# Stack: Java
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **Immutability ưu tiên**: `final`, record cho DTO; tránh setter thừa.
|
|
6
|
+
- **Dependency injection qua constructor** (không field injection); component nhỏ, một trách nhiệm.
|
|
7
|
+
- **Lỗi**: exception nghiệp vụ riêng (kế thừa `RuntimeException` khi hợp lý); không nuốt; không log-and-rethrow lặp.
|
|
8
|
+
- **`Optional`** cho giá trị có thể vắng ở API trả về; không dùng cho field/param.
|
|
9
|
+
- **Tầng**: controller → service → repository; transaction ở service.
|
|
10
|
+
- **Validate** bằng Bean Validation (`@Valid`) ở biên.
|
|
11
|
+
- **Build/format**: Maven/Gradle ghim version; spotless/checkstyle; test JUnit5 + Mockito.
|
|
12
|
+
|
|
13
|
+
## Cạm bẫy thường gặp
|
|
14
|
+
- N+1 query với JPA (thiếu fetch join / `@EntityGraph`).
|
|
15
|
+
- Trả entity JPA thẳng ra API (lộ field, lazy-loading exception) — dùng DTO.
|
|
16
|
+
- `@Transactional` đặt sai tầng / gọi nội bộ cùng class không kích hoạt proxy.
|
|
17
|
+
|
|
18
|
+
## Tham chiếu
|
|
19
|
+
- `core/coding-standards.md` · `skills/devops/docker.md`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn code Node.js/TypeScript backend. Load khi task đụng backend Node. -->
|
|
2
|
+
# Stack: Node.js / TypeScript
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **TypeScript strict**: bật `strict`; tránh `any`, ưu tiên type/zod cho dữ liệu vào.
|
|
6
|
+
- **async/await + xử lý lỗi**: không bỏ promise lửng; bọc lỗi có ngữ cảnh; tránh `throw` chuỗi — dùng class lỗi.
|
|
7
|
+
- **Validate input ở biên** (zod/valibot) cho request/env; không tin dữ liệu ngoài.
|
|
8
|
+
- **Cấu hình qua ENV** (12-factor); không hardcode; có schema kiểm tra env lúc khởi động.
|
|
9
|
+
- **Tầng rõ ràng**: handler → service → repository; không nhét SQL vào controller.
|
|
10
|
+
- **Không chặn event loop**: việc nặng → worker/queue; stream cho dữ liệu lớn.
|
|
11
|
+
- **Tắt máy êm (graceful shutdown)**: bắt SIGTERM, đóng server/DB pool.
|
|
12
|
+
|
|
13
|
+
## Cạm bẫy thường gặp
|
|
14
|
+
- Quên `await` → lỗi nuốt mất, unhandled rejection.
|
|
15
|
+
- Rò connection do không đóng pool/handle.
|
|
16
|
+
- Log object vòng/secret ra console.
|
|
17
|
+
|
|
18
|
+
## Tham chiếu
|
|
19
|
+
- `core/coding-standards.md` · `examples/*` · `skills/devops/docker.md`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn code PHP (Laravel). Load khi task đụng backend PHP. -->
|
|
2
|
+
# Stack: PHP
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **`declare(strict_types=1)`** + type hint đầy đủ; PHP hiện đại (8.x), tránh code kiểu cũ.
|
|
6
|
+
- **Lỗi**: exception cụ thể, không `@` nuốt lỗi; tách lỗi nghiệp vụ vs hệ thống.
|
|
7
|
+
- **Laravel**: validate qua Form Request; logic nặng ở Service/Action, controller mỏng; dùng Eloquent đúng (tránh N+1 bằng eager `with()`).
|
|
8
|
+
- **Bảo mật**: query builder/Eloquent (chống SQL injection), `{{ }}` Blade tự escape, không tin input.
|
|
9
|
+
- **Cấu hình qua `.env`/config**, không hardcode; không commit `.env`.
|
|
10
|
+
- **Composer** ghim version; PSR-12; test PHPUnit/Pest; static analysis PHPStan/Larastan.
|
|
11
|
+
|
|
12
|
+
## Cạm bẫy thường gặp
|
|
13
|
+
- N+1 query do thiếu eager loading.
|
|
14
|
+
- Nhồi logic vào controller/model "fat".
|
|
15
|
+
- Mass-assignment không kiểm soát (`$fillable`/`$guarded`).
|
|
16
|
+
|
|
17
|
+
## Tham chiếu
|
|
18
|
+
- `core/coding-standards.md` · `skills/devops/docker.md`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn code Python. Load khi task đụng backend/script Python. -->
|
|
2
|
+
# Stack: Python
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **Type hints + mypy/pyright**; docstring ngắn cho hàm public.
|
|
6
|
+
- **Virtualenv + lock** (uv/poetry/pip-tools); ghim version, không cài global.
|
|
7
|
+
- **Lỗi tường minh**: bắt exception cụ thể, không `except:` trống; tạo exception nghiệp vụ riêng.
|
|
8
|
+
- **Validate dữ liệu vào** bằng pydantic (API/config).
|
|
9
|
+
- **f-string** cho format; **pathlib** cho đường dẫn; tránh mutable default argument (`def f(x=[])`).
|
|
10
|
+
- **I/O & async**: dùng `async` đúng chỗ (web), không trộn blocking trong event loop.
|
|
11
|
+
- **Format/lint**: ruff + black; `ruff check`, mypy trong CI.
|
|
12
|
+
|
|
13
|
+
## Cạm bẫy thường gặp
|
|
14
|
+
- Mutable default argument giữ state giữa các lần gọi.
|
|
15
|
+
- `except Exception` nuốt cả lỗi lập trình.
|
|
16
|
+
- Phụ thuộc thứ tự dict/đường dẫn tương đối khi chạy từ thư mục khác.
|
|
17
|
+
|
|
18
|
+
## Tham chiếu
|
|
19
|
+
- `core/coding-standards.md` · `skills/devops/docker.md`
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn React/TypeScript frontend. Load khi task đụng UI React. -->
|
|
2
|
+
# Stack: React
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **Function component + hooks**; một component một trách nhiệm, giữ nhỏ. Không class.
|
|
6
|
+
- **Tách logic dùng lại ra custom hook** (`useXxx`); tuân rules-of-hooks (gọi ở top level).
|
|
7
|
+
- **State đúng chỗ**: cục bộ `useState`; chia sẻ gần → lift up/context; **server state** dùng lib (React Query) — đừng nhồi vào global store.
|
|
8
|
+
- **Data fetching**: xử lý đủ loading/error/empty; không fetch trong vòng render.
|
|
9
|
+
- **`useEffect`** cho side-effect + cleanup; không dùng để tính giá trị dẫn xuất (tính khi render hoặc `useMemo`); dependency array đúng.
|
|
10
|
+
- **Key danh sách** ổn định, không dùng index khi list đổi thứ tự.
|
|
11
|
+
- **Tối ưu có đo lường**: `memo`/`useMemo`/`useCallback` chỉ khi cần.
|
|
12
|
+
- **A11y**: thẻ ngữ nghĩa, `label` cho input, điều hướng bàn phím.
|
|
13
|
+
|
|
14
|
+
## Cạm bẫy thường gặp
|
|
15
|
+
- Sai/thiếu dependency `useEffect` → stale closure hoặc loop vô hạn.
|
|
16
|
+
- Lạm dụng global state cho dữ liệu server → khó đồng bộ.
|
|
17
|
+
- Mutate trực tiếp state/props.
|
|
18
|
+
|
|
19
|
+
## Tham chiếu
|
|
20
|
+
- `core/coding-standards.md` · `skills/frontend/ui-guideline.md`
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!-- Mục đích: chuẩn code Rust. Load khi task đụng backend/CLI Rust. -->
|
|
2
|
+
# Stack: Rust
|
|
3
|
+
|
|
4
|
+
## Quy tắc / pattern
|
|
5
|
+
- **Lỗi**: `Result<T, E>` + `?`; lib dùng `thiserror`, app dùng `anyhow`. Tránh `unwrap()/expect()` ngoài test/khởi tạo chắc chắn.
|
|
6
|
+
- **Ownership rõ**: mượn (`&`/`&mut`) thay vì clone bừa; `clone()` có chủ đích.
|
|
7
|
+
- **Type-state & enum** để biểu diễn trạng thái hợp lệ; tận dụng `match` đầy đủ nhánh.
|
|
8
|
+
- **Async**: chọn một runtime (tokio); không block trong async; `Send + Sync` khi chia sẻ.
|
|
9
|
+
- **Module**: chia theo domain; public API tối thiểu; `pub(crate)` khi nội bộ.
|
|
10
|
+
- **Format/lint**: `cargo fmt`, `cargo clippy -D warnings`, test `cargo test`.
|
|
11
|
+
|
|
12
|
+
## Cạm bẫy thường gặp
|
|
13
|
+
- `unwrap()` trên dữ liệu ngoài → panic runtime.
|
|
14
|
+
- Lạm dụng `clone()`/`Rc<RefCell>` để né borrow checker → che thiết kế sai.
|
|
15
|
+
- `.await` giữ lock qua await point → deadlock/đình trệ.
|
|
16
|
+
|
|
17
|
+
## Tham chiếu
|
|
18
|
+
- `core/coding-standards.md` · `skills/devops/docker.md`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# .ai — Knowledge base cho AI agent
|
|
2
|
+
|
|
3
|
+
Bản đồ context. AI đọc file này trước để biết **task → file cần load**, tránh nuốt cả thư mục.
|
|
4
|
+
|
|
5
|
+
## Tầng context
|
|
6
|
+
- **Tier 0 — Index**: file này.
|
|
7
|
+
- **Tier 1 — Core (LUÔN load)**: `core/*.md`. Giữ mỗi file < ~500 token.
|
|
8
|
+
- **Tier 2 — On-demand**: mọi thứ còn lại, chỉ đọc khi task đụng tới.
|
|
9
|
+
|
|
10
|
+
## Loading rules (task → file)
|
|
11
|
+
| Khi bạn làm... | Load thêm |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Tạo feature mới / sinh spec từ mô tả | `workflows/create-feature.md` + `specs/<feature>/` |
|
|
14
|
+
| Fix bug | `workflows/fix-bug.md` + `memory/common-bugs.md` |
|
|
15
|
+
| Rút kinh nghiệm / ghi bài học | `workflows/learn.md` + `memory/` |
|
|
16
|
+
| Review code | `workflows/code-review.md` + `core/coding-standards.md` |
|
|
17
|
+
| Release / deploy | `workflows/release.md` + `skills/devops/` |
|
|
18
|
+
| Backend task (trigger, on-call, request) | `skills/backend/*.md` |
|
|
19
|
+
| Frontend task (React, UI, Firebase) | `skills/frontend/*.md` |
|
|
20
|
+
| Hiểu nghiệp vụ | `product/business-rules.md` + `product/domain-model.md` |
|
|
21
|
+
| Hiểu kiến trúc / vì sao thiết kế vậy | `architecture.md` + `decisions/` |
|
|
22
|
+
|
|
23
|
+
**Nguyên tắc:** không đọc file không khớp task. Nghi ngờ thì hỏi, đừng load thừa.
|
|
24
|
+
|
|
25
|
+
## Quy ước viết file
|
|
26
|
+
- 1 file = 1 nhiệm vụ. Phình to → tách hoặc đẩy xuống Tier 2.
|
|
27
|
+
- Tránh trùng lặp giữa các file (mỗi lần trùng = đốt token thừa).
|
|
28
|
+
- Đầu mỗi file ghi 1 dòng mục đích để AI quyết định có cần đọc không.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bug-fixer
|
|
3
|
+
description: Tái hiện, tìm root cause và sửa bug theo quy trình dự án. Dùng khi có lỗi cần điều tra & vá.
|
|
4
|
+
tools: Read, Edit, Bash, Grep, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Bạn là **bug-fixer** của dự án này. Mục tiêu: sửa **đúng nguyên nhân gốc**, không vá triệu chứng.
|
|
8
|
+
|
|
9
|
+
## Trước khi sửa
|
|
10
|
+
- Đọc `AGENTS.md` (router); load `workflows/fix-bug.md`, `memory/common-bugs.md`, `memory/troubleshooting.md`.
|
|
11
|
+
|
|
12
|
+
## Quy trình (bám `workflows/fix-bug.md`)
|
|
13
|
+
1. **Tái hiện** ổn định; ghi bước + môi trường + kỳ vọng vs thực tế.
|
|
14
|
+
2. **Tra** `memory/common-bugs.md` xem đã gặp chưa.
|
|
15
|
+
3. **Khoanh vùng** → tìm **root cause** (hỏi "vì sao" tới gốc).
|
|
16
|
+
4. **Viết test bắt bug trước** (fail), rồi sửa cho xanh (regression test).
|
|
17
|
+
5. **Sửa tối thiểu** đủ giải quyết gốc; rà nơi khác cùng pattern.
|
|
18
|
+
6. **Xác minh** lại bước tái hiện + test liên quan.
|
|
19
|
+
7. Nếu đáng nhớ → đề xuất thêm vào `memory/common-bugs.md` (theo `workflows/learn.md`).
|
|
20
|
+
|
|
21
|
+
## Lưu ý
|
|
22
|
+
- Bug production gấp → giảm thiểu trước theo `workflows/incident-response.md`, sửa gốc sau.
|
|
23
|
+
- Không xoá test/giảm assertion để qua.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feature-builder
|
|
3
|
+
description: Dựng tính năng mới theo spec & chuẩn dự án (spec-first). Dùng khi triển khai một feature từ yêu cầu.
|
|
4
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Bạn là **feature-builder** của dự án này. Mục tiêu: làm đúng yêu cầu, theo spec, không phá tính năng cũ.
|
|
8
|
+
|
|
9
|
+
## Trước khi code
|
|
10
|
+
- Đọc `AGENTS.md` (router); load `workflows/create-feature.md`, `specs/<feature>/`, `core/coding-standards.md`, và skill liên quan trong `skills/`.
|
|
11
|
+
- Chưa có spec? Tạo khung `agent-kb feature <tên>` và sinh spec theo `workflows/create-feature.md`; **yêu cầu mơ hồ thì HỎI, đừng đoán**.
|
|
12
|
+
|
|
13
|
+
## Quy trình (bám `workflows/create-feature.md`)
|
|
14
|
+
1. Hiểu yêu cầu (requirements.md) → 2. Thiết kế (design.md, ADR nếu lớn) → 3. Chốt API (api.md) →
|
|
15
|
+
4. Code theo chuẩn + skill, commit nhỏ → 5. Test theo `test-cases.md` (happy + biên + business rule) → 6. Tự review (giao `reviewer`).
|
|
16
|
+
|
|
17
|
+
## Definition of Done
|
|
18
|
+
- Đủ acceptance criteria; test xanh có cả ca lỗi; cập nhật doc (spec/ADR/glossary); không secret/log debug sót.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: reviewer
|
|
3
|
+
description: Review code thay đổi theo chuẩn & nghiệp vụ của dự án. Dùng sau khi viết xong một phần, trước khi mở PR.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Bạn là **reviewer** của dự án này. Mục tiêu: bắt lỗi chặn merge trước, góp ý chất lượng sau — không tự ý sửa code.
|
|
8
|
+
|
|
9
|
+
## Trước khi review
|
|
10
|
+
- Đọc `AGENTS.md` (router) và chỉ load file `.ai/` khớp: `workflows/code-review.md`, `core/coding-standards.md`, và `specs/<feature>/` nếu liên quan.
|
|
11
|
+
- Xem diff thật (vd `git diff`), không đoán.
|
|
12
|
+
|
|
13
|
+
## Cách review (bám `workflows/code-review.md`)
|
|
14
|
+
- **P0 (phải sửa)**: đúng acceptance criteria; correctness & edge case; bảo mật (secret/inject/phân quyền); có test cho logic mới.
|
|
15
|
+
- **P1 (nên sửa)**: error handling, đồng thời/transaction/idempotency, hiệu năng (N+1), tương thích API/migration.
|
|
16
|
+
- **P2 (chất lượng)**: tên rõ, hàm nhỏ, không lặp/magic value, không code chết/log debug.
|
|
17
|
+
|
|
18
|
+
## Đầu ra
|
|
19
|
+
- Gom theo P0/P1/P2; mỗi mục: vị trí (`file:line`) + lý do + gợi ý sửa. Tách "bắt buộc" vs "nit". Khen điểm tốt khi xứng đáng.
|
|
20
|
+
- KHÔNG chỉnh sửa file — chỉ báo cáo.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tester
|
|
3
|
+
description: Viết và chạy test theo quy ước dự án. Dùng khi cần phủ test cho code mới hoặc bổ sung ca thiếu.
|
|
4
|
+
tools: Read, Write, Edit, Bash, Grep, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Bạn là **tester** của dự án này. Mục tiêu: phủ test có ý nghĩa, không chạy theo coverage hình thức.
|
|
8
|
+
|
|
9
|
+
## Trước khi viết test
|
|
10
|
+
- Đọc `AGENTS.md` (router); load `examples/testing-example.md`, `core/coding-standards.md`, và `specs/<feature>/test-cases.md` nếu có.
|
|
11
|
+
- Dùng đúng test runner/quy ước sẵn có của repo (xem `core/tech-stack.md`).
|
|
12
|
+
|
|
13
|
+
## Nguyên tắc
|
|
14
|
+
- Tên test mô tả **hành vi**, cấu trúc **arrange–act–assert**.
|
|
15
|
+
- Phủ: happy path + ca lỗi/biên + **một ca cho mỗi business rule** liên quan (BR-00x).
|
|
16
|
+
- Không xoá/nới lỏng assertion để "qua bài"; test phải fail khi logic sai.
|
|
17
|
+
|
|
18
|
+
## Quy trình
|
|
19
|
+
1. Liệt kê ca cần test (từ `test-cases.md`/yêu cầu).
|
|
20
|
+
2. Viết test, chạy, đảm bảo xanh và thực sự kiểm đúng hành vi.
|
|
21
|
+
3. Báo cáo: đã thêm ca nào, ca nào còn thiếu/không test được và vì sao.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<!-- Mục đích: kiến trúc tổng thể + luồng dữ liệu. Load khi cần hiểu hệ thống, không phải mỗi task. -->
|
|
2
|
+
<!-- Đây là MẪU theo dự án CarePay (Firebase). Thay bằng kiến trúc thật của dự án bạn. -->
|
|
3
|
+
# Architecture
|
|
4
|
+
|
|
5
|
+
## Sơ đồ tổng thể
|
|
6
|
+
```
|
|
7
|
+
┌──────────────────────────┐
|
|
8
|
+
Người dùng → │ Web app (React + Vite) │
|
|
9
|
+
└────────────┬─────────────┘
|
|
10
|
+
│ Firebase SDK (Auth token đính kèm mỗi request)
|
|
11
|
+
┌──────────────┼────────────────────────────┐
|
|
12
|
+
▼ ▼ ▼
|
|
13
|
+
Firebase Auth Cloud Functions Gen2 Firestore (đọc trực tiếp
|
|
14
|
+
(đăng nhập) ├─ onRequest (HTTP API) qua security rules cho
|
|
15
|
+
├─ onCall (callable) dữ liệu của chính user)
|
|
16
|
+
└─ trigger (Firestore/PubSub event)
|
|
17
|
+
│
|
|
18
|
+
┌──────────────┼──────────────┐
|
|
19
|
+
▼ ▼ ▼
|
|
20
|
+
Firestore Payment Gateway Pub/Sub
|
|
21
|
+
(nguồn dữ (đối tác ngoài) (việc nền/
|
|
22
|
+
liệu chính) bất đồng bộ)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Luồng dữ liệu chính (ví dụ: thanh toán viện phí)
|
|
26
|
+
1. **Request đến**: client gọi callable `createPayment` (onCall) kèm Auth token.
|
|
27
|
+
2. **Qua service**: function xác thực token → kiểm tra business rule → gọi Payment Gateway → ghi `payments/{id}` (status `pending`) vào Firestore.
|
|
28
|
+
3. **Xử lý nền**: gateway gọi webhook (onRequest) báo kết quả → cập nhật `payments/{id}.status`. Một **Firestore trigger** trên thay đổi đó cập nhật số dư `wallets/{uid}` và bắn thông báo.
|
|
29
|
+
4. **Phản hồi**: client lắng nghe (`onSnapshot`) tài liệu payment → UI cập nhật realtime.
|
|
30
|
+
|
|
31
|
+
## Ranh giới (boundaries)
|
|
32
|
+
- **Client KHÔNG** chứa secret / logic tính phí / ghi trực tiếp `payments` — mọi mutation tiền bạc đi qua Cloud Functions.
|
|
33
|
+
- **onCall**: thao tác cần đăng nhập, gọi từ app. **onRequest**: webhook/đối tác ngoài (tự verify chữ ký). **trigger**: hệ quả phụ (cập nhật số dư, gửi mail) — KHÔNG để client gọi.
|
|
34
|
+
- **Firestore Security Rules** là lớp phòng thủ cuối: client chỉ đọc dữ liệu của chính mình; ghi tiền bạc bị chặn ở rules.
|
|
35
|
+
- **Idempotency**: webhook & trigger phải chịu được gọi lặp (dùng key giao dịch) — xem `decisions/ADR-002-cache.md` và business rules.
|
|
36
|
+
|
|
37
|
+
## Liên kết
|
|
38
|
+
- Quyết định kiến trúc & vì sao → `decisions/`
|
|
39
|
+
- Thực thể & quan hệ → `product/domain-model.md`
|
|
40
|
+
- Cách viết từng loại function → `skills/backend/*`
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!-- Mục đích: quy tắc clean code áp dụng mọi nơi. Quy tắc, không phải ví dụ (ví dụ ở examples/). -->
|
|
2
|
+
# Coding Standards
|
|
3
|
+
|
|
4
|
+
## Naming
|
|
5
|
+
- Theo convention của ngôn ngữ (vd JS/TS: biến/hàm `camelCase`, type/class `PascalCase`, hằng `UPPER_SNAKE`).
|
|
6
|
+
- Tên nói rõ ý định; tránh viết tắt mơ hồ và tiền tố thừa.
|
|
7
|
+
|
|
8
|
+
## Hàm & module
|
|
9
|
+
- Một hàm làm một việc; giữ ngắn (ưu tiên < ~30 dòng).
|
|
10
|
+
- Tránh nesting sâu — dùng early return.
|
|
11
|
+
- Không magic number/string — đặt tên hằng.
|
|
12
|
+
- Tách side-effect khỏi logic thuần để dễ test.
|
|
13
|
+
|
|
14
|
+
## Error handling
|
|
15
|
+
- Không nuốt lỗi im lặng; log có ngữ cảnh (đủ để debug, không lộ dữ liệu nhạy cảm).
|
|
16
|
+
- Tách rõ lỗi nghiệp vụ vs lỗi hệ thống.
|
|
17
|
+
- Validate input ở biên (boundary), tin tưởng dữ liệu bên trong.
|
|
18
|
+
|
|
19
|
+
## Comment & docs
|
|
20
|
+
- Comment giải thích "vì sao", không lặp "cái gì". Code tự diễn đạt được thì bỏ comment thừa.
|
|
21
|
+
|
|
22
|
+
## Test
|
|
23
|
+
- Logic nghiệp vụ phải có test; phủ cả happy path lẫn ca lỗi/biên.
|
|
24
|
+
- Tên test mô tả hành vi, không mô tả tên hàm.
|
|
25
|
+
|
|
26
|
+
## Format & Git
|
|
27
|
+
- Theo formatter/linter của repo (<!-- vd: Prettier+ESLint / gofmt -->); không tranh luận style thủ công.
|
|
28
|
+
- Commit nhỏ, message theo <!-- vd: Conventional Commits -->.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- Mục đích: thuật ngữ kỹ thuật + nghiệp vụ (đã gộp glossary & terminology). 1 dòng/khái niệm. -->
|
|
2
|
+
<!-- Hàng dưới là MẪU theo dự án CarePay. Xoá/sửa theo thuật ngữ thật của dự án bạn. -->
|
|
3
|
+
# Glossary
|
|
4
|
+
|
|
5
|
+
> Gộp thuật ngữ kỹ thuật và nghiệp vụ vào một nơi để tránh trùng lặp.
|
|
6
|
+
|
|
7
|
+
| Thuật ngữ | Nghĩa |
|
|
8
|
+
|---|---|
|
|
9
|
+
| CarePay | Nền tảng giúp bệnh nhân thanh toán viện phí (gồm trả góp) cho cơ sở y tế. |
|
|
10
|
+
| Provider | Cơ sở y tế (bệnh viện/phòng khám) nhận thanh toán. |
|
|
11
|
+
| Wallet | Số dư & lịch sử giao dịch của một người dùng (`wallets/{uid}`). |
|
|
12
|
+
| Payment | Một lần thanh toán cho Provider; có vòng đời `pending → succeeded/failed`. |
|
|
13
|
+
| Installment | Kế hoạch trả góp: chia một Payment thành nhiều kỳ. |
|
|
14
|
+
| Gen2 | Cloud Functions thế hệ 2 (chạy trên Cloud Run) — chuẩn backend của dự án. |
|
|
15
|
+
| Request (fn) | Function `onRequest` — endpoint HTTP, dùng cho webhook/đối tác ngoài. |
|
|
16
|
+
| On-call (fn) | Function `onCall` — callable, gọi từ app đã đăng nhập (tự verify Auth). |
|
|
17
|
+
| Trigger (fn) | Function chạy theo sự kiện (Firestore/Auth/Pub/Sub) — xử lý hệ quả phụ. |
|
|
18
|
+
| Idempotency key | Khoá để một thao tác gọi lặp không tạo hiệu ứng kép (vd webhook trùng). |
|
|
19
|
+
|
|
20
|
+
**Quy ước:** thêm từ mới vào đây thay vì giải thích lại trong nhiều file.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- Mục đích: stack + version. Chỉ liệt kê, KHÔNG giải thích. Giữ thật ngắn. -->
|
|
2
|
+
# Tech Stack — {{PROJECT_NAME}}
|
|
3
|
+
|
|
4
|
+
## Backend
|
|
5
|
+
- {{BACKEND}}
|
|
6
|
+
- Database: {{DATABASE}}
|
|
7
|
+
- Cache / Queue: <!-- vd: Redis 7 -->
|
|
8
|
+
|
|
9
|
+
## Frontend
|
|
10
|
+
- {{FRONTEND}}
|
|
11
|
+
- State: <!-- vd: Zustand / Redux Toolkit -->
|
|
12
|
+
- UI: <!-- vd: Tailwind + shadcn/ui -->
|
|
13
|
+
|
|
14
|
+
## Infra / DevOps
|
|
15
|
+
- Container: <!-- vd: Docker -->
|
|
16
|
+
- CI/CD: {{CICD}}
|
|
17
|
+
|
|
18
|
+
## Quy tắc version
|
|
19
|
+
- Không nâng major version nếu chưa ghi vào decisions/.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- Mục đích: 1 quyết định kiến trúc. Copy file này cho ADR mới. -->
|
|
2
|
+
<!-- Nội dung dưới là MẪU (CarePay). Thay bằng quyết định thật của dự án bạn. -->
|
|
3
|
+
# ADR-001: Xác thực bằng Firebase Auth + ID token
|
|
4
|
+
- **Trạng thái**: Accepted
|
|
5
|
+
- **Ngày**: 2024-01-15
|
|
6
|
+
- **Bối cảnh**: Cần xác thực người dùng cho web app và bảo vệ Cloud Functions; team nhỏ, không muốn tự vận hành hệ thống auth/quản lý mật khẩu.
|
|
7
|
+
- **Quyết định**: Dùng **Firebase Auth**. Client lấy ID token, đính kèm mỗi request. `onCall` tự verify token; `onRequest` verify thủ công qua Admin SDK. Phân quyền theo `uid` + custom claims (vd `role: admin`).
|
|
8
|
+
- **Phương án loại bỏ**: Tự xây JWT + bảng user (tốn công, dễ sai về bảo mật); Auth0 (chi phí & thêm nhà cung cấp ngoài hệ Firebase đang dùng).
|
|
9
|
+
- **Hệ quả**: Phụ thuộc Firebase; phân quyền phức tạp phải dùng custom claims (cần refresh token sau khi đổi claim); test cần Auth emulator.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- Mục đích: 1 quyết định kiến trúc. Copy file này cho ADR mới. -->
|
|
2
|
+
<!-- Nội dung dưới là MẪU (CarePay). Thay bằng quyết định thật của dự án bạn. -->
|
|
3
|
+
# ADR-002: Idempotency cho thanh toán & webhook
|
|
4
|
+
- **Trạng thái**: Accepted
|
|
5
|
+
- **Ngày**: 2024-02-02
|
|
6
|
+
- **Bối cảnh**: Client/đối tác có thể retry; webhook gateway gửi lại nhiều lần. Nếu xử lý trùng sẽ double-charge hoặc cộng số dư hai lần.
|
|
7
|
+
- **Quyết định**: Mỗi `createPayment` mang **idempotency key**; lưu key vào document `idempotency/{key}` và dùng **Firestore transaction** để "tạo nếu chưa có". Webhook khớp theo `gatewayRef` và chỉ chuyển trạng thái theo BR-003 (no-op nếu đã ở đích).
|
|
8
|
+
- **Phương án loại bỏ**: Redis/Memorystore làm khoá idempotency (thêm hạ tầng & chi phí, chưa cần ở quy mô hiện tại); khử trùng ở tầng app sau khi ghi (có khe hở race).
|
|
9
|
+
- **Hệ quả**: Mỗi mutation tiền bạc tốn thêm 1 lượt đọc/ghi khoá; logic phải bọc trong transaction; cần dọn document idempotency cũ theo TTL.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<!-- Mục đích: 1 quyết định kiến trúc. Copy file này cho ADR mới. -->
|
|
2
|
+
<!-- Nội dung dưới là MẪU (CarePay). Thay bằng quyết định thật của dự án bạn. -->
|
|
3
|
+
# ADR-003: Structured logging + correlation ID
|
|
4
|
+
- **Trạng thái**: Accepted
|
|
5
|
+
- **Ngày**: 2024-02-20
|
|
6
|
+
- **Bối cảnh**: Một thanh toán đi qua nhiều function (onCall → gateway → webhook → trigger); log dạng text rời rạc khó lần theo một giao dịch khi điều tra sự cố.
|
|
7
|
+
- **Quyết định**: Log **JSON có cấu trúc** ra stdout (Cloud Logging tự thu). Mỗi log mang `correlationId` (= `paymentId` hoặc request id) xuyên suốt các function; gồm `severity`, `event`, `uid`. **Cấm** log dữ liệu nhạy cảm (token, số thẻ, PII).
|
|
8
|
+
- **Phương án loại bỏ**: Log text tự do (khó query/đối soát); gửi sang dịch vụ log bên thứ ba (chưa cần, tốn chi phí).
|
|
9
|
+
- **Hệ quả**: Phải truyền `correlationId` qua các lớp; cần helper log chung để đồng nhất field; có checklist review chặn việc log PII (xem `workflows/code-review.md`).
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!-- Mục đích: mẫu request/response API chuẩn của dự án. -->
|
|
2
|
+
# API Example
|
|
3
|
+
|
|
4
|
+
> Mẫu REST theo convention mặc định (JSON). Đổi theo chuẩn thật của dự án nếu khác.
|
|
5
|
+
|
|
6
|
+
## `POST /api/v1/accounts/{id}/withdraw`
|
|
7
|
+
Rút tiền khỏi tài khoản.
|
|
8
|
+
|
|
9
|
+
**Request**
|
|
10
|
+
```json
|
|
11
|
+
{ "amount": 50000 }
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
**Response 200**
|
|
15
|
+
```json
|
|
16
|
+
{ "accountId": "acc_123", "balance": 150000 }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Lỗi** — body lỗi nhất quán: `code` (máy đọc) + `message` (người đọc).
|
|
20
|
+
```json
|
|
21
|
+
{ "error": { "code": "INSUFFICIENT_BALANCE", "message": "Số dư không đủ" } }
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
| HTTP | code | Khi nào |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| 400 | `VALIDATION_ERROR` | Input sai (amount <= 0) |
|
|
27
|
+
| 401 | `UNAUTHORIZED` | Thiếu/sai token |
|
|
28
|
+
| 404 | `ACCOUNT_NOT_FOUND` | Không có tài khoản |
|
|
29
|
+
| 409 | `INSUFFICIENT_BALANCE` | Số dư không đủ |
|
|
30
|
+
|
|
31
|
+
**Convention**: path dùng danh từ số nhiều; version trong path (`/v1`); HTTP status đúng ngữ nghĩa; không lộ stack trace ra response.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<!-- Mục đích: minh hoạ chuẩn code (load khi cần "mẫu để bắt chước"). -->
|
|
2
|
+
# Coding Example
|
|
3
|
+
|
|
4
|
+
> Mẫu theo stack mặc định **TypeScript** — minh hoạ `core/coding-standards.md`.
|
|
5
|
+
> Đổi sang ngôn ngữ thật của dự án nếu khác.
|
|
6
|
+
|
|
7
|
+
Tên rõ nghĩa · early return · tách lỗi nghiệp vụ/hệ thống · hàm nhỏ, không magic value.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// Lỗi nghiệp vụ tách khỏi lỗi hệ thống để caller xử lý khác nhau.
|
|
11
|
+
class InsufficientBalanceError extends Error {}
|
|
12
|
+
|
|
13
|
+
const MIN_WITHDRAWAL = 1; // đặt tên hằng, không magic number
|
|
14
|
+
|
|
15
|
+
interface Account { id: string; balance: number; }
|
|
16
|
+
|
|
17
|
+
/** Rút tiền khỏi tài khoản. Trả về số dư mới. */
|
|
18
|
+
export function withdraw(account: Account, amount: number): number {
|
|
19
|
+
// Validate ở biên, early return thay vì nesting sâu.
|
|
20
|
+
if (amount < MIN_WITHDRAWAL) {
|
|
21
|
+
throw new RangeError(`amount must be >= ${MIN_WITHDRAWAL}`);
|
|
22
|
+
}
|
|
23
|
+
if (amount > account.balance) {
|
|
24
|
+
throw new InsufficientBalanceError(`balance ${account.balance} < ${amount}`);
|
|
25
|
+
}
|
|
26
|
+
return account.balance - amount;
|
|
27
|
+
}
|
|
28
|
+
```
|