docs: add architecture, deployment guides and update dev environment docs
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
177
README.md
Normal file
177
README.md
Normal file
@@ -0,0 +1,177 @@
|
||||
# GoodGo Platform AI
|
||||
|
||||
Vietnam's intelligent real estate platform — property search, AI-powered valuation, and end-to-end transaction management.
|
||||
|
||||
## Tech Stack
|
||||
|
||||
| Layer | Technology |
|
||||
|-------|-----------|
|
||||
| **Backend** | NestJS 11, TypeScript, Prisma ORM, CQRS |
|
||||
| **Frontend** | Next.js 14, React 18, Tailwind CSS, Zustand |
|
||||
| **Database** | PostgreSQL 16 + PostGIS 3.4 |
|
||||
| **Search** | Typesense 27 |
|
||||
| **Cache/Queue** | Redis 7 |
|
||||
| **AI/ML** | FastAPI, XGBoost, Claude API, Underthesea |
|
||||
| **MCP** | Model Context Protocol servers (property search, valuation, analytics) |
|
||||
| **Storage** | MinIO (S3-compatible) |
|
||||
| **Monitoring** | Prometheus + Grafana |
|
||||
| **Payments** | VNPay, MoMo, ZaloPay |
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
|
||||
│ Next.js 14 │────▶│ NestJS API │────▶│ PostgreSQL + │
|
||||
│ (Web App) │ │ (REST) │ │ PostGIS │
|
||||
└─────────────┘ └──────┬───────┘ └──────────────────┘
|
||||
│
|
||||
┌────────────┼────────────┐
|
||||
│ │ │
|
||||
┌─────▼──┐ ┌──────▼───┐ ┌────▼─────┐
|
||||
│ Redis │ │Typesense │ │ MinIO │
|
||||
│ Cache │ │ Search │ │ Storage │
|
||||
└────────┘ └──────────┘ └──────────┘
|
||||
│
|
||||
┌─────▼──────────────────────────┐
|
||||
│ MCP Servers │
|
||||
│ ├─ Property Search │
|
||||
│ ├─ Market Analytics │
|
||||
│ └─ Valuation │
|
||||
└─────────────┬─────────────────┘
|
||||
│
|
||||
┌───────▼────────┐
|
||||
│ AI Services │
|
||||
│ (FastAPI) │
|
||||
│ ├─ AVM │
|
||||
│ └─ Moderation │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
## Monorepo Structure
|
||||
|
||||
```
|
||||
goodgo-platform-ai/
|
||||
├── apps/
|
||||
│ ├── api/ # NestJS backend (port 3000)
|
||||
│ └── web/ # Next.js frontend (port 3001)
|
||||
├── libs/
|
||||
│ ├── ai-services/ # Python FastAPI — AVM + content moderation
|
||||
│ └── mcp-servers/ # MCP server implementations
|
||||
├── prisma/ # Database schema & migrations
|
||||
├── e2e/ # Playwright E2E tests
|
||||
├── monitoring/ # Prometheus & Grafana configs
|
||||
└── docs/ # Developer documentation
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- **Docker Engine 24+** & Docker Compose v2
|
||||
- **Node.js 22 LTS**
|
||||
- **pnpm 10.27+** (`corepack enable && corepack prepare pnpm@latest --activate`)
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# 1. Clone the repository
|
||||
git clone <repo-url> && cd goodgo-platform-ai
|
||||
|
||||
# 2. Copy environment file
|
||||
cp .env.example .env
|
||||
|
||||
# 3. Start infrastructure services
|
||||
docker compose up -d
|
||||
|
||||
# 4. Verify services are healthy
|
||||
docker compose ps
|
||||
|
||||
# 5. Install dependencies
|
||||
pnpm install
|
||||
|
||||
# 6. Generate Prisma client
|
||||
pnpm db:generate
|
||||
|
||||
# 7. Run database migrations
|
||||
pnpm db:migrate:dev
|
||||
|
||||
# 8. Seed the database (optional)
|
||||
pnpm db:seed
|
||||
|
||||
# 9. Start all apps in dev mode
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
The API will be available at `http://localhost:3000` and the web app at `http://localhost:3001`.
|
||||
|
||||
### Infrastructure Services
|
||||
|
||||
| Service | Port(s) | Dashboard |
|
||||
|---------|---------|-----------|
|
||||
| PostgreSQL + PostGIS | 5432 | — |
|
||||
| Redis | 6379 | — |
|
||||
| Typesense | 8108 | `http://localhost:8108/health` |
|
||||
| MinIO | 9000 / 9001 | `http://localhost:9001` (console) |
|
||||
| AI Services (FastAPI) | 8000 | `http://localhost:8000/health` |
|
||||
| Prometheus | 9090 | `http://localhost:9090` |
|
||||
| Grafana | 3002 | `http://localhost:3002` |
|
||||
|
||||
## Development
|
||||
|
||||
### Common Commands
|
||||
|
||||
```bash
|
||||
pnpm dev # Start all apps (API + Web)
|
||||
pnpm build # Build all packages
|
||||
pnpm lint # Run ESLint
|
||||
pnpm typecheck # TypeScript type checking
|
||||
pnpm format # Format with Prettier
|
||||
pnpm test # Run unit/integration tests
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
```bash
|
||||
pnpm db:generate # Regenerate Prisma client
|
||||
pnpm db:migrate:dev # Create and apply migrations
|
||||
pnpm db:migrate:deploy # Apply migrations (CI/production)
|
||||
pnpm db:seed # Seed database
|
||||
pnpm db:studio # Open Prisma Studio (visual editor)
|
||||
pnpm db:reset # Reset database (destructive)
|
||||
```
|
||||
|
||||
### E2E Testing
|
||||
|
||||
```bash
|
||||
pnpm test:e2e # Run all E2E tests
|
||||
pnpm test:e2e:api # API tests only
|
||||
pnpm test:e2e:web # Web UI tests only
|
||||
pnpm test:e2e:report # Open HTML test report
|
||||
```
|
||||
|
||||
## API Modules
|
||||
|
||||
| Module | Description |
|
||||
|--------|-------------|
|
||||
| **auth** | Registration, login, JWT + refresh token rotation, OAuth (Google/Zalo), KYC |
|
||||
| **listings** | Property listing CRUD, status workflow, media management |
|
||||
| **search** | Typesense full-text search with geo-spatial filters |
|
||||
| **payments** | VNPay, MoMo, ZaloPay integration |
|
||||
| **subscriptions** | Plan management, usage tracking |
|
||||
| **notifications** | Email and in-app notifications |
|
||||
| **admin** | Listing moderation, user management |
|
||||
| **analytics** | Market reports, price indices, AVM integration |
|
||||
| **mcp** | MCP server bridge (property search, valuation, analytics) |
|
||||
| **metrics** | Prometheus metrics endpoint |
|
||||
|
||||
Each module follows Domain-Driven Design with `presentation/`, `application/`, `domain/`, and `infrastructure/` layers.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Development Environment](docs/dev-environment.md) — Docker setup and local services
|
||||
- [Architecture](docs/architecture.md) — System design, data flow, module structure
|
||||
- [Deployment](docs/deployment.md) — Production deployment guide
|
||||
|
||||
## License
|
||||
|
||||
Proprietary — All rights reserved.
|
||||
239
docs/architecture.md
Normal file
239
docs/architecture.md
Normal file
@@ -0,0 +1,239 @@
|
||||
# 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│ │
|
||||
│ └────────┘ └────────┘ └─────────────┘ │
|
||||
└───┬─────┬──────┬─────────┬──────────────┘
|
||||
│ │ │ │
|
||||
┌────────────▼┐ ┌─▼────┐ ▼ ┌───▼──────────┐
|
||||
│ 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 `/metrics` endpoint every 15 seconds
|
||||
- **Grafana** dashboards auto-provisioned from `monitoring/grafana/dashboards/`
|
||||
- **Pino** structured JSON logging with configurable log levels
|
||||
- Metrics include HTTP request duration, error rates, and custom business metrics
|
||||
|
||||
## 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
|
||||
226
docs/deployment.md
Normal file
226
docs/deployment.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Deployment Guide
|
||||
|
||||
## Overview
|
||||
|
||||
GoodGo Platform AI consists of four deployable services:
|
||||
|
||||
| Service | Technology | Default Port |
|
||||
|---------|-----------|-------------|
|
||||
| **API** | NestJS (Node.js) | 3000 |
|
||||
| **Web** | Next.js | 3001 |
|
||||
| **AI Services** | FastAPI (Python) | 8000 |
|
||||
| **Infrastructure** | Docker Compose | Various |
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Engine 24+ & Docker Compose v2
|
||||
- Node.js 22 LTS
|
||||
- pnpm 10.27+
|
||||
- Python 3.12 (for AI services, if running outside Docker)
|
||||
|
||||
## Environment Configuration
|
||||
|
||||
Copy `.env.example` to `.env` and configure all required values:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
### Required Variables
|
||||
|
||||
| Variable | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@host:5432/goodgo` |
|
||||
| `JWT_SECRET` | JWT signing key (min 32 chars) | Generate with `openssl rand -hex 32` |
|
||||
| `JWT_REFRESH_SECRET` | Refresh token signing key | Generate with `openssl rand -hex 32` |
|
||||
| `REDIS_URL` | Redis connection string | `redis://localhost:6379` |
|
||||
| `TYPESENSE_API_KEY` | Typesense admin API key | Generate a secure random key |
|
||||
|
||||
### Optional Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| `API_PORT` | API server port | `3000` |
|
||||
| `WEB_PORT` | Web app port | `3001` |
|
||||
| `NODE_ENV` | Environment mode | `development` |
|
||||
| `CORS_ORIGINS` | Allowed CORS origins | — |
|
||||
| `CLAUDE_API_KEY` | Claude API key (for content moderation) | — |
|
||||
| `NEXT_PUBLIC_MAPBOX_TOKEN` | Mapbox token (for maps) | — |
|
||||
| `VNPAY_*`, `MOMO_*`, `ZALOPAY_*` | Payment gateway credentials | — |
|
||||
|
||||
## Infrastructure Setup (Docker Compose)
|
||||
|
||||
Start all infrastructure services:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
This starts:
|
||||
|
||||
- **PostgreSQL 16 + PostGIS 3.4** (port 5432)
|
||||
- **Redis 7** (port 6379)
|
||||
- **Typesense 27** (port 8108)
|
||||
- **MinIO** (API: 9000, Console: 9001)
|
||||
- **AI Services** (port 8000)
|
||||
- **Prometheus** (port 9090)
|
||||
- **Grafana** (port 3002)
|
||||
|
||||
Verify all services are healthy:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
All services include health checks. Wait until all show `healthy` status.
|
||||
|
||||
## Database Setup
|
||||
|
||||
```bash
|
||||
# Generate Prisma client
|
||||
pnpm db:generate
|
||||
|
||||
# Apply migrations
|
||||
pnpm db:migrate:deploy
|
||||
|
||||
# Seed initial data (optional)
|
||||
pnpm db:seed
|
||||
```
|
||||
|
||||
## Building for Production
|
||||
|
||||
### API (NestJS)
|
||||
|
||||
```bash
|
||||
cd apps/api
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Output: `apps/api/dist/`
|
||||
|
||||
Run in production:
|
||||
|
||||
```bash
|
||||
NODE_ENV=production node apps/api/dist/main.js
|
||||
```
|
||||
|
||||
### Web (Next.js)
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
pnpm build
|
||||
```
|
||||
|
||||
Output: `apps/web/.next/`
|
||||
|
||||
Run in production:
|
||||
|
||||
```bash
|
||||
NODE_ENV=production pnpm --filter web start
|
||||
```
|
||||
|
||||
### AI Services (FastAPI)
|
||||
|
||||
The AI service runs in Docker via `docker compose`. To build separately:
|
||||
|
||||
```bash
|
||||
cd libs/ai-services
|
||||
docker build -t goodgo-ai-services .
|
||||
docker run -p 8000:8000 --env-file ../../.env goodgo-ai-services
|
||||
```
|
||||
|
||||
## Production Checklist
|
||||
|
||||
### Security
|
||||
|
||||
- [ ] Set strong, unique `JWT_SECRET` and `JWT_REFRESH_SECRET` (min 32 characters)
|
||||
- [ ] Set `NODE_ENV=production`
|
||||
- [ ] Configure `CORS_ORIGINS` to only allow your domain(s)
|
||||
- [ ] Change default database passwords
|
||||
- [ ] Change default MinIO credentials (`MINIO_USER`, `MINIO_PASSWORD`)
|
||||
- [ ] Change default Grafana credentials (`GRAFANA_ADMIN_USER`, `GRAFANA_ADMIN_PASSWORD`)
|
||||
- [ ] Use a strong, unique `TYPESENSE_API_KEY`
|
||||
- [ ] Enable SSL/TLS termination (reverse proxy)
|
||||
- [ ] Set `MINIO_USE_SSL=true` if MinIO is exposed publicly
|
||||
|
||||
### Database
|
||||
|
||||
- [ ] Run `pnpm db:migrate:deploy` (not `db:migrate:dev`)
|
||||
- [ ] Enable PostgreSQL connection pooling (PgBouncer recommended)
|
||||
- [ ] Configure automated backups
|
||||
- [ ] Set appropriate `max_connections` in PostgreSQL config
|
||||
|
||||
### Monitoring
|
||||
|
||||
- [ ] Verify Prometheus is scraping `/metrics` endpoint
|
||||
- [ ] Import Grafana dashboards from `monitoring/grafana/dashboards/`
|
||||
- [ ] Set up alerting rules for error rates and latency
|
||||
|
||||
### Performance
|
||||
|
||||
- [ ] Configure Redis `maxmemory` and eviction policy
|
||||
- [ ] Set appropriate Typesense `--memory-limit`
|
||||
- [ ] Enable gzip/brotli compression in reverse proxy
|
||||
- [ ] Configure CDN for static assets (Next.js `/_next/static/`)
|
||||
|
||||
## Health Checks
|
||||
|
||||
| Service | Endpoint | Expected Response |
|
||||
|---------|----------|-------------------|
|
||||
| API | `GET /metrics` | Prometheus metrics |
|
||||
| AI Services | `GET /health` | `{"status": "ok"}` |
|
||||
| Typesense | `GET /health` | `{"ok": true}` |
|
||||
| Redis | `redis-cli ping` | `PONG` |
|
||||
| PostgreSQL | `pg_isready -h host -p 5432` | Exit code 0 |
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
### Horizontal Scaling
|
||||
|
||||
- **API**: Stateless — scale with multiple instances behind a load balancer
|
||||
- **Web**: Stateless — scale with multiple instances or deploy to Vercel/Cloudflare
|
||||
- **AI Services**: CPU-bound — scale based on valuation request volume
|
||||
- **Redis**: Use Redis Cluster for high availability
|
||||
- **PostgreSQL**: Read replicas for query-heavy workloads
|
||||
|
||||
### Recommended Architecture (Production)
|
||||
|
||||
```
|
||||
┌─────────────┐
|
||||
│ Load Balancer│
|
||||
│ (nginx/ALB) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌────────────┼────────────┐
|
||||
│ │ │
|
||||
┌─────▼──┐ ┌─────▼──┐ ┌─────▼──┐
|
||||
│ API #1 │ │ API #2 │ │ API #N │
|
||||
└────────┘ └────────┘ └────────┘
|
||||
│ │ │
|
||||
└────────────┼────────────┘
|
||||
│
|
||||
┌────────────┼────────────┐
|
||||
│ │ │
|
||||
┌─────▼──┐ ┌─────▼──┐ ┌─────▼─────┐
|
||||
│ PG │ │ Redis │ │ Typesense │
|
||||
│Primary │ │Cluster │ │ Cluster │
|
||||
│+ Replica│ │ │ │ │
|
||||
└────────┘ └────────┘ └────────────┘
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
### Application Rollback
|
||||
|
||||
Deploy the previous container image or build artifact. The API and Web are stateless — no rollback-specific steps needed.
|
||||
|
||||
### Database Rollback
|
||||
|
||||
Prisma does not support automatic down migrations. If a migration must be reverted:
|
||||
|
||||
1. Identify the migration in `prisma/migrations/`
|
||||
2. Write a manual SQL rollback script
|
||||
3. Apply via `psql` or a migration tool
|
||||
4. Update `_prisma_migrations` table
|
||||
|
||||
Always test migrations against a staging database before production deployment.
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Engine 24+ & Docker Compose v2
|
||||
- Node.js 22 LTS (for running app services locally)
|
||||
- **Docker Engine 24+** & Docker Compose v2
|
||||
- **Node.js 22 LTS**
|
||||
- **pnpm 10.27+** — install via `corepack enable && corepack prepare pnpm@latest --activate`
|
||||
|
||||
## Quick Start
|
||||
|
||||
@@ -16,19 +17,41 @@ docker compose up -d
|
||||
|
||||
# 3. Verify all services are healthy
|
||||
docker compose ps
|
||||
|
||||
# 4. Install dependencies
|
||||
pnpm install
|
||||
|
||||
# 5. Generate Prisma client
|
||||
pnpm db:generate
|
||||
|
||||
# 6. Run database migrations
|
||||
pnpm db:migrate:dev
|
||||
|
||||
# 7. Seed the database (optional)
|
||||
pnpm db:seed
|
||||
|
||||
# 8. Start API and Web in dev mode
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Services
|
||||
API runs at `http://localhost:3000`, Web at `http://localhost:3001`.
|
||||
|
||||
| Service | Port(s) | Description | Dashboard/UI |
|
||||
| ---------- | ----------- | ---------------------------- | ------------------------------- |
|
||||
| PostgreSQL | 5432 | Database with PostGIS | — |
|
||||
| Redis | 6379 | Cache, sessions, queue | — |
|
||||
| Typesense | 8108 | Full-text search engine | http://localhost:8108/health |
|
||||
| MinIO | 9000 / 9001 | S3-compatible object storage | http://localhost:9001 (console) |
|
||||
## Infrastructure Services
|
||||
|
||||
| Service | Port(s) | Description | Dashboard/UI |
|
||||
|---------|---------|-------------|--------------|
|
||||
| PostgreSQL + PostGIS | 5432 | Database with spatial queries | — |
|
||||
| Redis | 6379 | Cache, sessions, queue | — |
|
||||
| Typesense | 8108 | Full-text search engine | `http://localhost:8108/health` |
|
||||
| MinIO | 9000 / 9001 | S3-compatible object storage | `http://localhost:9001` (console) |
|
||||
| AI Services | 8000 | FastAPI — AVM + moderation | `http://localhost:8000/health` |
|
||||
| Prometheus | 9090 | Metrics collection | `http://localhost:9090` |
|
||||
| Grafana | 3002 | Dashboards & monitoring | `http://localhost:3002` |
|
||||
|
||||
## Common Commands
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```bash
|
||||
# Start services
|
||||
docker compose up -d
|
||||
@@ -50,6 +73,36 @@ docker compose restart redis
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
pnpm dev # Start all apps in watch mode
|
||||
pnpm build # Build all packages
|
||||
pnpm lint # ESLint across monorepo
|
||||
pnpm typecheck # TypeScript type checking
|
||||
pnpm format # Prettier formatting
|
||||
pnpm test # Run unit/integration tests
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
```bash
|
||||
pnpm db:generate # Regenerate Prisma client
|
||||
pnpm db:migrate:dev # Create and apply migrations
|
||||
pnpm db:seed # Seed database
|
||||
pnpm db:studio # Open Prisma Studio (visual editor)
|
||||
pnpm db:reset # Reset database (destructive)
|
||||
```
|
||||
|
||||
### E2E Testing
|
||||
|
||||
```bash
|
||||
pnpm test:e2e # Run all E2E tests
|
||||
pnpm test:e2e:api # API tests only
|
||||
pnpm test:e2e:web # Web UI tests only
|
||||
pnpm test:e2e:report # Open HTML test report
|
||||
```
|
||||
|
||||
## Connecting to Services
|
||||
|
||||
### PostgreSQL
|
||||
@@ -76,11 +129,25 @@ curl http://localhost:8108/health
|
||||
|
||||
### MinIO
|
||||
|
||||
- API: `http://localhost:9000`
|
||||
- Console: `http://localhost:9001` (login: minioadmin / minioadmin_secret)
|
||||
- **API**: `http://localhost:9000`
|
||||
- **Console**: `http://localhost:9001` (login: `minioadmin` / `minioadmin_secret`)
|
||||
|
||||
### AI Services
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
### Grafana
|
||||
|
||||
- **URL**: `http://localhost:3002`
|
||||
- **Login**: `admin` / `admin` (default, configurable via `.env`)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Port conflict**: Change ports in `.env` (e.g., `DB_PORT=5433`)
|
||||
- **Permission issues**: Run `docker compose down -v` and restart
|
||||
- **PostGIS not available**: Ensure using `postgis/postgis:16-3.4` image
|
||||
- **Port conflict** — Change ports in `.env` (e.g., `DB_PORT=5433`)
|
||||
- **Permission issues** — Run `docker compose down -v` and restart
|
||||
- **PostGIS not available** — Ensure using `postgis/postgis:16-3.4` image
|
||||
- **Prisma client out of date** — Run `pnpm db:generate` after pulling schema changes
|
||||
- **AI service not starting** — Check `docker compose logs ai-services` for Python dependency errors
|
||||
- **Typesense unhealthy** — Verify `TYPESENSE_API_KEY` matches in `.env` and Docker config
|
||||
|
||||
Reference in New Issue
Block a user