Files
goodgo-platform/docs/load-testing/K6_ENDPOINTS_SUMMARY.md
Ho Ngoc Hai b93c28fa01 chore: organize docs — move 37 files from root into docs/ subfolders
Root now contains only essential files:
  README.md, CLAUDE.md, CHANGELOG.md, CONTRIBUTING.md

Reorganized into:
  docs/audits/       — all audit reports & checklists (71 files)
  docs/architecture/  — codebase overview, implementation plan
  docs/guides/        — auth guide, implementation checklist
  docs/load-testing/  — k6 load test guides & endpoints
  docs/security/      — payment & security reviews

Also removed 5 untracked debug/investigation files and
cleaned up playwright-report/ & test-results/ artifacts.

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
2026-04-13 12:09:14 +07:00

9.5 KiB

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

POST /auth/register
{
  "phone": "0901234567",
  "password": "SecurePass123!",
  "fullName": "Nguyen Van A",
  "email": "user@example.com"  // optional
}

User Login

POST /auth/login
{
  "phone": "0901234567",
  "password": "SecurePass123!"
}

Create Listing (Minimal)

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

GET /listings?transactionType=SALE&city=Hồ Chi Minh&minPrice=2000000000&maxPrice=10000000000&page=1&limit=20
GET /search?q=chung cu quan 7&propertyType=apartment&transactionType=sale&page=1&perPage=20
GET /search/geo?lat=10.7769&lng=106.7009&radiusKm=5&transactionType=sale&page=1&perPage=20

Create Payment

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

// 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)

// 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

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