# Báo Cáo Khám Phá Frontend Nền Tảng GoodGo
## apps/web (Next.js 15 với App Router)

**Ngày:** 9 tháng 4, 2026  
**Trạng thái:** Chưa có i18n (Không phát hiện cấu hình i18n nào)  
**Phiên bản Next.js:** 15.5.14 | **React:** 18.3.0  
**Ngôn ngữ chính:** Tiếng Việt (vi_VN)

---

## 📁 Tổng Quan Cấu Trúc Thư Mục

```
apps/web/
├── app/                          # Next.js App Router (ứng dụng chính)
│   ├── layout.tsx               # Layout gốc với metadata & providers
│   ├── globals.css              # Style Tailwind toàn cục & biến theme
│   ├── middleware.ts            # Đã có sẵn (middleware định tuyến xác thực)
│   ├── loading.tsx              # Trạng thái tải gốc
│   ├── error.tsx                # Xử lý lỗi gốc
│   ├── not-found.tsx            # Trang 404
│   │
│   ├── (public)/                # Nhóm route công khai
│   │   ├── layout.tsx           # Layout công khai với header/footer
│   │   ├── page.tsx             # Trang đích (hero + danh sách nổi bật)
│   │   ├── search/              # Trang kết quả tìm kiếm
│   │   │   ├── page.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── error.tsx
│   │   │   ├── loading.tsx
│   │   │   └── __tests__/
│   │   └── listings/[id]/       # Trang chi tiết tin đăng
│   │       └── page.tsx
│   │
│   ├── (auth)/                  # Nhóm route xác thực
│   │   ├── layout.tsx
│   │   ├── login/page.tsx       # Form đăng nhập
│   │   ├── register/page.tsx    # Form đăng ký
│   │   ├── error.tsx
│   │   ├── loading.tsx
│   │   └── __tests__/
│   │
│   ├── (dashboard)/             # Nhóm route dashboard được bảo vệ
│   │   ├── layout.tsx           # Layout dashboard với thanh điều hướng bên
│   │   ├── dashboard/page.tsx   # Dashboard chính
│   │   ├── listings/
│   │   │   ├── page.tsx         # Danh sách tin đăng của người dùng
│   │   │   ├── new/page.tsx     # Tạo tin đăng (form nhiều bước)
│   │   │   └── [id]/edit/page.tsx
│   │   ├── analytics/page.tsx
│   │   ├── profile/page.tsx     # Cài đặt hồ sơ người dùng
│   │   ├── subscription/page.tsx # Gói đăng ký
│   │   ├── payments/page.tsx    # Lịch sử thanh toán
│   │   ├── valuation/page.tsx   # Định giá bất động sản bằng AI
│   │   ├── error.tsx
│   │   ├── loading.tsx
│   │   └── __tests__/
│   │
│   ├── (admin)/                 # Nhóm route quản trị
│   │   ├── layout.tsx
│   │   ├── admin/page.tsx       # Dashboard quản trị
│   │   ├── admin/users/page.tsx
│   │   ├── admin/kyc/page.tsx
│   │   ├── admin/moderation/page.tsx
│   │   ├── error.tsx
│   │   └── loading.tsx
│   │
│   ├── auth/                    # Callback xác thực
│   │   └── callback/
│   │       ├── google/page.tsx
│   │       └── zalo/page.tsx
│   │
│   ├── api/                     # Route API
│   │   └── health/route.ts
│   │
│   ├── robots.ts
│   └── sitemap.ts
│
├── components/                   # Các component React tái sử dụng
│   ├── providers/               # Context providers
│   │   ├── auth-provider.tsx    # Context xác thực & wrapper store
│   │   ├── query-provider.tsx   # Provider TanStack React Query
│   │   └── theme-provider.tsx   # Provider chế độ tối/sáng
│   │
│   ├── ui/                      # Các component UI cơ sở không có style
│   │   ├── button.tsx           # Biến thể button dựa trên CVA
│   │   ├── input.tsx
│   │   ├── label.tsx
│   │   ├── card.tsx
│   │   ├── dialog.tsx           # Hộp thoại modal
│   │   ├── tabs.tsx
│   │   ├── select.tsx           # Component select tùy chỉnh
│   │   ├── badge.tsx
│   │   ├── textarea.tsx
│   │   ├── table.tsx
│   │   └── __tests__/           # Test component
│   │
│   ├── auth/
│   │   └── oauth-buttons.tsx    # Nút OAuth Google & Zalo
│   │
│   ├── search/
│   │   ├── filter-bar.tsx       # Bộ lọc tìm kiếm (loại giao dịch, bất động sản, khoảng giá)
│   │   ├── property-card.tsx    # Thẻ danh sách bất động sản
│   │   └── search-results.tsx   # Container kết quả tìm kiếm
│   │
│   ├── listings/
│   │   ├── listing-form-steps.tsx      # Form tạo/chỉnh sửa nhiều bước
│   │   ├── image-upload.tsx            # Component tải ảnh lên
│   │   ├── image-gallery.tsx           # Trình xem thư viện ảnh
│   │   └── listing-status-badge.tsx    # Badge hiển thị trạng thái
│   │
│   ├── map/
│   │   └── listing-map.tsx      # Tích hợp Mapbox GL
│   │
│   ├── valuation/
│   │   ├── valuation-form.tsx
│   │   ├── valuation-results.tsx
│   │   ├── valuation-history.tsx
│   │   └── ai-estimate-button.tsx
│   │
│   └── charts/
│       ├── price-trend-chart.tsx
│       ├── agent-performance.tsx
│       └── district-heatmap.tsx
│
├── lib/                         # Tiện ích và hooks
│   ├── utils.ts                # cn() - clsx + tailwind-merge
│   ├── auth-store.ts           # Quản lý trạng thái xác thực Zustand
│   ├── api-client.ts           # Wrapper Axios/fetch
│   ├── query-client.ts         # Cấu hình TanStack React Query
│   │
│   ├── hooks/
│   │   ├── use-listings.ts
│   │   ├── use-analytics.ts
│   │   ├── use-valuation.ts
│   │   ├── use-payments.ts
│   │   └── use-subscription.ts
│   │
│   ├── validations/            # Schema Zod
│   │   ├── auth.ts            # Schema đăng nhập/đăng ký
│   │   ├── listings.ts        # Schema tin đăng nhiều bước
│   │   └── valuation.ts
│   │
│   ├── *-api.ts               # Các API client
│   │   ├── auth-api.ts
│   │   ├── listings-api.ts
│   │   ├── profile-api.ts
│   │   ├── payment-api.ts
│   │   ├── subscription-api.ts
│   │   ├── analytics-api.ts
│   │   ├── valuation-api.ts
│   │   └── admin-api.ts
│   │
│   └── __tests__/            # Unit test (Vitest + React Testing Library)
│       ├── auth-store.spec.ts
│       ├── auth-validations.spec.ts
│       ├── listing-validations.spec.ts
│       └── utils.spec.ts
│
├── public/                     # Tài nguyên tĩnh
│   └── [images, icons, etc.]
│
├── .next/                      # Đầu ra build (được tạo tự động)
├── node_modules/
│
└── Tệp Cấu Hình:
    ├── package.json            # Phụ thuộc & scripts
    ├── next.config.js          # Cấu hình Next.js (Sentry, CSP, headers)
    ├── tailwind.config.ts      # Cấu hình Tailwind CSS
    ├── postcss.config.js       # Cấu hình PostCSS (Tailwind + Autoprefixer)
    ├── tsconfig.json           # Cấu hình TypeScript (kế thừa base)
    ├── vitest.config.ts        # Cấu hình framework kiểm thử
    ├── vitest.setup.ts         # Thiết lập kiểm thử
    ├── middleware.ts           # Middleware định tuyến xác thực
    ├── sentry.*.config.ts      # Theo dõi lỗi Sentry (3 tệp)
    ├── instrumentation.ts      # Instrumentation phía server
    └── global.d.ts             # Định nghĩa TypeScript toàn cục
```

---

## 📦 Phụ Thuộc Package.json

### Phụ Thuộc Production:
```json
{
  "@hookform/resolvers": "^5.2.2",      // Resolver xác thực form
  "@sentry/nextjs": "^10.47.0",         // Theo dõi lỗi
  "@tanstack/react-query": "^5.96.2",   // Lấy dữ liệu & bộ nhớ đệm
  "class-variance-authority": "^0.7.1", // Tiện ích biến thể component
  "clsx": "^2.1.1",                     // Tiện ích tên class
  "lucide-react": "^1.7.0",             // Thư viện icon
  "mapbox-gl": "^3.21.0",               // Thư viện bản đồ
  "next": "^14.2.0",                    // Framework
  "react": "^18.3.0",
  "react-dom": "^18.3.0",
  "react-hook-form": "^7.72.1",         // Quản lý trạng thái form
  "recharts": "^3.8.1",                 // Thư viện biểu đồ
  "tailwind-merge": "^3.5.0",           // Giải quyết xung đột Tailwind
  "zod": "^4.3.6",                      // Xác thực schema
  "zustand": "^5.0.12"                  // Quản lý trạng thái nhẹ
}
```

### Phụ Thuộc Dev (bao gồm kiểm thử):
```json
{
  "@testing-library/jest-dom": "^6.9.1",
  "@testing-library/react": "^16.3.2",
  "@testing-library/user-event": "^14.6.1",
  "@vitejs/plugin-react": "^4.7.0",
  "vitest": "^4.1.3",
  "tailwindcss": "^3.4.0",
  "tailwindcss-animate": "^1.0.7",
  "msw": "^2.13.2",                     // Mock Service Worker
  "typescript": "^6.0.2"
}
```

---

## 🎯 Layout Gốc (app/layout.tsx)

### Triển Khai Hiện Tại:
- **Ngôn ngữ HTML:** `lang="vi"` (Tiếng Việt được mã hóa cứng)
- **Cấu trúc Metadata:** Tiêu đề & mô tả bằng tiếng Việt
- **OpenGraph:** Locale đặt là `vi_VN`
- **Providers xếp chồng:** `ThemeProvider → QueryProvider → AuthProvider`
- **Khả năng tiếp cận:** Bao gồm liên kết bỏ qua đến nội dung chính (đã tuân thủ A11y)
- **Màu theme:** `#15803d` (xanh lá chính)

### Metadata Hiện Tại:
```javascript
title: 'GoodGo — Nền tảng Bất động sản Việt Nam'
description: 'GoodGo — nền tảng bất động sản thông minh tại Việt Nam...'
openGraph: { locale: 'vi_VN', ... }
```

---

## 🔐 Middleware (middleware.ts)

### Định Tuyến Xác Thực Hiện Tại:
```typescript
- Public paths: /login, /register, /search, /auth/callback, / (root)
- Protected paths: Anything else requires 'goodgo_authenticated' cookie
- Auth-only paths: /login, /register (redirects to /dashboard if authenticated)
- Redirect param: Adds ?redirect=[original-path] on unauthorized access
```

**Các Điểm Nhập Quan Trọng Cần Cập Nhật Cho i18n:**
- Cần phát hiện tiền tố locale (ví dụ: `/en/dashboard`, `/vi/dashboard`)
- Phát hiện locale qua cookie/header

---

## 🎨 Cấu Hình Tailwind

### Thiết Lập Theme (tailwind.config.ts):
```typescript
- Dark mode: 'class' based
- Content paths: ./app/**, ./components/**, ./lib/**
- Colors: HSL-based CSS variables (--primary, --secondary, etc.)
- Border radius: Customizable via --radius CSS variable
- Animation plugin: tailwindcss-animate
```

### Style Toàn Cục (app/globals.css):
- **Biến CSS:** Bảng màu chế độ sáng + chế độ tối
- **Màu chính:** HSL(142.1, 76.2%, 36.3%) — xanh lá
- **Tất cả component:** Dùng @apply border-border để nhất quán
- **Nền gốc:** Áp dụng biến HSL

---

## 🗣️ Nội Dung Văn Bản & Các Điểm i18n

### Vị Trí Văn Bản Tiếng Việt Được Mã Hóa Cứng:

#### Layout & Điều Hướng:
- `app/(public)/layout.tsx` — Nav header: "Trang chủ", "Tìm kiếm", "Đăng nhập", "Đăng ký"
- `app/(dashboard)/layout.tsx` — Các mục nav dashboard (8 mục + nhãn chuyển đổi theme)
- Footer trong layout công khai — Tiêu đề phần, liên kết

#### Trang:
- `app/(public)/page.tsx` — Trang đích (hero, thanh tìm kiếm, quận huyện, thống kê, CTA)
- `app/(auth)/login/page.tsx` — Nhãn form, thông báo lỗi (đối tượng OAUTH_ERROR_MESSAGES)
- `app/(auth)/register/page.tsx` — Cấu trúc form tương tự

#### Component:
- `components/search/filter-bar.tsx` — Nhãn bộ lọc (PRICE_RANGES), tên thành phố
- `components/search/property-card.tsx` — Badge thông tin bất động sản, nhãn hướng
- `components/listings/listing-form-steps.tsx` — Nhãn form, thông báo xác thực
- `components/ui/label.tsx` — Nhãn form trong toàn bộ ứng dụng

#### Thông Báo Lỗi API & Xác Thực Zod:
- `lib/validations/listings.ts` — Thông báo lỗi Zod (tiếng Việt)
- `lib/validations/auth.ts` — Thông báo xác thực xác thực
- `components/auth/oauth-buttons.tsx` — Văn bản nút ("Google", "Zalo")

---

## 🧩 Các Component Quan Trọng Cần Dịch

### Form (Xác thực form + nhãn):
1. **Form Đăng Nhập** (`app/(auth)/login/page.tsx`)
   - Nhãn nhập số điện thoại, nhãn mật khẩu, lỗi
   - Nhãn nút OAuth
   - Văn bản liên kết: "Chưa có tài khoản? Đăng ký"

2. **Form Đăng Ký** (`app/(auth)/register/page.tsx`)
   - Cấu trúc tương tự form đăng nhập

3. **Tạo Tin Đăng** (`components/listings/listing-form-steps.tsx`)
   - Form nhiều bước với nhãn cho:
     - Loại giao dịch (Bán/Cho thuê)
     - Loại bất động sản (Căn hộ/Nhà riêng/v.v.)
     - Vị trí (địa chỉ, phường, quận, thành phố)
     - Chi tiết (diện tích, phòng ngủ, phòng tắm, hướng)
     - Giá cả

4. **Bộ Lọc Tìm Kiếm** (`components/search/filter-bar.tsx`)
   - Select Giao dịch/Loại BĐS/Giá/Diện tích
   - Tùy chọn thành phố (13 thành phố Việt Nam)

### Component UI:
- **Nút:** Nhãn văn bản ("Đăng nhập", "Tìm kiếm", "Gửi", v.v.)
- **Badge:** Nhãn cho loại bất động sản, trạng thái, hướng
- **Nhãn input:** Trên tất cả các form
- **Thông báo lỗi:** Văn bản cảnh báo

### Điều Hướng:
- **Header công khai:** 4 mục nav chính + menu người dùng
- **Nav dashboard:** 8 phần chính + chuyển đổi theme
- **Footer:** 4 cột liên kết + bản quyền

---

## ♿ Khả Năng Tiếp Cận (Trạng Thái Hiện Tại - WCAG 2.1 AA)

### Đã Triển Khai ✅:
- Liên kết bỏ qua đến nội dung chính (ẩn, hiện khi focus)
- HTML ngữ nghĩa: `<header>`, `<nav>`, `<main>`, `<footer>`
- `aria-label` trên các mục điều hướng
- `aria-label` trên thẻ bất động sản (cho trình đọc màn hình)
- `role="alert"` trên thông báo lỗi
- `aria-invalid` trên các input form
- Nhãn form liên kết với `htmlFor`
- Văn bản alt trên ảnh bất động sản
- `aria-hidden="true"` trên các phần tử trang trí

### Lỗ Hổng Khả Năng Tiếp Cận Cần Khắc Phục 🔧:
1. **Độ tương phản màu sắc:** Cần kiểm tra theo chuẩn WCAG AA
2. **Chỉ báo focus:** Đảm bảo trạng thái focus hiển thị rõ trên tất cả phần tử tương tác
3. **Dialog/Modal:** Cần quản lý focus đúng cách trong dialog
4. **Form:** Đảm bảo nhóm trường với `<fieldset>` khi cần
5. **Xử lý lỗi:** Một số thông báo lỗi thiếu nhãn rõ ràng
6. **Trạng thái tải:** Spinner cần `aria-busy` hoặc `aria-label`
7. **Bảng:** Bảng dữ liệu cần header đúng cách (`<th>`, `scope`)
8. **Liên kết:** Liên kết "Xem tất cả" nên có ngữ cảnh hoặc aria-label
9. **Nút chỉ có icon:** Cần `aria-label` phù hợp
10. **Văn bản thay thế:** Đảm bảo tất cả icon có ý nghĩa đều có nhãn mô tả

### Các Điểm Triển Khai ARIA:
- Điều hướng dropdown (nếu phức tạp)
- Giao diện Tab (recharts/biểu đồ)
- Component tải tệp
- Input ngày/giờ (nếu được thêm vào)

---

## 🔗 Thiết Lập Locale Hiện Tại

### Trạng thái: **CHƯA CÓ i18n**
- Không có package `next-intl`
- Không có tệp dịch (JSON/YAML)
- Không có route theo locale (`/en/*`, `/vi/*`)
- Không có middleware i18n
- **Ngôn ngữ được mã hóa cứng thành tiếng Việt ở khắp nơi**

### Nơi i18n Sẽ Được Tích Hợp:
1. **Middleware:** Phát hiện locale từ URL, cookie, hoặc header `Accept-Language`
2. **Wrapper layout:** Cấu trúc thư mục `[locale]/layout.tsx`
3. **Message providers:** Provider `next-intl` trong layout gốc
4. **Phản hồi API:** Có thể cần quốc tế hóa thông báo lỗi từ backend

---

## 🔒 Cấu Hình Bảo Mật

### Security Headers Cấu Hình Next.js:
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `X-XSS-Protection: 1; mode=block`
- `Content-Security-Policy` với các domain Mapbox được đưa vào danh sách trắng
- `Permissions-Policy` hạn chế camera/microphone/geolocation

### Middleware Xác Thực:
- Kiểm tra xác thực dựa trên cookie (`goodgo_authenticated`)
- Các route được bảo vệ chuyển hướng đến `/login?redirect=...`
- Bảo vệ route công khai trong middleware

---

## 📊 Cấu Trúc Dữ Liệu & Enum Quan Trọng

### Loại Giao Dịch:
```typescript
const TRANSACTION_TYPES = [
  { value: 'SALE', label: 'Bán' },
  { value: 'RENT', label: 'Cho thuê' },
];
```

### Loại Bất Động Sản:
```typescript
const PROPERTY_TYPES = [
  { value: 'APARTMENT', label: 'Căn hộ' },
  { value: 'HOUSE', label: 'Nhà riêng' },
  { value: 'VILLA', label: 'Biệt thự' },
  { value: 'LAND', label: 'Đất nền' },
  { value: 'OFFICE', label: 'Văn phòng' },
  { value: 'SHOPHOUSE', label: 'Shophouse' },
];
```

### Trạng Thái Tin Đăng:
```typescript
const LISTING_STATUSES = {
  DRAFT, PENDING_REVIEW, ACTIVE, RESERVED, SOLD, RENTED, EXPIRED, REJECTED
};
```

### Hướng:
```typescript
const DIRECTIONS = [
  { value: 'NORTH', label: 'Bắc' },
  { value: 'SOUTH', label: 'Nam' },
  { value: 'EAST', label: 'Đông' },
  { value: 'WEST', label: 'Tây' },
  // ... và các tổ hợp đường chéo
];
```

### Thành Phố (13 tổng):
```typescript
Hồ Chí Minh, Hà Nội, Đà Nẵng, Nha Trang, Cần Thơ, Hải Phòng,
Bình Dương, Đồng Nai, Long An, Bà Rịa - Vũng Tàu, [+ more]
```

---

## 🧪 Thiết Lập Kiểm Thử

### Framework Kiểm Thử: Vitest + React Testing Library
- **Tệp cấu hình:** `vitest.config.ts`
- **Tệp thiết lập:** `vitest.setup.ts`
- **Tệp test:** Đặt cạnh source (`__tests__` folders)

### Phạm Vi Test Hiện Tại:
- Test component cho thư viện UI
- Test auth store
- Test schema xác thực
- Test hàm tiện ích

### Thực Hành Tốt Nhất Khi Kiểm Thử i18n:
- Mock provider i18n trong thiết lập test
- Kiểm thử cả hai biến thể locale
- Xác minh các bản dịch hiển thị đúng

---

## 🚀 Mức Độ Sẵn Sàng Triển Khai

### Sẵn Sàng Cho Triển Khai i18n:
✅ Thông báo xác thực tập trung (schema Zod)  
✅ Văn bản UI dựa trên enum/hằng số (TRANSACTION_TYPES, PROPERTY_TYPES, v.v.)  
✅ Thư viện component với các pattern nhất quán  
✅ TypeScript để đảm bảo type safety  
✅ Hỗ trợ middleware cho định tuyến theo locale  

### Cần Tái Cấu Trúc Nhỏ:
⚠️ Trích xuất một số chuỗi được mã hóa cứng ra khỏi component  
⚠️ Chuyển thông báo lỗi form sang tệp message  
⚠️ Tập trung hóa metadata trang cho i18n  

---

## 📝 Tóm Tắt: Các Điểm Triển Khai i18n & A11y

| Khu Vực | Trạng Thái Hiện Tại | Cần Làm |
|---------|---------------------|---------|
| **Hỗ Trợ Locale** | Mã hóa cứng thành tiếng Việt | Triển khai next-intl với định tuyến |
| **Khóa Dịch** | Rải rác trong code | Tập trung vào tệp message |
| **Thông Báo Xác Thực** | Trong schema Zod (tiếng Việt) | Trích xuất sang message i18n |
| **Văn Bản Component** | Chuỗi mã hóa cứng | Dùng hook i18n |
| **Metadata/SEO** | Tiếng Việt mã hóa cứng | Tạo cho từng locale |
| **Độ Tương Phản Màu** | Có thể đạt AA | Kiểm tra và xác minh |
| **Quản Lý Focus** | Một phần (nút/liên kết ổn) | Thêm vào modal & dropdown |
| **Nhãn ARIA** | Phạm vi tốt | Hoàn thiện nhãn còn thiếu |
| **Thông Báo Lỗi** | Hầu hết có aria-invalid | Thêm ngữ cảnh cho một số trường hợp |
| **Trạng Thái Tải** | Spinner tồn tại | Thêm aria-busy, nhãn tốt hơn |
| **Bảng** | Cấu trúc cơ bản | Thêm ngữ nghĩa header đúng cách |

---

## 🗂️ Tóm Tắt Số Lượng Tệp

- **Route ứng dụng:** ~15 tệp trang
- **Component:** ~35 tệp component
- **Tiện ích lib:** ~20 tệp (hooks, API, xác thực)
- **Test:** ~15 tệp test
- **Tệp cấu hình:** ~8 tệp cấu hình
- **Tổng tệp TypeScript/TSX:** ~90+

---

## Các Bước Tiếp Theo Để Triển Khai

1. **Cài đặt i18n:** Thêm `next-intl` vào dependencies
2. **Tạo tệp message:** Thiết lập `messages/en.json` và `messages/vi.json`
3. **Tái cấu trúc middleware:** Thêm phát hiện locale & định tuyến
4. **Cập nhật layout gốc:** Bọc với provider i18n
5. **Cập nhật tất cả component:** Thay thế chuỗi mã hóa cứng bằng `useTranslations()`
6. **Kiểm thử cả hai locale:** Đảm bảo tất cả trang hiển thị đúng
7. **Kiểm tra A11y:** Dùng axe DevTools để xác định các vấn đề còn lại
8. **Quản lý focus:** Thêm focus trapping trong modal
9. **Kiểm thử:** Cập nhật thiết lập test cho mock i18n

---

**Báo Cáo Được Tạo:** 9 tháng 4, 2026  
**Phạm Vi Khám Phá:** Toàn diện  
**Độ Tin Cậy:** Cao
