╔════════════════════════════════════════════════════════════════════════════╗ ║ GOODGO PLATFORM AI - NEXT.JS FRONTEND QUICK REFERENCE ║ ╚════════════════════════════════════════════════════════════════════════════╝ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1. PROJECT STRUCTURE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ /apps/web/ ├─ app/[locale]/ ← Next.js 15 App Router (public, auth, dashboard, admin) ├─ components/ ← React components (listings, neighborhood, map, charts, design-system) ├─ lib/ ← API clients, hooks, stores, utilities ├─ i18n/ & messages/ ← Internationalization (vi/en) └─ public/ ← Static assets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2. CORE TECHNOLOGIES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Framework: Next.js 15.5.14 (App Router) Runtime: React 18.3.0 Styling: Tailwind CSS 3.4.0 + CVA 0.7.1 Forms: react-hook-form 7.72.1 + Zod 4.3.6 State: Zustand 5.0.12 (client) + React Query 5.96.2 (server) Mapping: Mapbox GL 3.21.0 Charts: Recharts 3.8.1 Icons: lucide-react 1.7.0 i18n: next-intl 4.9.0 Theme: next-themes 0.4.6 Real-time: socket.io-client 4.8.3 PDF Export: html2canvas 1.4.1 + jspdf 4.2.1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3. NEIGHBORHOOD FEATURES ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ COMPONENTS: ✓ NeighborhoodPOIMap (11 KB, Mapbox GL + 6 POI categories) ✓ NeighborhoodRadarChart (2 KB, Recharts radar, 0-10 scores, 6 categories) ✓ NeighborhoodScore (2 KB, compact score display) TYPES & CONFIG: ✓ NeighborhoodCategory (label, score 0-10, icon) ✓ POIItem (id, name, category, lat/lng, distance) ✓ POICategory (school, hospital, transit, shopping, restaurant, park) ✓ NeighborhoodScoreData (overall score, categories, POIs, center) INTEGRATION: ✓ Dynamically loaded in listing-detail-client.tsx ✓ Part of enrichment data pipeline (API response) ✓ Maps imported with SSR disabled for performance ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4. MAPBOX GL USAGE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ COMPONENTS: • listing-map.tsx Multiple listings + click handlers • location-picker.tsx Interactive location selection • neighborhood-poi-map.tsx POI visualization with filters STYLING: • Light: mapbox://styles/mapbox/streets-v12 • Dark: mapbox://styles/mapbox/dark-v11 • Theme-aware via useMapboxStyle() hook PATTERN: 'use client' ← Must be client component import 'mapbox-gl/dist/mapbox-gl.css' const style = useMapboxStyle() ← Get theme-aware style new mapboxgl.Map({ style }) ← Create map instance ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5. CHART COMPONENTS (RECHARTS) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ✓ price-area-chart.tsx Trend visualization (up/down coloring) ✓ price-trend-chart.tsx Historical trends ✓ district-bar-chart.tsx District comparisons ✓ district-heatmap.tsx Heat visualization (9 KB) ✓ agent-performance.tsx Agent metrics (6 KB) ✓ neighborhood-radar-chart.tsx Radar chart (0-10 scores) PATTERN: ResponsiveContainer ← Responsive sizing CSS variables for theming ← --color-signal-up, --color-signal-down Custom Tooltip styling ← Themed backgrounds Vietnamese number formatting ← tr/k notation ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6. API CLIENT PATTERN ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BASE CLIENT (lib/api-client.ts): apiClient.get(endpoint, headers?) apiClient.post(endpoint, body?, headers?) apiClient.patch(endpoint, body?, headers?) apiClient.delete(endpoint, headers?) FEATURES: ✓ CSRF token handling (from cookies) ✓ Automatic 401 refresh-and-retry (except auth endpoints) ✓ Concurrent refresh coalescing ✓ Type-safe with generics ✓ Base URL from NEXT_PUBLIC_API_URL env var DOMAIN-SPECIFIC CLIENTS (lib/*-api.ts): listings-api.ts | Listing CRUD, search analytics-api.ts | Market reports, heatmaps, trends neighborhood-api.ts | Neighborhood scoring (if exists) valuation-api.ts | AVM estimates agents-api.ts | Agent profiles khu-cong-nghiep-api | Industrial parks du-an-api.ts | Projects inquiries-api.ts | Inquiries leads-api.ts | Leads admin-api.ts | Admin operations ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 7. REACT QUERY HOOKS (lib/hooks/) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ PATTERN: const analyticsKeys = { all: ['analytics'] as const, marketReport: (city, period) => ['analytics', 'market-report', city, period] as const, }; export function useMarketReport(city: string, period: string) { return useQuery({ queryKey: analyticsKeys.marketReport(city, period), queryFn: () => analyticsApi.getMarketReport(city, period), }); } AVAILABLE HOOKS: use-analytics.ts useMarketReport, useHeatmap, usePriceTrend, etc. use-listings.ts useListings, useListing use-khu-cong-nghiep.ts useIndustrialParks use-du-an.ts useProjects use-valuation.ts useValuation use-inquiries.ts useInquiries use-leads.ts useLeads use-reports.ts useReports use-saved-searches.ts useSavedSearches ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8. LISTING DETAIL PAGE FLOW ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ROUTE: /[locale]/(public)/listings/[id]/page.tsx 1. SERVER COMPONENT (RSC) ├─ generateMetadata() ← SEO: OG, canonical, schema └─ fetchListingById(id) ← Data fetching 2. CLIENT COMPONENT (listing-detail-client.tsx - 39 KB) ├─ ImageGallery ← Media slideshow ├─ KPI Strip ← Trader-style metrics ├─ Core Details ← Address, bedrooms, etc. ├─ PriceHistoryChart ← Recharts trend ├─ Neighborhood Section │ ├─ NeighborhoodRadarChart ← (dynamic import, SSR: false) │ └─ NeighborhoodPOIMap ← (dynamic import, SSR: false) ├─ AiAdviceCards ← Personas ├─ SimilarListings ← Recommendations ├─ AgentCard ← Quality score └─ CTA Section ← Inquiry, comparison, estimate ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9. STATE MANAGEMENT LAYERS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ LAYER 1: REACT QUERY (Server State) Purpose: Fetch & cache API data Provider: QueryProvider (components/providers/query-provider.tsx) Error Handle: QueryErrorResetBoundary + custom error boundary Usage: useQuery, useMutation hooks LAYER 2: ZUSTAND (Client State) Purpose: UI state, preferences Examples: auth-store, comparison-store, preferences-store Persistence: localStorage integration Usage: Direct store access or hooks LAYER 3: CONTEXT (Global Features) Theme: ThemeProvider (next-themes) Notifications: NotificationsProvider Auth: AuthProvider Query: QueryProvider ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10. DESIGN SYSTEM COMPONENTS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FINANCIAL METRICS: ✓ kpi-card.tsx Key performance indicator ✓ stat-card.tsx Statistics display ✓ ticker-strip.tsx Horizontal ticker/marquee ✓ price-delta.tsx Price change with signal ✓ signal.tsx Up/down indicator ✓ numeric.tsx Formatted number display DATA DISPLAY: ✓ data-table.tsx @tanstack/react-table wrapper ✓ empty-state.tsx Empty data fallback ✓ skeleton.tsx Loading skeleton ✓ status-chip.tsx Status badge LAYOUT: ✓ dashboard-layout.tsx Dashboard structure ✓ density-provider.tsx Compact/dense mode toggle ✓ divider.tsx Visual separator UI PRIMITIVES (from shadcn/ui via design-system/): ✓ badge.tsx, button.tsx, card.tsx, dialog.tsx, etc. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11. INTERNATIONALIZATION (i18n) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SETUP: Library: next-intl 4.9.0 Locales: vi (Vietnamese), en (English) Route param: [locale] prefix Translations: /messages/ directory USAGE: const t = useTranslations(); {t('key.path')} ROUTES: /vi/listings/[id] ← Vietnamese /en/listings/[id] ← English ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12. PERFORMANCE OPTIMIZATIONS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE SPLITTING: dynamic(() => import(...), { ssr: false }) ← Heavy components (maps, charts) LAZY LOADING: loading: () => ← Show UI while loading IMAGE OPTIMIZATION: next/image ← Built-in optimization CACHING: React Query query keys ← Automatic deduplication & refetch intervals CSS-IN-JS: Tailwind + CVA ← Static + composable variants ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13. KEY FILE PATHS REFERENCE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ NEIGHBORHOOD: lib/components/neighborhood/ Components lib/components/neighborhood/types.ts Type definitions lib/components/neighborhood/neighborhood-poi-map.tsx Mapbox POI layer lib/components/neighborhood/neighborhood-radar-chart.tsx Radar scores MAPPING: lib/mapbox-style.ts Theme-aware styles lib/components/map/listing-map.tsx Listings on map lib/components/map/location-picker.tsx Location selection CHARTS: lib/components/charts/ Chart components lib/components/charts/price-area-chart.tsx Area trend chart API & STATE: lib/api-client.ts Base HTTP client lib/listings-api.ts Listings endpoints lib/analytics-api.ts Analytics endpoints lib/hooks/use-analytics.ts Analytics React Query hooks LISTING DETAIL: app/[locale]/(public)/listings/[id]/page.tsx Server component lib/components/listings/listing-detail-client.tsx Client component (39 KB) PROVIDERS: lib/components/providers/query-provider.tsx React Query setup lib/components/providers/theme-provider.tsx Theme management ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14. CODING PATTERNS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ COMPONENT FILE HEADER: 'use client' ← Client component marker import ... ← External imports import ... ← Internal imports interface ComponentProps { ... } ← Props interface export function Component({ ... }: ComponentProps) { // implementation } API CLIENT USAGE: const data = await apiClient.get('/endpoint'); const result = await apiClient.post('/endpoint', body); REACT QUERY HOOK: export function useData(param: string) { return useQuery({ queryKey: ['key', param], queryFn: () => api.getData(param), enabled: !!param, ← Conditional queries }); } COMPONENT IMPORTS: import dynamic from 'next/dynamic'; const Map = dynamic(() => import('...').then(m => m.Component), { ssr: false, loading: () => }); ZUSTAND STORE: import { create } from 'zustand'; const useStore = create((set) => ({ value: null, setValue: (v) => set({ value: v }), })); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 15. DEBUGGING & DEVELOPMENT TIPS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ENV VARS: NEXT_PUBLIC_API_URL ← Backend API base URL NEXT_PUBLIC_SITE_URL ← Frontend base URL MAPBOX_ACCESS_TOKEN ← Mapbox API key SCRIPTS: npm run dev ← Start dev server (port 3000) npm run build ← Production build npm run lint ← ESLint npm test ← Vitest npm run typecheck ← TypeScript check HOT TIPS: • Dynamic imports reduce bundle size for heavy components • React Query keys are the foundation of caching strategy • Use CSS variables for theming (see design-system/) • Barrel exports (index.ts) for cleaner imports • Zustand for simple state, React Query for server state • Always check enabled condition in useQuery() for dependent queries ╔════════════════════════════════════════════════════════════════════════════╗ ║ Report Generated: April 2026 ║ ║ Base Path: /Users/velikho/Desktop/WORKING/goodgo-platform-ai/apps/web ║ ╚════════════════════════════════════════════════════════════════════════════╝