Skip to content

ERD 설계 #2

@zhy2on

Description

@zhy2on

https://dbdiagram.io/d/PJT-690d8b7e6735e11170adcb5b

1차 설계

Image
dbml
//////////////////////////////////////////////////////
// 🔐 권한 (Role)
//////////////////////////////////////////////////////
Table role {
 id          bigint       [pk, increment] // ✅ ID 추가
 code        varchar(20)  [not null, unique] // 'USER', 'ADMIN'
 name        varchar(50)  [not null]
}

//////////////////////////////////////////////////////
// 👤 유저 상태 (User Status)
//////////////////////////////////////////////////////
Table user_status {
 id          bigint       [pk, increment] // ✅ ID 추가
 code        varchar(20)  [not null, unique] // 'ACTIVE', 'BANNED'
 name        varchar(50)  [not null]
 description varchar(100)
}

Table user {
 id                bigint       [pk, increment]
 
 // ✅ 참조를 code -> id로 변경
 role_id           bigint       [not null, ref: > role.id] 
 status_id         bigint       [not null, ref: > user_status.id]

 email             varchar(100)
 password_hash     varchar(255) [not null]
 nickname          varchar(50)  [not null]
 profile_image_url varchar(255)
 
 created_at        datetime     [not null]
 updated_at        datetime     [not null]

 indexes {
   (email)
 }
}

//////////////////////////////////////////////////////
// 🌏 지역 (Region)
//////////////////////////////////////////////////////
Table region_type {
 id   bigint      [pk, increment]
 code varchar(20) [not null, unique] // 'CITY', 'DISTRICT'
 name varchar(50) [not null]
}

Table region {
 id           bigint       [pk, increment]
 parent_id    bigint       [ref: > region.id]
 
 // ✅ Type도 테이블로 분리하여 ID 참조
 type_id      bigint       [not null, ref: > region_type.id]
 
 name         varchar(100) [not null]
 code         varchar(50)
 slug         varchar(100)
 timezone     varchar(50)
 created_at   datetime     [not null]
 updated_at   datetime     [not null]
}

Table region_boundary {
 region_id        bigint [pk, ref: > region.id]
 boundary_geojson text   [not null]
 created_at       datetime [not null]
}

//////////////////////////////////////////////////////
// 📍 스팟 관련 (Spot)
//////////////////////////////////////////////////////
Table spot_status {
 id   bigint      [pk, increment] // ✅ ID 추가
 code varchar(20) [not null, unique] // 'ACTIVE', 'CLOSED'
 name varchar(50) [not null]
}

Table spot_category {
 id   bigint       [pk, increment]
 name varchar(100) [not null, unique]
}

Table spot {
 id                bigint       [pk, increment]
 region_id         bigint       [not null, ref: > region.id]
 category_id       bigint       [not null, ref: > spot_category.id]
 
 // ✅ 참조를 code -> id로 변경
 status_id         bigint       [not null, ref: > spot_status.id]

 name              varchar(255) [not null]
 lat               double       [not null]
 lon               double       [not null]
 summary           text
 address           text
 phone             varchar(50)
 primary_photo_url text
 source_provider   varchar(50)
 source_place_id   varchar(100)
 created_at        datetime     [not null]

 indexes {
   (lat, lon)
   (source_provider, source_place_id) [unique]
 }
}

Table spot_category_map {
 spot_id     bigint [not null, ref: > spot.id]
 category_id bigint [not null, ref: > spot_category.id]
 created_at  datetime [not null]
 
 indexes { (spot_id, category_id) [pk] }
}

Table spot_photo {
 id         bigint   [pk, increment]
 spot_id    bigint   [not null, ref: > spot.id]
 url        text     [not null]
 is_primary bool     [not null, default: false]
 width      int
 height     int
 created_at datetime [not null]
}

Table spot_hour {
 id          bigint   [pk, increment]
 spot_id     bigint   [not null, ref: > spot.id]
 dow         smallint [not null]
 segment_no  smallint [not null, default: 1]
 is_24h      bool     [not null, default: false]
 open_time   time
 close_time  time
 break_start time
 break_end   time
}

Table spot_hour_exception {
 id         bigint [pk, increment]
 spot_id    bigint [not null, ref: > spot.id]
 date       date   [not null]
 is_closed  bool   [not null, default: false]
 open_time  time
 close_time time
}

//////////////////////////////////////////////////////
// 🏷 태그 (Tag)
//////////////////////////////////////////////////////
Table tag_category {
 id   bigint      [pk, increment]
 code varchar(20) [not null, unique] // 'THEME', 'MOOD'
 name varchar(50) [not null]
}

Table tag {
 id          bigint [pk, increment]
 name        varchar(50) [not null, unique]
 
 // ✅ 카테고리도 ID 참조로 변경
 category_id bigint [ref: > tag_category.id] 
 
 created_at  datetime [not null]
}

Table spot_tag {
 spot_id bigint [not null, ref: > spot.id]
 tag_id  bigint [not null, ref: > tag.id]
 indexes { (spot_id, tag_id) [pk] }
}

Table travel_plan_tag {
 plan_id bigint [not null, ref: > travel_plan.id]
 tag_id  bigint [not null, ref: > tag.id]
 indexes { (plan_id, tag_id) [pk] }
}

//////////////////////////////////////////////////////
// 🗺 여행 계획 (Travel Plan)
//////////////////////////////////////////////////////
Table plan_status {
 id   bigint      [pk, increment] // ✅ ID 추가
 code varchar(20) [not null, unique] // 'PLANNED', 'DONE'
 name varchar(50) [not null]
}

Table travel_plan {
 id            bigint       [pk, increment]
 user_id       bigint       [not null, ref: > user.id]
 
 // ✅ 참조를 code -> id로 변경
 status_id     bigint       [not null, ref: > plan_status.id]

 title         varchar(100) [not null]
 summary       varchar(255)
 planned_date  date
 visited_date  date
 region_code   varchar(50)
 area_name     varchar(100)
 thumbnail_url varchar(255)
 is_public     bool         [not null, default: true]
 is_deleted    bool         [not null, default: false]
 created_at    datetime     [not null]
 updated_at    datetime     [not null]
}

Table travel_plan_item {
 id         bigint   [pk, increment]
 plan_id    bigint   [not null, ref: > travel_plan.id]
 spot_id    bigint   [not null, ref: > spot.id]
 order_no   int      [not null]
 memo       text
 created_at datetime [not null]

 indexes {
   (plan_id, order_no) [unique]
 }
}

//////////////////////////////////////////////////////
// 💬 채팅 (Chat)
//////////////////////////////////////////////////////
Table chat_room_type {
 id   bigint      [pk, increment] // ✅ ID 추가
 code varchar(20) [not null, unique] // 'PLAN', 'DM'
 name varchar(50) [not null]
}

Table chat_room {
 id         bigint       [pk, increment]
 plan_id    bigint       [ref: > travel_plan.id]
 
 // ✅ 참조를 code -> id로 변경
 type_id    bigint       [not null, ref: > chat_room_type.id]
 
 name       varchar(100)
 created_at datetime     [not null]
 updated_at datetime     [not null]
}

Table chat_room_member {
 room_id    bigint   [not null, ref: > chat_room.id]
 user_id    bigint   [not null, ref: > user.id]
 joined_at  datetime [not null]
 is_active  bool     [not null, default: true]

 indexes { (room_id, user_id) [pk] }
}

Table chat_message_type {
 id   bigint      [pk, increment] // ✅ ID 추가
 code varchar(20) [not null, unique] // 'TEXT', 'IMAGE'
 name varchar(50) [not null]
}

Table chat_message {
 id              bigint       [pk, increment]
 room_id         bigint       [not null, ref: > chat_room.id]
 sender_id       bigint       [not null, ref: > user.id]
 
 // ✅ 참조를 code -> id로 변경
 message_type_id bigint       [not null, ref: > chat_message_type.id]
 
 content         text
 file_url        varchar(500)
 created_at      datetime     [not null]
 is_deleted      bool         [not null, default: false]

 indexes {
   (room_id, created_at)
 }
}

//////////////////////////////////////////////////////
// ⭐ 북마크, 저널, 프로필
//////////////////////////////////////////////////////
Table travel_plan_bookmark {
 user_id    bigint   [not null, ref: > user.id]
 plan_id    bigint   [not null, ref: > travel_plan.id]
 created_at datetime [not null]

 indexes {
   (user_id, plan_id) [pk]
 }
}

Table travel_journal_mood {
 id   bigint      [pk, increment]
 code varchar(20) [not null, unique] // 'HAPPY', 'TIRED'
 name varchar(50) [not null]
}

Table travel_journal {
 id           bigint       [pk, increment]
 plan_id      bigint       [not null, ref: > travel_plan.id]
 user_id      bigint       [not null, ref: > user.id]
 visited_date date         [not null]
 title        varchar(120) [not null]
 diary        text
 
 // ✅ 기분(Mood)도 테이블 분리 및 ID 참조
 mood_id      bigint       [ref: > travel_journal_mood.id]
 
 weather_note varchar(50)
 companion    varchar(100)
 rating       tinyint
 total_spent  int
 is_private   bool         [not null, default: false]
 is_deleted   bool         [not null, default: false]
 created_at   datetime     [not null]
 updated_at   datetime     [not null]
}

Table travel_journal_photo {
 id         bigint   [pk, increment]
 journal_id bigint   [not null, ref: > travel_journal.id]
 spot_id    bigint   [ref: > spot.id]
 url        text     [not null]
 taken_at   datetime
 caption    text
 order_no   int
 created_at datetime [not null]
}

Table travel_style {
 id   bigint      [pk, increment]
 code varchar(20) [not null, unique] // 'CAFE_LOVER'
 name varchar(50) [not null]
}

Table user_profile {
 user_id              bigint       [pk, ref: > user.id]
 bio                  varchar(255)
 intro                text
 home_region_id       bigint       [ref: > region.id]
 travel_style_summary text
 
 // ✅ 스타일도 ID 참조
 travel_style_id      bigint       [ref: > travel_style.id]

 profile_banner_url   varchar(255)
 is_profile_public    bool         [not null, default: true]
 created_at           datetime     [not null]
 updated_at           datetime     [not null]
}

Table badge {
 id          bigint       [pk, increment]
 code        varchar(50)  [not null, unique]
 name        varchar(100) [not null]
 description varchar(255)
 icon_url    varchar(255)
 category    varchar(30)
 level       int
 created_at  datetime     [not null]
 updated_at  datetime     [not null]
}

Table user_badge {
 user_id     bigint   [not null, ref: > user.id]
 badge_id    bigint   [not null, ref: > badge.id]
 obtained_at datetime [not null]
 is_pinned   bool     [not null, default: false]

 indexes {
   (user_id, badge_id) [pk]
 }
}

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions