Some checks failed
CI / Lint → Typecheck → Test → Build (22) (push) Failing after 29s
CI / E2E Tests (push) Has been skipped
CodeQL Analysis / CodeQL (javascript-typescript) (push) Failing after 2m42s
Deploy / Build Web Image (push) Failing after 27s
Deploy / Build AI Services Image (push) Failing after 29s
E2E Tests / Playwright E2E (push) Failing after 43s
Deploy / Build API Image (push) Failing after 1m31s
Security Scanning / Dependency Audit (pnpm) (push) Failing after 6s
Security Scanning / Trivy Scan — API Image (push) Failing after 5m35s
Security Scanning / Trivy Scan — AI Services Image (push) Failing after 3m45s
Deploy / Deploy to Staging (push) Has been skipped
Deploy / Smoke Test Staging (push) Has been skipped
Deploy / Deploy to Production (push) Has been skipped
Deploy / Smoke Test Production (push) Has been skipped
Deploy / Rollback Staging (push) Has been skipped
Deploy / Rollback Production (push) Has been skipped
Security Scanning / Trivy Scan — Web Image (push) Failing after 13m51s
Security Scanning / Trivy Filesystem Scan (push) Failing after 14m46s
Security Scanning / Security Gate (push) Has been cancelled
18 KiB
18 KiB
GoodGo Platform AI - Tài Liệu Kỹ Thuật Tham Chiếu & Phân Tích Chuyên Sâu
Dành cho Nhà Phát Triển & Kiến Trúc Sư
PHÂN CẤP MODULE BACKEND
Phụ Thuộc Module Cốt Lõi
SharedModule (cấp thấp nhất)
├── 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)
MÔ HÌNH MIỀN - MỐI QUAN HỆ
Phân Cấp Vai Trò Người Dùng
User (thực thể gốc)
├── Role: BUYER → Có thể duyệt, tìm kiếm, hỏi thăm, mua
├── Role: SELLER → Có thể tạo tin đăng, nhận hỏi thăm, bán
├── Role: AGENT → Mở rộng từ Seller + quản lý khách hàng tiềm năng
└── Role: ADMIN → Toàn bộ quyền hạn + kiểm duyệt
Luồng Xử Lý Tin Đăng
User (SELLER)
↓ tạo
Property + PropertyMedia
↓ liên kết với
Listing (trạng thái: DRAFT → PUBLISHED → SOLD → ARCHIVED)
↓ nhận
Inquiry (từ BUYER/AGENT)
↓ chuyển đổi thành
Transaction (giao dịch người mua - người bán)
↓ tiếp theo là
Review + UsageRecord (phân tích)
Luồng Thanh Toán
User (Bắt đầu Đăng ký)
↓
Plan (giá hàng tháng/hàng năm)
↓
Subscription (đang hoạt động/đã hủy/đã hết hạn)
↓
Payment (xử lý qua VNPay)
├── Idempotency Key (ngăn trùng lặp)
└── Status Tracking
↓
UsageRecord (theo dõi tài nguyên đã dùng)
LUỒNG XÁC THỰC
Vòng Đời Token JWT
1. Đăng nhập Người dùng (email + mật khẩu HOẶC OAuth)
└→ Xác minh thông tin đăng nhập (bcrypt hash)
2. Tạo Token
├→ AccessToken (15 phút, bearer auth)
└→ RefreshToken (7 ngày, lưu trong DB)
└→ Token Family (luân phiên refresh)
3. Trả về Client
└→ Đặt Cookie HTTP-Only Bảo mật (refresh token)
4. Truy cập API
├→ Authorization: Bearer <accessToken>
├→ Guard xác thực chữ ký JWT
└→ Đưa ngữ cảnh người dùng vào request
5. Làm mới Token
├→ Client gửi refresh token
├→ Xác minh token family (kiểm tra thu hồi)
├→ Luân phiên token (cấp family mới)
└→ Trả về access token mới
SCHEMA CƠ SỞ DỮ LIỆU - CHỈ MỤC QUAN TRỌNG
Chiến Lược Tối Ưu Hóa Truy Vấn
Bảng User:
├── idx_user_role (lọc BUYER/SELLER/AGENT/ADMIN)
├── idx_user_kyc_status (kiểm tra tuân thủ)
├── idx_user_active (truy vấn người dùng hoạt động)
├── idx_user_deleted_at (lọc xóa mềm)
└── idx_role_active_created (truy vấn phức tạp: vai trò + hoạt động + sắp xếp theo)
Bảng Listing:
├── idx_listing_status (lọc đã đăng, đã lưu trữ, đã bán)
├── idx_listing_user_created (tin đăng của người dùng theo thứ tự)
└── idx_listing_location_geo (truy vấn không gian PostGIS)
Bảng Payment:
├── idx_payment_user_status (lịch sử thanh toán của người dùng)
├── idx_payment_idempotency (ngăn trùng lặp)
└── idx_payment_external_ref (đối soát cổng thanh toán)
Tối Ưu Hóa Tìm Kiếm:
└── Typesense (tìm kiếm toàn văn bản + địa lý, ủy thác từ DB)
CÁC LỚP BẢO MẬT - CHI TIẾT
Lớp 1: Cấp Mạng
HTTP Request
↓
Helmet (Express middleware)
├── Content-Security-Policy
│ └── Chặn script nội tuyến, hạn chế nguồn gốc
├── X-Frame-Options: DENY
│ └── Ngăn chặn clickjacking
├── Strict-Transport-Security (HSTS)
│ └── Bắt buộc HTTPS trong 31536000 giây
├── X-Content-Type-Options: nosniff
│ └── Ngăn chặn MIME-sniffing
└── Referrer-Policy: strict-origin-when-cross-origin
└── Kiểm soát rò rỉ referrer
Lớp 2: Cấp Ứng Dụng
Xử Lý Request
↓
1. Xác Thực CORS
└── Kiểm tra danh sách trắng (process.env.CORS_ORIGINS)
2. Bảo Vệ CSRF
├── Đọc (GET): Đặt cookie __Host-X-CSRF-Token
└── Ghi (POST/PUT/PATCH/DELETE):
├── Xác minh header X-CSRF-Token
└── Xác nhận cookie khớp header (double-submit)
3. Làm Sạch Đầu Vào
├── Loại bỏ vector XSS (sanitize-html)
├── Xác thực danh sách trắng (class-validator)
└── Ép kiểu dữ liệu (class-transformer)
4. Giới Hạn Tốc Độ
├── Toàn cầu: 60 req/phút mỗi IP
├── Xác thực: 10 req/phút mỗi IP (bảo vệ brute-force đăng nhập)
└── Thanh toán: 20 req/phút mỗi IP (bảo vệ phát lại webhook)
Lớp 3: Cấp Dữ Liệu
Mã Hóa Trường (Bảo Vệ PII)
├── FieldEncryptionService
│ ├── Mã hóa AES-256-GCM
│ ├── Cấp trường (có thể truy vấn bằng hash)
│ └── Dẫn xuất khóa từ bí mật chính
├── Email: Đã mã hóa + đã băm (cả hai trong DB)
├── Điện thoại: Đã mã hóa + đã băm (cả hai trong DB)
└── Dữ liệu KYC: Lưu trữ JSON đã mã hóa
Nhật Ký Kiểm Toán
├── AdminAuditLog ghi lại:
│ ├── User ID (ai)
│ ├── Action (gì)
│ ├── Target entity (ở đâu)
│ ├── Changes (trước/sau)
│ └── Timestamp (khi nào)
└── Có thể truy vấn để tuân thủ
Lớp 4: Phân Quyền
Route Handler
↓
@UseGuards(JwtGuard, RoleGuard)
├── Trích xuất JWT từ header Authorization
├── Xác thực chữ ký (HS256)
├── Kiểm tra hạn sử dụng token
├── Đưa ngữ cảnh người dùng vào (request.user)
└── Xác minh vai trò (BUYER/SELLER/AGENT/ADMIN)
└── Từ chối nếu không đủ quyền
TRIỂN KHAI MẪU CQRS
Mẫu Lệnh (Thay Đổi Trạng Thái)
CreateListingCommand
├── Input: CreateListingDTO
├── Handler: CreateListingCommandHandler
│ ├── Xác thực đầu vào
│ ├── Kiểm tra quyền người dùng
│ ├── Tạo thực thể Property
│ ├── Tạo thực thể Listing
│ ├── Phát ListingCreatedEvent
│ └── Cập nhật chỉ mục tìm kiếm
└── Output: CreatedListingDTO
Luồng:
Controller → Command → CommandHandler → Domain → Event → Repository → Cache invalidate
Mẫu Truy Vấn (Chỉ Đọc)
GetListingQuery
├── Input: ListingId
├── Handler: GetListingQueryHandler
│ ├── Kiểm tra cache (Redis)
│ ├── Nếu trúng cache: trả về kết quả đã cache
│ └── Nếu không trúng:
│ ├── Truy vấn cơ sở dữ liệu
│ ├── Cache kết quả (dựa trên TTL)
│ └── Trả về cho client
└── Output: ListingDTO
Luồng:
Controller → Query → QueryHandler → Repository → Cache store → Response
CHIẾN LƯỢC CACHE
Cache Nhiều Cấp
Cấp 1: Cache Trình Duyệt
├── Tài nguyên tĩnh (CSS, JS)
├── Max-Age: 31536000 (1 năm)
└── Immutable: true
Cấp 2: Cache CDN (nếu đã triển khai)
├── Phản hồi JSON
├── Max-Age: 300 (5 phút)
└── Vô hiệu hóa Surrogate-Key
Cấp 3: Cache Ứng Dụng (Redis)
├── Đối tượng User (TTL: 1 giờ)
├── Chi tiết Listing (TTL: 30 phút)
├── Kết quả tìm kiếm (TTL: 5 phút)
└── Bộ đếm giới hạn tốc độ (TTL: theo cửa sổ)
Kích Hoạt Vô Hiệu Hóa Cache:
├── Dựa trên sự kiện: ListingUpdatedEvent → vô hiệu hóa key
├── Dựa trên thời gian: hết hạn TTL
├── Thủ công: Cache.delete(key) trên các thao tác theo lô
└── Circuit breaker: Nếu Redis down, bỏ qua sang DB
XỬ LÝ LỖI & QUAN SÁT HỆ THỐNG
Phân Cấp Ngoại Lệ
GlobalExceptionFilter (bắt tất cả)
│
├→ HttpException (lỗi đã biết)
│ ├── BadRequestException (400)
│ ├── UnauthorizedException (401)
│ ├── ForbiddenException (403)
│ ├── NotFoundException (404)
│ ├── ConflictException (409)
│ └── InternalServerErrorException (500)
│
└→ Lỗi Không Xác Định
└→ Sentry.captureException(error)
├── Ghi lại stack trace
├── Đính kèm ngữ cảnh request
├── Gắn thẻ theo module/thao tác
└── Cảnh báo đội vận hành (nếu mức độ nghiêm trọng > WARN)
Ghi Log Có Cấu Trúc (Pino)
├── Định dạng JSON để tổng hợp log
├── Đưa ngữ cảnh vào (request ID, user ID)
├── Cấp độ log: trace, debug, info, warn, error, fatal
└── Đích: stdout (thu thập bởi Loki/Promtail)
Điểm Giám Sát
Chỉ Số (Prometheus)
├── Độ trễ HTTP request
├── Thời gian truy vấn cơ sở dữ liệu
├── Tỷ lệ trúng/trượt cache
├── Tỷ lệ lỗi theo endpoint
├── Độ sâu hàng đợi (công việc nền)
└── Tỷ lệ thành công xử lý thanh toán
Log (Loki)
├── Có thể tìm kiếm theo timestamp, cấp độ, dịch vụ, người dùng
├── Lưu trữ: 30 ngày
└── Truy vấn: xu hướng lỗi, hoạt động người dùng, nhật ký kiểm toán
Trace (Sentry)
├── Luồng waterfall request
├── Chuỗi gọi cơ sở dữ liệu
└── Snapshot ngữ cảnh lỗi
CÔNG VIỆC NỀN & SỰ KIỆN
Hệ Thống Sự Kiện
Domain Event
├── ListingCreatedEvent
├── PaymentProcessedEvent
├── NotificationScheduledEvent
└── UserDeletedEvent
↓
EventEmitter.emit()
↓
Event Subscribers (xử lý theo thứ tự)
├── ListingCreatedEventSubscriber
│ └→ Lập chỉ mục trong Typesense
├── PaymentProcessedEventSubscriber
│ └→ Gửi email biên lai
├── NotificationScheduledEventSubscriber
│ └→ Xếp hàng FCM push
└── UserDeletedEventSubscriber
└→ Lưu trữ dữ liệu + nhật ký kiểm toán
Xử Lý Lỗi:
├── Chính sách thử lại (3 lần, exponential backoff)
├── Dead letter queue (sự kiện thất bại)
└── Cảnh báo giám sát (sự kiện quan trọng thất bại)
QUẢN LÝ TRẠNG THÁI FRONTEND
Mẫu Zustand Store
// 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 }),
}
}))
// Cách Dùng Trong Component
const { user, setUser } = useAuthStore()
// Lưu Trữ Bền Vững (tự động)
├── localStorage (phía client)
├── Hydration khi tải trang
└── Đồng bộ giữa các tab (storage event)
Tích Hợp React Query
// Mẫu Hook
const useListings = (filters) => {
return useQuery({
queryKey: ['listings', filters],
queryFn: () => listingsApi.search(filters),
staleTime: 5 * 60 * 1000, // 5 phút
gcTime: 10 * 60 * 1000, // 10 phút (cũ: cacheTime)
retry: 3,
retryDelay: exponentialBackoff,
})
}
// Tính Năng
├── Cache tự động theo queryKey
├── Tải lại nền
├── Cập nhật lạc quan
├── Hỗ trợ phân trang
└── Theo dõi phụ thuộc
KIẾN TRÚC TRIỂN KHAI
Phát Triển Cục Bộ
docker-compose.yml
├── PostgreSQL (5432)
├── Redis (6379)
├── Typesense (8108)
├── MinIO (9000)
└── PgBouncer (6432 - tùy chọn)
API Server: http://localhost:3001/api/v1
Web Server: http://localhost:3000
Swagger Docs: http://localhost:3001/api/v1/docs
Triển Khai Sản Xuất
Kubernetes Cluster
├── API Pod (NestJS)
│ ├── Port: 3001
│ ├── Tài nguyên: 2 CPU, 2GB RAM
│ ├── Replicas: 3+ (tự động mở rộng)
│ ├── Probes: liveness + readiness
│ └── Limits: thực thi hạn mức tài nguyên
├── Web Pod (Next.js)
│ ├── Port: 3000
│ ├── Replicas: 2+
│ └── CDN: CloudFront/Cloudflare
├── PostgreSQL (RDS được quản lý hoặc Kubernetes StatefulSet)
├── Redis (ElastiCache được quản lý hoặc Kubernetes)
└── Typesense (được quản lý hoặc cluster tự lưu trữ)
Ingress → Load Balancer → Service → Pods
PIPELINE CI/CD
Các Giai Đoạn Tự Động
1. Đẩy Code lên master/PR
└→ Kích hoạt GitHub Actions
2. Giai Đoạn Lint (2 phút)
├── Kiểm tra ESLint
└── Xác thực Prettier
3. Giai Đoạn Kiểm Tra Kiểu (3 phút)
└── Biên dịch TypeScript (không emit)
4. Giai Đoạn Kiểm Thử Đơn Vị (5 phút)
├── Backend: Vitest (pnpm test)
└── Frontend: Vitest + RTL
5. Giai Đoạn Kiểm Thử Tích Hợp (8 phút)
├── Thiết lập cơ sở dữ liệu kiểm thử
└── Cấu hình tích hợp Vitest
6. Giai Đoạn Build (10 phút)
├── Build NestJS (tsc + webpack)
├── Build Next.js (thư mục .next)
└── Lưu trữ artifact
7. Giai Đoạn Kiểm Thử E2E (15 phút) - nếu CI vượt qua
├── Khởi động dịch vụ (Postgres, Redis, Typesense)
├── Migration cơ sở dữ liệu
├── Dữ liệu seed
├── Kiểm thử Playwright (Chromium)
└── Tạo báo cáo
8. Giai Đoạn Triển Khai (5 phút) - nếu tất cả vượt qua
├── Build Docker image
├── Đẩy lên Registry
└── Triển khai Kubernetes
Tổng cộng: ~50 phút (tuần tự) hoặc ~15 phút (song song)
DANH SÁCH KIỂM TRA TINH CHỈNH HIỆU SUẤT
Cơ Sở Dữ Liệu
- Phân tích truy vấn (EXPLAIN ANALYZE)
- Thiếu chỉ mục (pg_stat_statements)
- Tinh chỉnh connection pooling (PgBouncer)
- Giám sát độ trễ nhân rộng
- Kiểm tra sao lưu (thời gian phục hồi < 1 giờ)
Ứng Dụng
- Lập hồ sơ sử dụng bộ nhớ (Node.js heap)
- Xác định giới hạn CPU
- Tinh chỉnh garbage collection (heap snapshots)
- Đo lường chi phí ghi log
- Cập nhật phiên bản phụ thuộc
Frontend
- Phân tích kích thước bundle (webpack analyzer)
- Triển khai code splitting (routes)
- Tối ưu hóa hình ảnh (Next.js Image)
- Nội tuyến CSS quan trọng
- Theo dõi web vitals (LCP, FID, CLS)
Hạ Tầng
- Tinh chỉnh kiểm tra sức khỏe load balancer
- Kiểm tra chính sách tự động mở rộng
- Tỷ lệ trúng cache > 80%
- Độ trễ mạng chấp nhận được (< 100ms)
- Ngưỡng cảnh báo giám sát thực tế
HƯỚNG DẪN KHẮC PHỤC SỰ CỐ
"Database Connection Timeout"
Chẩn Đoán:
1. Kiểm tra container PostgreSQL có đang chạy: docker-compose ps
2. Xác minh DATABASE_URL trong .env
3. Kiểm tra PgBouncer nếu production: psql -h localhost -p 6432 -U pgbouncer
4. Tìm kiếm giới hạn kết nối đạt: SELECT count(*) FROM pg_stat_activity
Khắc Phục:
├── Khởi động lại: docker-compose restart postgres
├── Tăng pool PgBouncer: PGBOUNCER_POOL_SIZE=30
└── Kiểm tra truy vấn chậm: pg_stat_statements
"Redis Connection Refused"
Chẩn Đoán:
1. Kiểm tra container Redis: docker-compose ps redis
2. Xác minh REDIS_URL trong .env
3. Kiểm tra port: redis-cli -p 6379 ping
4. Kiểm tra bộ nhớ: redis-cli INFO memory
Khắc Phục:
├── Khởi động lại: docker-compose restart redis
├── Xóa nếu cần: redis-cli FLUSHALL (chỉ môi trường dev!)
└── Giám sát: redis-cli --stat
"Typesense Index Not Found"
Chẩn Đoán:
1. Kiểm tra container Typesense: docker-compose ps typesense
2. Xác minh TYPESENSE_API_KEY trong .env
3. Liệt kê chỉ mục: curl http://localhost:8108/collections -H "X-TYPESENSE-API-KEY: <key>"
4. Kiểm tra log công việc đồng bộ
Khắc Phục:
├── Seed lại: pnpm db:seed
├── Lập chỉ mục lại: XÓA chỉ mục /listings, sau đó xây dựng lại
└── Giám sát: Typesense dashboard http://localhost:8108/dashboard
"Tests Failing with 'Port Already in Use'"
Chẩn Đoán:
1. Kiểm tra tiến trình đang chạy: lsof -i :3001 (macOS) hoặc netstat -ano (Windows)
2. Container Docker: docker ps
Khắc Phục:
├── Hủy tiến trình: kill -9 <PID>
├── Dừng container: docker-compose down
├── Cập nhật port trong .env.test
└── Đảm bảo dọn dẹp trong global-teardown.ts
DANH SÁCH KIỂM TRA BẢO MẬT - TRƯỚC KHI TRIỂN KHAI
- Bí mật JWT đã được xoay vòng và duy nhất
- CORS_ORIGINS đã được hoàn thiện (không có localhost trong production)
- Thông tin đăng nhập cơ sở dữ liệu mạnh (> 16 ký tự, ngẫu nhiên)
- Thông tin đăng nhập MinIO/AWS S3 an toàn (chính sách IAM bị hạn chế)
- Bí mật OAuth client đã được che giấu
- Chứng chỉ SSL đã được cài đặt (HTTPS)
- HSTS preload đã được gửi
- Headers bảo mật đã được kiểm tra (securityheaders.com)
- OWASP Top 10 đã được xem xét
- Kiểm tra thâm nhập đã được lên lịch
- Giới hạn tốc độ đã được tinh chỉnh (không thể bỏ qua)
- Ghi log kiểm toán đã được xác minh
- Mã hóa sao lưu đã được bật
- Kế hoạch ứng phó sự cố đã được lập tài liệu
- Lịch trực đã được cấu hình