- Fix remaining "Next.js 14" references in: - docs/architecture/IMPLEMENTATION_QUICK_REFERENCE.md - docs/load-testing/K6_LOAD_TESTING_GUIDE.md - Create README.md for libs/ai-services/ (FastAPI AVM, moderation, NLP) - Create README.md for libs/mcp-servers/ (MCP tool server library) - Note: CLAUDE.md, README.md, and docs/architecture.md were already updated in a prior pass Co-Authored-By: Paperclip <noreply@paperclip.ing>
806 lines
22 KiB
Markdown
806 lines
22 KiB
Markdown
# GoodGo Platform API — K6 Load Testing Guide
|
|
|
|
## 🎯 Quick Summary
|
|
|
|
**Base URL**: `http://localhost:3001/api/v1`
|
|
**Node Version**: >= 22.0.0
|
|
**Testing Framework**: Playwright (E2E), Vitest (Unit)
|
|
**No existing K6 or load testing setup found**
|
|
|
|
---
|
|
|
|
## 📋 Project Structure
|
|
|
|
### Root Directory
|
|
```
|
|
goodgo-platform/
|
|
├── apps/api # NestJS backend (port 3001)
|
|
├── apps/web # Next.js 15 frontend (port 3000)
|
|
├── libs/mcp-servers # MCP tool server library
|
|
├── prisma/ # Database schema & migrations
|
|
├── e2e/ # Playwright E2E tests (api + web)
|
|
├── turbo.json # Turborepo config
|
|
├── package.json # Root workspace scripts
|
|
├── .env.example # Environment variables template
|
|
└── playwright.config.ts # Playwright configuration
|
|
```
|
|
|
|
### Key Scripts (package.json)
|
|
```bash
|
|
pnpm dev # Start all apps (API :3001, Web :3000)
|
|
pnpm test # Unit tests via Vitest (API only)
|
|
pnpm test:e2e # Playwright E2E tests
|
|
pnpm test:e2e:api # API E2E tests only
|
|
pnpm test:e2e:web # Web E2E tests only
|
|
pnpm build # Production build
|
|
pnpm lint # ESLint
|
|
pnpm typecheck # TypeScript checking
|
|
```
|
|
|
|
---
|
|
|
|
## 🏗️ API Module Structure
|
|
|
|
### API Base Architecture: `apps/api/src/modules/`
|
|
|
|
Each module follows DDD layers: `domain/` → `application/` → `infrastructure/` → `presentation/`
|
|
|
|
```
|
|
modules/
|
|
├── auth/ # Authentication & JWT
|
|
├── listings/ # Property listings CRUD
|
|
├── payments/ # Payment processing (VNPay, MoMo, ZaloPay)
|
|
├── search/ # Full-text & geo search (Typesense)
|
|
├── subscriptions/ # Plans, quotas, usage tracking
|
|
├── admin/ # Moderation, KYC, user management
|
|
├── analytics/ # Market data, heatmaps, price trends
|
|
├── reviews/ # User reviews
|
|
├── notifications/ # Email, push (FCM), in-app
|
|
├── metrics/ # Prometheus metrics
|
|
├── health/ # Health checks
|
|
├── shared/ # Domain primitives, guards, pipes, logging
|
|
└── mcp/ # MCP tool server endpoints
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 AUTH MODULE
|
|
|
|
### Controllers & Endpoints
|
|
|
|
#### File: `apps/api/src/modules/auth/presentation/controllers/auth.controller.ts`
|
|
|
|
| Method | Endpoint | Rate Limit | Auth | Description |
|
|
|--------|----------|-----------|------|-------------|
|
|
| POST | `/auth/register` | 5/hour | No | Register new user |
|
|
| POST | `/auth/login` | 5/hour | LocalAuth | Login with phone + password |
|
|
| POST | `/auth/refresh` | 5/hour | No | Refresh access token |
|
|
| POST | `/auth/logout` | No limit | No | Clear auth cookies |
|
|
| POST | `/auth/exchange-token` | No limit | No | Exchange OAuth tokens for cookies |
|
|
| GET | `/auth/profile` | No limit | JWT | Get current user profile |
|
|
| GET | `/auth/profile/agent` | No limit | JWT | Get agent profile for user |
|
|
| PATCH | `/auth/kyc` | No limit | JWT+Admin | Verify user KYC (admin only) |
|
|
|
|
### DTOs
|
|
|
|
#### LoginDto
|
|
```typescript
|
|
{
|
|
phone: string // Required, example: "0901234567"
|
|
password: string // Required, example: "P@ssw0rd!"
|
|
}
|
|
```
|
|
|
|
#### RegisterDto
|
|
```typescript
|
|
{
|
|
phone: string // Required, example: "0901234567"
|
|
password: string // Required, min 8 chars, example: "P@ssw0rd!"
|
|
fullName: string // Required, example: "Nguyen Van A"
|
|
email?: string // Optional, valid email format
|
|
}
|
|
```
|
|
|
|
#### RefreshTokenDto
|
|
```typescript
|
|
{
|
|
refreshToken?: string // Optional if using cookie
|
|
}
|
|
```
|
|
|
|
#### VerifyKycDto
|
|
```typescript
|
|
{
|
|
userId: string
|
|
kycStatus: string
|
|
kycData?: object
|
|
}
|
|
```
|
|
|
|
### Cookies & Authentication
|
|
|
|
**Access Token**:
|
|
- Cookie: `access_token`
|
|
- Max Age: 15 minutes (900s)
|
|
- HttpOnly: true
|
|
- Secure: true (production only)
|
|
- SameSite: strict
|
|
- Path: /
|
|
|
|
**Refresh Token**:
|
|
- Cookie: `refresh_token`
|
|
- Max Age: 30 days
|
|
- HttpOnly: true
|
|
- Secure: true (production only)
|
|
- SameSite: strict
|
|
- Path: `/auth`
|
|
|
|
**Session Indicator**:
|
|
- Cookie: `goodgo_authenticated` = "1"
|
|
- HttpOnly: false (visible to frontend)
|
|
|
|
### OAuth Support
|
|
- Google OAuth 2.0
|
|
- Zalo OAuth (Vietnamese platform)
|
|
- Environment: `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `ZALO_APP_ID`, `ZALO_APP_SECRET`
|
|
|
|
---
|
|
|
|
## 🏠 LISTINGS MODULE
|
|
|
|
### Controllers & Endpoints
|
|
|
|
#### File: `apps/api/src/modules/listings/presentation/controllers/listings.controller.ts`
|
|
|
|
| Method | Endpoint | Auth | Quota | Description |
|
|
|--------|----------|------|-------|-------------|
|
|
| POST | `/listings` | JWT | Yes | Create new listing |
|
|
| GET | `/listings` | No | No | Search/filter listings (public) |
|
|
| GET | `/listings/:id` | No | No | Get listing detail |
|
|
| GET | `/listings/pending` | JWT+Admin | No | Get listings pending moderation |
|
|
| PATCH | `/listings/:id/status` | JWT | No | Update listing status |
|
|
| POST | `/listings/:id/media` | JWT | No | Upload photo/video |
|
|
| PATCH | `/listings/:id/moderate` | JWT+Admin | No | Moderate a listing (admin) |
|
|
|
|
### DTOs
|
|
|
|
#### CreateListingDto
|
|
```typescript
|
|
{
|
|
transactionType: 'SALE' | 'RENT',
|
|
priceVND: bigint | string,
|
|
propertyType: 'APARTMENT' | 'HOUSE' | 'LAND' | etc.,
|
|
title: string, // Min 5 chars
|
|
description: string, // Min 10 chars
|
|
address: string,
|
|
ward: string,
|
|
district: string,
|
|
city: string,
|
|
latitude: number, // -90 to 90
|
|
longitude: number, // -180 to 180
|
|
areaM2: number, // Total area
|
|
usableAreaM2?: number,
|
|
bedrooms?: number,
|
|
bathrooms?: number,
|
|
floors?: number, // For houses
|
|
floor?: number, // For apartments
|
|
totalFloors?: number,
|
|
direction?: 'EAST' | 'WEST' | 'NORTH' | 'SOUTH' | etc.,
|
|
yearBuilt?: number,
|
|
legalStatus?: string,
|
|
amenities?: string[], // e.g., ['Hồ bơi', 'Gym']
|
|
nearbyPOIs?: object, // e.g., { schools: [], hospitals: [] }
|
|
metroDistanceM?: number,
|
|
projectName?: string,
|
|
agentId?: string,
|
|
rentPriceMonthly?: bigint | string,
|
|
commissionPct?: number,
|
|
}
|
|
```
|
|
|
|
#### SearchListingsDto
|
|
```typescript
|
|
{
|
|
status?: 'ACTIVE' | 'INACTIVE' | 'ARCHIVED',
|
|
transactionType?: 'SALE' | 'RENT',
|
|
propertyType?: 'APARTMENT' | 'HOUSE' | 'LAND' | etc.,
|
|
city?: string,
|
|
district?: string,
|
|
minPrice?: bigint | string,
|
|
maxPrice?: bigint | string,
|
|
minArea?: number,
|
|
maxArea?: number,
|
|
bedrooms?: number,
|
|
page?: number, // Default: 1
|
|
limit?: number, // Default: 20, Max: 100
|
|
}
|
|
```
|
|
|
|
#### UpdateListingStatusDto
|
|
```typescript
|
|
{
|
|
status: string,
|
|
moderationNotes?: string,
|
|
}
|
|
```
|
|
|
|
#### ModerateListingDto
|
|
```typescript
|
|
{
|
|
action: 'APPROVE' | 'REJECT',
|
|
moderationScore?: number,
|
|
notes?: string,
|
|
}
|
|
```
|
|
|
|
### Response Structures
|
|
|
|
#### ListingDetailData
|
|
Contains full listing information including:
|
|
- id, title, description
|
|
- propertyType, transactionType
|
|
- address, latitude, longitude, ward, district, city
|
|
- priceVND, rentPriceMonthly
|
|
- areaM2, usableAreaM2, bedrooms, bathrooms, floors
|
|
- amenities, nearbyPOIs
|
|
- legalStatus, yearBuilt, direction
|
|
- mediaUrls (photos/videos)
|
|
- agentInfo
|
|
- createdAt, updatedAt
|
|
|
|
#### PaginatedResult<ListingSearchItem>
|
|
```typescript
|
|
{
|
|
items: ListingSearchItem[],
|
|
total: number,
|
|
page: number,
|
|
limit: number,
|
|
totalPages: number,
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 💳 PAYMENTS MODULE
|
|
|
|
### Controllers & Endpoints
|
|
|
|
#### File: `apps/api/src/modules/payments/presentation/controllers/payments.controller.ts`
|
|
|
|
| Method | Endpoint | Auth | Rate Limit | Description |
|
|
|--------|----------|------|-----------|-------------|
|
|
| POST | `/payments` | JWT | No | Create payment |
|
|
| GET | `/payments` | JWT | No | List user transactions |
|
|
| GET | `/payments/:id` | JWT | No | Get payment status |
|
|
| POST | `/payments/callback/:provider` | No | 20/min | Handle payment callback (webhook) |
|
|
| POST | `/payments/:id/refund` | JWT+Admin | No | Refund payment (admin) |
|
|
|
|
### DTOs
|
|
|
|
#### CreatePaymentDto
|
|
```typescript
|
|
{
|
|
provider: 'VNPAY' | 'MOMO' | 'ZALOPAY',
|
|
type: 'LISTING_FEE' | 'SUBSCRIPTION' | 'AGENT_COMMISSION',
|
|
amountVND: number, // 1 to 100,000,000,000
|
|
description: string, // Payment description
|
|
returnUrl: string, // URL (must be valid)
|
|
transactionId?: string, // External ID
|
|
idempotencyKey?: string, // For idempotency
|
|
}
|
|
```
|
|
|
|
#### ListTransactionsDto
|
|
```typescript
|
|
{
|
|
status?: string,
|
|
limit?: number,
|
|
offset?: number,
|
|
}
|
|
```
|
|
|
|
#### RefundPaymentDto
|
|
```typescript
|
|
{
|
|
reason: string,
|
|
}
|
|
```
|
|
|
|
### Payment Providers
|
|
|
|
- **VNPay** (Primary for Vietnam)
|
|
- Environment: `VNPAY_TMN_CODE`, `VNPAY_HASH_SECRET`
|
|
- Sandbox: `https://sandbox.vnpayment.vn/paymentv2/vpcpay.html`
|
|
- API: `https://sandbox.vnpayment.vn/merchant_webapi/api/transaction`
|
|
|
|
- **MoMo** (Mobile wallet)
|
|
- Environment: `MOMO_PARTNER_CODE`, `MOMO_ACCESS_KEY`, `MOMO_SECRET_KEY`
|
|
- Endpoint: `https://test-payment.momo.vn/v2/gateway/api`
|
|
|
|
- **ZaloPay** (Zalo integrated)
|
|
- Environment: `ZALOPAY_APP_ID`, `ZALOPAY_KEY1`, `ZALOPAY_KEY2`
|
|
- Endpoint: `https://sb-openapi.zalopay.vn/v2`
|
|
|
|
### Callback Processing
|
|
|
|
**Webhook URL Pattern**: `/payments/callback/{provider}`
|
|
|
|
Supports both:
|
|
- Query parameters (VNPay)
|
|
- Request body (MoMo, ZaloPay)
|
|
- Merged data handling internally
|
|
|
|
---
|
|
|
|
## 🔍 SEARCH MODULE
|
|
|
|
### Controllers & Endpoints
|
|
|
|
#### File: `apps/api/src/modules/search/presentation/controllers/search.controller.ts`
|
|
|
|
| Method | Endpoint | Auth | Description |
|
|
|--------|----------|------|-------------|
|
|
| GET | `/search` | No | Full-text search (public) |
|
|
| GET | `/search/geo` | No | Geographic radius search (public) |
|
|
| POST | `/search/reindex` | JWT+Admin | Reindex all properties (admin) |
|
|
|
|
### DTOs
|
|
|
|
#### SearchPropertiesDto (Full-text search)
|
|
```typescript
|
|
{
|
|
q?: string, // Free-text query, e.g., 'chung cu quan 7'
|
|
propertyType?: string, // Filter by type
|
|
transactionType?: string, // 'sale' or 'rent'
|
|
priceMin?: number, // Min price in VND
|
|
priceMax?: number, // Max price in VND
|
|
areaMin?: number, // Min area in m²
|
|
areaMax?: number, // Max area in m²
|
|
bedrooms?: number, // Number of bedrooms
|
|
district?: string, // District name
|
|
city?: string, // City name
|
|
sortBy?: 'price_asc' | 'price_desc' | 'date_desc' | 'relevance',
|
|
page?: number, // 1-based, default: 1
|
|
perPage?: number, // Default: 20, Max: 100
|
|
}
|
|
```
|
|
|
|
#### GeoSearchDto (Geographic search)
|
|
```typescript
|
|
{
|
|
lat: number, // Latitude, -90 to 90
|
|
lng: number, // Longitude, -180 to 180
|
|
radiusKm: number, // Radius, 0.1 to 100
|
|
propertyType?: string,
|
|
transactionType?: string,
|
|
priceMin?: number,
|
|
priceMax?: number,
|
|
sortBy?: 'distance' | 'price_asc' | 'price_desc' | 'date_desc',
|
|
page?: number, // Default: 1
|
|
perPage?: number, // Default: 20, Max: 100
|
|
}
|
|
```
|
|
|
|
### Search Engine
|
|
|
|
**Typesense** integration for fast full-text & faceted search
|
|
- Environment: `TYPESENSE_HOST`, `TYPESENSE_PORT`, `TYPESENSE_API_KEY`
|
|
- Default: `http://localhost:8108`
|
|
|
|
### Response Structure
|
|
|
|
#### SearchResult
|
|
```typescript
|
|
{
|
|
results: SearchHit[],
|
|
facets?: {
|
|
propertyType?: { value: string; count: number }[],
|
|
district?: { value: string; count: number }[],
|
|
transactionType?: { value: string; count: number }[],
|
|
},
|
|
total: number,
|
|
page: number,
|
|
perPage: number,
|
|
totalPages: number,
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 🗄️ Database & Environment
|
|
|
|
### PostgreSQL with PostGIS
|
|
|
|
```
|
|
DB_HOST=localhost
|
|
DB_PORT=5432
|
|
DB_NAME=goodgo
|
|
DB_USER=goodgo
|
|
DB_PASSWORD=<change_me>
|
|
DATABASE_URL=postgresql://goodgo:password@localhost:5432/goodgo?schema=public
|
|
```
|
|
|
|
### Redis Cache
|
|
|
|
```
|
|
REDIS_URL=redis://localhost:6379
|
|
```
|
|
|
|
### Key Environment Variables
|
|
|
|
```bash
|
|
# JWT Secrets (REQUIRED)
|
|
JWT_SECRET=<openssl rand -base64 48>
|
|
JWT_REFRESH_SECRET=<openssl rand -base64 48>
|
|
JWT_EXPIRES_IN=15m
|
|
JWT_REFRESH_EXPIRES_IN=7d
|
|
|
|
# CORS
|
|
CORS_ORIGINS=http://localhost:3000,http://localhost:3001
|
|
|
|
# Node Environment
|
|
NODE_ENV=development|test|production
|
|
PORT=3001 # API port
|
|
|
|
# OAuth
|
|
GOOGLE_CLIENT_ID=
|
|
GOOGLE_CLIENT_SECRET=
|
|
ZALO_APP_ID=
|
|
ZALO_APP_SECRET=
|
|
|
|
# Typesense Search
|
|
TYPESENSE_HOST=localhost
|
|
TYPESENSE_PORT=8108
|
|
TYPESENSE_API_KEY=
|
|
|
|
# MinIO/S3 Storage
|
|
MINIO_ENDPOINT=localhost
|
|
MINIO_PORT=9000
|
|
MINIO_ACCESS_KEY=
|
|
MINIO_SECRET_KEY=
|
|
MINIO_BUCKET=goodgo-media
|
|
|
|
# Payment Gateways
|
|
VNPAY_TMN_CODE=
|
|
VNPAY_HASH_SECRET=
|
|
MOMO_PARTNER_CODE=
|
|
ZALOPAY_APP_ID=
|
|
|
|
# Logging
|
|
LOG_LEVEL=info
|
|
```
|
|
|
|
---
|
|
|
|
## 🧪 Existing Test Setup
|
|
|
|
### Playwright Configuration
|
|
|
|
**File**: `playwright.config.ts`
|
|
|
|
```typescript
|
|
testDir: './e2e'
|
|
globalSetup: './e2e/global-setup.ts'
|
|
globalTeardown: './e2e/global-teardown.ts'
|
|
|
|
Projects:
|
|
- "api": Tests NestJS API (port 3001)
|
|
baseURL: http://localhost:3001/api/v1
|
|
- "web": Tests Next.js frontend (port 3000)
|
|
baseURL: http://localhost:3000
|
|
```
|
|
|
|
### Playwright Scripts
|
|
|
|
```bash
|
|
pnpm test:e2e # Run all E2E tests
|
|
pnpm test:e2e:api # API tests only
|
|
pnpm test:e2e:web # Web tests only
|
|
pnpm test:e2e:report # Show HTML report
|
|
```
|
|
|
|
### Test Database
|
|
|
|
- CI uses `goodgo_test` database
|
|
- Local uses `.env.test` for test database URL
|
|
- Migrations & seed run in `global-setup.ts`
|
|
- Cleanup in `global-teardown.ts`
|
|
|
|
### Example E2E Test
|
|
|
|
**File**: `e2e/api/auth-register.spec.ts`
|
|
|
|
```typescript
|
|
import { test, expect } from '@playwright/test';
|
|
import { createTestUser } from '../fixtures';
|
|
|
|
test.describe('POST /auth/register', () => {
|
|
test('registers a new user and returns token pair', async ({ request }) => {
|
|
const user = createTestUser();
|
|
const res = await request.post('/auth/register', { data: user });
|
|
|
|
expect(res.status()).toBe(201);
|
|
const body = await res.json();
|
|
expect(body).toHaveProperty('accessToken');
|
|
expect(body).toHaveProperty('refreshToken');
|
|
});
|
|
});
|
|
```
|
|
|
|
### Unit Tests (Vitest)
|
|
|
|
```bash
|
|
pnpm test # Run unit tests (API only)
|
|
pnpm test:integration # Integration tests
|
|
```
|
|
|
|
---
|
|
|
|
## 🔄 CI/CD Setup
|
|
|
|
### GitHub Actions Workflows
|
|
|
|
#### `ci.yml` - Lint → Typecheck → Test → Build
|
|
- Runs on: `push main` and `pull_request`
|
|
- Services: PostgreSQL 16 + PostGIS
|
|
- Steps: lint → typecheck → test → build
|
|
|
|
#### `e2e.yml` - Playwright E2E Tests
|
|
- Runs on: `push main` and `pull_request`
|
|
- Services:
|
|
- PostgreSQL 16 + PostGIS
|
|
- Redis 7
|
|
- Typesense 27.1
|
|
- MinIO (S3-compatible storage)
|
|
- Artifacts: HTML report + traces
|
|
|
|
#### `security.yml` - Code Security
|
|
- Dependency scanning
|
|
- SAST analysis
|
|
|
|
#### `deploy.yml` - Production Deployment
|
|
- Docker builds
|
|
- Registry push
|
|
- Deployment orchestration
|
|
|
|
---
|
|
|
|
## 📊 Architecture Patterns
|
|
|
|
### NestJS CQRS Pattern
|
|
|
|
Each module uses:
|
|
- **Commands** (Write operations)
|
|
- `CommandBus.execute(command)`
|
|
- Located in `application/commands/`
|
|
- Handlers in `application/commands/{command}/`
|
|
|
|
- **Queries** (Read operations)
|
|
- `QueryBus.execute(query)`
|
|
- Located in `application/queries/`
|
|
- Handlers in `application/queries/{query}/`
|
|
|
|
Example:
|
|
```typescript
|
|
// In controller
|
|
const result = await this.commandBus.execute(
|
|
new CreateListingCommand(userId, ...)
|
|
);
|
|
|
|
const profile = await this.queryBus.execute(
|
|
new GetProfileQuery(userId)
|
|
);
|
|
```
|
|
|
|
### Guards & Interceptors
|
|
|
|
- `JwtAuthGuard` - Validates JWT token
|
|
- `LocalAuthGuard` - Email/password validation
|
|
- `RolesGuard` - Role-based access control
|
|
- `QuotaGuard` - Subscription quota enforcement
|
|
- `FileValidationPipe` - File upload validation
|
|
|
|
---
|
|
|
|
## 🚀 Starting the API
|
|
|
|
### Local Development
|
|
|
|
```bash
|
|
# Install dependencies
|
|
pnpm install
|
|
|
|
# Generate Prisma client
|
|
pnpm db:generate
|
|
|
|
# Run migrations
|
|
pnpm db:migrate:dev
|
|
|
|
# Seed data (users, listings, etc.)
|
|
pnpm db:seed
|
|
|
|
# Start API (and Web)
|
|
pnpm dev
|
|
|
|
# API will be available at:
|
|
# http://localhost:3001/api/v1
|
|
# Swagger UI: http://localhost:3001/api/v1/docs
|
|
```
|
|
|
|
### With Docker
|
|
|
|
```bash
|
|
docker-compose up
|
|
# Services: PostgreSQL, Redis, Typesense, MinIO, API, Web
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 K6 Load Testing Recommendations
|
|
|
|
### Key Endpoints to Test
|
|
|
|
1. **Authentication** (High priority)
|
|
- Register: `POST /auth/register`
|
|
- Login: `POST /auth/login`
|
|
- Refresh: `POST /auth/refresh`
|
|
- Profile: `GET /auth/profile` (authenticated)
|
|
|
|
2. **Listings** (High priority)
|
|
- Create: `POST /listings` (quota-gated)
|
|
- Search: `GET /listings` (public, high volume)
|
|
- Detail: `GET /listings/:id` (public, high volume)
|
|
|
|
3. **Search** (High priority)
|
|
- Full-text: `GET /search?q=...` (public, high volume)
|
|
- Geo: `GET /search/geo?lat=...&lng=...` (public, high volume)
|
|
|
|
4. **Payments** (Medium priority)
|
|
- Create: `POST /payments` (authenticated)
|
|
- List: `GET /payments` (authenticated)
|
|
- Webhook: `POST /payments/callback/:provider` (unthrottled)
|
|
|
|
5. **Admin Endpoints** (Medium priority, restricted)
|
|
- Moderate listings: `PATCH /listings/:id/moderate`
|
|
- List pending: `GET /listings/pending`
|
|
- Verify KYC: `PATCH /auth/kyc`
|
|
- Reindex: `POST /search/reindex`
|
|
|
|
### K6 Script Structure
|
|
|
|
```javascript
|
|
import http from 'k6/http';
|
|
import { check, group, sleep } from 'k6';
|
|
|
|
const BASE_URL = 'http://localhost:3001/api/v1';
|
|
|
|
// Stage-based load: ramp up → sustained → ramp down
|
|
export const options = {
|
|
stages: [
|
|
{ duration: '2m', target: 100 }, // Ramp up
|
|
{ duration: '5m', target: 100 }, // Sustained
|
|
{ duration: '2m', target: 0 }, // Ramp down
|
|
],
|
|
thresholds: {
|
|
http_req_duration: ['p(95)<500', 'p(99)<1000'],
|
|
http_req_failed: ['rate<0.1'],
|
|
},
|
|
};
|
|
|
|
export default function() {
|
|
// Test scenarios here
|
|
}
|
|
```
|
|
|
|
### Data Generation Tips
|
|
|
|
- Use test fixture users from Playwright tests
|
|
- Leverage Prisma seed data (districts, property types)
|
|
- Generate realistic search queries
|
|
- Test with various geo coordinates (Ho Chi Minh City: ~10.77°N, 106.70°E)
|
|
|
|
---
|
|
|
|
## 📁 File Locations Quick Reference
|
|
|
|
```
|
|
apps/api/
|
|
├── src/
|
|
│ ├── main.ts # API entry point (port 3001)
|
|
│ ├── app.module.ts # Root module
|
|
│ └── modules/
|
|
│ ├── auth/
|
|
│ │ ├── presentation/controllers/auth.controller.ts
|
|
│ │ ├── presentation/dto/
|
|
│ │ │ ├── login.dto.ts
|
|
│ │ │ ├── register.dto.ts
|
|
│ │ │ ├── refresh-token.dto.ts
|
|
│ │ │ └── verify-kyc.dto.ts
|
|
│ │ ├── application/commands/
|
|
│ │ ├── application/queries/
|
|
│ │ ├── infrastructure/services/token.service.ts
|
|
│ │ └── domain/
|
|
│ ├── listings/
|
|
│ │ ├── presentation/controllers/listings.controller.ts
|
|
│ │ ├── presentation/dto/
|
|
│ │ │ ├── create-listing.dto.ts
|
|
│ │ │ ├── search-listings.dto.ts
|
|
│ │ │ ├── update-listing-status.dto.ts
|
|
│ │ │ └── moderate-listing.dto.ts
|
|
│ │ └── ...
|
|
│ ├── payments/
|
|
│ │ ├── presentation/controllers/payments.controller.ts
|
|
│ │ ├── presentation/dto/
|
|
│ │ │ ├── create-payment.dto.ts
|
|
│ │ │ ├── list-transactions.dto.ts
|
|
│ │ │ └── refund-payment.dto.ts
|
|
│ │ └── ...
|
|
│ ├── search/
|
|
│ │ ├── presentation/controllers/search.controller.ts
|
|
│ │ ├── presentation/dto/
|
|
│ │ │ ├── search-properties.dto.ts
|
|
│ │ │ └── geo-search.dto.ts
|
|
│ │ └── ...
|
|
│ └── ...
|
|
│
|
|
└── package.json # Dependencies, scripts
|
|
|
|
e2e/
|
|
├── api/ # Playwright API tests
|
|
│ ├── auth-register.spec.ts
|
|
│ ├── auth-refresh.spec.ts
|
|
│ └── ...
|
|
├── web/ # Playwright web tests
|
|
├── fixtures.ts # Test data generators
|
|
├── global-setup.ts # DB setup before tests
|
|
└── global-teardown.ts # DB cleanup after tests
|
|
|
|
playwright.config.ts # Playwright config
|
|
.github/workflows/
|
|
├── ci.yml # Lint → typecheck → test → build
|
|
├── e2e.yml # Playwright E2E
|
|
├── security.yml # Security scanning
|
|
└── deploy.yml # Production deployment
|
|
|
|
.env.example # Environment variable template
|
|
.env.test # Test database connection
|
|
```
|
|
|
|
---
|
|
|
|
## 🔗 Useful Links & References
|
|
|
|
- **API Swagger Docs**: `http://localhost:3001/api/v1/docs`
|
|
- **Project Root Docs**: `CLAUDE.md`
|
|
- **Existing Analysis**: `CODEBASE_ANALYSIS.md`, `EXPLORATION_REPORT.md`
|
|
- **Frontend Docs**: `docs/audits/FRONTEND_EXPLORATION.md`
|
|
|
|
---
|
|
|
|
## ✅ Summary for K6 Implementation
|
|
|
|
**No existing K6 setup** — you have a clean slate!
|
|
|
|
**Key endpoints** identified across:
|
|
- Auth (register, login, refresh, profile)
|
|
- Listings (create, search, detail, moderate)
|
|
- Search (full-text, geo)
|
|
- Payments (create, callback, list, refund)
|
|
- Admin (moderate, KYC, reindex)
|
|
|
|
**Rate limits** to consider:
|
|
- Auth: 5/hour per endpoint
|
|
- Payments callback: 20/min
|
|
- Others: No limit (except quota guards on create operations)
|
|
|
|
**Infrastructure ready**:
|
|
- Turbo monorepo for dependency management
|
|
- PostgreSQL + PostGIS for spatial data
|
|
- Typesense for search indexing
|
|
- Redis for caching
|
|
- MinIO for media storage
|
|
- Prometheus metrics endpoint
|
|
|
|
**Tests can be integrated** into CI/CD pipeline via `.github/workflows/` (suggested: new `load-test.yml`)
|
|
|