- Fix port numbers across all docs (API :3001, Web :3000) - Add 6 missing modules to README, CLAUDE.md, and architecture doc (agents, health, inquiries, leads, reviews, metrics/web-vitals) - Add Swagger UI reference and /api/v1 prefix notes - Create docs/api-endpoints.md with complete REST API reference - Create docs/README.md as documentation index - Update deployment guide with Loki, Promtail, pg-backup services - Update health check table with all current endpoints Co-Authored-By: Paperclip <noreply@paperclip.ing>
246 lines
13 KiB
Markdown
246 lines
13 KiB
Markdown
# Architecture
|
|
|
|
## System Overview
|
|
|
|
GoodGo Platform AI is a monorepo containing a NestJS backend, Next.js frontend, Python AI services, and MCP (Model Context Protocol) servers. The system is orchestrated with Turborepo and pnpm workspaces.
|
|
|
|
```
|
|
┌──────────────────────────────────────────┐
|
|
│ Client (Browser) │
|
|
└──────────────────┬───────────────────────┘
|
|
│
|
|
┌──────────────────▼───────────────────────┐
|
|
│ Next.js 14 (apps/web) │
|
|
│ ┌─────────┐ ┌──────────┐ ┌───────┐ │
|
|
│ │ Pages │ │Components│ │Zustand │ │
|
|
│ │(App │ │(UI + │ │(State) │ │
|
|
│ │ Router) │ │ Domain) │ │ │ │
|
|
│ └─────────┘ └──────────┘ └───────┘ │
|
|
└──────────────────┬───────────────────────┘
|
|
│ REST API
|
|
┌──────────────────▼───────────────────────┐
|
|
│ NestJS 11 (apps/api) │
|
|
│ │
|
|
│ ┌────────┐ ┌────────┐ ┌─────────────┐ │
|
|
│ │ Auth │ │Listings│ │ Payments │ │
|
|
│ ├────────┤ ├────────┤ ├─────────────┤ │
|
|
│ │ Search │ │ Admin │ │Subscriptions│ │
|
|
│ ├────────┤ ├────────┤ ├─────────────┤ │
|
|
│ │Analytics│ │ MCP │ │Notifications│ │
|
|
│ ├────────┤ ├────────┤ ├─────────────┤ │
|
|
│ │ Agents │ │Inquires│ │ Leads │ │
|
|
│ ├────────┤ ├────────┤ ├─────────────┤ │
|
|
│ │Reviews │ │ Health │ │ Metrics │ │
|
|
│ └────────┘ └────────┘ └─────────────┘ │
|
|
└───┬─────┬──────┬─────────┬──────────────┘
|
|
│ │ │ │
|
|
┌────────────▼┐ ┌─▼────┐ ▼ ┌───▼──────────┐
|
|
│ PostgreSQL │ │Redis │ │ │ Typesense │
|
|
│ + PostGIS │ │ │ │ │ (Search) │
|
|
└─────────────┘ └──────┘ │ └──────────────┘
|
|
│
|
|
┌───────────────▼──────────────────────┐
|
|
│ MCP Servers (libs/mcp-servers) │
|
|
│ ┌──────────┐┌──────────┐┌────────┐ │
|
|
│ │ Property ││ Market ││Valua- │ │
|
|
│ │ Search ││Analytics ││tion │ │
|
|
│ └──────────┘└──────────┘└───┬────┘ │
|
|
└──────────────────────────────┼───────┘
|
|
│
|
|
┌──────────────────────────────▼───────┐
|
|
│ AI Services (libs/ai-services) │
|
|
│ FastAPI + XGBoost + Claude API │
|
|
│ ┌──────────┐ ┌────────────────┐ │
|
|
│ │ AVM │ │ Moderation │ │
|
|
│ │(Pricing) │ │ (Claude API) │ │
|
|
│ └──────────┘ └────────────────┘ │
|
|
└──────────────────────────────────────┘
|
|
```
|
|
|
|
## Module Architecture
|
|
|
|
Each API module follows a layered Domain-Driven Design structure:
|
|
|
|
```
|
|
modules/{module-name}/
|
|
├── presentation/ # HTTP layer
|
|
│ ├── controllers/ # Route handlers
|
|
│ └── dtos/ # Request/response DTOs (class-validator)
|
|
├── application/ # Business orchestration
|
|
│ ├── commands/ # Write operations (CQRS)
|
|
│ ├── queries/ # Read operations (CQRS)
|
|
│ ├── handlers/ # Command/query handlers
|
|
│ └── services/ # Application services
|
|
├── domain/ # Core business logic
|
|
│ ├── entities/ # Domain entities & value objects
|
|
│ ├── repositories/ # Repository interfaces (abstractions)
|
|
│ └── events/ # Domain events
|
|
├── infrastructure/ # External integrations
|
|
│ ├── repositories/ # Prisma repository implementations
|
|
│ └── services/ # External service adapters
|
|
└── {module-name}.module.ts # NestJS module definition
|
|
```
|
|
|
|
### CQRS Pattern
|
|
|
|
The platform uses NestJS CQRS (`@nestjs/cqrs`) for complex operations:
|
|
|
|
- **Commands** — mutate state (create listing, process payment, register user)
|
|
- **Queries** — read state (search properties, get analytics)
|
|
- **Events** — cross-module communication (listing published → index in Typesense, payment completed → send notification)
|
|
|
|
### Shared Module
|
|
|
|
The `shared/` module provides cross-cutting concerns:
|
|
|
|
- **Prisma service** — database connection and client
|
|
- **Redis service** — caching and session management
|
|
- **Guards** — JWT auth guard, roles guard, throttle guard
|
|
- **Pipes** — global validation pipe (whitelist mode)
|
|
- **Filters** — exception filters for consistent error responses
|
|
- **Decorators** — `@CurrentUser()`, `@Roles()`, `@Public()`
|
|
|
|
## Data Flow
|
|
|
|
### Property Listing Lifecycle
|
|
|
|
```
|
|
DRAFT → PENDING_REVIEW → ACTIVE → RESERVED → SOLD/RENTED
|
|
│ │
|
|
▼ │
|
|
REJECTED EXPIRED
|
|
```
|
|
|
|
1. **Seller/Agent** creates listing (status: `DRAFT`)
|
|
2. **Seller** submits for review → `PENDING_REVIEW`
|
|
3. **Admin** moderates (AI moderation score assists) → `ACTIVE` or `REJECTED`
|
|
4. Active listings are indexed in Typesense for search
|
|
5. **Buyer** makes inquiry → `Inquiry` record created
|
|
6. Transaction workflow: `OFFER_MADE → DEPOSIT_PAID → CONTRACT_SIGNING → COMPLETED`
|
|
|
|
### Search Flow
|
|
|
|
```
|
|
User Query → NestJS Search Module → Typesense
|
|
│
|
|
├─ Full-text on title/description
|
|
├─ Faceted filters (price, type, bedrooms)
|
|
└─ Geo-spatial (lat/long + radius)
|
|
```
|
|
|
|
### Payment Flow
|
|
|
|
```
|
|
User → API (create payment) → Provider (VNPay/MoMo/ZaloPay)
|
|
│
|
|
[User pays on provider page]
|
|
│
|
|
Provider callback → API → Verify signature → Update Payment status
|
|
│
|
|
SUCCESS / FAILED
|
|
```
|
|
|
|
### AI Valuation Flow
|
|
|
|
```
|
|
API Request → MCP Valuation Server → AI Service (FastAPI)
|
|
│
|
|
XGBoost Model
|
|
│
|
|
┌─────▼──────┐
|
|
│ Estimated │
|
|
│ Price + │
|
|
│ Confidence │
|
|
│ + Factors │
|
|
└─────────────┘
|
|
```
|
|
|
|
## Database Schema
|
|
|
|
### Core Models
|
|
|
|
```
|
|
User ──┬── Agent (1:1, for AGENT role users)
|
|
├── OAuthAccount (1:N, Google/Zalo)
|
|
├── RefreshToken (1:N, token families)
|
|
├── Subscription (1:N)
|
|
├── SavedSearch (1:N)
|
|
└── UsageRecord (1:N)
|
|
|
|
Property ──┬── PropertyMedia (1:N, images/videos)
|
|
├── Listing (1:N)
|
|
└── Valuation (1:N)
|
|
|
|
Listing ──┬── Inquiry (1:N)
|
|
├── Lead (1:N)
|
|
├── Transaction (1:N)
|
|
└── Agent (N:1)
|
|
|
|
Transaction ── Payment (1:N)
|
|
|
|
Plan ── Subscription (1:N)
|
|
|
|
MarketIndex (standalone — city/district/month aggregates)
|
|
```
|
|
|
|
### Key Design Decisions
|
|
|
|
- **PostGIS** for spatial queries — property locations stored as `Point` geometry
|
|
- **JSON columns** for flexible data: amenities, nearby POIs, KYC data, subscription features
|
|
- **Token family tracking** for secure refresh token rotation (detects reuse attacks)
|
|
- **Soft statuses** over soft deletes — listings use status workflow, not `deletedAt`
|
|
|
|
## MCP Servers
|
|
|
|
Three Model Context Protocol servers provide AI tool interfaces:
|
|
|
|
| Server | Tools | Data Source |
|
|
|--------|-------|-------------|
|
|
| **Property Search** | `search_properties`, `compare_properties`, `get_property_details` | Typesense |
|
|
| **Market Analytics** | `get_market_report`, `analyze_trends`, `get_price_indices` | PostgreSQL |
|
|
| **Valuation** | `estimate_valuation`, `extract_features`, `compare_valuations` | AI Services (FastAPI) |
|
|
|
|
MCP servers are registered via `McpModule` in NestJS, managed by `McpRegistryService`, and exposed through `McpTransportController` over HTTP.
|
|
|
|
## AI Services
|
|
|
|
Python FastAPI microservice (`libs/ai-services/`) provides:
|
|
|
|
| Endpoint | Model | Purpose |
|
|
|----------|-------|---------|
|
|
| `POST /avm/estimate` | XGBoost | Property price estimation with confidence score |
|
|
| `POST /moderation/check` | Claude API | Content moderation for listing descriptions |
|
|
| `GET /health` | — | Health check |
|
|
|
|
- **Underthesea** handles Vietnamese text tokenization and NLP preprocessing
|
|
- XGBoost model uses engineered features (area, location, property type, amenities)
|
|
|
|
## Security
|
|
|
|
- **JWT + Refresh Token Rotation** — 15-minute access tokens, 7-day refresh tokens with family-based rotation
|
|
- **OAuth** — Google and Zalo social login
|
|
- **Rate Limiting** — 60 req/60s default, 10 req/60s for auth endpoints
|
|
- **Helmet** — HTTP security headers
|
|
- **CORS** — Configurable origins via `CORS_ORIGINS`
|
|
- **Input Validation** — class-validator (backend), Zod (frontend)
|
|
- **Content Sanitization** — sanitize-html for user-generated content
|
|
- **KYC** — Agent verification workflow (NONE → PENDING → VERIFIED/REJECTED)
|
|
|
|
## Monitoring
|
|
|
|
- **Prometheus** scrapes `/api/v1/metrics` endpoint every 15 seconds
|
|
- **Grafana** dashboards auto-provisioned from `monitoring/grafana/dashboards/`
|
|
- **Loki + Promtail** aggregate container logs; viewable in Grafana
|
|
- **Pino** structured JSON logging with configurable log levels
|
|
- Metrics include HTTP request duration, error rates, web vitals, and custom business metrics
|
|
- Log retention: 15 days (configured in `monitoring/loki/loki-config.yml`)
|
|
|
|
## Event System
|
|
|
|
The platform uses `@nestjs/event-emitter` for loose coupling between modules:
|
|
|
|
- `listing.published` → Typesense indexer updates search index
|
|
- `payment.completed` → Notification service sends confirmation
|
|
- `inquiry.created` → Agent notification triggered
|
|
- `user.registered` → Welcome email sent
|