Files
goodgo-platform/docs/explorations/from-desktop/FRONTEND_QUICK_REFERENCE.txt
Ho Ngoc Hai 08b96f9c2d docs: consolidate exploration & audit reports under docs/ (TEC-3094)
- 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>
2026-04-21 16:29:24 +07:00

358 lines
19 KiB
Plaintext

╔════════════════════════════════════════════════════════════════════════════╗
║ 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<T>(endpoint, headers?)
apiClient.post<T>(endpoint, body?, headers?)
apiClient.patch<T>(endpoint, body?, headers?)
apiClient.delete<T>(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();
<span>{t('key.path')}</span>
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: () => <Fallback /> ← 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<Type>('/endpoint');
const result = await apiClient.post<Type>('/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: () => <LoadingState />
});
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 ║
╚════════════════════════════════════════════════════════════════════════════╝