[Series Real Estate] Xây dựng Hệ thống Bất động sản từ A-Z - Phần 1: Thiết kế Cơ sở dữ liệu (Database Design)
Chào các bạn, mình đã quay trở lại!
Sau khi kết thúc series E-commerce, mình nhận ra rằng lĩnh vực PropTech (Property Technology) đang là một mảnh đất cực kỳ màu mỡ. Hôm nay, chúng ta sẽ bắt đầu một hành trình hoàn toàn mới: Xây dựng một "https://www.google.com/search?q=Batdongsan.com.vn" thu nhỏ.
Bài toán bất động sản khó hơn ở chỗ dữ liệu thuộc tính (Properties) cực kỳ đa dạng: hướng nhà, số tầng, pháp lý, vị trí địa lý 3 cấp (Tỉnh - Huyện - Xã). Để hệ thống chạy mượt, chúng ta cần một cái "móng" (Database) thật vững chắc.
1. Sơ đồ thực thể (Schema Overview)
Dựa trên yêu cầu, mình đã cấu trúc lại Database thành các nhóm thực thể chính để các bạn dễ hình dung:
Table users {
id integer [primary key]
email string
fullname string
phone string
emailVerified bool
phoneVerified bool
password string
avatar string
balance bigint
score integer
resetPwdToken string
resetPwdExpiry timestamp
idPricing integer [ref: > pricings.id]
}
Table WishLists {
id integer [primary key]
idPost integer [ref: > posts.id]
idUser integer [ref: < users.id]
content text
idParent integer
}
Table ratings {
id integer [primary key]
idPost integer [ref: < posts.id]
idUser integer [ref: < users.id]
content text
star integer
}
Table Comments {
id integer [primary key]
idPost integer [ref: < posts.id]
idUser integer [ref: < users.id]
content String
idParent integer
}
Table posts {
id integer
idPost string [note: 'kiểu uuid']
title string
address string
province string
district string
ward string
price bigint
avgStar integer
size integer
description text [note: 'kiểu rich text / markdown']
floor integer
bedroom integer
bathroom integer
isFurniture bool
listingType ListingTypes
propertyType PropertyTypes
direction Directions
verified bool
expiredData timestamp
expiredPoost timestamp
status PostStatus
idUser integer [ref: < users.id]
}
Table pricings {
id integer [primary key]
name string
isDisplayImmedialy bool
isShowDescription bool
priority integer
requireScore integer
price integer
expiredDay integer
}
Table tags{
id integer [primary key]
tag string
}
Table Tags_posts {
id integer [primary key]
idPost integer [ref: > posts.id]
idTag integer [ref: > tags.id]
}
Enum ListingTypes {
"Bán"
"Cho thuê"
}
Enum PropertyTypes {
"Căn hộ chung cư"
"Nhà mặt phố"
"Nhà riêng"
"Nhà phố thương mại"
"Biệt thự"
"Đất nền"
"Bán đất"
"Trang trại"
"Khu nghỉ dưỡng"
"Kho"
"Nhà xưởng"
"Khác"
}
Enum Directions {
"Đông - Bắc"
"Tây - Nam"
"Đông - Nam"
"Tây - Bắc"
"Đông"
"Tây"
"Nam"
"Bắc"
}
Enum PostStatus {
"Còn trống"
"Đang đàm phán"
"Đã bàn giao"
}
👤 Nhóm 1: Người dùng & Gói dịch vụ (Users & Pricings)
Đây là nơi quản lý "ví tiền" và cấp độ hiển thị tin đăng của người dùng. Một User sẽ gắn liền với một cấp độ Pricing nhất định.
| Table | Ý nghĩa |
|---|---|
| users | Lưu thông tin cá nhân, số dư (balance), điểm thưởng (score) và cấp độ gói (idPricing). |
| pricings | Định nghĩa các gói thành viên (VIP 1, VIP 2, Tin thường...) với các ưu tiên hiển thị khác nhau. |
🏠 Nhóm 2: Tin đăng & Thuộc tính (Posts & Metadata)
Đây là "trái tim" của hệ thống. Tin đăng chứa mọi thông tin từ tọa độ địa lý đến đặc điểm nhà đất.
| Table | Ý nghĩa |
|---|---|
| posts | Lưu tiêu đề, giá, diện tích, vị trí, số phòng, hướng nhà và trạng thái tin (PostStatus). |
| tags | Các nhãn phân loại nhanh (ví dụ: "Nhà giá rẻ", "Gần trường học"). |
| Tags_posts | Bảng trung gian giải quyết mối quan hệ N-N giữa Tin đăng và Tags. |
💬 Nhóm 3: Tương tác & Phản hồi (Social Features)
Nơi người dùng để lại đánh giá, bình luận hoặc lưu lại những căn nhà ưng ý.
| Table | Ý nghĩa |
|---|---|
| Comments | Bình luận đa cấp (hỗ trợ idParent để reply). |
| ratings | Đánh giá sao (AvgStar) để tăng độ uy tín cho tin đăng. |
| WishLists | Danh sách sản phẩm "thả tim". |
2. Chi tiết các Enums (Dữ liệu chuẩn hóa)
Để tránh việc mỗi người dùng nhập một kiểu (ví dụ: "Căn hộ" vs "Chung cư"), chúng ta sử dụng Enum để ép kiểu dữ liệu ngay từ tầng DB.
ListingTypes: Phân loại mục đích (Bán / Cho thuê).
PropertyTypes: Loại hình bất động sản (từ Căn hộ đến Nhà xưởng).
Directions: 8 hướng chính (Đông, Tây, Nam, Bắc, Đông-Bắc...).
PostStatus: Vòng đời tin đăng (Còn trống, Đang đàm phán, Đã bàn giao).
3. Những lưu ý "sương máu" trong thiết kế này
UUID cho Tin đăng: Trường idPost mình để kiểu String (UUID). Điều này cực kỳ quan trọng để bảo mật URL và tránh việc đối thủ dùng script để "crawl" dữ liệu của bạn bằng cách chạy ID từ 1 đến hết.
Rich Text / Markdown: Trường description trong bảng posts nên được lưu ở dạng Text dài để hỗ trợ định dạng, giúp mô tả căn nhà trở nên sinh động hơn.
Hệ thống Phân cấp Bình luận: Trường idParent trong bảng Comments cho phép chúng ta xây dựng luồng thảo luận kiểu "Thread", rất chuyên nghiệp.
Hệ thống Điểm (Score): Việc gắn requireScore vào bảng pricings giúp bạn tạo ra các cơ chế Game hóa (Gamification), khích lệ người dùng hoạt động tích cực để lên cấp VIP.
Lời kết cho Phần 1
Chúng ta vừa hoàn thành bản vẽ thiết kế cho một hệ thống Bất động sản quy mô. Một Database tốt là bước đệm để chúng ta triển khai code Backend cực kỳ nhàn hạ ở các phần sau.
Hãy để lại bình luận phía dưới nhé! Đừng quên Upvote để tiếp thêm động lực cho mình. Chào mừng bạn đến với thế giới PropTech!
All rights reserved