//////////////////////////////////////////////////////
// 🔐 권한 (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]
}
}
https://dbdiagram.io/d/PJT-690d8b7e6735e11170adcb5b
1차 설계
dbml