- 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>
15 KiB
UI Mapping Quick Guide — GoodGo API Fields
A fast reference for wiring UI mockups to real API data. All fields with their actual types and endpoints.
🏠 Property/Listing Display
Card View (Search Results)
┌─────────────────────────────────┐
│ [Featured Badge] 2 hrs ago │ ← listing.featuredUntil | createdAt
├─────────────────────────────────┤
│ $2.5B [SALE] [ACTIVE] │ ← priceVND | transactionType | status
│ 75 m² • 2BR • 1BA • Q1, HCMC │ ← areaM2 | bedrooms | bathrooms | district
├─────────────────────────────────┤
│ 👁️ 342 ❤️ 28 💬 12 │ ← viewCount | saveCount | inquiryCount
├─────────────────────────────────┤
│ Agent: John | ⭐ 4.8 │ ← agent.user.fullName | agent.qualityScore
└─────────────────────────────────┘
API Fields:
- Price:
listing.priceVND→ format as VND - Type/Status:
listing.transactionType,listing.status - Area:
property.areaM2 - Bedrooms:
property.bedrooms(null = studio) - Bathrooms:
property.bathrooms - District:
property.district - Metrics:
listing.viewCount,listing.saveCount,listing.inquiryCount - Agent:
listing.agent.user.fullName,listing.agent.qualityScore
Endpoint: GET /search or search index
Detail Page (Hero Section)
Main Image Carousel
┌────────────────────────────────────────────────┐
│ │
│ Apartment in District 1 for $2.5B │
│ 75 m² | 2BR 1BA | ACTIVE │
│ │
│ ⭐ 4.8 (234 views) | 28 saves | 12 inquiries │
│ │
│ [Agent: John] [Verified] [License: xxx] │
└────────────────────────────────────────────────┘
API Fields (from Listing + Property):
- Title:
property.title - Price:
listing.priceVND - Area:
property.areaM2 - Beds/Baths:
property.bedrooms,property.bathrooms - Status:
listing.status - Views:
listing.viewCount - Saves:
listing.saveCount - Inquiries:
listing.inquiryCount - Agent Name:
listing.agent.user.fullName - Agent Verified:
listing.agent.isVerified - License:
listing.agent.licenseNumber
Endpoint: Individual listing API or detail endpoint
Property Details Panel
LOCATION
├─ Address: 123 Nguyen Hue, District 1, HCMC
├─ Lat/Lng: 10.7769, 106.7009
├─ Metro Distance: 450m
└─ Project: [Project Name if applicable]
PHYSICAL
├─ Type: APARTMENT
├─ Area: 75 m²
├─ Usable Area: 70 m²
├─ Bedrooms: 2 (or Studio if -1)
├─ Bathrooms: 1
├─ Floors: 25 total, Unit on Floor 12
├─ Direction: NORTHEAST
├─ Year Built: 2020
└─ Legal: Sở hữu lâu dài
AMENITIES
├─ Furnishing: FULLY_FURNISHED
├─ Condition: LIKE_NEW
├─ Parking: 1 slot
├─ Maintenance Fee: 2.5M/month
├─ Pet Friendly: Yes
├─ Views: Street, Park
└─ Suitable For: Young couples, Families
API Fields (all from property):
- Address:
address,ward,district,city - Coordinates:
location.lat,location.lng - Metro:
metroDistanceM - Project:
projectName,projectDevelopmentId - Type:
propertyType - Sizes:
areaM2,usableAreaM2 - Rooms:
bedrooms,bathrooms - Levels:
floor,totalFloors - Direction:
direction - Year:
yearBuilt - Legal:
legalStatus - Furnishing:
furnishing - Condition:
propertyCondition - Parking:
parkingSlots - Fee:
maintenanceFeeVND - Pet:
petFriendly - Views:
viewType[] - Suitable:
suitableFor[]
📊 Analytics & Market Data
Market Snapshot Widget
HCMC Market Overview (Last Updated: 2 hours ago)
┌─────────────────────────────┐
│ Active Listings 2,345 │ ← activeCount
│ Avg Price $2.8B │ ← avgPrice (format)
│ Median Price $2.5B │ ← medianPrice (format)
│ Price/m² $35M │ ← avgPricePerM2
│ Avg Days on Mkt 45d │ ← daysOnMarket
│ New (24h) 12 │ ← newListings24h
│ │
│ Price Change (24h) +2% │ ← priceChangePct.d1
│ Price Change (7d) +5% │ ← priceChangePct.d7
│ Price Change (30d) +12% │ ← priceChangePct.d30
└─────────────────────────────┘
Cache: Next update in 25 min ← nextRefreshAt
Endpoint: GET /analytics/market-snapshot?city=HCMC
Response Fields (MarketSnapshotDto):
activeCountavgPrice→ convert string to number for displaymedianPriceavgPricePerM2daysOnMarketnewListings24hpriceChangePct.d1/d7/d30→ percentage valuesnextRefreshAt→ show "Updates in X mins"
Price Trend Chart (Line)
Price Over Time (Q1 2026 - Q2 2026)
$4B ┌─────╮
│ │
$3B │ ╰──────
│
$2B └──────────
Q1 Q2 Q3
Endpoint: GET /analytics/price-trend?district=Quận%201&city=HCMC&propertyType=APARTMENT
Response Fields (PriceTrendDto):
trend[]:period→ x-axis label (e.g., "Q1 2026")medianPrice→ y-axis value (parse from string)avgPriceM2→ optional secondary axistotalListings→ tooltip data
Heatmap (District Color Intensity)
[District] [Price/m²] [Listings] [Median Price]
├─ D1 $45M 234 $2.8B
├─ D2 $38M 412 $2.2B
└─ D3 $28M 567 $1.8B
→ Use avgPriceM2 for color intensity
Endpoint: GET /analytics/heatmap?city=HCMC&period=2026-04
Response Fields (HeatmapDto):
dataPoints[]:district→ overlay labelavgPriceM2→ color intensity (higher = redder)totalListings→ hover tooltipmedianPrice→ detail view
District Stats Table
District Median Price Price/m² Listings Days Market YoY Change
├─ D1 $2.8B $45M 234 42d +12%
├─ D2 $2.2B $38M 412 48d +8%
└─ D3 $1.8B $28M 567 52d +5%
Endpoint: GET /analytics/district-stats?city=HCMC&period=2026-04
Response Fields (DistrictStatsDto):
districts[]:district→ row labelmedianPrice→ format as VNDavgPriceM2totalListingsdaysOnMarketyoyChange→ percentage
Trending Areas Widget
🔥 Trending (Last 30 Days)
┌────────────────────────────────────┐
│ 1. District 1 │ ← scoreRank
│ 📊 12 new | 45 inquiries │ ← listings | inquiries
│ 👁️ 234 views | ↑5% price │ ← views | priceChangePct
│ │
│ 2. District 5 │
│ 📊 8 new | 32 inquiries │
│ 👁️ 156 views | ↑2% price │
│ │
│ 3. District 9 │
│ 📊 15 new | 28 inquiries │
│ 👁️ 189 views | ↓1% price │
└────────────────────────────────────┘
Score = inquiries×0.6 + views×0.3 + listings×0.1
Endpoint: GET /analytics/trending-areas?period=30&limit=10&level=district
Response Fields (TrendingAreasDto):
areas[]:scoreRank→ ranking numbername→ district name (e.g., "Quận 1")listings→ new listings countinquiriesviewspriceChangePct→ YoY change or null
💰 Valuations (AVM)
Quick Estimate Card
PROPERTY VALUATION (by Coordinates)
Estimated Value: $2.5B
Confidence: 82% (Good)
Price/m²: $33.3M
Model: AVM v2 Ensemble
Comparable Sales (5 nearby):
├─ 234B (apt, 75m²) - 450m away
├─ 231B (apt, 78m²) - 520m away
└─ 238B (apt, 72m²) - 380m away
Endpoint: GET /analytics/valuation?propertyId=prop-123 OR POST /analytics/valuation
GET Response (ValuationDto):
estimatedPrice→ format as VNDconfidence→ 0.0-1.0, convert to percentagepricePerM2modelVersioncomparables[]:priceVNDareaM2distanceMeters→ convert to distance label
POST Request:
{
"propertyType": "APARTMENT",
"area": 75,
"district": "Quận 1",
"city": "Hồ Chí Minh",
"bedrooms": 2,
"bathrooms": 1,
"yearBuilt": 2020,
"useV2": true,
"distanceToHospitalKm": 0.5,
"distanceToParkKm": 1.2,
"hasElevator": true,
"hasParking": true
}
Valuation History Chart
Estimated Value Over 12 Months
$2.8B ┌─────╮
│ │
$2.5B │ ╰──────
│
$2.2B └──────────
Apr Aug Dec
Endpoint: GET /analytics/valuation/history/prop-123?limit=50
Response Fields:
history[]:valuedAt→ x-axis timestampestimatedPrice→ y-axis value (parse)confidence→ tooltippricePerM2→ tooltipmodelVersion→ metadata
Property Comparison Table
Property A Property B Property C
Value $2.5B $2.2B $2.8B
Conf 85% 78% 92%
/m² $33.3M $31.4M $35M
Model v2 Ensemble v2 Ensemble v1 Standard
[Comparables shown for each]
Endpoint: POST /analytics/valuation/compare
Request:
{
"propertyIds": ["prop-a", "prop-b", "prop-c"]
}
Response Fields:
comparisons[]:propertyIdaddress,district,areaM2valuation(same as ValuationDto above)
🌟 Neighborhood & POIs
Neighborhood Score Card
NEIGHBORHOOD SCORE
Overall: 78/100 ⭐⭐⭐⭐
├─ Education 85/100
├─ Healthcare 92/100
├─ Transport 78/100
├─ Shopping 85/100
├─ Greenery 65/100
└─ Safety 72/100
POI Summary:
├─ 3 Schools
├─ 5 Hospitals
├─ 2 Transit Stations
├─ 8 Shopping Centers
├─ 2 Parks
└─ 12 Restaurants
Endpoint: GET /analytics/neighborhoods/Quận%201/score?city=HCMC (PUBLIC)
Response Fields (NeighborhoodScoreResult):
totalScore→ 0-100educationScore,healthcareScore,transportScore, etc. → each 0-100poiCounts→ map of category→countcalculatedAt→ timestamp
Nearby POIs Map
Center: (10.7769, 106.7009)
POI Markers (within 2km):
🏫 School (450m)
Name: Saigon Star International School
Address: 123 Nguyen Hue, D1
🏥 Hospital (890m)
Name: Vinmec Hospital
Address: 458 Ly Thuong Kiet, D1
🛍️ Mall (1.2km)
Name: The Landmark 81
🚇 Metro (680m)
Name: Ben Thanh Station
Endpoint: GET /analytics/pois/nearby?lat=10.7769&lng=106.7009&radius=2000&limit=30 (PUBLIC)
Response Fields (NearbyPOIsResultDto):
center:{lat, lng}pois[]:nametype→ SCHOOL, HOSPITAL, METRO_STATION, MALL, PARK, RESTAURANT, etc.category→ school | hospital | transit | shopping | restaurant | parklat,lng→ for map markersdistance→ meters from centeraddress
👨💼 Agent Profile
Agent Card
┌─────────────────────────────┐
│ [Avatar] John Doe │
│ ⭐ 4.8/5 │ ← qualityScore
│ [Verified] [Licensed] │ ← isVerified | licenseNumber exists
│ │
│ License: RE-12345 │ ← licenseNumber
│ Agency: Saigon Realty │ ← agency
│ Response Time: 2.5 hours │ ← responseTimeAvg (seconds→hours)
│ Deals: 42 completed │ ← totalDeals
│ │
│ Service Areas: │
│ District 1, 3, 7, Binh Thanh│ ← serviceAreas[]
│ │
│ Bio: "10+ years experience" │ ← bio
│ │
│ [Message] [View Listings] │
└─────────────────────────────┘
API Fields (Agent + User):
- Avatar:
user.avatarUrl - Name:
user.fullName - Rating:
qualityScore→ convert 0-100 to 0-5 stars - Verified Badge:
isVerified - License:
licenseNumber(display if exists) - Agency:
agency - Response Time:
responseTimeAvg(seconds) → format as "X.X hours" - Deals:
totalDeals - Service Areas:
serviceAreas[]→ join with comma
📋 Listing Management
Listing Status Flow
DRAFT
↓
PENDING_REVIEW ← re-moderation if edited while ACTIVE
↓
ACTIVE ← publishedAt timestamp
↓
RESERVED ← buyer offer
↓
SOLD/RENTED ← transaction complete
Alternative: REJECTED → DRAFT (can re-submit)
Alternative: EXPIRED → DRAFT (can re-list)
Status Colors:
- DRAFT: Gray
- PENDING_REVIEW: Yellow
- ACTIVE: Green
- RESERVED: Blue
- SOLD: Dark Gray
- RENTED: Dark Gray
- EXPIRED: Orange
- REJECTED: Red
Listing Engagement Metrics
VIEWS 342 ← listing.viewCount
SAVES 28 ← listing.saveCount
INQUIRIES 12 ← listing.inquiryCount
Engagement Targets:
- Views → increased each time listing is viewed
- Saves → increased when user bookmarks
- Inquiries → increased when buyer sends inquiry
💡 Common Conversions
Price Formatting
// Input: priceVND = "2500000000" (string)
const formatted = new Intl.NumberFormat('vi-VN', {
style: 'currency',
currency: 'VND'
}).format(Number(priceVND));
// Output: "2.500.000.000 ₫" or "$2.5B"
Confidence to Stars
// Input: confidence = 0.82 (0.0-1.0)
const stars = Math.round(confidence * 5); // 0-5 stars
const label = confidence > 0.8 ? "High" : confidence > 0.6 ? "Good" : "Low";
Response Time
// Input: responseTimeAvg = 9000 (seconds)
const hours = (responseTimeAvg / 3600).toFixed(1);
// Output: "2.5 hours"
Distance Display
// Input: distanceMeters = 890
const label = distanceMeters < 1000
? `${distanceMeters}m`
: `${(distanceMeters/1000).toFixed(1)}km`;
Last Updated: April 2026