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>
601 lines
16 KiB
Markdown
601 lines
16 KiB
Markdown
# GoodGo Platform AI - Technical Reference & Deep Dive
|
|
**For Developers & Architects**
|
|
|
|
---
|
|
|
|
## BACKEND MODULE HIERARCHY
|
|
|
|
### Core Module Dependencies
|
|
```
|
|
SharedModule (lowest level)
|
|
├── Infrastructure Services
|
|
├── Middleware & Guards
|
|
├── Decorators & Utilities
|
|
└── Domain Enums & Types
|
|
↓
|
|
├→ AuthModule
|
|
├→ HealthModule
|
|
└→ All Feature Modules
|
|
├→ AdminModule (audit, user management)
|
|
├→ AgentsModule (agent profiles, specialized deals)
|
|
├→ AnalyticsModule (market reports, valuation history)
|
|
├→ InquiriesModule (property inquiries)
|
|
├→ LeadsModule (agent leads management)
|
|
├→ ListingsModule (property listings)
|
|
├→ NotificationsModule (FCM push, email)
|
|
├→ PaymentsModule (VNPay integration)
|
|
├→ ReviewsModule (property reviews)
|
|
├→ SearchModule (Typesense full-text search)
|
|
├→ SubscriptionsModule (billing, usage metering)
|
|
└→ MetricsModule (Prometheus metrics)
|
|
```
|
|
|
|
---
|
|
|
|
## DOMAIN MODELS - RELATIONSHIPS
|
|
|
|
### User Role Hierarchy
|
|
```
|
|
User (root entity)
|
|
├── Role: BUYER → Can browse, search, inquire, purchase
|
|
├── Role: SELLER → Can create listings, receive inquiries, sell
|
|
├── Role: AGENT → Extends Seller + lead management
|
|
└── Role: ADMIN → All permissions + moderation
|
|
```
|
|
|
|
### Listing Workflow
|
|
```
|
|
User (SELLER)
|
|
↓ creates
|
|
Property + PropertyMedia
|
|
↓ associated with
|
|
Listing (status: DRAFT → PUBLISHED → SOLD → ARCHIVED)
|
|
↓ receives
|
|
Inquiry (from BUYER/AGENT)
|
|
↓ converts to
|
|
Transaction (buyer-seller exchange)
|
|
↓ followed by
|
|
Review + UsageRecord (analytics)
|
|
```
|
|
|
|
### Payment Flow
|
|
```
|
|
User (Subscription Start)
|
|
↓
|
|
Plan (monthly/yearly pricing)
|
|
↓
|
|
Subscription (active/cancelled/expired)
|
|
↓
|
|
Payment (processed via VNPay)
|
|
├── Idempotency Key (prevents duplicates)
|
|
└── Status Tracking
|
|
↓
|
|
UsageRecord (track consumed resources)
|
|
```
|
|
|
|
---
|
|
|
|
## AUTHENTICATION FLOW
|
|
|
|
### JWT Token Lifecycle
|
|
```
|
|
1. User Login (email + password OR OAuth)
|
|
└→ Verify credentials (bcrypt hash)
|
|
|
|
2. Generate Tokens
|
|
├→ AccessToken (15 min, bearer auth)
|
|
└→ RefreshToken (7 days, stored in DB)
|
|
└→ Token Family (refresh rotation)
|
|
|
|
3. Return to Client
|
|
└→ Set Secure HTTP-Only Cookie (refresh token)
|
|
|
|
4. API Access
|
|
├→ Authorization: Bearer <accessToken>
|
|
├→ Guard validates JWT signature
|
|
└→ Inject user context into request
|
|
|
|
5. Token Refresh
|
|
├→ Client sends refresh token
|
|
├→ Verify token family (revocation check)
|
|
├→ Rotate token (issue new family)
|
|
└→ Return new access token
|
|
```
|
|
|
|
---
|
|
|
|
## DATABASE SCHEMA - KEY INDEXES
|
|
|
|
### Query Optimization Strategy
|
|
```
|
|
User Table:
|
|
├── idx_user_role (BUYER/SELLER/AGENT/ADMIN filtering)
|
|
├── idx_user_kyc_status (compliance checks)
|
|
├── idx_user_active (active user queries)
|
|
├── idx_user_deleted_at (soft delete filtering)
|
|
└── idx_role_active_created (complex queries: role + active + order by)
|
|
|
|
Listing Table:
|
|
├── idx_listing_status (published, archived, sold filtering)
|
|
├── idx_listing_user_created (user's listings ordered)
|
|
└── idx_listing_location_geo (PostGIS spatial queries)
|
|
|
|
Payment Table:
|
|
├── idx_payment_user_status (user's payment history)
|
|
├── idx_payment_idempotency (duplicate prevention)
|
|
└── idx_payment_external_ref (payment gateway reconciliation)
|
|
|
|
Search Optimization:
|
|
└── Typesense (full-text + geo-search, delegated from DB)
|
|
```
|
|
|
|
---
|
|
|
|
## SECURITY LAYERS - DETAILED
|
|
|
|
### Layer 1: Network Level
|
|
```
|
|
HTTP Request
|
|
↓
|
|
Helmet (Express middleware)
|
|
├── Content-Security-Policy
|
|
│ └── Blocks inline scripts, restricts origins
|
|
├── X-Frame-Options: DENY
|
|
│ └── Prevents clickjacking
|
|
├── Strict-Transport-Security (HSTS)
|
|
│ └── Forces HTTPS for 31536000 seconds
|
|
├── X-Content-Type-Options: nosniff
|
|
│ └── Prevents MIME-sniffing
|
|
└── Referrer-Policy: strict-origin-when-cross-origin
|
|
└── Controls referrer leaks
|
|
```
|
|
|
|
### Layer 2: Application Level
|
|
```
|
|
Request Processing
|
|
↓
|
|
1. CORS Validation
|
|
└── Whitelist check (process.env.CORS_ORIGINS)
|
|
|
|
2. CSRF Protection
|
|
├── Read (GET): Set __Host-X-CSRF-Token cookie
|
|
└── Write (POST/PUT/PATCH/DELETE):
|
|
├── Verify X-CSRF-Token header
|
|
└── Validate cookie matches header (double-submit)
|
|
|
|
3. Input Sanitization
|
|
├── Remove XSS vectors (sanitize-html)
|
|
├── Whitelist validation (class-validator)
|
|
└── Type coercion (class-transformer)
|
|
|
|
4. Rate Limiting
|
|
├── Global: 60 req/min per IP
|
|
├── Auth: 10 req/min per IP (login brute-force protection)
|
|
└── Payments: 20 req/min per IP (webhook replay protection)
|
|
```
|
|
|
|
### Layer 3: Data Level
|
|
```
|
|
Field Encryption (PII Protection)
|
|
├── FieldEncryptionService
|
|
│ ├── AES-256-GCM encryption
|
|
│ ├── Field-level (can query by hash)
|
|
│ └── Key derivation from master secret
|
|
├── Email: Encrypted + hashed (both in DB)
|
|
├── Phone: Encrypted + hashed (both in DB)
|
|
└── KYC Data: Encrypted JSON storage
|
|
|
|
Audit Trail
|
|
├── AdminAuditLog captures:
|
|
│ ├── User ID (who)
|
|
│ ├── Action (what)
|
|
│ ├── Target entity (where)
|
|
│ ├── Changes (before/after)
|
|
│ └── Timestamp (when)
|
|
└── Queryable for compliance
|
|
```
|
|
|
|
### Layer 4: Authorization
|
|
```
|
|
Route Handler
|
|
↓
|
|
@UseGuards(JwtGuard, RoleGuard)
|
|
├── Extract JWT from Authorization header
|
|
├── Validate signature (HS256)
|
|
├── Check token expiration
|
|
├── Inject user context (request.user)
|
|
└── Verify role (BUYER/SELLER/AGENT/ADMIN)
|
|
└── Reject if insufficient permissions
|
|
```
|
|
|
|
---
|
|
|
|
## CQRS PATTERN IMPLEMENTATION
|
|
|
|
### Command Pattern (State Changes)
|
|
```
|
|
CreateListingCommand
|
|
├── Input: CreateListingDTO
|
|
├── Handler: CreateListingCommandHandler
|
|
│ ├── Validate inputs
|
|
│ ├── Check user permissions
|
|
│ ├── Create Property entity
|
|
│ ├── Create Listing entity
|
|
│ ├── Emit ListingCreatedEvent
|
|
│ └── Update search index
|
|
└── Output: CreatedListingDTO
|
|
|
|
Flow:
|
|
Controller → Command → CommandHandler → Domain → Event → Repository → Cache invalidate
|
|
```
|
|
|
|
### Query Pattern (Read-only)
|
|
```
|
|
GetListingQuery
|
|
├── Input: ListingId
|
|
├── Handler: GetListingQueryHandler
|
|
│ ├── Check cache (Redis)
|
|
│ ├── If hit: return cached
|
|
│ └── If miss:
|
|
│ ├── Query database
|
|
│ ├── Cache result (TTL-based)
|
|
│ └── Return to client
|
|
└── Output: ListingDTO
|
|
|
|
Flow:
|
|
Controller → Query → QueryHandler → Repository → Cache store → Response
|
|
```
|
|
|
|
---
|
|
|
|
## CACHING STRATEGY
|
|
|
|
### Multi-Level Caching
|
|
```
|
|
Level 1: Browser Cache
|
|
├── Static assets (CSS, JS)
|
|
├── Max-Age: 31536000 (1 year)
|
|
└── Immutable: true
|
|
|
|
Level 2: CDN Cache (if deployed)
|
|
├── JSON responses
|
|
├── Max-Age: 300 (5 min)
|
|
└── Surrogate-Key invalidation
|
|
|
|
Level 3: Application Cache (Redis)
|
|
├── User objects (TTL: 1 hour)
|
|
├── Listing details (TTL: 30 min)
|
|
├── Search results (TTL: 5 min)
|
|
└── Rate limit counters (TTL: per window)
|
|
|
|
Cache Invalidation Triggers:
|
|
├── Event-based: ListingUpdatedEvent → invalidate key
|
|
├── Time-based: TTL expiration
|
|
├── Manual: Cache.delete(key) on batch operations
|
|
└── Circuit breaker: If Redis down, bypass to DB
|
|
```
|
|
|
|
---
|
|
|
|
## ERROR HANDLING & OBSERVABILITY
|
|
|
|
### Exception Hierarchy
|
|
```
|
|
GlobalExceptionFilter (catches all)
|
|
│
|
|
├→ HttpException (known errors)
|
|
│ ├── BadRequestException (400)
|
|
│ ├── UnauthorizedException (401)
|
|
│ ├── ForbiddenException (403)
|
|
│ ├── NotFoundException (404)
|
|
│ ├── ConflictException (409)
|
|
│ └── InternalServerErrorException (500)
|
|
│
|
|
└→ Unknown Error
|
|
└→ Sentry.captureException(error)
|
|
├── Capture stack trace
|
|
├── Attach request context
|
|
├── Tag by module/operation
|
|
└── Alert ops team (if severity > WARN)
|
|
|
|
Structured Logging (Pino)
|
|
├── JSON format for log aggregation
|
|
├── Context injection (request ID, user ID)
|
|
├── Log levels: trace, debug, info, warn, error, fatal
|
|
└── Destination: stdout (collected by Loki/Promtail)
|
|
```
|
|
|
|
### Monitoring Points
|
|
```
|
|
Metrics (Prometheus)
|
|
├── HTTP request latency
|
|
├── Database query time
|
|
├── Cache hit/miss ratio
|
|
├── Error rate by endpoint
|
|
├── Queue depth (background jobs)
|
|
└── Payment processing success rate
|
|
|
|
Logs (Loki)
|
|
├── Searchable by timestamp, level, service, user
|
|
├── Retention: 30 days
|
|
└── Queries: error trends, user activity, audit trail
|
|
|
|
Traces (Sentry)
|
|
├── Request waterfall
|
|
├── Database call chains
|
|
└── Error context snapshot
|
|
```
|
|
|
|
---
|
|
|
|
## BACKGROUND JOBS & EVENTS
|
|
|
|
### Event System
|
|
```
|
|
Domain Event
|
|
├── ListingCreatedEvent
|
|
├── PaymentProcessedEvent
|
|
├── NotificationScheduledEvent
|
|
└── UserDeletedEvent
|
|
↓
|
|
EventEmitter.emit()
|
|
↓
|
|
Event Subscribers (consume in order)
|
|
├── ListingCreatedEventSubscriber
|
|
│ └→ Index in Typesense
|
|
├── PaymentProcessedEventSubscriber
|
|
│ └→ Send email receipt
|
|
├── NotificationScheduledEventSubscriber
|
|
│ └→ Queue FCM push
|
|
└── UserDeletedEventSubscriber
|
|
└→ Archive data + audit trail
|
|
|
|
Error Handling:
|
|
├── Retry policy (3 retries, exponential backoff)
|
|
├── Dead letter queue (failed events)
|
|
└── Monitoring alert (critical events failed)
|
|
```
|
|
|
|
---
|
|
|
|
## FRONTEND STATE MANAGEMENT
|
|
|
|
### Zustand Store Pattern
|
|
```
|
|
// auth-store.ts
|
|
const useAuthStore = create((set) => ({
|
|
user: null,
|
|
tokens: { accessToken: null, refreshToken: null },
|
|
|
|
actions: {
|
|
setUser: (user) => set({ user }),
|
|
setTokens: (tokens) => set({ tokens }),
|
|
logout: () => set({ user: null, tokens: null }),
|
|
}
|
|
}))
|
|
|
|
// Component Usage
|
|
const { user, setUser } = useAuthStore()
|
|
|
|
// Persistence (automatic)
|
|
├── localStorage (client-side)
|
|
├── Hydration on page load
|
|
└── Sync across tabs (storage event)
|
|
```
|
|
|
|
### React Query Integration
|
|
```
|
|
// Hook Pattern
|
|
const useListings = (filters) => {
|
|
return useQuery({
|
|
queryKey: ['listings', filters],
|
|
queryFn: () => listingsApi.search(filters),
|
|
staleTime: 5 * 60 * 1000, // 5 min
|
|
gcTime: 10 * 60 * 1000, // 10 min (old: cacheTime)
|
|
retry: 3,
|
|
retryDelay: exponentialBackoff,
|
|
})
|
|
}
|
|
|
|
// Features
|
|
├── Automatic caching by queryKey
|
|
├── Background refetching
|
|
├── Optimistic updates
|
|
├── Pagination support
|
|
└── Dependency tracking
|
|
```
|
|
|
|
---
|
|
|
|
## DEPLOYMENT ARCHITECTURE
|
|
|
|
### Local Development
|
|
```
|
|
docker-compose.yml
|
|
├── PostgreSQL (5432)
|
|
├── Redis (6379)
|
|
├── Typesense (8108)
|
|
├── MinIO (9000)
|
|
└── PgBouncer (6432 - optional)
|
|
|
|
API Server: http://localhost:3001/api/v1
|
|
Web Server: http://localhost:3000
|
|
Swagger Docs: http://localhost:3001/api/v1/docs
|
|
```
|
|
|
|
### Production Deployment
|
|
```
|
|
Kubernetes Cluster
|
|
├── API Pod (NestJS)
|
|
│ ├── Port: 3001
|
|
│ ├── Resources: 2 CPU, 2GB RAM
|
|
│ ├── Replicas: 3+ (autoscaling)
|
|
│ ├── Probes: liveness + readiness
|
|
│ └── Limits: enforce resource quotas
|
|
├── Web Pod (Next.js)
|
|
│ ├── Port: 3000
|
|
│ ├── Replicas: 2+
|
|
│ └── CDN: CloudFront/Cloudflare
|
|
├── PostgreSQL (managed RDS or Kubernetes StatefulSet)
|
|
├── Redis (managed ElastiCache or Kubernetes)
|
|
└── Typesense (managed or self-hosted cluster)
|
|
|
|
Ingress → Load Balancer → Service → Pods
|
|
```
|
|
|
|
---
|
|
|
|
## CI/CD PIPELINE
|
|
|
|
### Automated Stages
|
|
```
|
|
1. Code Push to master/PR
|
|
└→ GitHub Actions triggered
|
|
|
|
2. Lint Stage (2 min)
|
|
├── ESLint check
|
|
└── Prettier validation
|
|
|
|
3. Type Check Stage (3 min)
|
|
└── TypeScript compilation (no emit)
|
|
|
|
4. Unit Test Stage (5 min)
|
|
├── Backend: Vitest (pnpm test)
|
|
└── Frontend: Vitest + RTL
|
|
|
|
5. Integration Test Stage (8 min)
|
|
├── Test database setup
|
|
└── Vitest integration config
|
|
|
|
6. Build Stage (10 min)
|
|
├── NestJS build (tsc + webpack)
|
|
├── Next.js build (.next folder)
|
|
└── Artifact storage
|
|
|
|
7. E2E Test Stage (15 min) - if CI passes
|
|
├── Service startup (Postgres, Redis, Typesense)
|
|
├── Database migration
|
|
├── Seed data
|
|
├── Playwright tests (Chromium)
|
|
└── Report generation
|
|
|
|
8. Deploy Stage (5 min) - if all pass
|
|
├── Docker image build
|
|
├── Registry push
|
|
└── Kubernetes rollout
|
|
|
|
Total: ~50 min (sequential) or ~15 min (parallel)
|
|
```
|
|
|
|
---
|
|
|
|
## PERFORMANCE TUNING CHECKLIST
|
|
|
|
### Database
|
|
- [ ] Query analysis (EXPLAIN ANALYZE)
|
|
- [ ] Missing indexes (pg_stat_statements)
|
|
- [ ] Connection pooling tuned (PgBouncer)
|
|
- [ ] Replication lag monitored
|
|
- [ ] Backup tested (recovery time < 1 hour)
|
|
|
|
### Application
|
|
- [ ] Memory usage profiled (Node.js heap)
|
|
- [ ] CPU throttling identified
|
|
- [ ] Garbage collection tuned (heap snapshots)
|
|
- [ ] Logging overhead measured
|
|
- [ ] Dependency versions updated
|
|
|
|
### Frontend
|
|
- [ ] Bundle size analyzed (webpack analyzer)
|
|
- [ ] Code splitting implemented (routes)
|
|
- [ ] Images optimized (Next.js Image)
|
|
- [ ] Critical CSS inlined
|
|
- [ ] Web vitals tracked (LCP, FID, CLS)
|
|
|
|
### Infrastructure
|
|
- [ ] Load balancer health checks tuned
|
|
- [ ] Autoscaling policies tested
|
|
- [ ] Cache hit rates > 80%
|
|
- [ ] Network latency acceptable (< 100ms)
|
|
- [ ] Monitoring alert thresholds realistic
|
|
|
|
---
|
|
|
|
## TROUBLESHOOTING GUIDE
|
|
|
|
### "Database Connection Timeout"
|
|
```
|
|
Diagnosis:
|
|
1. Check if PostgreSQL container is running: docker-compose ps
|
|
2. Verify DATABASE_URL in .env
|
|
3. Check PgBouncer if production: psql -h localhost -p 6432 -U pgbouncer
|
|
4. Look for connection limit reached: SELECT count(*) FROM pg_stat_activity
|
|
|
|
Fix:
|
|
├── Restart: docker-compose restart postgres
|
|
├── Increase PgBouncer pool: PGBOUNCER_POOL_SIZE=30
|
|
└── Check slow queries: pg_stat_statements
|
|
```
|
|
|
|
### "Redis Connection Refused"
|
|
```
|
|
Diagnosis:
|
|
1. Check Redis container: docker-compose ps redis
|
|
2. Verify REDIS_URL in .env
|
|
3. Check port: redis-cli -p 6379 ping
|
|
4. Check memory: redis-cli INFO memory
|
|
|
|
Fix:
|
|
├── Restart: docker-compose restart redis
|
|
├── Flush if needed: redis-cli FLUSHALL (dev only!)
|
|
└── Monitor: redis-cli --stat
|
|
```
|
|
|
|
### "Typesense Index Not Found"
|
|
```
|
|
Diagnosis:
|
|
1. Check Typesense container: docker-compose ps typesense
|
|
2. Verify TYPESENSE_API_KEY in .env
|
|
3. List indexes: curl http://localhost:8108/collections -H "X-TYPESENSE-API-KEY: <key>"
|
|
4. Check sync job logs
|
|
|
|
Fix:
|
|
├── Re-seed: pnpm db:seed
|
|
├── Reindex: DELETE /listings index, then rebuild
|
|
└── Monitor: Typesense dashboard http://localhost:8108/dashboard
|
|
```
|
|
|
|
### "Tests Failing with 'Port Already in Use'"
|
|
```
|
|
Diagnosis:
|
|
1. Check running processes: lsof -i :3001 (macOS) or netstat -ano (Windows)
|
|
2. Docker containers: docker ps
|
|
|
|
Fix:
|
|
├── Kill process: kill -9 <PID>
|
|
├── Stop containers: docker-compose down
|
|
├── Update port in .env.test
|
|
└── Ensure cleanup in global-teardown.ts
|
|
```
|
|
|
|
---
|
|
|
|
## SECURITY CHECKLIST - PRE-DEPLOYMENT
|
|
|
|
- [ ] JWT secrets rotated and unique
|
|
- [ ] CORS_ORIGINS finalized (no localhost in prod)
|
|
- [ ] Database credentials strong (> 16 chars, random)
|
|
- [ ] MinIO/AWS S3 credentials secure (IAM policy restricted)
|
|
- [ ] OAuth client secrets masked
|
|
- [ ] SSL certificate installed (HTTPS)
|
|
- [ ] HSTS preload submitted
|
|
- [ ] Security headers tested (securityheaders.com)
|
|
- [ ] OWASP Top 10 reviewed
|
|
- [ ] Penetration test scheduled
|
|
- [ ] Rate limits tuned (no bypass possible)
|
|
- [ ] Audit logging verified
|
|
- [ ] Backup encryption enabled
|
|
- [ ] Incident response plan documented
|
|
- [ ] On-call rotation configured
|
|
|