# GoodGo Platform — K6 Load Testing Endpoints Summary Quick reference for all testable API endpoints. ## 📍 Base URL ``` http://localhost:3001/api/v1 ``` --- ## 🔐 Authentication (Auth Module) ### Public Endpoints (No Auth Required) | Method | Path | Rate Limit | Purpose | |--------|------|-----------|---------| | **POST** | `/auth/register` | 5/hour | Register new user with phone/password/name | | **POST** | `/auth/login` | 5/hour | Login with phone/password (basic auth) | | **POST** | `/auth/refresh` | 5/hour | Refresh expired access token | | **POST** | `/auth/logout` | None | Clear auth cookies | | **POST** | `/auth/exchange-token` | None | Exchange OAuth tokens for httpOnly cookies | ### Protected Endpoints (JWT Required) | Method | Path | Rate Limit | Purpose | |--------|------|-----------|---------| | **GET** | `/auth/profile` | None | Get authenticated user profile | | **GET** | `/auth/profile/agent` | None | Get agent profile (if user is agent) | ### Admin Only | Method | Path | Rate Limit | Auth | Purpose | |--------|------|-----------|------|---------| | **PATCH** | `/auth/kyc` | None | JWT+Admin | Verify/update user KYC status | --- ## 🏠 Listings (Listings Module) ### Public Endpoints | Method | Path | Rate Limit | Purpose | |--------|------|-----------|---------| | **GET** | `/listings` | None | Search/filter listings (queryable) | | **GET** | `/listings/:id` | None | Get listing detail by ID | ### Protected Endpoints (JWT Required) | Method | Path | Quota Gate | Purpose | |--------|------|-----------|---------| | **POST** | `/listings` | Yes | Create new property listing | | **PATCH** | `/listings/:id/status` | No | Update listing status (owner only) | | **POST** | `/listings/:id/media` | No | Upload photo/video for listing (owner only) | ### Admin Only | Method | Path | Purpose | |--------|------|---------| | **GET** | `/listings/pending` | Get listings awaiting moderation (paginated) | | **PATCH** | `/listings/:id/moderate` | Approve/reject listing & score it | --- ## 💳 Payments (Payments Module) ### Protected Endpoints (JWT Required) | Method | Path | Purpose | |--------|------|---------| | **POST** | `/payments` | Create payment (initiates payment flow) | | **GET** | `/payments` | List user's transactions (paginated) | | **GET** | `/payments/:id` | Get payment status by ID | ### Admin Only | Method | Path | Purpose | |--------|------|---------| | **POST** | `/payments/:id/refund` | Initiate refund for payment | ### Webhook (Unthrottled, No Auth) | Method | Path | Rate Limit | Purpose | |--------|------|-----------|---------| | **POST** | `/payments/callback/:provider` | 20/min | Handle payment provider callbacks (VNPay, MoMo, ZaloPay) | --- ## 🔍 Search (Search Module) ### Public Endpoints | Method | Path | Purpose | Query Params | |--------|------|---------|--------------| | **GET** | `/search` | Full-text search listings | q, propertyType, transactionType, priceMin/Max, areaMin/Max, bedrooms, district, city, sortBy, page, perPage | | **GET** | `/search/geo` | Geographic radius search | lat, lng, radiusKm, propertyType, transactionType, priceMin/Max, sortBy, page, perPage | ### Admin Only | Method | Path | Purpose | |--------|------|---------| | **POST** | `/search/reindex` | Reindex all properties in search engine | --- ## 📊 Key Data Shapes ### User Registration ```json POST /auth/register { "phone": "0901234567", "password": "SecurePass123!", "fullName": "Nguyen Van A", "email": "user@example.com" // optional } ``` ### User Login ```json POST /auth/login { "phone": "0901234567", "password": "SecurePass123!" } ``` ### Create Listing (Minimal) ```json POST /listings { "transactionType": "SALE", "priceVND": "5500000000", "propertyType": "APARTMENT", "title": "Căn hộ 3PN view sông", "description": "Căn hộ cao cấp 3 phòng ngủ, nội thất đầy đủ...", "address": "208 Nguyễn Hữu Cảnh", "ward": "Phường 22", "district": "Bình Thạnh", "city": "Hồ Chí Minh", "latitude": 10.7942, "longitude": 106.7219, "areaM2": 85.5 } ``` ### Search Listings ```json GET /listings?transactionType=SALE&city=Hồ Chi Minh&minPrice=2000000000&maxPrice=10000000000&page=1&limit=20 ``` ### Full-Text Search ```json GET /search?q=chung cu quan 7&propertyType=apartment&transactionType=sale&page=1&perPage=20 ``` ### Geo Search ```json GET /search/geo?lat=10.7769&lng=106.7009&radiusKm=5&transactionType=sale&page=1&perPage=20 ``` ### Create Payment ```json POST /payments { "provider": "VNPAY", "type": "LISTING_FEE", "amountVND": 500000, "description": "Listing fee", "returnUrl": "https://example.com/return", "idempotencyKey": "uuid-123" } ``` --- ## 🎯 K6 Test Scenarios ### Load Test 1: Search Load (High Volume, Public) - **Endpoint**: `GET /search` & `GET /search/geo` - **Load Profile**: Ramp 100 → 1000 users over 10 min - **Success Criteria**: p(95) < 500ms, p(99) < 1000ms - **Expected**: Public search should handle high concurrent load ### Load Test 2: Authentication (Moderate Load, Gated) - **Endpoint**: `POST /auth/register`, `POST /auth/login` - **Load Profile**: Ramp 10 → 100 users - **Rate Limit**: 5/hour per endpoint - **Success Criteria**: All requests within rate limit, p(95) < 300ms - **Expected**: Should gracefully reject over-limit requests ### Load Test 3: Listing Creation (Low Load, Quota Gated) - **Endpoint**: `POST /listings` - **Load Profile**: Ramp 5 → 50 users over 5 min - **Rate Limit**: Quota-gated (per subscription plan) - **Success Criteria**: 201 for successful creates, 403 for quota exceeded - **Expected**: Quota guard enforces plan limits ### Load Test 4: Payment Processing (Medium Load, Unthrottled) - **Endpoint**: `POST /payments` - **Load Profile**: Ramp 20 → 200 users - **Dependencies**: Requires authenticated session (JWT) - **Success Criteria**: p(95) < 1s (external provider latency) - **Expected**: System handles payment initiation concurrently ### Load Test 5: Payment Webhooks (High Volume, Throttled) - **Endpoint**: `POST /payments/callback/vnpay` - **Load Profile**: Sustained 20 requests/min (rate limit) - **Rate Limit**: 20/min enforced - **Success Criteria**: All requests process within rate limit - **Expected**: Webhook queue prevents abuse --- ## 🔗 Authentication Flow for K6 ### Cookie-Based Flow (Recommended) ```javascript // 1. Register/Login const loginRes = http.post(`${BASE_URL}/auth/login`, { phone, password }); // Cookies: access_token, refresh_token, goodgo_authenticated // 2. Use cookies for authenticated requests const profileRes = http.get(`${BASE_URL}/auth/profile`); // Browser automatically sends cookies // 3. Refresh when needed const refreshRes = http.post(`${BASE_URL}/auth/refresh`); ``` ### Token-Based Flow (Alternative) ```javascript // 1. Capture tokens from register/login const loginRes = http.post(`${BASE_URL}/auth/login`, { phone, password }); const { accessToken, refreshToken } = loginRes.json(); // 2. Use Bearer token header const params = { headers: { Authorization: `Bearer ${accessToken}` } }; const profileRes = http.get(`${BASE_URL}/auth/profile`, params); // 3. Refresh access token const refreshRes = http.post(`${BASE_URL}/auth/refresh`, { refreshToken }, params ); ``` --- ## 🏪 Test Data Resources ### Available Seed Data - **Users**: Various roles (USER, AGENT, ADMIN) - **Listings**: Properties across Ho Chi Minh City districts - **Districts/Wards**: Vietnamese administrative data - **Property Types**: APARTMENT, HOUSE, LAND, SHOP, etc. - **Transaction Types**: SALE, RENT ### Test Fixtures - See `e2e/fixtures.ts` for test data generators - Use `createTestUser()` to generate unique test users - Test database seeded in `global-setup.ts` --- ## ⚡ Quick K6 Script Template ```javascript import http from 'k6/http'; import { check, group, sleep } from 'k6'; const BASE_URL = __ENV.BASE_URL || 'http://localhost:3001/api/v1'; export const options = { stages: [ { duration: '2m', target: 100 }, // Ramp up { duration: '5m', target: 100 }, // Sustain { 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() { group('Search - Public, High Volume', () => { const res = http.get(`${BASE_URL}/search?q=chung cu&page=1&perPage=20`); check(res, { 'status is 200': (r) => r.status === 200 }); sleep(1); }); group('Geo Search - Public', () => { const res = http.get(`${BASE_URL}/search/geo?lat=10.77&lng=106.70&radiusKm=5&perPage=20`); check(res, { 'status is 200': (r) => r.status === 200 }); sleep(1); }); } ``` --- ## 📌 Important Rate Limits | Endpoint | Limit | Window | |----------|-------|--------| | `/auth/register` | 5 | per hour | | `/auth/login` | 5 | per hour | | `/auth/refresh` | 5 | per hour | | `/payments/callback/*` | 20 | per minute | | Others | None | (quota gates apply instead) | --- ## 📁 Files to Reference ``` K6_LOAD_TESTING_GUIDE.md # Comprehensive guide (THIS FILE IS SUMMARY OF) apps/api/src/modules/*/presentation/controllers/ apps/api/src/modules/*/presentation/dto/ e2e/fixtures.ts # Test data generators e2e/api/ # Existing E2E tests (reference) .env.example # Environment setup ``` --- ## ✅ Checklist Before Running K6 - [ ] API running: `pnpm dev` - [ ] Database seeded: `pnpm db:seed` - [ ] Test database migrated: `.env.test` configured - [ ] K6 installed: `brew install k6` or Docker - [ ] JWT_SECRET set in `.env` - [ ] Base URL correct: `http://localhost:3001/api/v1` ---