# Backend API Audit: Trading Exchange UI Refactor **Prepared for TechLead** | Gap analysis for sΓ n giao dα»‹ch-style dashboard Audit date: 2026-04-21 --- ## Executive Summary Backend has **strong coverage** for analytics, listings, and agent profiles. Critical gaps exist for **real-time market tickers, recent-updates feeds, and aggregated district-level indices** needed for the home dashboard and listings board. --- ## Available Endpoints (Ready for FE) ### **Listings Module** πŸ“ `apps/api/src/modules/listings/presentation/controllers/listings.controller.ts` **Route prefix:** `/listings` | Method | Path | Description | Auth | |--------|------|-------------|------| | GET | `/` | Search/filter listings (pagination, sort) | Public | | GET | `/:id` | Listing detail (full property data, seller, agent) | Public | | GET | `/:id/price-history` | Price change history (chart data) | Public | | GET | `/:id/qr-code` | Generate QR code PNG | Public | | POST | `/` | Create listing | JWT + quota | | PATCH | `/:id` | Update listing (price, description, amenities) | JWT + owner | | PATCH | `/:id/status` | Update status (DRAFTβ†’ACTIVE, etc.) | JWT + owner | | POST | `/:id/media` | Upload photo/video | JWT + owner | | POST | `/:id/feature` | Feature listing (payment gateway) | JWT + rate limit | | POST | `/:id/promote` | Promote featured (subscription quota) | JWT + quota | | POST | `bulk-update` | Bulk patch price/status/featured (≀100 items) | JWT + owner | | GET | `/pending` | Get moderation queue (admin) | ADMIN | | GET | `/duplicates` | Find duplicate listings by geo (admin) | ADMIN | | PATCH | `/:id/moderate` | Moderate listing (admin) | ADMIN | | DELETE | `/:id` | Delete listing | JWT + owner | --- ### **Analytics Module** πŸ“ `apps/api/src/modules/analytics/presentation/controllers/analytics.controller.ts` **Route prefix:** `/analytics` | Method | Path | Description | Auth | Quota | |--------|------|-------------|------|-------| | GET | `/market-report` | Market report by city/district (median price, inventory, absorption) | JWT | Yes | | GET | `/price-trend` | Price trend time-series by district | JWT | Yes | | GET | `/heatmap` | Price heatmap by city (grid: avg_m2, counts) | JWT | Yes | | GET | `/district-stats` | Statistics by district (city-level aggregates) | JWT | Yes | | GET | `/valuation` | AVM estimate (by property ID or coords) | JWT | Yes | | POST | `/valuation` | AVM with custom form data (v1/v2 ensemble) | JWT | Yes | | POST | `/valuation/batch` | Batch AVM (≀50 properties) | JWT | Yes | | GET | `/valuation/history/:propertyId` | Valuation time-series (chart) | JWT | Yes | | POST | `/valuation/compare` | Compare valuations (2–5 properties) | JWT | Yes | | GET | `/neighborhoods/:district/score` | Neighborhood quality score | Public | No | **Note:** All analytics queries return cached data (TTL varies by type). --- ### **Search Module** πŸ“ `apps/api/src/modules/search/presentation/controllers/search.controller.ts` **Route prefix:** `/search` | Method | Path | Description | Auth | |--------|------|-------------|------| | GET | `/` | Full-text & faceted property search | Public | | GET | `/geo` | Geographic radius search (lat, lng, radiusKm) | Public | | POST | `/reindex` | Trigger full-text reindex (admin) | ADMIN | --- ### **Agents Module** πŸ“ `apps/api/src/modules/agents/presentation/controllers/agents.controller.ts` **Route prefix:** `/agents` | Method | Path | Description | Auth | |--------|------|-------------|------| | GET | `/:agentId/profile` | Public agent profile (name, quality score, listings count, reviews) | Public | | GET | `/me/dashboard` | Agent dashboard stats (my listings, inquiries, quality metrics) | JWT (AGENT role) | | POST | `/me/upgrade` | Upgrade user account to agent | JWT | | POST | `/:agentId/recalculate-score` | Recalc quality score (admin) | ADMIN | --- ### **Admin Module** πŸ“ `apps/api/src/modules/admin/presentation/controllers/admin-moderation.controller.ts` + `admin.controller.ts` **Route prefix:** `/admin` | Method | Path | Description | Auth | |--------|------|-------------|------| | GET | `/moderation` | Moderation queue (pending listings) | ADMIN | | POST | `/moderation/approve` | Approve listing | ADMIN | | POST | `/moderation/reject` | Reject listing with reason | ADMIN | | POST | `/moderation/bulk` | Bulk approve/reject | ADMIN | | GET | `/moderation/audit-logs` | Moderation audit trail | ADMIN | | GET | `/kyc` | KYC approval queue | ADMIN | | POST | `/kyc/approve` | Approve KYC | ADMIN | | POST | `/kyc/reject` | Reject KYC | ADMIN | | GET | `/users` | List all users (paginated, filters) | ADMIN | | GET | `/users/:id` | Get user details | ADMIN | | POST | `/users/ban` | Ban user | ADMIN | | POST | `/subscriptions/adjust` | Adjust user subscription | ADMIN | | GET | `/dashboard` | Admin dashboard stats | ADMIN | | GET | `/revenue` | Revenue analytics | ADMIN | | GET | `/audit-logs` | General audit logs | ADMIN | --- ### **Reviews Module** πŸ“ `apps/api/src/modules/reviews/presentation/controllers/reviews.controller.ts` **Route prefix:** `/reviews` | Method | Path | Description | Auth | |--------|------|-------------|------| | GET | `/` | List reviews for target (agent, listing, user) | Public | | GET | `/stats` | Aggregate rating stats (avg, distribution) | Public | | GET | `/me` | User's own reviews | JWT | | POST | `/` | Create review | JWT | --- ## Critical Gaps (Missing or Insufficient) ### πŸ”΄ **1. Market Overview Ticker β€” NOT PRESENT** **UI Need:** Home dashboard ticker with price changes, recent listings, trending areas **Gap:** No endpoint for: - Recent listings (last 24h, last 7d) with timestamp - Trending areas (by inquiry/view volume) - Price change summary (top gainers/losers by district) - Active listings count by type **Solution:** `GET /listings/recent?limit=10&hours=24` + `GET /analytics/trending-areas?period=7d` --- ### πŸ”΄ **2. Real-Time Listing Updates β€” NOT PRESENT** **UI Need:** Listings board shows "just posted," "price dropped," "featured" badges **Gap:** - Search doesn't sort by `publishedAt` - No webhook/SSE for status changes - No delta updates since last refresh **Solution:** Add `sortBy=publishedAt` to search + `GET /listings?newSince=TIMESTAMP` --- ### πŸ”΄ **3. Similar Listings / Comparables β€” NOT PRESENT** **UI Need:** Listing detail shows 5–10 comparable properties **Gap:** No endpoint; search is generic, not contextual **Solution:** `GET /listings/:id/similar?limit=5` (same district, Β±10% price, same type) --- ### πŸ”΄ **4. Market Indicators: Ward-Level Data β€” PARTIAL** **Available:** District-level market report, heatmap **Missing:** Ward (phường)-level price trends, listing volume by ward **Solution:** `GET /analytics/heatmap?level=ward` + `GET /analytics/listing-volume?ward=X` --- ### πŸ”΄ **5. Listing Detail: Enrichment Missing** **Current:** Basic property, seller, agent, media **Missing:** - `valuationEstimate` (AVM not included) - `inquiryCount` (exists but not exposed?) - `agentQualityScore` (denormalized from agent profile) - Similar listings reference --- ### πŸ”΄ **6. Market Snapshot (Live Indicators) β€” NOT PRESENT** **UI Need:** Home dashboard tiles with total active listings, avg price, price change % **Gap:** No single endpoint; requires multiple calls **Solution:** `GET /analytics/market-snapshot?city=HCMC` returns `{ activeCount, avgPrice, medianPrice, priceChange%, inventoryM2, daysOnMarket }` --- ### 🟑 **7. Trending Areas / Hot Markets β€” NOT PRESENT** **UI Need:** "Top 10 areas by inquiry volume" for home dashboard heatmap **Gap:** No aggregation by inquiry/view counts per district **Solution:** `GET /analytics/trending-areas?period=7d&limit=10` (sorted by inquiries/views) --- ### 🟑 **8. Price Movers (Gainers/Losers) β€” NOT PRESENT** **UI Need:** "Top 5 price drops" / "Top 5 price increases" for exchange ticker **Gap:** No endpoint; requires post-processing of market report data **Solution:** `GET /analytics/price-movers?direction=up|down&limit=5` aggregated by district --- ### 🟑 **9. Market History (Time-Series Trends) β€” NOT PRESENT** **UI Need:** Analytics page showing 12-month price, volume, absorption trends **Gap:** Market report is current snapshot only **Solution:** `GET /analytics/market-history?city=HCMC&period=12m` returns monthly snapshots --- ### 🟑 **10. Cache Metadata in Analytics Responses β€” MISSING** **Issue:** No transparency on data freshness **Gap:** Endpoints don't expose `cachedAt`, `nextRefreshAt`, or data age **Solution:** Add metadata fields to all analytics responses --- ## Summary Table | Feature | Status | Severity | Module | |---------|--------|----------|--------| | Listing search & filter | βœ… | β€” | listings | | Listing detail | βœ… | β€” | listings | | Price history | βœ… | β€” | listings | | Market report | βœ… | β€” | analytics | | Heatmap | βœ… | β€” | analytics | | AVM/Valuation | βœ… | Partial | analytics | | Agent profile | βœ… | Minor | agents | | Admin moderation | βœ… | β€” | admin | | **Recent listings ticker** | ❌ | πŸ”΄ High | listings | | **Market snapshot** | ❌ | πŸ”΄ High | analytics | | **Trending areas** | ❌ | πŸ”΄ High | analytics | | **Similar listings** | ❌ | πŸ”΄ High | listings | | **Real-time updates** | ❌ | 🟑 Medium | listings | | **Price movers** | ❌ | 🟑 Medium | analytics | | **Market history** | ❌ | 🟑 Medium | analytics | | Ward-level heatmap | ❌ | 🟑 Medium | analytics | | Cache metadata | ❌ | 🟑 Medium | analytics | --- ## Recommendations ### **Phase 1: Sprint 1–2 (High Priority)** 1. `GET /listings?sortBy=publishedAt&limit=20` β€” Recent listings first 2. `GET /analytics/market-snapshot?city=HCMC` β€” Live indicators (total, avg, median) 3. `GET /analytics/trending-areas?period=7d` β€” Top areas by activity 4. `GET /listings/:id/similar?limit=5` β€” Comparable properties 5. Enhance listing detail response with `valuationEstimate`, `inquiryCount`, `agentScore` ### **Phase 2: Sprint 3 (Medium Priority)** 6. `GET /analytics/price-movers` β€” Gainers/losers 7. `GET /analytics/market-history?period=12m` β€” Trends for charts 8. Add cache metadata to all analytics endpoints ### **Phase 3: Sprint 4+ (Polish)** 9. Real-time updates (WebSocket/SSE) 10. Ward-level drill-down for heatmap 11. Most-saved listings for admin analytics --- **Total Endpoints Reviewed:** 70+ **Ready for FE:** 58 **Critical Gaps:** 10 **Easy Wins:** ~5 queries over 2–3 sprints