Tech Stack chính thức
1. Stack bắt buộc cho MVP
| Layer | Công nghệ | Phiên bản | Ghi chú ràng buộc |
|---|---|---|---|
| Database core | PostgreSQL | 15.x | BẮT BUỘC. Không thay thế bằng MySQL/MongoDB. |
| Geospatial | PostGIS | 3.3+ | Extension trong cùng DB. |
| Vector search | pgvector | 0.5+ | Extension. MVP dùng pgvector, không setup riêng vector DB. |
| Cache / Queue | Redis | 7.x | Cache + BullMQ + rate limit + session blacklist. |
| Object storage | MinIO hoặc S3-compatible | — | Lưu ảnh, file pháp lý, raw HTML lớn. |
| Backend API | Java Spring Boot | 3.x (Java 21) | ORM: JPA/Hibernate; migration: Flyway. |
| AI Service | FastAPI (Python) | 3.11+ | REST internal, không expose ra public. |
| Worker | BullMQ (Node) / Celery (Python) | — | Tùy ngôn ngữ worker (data-worker). |
| Search nâng cao | OpenSearch | 2.x | PHASE 2. MVP dùng PostgreSQL FTS. |
| Container | Docker + Docker Compose | — | Production: Kubernetes (sau MVP). |
| CI/CD | GitHub Actions / GitLab CI | — | Pipeline test → build → deploy staging. |
| Observability | OpenTelemetry + Grafana + Loki | — | Trace, metric, log tập trung. |
2. Lý do chọn PostgreSQL làm core
- Hỗ trợ relational + JSONB + geospatial (PostGIS) + vector (pgvector) trong cùng 1 DB → giảm complexity.
- Transaction ACID đầy đủ — bắt buộc cho dữ liệu BĐS (sai 1 record giá có thể gây thiệt hại tỷ đồng).
- Hệ sinh thái migration tool trưởng thành (Flyway, Alembic cho Python).
- Có thể scale read qua replica, scale write qua partition trước khi cần shard.
3. Naming convention bắt buộc
| Đối tượng | Convention | Ví dụ đúng | Ví dụ sai |
|---|---|---|---|
| Bảng DB | snake_case, số nhiều | listings, contact_property_relations | Listing, contactPropertyRelation |
| Cột DB | snake_case | created_at, source_actor_type | createdAt, sourceActorType |
| Khóa chính | id (UUID v4) | id UUID PK DEFAULT gen_random_uuid() | listing_id, ListingID |
| Khóa ngoại | {table_singular}_id | property_id, source_id | propertyFK, propertyRef |
| Index | idx_{table}_{cols} | idx_listings_phone, idx_properties_geo | listings_phone_index |
| Enum type | {table}_{col} | listing_status, property_type | ListingStatusEnum |
| API endpoint | kebab-case, plural noun | /api/v1/listings, /api/v1/market/price-trends | /api/v1/getListing |
| Class Java | PascalCase | ListingService, PropertyController | listing_service |
| Package Java | lowercase, theo module | com.vnexus.listings.service | ListingsService (tên file lẫn case) |
| Class TS (FE) | PascalCase | ListingCard, PropertySearchForm | listing_card |
| File TS (FE) | kebab-case | listing-card.tsx, property-search.ts | ListingCard.tsx |
4. Service boundary & repo layout
Cấu trúc monorepo đề xuất
vnexus/├── backend-api/ (Spring Boot modular monolith)│ └── src/main/java/com/vnexus/│ ├── modules/│ │ ├── auth/ (login, register, JWT, refresh)│ │ ├── users/│ │ ├── organizations/ (sàn, broker agency, RBAC)│ │ ├── listings/ (CRUD listing, search)│ │ ├── properties/ (CRUD property, merge, valuation)│ │ ├── contacts/ (chủ nhà, môi giới đã nhận diện)│ │ ├── leads/ (CRM khách mua/thuê)│ │ ├── market/ (analytics, snapshot, trend)│ │ ├── notifications/ (alert, email, push)│ │ ├── admin/ (kiểm duyệt, data review)│ │ └── aigateway/ (proxy gọi sang ai-service)│ ├── common/│ │ ├── config/ security/ exception/ util/│ ├── persistence/│ │ ├── entity/ repository/ flyway/│ └── jobs/│ ├── scheduler/ queue/ (Redis / BullMQ consumer nếu chạy trong JVM)│├── ai-service/ (FastAPI Python)│ └── app/│ ├── api/│ │ ├── classify.py deduplicate.py valuation.py│ │ ├── embedding.py semantic_search.py│ ├── services/│ ├── models/ (loaded ML models)│ ├── schemas/ (Pydantic request/response)│ └── utils/│├── data-worker/ (Crawl + ingest + normalize)│ └── workers/│ ├── crawlers/ (1 file/source)│ ├── parsers/│ ├── normalizers/│ └── schedulers/│├── infra/│ ├── docker/ k8s/ terraform/│└── docs/ ├── adr/ (Architecture Decision Records) ├── api/ (OpenAPI generated) └── runbooks/