PHẦN 4 — SỬ DỤNG GITLAB ĐỂ QUẢN LÝ TASK
Phần này hướng dẫn thực hành từ số 0: hiểu mô hình GitLab, kết nối máy của bạn, thiết lập project, tạo và vận hành issue, làm việc với Merge Request, theo dõi thời gian và xuất báo cáo. Ưu tiên hình ảnh để dễ hình dung.
4.1 Hiểu mô hình GitLab
Ba cấp đối tượng: Group là không gian chung của cả dự án; bên trong là các Project (mỗi project là một repository kèm công cụ quản lý); mỗi Project chứa Issue (đơn vị công việc) cùng Label, Milestone, Board và Merge Request.

| Đối tượng | Vai trò trong quản lý task |
|---|---|
Group /thaco-voc | Gom hai project, quản lý thành viên và phân quyền chung |
| Project | Một repository + bộ công cụ. Dự án có 2: thaco-voc-docs và thaco-voc-src |
| Issue | Một đơn vị công việc: feature, bug hoặc task. Là nơi mọi thứ quy tụ |
| Label | Nhãn phân loại. Dùng scoped label (status::in-dev) để biểu diễn trạng thái |
| Milestone | Nhóm issue theo mốc thời gian — dùng làm Sprint |
| Board | Bảng Kanban, mỗi cột là một status:: |
| Merge Request (MR) | Yêu cầu gộp nhánh code vào nhánh chính, kèm review |
💡 Một Issue không nằm một mình — nó mang Labels, Milestone, Weight, Assignee và liên kết tới Merge Request chứa code. Mã FE-001-AC-03 là sợi chỉ chạy xuyên suốt từ Issue → Branch → Commit → MR → test (xem 4.5).
4.2 Kết nối máy tới GitLab
Có hai kênh kết nối dùng chung một Personal Access Token (PAT): git để đẩy/kéo code, và REST API / glab CLI để đọc issue và xuất báo cáo.

Bước 1 — Vào được Group. Đăng nhập GitLab, nhờ quản trị viên mời vào Group /thaco-voc: BA/PM thường là *Maintainer*, DEV là *Developer*.
Bước 2 — Tạo Personal Access Token (PAT). PAT là "mật khẩu dùng cho máy", thay cho mật khẩu thật khi git đẩy code hoặc gọi API. Không bao giờ commit PAT vào repo.

Ba scope cần chọn:
| Scope | Cho phép làm gì |
|---|---|
api | Đọc/ghi qua REST API: tạo issue, gắn label, lấy dữ liệu báo cáo |
read_repository | Clone / pull code |
write_repository | Push code, tạo branch, mở MR qua git |
🔒 Token chỉ hiện một lần ngay sau khi tạo. Copy ngay và lưu vào trình quản lý mật khẩu; luôn đặt ngày hết hạn. Nếu lỡ lộ, thu hồi (revoke) rồi tạo cái mới.
Bước 3 — Cấu hình git và clone.
git config --global user.name "Nguyễn Văn A"
git config --global user.email "a.nguyen@congty.vn"
mkdir -p ~/work/thaco-voc && cd ~/work/thaco-voc
# HTTPS — khi git hỏi mật khẩu thì dán PAT (không phải mật khẩu tài khoản)
git clone https://gitlab.com/thaco-voc/thaco-voc-docs.git
git clone https://gitlab.com/thaco-voc/thaco-voc-src.git
DEV mở Claude Code ở thư mục cha ~/work/thaco-voc để thấy được cả tài liệu lẫn code.
Bước 4 — Lưu PAT cho API và Claude Code vào file .env (đã nằm trong .gitignore, không commit):
# .env
GITLAB_URL=https://gitlab.com
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
PROJECT_ID=12345678 # xem ở Project → Settings → General
# Kiểm tra kết nối
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" "$GITLAB_URL/api/v4/projects/$PROJECT_ID" | head
Tùy chọn — SSH thay cho HTTPS (khỏi dán PAT mỗi lần push):
ssh-keygen -t ed25519 -C "a.nguyen@congty.vn"
cat ~/.ssh/id_ed25519.pub # dán vào GitLab: Preferences → SSH Keys → Add key
git remote set-url origin git@gitlab.com:thaco-voc/thaco-voc-src.git
Tùy chọn — glab CLI (thao tác issue/MR nhanh từ dòng lệnh):
glab auth login # dán PAT khi được hỏi
glab issue list
glab mr create --fill
4.3 Thiết lập Project
Người quản trị (thường là PM) làm một lần khi khởi tạo dự án.
- New group →
thaco-voc. Trong group, New project hai lần:thaco-voc-docs,thaco-voc-src. - Tạo Labels ở cấp Group (Group → Labels) để cả hai repo dùng chung. Scoped label dùng dấu
::để mỗi issue chỉ mang một nhãn trong cùng nhóm — điều kiện để tính cycle time đúng. Danh sách đầy đủ ở Phụ lục B; nội dung trùng với quy ước ở Phần 2.6. - Tạo Milestone (= Sprint): Plan → Milestones → New milestone, đặt
Sprint 05, chọn ngày bắt đầu/kết thúc (sprint 2 tuần). - Cấu hình Board: Plan → Boards, tạo mỗi cột ứng với một
status::. - Bảo vệ nhánh & CODEOWNERS: đặt file
CODEOWNERS(xem Phần 2.3) và bật Protected branches để chặn push thẳng vàomain, buộc đi qua Merge Request.
4.4 Làm việc với Issue & Board
Cấu tạo một Issue. Một issue tốt gồm: tiêu đề có mã feature, mô tả kèm checklist Acceptance Criteria, và các trường bên phải (assignee, milestone, weight, labels, thời gian). Ai điền trường nào xem bảng ở Phần 2.6.

Tạo Issue: Plan → Issues → New issue (hoặc dùng template Feature/Bug/Change-Request). Đặt title theo quy ước và dán checklist AC vào description — GitLab tự đếm số ô đã tick:
## Acceptance Criteria
- [ ] FE-001-AC-01 Hiển thị danh sách xe theo trạng thái giao
- [ ] FE-001-AC-02 Lọc theo khoảng ngày dự kiến giao
- [ ] FE-001-AC-03 Chặn tạo phiếu trùng VIN trong cùng ngày
Vận hành trên Board. Mỗi cột là một status::; kéo thẻ sang cột kế tiếp thì nhãn tự đổi theo.

Vòng đời trạng thái đầy đủ (kể cả các nhánh quay lui) — scoped label đảm bảo mỗi issue chỉ mang một label trong cùng scope, để lịch sử chuyển trạng thái đủ sạch mà tính số liệu:

Ba chỉ số đọc trực tiếp từ lịch sử chuyển trạng thái:
| Chỉ số | Cách tính | Ngưỡng |
|---|---|---|
| Spec time | Thời gian ở status::spec | > 3 ngày → PRD viết chưa đủ rõ |
| Cycle time | ready-for-dev → done | > 2× trung vị |
| Rework rate | Số lần quay lại in-dev sau khi đã rời | > 15% → DoR hoặc DoD quá lỏng |
Gọi API lấy lịch sử chuyển trạng thái: GET /api/v4/projects/:id/issues/:iid/resource_label_events.
4.5 Dòng chảy mã AC
Mã FE-001-AC-03 là sợi chỉ chạy xuyên suốt sáu chặng, từ tài liệu nghiệp vụ tới ma trận đối chiếu:

Giới hạn cần biết: script kiểm được mã có tồn tại, không kiểm được nội dung có đúng. Một test đặt tên [FE-001-AC-03] nhưng assert sai vẫn qua trơn tru. Nó chống bỏ sót, không chống hiểu sai. Chốt thật vẫn là bước BA duyệt spec ở G3.5. Đừng để con số "AC coverage 100%" tạo cảm giác an toàn giả.
4.6 Luồng code: Issue → Branch → MR → Đóng
Đây là luồng DEV thực hiện sau khi issue đã ở status::ready-for-dev. Điểm mấu chốt: dùng từ khóa Closes #42 trong mô tả MR để GitLab tự đóng issue khi MR được merge.

Các lệnh git tương ứng:
# 1. Tạo branch theo mã feature
git checkout -b feature/FE-001-quan-ly-tien-do-giao-xe
# 2. Code + commit, mỗi commit gắn mã feature
git commit -m "feat(FE-001): add duplicate VIN check"
# 3. Đẩy branch lên
git push -u origin feature/FE-001-quan-ly-tien-do-giao-xe
# 4. Mở MR (qua web hoặc glab), mô tả ghi: Closes #42
glab mr create --fill --label "status::mr-review"
Quy ước đặt tên đi kèm (nhắc lại từ Phần 2.4, phần liên quan tới GitLab):
| Loại | Quy ước | Ví dụ |
|---|---|---|
| Branch | feature/FE-001-slug | feature/FE-001-quan-ly-tien-do-giao-xe |
| Commit | <type>(FE-001): <mô tả> | feat(FE-001): add duplicate VIN check |
| Tên test | [FE-001-AC-03] <mô tả> | [FE-001-AC-03] should_reject_duplicate_vin |
💡Closes #42(hoặcFixes,Resolves) đặt trong mô tả MR — khi MR merge vào nhánh mặc định, issue #42 tự chuyển sang đóng. Nếu chỉ muốn liên kết mà không đóng, dùngRelated to #42.
4.7 Theo dõi thời gian & xuất báo cáo
Quick actions — gõ thẳng trong ô comment của issue/MR:
| Lệnh | Tác dụng |
|---|---|
/assign @me | Tự nhận việc |
/estimate 3d | Đặt thời gian ước lượng |
/spend 4h | Ghi thời gian đã bỏ ra (cập nhật hằng ngày) |
/spend 2h 2026-07-25 | Ghi thời gian cho một ngày cụ thể |
/label ~"status::qc" | Gắn nhãn |
/milestone %"Sprint 05" | Xếp vào sprint |
/weight 5 | Đặt story point |
/close · /reopen | Đóng / mở lại issue |
Lấy dữ liệu qua API cho báo cáo tuần (phục vụ G6 và Phần 6):
# Danh sách issue trong sprint, kèm time_stats
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"$GITLAB_URL/api/v4/projects/$PROJECT_ID/issues?milestone=Sprint%2005&per_page=100" \
> 06-reports/raw/sprint05-issues.json
Endpoint hữu ích:
| Mục đích | Endpoint |
|---|---|
| Danh sách issue | GET /projects/:id/issues |
| Chi tiết một issue | GET /projects/:id/issues/:iid |
| Lịch sử chuyển trạng thái | GET /projects/:id/issues/:iid/resource_label_events |
| Thống kê thời gian | GET /projects/:id/issues/:iid/time_stats |
| Danh sách Merge Request | GET /projects/:id/merge_requests |
⚠️ Số liệu chỉ đúng khi DEV/spendhằng ngày và mỗi issue luôn mang đúng mộtstatus::. Dùng số liệu để nhìn xu hướng quy trình, không để chấm điểm cá nhân.
4.8 Xử lý sự cố thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
| Git hỏi mật khẩu và báo sai | Dùng mật khẩu tài khoản thay vì PAT | Dán PAT vào ô mật khẩu; hoặc chuyển sang SSH |
401 Unauthorized khi gọi API | Token sai, hết hạn, hoặc thiếu scope api | Tạo PAT mới đủ scope, cập nhật .env |
403 Forbidden khi push | Nhánh được bảo vệ hoặc thiếu quyền | Push lên branch riêng rồi mở MR |
| Issue không tự đóng khi merge | Quên Closes #42, hoặc merge vào nhánh không phải mặc định | Sửa mô tả MR hoặc đóng tay bằng /close |
| Board đếm cycle time sai | Issue mang hai status:: cùng lúc | Chỉ dùng scoped label (::), gỡ nhãn thường trùng nghĩa |
| Lỡ commit PAT/secret | Token lộ | Revoke ngay, tạo token mới, xóa khỏi lịch sử git |