Files
goodgo-platform/docs/audits/FRONTEND_EXPLORATION.md
Ho Ngoc Hai 11f2bf26e6
Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 29s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m42s
Deploy / Build Web Image (push) Failing after 27s
Deploy / Build AI Services Image (push) Failing after 29s
E2E Tests / Playwright E2E (push) Failing after 43s
Deploy / Build API Image (push) Failing after 1m31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 6s
Security Scanning / Trivy Scan — API Image (push) Failing after 5m35s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 3m45s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Security Scanning / Trivy Scan — Web Image (push) Failing after 13m51s
Security Scanning / Trivy Filesystem Scan (push) Failing after 14m46s
Security Scanning / Security Gate (push) Has been cancelled
chore: update project documentation, audit reports, and initialize IDE configuration files
2026-04-19 03:12:54 +07:00

22 KiB

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:

{
  "@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ử):

{
  "@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:

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:

- 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):

- 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:

const TRANSACTION_TYPES = [
  { value: 'SALE', label: 'Bán' },
  { value: 'RENT', label: 'Cho thuê' },
];

Loại Bất Động Sản:

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:

const LISTING_STATUSES = {
  DRAFT, PENDING_REVIEW, ACTIVE, RESERVED, SOLD, RENTED, EXPIRED, REJECTED
};

Hướng:

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):

Hồ Chí Minh,  Nội, Đà Nẵng, Nha Trang, Cần Thơ, Hải Phòng,
Bình Dương, Đồng Nai, Long An,  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.jsonmessages/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