# Trang Hồ Sơ Công Khai Môi Giới — Hướng Dẫn Tham Khảo Nhanh

## 🎯 Tổng Quan Triển Khai

### Cấu Trúc URL
```
/agents/[id]                    # Desktop
/agents/[id]?locale=vi          # Với locale (i18n)
/en/agents/[id]                 # Locale tường minh
```

### Vị Trí Trang
```
apps/web/app/[locale]/(public)/agents/[id]/page.tsx
```

---

## 📦 Cấu Hình Backend (Cần Thay Đổi API)

### Endpoint Công Khai Mới
```http
GET /agents/:agentId/profile
```

### DTO Phản Hồi
```typescript
{
  id: string;
  fullName: string;
  avatarUrl: string | null;
  licenseNumber: string | null;
  agency: string | null;
  qualityScore: number;
  bio: string | null;
  serviceAreas: string[];
  isVerified: boolean;
  totalListings: number;
  activeListings: number;
  avgReviewRating: number;
  totalReviews: number;
  phone?: string;
  createdAt: string;
  updatedAt: string;
}
```

### Các File Query Handler Cần Tạo
```
apps/api/src/modules/agents/application/queries/get-agent-profile/
├── get-agent-profile.query.ts
└── get-agent-profile.handler.ts

apps/api/src/modules/agents/presentation/dto/
└── agent-public-profile.dto.ts
```

---

## 🎨 Kiến Trúc Frontend

### Cấu Trúc Thư Mục Cần Tạo
```
apps/web/
├── app/[locale]/(public)/agents/
│   └── [id]/
│       ├── page.tsx              ← Server component (metadata, ISR)
│       └── layout.tsx            ← Layout dùng chung tùy chọn
│
├── components/agents/
│   ├── agent-detail-client.tsx   ← Component tương tác chính
│   ├── agent-header.tsx          ← Phần thông tin hồ sơ
│   ├── agent-listings-section.tsx ← Lưới danh sách bất động sản
│   └── agent-reviews-section.tsx  ← Đánh giá với sao
│
└── lib/
    ├── agents-api.ts            ← API client
    └── agents-server.ts         ← Fetch phía server (ISR)
```

---

## 🔄 Luồng Dữ Liệu

```
1. Trình duyệt yêu cầu: /agents/[id]
                ↓
2. Next.js tạo metadata (SEO)
   - Title: "Agent Name — Real Estate Agent at GoodGo"
   - Description: Bio + thống kê
   - Image: Avatar
   - Canonical URL
                ↓
3. Fetch dữ liệu hồ sơ môi giới phía server
   - GET /api/v1/agents/:id/profile (ISR: revalidate 3600s)
                ↓
4. Render Server Component với metadata + JSON-LD
                ↓
5. Truyền dữ liệu sang Client Component để tương tác
   - Fetch đánh giá song song
   - Fetch danh sách bất động sản song song
                ↓
6. Client render:
   - Header môi giới (avatar, tên, thống kê, huy hiệu)
   - Phần đánh giá (xếp hạng sao, thẻ bình luận)
   - Phần danh sách bất động sản (tái sử dụng component PropertyCard)
```

---

## 🎭 Kết Hợp Component

### Server Component (page.tsx)
```typescript
export async function generateMetadata({ params }): Promise<Metadata> {
  // 1. Fetch môi giới dùng agents-server.ts
  // 2. Xây dựng metadata SEO
  // 3. Trả về title, description, OG, canonical
}

export default async function AgentProfilePage({ params }) {
  // 1. Fetch hồ sơ môi giới (với ISR)
  // 2. Tạo JSON-LD (schema LocalBusiness)
  // 3. Render <JsonLd> cho dữ liệu có cấu trúc
  // 4. Truyền agent sang client component
  return <>
    <JsonLd data={agentJsonLd} />
    <AgentDetailClient agent={agent} />
  </>
}
```

### Client Component (agent-detail-client.tsx)
```typescript
'use client';

export function AgentDetailClient({ agent }: Props) {
  const [listings, setListings] = useState([]);
  const [reviews, setReviews] = useState([]);
  const [reviewStats, setReviewStats] = useState(null);

  useEffect(() => {
    // Fetch danh sách bất động sản đang hoạt động của môi giới
    // Fetch đánh giá & thống kê
  }, [agent.id]);

  return <>
    <AgentHeader agent={agent} />
    <AgentReviewsSection reviews={reviews} stats={reviewStats} />
    <AgentListingsSection listings={listings} />
  </>
}
```

---

## 🔗 Các API Call Được Sử Dụng

### Endpoint Công Khai Hiện Có (Không Cần Xác Thực)
```http
# Lấy hồ sơ môi giới (MỚI - cần tạo)
GET /api/v1/agents/:agentId/profile

# Lấy danh sách bất động sản của môi giới (ĐÃ CÓ)
GET /api/v1/listings?agentId=:agentId&status=ACTIVE

# Lấy đánh giá môi giới (ĐÃ CÓ)
GET /api/v1/reviews?targetType=AGENT&targetId=:agentId&limit=20

# Lấy thống kê đánh giá môi giới (ĐÃ CÓ)
GET /api/v1/reviews/stats?targetType=AGENT&targetId=:agentId
```

---

## 🎨 Các Phần UI & Component Tái Sử Dụng

### 1. Phần Header Môi Giới
```
┌─────────────────────────────────┐
│ [Avatar] Tên                    │
│          Giấy phép: ABC123      │
│          Công ty: XYZ Agency    │
│          ✓ Đã Xác Minh          │
│                                 │
│ ⭐ 4.5 (120 đánh giá)           │
│ 📍 Phục vụ: Quận 1, Quận 7, ...│
│ 🏠 45 tin đăng đang hoạt động  │
└─────────────────────────────────┘

Components: Card, Badge, Image, Text
Styling: Tailwind (p-6, flex, gap-4)
```

### 2. Phần Đánh Giá
```
┌─────────────────────────────────┐
│ Đánh Giá Khách Hàng (120 tổng) │
├─────────────────────────────────┤
│ [Thẻ Đánh Giá]                  │
│ ⭐⭐⭐⭐⭐ John Doe  │ 2 ngày trước│
│ "Môi giới tuyệt vời, rất chuyên nghiệp" │
├─────────────────────────────────┤
│ [Thẻ Đánh Giá]                  │
│ ⭐⭐⭐⭐ Jane Smith │ 1 tuần trước│
│ "Giao tiếp tốt"                  │
└─────────────────────────────────┘

Components: Card, Badge (xếp hạng), Avatar
Tái sử dụng: Kiểu padding/spacing của PropertyCard
```

### 3. Phần Danh Sách Bất Động Sản
```
┌─────────────────────────────────┐
│ Tin Đăng Đang Hoạt Động (45)   │
├─────────────────────────────────┤
│ [PropertyCard]  [PropertyCard]   │
│ [PropertyCard]  [PropertyCard]   │
│ [PropertyCard]  [PropertyCard]   │
└─────────────────────────────────┘

Components: PropertyCard (tái sử dụng từ search/property-card.tsx)
Grid: grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4
```

---

## 🎯 Mẫu Copy-Paste

### agents-api.ts
```typescript
import { apiClient } from './api-client';

export interface AgentPublicProfile {
  id: string;
  fullName: string;
  avatarUrl: string | null;
  licenseNumber: string | null;
  agency: string | null;
  qualityScore: number;
  bio: string | null;
  serviceAreas: string[];
  isVerified: boolean;
  totalListings: number;
  activeListings: number;
  avgReviewRating: number;
  totalReviews: number;
  createdAt: string;
  updatedAt: string;
}

export const agentsApi = {
  getById: (id: string) => 
    apiClient.get<AgentPublicProfile>(`/agents/${id}/profile`),
};
```

### agents-server.ts
```typescript
const API_BASE_URL = process.env['NEXT_PUBLIC_API_URL'] || 'http://localhost:3001/api/v1';

export async function fetchAgentById(id: string) {
  try {
    const res = await fetch(`${API_BASE_URL}/agents/${id}/profile`, {
      next: { revalidate: 3600 } // ISR: revalidate mỗi 1 giờ
    });
    if (!res.ok) return null;
    return res.json();
  } catch {
    return null;
  }
}
```

---

## 🔍 SEO & Dữ Liệu Có Cấu Trúc

### Gợi Ý Metadata
```typescript
title: `${agent.fullName} — Real Estate Agent at GoodGo`
description: `${agent.bio}. Quality Score: ${agent.qualityScore}. ${agent.activeListings} active listings. ⭐ ${agent.avgReviewRating} (${agent.totalReviews} reviews)`

// OG Image: Dùng avatar hoặc ảnh thay thế
```

### Schema JSON-LD
```json
{
  "@context": "https://schema.org",
  "@type": "LocalBusiness",
  "name": "Agent Full Name",
  "description": "Bio",
  "url": "https://goodgo.vn/en/agents/[id]",
  "image": "avatarUrl",
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.5,
    "reviewCount": 120
  },
  "areaServed": ["Quan 1", "Quan 7", "Thu Duc"],
  "knowsAbout": "Real Estate"
}
```

---

## 🚀 Các Giai Đoạn Triển Khai

### Giai Đoạn 1: Backend (1-2 giờ)
- [ ] Tạo GetAgentProfileQuery
- [ ] Tạo GetAgentProfileHandler
- [ ] Tạo AgentPublicProfileDto
- [ ] Thêm endpoint vào AgentsController
- [ ] Cập nhật interface AgentRepository
- [ ] Triển khai trong PrismaAgentRepository
- [ ] Kiểm tra với Postman/curl

### Giai Đoạn 2: Cài Đặt Frontend (1 giờ)
- [ ] Tạo agents-api.ts
- [ ] Tạo agents-server.ts
- [ ] Tạo cấu trúc thư mục agents
- [ ] Tạo [id]/page.tsx (stub)
- [ ] Import kiểu từ agents-api.ts

### Giai Đoạn 3: Các Component UI (2-3 giờ)
- [ ] Tạo component AgentHeader
- [ ] Tạo component AgentReviewsSection
- [ ] Tạo component AgentListingsSection
- [ ] Tạo các component RatingStars/ReviewCard
- [ ] Kết nối việc fetch dữ liệu

### Giai Đoạn 4: SEO & Hoàn Thiện (1 giờ)
- [ ] Thêm generateMetadata()
- [ ] Tạo schema JSON-LD
- [ ] Kiểm tra xem trước OG
- [ ] Kiểm tra responsive trên di động
- [ ] Kiểm tra chế độ tối

### Giai Đoạn 5: Kiểm Thử (1 giờ)
- [ ] Kiểm thử e2e thủ công
- [ ] Kiểm tra xử lý lỗi 404
- [ ] Xác minh việc revalidate ISR
- [ ] Kiểm tra phân trang (danh sách/đánh giá)
- [ ] Kiểm tra SEO (Lighthouse)

---

## 📊 Ví Dụ Cấu Trúc Phản Hồi

```json
{
  "id": "clu1x2y3z4a5b6c7d8e9f0",
  "fullName": "Nguyễn Văn A",
  "avatarUrl": "https://cdn.goodgo.vn/avatars/agent-123.jpg",
  "licenseNumber": "DA123456",
  "agency": "GoodGo Agency",
  "qualityScore": 4.8,
  "bio": "Specialized in high-end real estate in District 1 and 7",
  "serviceAreas": ["quan-1", "quan-7", "thu-duc"],
  "isVerified": true,
  "totalListings": 45,
  "activeListings": 32,
  "avgReviewRating": 4.7,
  "totalReviews": 120,
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-04-10T15:45:00Z"
}
```

---

## 🎯 Tham Khảo Các File Chính

| Giai Đoạn | File Cần Tạo/Chỉnh Sửa |
|-----------|------------------------|
| Backend | `agents/application/queries/get-agent-profile/*` |
| Backend | `agents/presentation/controllers/agents.controller.ts` |
| Backend | `agents/presentation/dto/agent-public-profile.dto.ts` |
| Frontend | `lib/agents-api.ts` |
| Frontend | `lib/agents-server.ts` |
| Frontend | `app/[locale]/(public)/agents/[id]/page.tsx` |
| Frontend | `components/agents/agent-detail-client.tsx` |
| Frontend | `components/agents/agent-header.tsx` |
| Frontend | `components/agents/agent-reviews-section.tsx` |
| Frontend | `components/agents/agent-listings-section.tsx` |
