# 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

