# GoodGo Platform Kiểm Toán Khả Năng Tiếp Cận - Tài Liệu Tham Khảo Nhanh
**Ngày:** 10 tháng 4 năm 2026 | **Trạng thái:** Tuân thủ WCAG 2.1 AA ở mức 70–75%

---

## 📊 Chỉ Số Chính

| Chỉ số | Số lượng | Trạng thái |
|--------|----------|------------|
| Tổng số tệp đã phân tích | 90+ | ✅ |
| Thuộc tính ARIA tìm thấy | 75 | ✅ |
| Tệp sử dụng ARIA | 14 | ✅ |
| Vấn đề nghiêm trọng | 2 | 🔴 |
| Vấn đề lớn | 3 | 🟡 |
| Vấn đề nhỏ | 2 | 🟢 |

---

## 🔴 VẤN ĐỀ NGHIÊM TRỌNG (Phải Sửa)

### 1. Thành Phần Dialog Thiếu Khả Năng Tiếp Cận
**Tệp:** `apps/web/components/ui/dialog.tsx`
**Vấn đề:**
- Thiếu `role="dialog"`
- Thiếu `aria-modal="true"`
- Không có bẫy tiêu điểm (focus trap)
- Không xử lý phím Escape
- Phần nền không bị ẩn khỏi trình đọc màn hình

**Thời gian sửa:** 2–3 giờ | **Ưu tiên:** 1

**Danh sách kiểm tra sửa nhanh:**
- [ ] Thêm role="dialog" vào vùng chứa dialog
- [ ] Thêm aria-modal="true"
- [ ] Triển khai trình lắng nghe phím Escape
- [ ] Thêm aria-hidden="true" vào lớp phủ nền
- [ ] Kiểm tra với trình đọc màn hình NVDA

---

### 2. Nút Hình Thu Nhỏ Trong Thư Viện Ảnh Thiếu Nhãn
**Tệp:** `apps/web/components/listings/image-gallery.tsx:69-84`
**Vấn đề:** Các nút hình thu nhỏ thiếu aria-label

**Thời gian sửa:** 15–30 phút | **Ưu tiên:** 2

**Sửa nhanh:**
```tsx
// Thêm vào mỗi nút hình thu nhỏ:
aria-label={`Select image ${index + 1}${img.caption ? ': ' + img.caption : ''}`}
aria-pressed={index === selectedIndex}
```

---

## 🟡 VẤN ĐỀ LỚN (Nên Sửa)

### 1. Tiêu Đề Layout Admin Thiếu Vai Trò Banner
**Tệp:** `apps/web/app/[locale]/(admin)/layout.tsx:134`

**Sửa nhanh:**
```tsx
// Đổi từ:
<header className="sticky...">

// Sang:
<header role="banner" className="sticky...">
```

**Thời gian sửa:** 2 phút | **Ưu tiên:** 3

---

### 2. Độ Tương Phản Màu Chưa Được Kiểm Tra
**Vấn đề:** Các biến CSS đã được định nghĩa nhưng tỷ lệ tương phản chưa được kiểm tra
**Tác động:** Có thể vi phạm WCAG 1.4.3
**Thời gian sửa:** 4–6 giờ kiểm tra

**Danh sách kiểm tra:**
- [ ] Trích xuất giá trị biến CSS từ globals.css
- [ ] Kiểm tra bằng WebAIM Contrast Checker
- [ ] Xác minh tỷ lệ 4.5:1 cho văn bản thông thường (WCAG AA)
- [ ] Xác minh tỷ lệ 7:1 cho tuân thủ AAA
- [ ] Kiểm tra ở cả chế độ sáng và tối

---

### 3. Ô Nhập Tìm Kiếm Trang Đầu Thiếu Nhãn Hiển Thị
**Tệp:** `apps/web/app/[locale]/(public)/page.tsx:87-92`

**Sửa nhanh:**
```tsx
<div className="flex flex-col gap-1">
  <label htmlFor="search-input" className="sr-only">
    {t('landing.searchPlaceholder')}
  </label>
  <Input
    id="search-input"
    placeholder={t('landing.searchPlaceholder')}
    value={searchQuery}
    onChange={(e) => setSearchQuery(e.target.value)}
  />
</div>
```

**Thời gian sửa:** 30 phút | **Ưu tiên:** 4

---

## 🟢 VẤN ĐỀ NHỎ (Nên Có)

### 1. aria-label Thừa Trên Văn Bản Đã Hiển Thị
**Tệp:** `apps/web/app/[locale]/(dashboard)/layout.tsx:125`
**Vấn đề:** Các liên kết có aria-label trong khi văn bản đã hiển thị

**Khuyến nghị:** Xóa các aria-label thừa — văn bản hiển thị sẵn tốt hơn cho khả năng tiếp cận

---

## ✅ NHỮNG GÌ ĐANG HOẠT ĐỘNG TỐT

### Biểu Mẫu Xác Thực
- ✅ Tất cả các ô nhập có nhãn hiển thị với `<Label htmlFor="id">`
- ✅ Thông báo lỗi được liên kết qua `aria-describedby`
- ✅ Trạng thái không hợp lệ được đánh dấu bằng `aria-invalid`
- ✅ Nút hiện/ẩn mật khẩu có `aria-label` đúng chuẩn
- **Ví dụ:** `apps/web/app/[locale]/(auth)/login/page.tsx`

### Liên Kết Bỏ Qua Nội Dung (Skip-to-Content)
- ✅ Được triển khai đúng chuẩn với khả năng hiển thị tiêu điểm
- ✅ Ẩn theo mặc định, hiển thị khi được tiêu điểm
- ✅ Liên kết đến `id="main-content"`
- **Ví dụ:** `apps/web/app/[locale]/layout.tsx:105-110`

### Điều Hướng
- ✅ Tất cả các nav có `aria-label`
- ✅ Nút chuyển đổi menu di động có nhãn động
- ✅ Biểu tượng được ẩn đúng chuẩn với `aria-hidden="true"`
- **Ví dụ:** Tất cả các tệp layout

### Tìm Kiếm & Bộ Lọc
- ✅ Phần bộ lọc có `role="search"`
- ✅ Tất cả các ô select có `aria-label`
- ✅ Ô nhập kiểu dải (range) được gắn nhãn đúng chuẩn
- **Ví dụ:** `apps/web/components/search/filter-bar.tsx`

### Thư Viện Ảnh
- ✅ Các nút Trước/Sau có aria-label
- ✅ Cấu trúc ngữ nghĩa tốt
- **Ví dụ:** `apps/web/components/listings/image-gallery.tsx:47, 54`

---

## 📋 DANH SÁCH KIỂM TRA THỬ NGHIỆM

### Trước Khi Triển Khai
- [ ] Sửa khả năng tiếp cận của thành phần dialog
- [ ] Thêm nhãn cho các nút hình thu nhỏ
- [ ] Thêm vai trò banner vào tiêu đề admin
- [ ] Chạy kiểm toán khả năng tiếp cận Lighthouse (mục tiêu: 90+)
- [ ] Kiểm tra với trình đọc màn hình NVDA
- [ ] Kiểm tra điều hướng bàn phím (Tab, Shift+Tab, Enter, Escape)
- [ ] Xác minh tỷ lệ tương phản màu sắc
- [ ] Kiểm tra chuyển đổi giao diện (chế độ sáng/tối)

### Kiểm Tra Trình Đọc Màn Hình (NVDA)
- [ ] Biểu mẫu đăng nhập: Có thể điền trường, nghe thông báo lỗi
- [ ] Điều hướng: Có thể điều hướng menu, hiểu trang hiện tại
- [ ] Tìm kiếm: Có thể tìm và gửi biểu mẫu tìm kiếm
- [ ] Hộp thoại: Có thể mở, tương tác, đóng bằng phím Escape
- [ ] Thư viện ảnh: Có thể chọn ảnh, nghe ảnh nào đang được chọn
- [ ] Menu di động: Có thể mở/đóng, nút chuyển đổi hoạt động bình thường

### Điều Hướng Bàn Phím
- [ ] Tab: Di chuyển qua tất cả các phần tử tương tác theo thứ tự hợp lý
- [ ] Shift+Tab: Di chuyển ngược lại qua các phần tử
- [ ] Enter: Kích hoạt nút/liên kết/gửi biểu mẫu
- [ ] Space: Kích hoạt nút, bật/tắt hộp kiểm
- [ ] Escape: Đóng modal/menu
- [ ] Phím mũi tên: Hoạt động trong dropdown/băng chuyền

---

## 🎯 Lộ Trình Ưu Tiên

### Tuần 1 (40 giờ)
1. **Sửa Thành Phần Dialog** (2–3 giờ)
   - [ ] Thêm role, aria-modal, focus trap, xử lý phím Escape
   - [ ] Kiểm tra với trình đọc màn hình

2. **Thêm Nhãn Hình Thu Nhỏ** (0,5 giờ)
   - [ ] Thêm aria-label vào các nút hình thu nhỏ
   - [ ] Kiểm tra

3. **Sửa Tiêu Đề Admin** (0,1 giờ)
   - [ ] Thêm role="banner"

4. **Xác Minh Tương Phản** (6–8 giờ)
   - [ ] Trích xuất biến CSS
   - [ ] Kiểm tra tất cả các tổ hợp
   - [ ] Ghi lại kết quả
   - [ ] Điều chỉnh nếu cần

5. **Thêm Nhãn Trang Đầu** (0,5 giờ)
   - [ ] Thêm nhãn hiển thị vào ô nhập tìm kiếm

6. **Kiểm Tra Trình Duyệt** (8 giờ)
   - [ ] Kiểm tra NVDA
   - [ ] Kiểm tra Chrome/Firefox/Safari
   - [ ] Kiểm tra trên thiết bị di động

### Tuần 2 (20 giờ)
1. **Xóa Nhãn Thừa** (0,5 giờ)
2. **Thêm Liên Kết Bỏ Qua Bổ Sung** (2–3 giờ)
3. **Kiểm Tra Toàn Diện** (8 giờ)
4. **Sửa Các Vấn Đề Phát Hiện** (6 giờ)

---

## 📁 Tài Liệu Tham Chiếu Tệp

### Các Tệp Quan Trọng Cần Xem Xét/Sửa
- `apps/web/components/ui/dialog.tsx` - 🔴 CẦN VIẾT LẠI
- `apps/web/components/listings/image-gallery.tsx` - 🔴 CẦN SỬA NHỎ
- `apps/web/app/[locale]/(admin)/layout.tsx` - 🟡 THÊM ROLE
- `apps/web/app/globals.css` - 🟡 XÁC MINH MÀU SẮC (chưa kiểm toán)

### Các Tệp Có Khả Năng Tiếp Cận Tốt
- `apps/web/app/[locale]/(public)/layout.tsx` - ✅ XUẤT SẮC
- `apps/web/app/[locale]/(auth)/login/page.tsx` - ✅ XUẤT SẮC
- `apps/web/app/[locale]/(auth)/register/page.tsx` - ✅ XUẤT SẮC
- `apps/web/components/ui/button.tsx` - ✅ TỐT
- `apps/web/components/ui/input.tsx` - ✅ TỐT
- `apps/web/components/ui/label.tsx` - ✅ TỐT
- `apps/web/components/ui/select.tsx` - ✅ TỐT
- `apps/web/components/search/filter-bar.tsx` - ✅ TỐT

---

## 🔍 Ví Dụ Mã

### Ví Dụ Sử Dụng ARIA Tốt
```tsx
// Tốt: aria-label động cập nhật theo trạng thái
<button
  aria-label={mobileMenuOpen ? t('nav.closeMenu') : t('nav.openMenu')}
  onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
>
  {mobileMenuOpen ? <X /> : <Menu />}
</button>
```

### Ví Dụ Khả Năng Tiếp Cận Biểu Mẫu
```tsx
// Tốt: Liên kết nhãn đúng chuẩn + xử lý lỗi
<div className="space-y-2">
  <Label htmlFor="phone">{t('phone')}</Label>
  <Input
    id="phone"
    type="tel"
    aria-describedby={errors.phone ? 'phone-error' : undefined}
    aria-invalid={!!errors.phone}
    {...register('phone')}
  />
  {errors.phone && (
    <p id="phone-error" role="alert">{errors.phone.message}</p>
  )}
</div>
```

### Ví Dụ Biểu Mẫu Tìm Kiếm
```tsx
// Tốt: Vai trò ngữ nghĩa đúng chuẩn với các điều khiển được gắn nhãn
<form role="search" aria-label={t('filters')}>
  <Select aria-label={t('allTransactions')}>
    {/* options */}
  </Select>
</form>
```

---

## 📞 Tài Nguyên

### Tài Liệu
- Báo cáo kiểm toán đầy đủ: `ACCESSIBILITY_AUDIT_2026-04-10.md`
- Kết quả chi tiết trên 15 phần
- Phân tích từng tệp
- Đánh giá tuân thủ WCAG 2.1

### Công Cụ Kiểm Tra
- **Axe DevTools:** Tiện ích mở rộng Chrome/Firefox để kiểm tra nhanh
- **Lighthouse:** Tích hợp trong Chrome DevTools
- **WebAIM Contrast Checker:** https://webaim.org/resources/contrastchecker/
- **NVDA:** Trình đọc màn hình miễn phí - https://www.nvaccess.org/

### Tài Nguyên Học Tập
- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)
- [ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)
- [MDN Accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility)

---

## 📝 Ghi Chú

**Phạm vi kiểm toán:** apps/web (giao diện Next.js 15)
**Số tệp đã phân tích:** 90+ tệp TSX/JSX
**Thời gian đạt tuân thủ AA:** 4–6 ngày làm toàn thời gian
**Bảo trì liên tục:** Nên tích hợp vào CI/CD và đào tạo lập trình viên

**Bước tiếp theo:**
1. Xem xét báo cáo kiểm toán đầy đủ (1552 dòng)
2. Tạo ticket Jira cho mỗi vấn đề
3. Phân công nhiệm vụ cho nhóm phát triển
4. Lên lịch kiểm tra khả năng tiếp cận
5. Lập kế hoạch buổi đào tạo lập trình viên

