Published on

Day 08 - Backend CRUD với plan-first workflow

Authors

1. Mục tiêu bài học

Sau khoảng 2 tiếng, học viên có thể:

  • Dùng Claude Code theo workflow plan-first để xây dựng backend CRUD mà không để AI tự ý đổi architecture.
  • Chuyển yêu cầu mơ hồ như "thêm task CRUD" thành API contract rõ ràng: endpoint, request, response, status code, validation, error shape và logging.
  • Yêu cầu Claude Code đọc đúng module trong taskflow-ai, lập plan có bằng chứng, rồi mới implement.
  • Viết hoặc yêu cầu Claude Code viết unit test và integration test có assertion thật, không chỉ test happy path.
  • Review diff như senior backend reviewer: kiểm tra contract drift, behavior ngoài ý muốn, security, maintainability và rollback.
  • Quản lý permission, command và context để giảm rủi ro khi Claude Code được quyền sửa nhiều file backend.

2. Bối cảnh thực tế

Backend CRUD nhìn đơn giản nhưng trong project thật lại dễ bị AI làm quá tay. Với một prompt ngắn kiểu "create task CRUD API", Claude Code có thể tự thêm framework mới, đổi folder structure, tạo generic repository, đổi error format, viết route khác convention, hoặc thêm migration/schema ngoài scope. Nếu project taskflow-ai đã có pattern route/service/repository, hành vi đó làm code khó maintain và gây tranh chấp với các worker khác.

Vấn đề thường gặp trong team:

  • API contract chưa rõ nên mỗi endpoint trả lỗi một kiểu.
  • Validation nằm rải rác: lúc ở route, lúc ở service, lúc dựa vào database constraint.
  • Logging quá ít để debug, hoặc quá nhiều làm lộ PII/token.
  • Test chỉ kiểm tra status code, không kiểm tra body, validation, quyền truy cập hoặc error mapping.
  • Claude Code sửa nhiều file ngoài phạm vi vì developer không khóa architecture và file boundary.

Claude Code hữu ích khi bạn buộc nó đi theo vòng lặp có kiểm soát:

observe -> propose contract -> plan -> implement small slice -> test -> review diff -> adjust

Không nên dùng Claude Code để tự động implement CRUD khi:

  • Team chưa thống nhất API contract hoặc error format.
  • Module liên quan tới auth, billing, permission, production data hoặc migration phá dữ liệu.
  • Working tree đang có thay đổi của người khác mà bạn chưa hiểu.
  • Bạn chưa có cách verify: test command, database test, hoặc ít nhất contract checklist.
  • Bạn muốn quyết định kiến trúc lớn, ví dụ đổi Fastify sang NestJS, đổi ORM, đổi logging stack. Những việc này cần RFC/ADR riêng, không gộp vào CRUD.

3. Kiến thức nền

Plan-first workflow nghĩa là không bắt Claude Code sửa code trong prompt đầu tiên. Trước hết Claude phải đọc code liên quan, nêu bằng chứng, đề xuất contract và plan nhỏ. Developer duyệt plan, chỉnh scope, rồi mới cho implement. Đây là cách biến Claude Code từ "người viết code tự do" thành "pair engineer làm trong boundary".

Trong taskflow-ai, một API task CRUD tối thiểu thường có các phần sau. Tên file chỉ là ví dụ; hãy yêu cầu Claude đọc project thật trước khi dùng:

Thành phầnTrách nhiệmĐiều cần khóa trong plan
Route/controllerNhận HTTP request, parse input, gọi service, map responseKhông tự đổi framework hoặc route prefix hiện có
Validation schemaKiểm tra input tại boundaryKhông tin client; reject input sai trước khi vào business logic
Service/use caseÁp dụng business rule: trim title, status transition, ownershipKhông nhét SQL hoặc HTTP detail vào service nếu project không làm vậy
Repository/data accessĐọc/ghi database hoặc in-memory store theo pattern hiện cóKhông đổi ORM/query builder ngoài scope
Error handlerMap lỗi domain/validation/not found thành response thống nhấtKhông leak stack trace hoặc database detail
LoggerGhi event đủ debug: request id, task id, user id nếu có, latencyKhông log token, password, raw secret, payload nhạy cảm
TestUnit test business rule, integration test route contractKhông chỉ snapshot hoặc status code chung chung

API contract là tài liệu nhỏ mô tả hành vi public của API trước khi code. Contract không cần dài, nhưng phải đủ để review:

EndpointÝ nghĩaRequest chínhResponse thành côngLỗi cần có
POST /tasksTạo tasktitle, optional description, optional priority201 + task mới400 validation
GET /tasksDanh sách taskoptional filter/pagination theo pattern hiện có200 + list400 filter sai
GET /tasks/:idChi tiết taskpath id200 + task404 not found
PATCH /tasks/:idCập nhật một phầnfields được phép update200 + task mới400, 404, conflict nếu có
DELETE /tasks/:idXóa taskpath id204 hoặc 200 theo convention hiện có404

Điểm quan trọng: contract phải bám convention hiện có. Nếu taskflow-ai đang dùng 200 cho delete với body { success: true }, đừng để Claude tự đổi sang 204 chỉ vì phổ biến hơn. Nếu project đang dùng centralized error handler, không để Claude trả lỗi thủ công ở từng route.

Validation nên đặt ở HTTP boundary hoặc schema layer nếu project đã có. Business rule vẫn nên được test ở service. Ví dụ title sau khi trim không được rỗng là rule có thể kiểm tra ở schema và service tùy architecture, nhưng không nên để database là lớp đầu tiên phát hiện lỗi.

Error handling cần phân biệt:

  • Validation error: input sai, client có thể sửa.
  • Not found: task id không tồn tại hoặc không thuộc user hiện tại.
  • Conflict: trạng thái không hợp lệ, ví dụ reopen task đã archived nếu domain cấm.
  • Internal error: lỗi không mong muốn; response không leak stack trace, log nội bộ có correlation id.

Logging tốt cho CRUD không phải log mọi thứ. Log nên trả lời được: request nào, user nào nếu có, task id nào, action nào, kết quả gì, mất bao lâu. Không log raw authorization header, cookie, secret, hoặc payload dài có dữ liệu nhạy cảm.

4. Step-by-step thực hành

Mục tiêu thực hành: dùng Claude Code để tạo hoặc hoàn thiện API task CRUD trong backend taskflow-ai theo contract rõ ràng, có validation, error handling, logging và test. Nếu project của bạn chưa có backend hoặc module tasks, yêu cầu Claude Code đề xuất slice nhỏ nhất theo architecture hiện có, không tự dựng lại toàn bộ app.

Bước 1: Kiểm tra trạng thái và phạm vi repo

Chạy trong thư mục gốc taskflow-ai:

git status --short

Lệnh này hiển thị working tree ở dạng ngắn. Output kỳ vọng là rỗng hoặc chỉ có file bạn hiểu rõ. Rủi ro: nếu có thay đổi của worker khác hoặc thay đổi chưa review, bạn có thể nhầm diff của mình với diff của họ.

Nếu cần biết backend nằm ở đâu, chạy trong thư mục gốc taskflow-ai:

find . -maxdepth 3 -name package.json

Lệnh này tìm các package Node trong repo. Output kỳ vọng có thể là ./package.json hoặc ./backend/package.json. Rủi ro thấp vì đây là read-only, nhưng trên Windows PowerShell có thể cần lệnh tương đương như Get-ChildItem -Recurse -Filter package.json -Depth 3.

Nếu repo dùng Git branch, kiểm tra branch hiện tại:

git branch --show-current

Lệnh này in tên branch. Output kỳ vọng là branch feature, ví dụ feature/day-08-task-crud, không phải main. Rủi ro: làm trực tiếp trên branch chính khiến rollback và review khó hơn.

Bước 2: Mở Claude Code ở plan mode để đọc trước

Chạy trong thư mục gốc taskflow-ai:

claude --permission-mode plan

Lệnh này mở Claude Code ở mode phù hợp cho đọc, hiểu và lập plan trước khi sửa. Output kỳ vọng là session Claude Code sẵn sàng nhận prompt. Rủi ro thấp hơn implement mode, nhưng plan vẫn có thể sai nếu Claude đọc thiếu file hoặc suy diễn architecture.

Prompt khám phá:

Bạn đang ở repo taskflow-ai. Hãy khảo sát backend để tìm module hoặc convention liên quan tới tasks/todos, route, validation, error handling, logger và test.

Ràng buộc:
- Chưa sửa file.
- Chỉ đọc file cần thiết.
- Nêu rõ file đã đọc và bằng chứng từ code.
- Không đề xuất đổi framework, ORM, folder structure, logger hoặc error format.
- Nếu project chưa có module tasks, hãy chỉ ra nơi nhỏ nhất nên thêm module mới theo convention hiện có.

Kỳ vọng: Claude liệt kê file đã đọc, vẽ luồng request hiện tại, chỉ ra test framework và command dự kiến. Nếu Claude chưa đọc package.json, route registration hoặc test setup mà đã lập plan, yêu cầu đọc bổ sung.

Bước 3: Chốt API contract trước khi implement

Gửi prompt trong cùng session:

Từ các file đã đọc, hãy đề xuất API contract cho task CRUD.

Yêu cầu output:
- Bảng endpoint, method, path, request, response, status code.
- Validation rule cho title, description, status/priority nếu có.
- Error shape phải bám pattern hiện có; nếu chưa có pattern, đề xuất một format tối thiểu và nêu rõ trade-off.
- Logging event cần có và field không được log.
- Test cases unit và integration tối thiểu.
- Chưa sửa file.

Kỳ vọng: contract đủ cụ thể để reviewer bắt lỗi trước khi code. Nếu Claude đề xuất thêm pagination, auth, assignee, audit log hoặc status workflow phức tạp ngoài yêu cầu, yêu cầu cắt scope về CRUD task cơ bản.

Bước 4: Lập plan file-by-file

Prompt lập plan:

Lập plan implement API task CRUD theo contract đã duyệt.

Ràng buộc:
- Plan tối đa 7 bước.
- Mỗi bước ghi file dự kiến sửa hoặc tạo.
- Không đổi architecture hiện có.
- Không thêm dependency nếu chưa có lý do rõ và chưa được approve.
- Không tạo migration trong Day 08 nếu project chưa học Day 09; nếu cần data layer, dùng pattern test/dev hiện có hoặc ghi TODO rõ.
- Chờ tôi approve trước khi edit.

Plan tốt thường có dạng:

1. Thêm/hoàn thiện validation schema cho task request.
2. Thêm route handlers CRUD theo route registration hiện có.
3. Thêm service method với business rule tối thiểu.
4. Dùng repository/data access hiện có; không đổi database contract.
5. Map lỗi validation/not found bằng error handler hiện có.
6. Thêm unit test cho service validation và not found.
7. Thêm integration test cho route contract.

Nếu plan chạm quá nhiều file, yêu cầu Claude chia thành slice:

Plan này quá rộng. Hãy chia thành slice 1 chỉ gồm POST /tasks và GET /tasks/:id, có test. Không implement.

Bước 5: Cho implement với permission và boundary hẹp

Sau khi duyệt plan, mở Claude Code ở mode kiểm soát. Chạy trong thư mục gốc taskflow-ai:

claude --permission-mode default --tools "Read,Write,Edit,Bash" --allowedTools "Bash(git status *)" "Bash(git diff *)"

Lệnh này giới hạn built-in tool family vào Read, Write, Edit, Bash, đồng thời auto-approve riêng git statusgit diff. Output kỳ vọng là session sẵn sàng. Rủi ro: --allowedTools không deny Bash command khác; command ngoài pattern sẽ phải hỏi theo default mode. Nếu mở rộng thành Bash(*) hoặc auto-approve quá rộng, Claude có thể chạy install, migration hoặc command tốn thời gian ngoài plan.

Prompt implement:

Implement theo plan đã duyệt cho API task CRUD.

Ràng buộc bắt buộc:
- Chỉ sửa/tạo các file đã liệt kê trong plan.
- Không đổi framework, architecture, folder convention, error format hoặc logger format.
- Không thêm dependency mới.
- Không chạy npm install, migration, docker command, git add, git commit, git reset, git clean hoặc lệnh xóa file.
- Nếu gặp thiếu thông tin, dừng và hỏi thay vì tự quyết.
- Sau khi edit, tóm tắt diff theo file và nêu test command tôi nên chạy.

Kỳ vọng: Claude tạo patch theo plan, không tự commit, không đổi scope. Nếu Claude muốn sửa README, config global, schema database hoặc file ngoài plan, từ chối và yêu cầu giải thích.

Bước 6: Chạy test có kiểm soát

Trước khi chạy test, đọc package.json để biết script thật. Các command dưới đây là ví dụ phổ biến; chạy trong folder có package.json của backend, có thể là taskflow-ai/backend hoặc root nếu backend package nằm ở root.

npm run test -- --run

Lệnh này thường chạy test một lần thay vì watch mode nếu project dùng Vitest. Output kỳ vọng là các test pass và process exit code 0. Rủi ro: nếu script test trỏ vào database local, hãy chắc chắn đang dùng database dev/test, không phải production.

npm run test:unit -- tasks

Lệnh này là ví dụ cho unit test tập trung vào module tasks nếu project có script tương ứng. Output kỳ vọng là test service/validation pass. Rủi ro: script có thể không tồn tại; không để Claude tự thêm script chỉ để command này chạy nếu project đã có convention khác.

npm run test:integration -- tasks

Lệnh này là ví dụ cho integration test route contract nếu project có script tương ứng. Output kỳ vọng là request POST, GET, PATCH, DELETE trả đúng status/body. Rủi ro: integration test có thể cần database test, Docker hoặc seed data; không chạy nếu môi trường chưa rõ.

Nếu test fail, không cho Claude sửa ngay. Đưa failure output vào prompt review:

Test fail như sau. Hãy phân tích nguyên nhân trước, chưa sửa file.
Phân loại: bug trong implementation, test sai contract, thiếu setup, hay môi trường.
Đề xuất patch nhỏ nhất và file cần sửa.

Bước 7: Review diff như reviewer

Chạy trong thư mục gốc taskflow-ai:

git diff --stat

Lệnh này cho biết số file và số dòng thay đổi. Output kỳ vọng khớp file list trong plan. Rủi ro: --stat không cho thấy logic, chỉ dùng để phát hiện patch rộng bất thường.

git diff

Lệnh này hiển thị patch chi tiết. Output kỳ vọng: route contract đúng, validation rõ, error mapping bám convention, logging không lộ secret, test có assertion meaningful. Rủi ro: diff dài dễ bỏ sót behavior change; hãy xem theo file nếu cần.

Ví dụ xem một file:

git diff -- backend/src/tasks/task.routes.ts

Lệnh này giới hạn diff vào file route ví dụ. Output kỳ vọng chỉ có route CRUD theo plan. Rủi ro thấp vì read-only; thay path theo file thật trong repo.

Prompt review:

Review diff hiện tại như senior backend reviewer.

Tập trung:
- API contract có bị đổi ngoài plan không.
- Validation có reject input xấu nhưng không duplicate quá mức không.
- Error response có thống nhất với project không.
- Logging có đủ debug nhưng không lộ secret/PII không.
- Test có kiểm tra body, edge case và error path không.
- Có file nào ngoài plan bị chạm không.

Không sửa file trong bước review này.

Bước 8: Rollback an toàn nếu patch sai

Trước khi rollback, luôn xem file nào bị thay đổi:

git status --short

Lệnh này giúp xác định file đang modified/untracked. Output kỳ vọng chỉ gồm file của Day 08 hoặc task hiện tại. Rủi ro: nếu có file của người khác, không rollback toàn repo.

Rollback một file đã review:

git restore -- backend/src/tasks/task.routes.ts

Lệnh này đưa file tracked về trạng thái trong Git. Chạy ở root repo. Output thường rỗng nếu thành công. Rủi ro: mất toàn bộ thay đổi chưa commit trong file đó, kể cả thay đổi bạn tự viết.

Xóa file mới tạo sai chỉ khi chắc chắn file đó do bạn/Claude tạo trong task này:

git clean -f -- backend/src/tasks/task.routes.ts

Lệnh này xóa untracked file cụ thể. Chạy ở root repo. Output kỳ vọng là tên file bị remove. Rủi ro cao hơn git restore vì xóa file chưa tracked; không dùng dạng rộng như git clean -fd trong repo có nhiều worker.

Không chạy các lệnh này theo đề xuất tự động của Claude nếu chưa tự quyết định:

git reset --hard
git clean -fd
docker compose down -v
rm -rf backend/src

Các lệnh này có thể làm mất thay đổi của bạn hoặc worker khác, xóa volume database, hoặc xóa source. Với repo nhiều worker, rollback phải theo file, không rollback toàn working tree.

5. Prompt mẫu nên dùng

Prompt khám phá codebase

Hãy đọc backend taskflow-ai để hiểu convention trước khi thêm task CRUD.

Yêu cầu:
- Chỉ đọc file, chưa sửa.
- Nêu rõ file đã đọc và bằng chứng.
- Tìm route registration, validation pattern, error handler, logger, test setup.
- Nếu chưa có module tasks, tìm module tương tự nhất để bắt chước.
- Không đề xuất đổi framework hoặc architecture.

Prompt lập API contract

Hãy viết API contract cho task CRUD theo convention hiện có.

Output cần có:
- Endpoint/method/path.
- Request body/query/path params.
- Response success và status code.
- Error cases: validation, not found, conflict nếu có.
- Validation rule cụ thể cho title/description/status.
- Logging event và field không được log.
- Test cases tối thiểu.

Chưa implement.

Prompt lập plan file-by-file

Tạo implementation plan cho contract đã duyệt.

Ràng buộc:
- Tối đa 7 bước.
- Mỗi bước ghi file sẽ sửa/tạo.
- Không thêm dependency.
- Không đổi architecture, folder structure, error format hoặc logger.
- Nếu cần thay đổi database schema, dừng lại và đề xuất chuyển sang Day 09.
- Chờ tôi approve trước khi sửa.

Prompt implement

Implement task CRUD theo plan đã approve.

Giới hạn:
- Chỉ chạm file trong plan.
- Không chạy install, migration, docker, git add/commit/reset/clean, hoặc lệnh xóa file.
- Bám API contract đã duyệt.
- Viết unit test cho business rule và integration test cho route contract theo pattern hiện có.
- Nếu không chắc convention, hỏi lại trước.
- Sau khi xong, tóm tắt diff và test command cần chạy.

Prompt review diff

Review diff hiện tại như senior backend reviewer, không sửa file.

Kiểm tra:
- Contract drift.
- Validation edge cases: title rỗng, title chỉ có khoảng trắng, id sai format, update body rỗng.
- Error handling có thống nhất không.
- Logging có leak dữ liệu nhạy cảm không.
- Test có meaningful assertion không.
- Có thay đổi architecture hoặc dependency ngoài scope không.

Kết luận theo format: Blocker, Should fix, Nice to have, Test gaps.

Prompt viết test trước khi sửa tiếp

Hãy đề xuất test bổ sung cho task CRUD trước khi sửa code tiếp.

Ràng buộc:
- Đọc pattern test hiện có.
- Chỉ đề xuất test cases và file cần sửa.
- Ưu tiên assertion về contract: status code, response body, error code, database side effect.
- Không tạo snapshot rộng.
- Chưa edit file.

6. Trade-offs

Plan-first chậm hơn implement-first vì phải tách các bước đọc, contract, plan và implement. Đổi lại, nó giảm rủi ro Claude sửa nhầm architecture, đặc biệt khi CRUD chạm nhiều lớp backend.

Contract-first buộc bạn quyết định status code và error shape trước. Nhược điểm là phải suy nghĩ nhiều hơn trước khi code. Lợi ích là test rõ hơn, frontend ít bị đổi bất ngờ, và reviewer có tiêu chuẩn khách quan để bắt lỗi.

Viết cả unit test và integration test tốn thời gian hơn chỉ viết route test. Unit test giúp khóa business rule như trim title, update body rỗng, status transition. Integration test giúp khóa HTTP contract và error mapping. Với feature CRUD public, cả hai loại test đều đáng có.

Không thêm dependency mới làm implementation có thể dài hơn một chút, nhưng giữ maintainability. Với Day 08, mục tiêu là dùng pattern hiện có; đổi validation library, logger hoặc ORM là quyết định architecture, không phải chi tiết CRUD.

Logging nhiều giúp debug production, nhưng tăng rủi ro lộ dữ liệu và tăng noise. Log event cấp cao, id và metadata đủ truy vết; không log raw request body nếu body có thể chứa secret hoặc dữ liệu cá nhân.

7. Best practices

  • Luôn bắt đầu bằng plan mode cho CRUD mới vì task chạm route, validation, service, data access và test.
  • Bắt Claude nêu "file đã đọc" và "bằng chứng từ code"; không accept plan dựa trên suy đoán.
  • Chốt API contract trước khi implement, kể cả khi contract chỉ là bảng ngắn trong chat.
  • Ghi rõ "không đổi architecture" trong prompt implement. Cấm tự thêm dependency, đổi framework, đổi ORM, đổi logger hoặc đổi error format.
  • Dùng CLAUDE.md để giữ convention lâu dài: folder structure, scripts, test rules, error response, logging rule, command bị cấm.
  • Với command quyền cao, dùng permission mode default, --tools để giới hạn tool family và --allowedTools chỉ cho command thật sự muốn auto-approve. Không dùng bypassPermissions trên repo thật.
  • Không đưa .env, token, production credential, customer payload hoặc database dump vào prompt.
  • Với CRUD có auth/tenant boundary, test bắt buộc phải có case "user không được đọc/sửa task của user khác".
  • Sau mỗi patch, chạy git diff --stat trước, rồi review diff chi tiết. Nếu file ngoài plan bị chạm, dừng implement.
  • Rollback theo file. Không dùng git reset --hard hoặc git clean -fd trong repo nhiều worker.
  • Không để Claude tự commit. Commit message và PR description có thể nhờ Claude soạn sau khi human review.

8. Performance / cost / context

CRUD backend dễ làm phình context vì Claude có thể đọc route, schema, service, repository, tests, config, migration và docs. Tối ưu không phải là nhồi toàn repo vào prompt, mà là ép Claude đọc đúng file.

Cách giảm token và chi phí:

  • Prompt khám phá chỉ yêu cầu module liên quan: route registration, validation, error handler, logger, test setup.
  • Yêu cầu Claude tóm tắt contract và plan ngắn trước khi edit; không để nó tạo bài giải dài trong mỗi lượt.
  • Chia feature thành slice nếu module lớn: POST + GET detail trước, sau đó LIST + PATCH + DELETE.
  • Khi test fail, chỉ đưa failure output liên quan, không paste toàn bộ log nếu log quá dài.
  • Dùng /compact hoặc summary thủ công khi session dài: giữ contract, file list, test command, quyết định đã duyệt.
  • Dùng custom slash command cho review/test nếu team lặp lại workflow, ví dụ command read-only để review diff với allowed-tools: Read, Bash(git status *), Bash(git diff *).

Performance runtime của API cũng cần được nhắc trong contract:

  • GET /tasks nên có pagination hoặc limit theo convention nếu danh sách có thể lớn.
  • Không log payload lớn trong loop hoặc mỗi row.
  • Không gọi database nhiều lần trong route list nếu repository có thể query một lần.
  • Integration test không nên phụ thuộc timing hoặc sleep dài; dùng setup/teardown rõ.

9. Checklist cuối bài

  • Tôi đã kiểm tra git status --short trước khi cho Claude Code sửa.
  • Tôi đã dùng plan mode để Claude đọc backend và nêu file đã đọc.
  • Tôi có API contract cho task CRUD trước khi implement.
  • Tôi đã khóa scope: không đổi architecture, không thêm dependency, không đổi error/logger format.
  • Tôi đã yêu cầu validation cho title rỗng/whitespace, id sai format và update body rỗng nếu phù hợp.
  • Tôi đã yêu cầu error handling thống nhất với project.
  • Tôi đã yêu cầu logging đủ debug nhưng không log secret/PII.
  • Tôi có unit test cho business rule và integration test cho route contract.
  • Tôi đã review git diff --statgit diff.
  • Tôi biết rollback theo file và tránh lệnh phá working tree của người khác.

10. Bài tập

Bài cơ bản: mở taskflow-aiclaude --permission-mode plan, yêu cầu Claude khảo sát backend và viết API contract cho task CRUD. Không cho sửa file. Kết quả cần có: file đã đọc, contract, validation rule, error shape, logging rule và test plan.

Bài nâng cao: sau khi duyệt contract, cho Claude implement slice nhỏ đầu tiên: POST /tasksGET /tasks/:id kèm unit/integration test. Giới hạn file theo plan, không thêm dependency, không migration. Review diff và ghi lại ít nhất 3 điểm bạn reject hoặc yêu cầu sửa.

Bài áp dụng project cá nhân: chọn một CRUD nhỏ trong repo cá nhân hoặc repo sandbox. Viết prompt theo format Context, Goal, Contract, Constraints, Acceptance Criteria, Verification. So sánh output khi prompt có contract và khi prompt chỉ nói "create CRUD API". Ghi lại khác biệt về số file sửa, chất lượng test và contract drift.


Tài liệu

Tóm tắt kiến thức

Day 08 tập trung vào backend CRUD nhưng trọng tâm thật sự là workflow kiểm soát Claude Code. CRUD là bài test tốt vì nó chạm nhiều lớp: route, validation, service, repository, error handling, logging và test. Nếu không có plan-first, Claude dễ tạo patch rộng, đổi architecture hoặc tự chọn API contract khác với project.

Nguyên tắc chính:

  • Bắt đầu bằng plan mode để Claude đọc và hiểu trước khi sửa.
  • Chốt API contract trước khi implement: endpoint, request, response, status code, error shape, validation và logging.
  • Không để Claude tự thêm dependency, đổi framework, đổi ORM, đổi logger, đổi error format hoặc tạo migration nếu chưa được approve.
  • Implement theo slice nhỏ, có file list rõ.
  • Unit test khóa business rule; integration test khóa HTTP contract.
  • Review diff trước khi accept; rollback theo file nếu patch sai.

Contract tham khảo cho taskflow-ai:

EndpointThành côngValidation/error tối thiểuGhi chú maintainability
POST /tasks201 + task mới theo conventiontitle required, trim không rỗng, body field lạ xử lý theo pattern hiện cóKhông tự thêm field ngoài contract
GET /tasks200 + danh sáchfilter/pagination sai trả validation error nếu có filterCó limit/pagination nếu project đã có pattern
GET /tasks/:id200 + taskid sai format hoặc task không tồn tạiKhông leak thông tin task của user khác nếu có auth
PATCH /tasks/:id200 + task đã updateupdate body rỗng, field không được phép, title whitespaceKhông cho update id/owner/system field
DELETE /tasks/:id204 hoặc response hiện cónot foundBám convention hiện có, không đổi tùy ý

Sơ đồ tư duy hoặc luồng xử lý

Yêu cầu CRUD
  |
  v
Git state sạch?
  |
  +-- Không -> dừng, đọc diff, tách thay đổi người khác
  |
  v
Claude Code plan mode
  |
  v
Đọc backend convention
  |
  +-- route registration
  +-- validation schema
  +-- error handler
  +-- logger
  +-- test setup
  |
  v
API contract
  |
  +-- endpoints
  +-- request/response
  +-- status codes
  +-- validation
  +-- error shape
  +-- logging fields
  |
  v
Plan file-by-file
  |
  v
Developer approve
  |
  v
Implement slice nhỏ
  |
  v
Unit test + integration test
  |
  v
git diff --stat -> git diff
  |
  v
Review: contract, security, maintainability, performance
  |
  +-- Đạt -> commit thủ công / PR
  |
  +-- Sai -> rollback theo file hoặc yêu cầu patch nhỏ

Luồng prompt nên dùng:

Explore/read-only
  -> Contract
  -> Plan file-by-file
  -> Implement with boundaries
  -> Test diagnosis
  -> Diff review

Bảng so sánh

Cách làmLợi íchRủi roKhi dùng
Implement-firstNhanh ở demo nhỏContract drift, patch rộng, đổi architectureChỉ dùng trong sandbox throwaway
Plan-firstKiểm soát scope và file listTốn thêm lượt chatDefault cho repo team
Contract-firstTest và frontend rõ ràngCần quyết định trướcAPI public hoặc có nhiều consumer
Test-afterDễ bắt đầuCó thể test theo implementation saiTask nhỏ, contract đã rõ
Test-first hoặc test-plan-firstKhóa behavior trướcTốn công thiết kế assertionCRUD quan trọng, bug fix, regression
Chủ đềNên làmKhông nên làm
ValidationValidate ở boundary theo schema/convention hiện có; service giữ business rule quan trọngĐể database là nơi đầu tiên báo lỗi input
Error handlingDùng centralized error handler hoặc pattern hiện cóMỗi route tự format lỗi một kiểu
LoggingLog action, id, request id, user id nếu có, duration, outcomeLog raw token, password, cookie, secret hoặc body nhạy cảm
ArchitectureBắt chước module tương tự trong projectThêm framework/ORM/repository pattern mới
TestUnit test rule, integration test contractChỉ snapshot hoặc chỉ kiểm tra status code
Rollbackgit restore -- path cho tracked file, git clean -f -- path cho file mới đã reviewgit reset --hard, git clean -fd trong repo có nhiều worker
CommandChạy ở đâuDùng để làm gìOutput kỳ vọngRủi ro
git status --shortRoot taskflow-aiKiểm tra working treeRỗng hoặc file đã hiểuBỏ sót thay đổi của worker khác nếu không đọc
claude --permission-mode planRoot taskflow-aiMở session đọc/lập planClaude sẵn sàng nhận promptPlan sai nếu đọc thiếu file
git diff --statRoot taskflow-aiXem phạm vi patchFile list khớp planKhông thấy logic chi tiết
git diffRoot taskflow-aiReview patchDiff đúng contractDiff dài dễ bỏ sót
npm run test -- --runFolder có package.json backendChạy test một lần nếu script hỗ trợTest pass, exit code 0Có thể phụ thuộc database/test env
git restore -- path/to/fileRoot taskflow-aiRollback tracked fileKhông output nếu thành côngMất thay đổi chưa commit trong file đó

Lỗi thường gặp

  1. Prompt "create CRUD API" quá rộng
    Claude có thể tự tạo architecture mới, đổi route prefix hoặc thêm dependency. Cách sửa: yêu cầu đọc module tương tự và lập plan file-by-file trước.

  2. Không chốt error shape
    Endpoint này trả { error: "..." }, endpoint khác trả { message, code }. Cách sửa: bắt Claude tìm error handler hiện có và bám pattern.

  3. Validation chỉ có happy path
    Test tạo task thành công nhưng không test title whitespace, body rỗng, id sai format, field không được phép. Cách sửa: contract phải liệt kê negative cases.

  4. Logging lộ dữ liệu
    Claude có thể log raw request body để debug. Cách sửa: prompt rõ field được log và field bị cấm; review diff tìm authorization, cookie, password, token, secret.

  5. Integration test phụ thuộc database thật
    Test có thể dùng connection string từ .env dev hoặc production. Cách sửa: đọc test setup trước, yêu cầu Claude không chạm production data, không chạy migration destructive.

  6. Patch vượt scope nhưng test vẫn pass
    Test pass không có nghĩa architecture đúng. Cách sửa: review git diff --stat, so với file list trong plan.

  7. Rollback toàn repo
    Trong môi trường nhiều worker, git reset --hard có thể xóa thay đổi của người khác. Cách sửa: rollback theo file đã review.

Cách debug

Khi Claude Code tạo patch quá rộng:

git diff --stat

Chạy ở root taskflow-ai. Lệnh này cho biết file nào bị chạm. Nếu output có file ngoài plan, dừng implement và yêu cầu Claude giải thích trước khi sửa tiếp.

Patch đang chạm file ngoài plan. Hãy giải thích vì sao từng file cần thay đổi.
Không sửa thêm. Đề xuất cách thu hẹp patch về contract ban đầu.

Khi test fail:

  1. Chạy test tập trung trong folder backend có package.json, ví dụ:
npm run test -- --run tasks

Lệnh này cố gắng chạy test liên quan tới tasks nếu test runner hỗ trợ filter. Output kỳ vọng là danh sách test pass/fail liên quan. Rủi ro: syntax filter phụ thuộc script; đọc package.json trước nếu không chắc.

  1. Đưa failure ngắn vào Claude:
Đây là failure output. Hãy phân tích nguyên nhân, chưa sửa file.
Phân loại: implementation bug, test sai contract, thiếu setup, hay môi trường.
Chỉ đề xuất patch nhỏ nhất.
  1. Nếu lỗi do contract không rõ, quay lại bước contract. Không vá test cho pass nếu behavior chưa đúng.

Khi nghi ngờ contract drift:

  • So sánh diff với bảng endpoint/status code đã duyệt.
  • Kiểm tra response body của success và error.
  • Tìm các thay đổi ở file config, dependency, route prefix hoặc global error handler.
  • Yêu cầu Claude review read-only:
So sánh diff hiện tại với API contract đã duyệt.
Liệt kê mọi điểm drift, phân loại blocker/should fix/nice to have.
Không sửa file.

Khi cần rollback:

git restore -- path/to/tracked-file

Chạy ở root taskflow-ai. Lệnh này rollback một tracked file. Rủi ro: mất thay đổi chưa commit trong file đó.

git clean -f -- path/to/new-file

Chạy ở root taskflow-ai. Lệnh này xóa một untracked file cụ thể. Chỉ dùng sau khi chắc chắn file đó do task hiện tại tạo và không phải file của worker khác.


Bài tập

Bài 1 — Cơ bản

Mục tiêu: dùng Claude Code ở plan mode để khảo sát backend và viết API contract cho task CRUD, chưa sửa file.

Yêu cầu:

  1. Mở terminal tại thư mục gốc taskflow-ai.
  2. Kiểm tra working tree:
git status --short

Lệnh này chạy ở root repo để xem file đang thay đổi. Output kỳ vọng là rỗng hoặc chỉ có file bạn hiểu rõ. Rủi ro: nếu có file lạ, bạn có thể chồng diff lên thay đổi của người khác; dừng lại và đọc trước.

  1. Mở Claude Code ở plan mode:
claude --permission-mode plan

Lệnh này chạy ở root repo để mở Claude Code trong workflow đọc/lập plan. Output kỳ vọng là session sẵn sàng. Rủi ro thấp hơn implement mode, nhưng Claude vẫn có thể suy diễn nếu đọc thiếu file.

  1. Gửi prompt:
Bạn đang ở repo taskflow-ai. Hãy khảo sát backend để chuẩn bị API task CRUD.

Ràng buộc:
- Chỉ đọc file, chưa sửa.
- Nêu rõ file đã đọc và bằng chứng.
- Tìm route registration, validation pattern, error handler, logger và test setup.
- Nếu project chưa có module tasks, tìm module tương tự nhất để bắt chước.
- Không đề xuất đổi framework, ORM, folder structure, logger hoặc error format.
  1. Yêu cầu Claude viết contract:
Hãy viết API contract cho task CRUD dựa trên convention vừa đọc.

Contract phải có:
- Endpoint/method/path.
- Request body/query/path params.
- Response success và status code.
- Error cases: validation, not found, conflict nếu phù hợp.
- Validation rule cho title, description, status/priority nếu có.
- Logging event và field không được log.
- Unit test và integration test tối thiểu.

Chưa implement.

Kết quả cần nộp: bảng API contract, file list Claude đã đọc, test cases dự kiến, và 3 rủi ro nếu implement ngay không có plan.

Bài 2 — Thực tế

Mục tiêu: implement slice đầu tiên của task CRUD với boundary rõ, có validation/error/logging/test.

Phạm vi đề xuất: POST /tasksGET /tasks/:id. Nếu project đã có hai endpoint này, chọn PATCH /tasks/:idDELETE /tasks/:id.

Yêu cầu:

  1. Từ contract ở Bài 1, yêu cầu Claude lập plan file-by-file:
Lập plan implement slice đầu tiên của task CRUD: POST /tasks và GET /tasks/:id.

Ràng buộc:
- Tối đa 6 bước.
- Mỗi bước ghi file sẽ sửa/tạo.
- Không thêm dependency.
- Không đổi architecture, folder structure, error format hoặc logger.
- Không tạo migration trong bài này.
- Chờ tôi approve trước khi edit.
  1. Sau khi approve plan, mở session implement:
claude --permission-mode default --tools "Read,Write,Edit,Bash" --allowedTools "Bash(git status *)" "Bash(git diff *)"

Lệnh này chạy ở root taskflow-ai để giới hạn tool family vào đọc/sửa file và Bash, đồng thời auto-approve riêng Git read-only. Output kỳ vọng là session sẵn sàng. Rủi ro: nếu allowlist mở rộng quá mức, Claude có thể chạy command ngoài plan mà không hỏi.

  1. Gửi prompt implement:
Implement theo plan đã duyệt.

Ràng buộc bắt buộc:
- Chỉ chạm file trong plan.
- Bám API contract đã duyệt.
- Không thêm dependency.
- Không chạy npm install, migration, docker command, git add, git commit, git reset, git clean hoặc lệnh xóa file.
- Validation: title sau khi trim không được rỗng.
- Error handling phải theo pattern hiện có.
- Logging không được log token, cookie, password, secret hoặc raw request body nhạy cảm.
- Viết unit test cho business rule và integration test cho route contract nếu project đã có pattern test.
- Nếu thiếu thông tin, dừng và hỏi.
  1. Review phạm vi patch:
git diff --stat

Lệnh này chạy ở root repo để xem số file/dòng thay đổi. Output kỳ vọng khớp file trong plan. Rủi ro: nếu xuất hiện file ngoài plan, dừng lại và yêu cầu Claude giải thích.

  1. Review chi tiết:
git diff

Lệnh này chạy ở root repo để xem patch chi tiết. Output kỳ vọng: endpoint đúng contract, validation rõ, error response thống nhất, log không lộ dữ liệu nhạy cảm, test có assertion cụ thể. Rủi ro: diff dài dễ bỏ sót; xem từng file nếu cần.

  1. Chạy test theo script thật trong backend. Ví dụ nếu backend package dùng Vitest:
npm run test -- --run

Lệnh này chạy ở folder có package.json backend. Output kỳ vọng là test pass và exit code 0. Rủi ro: test có thể phụ thuộc database test; kiểm tra .env.test hoặc setup tương đương, không dùng production credential.

Kết quả cần nộp: diff summary, test command đã chạy, output chính, và danh sách issue còn lại nếu có.

Bài 3 — Nâng cao

Mục tiêu: hoàn thiện CRUD còn lại, thêm integration test quan trọng và review contract drift.

Yêu cầu:

  1. Yêu cầu Claude chỉ review trạng thái hiện tại:
Review task CRUD hiện tại so với API contract Day 08.
Chưa sửa file.
Liệt kê endpoint đã đủ, endpoint thiếu, validation thiếu, error handling thiếu, logging thiếu và test gap.
Phân loại theo Blocker, Should fix, Nice to have.
  1. Chọn phần thiếu có giá trị nhất, ví dụ PATCH /tasks/:idDELETE /tasks/:id. Yêu cầu plan:
Lập plan bổ sung PATCH /tasks/:id và DELETE /tasks/:id.

Ràng buộc:
- Không đổi contract endpoint đã có.
- Không đổi schema database.
- Không thêm dependency.
- Không refactor rộng.
- Thêm integration test cho success và not found.
- Thêm validation cho update body rỗng và title whitespace nếu update title.
- Chờ tôi approve trước khi sửa.
  1. Cho implement sau khi approve, vẫn giữ --tools--allowedTools hẹp như Bài 2.

  2. Chạy test tập trung nếu project hỗ trợ filter:

npm run test -- --run tasks

Lệnh này chạy ở folder backend có package.json để chạy test liên quan tới tasks nếu script hỗ trợ filter. Output kỳ vọng là test task CRUD pass. Rủi ro: cú pháp filter phụ thuộc test runner/script; nếu không hỗ trợ, dùng script test chuẩn của project.

  1. Yêu cầu Claude review diff read-only:
Review diff hiện tại, không sửa file.

Tập trung:
- Có contract drift không.
- Có endpoint nào trả status/body khác contract không.
- Có logging nào leak dữ liệu không.
- Có test nào chỉ kiểm tra happy path không.
- Có thay đổi architecture/dependency ngoài scope không.
  1. Nếu patch sai, rollback theo file đã review:
git restore -- path/to/tracked-file

Lệnh này chạy ở root repo để rollback một tracked file. Output thường rỗng nếu thành công. Rủi ro: mất thay đổi chưa commit trong file đó; không dùng nếu file có thay đổi của người khác.

Nếu có file mới tạo sai và chắc chắn là của task này:

git clean -f -- path/to/new-file

Lệnh này chạy ở root repo để xóa một untracked file cụ thể. Output kỳ vọng là file bị remove. Rủi ro: xóa vĩnh viễn file chưa tracked; không dùng dạng rộng.

Kết quả cần nộp: endpoint còn thiếu đã hoàn thiện, test bổ sung, review diff read-only và quyết định accept/reject.

Bài 4 — Review & Reflection

Mục tiêu: biến bài CRUD thành rule làm việc cho team.

Trả lời các câu hỏi:

  1. API contract cuối cùng của task CRUD gồm endpoint nào, status code nào, error shape nào?
  2. Claude Code có đề xuất đổi architecture, thêm dependency hoặc sửa file ngoài plan không? Bạn xử lý thế nào?
  3. Test nào có giá trị nhất trong bài này: unit hay integration? Vì sao?
  4. Logging hiện tại có đủ debug chưa? Có field nào bạn cấm log không?
  5. Nếu frontend Day 10 dùng API này, contract nào cần ổn định nhất?
  6. Bạn sẽ thêm rule gì vào CLAUDE.md để các task backend sau không bị patch rộng?

Gợi ý prompt reflection:

Dựa trên Day 08, hãy giúp tôi viết 10 rule backend workflow cho CLAUDE.md của taskflow-ai.

Yêu cầu:
- Rule phải cụ thể cho CRUD/API.
- Có rule về plan-first, API contract, validation, error handling, logging, test và rollback.
- Có danh sách command không được tự chạy.
- Không viết chung chung.

Kết quả cần nộp: reflection ngắn 10-15 dòng và rule đề xuất cho CLAUDE.md.

Tiêu chí hoàn thành

  • Đã dùng claude --permission-mode plan để khảo sát trước khi sửa.
  • Có API contract rõ cho task CRUD.
  • Plan implement có file list, không đổi architecture, không thêm dependency ngoài duyệt.
  • Có validation cho title rỗng/whitespace và các edge case phù hợp với contract.
  • Error handling bám pattern hiện có của project.
  • Logging đủ truy vết nhưng không log secret/PII/raw payload nhạy cảm.
  • Có unit test cho business rule và integration test cho route contract, hoặc có lý do rõ nếu project chưa có test setup.
  • Đã chạy test command phù hợp và ghi lại output chính.
  • Đã review git diff --statgit diff.
  • Biết rollback theo file, không dùng command phá toàn working tree.

Gợi ý nếu bí

Nếu Claude không tìm được backend:

Hãy tìm các file package.json, route entrypoint, server bootstrap hoặc module tương tự todo/task.
Chỉ đọc file.
Nếu repo chưa có backend, hãy đề xuất cấu trúc tối thiểu theo README hiện có, chưa tạo file.

Nếu Claude đề xuất đổi architecture:

Không đổi architecture trong Day 08.
Hãy viết lại plan bằng cách bắt chước module gần nhất trong project.
Chỉ nêu file cần sửa/tạo và lý do.
Không implement.

Nếu contract chưa rõ:

Trước khi implement, hãy đưa ra 3 phương án status code/error shape và chọn phương án bám convention hiện có nhất.
Nêu trade-off ngắn.
Chưa sửa file.

Nếu test fail:

Test fail như sau. Hãy phân tích nguyên nhân, chưa sửa file.
Phân loại lỗi: implementation bug, test sai contract, thiếu setup, hay môi trường.
Đề xuất patch nhỏ nhất.

Nếu diff quá rộng:

Diff đang rộng hơn plan. Hãy dừng implement.
Liệt kê file ngoài plan, lý do bị chạm, và cách rollback hoặc thu hẹp.
Không sửa file.

Đáp án tham khảo hoặc expected result

Kết quả tốt cho Bài 1:

  • Claude đọc đúng file backend liên quan, không sửa file.
  • Contract có đủ endpoint CRUD, status code, request/response, validation, error và logging.
  • Contract ghi rõ không đổi architecture, không thêm dependency, không migration trong Day 08.

Kết quả tốt cho Bài 2:

  • POST /tasks reject title rỗng hoặc chỉ có khoảng trắng.
  • GET /tasks/:id trả task đúng contract hoặc not found theo error format hiện có.
  • Unit test kiểm tra business rule như trim title hoặc reject title rỗng.
  • Integration test kiểm tra status code và response body, không chỉ kiểm tra request không crash.
  • git diff --stat chỉ gồm file trong plan.

Ví dụ diff summary chấp nhận được:

4 files changed, 120 insertions(+), 8 deletions(-)

Con số này chỉ là ví dụ. Quan trọng là file list khớp plan và không có config/dependency/architecture drift.

Kết quả tốt cho Bài 3:

  • PATCH /tasks/:id xử lý update một phần, reject body rỗng hoặc title whitespace nếu update title.
  • DELETE /tasks/:id bám convention status code của project.
  • Integration test có ít nhất success và not found.
  • Review diff phát hiện được mọi thay đổi ngoài contract.

Kết quả tốt cho Bài 4:

Rule mẫu có thể đưa vào CLAUDE.md:

- Với backend API, luôn bắt đầu bằng contract trước khi implement.
- Không đổi framework, ORM, logger, error format hoặc folder structure trong task CRUD.
- Mọi endpoint mới phải có validation rule, error case và test case tương ứng.
- Không log authorization header, cookie, password, token, secret hoặc raw request body nhạy cảm.
- Không chạy npm install, migration, docker volume command, git reset, git clean dạng rộng hoặc commit tự động.
- Sau mỗi patch, báo file changed, test command và known risks; human review diff trước khi commit.