- Move 8 stray .md (+5 .txt) from ~/Desktop into docs/explorations/from-desktop/ - Reorganize 27 .md/.txt at workspace root: - audit reports -> docs/audits/ - exploration reports -> docs/explorations/ - design system -> docs/design-system/ - Keep only README/CHANGELOG/CONTRIBUTING/CLAUDE at repo root - Refresh docs/README.md as canonical index with links to all groups - Note: pre-existing docs/audits/AUDIT_INDEX.md and AUDIT_SUMMARY.md were overwritten by the newer root-level versions during the move Co-Authored-By: Paperclip <noreply@paperclip.ing>
16 KiB
16 KiB
GoodGo Platform AI - Next.js Frontend Exploration Report
1. Overall Directory Structure
Root Layout
/Users/velikho/Desktop/WORKING/goodgo-platform-ai/apps/web/
├── app/ # Next.js App Router directory
├── components/ # Reusable React components
├── lib/ # API clients, hooks, utilities, stores
├── i18n/ # Internationalization config
├── messages/ # Translation files
├── public/ # Static assets
├── node_modules/ # Dependencies
└── package.json # Project metadata & dependencies
Key Dependencies (from package.json)
- Framework: Next.js 15.5.14, React 18.3.0
- State Management: Zustand 5.0.12 (lightweight state), @tanstack/react-query 5.96.2 (server state)
- Forms: react-hook-form 7.72.1, @hookform/resolvers 5.2.2, zod 4.3.6
- Mapping: mapbox-gl 3.21.0, @types/mapbox-gl 3.5.0
- Charts: recharts 3.8.1
- UI: Tailwind CSS 3.4.0, class-variance-authority 0.7.1
- Icons: lucide-react 1.7.0
- Other: next-intl 4.9.0, next-themes 0.4.6, socket.io-client 4.8.3, html2canvas + jspdf
2. App Router Structure (Next.js 15 App Router)
Directory: /app/[locale]/
Routes are organized by locale (vi/en) with multiple layout groups:
app/[locale]/
├── (public)/ # Public routes (no auth required)
│ ├── listings/
│ │ ├── page.tsx # Listings search/browse page
│ │ └── [id]/page.tsx # Individual listing detail page
│ ├── search/ # Advanced search interface
│ ├── khu-cong-nghiep/ # Industrial parks (Vietnamese)
│ ├── du-an/ # Projects
│ ├── bao-cao/ # Reports
│ ├── agents/[id]/ # Agent profiles
│ └── payment/return/ # Payment callbacks
├── (auth)/ # Authentication routes
│ ├── login/page.tsx
│ ├── register/page.tsx
│ └── auth/callback/ # OAuth callbacks (Google, Zalo)
├── (dashboard)/ # Protected routes (auth required)
│ ├── dashboard/ # Main dashboard
│ ├── analytics/ # Market analytics
│ ├── industrial-parks/ # Industrial park management
│ ├── valuation/ # Valuation service
│ ├── reports/ # User's reports
│ └── ...
├── (admin)/ # Admin routes
│ └── admin/
│ ├── users/
│ ├── kyc/
│ ├── moderation/
│ └── ...
├── auth/callback/ # Special auth callbacks
│ ├── zalo/page.tsx
│ └── google/page.tsx
└── [locale]/layout.tsx # Root layout wrapping all routes
3. Components Directory Structure
Organized by Domain:
components/
├── listings/ # Listing-related components
│ ├── listing-detail-client.tsx (39KB - main detail component)
│ ├── listing-form-steps.tsx (14KB - form wizard)
│ ├── ai-advice-cards.tsx (9KB - AI recommendations)
│ ├── image-gallery.tsx
│ ├── image-lightbox.tsx
│ ├── image-upload.tsx
│ ├── inquiry-modal.tsx
│ ├── price-history-chart.tsx (uses recharts)
│ ├── social-share.tsx
│ └── sparkline.tsx
│
├── neighborhood/ # Neighborhood analysis components
│ ├── neighborhood-poi-map.tsx (11KB - POI map with Mapbox)
│ ├── neighborhood-radar-chart.tsx (2KB - radar chart)
│ ├── neighborhood-score.tsx (2KB - score display)
│ ├── types.ts # Shared types & config
│ └── index.ts # Barrel export
│
├── map/ # Map components
│ ├── listing-map.tsx (10KB - listings on Mapbox)
│ └── location-picker.tsx (9KB - location selection)
│
├── charts/ # Recharts-based charts
│ ├── price-area-chart.tsx (2KB - trend visualization)
│ ├── price-trend-chart.tsx
│ ├── district-bar-chart.tsx
│ ├── district-heatmap.tsx (9KB - with Mapbox)
│ └── agent-performance.tsx
│
├── design-system/ # Reusable UI primitives & patterns
│ ├── badge.tsx
│ ├── kpi-card.tsx # Key performance indicator card
│ ├── stat-card.tsx # Statistics card
│ ├── ticker-strip.tsx # Horizontal ticker
│ ├── price-delta.tsx # Price change indicator
│ ├── signal.tsx # Up/down signal display
│ ├── numeric.tsx # Formatted number display
│ ├── status-chip.tsx
│ ├── empty-state.tsx
│ ├── skeleton.tsx
│ ├── data-table.tsx # @tanstack/react-table wrapper
│ ├── dashboard-layout.tsx
│ ├── density-provider.tsx # Density/compact mode
│ └── index.ts
│
├── khu-cong-nghiep/ # Industrial park domain
├── du-an/ # Project domain
├── agents/ # Real estate agents
├── valuation/ # Valuation/AVM features
├── search/ # Search interface
├── comparison/ # Property comparison
├── leads/ # Lead management
├── inquiries/ # Inquiry management
├── reports/ # Report generation
├── chuyen-nhuong/ # Transfer/ownership change
├── notifications/
├── auth/
├── providers/ # React context providers
│ ├── auth-provider.tsx
│ ├── query-provider.tsx # React Query with error boundary
│ ├── theme-provider.tsx # next-themes integration
│ ├── notifications-provider.tsx
│ └── web-vitals.tsx
├── seo/ # SEO components
│ └── json-ld.tsx # JSON-LD schema generation
├── subscription/
├── ui/ # Base UI components (from shadcn/ui)
│ ├── badge.tsx
│ ├── button.tsx
│ ├── card.tsx
│ ├── dialog.tsx
│ └── ... (standard shadcn components)
4. Existing Neighborhood Components
Key Files:
-
components/neighborhood/types.tsNeighborhoodCategory: score category with label, score (0-10), iconPOIItem: Point of Interest (school, hospital, etc.) with lat/lngNeighborhoodScoreData: aggregated neighborhood dataPOI_CATEGORY_CONFIG: config for 6 categories (school, hospital, transit, shopping, restaurant, park)DEFAULT_CATEGORIES: default scoring categories
-
components/neighborhood/neighborhood-poi-map.tsx- Uses Mapbox GL with hardcoded SVG icons for 6 POI categories
- Category filter toggles
- Responsive map with custom markers
- Integrated POI display
-
components/neighborhood/neighborhood-radar-chart.tsx- Recharts
RadarChartcomponent - 0-10 score scale
- Badge display below chart
- Responsive, themed
- Recharts
-
components/neighborhood/neighborhood-score.tsx- Small score display component
- Used as quick reference
Integration in Listing Detail:
- Dynamically imported in
listing-detail-client.tsx - Used when neighborhood data is available from API
- Part of the enrichment data pipeline
5. Mapbox GL Integration
Setup & Styling:
lib/mapbox-style.tsexport const MAPBOX_STYLE_LIGHT = 'mapbox://styles/mapbox/streets-v12'; export const MAPBOX_STYLE_DARK = 'mapbox://styles/mapbox/dark-v11'; export function useMapboxStyle(): string { const { theme } = useTheme(); return theme === 'dark' ? MAPBOX_STYLE_DARK : MAPBOX_STYLE_LIGHT; }
Map Components:
-
components/map/listing-map.tsx(10KB)- Displays multiple listings as markers
- Custom markers with price popup
- Click handler for marker selection
- Responsive sizing
- City coordinate presets for auto-centering
-
components/map/location-picker.tsx(9KB)- Interactive location selection
- User-clickable map for address input
- Reverse geocoding integration
-
components/neighborhood/neighborhood-poi-map.tsx(11KB)- POI visualization with category filters
- SVG marker icons (6 types)
- Distance display
- Category toggle buttons
Pattern:
- Maps created as client components (
'use client') - Mapbox GL CSS imported per file
- Theme-aware style selection via
useMapboxStyle() - Responsive containers
6. API Client Setup
Main Client: lib/api-client.ts (127 lines)
// Core features:
- Base URL from environment: process.env.NEXT_PUBLIC_API_URL
- CSRF token handling from cookies
- Automatic 401 refresh-and-retry (except auth endpoints)
- Concurrent refresh coalescing
- Type-safe request/response with generics
- Credentials: include for cookies
// API methods:
apiClient.get<T>(endpoint, headers?)
apiClient.post<T>(endpoint, body?, headers?)
apiClient.patch<T>(endpoint, body?, headers?)
apiClient.delete<T>(endpoint, headers?)
Domain-Specific API Clients (in lib/):
listings-api.ts- Listing CRUD, search, recommendationsanalytics-api.ts- Market reports, heatmaps, price trendsagents-api.ts- Agent profiles & statsvaluation-api.ts- AVM (Automated Valuation Model) estimateskhu-cong-nghiep-api.ts- Industrial park datadu-an-api.ts- Project datainquiries-api.ts- Inquiry managementleads-api.ts- Lead datareports-api.ts- Report generationadmin-api.ts- Admin operationsauth-api.ts- Auth endpointspayment-api.ts- Payment processing
Each API module:
- Defines request/response interfaces
- Uses
apiClienthelper for HTTP calls - May have both client and server implementations
7. Hooks & React Query Integration
React Query Setup: lib/query-client.ts
// Creates QueryClient singleton
// Provider in components/providers/query-provider.tsx
// Includes QueryErrorResetBoundary error handling
Custom Hooks: lib/hooks/
use-analytics.ts - Market reports, heatmaps, trends
use-khu-cong-nghiep.ts - Industrial parks
use-du-an.ts - Projects
use-listings.ts - Listings data
use-valuation.ts - AVM valuations
use-inquiries.ts - Inquiries
use-leads.ts - Leads
use-reports.ts - Reports
use-saved-searches.ts - Saved search queries
use-socket-notifications.ts - Real-time notifications
Hook Pattern (example from use-analytics.ts):
export const analyticsKeys = {
all: ['analytics'] as const,
marketReport: (city, period) => [...],
// ...
};
export function useMarketReport(city: string, period: string) {
return useQuery({
queryKey: analyticsKeys.marketReport(city, period),
queryFn: () => analyticsApi.getMarketReport(city, period),
});
}
8. Chart Components
Using Recharts:
-
components/charts/price-area-chart.tsx- AreaChart with gradient fills
- Up/down signal coloring
- Formatted Y-axis (tr/k notation for Vietnamese)
- Responsive container
-
components/charts/district-heatmap.tsx(9KB)- District-level visualization
- Possibly Mapbox layer integration
-
components/charts/price-trend-chart.tsx- Historical price trends
- Multi-period comparison
-
components/charts/district-bar-chart.tsx- Bar chart for district comparisons
-
components/charts/agent-performance.tsx(6KB)- Agent metrics visualization
-
components/listings/price-history-chart.tsx(2KB)- Listing-specific price history
- Small inline chart
Recharts Pattern:
ResponsiveContainerfor responsive sizing- Custom CSS variable colors (--color-signal-up, --signal-down, etc.)
- Tooltip with custom styling
- Dark/light theme support via CSS variables
9. Listing Detail Page Structure
Route: app/[locale]/(public)/listings/[id]/page.tsx
- Server component (RSC) for metadata generation
- Uses
generateMetadata()for SEO (Open Graph, canonical URLs) - Fetches listing via
fetchListingById() - Returns
<ListingDetailClient>for interactivity
Client Component: components/listings/listing-detail-client.tsx (39KB)
Core Sections:
- Image Gallery -
<ImageGallery> - KPI Strip - Trader-style metrics (price, m², DOM, etc.)
- Core Details - Address, bedrooms, furnishing, etc.
- Price History Chart -
<PriceHistoryChart> - Neighborhood Section - Dynamically loaded:
<NeighborhoodRadarChart>(6 categories, 0-10 scores)<NeighborhoodPOIMap>(POI layer)
- AI Advice Cards -
<AiAdviceCards>with personas - Similar Listings - Recommendations
- Agent Card - Agent quality score & info
- Call-to-Action - Inquiry modal, comparison, AI estimate
Key Data Types:
export interface ListingDetail {
id: string;
status: ListingStatus;
transactionType: 'SALE' | 'RENT';
priceVND: string;
property: { title, address, bedrooms, areaM2, media[], ... };
valuationEstimate?: { value, confidence, ... };
neighborhoodScore?: NeighborhoodScoreData;
agentQualityScore?: AgentQualityScore;
similarListings?: ListingSimilarItem[];
// ...
}
Dynamic Imports (performance):
NeighborhoodRadarChart- SSR disabledNeighborhoodPOIMap- SSR disabled + loading fallback
10. State Management Patterns
React Query (Server State):
- Used for API data fetching & caching
- Query keys follow convention pattern
- Error boundaries handle failures
- Automatic refetch intervals for live data
Zustand Stores (Client State):
- Examples:
auth-store.ts,comparison-store.ts,preferences-store.ts - Lightweight, minimal boilerplate
- Integrated with localStorage where needed
Context (Theme, Notifications):
ThemeProvider(via next-themes)QueryProvider(React Query)NotificationsProviderAuthProvider
11. Key File Patterns & Conventions
Naming:
- Pages:
page.tsxin route directories - Layouts:
layout.tsx - Components: PascalCase with domain prefix (e.g.,
NeighborhoodPOIMap) - API modules:
*-api.tsfor client-side,*-server.tsfor server-side - Hooks:
use-*pattern - Types: inline in files or
types.tsper domain
File Organization:
- Domain-based (listings/, neighborhood/, khu-cong-nghiep/)
- Shared utilities in
/liband/components/design-system - Barrel exports with
index.tsfor easy importing
Code Structure:
- 'use client' at top of client components
- TypeScript strict mode
- Props interfaces above component functions
- Sub-components extracted for readability
- Helpers defined near top-level components
12. Performance & SEO
SEO:
- Server-side metadata generation with
generateMetadata() - JSON-LD schema generation (
components/seo/json-ld.tsx) - Open Graph + canonical URLs
- Multi-language support (vi/en)
Performance:
- Dynamic imports with code splitting (e.g., maps, heavy charts)
- Lazy-loading fallbacks
- Image optimization (Next.js Image component)
- CSS-in-JS via Tailwind + CVA
- Responsive containers for charts/maps
Internationalization:
next-intlfor translations- Route segments by locale:
[locale]/ - Translations in
/messagesdirectory
Summary Table
| Aspect | Technology | Key Files |
|---|---|---|
| Mapping | Mapbox GL 3.21.0 | components/map/, lib/mapbox-style.ts |
| Charts | Recharts 3.8.1 | components/charts/, components/neighborhood/neighborhood-radar-chart.tsx |
| API Client | Fetch + CSRF | lib/api-client.ts, lib/*-api.ts |
| State (Server) | React Query 5.96.2 | lib/query-client.ts, lib/hooks/ |
| State (Client) | Zustand 5.0.12 | lib/*-store.ts |
| Forms | react-hook-form + Zod | lib/validations/ |
| UI | Tailwind + CVA | components/design-system/, components/ui/ |
| Routing | Next.js App Router | app/[locale]/ |
| i18n | next-intl | /messages/, route [locale]/ |