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>
This commit is contained in:
261
docs/audits/BACKEND_API_AUDIT_EXCHANGE_UI.md
Normal file
261
docs/audits/BACKEND_API_AUDIT_EXCHANGE_UI.md
Normal file
@@ -0,0 +1,261 @@
|
||||
# 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
|
||||
|
||||
Reference in New Issue
Block a user