0

[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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí