📘 Guide vận hành

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.

Hình 4.1 — Phân cấp đối tượng trên GitLab
Hình 4.1 — Phân cấp đối tượng trên GitLab
Đối tượngVai trò trong quản lý task
Group /thaco-vocGom hai project, quản lý thành viên và phân quyền chung
ProjectMột repository + bộ công cụ. Dự án có 2: thaco-voc-docsthaco-voc-src
IssueMột đơn vị công việc: feature, bug hoặc task. Là nơi mọi thứ quy tụ
LabelNhãn phân loại. Dùng scoped label (status::in-dev) để biểu diễn trạng thái
MilestoneNhóm issue theo mốc thời gian — dùng làm Sprint
BoardBả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.

Hình 4.2 — Cách kết nối từ máy của bạn tới GitLab
Hình 4.2 — Cách kết nối từ máy của bạn tới GitLab

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.

Hình 4.3 — Sáu bước tạo Personal Access Token
Hình 4.3 — Sáu bước tạo Personal Access Token

Ba scope cần chọn:

ScopeCho 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_repositoryClone / pull code
write_repositoryPush 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.

  1. New groupthaco-voc. Trong group, New project hai lần: thaco-voc-docs, thaco-voc-src.
  2. 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.
  3. 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).
  4. Cấu hình Board: Plan → Boards, tạo mỗi cột ứng với một status::.
  5. 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ào main, 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.

Hình 4.4 — Cấu tạo một Issue
Hình 4.4 — Cấu tạo một Issue

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.

Hình 4.5 — Bảng Kanban theo scoped label status::
Hình 4.5 — Bảng Kanban theo scoped label status::

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:

Sơ đồ 6 — Vòng đời trạng thái GitLab
Sơ đồ 6 — Vòng đời trạng thái GitLab

Ba chỉ số đọc trực tiếp từ lịch sử chuyển trạng thái:

Chỉ sốCách tínhNgưỡng
Spec timeThời gian ở status::spec> 3 ngày → PRD viết chưa đủ rõ
Cycle timeready-for-devdone> 2× trung vị
Rework rateSố 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

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:

Sơ đồ 7 — Dòng chảy mã AC
Sơ đồ 7 — Dòng chảy mã AC

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.

Hình 4.6 — Luồng làm việc: Issue → Branch → MR → Đóng
Hình 4.6 — Luồng làm việc: Issue → Branch → MR → Đóng

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ạiQuy ướcVí dụ
Branchfeature/FE-001-slugfeature/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ặc Fixes, 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ùng Related 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ệnhTác dụng
/assign @meTự nhận việc
/estimate 3dĐặt thời gian ước lượng
/spend 4hGhi thời gian đã bỏ ra (cập nhật hằng ngày)
/spend 2h 2026-07-25Ghi 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 đíchEndpoint
Danh sách issueGET /projects/:id/issues
Chi tiết một issueGET /projects/:id/issues/:iid
Lịch sử chuyển trạng tháiGET /projects/:id/issues/:iid/resource_label_events
Thống kê thời gianGET /projects/:id/issues/:iid/time_stats
Danh sách Merge RequestGET /projects/:id/merge_requests
⚠️ Số liệu chỉ đúng khi DEV /spend hằng ngày và mỗi issue luôn mang đúng một status::. 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ứngNguyên nhânCách xử lý
Git hỏi mật khẩu và báo saiDùng mật khẩu tài khoản thay vì PATDán PAT vào ô mật khẩu; hoặc chuyển sang SSH
401 Unauthorized khi gọi APIToken sai, hết hạn, hoặc thiếu scope apiTạo PAT mới đủ scope, cập nhật .env
403 Forbidden khi pushNhánh được bảo vệ hoặc thiếu quyềnPush lên branch riêng rồi mở MR
Issue không tự đóng khi mergeQuên Closes #42, hoặc merge vào nhánh không phải mặc địnhSửa mô tả MR hoặc đóng tay bằng /close
Board đếm cycle time saiIssue mang hai status:: cùng lúcChỉ dùng scoped label (::), gỡ nhãn thường trùng nghĩa
Lỡ commit PAT/secretToken lộRevoke ngay, tạo token mới, xóa khỏi lịch sử git