Backend Wiki - 100-hours-a-week/KTB4-4th-wiki GitHub Wiki

ํ”„๋กœ์ ํŠธ ์ด๋ฆ„ Backend Wiki

Backend Repository


๋ชฉ์ฐจ


๊ฐœ๋ฐœ ์ผ์ •

๊ธฐ๊ฐ„ ์ฃผ์š” ์ž‘์—…
MM/DD ~ ์ž‘์—… ๋‚ด์šฉ ์ž‘์„ฑ

์ปจ๋ฒค์…˜ ๋ฃฐ

1. ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ

์˜ˆ์‹œ

  1. EditorConfig ์„ค์ •
์„ค์ • ํ•ญ๋ชฉ ๊ฐ’ ์„ค๋ช…
charset utf-8
end_of_line lf
indent_style space
insert_final_newline true
trim_trailing_whitespace true
max_line_length 120

2. CheckStyle ์„ค์ •

์˜ˆ์‹œ

ํ•ญ๋ชฉ ๊ทœ์น™
ํด๋ž˜์Šค๋ช…
๋ณ€์ˆ˜๋ช… ๋ฐ ๋ฉ”์„œ๋“œ๋ช…
์ƒ์ˆ˜๋ช…
ํŒจํ‚ค์ง€๋ช…
ํƒญ ์‚ฌ์šฉ
์ค„ ๋ฐ”๊ฟˆ
์ตœ๋Œ€ ๋ผ์ธ ๊ธธ์ด
์ œ์–ด๋ฌธ ๋ธ”๋ก {}
์—ฐ์‚ฐ์ž ๋ฐฐ์น˜
import ์ˆœ์„œ
์ฃผ์„ ์Šคํƒ€์ผ

3. ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ปจ๋ฒค์…˜

์˜ˆ์‹œ


** ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” type: message ํ˜•์‹์„ ๋”ฐ๋ฅด๋ฉฐ, ์•„๋ž˜์˜ ๊ทœ์น™์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. **

์ œ๋ชฉ ๊ทœ์น™

  • ์ œ๋ชฉ์€ ๋‹ค์Œ ๋Œ€์†Œ๋ฌธ์ž ์Šคํƒ€์ผ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค:
    • sentence-case
    • start-case
    • pascal-case
    • upper-case
    • lower-case
  • ์ œ๋ชฉ ๋์— ๋งˆ์นจํ‘œ(.)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ œ๋ชฉ์€ ์ตœ์†Œ 5์ž ์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ „์ฒด ํ—ค๋”๋Š” 72์ž๋ฅผ ์ดˆ๊ณผํ•˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํƒ€์ž… ์„ค๋ช…
build
chore
content
docs
feat
fix
refactor
style
test
deploy

์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ํ˜•์‹

type: ์ œ๋ชฉ (#์ด์Šˆ๋ฒˆํ˜ธ)

๋ณธ๋ฌธ (์„ ํƒ ์‚ฌํ•ญ)

์˜ˆ์‹œ

feat: ๊ธฐ๋Šฅ ์š”์•ฝ (#์ด์Šˆ๋ฒˆํ˜ธ)

๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ์„ค๋ช… ์ถ”๊ฐ€

4. ์ถ”๊ฐ€ ๊ทœ์น™

์˜ˆ์‹œ

  • PR ์ œ๋ชฉ์€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ ๋™์ผํ•œ ํ˜•์‹์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ํ•œ ๋ฒˆ์˜ PR์€ ํ•˜๋‚˜์˜ ๋ชฉ์ ์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ๊ฑฐ์นœ ํ›„ ๋ณ‘ํ•ฉ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ด ์ปจ๋ฒค์…˜์„ ์ค€์ˆ˜ํ•˜์—ฌ ํŒ€์˜ ์ฝ”๋“œ ํ’ˆ์งˆ์„ ์œ ์ง€ํ•˜๊ณ  ์›ํ™œํ•œ ํ˜‘์—…์„ ์ง„ํ–‰ํ•ฉ์‹œ๋‹ค!


ํŠธ๋Ÿฌ๋ธ” ์ŠˆํŒ…


ERD

ERD ์ด๋ฏธ์ง€ ๋˜๋Š” ๋งํฌ ์‚ฝ์ž…

1. users

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์‚ฌ์šฉ์ž
์„ค๋ช… Kakao OAuth 2.0์„ ํ†ตํ•ด ๊ฐ€์ž…ํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„ ์ •๋ณด, ๊ธฐ๋ณธ ํ”„๋กœํ•„ ๋ฐ ์„œ๋น„์Šค ์ด์šฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์™ธ๋ถ€ ์ธ์ฆ ์‹๋ณ„์ž์™€ ์„œ๋น„์Šค ๋‚ด๋ถ€ ์‚ฌ์šฉ์ž ID๋ฅผ ์—ฐ๊ฒฐํ•˜๊ณ , ํ”„๋กœํ•„/์˜จ๋ณด๋”ฉ/๊ณ„์ • ์ƒํƒœ/๋งˆ์ง€๋ง‰ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด ์‚ฌ์šฉ์ž ๊ด€๋ จ ๋ฐ์ดํ„ฐ์˜ ๊ธฐ์ค€ ์—”ํ„ฐํ‹ฐ ์—ญํ• ์„ ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ auth_sessions, push_subscriptions, calendar_connections์™€ 1:N, user_taste_profiles์™€ 1:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
์ถ”์ฒœ/ํด๋ฆญ/ํ”ผ๋“œ๋ฐฑ ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด products์™€ ์—ฐ๊ฒฐ๋œ๋‹ค.
PK id
FK ์—†์Œ

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
external_id BIGINT NULL -
nickname VARCHAR(50) NOT NULL -
profile_image_url VARCHAR(2048) NULL -
gender ENUM('MALE', 'FEMALE') NOT NULL -
birth_date DATE NULL -
is_onboarding_complete BOOLEAN NOT NULL; DEFAULT FALSE -
status VARCHAR(30) NOT NULL; DEFAULT 'ONBOARDING' -
blocked_at DATETIME(6) NULL -
last_login_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์„œ๋น„์Šค ๋‚ด๋ถ€ ์‚ฌ์šฉ์ž ์‹๋ณ„์ž ์‚ฌ์šฉ์ž ์ฆ๊ฐ€์™€ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์˜ ๊ณตํ†ต ์ฐธ์กฐ๋ฅผ ๊ณ ๋ คํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
external_id OAuth ์ œ๊ณต์ž๊ฐ€ ๋ฐœ๊ธ‰ํ•œ ์™ธ๋ถ€ ์‚ฌ์šฉ์ž ์‹๋ณ„์ž ํ˜„์žฌ Kakao ์‹๋ณ„์ž๊ฐ€ ์ˆซ์ž๋ผ๋Š” ์ „์ œ์— ๋”ฐ๋ผ BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ž์ฒด ๋กœ๊ทธ์ธ ์‚ฌ์šฉ์ž๋Š” NULL์ผ ์ˆ˜ ์žˆ๋‹ค.
nickname ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋‹‰๋„ค์ž„ ๊ฐ€๋ณ€ ๊ธธ์ด ๋ฌธ์ž์—ด์ด๋ฉฐ ์„œ๋น„์Šค ์ •์ฑ…์ƒ ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
profile_image_url OAuth ํ”„๋กœํ•„ ์ด๋ฏธ์ง€ URL ๊ธด ์™ธ๋ถ€ URL์„ ์ˆ˜์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ตœ๋Œ€ 2,048์ž๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค.
gender ์‚ฌ์šฉ์ž ์„ฑ๋ณ„ ํ˜„์žฌ ํ—ˆ์šฉ๋˜๋Š” ๊ฐ’์ด ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ DB์—์„œ ์œ ํšจ๊ฐ’์„ ์ œํ•œํ•œ๋‹ค.
birth_date ์ƒ๋…„์›”์ผ ์‹œ๊ฐ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๋‚ ์งœ ๊ฐ’์ด๋ฏ€๋กœ DATE๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
is_onboarding_complete ์˜จ๋ณด๋”ฉ ์™„๋ฃŒ ์—ฌ๋ถ€ ์ฐธยท๊ฑฐ์ง“ ๋‘ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๋ฏ€๋กœ BOOLEAN์„ ์‚ฌ์šฉํ•œ๋‹ค.
status ๊ฐ€์ž… ์ง„ํ–‰, ์ •์ƒ ์ด์šฉ, ์ฐจ๋‹จ ๋“ฑ ์‚ฌ์šฉ์ž ์ƒํƒœ ํ–ฅํ›„ ์ƒํƒœ๊ฐ€ ์ถ”๊ฐ€๋  ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•ด ENUM ๋Œ€์‹  VARCHAR๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ—ˆ์šฉ๊ฐ’์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ •์ฑ…์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.
blocked_at ๊ณ„์ • ์ฐจ๋‹จ ์‹œ๊ฐ ์„œ๋น„์Šค ์‹œ๊ฐ„ ์ •์ฑ…์— ๋งž์ถฐ ๋‚ ์งœ์™€ ์‹œ๊ฐ์„ ํ•จ๊ป˜ ์ €์žฅํ•˜๋ฉฐ, ์ฐจ๋‹จ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ NULL์ด๋‹ค.
last_login_at ๋งˆ์ง€๋ง‰ ๋กœ๊ทธ์ธ ์‹œ๊ฐ ์‚ฌ์šฉ์ž ํ™œ๋™ ๋ฐ ๋ณด์•ˆ ํ™•์ธ์— ํ•„์š”ํ•œ ๋งˆ์ง€๋ง‰ ๋กœ๊ทธ์ธ ์‹œ์ ์„ ์ €์žฅํ•œ๋‹ค.
created_at ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ ์‹œ๊ฐ ์ƒ์„ฑ ์‹œ๊ฐ์„ ์ž๋™ ๊ธฐ๋กํ•˜๊ณ  ๋‹ค๋ฅธ ์‹œ๊ฐ ์ปฌ๋Ÿผ๊ณผ ์ •๋ฐ€๋„๋ฅผ ํ†ต์ผํ•œ๋‹ค.
updated_at ๋ ˆ์ฝ”๋“œ ์ตœ์ข… ์ˆ˜์ • ์‹œ๊ฐ ์‚ฌ์šฉ์ž ์ •๋ณด์˜ ๋งˆ์ง€๋ง‰ ๋ณ€๊ฒฝ ์‹œ์ ์„ ์ €์žฅํ•œ๋‹ค.
deleted_at ์‚ฌ์šฉ์ž ํƒˆํ‡ด ์‹œ๊ฐ ์—ฐ๊ด€ ๋ฐ์ดํ„ฐ์˜ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ํƒˆํ‡ด ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋…ผ๋ฆฌ ์‚ญ์ œ ์‹œ๊ฐ์„ ์ €์žฅํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ˜„์žฌ๋Š” Kakao OAuth 2.0๋งŒ ์ง€์›ํ•˜์ง€๋งŒ ํ–ฅํ›„ ์ž์ฒด ๋กœ๊ทธ์ธ์ด๋‚˜ ๋‹ค๋ฅธ OAuth ๊ณต๊ธ‰์ž๊ฐ€ ์ถ”๊ฐ€๋  ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ์™ธ๋ถ€ ์‹๋ณ„์ž ์ปฌ๋Ÿผ์„ kakao_id๊ฐ€ ์•„๋‹Œ external_id๋กœ ์ •์˜ํ–ˆ๋‹ค. ์ž์ฒด ๊ฐ€์ž… ์‚ฌ์šฉ์ž๋Š” ์™ธ๋ถ€ ์‹๋ณ„์ž๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค. ์™ธ๋ถ€ ์‹๋ณ„์ž์™€ ๋ณ„๋„๋กœ ๋‚ด๋ถ€ PK์ธ id๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ ๊ณต๊ธ‰์ž์˜ ์‹๋ณ„์ž ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋˜๋”๋ผ๋„ ๋‹ค๋ฅธ ์—…๋ฌด ํ…Œ์ด๋ธ”์˜ ์ฐธ์กฐ ๊ด€๊ณ„๊ฐ€ ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋„๋ก ํ–ˆ๋‹ค.

์‚ฌ์šฉ์ž ๊ธฐ๋ณธ ์ •๋ณด๋งŒ users์— ์ €์žฅํ•˜๊ณ  ์ธ์ฆ ์„ธ์…˜, ํ‘ธ์‹œ ๊ตฌ๋…, ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ, ์ทจํ–ฅ ํ”„๋กœํ•„์€ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ–ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ธฐ๋Šฅ๋ณ„ ๋ฐ์ดํ„ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ์™€ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์—ฌ๋Ÿฌ ๋กœ๊ทธ์ธ ๋ฐฉ์‹์„ ๋™์‹œ์— ์ง€์›ํ•˜๊ฒŒ ๋˜๋ฉด provider, provider_user_id, user_id๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ณ„๋„ ์™ธ๋ถ€ ์ธ์ฆ ๊ณ„์ • ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ Kakao์™€ ์ž์ฒด ๊ณ„์ • ๋“ฑ ์—ฌ๋Ÿฌ ์ธ์ฆ ์ˆ˜๋‹จ์„ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ status์™€ is_onboarding_complete๊ฐ€ ๋ชจ๋‘ ์˜จ๋ณด๋”ฉ ์ƒํƒœ์— ๊ด€์—ฌํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ ์ปฌ๋Ÿผ์˜ ์ฑ…์ž„์„ ๋ช…ํ™•ํžˆ ํ•ด์•ผ ํ•œ๋‹ค. ์˜จ๋ณด๋”ฉ ๋‹จ๊ณ„๊ฐ€ ๋ณต์žกํ•ด์ง€๋ฉด ๋ณ„๋„์˜ ์ง„ํ–‰ ์ƒํƒœ ๋˜๋Š” ๋‹จ๊ณ„๋ณ„ ์ด๋ ฅ ํ…Œ์ด๋ธ”๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•ด์™ธ ์‚ฌ์šฉ์ž๋ฅผ ์ง€์›ํ•˜๊ฒŒ ๋˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ DB์˜ ๊ธฐ์ค€ ์‹œ๊ฐ์„ UTC๋กœ ํ†ต์ผํ•˜๊ณ  ํ™”๋ฉด์—์„œ ์‚ฌ์šฉ์ž ์‹œ๊ฐ„๋Œ€๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์„ ๊ฒ€ํ† ํ•œ๋‹ค.


2. auth_sessions

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ๋กœ๊ทธ์ธ ์ธ์ฆ ์„ธ์…˜
์„ค๋ช… JWT ์ธ์ฆ์—์„œ Refresh Token๊ณผ ๊ธฐ๊ธฐ๋ณ„ ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
Access JWT ์›๋ฌธ์€ ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  API ์š”์ฒญ์€ Access JWT์˜ ์„œ๋ช…๊ณผ ๋งŒ๋ฃŒ ์‹œ๊ฐ์„ ์ด์šฉํ•ด ๋ฌด์ƒํƒœ๋กœ ์ธ์ฆํ•˜๊ณ ,
ํ† ํฐ ๊ฐฑ์‹ ยท๋กœ๊ทธ์•„์›ƒยทํšŒ์› ํƒˆํ‡ดยท๋ณด์•ˆ ์กฐ์น˜๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ด ํ…Œ์ด๋ธ”์—์„œ Refresh Token๊ณผ ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ํ™•์ธํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ์—ฌ๋Ÿฌ ๋กœ๊ทธ์ธ ์„ธ์…˜์ด ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋ฅผ ์ฐธ์กฐํ•˜๋ฏ€๋กœ users์™€ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
์‚ฌ์šฉ์ž ํ•œ ๋ช…์ด ์—ฌ๋Ÿฌ ๊ธฐ๊ธฐ์—์„œ ๋…๋ฆฝ์ ์ธ ๋กœ๊ทธ์ธ ์„ธ์…˜์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
PK id
FK user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NOT NULL FK โ†’ users.id
refresh_token_hash BINARY(32) NOT NULL; UNIQUE UK
device_name VARCHAR(100) NULL -
ip_address VARBINARY(16) NULL -
refresh_expires_at DATETIME(6) NOT NULL -
last_used_at DATETIME(6) NULL -
revoked_at DATETIME(6) NULL -
revoke_reason ENUM('LOGOUT', 'WITHDRAWN', 'SECURITY', 'EXPIRED') NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ๊ธฐ๊ธฐ๋ณ„ ๋กœ๊ทธ์ธ ์„ธ์…˜ ์‹๋ณ„์ž ์‚ฌ์šฉ์ž๋ณ„ ๋‹ค์ค‘ ๋กœ๊ทธ์ธ ์„ธ์…˜์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
Refresh JWT์˜ ์„ธ์…˜ ์‹๋ณ„ ํด๋ ˆ์ž„์œผ๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
user_id ์„ธ์…˜ ์†Œ์œ  ์‚ฌ์šฉ์ž ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ์„ธ์…˜์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉ์ž FK๋ฅผ ๋ณ„๋„๋กœ ๋‘”๋‹ค.
refresh_token_hash ํ˜„์žฌ ์œ ํšจํ•œ Refresh Token์˜ SHA-256 ํ•ด์‹œ ํ† ํฐ ์›๋ฌธ์„ ์ €์žฅํ•˜์ง€ ์•Š์œผ๋ฉฐ, 32๋ฐ”์ดํŠธ ํ•ด์‹œ๋ฅผ ๊ณ ์ • ๊ธธ์ด ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ์ €์žฅํ•œ๋‹ค.
device_name ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ๊ธฐ๊ธฐ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์‹œ ์ด๋ฆ„ ๋ธŒ๋ผ์šฐ์ € ๋˜๋Š” ๊ธฐ๊ธฐ ์ด๋ฆ„์˜ ๊ฐ€๋ณ€ ๊ธธ์ด๋ฅผ ์ˆ˜์šฉํ•œ๋‹ค.
ip_address ์„ธ์…˜ ์ƒ์„ฑ ๋˜๋Š” ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ IP ์ฃผ์†Œ IPv4์™€ IPv6๋ฅผ ๋ชจ๋‘ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ์ตœ๋Œ€ 16๋ฐ”์ดํŠธ ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
refresh_expires_at Refresh Token์˜ ์ ˆ๋Œ€ ๋งŒ๋ฃŒ ์‹œ๊ฐ ๋งŒ๋ฃŒ ์—ฌ๋ถ€์™€ ์ •๋ฆฌ ๋Œ€์ƒ ์„ธ์…˜์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ„๋„ ์‹œ๊ฐ์„ ์ €์žฅํ•œ๋‹ค.
last_used_at Refresh Token์ด ๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ฌ์šฉ๋œ ์‹œ๊ฐ ์žฅ๊ธฐ๊ฐ„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์„ธ์…˜ ๋งŒ๋ฃŒ์™€ ์ด์ƒ ์‚ฌ์šฉ ํƒ์ง€์— ํ™œ์šฉํ•œ๋‹ค.
revoked_at ๋กœ๊ทธ์•„์›ƒ ๋˜๋Š” ๋ณด์•ˆ ์กฐ์น˜๋กœ ์„ธ์…˜์ด ํ๊ธฐ๋œ ์‹œ๊ฐ ํ™œ์„ฑ ์„ธ์…˜์€ NULL์ด๋ฉฐ ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ๋” ์ด์ƒ ํ† ํฐ ๊ฐฑ์‹ ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
revoke_reason ์„ธ์…˜ ํ๊ธฐ ์‚ฌ์œ  ํ˜„์žฌ ํ•„์š”ํ•œ ํ๊ธฐ ์‚ฌ์œ ๋ฅผ ์ œํ•œํ•˜์—ฌ ์ผ๊ด€๋œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
Refresh Token ํšŒ์ „์€ ์„ธ์…˜ ํ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ROTATED๋ฅผ ์ œ์™ธํ•œ๋‹ค.
created_at ๋กœ๊ทธ์ธ ์„ธ์…˜ ์ƒ์„ฑ ์‹œ๊ฐ ๋กœ๊ทธ์ธ ๋ฐœ์ƒ ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ์„ธ์…˜ ์ •๋ณด ์ตœ์ข… ์ˆ˜์ • ์‹œ๊ฐ ํ† ํฐ ํšŒ์ „, ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ ์‹œ๊ฐ ๋ฐ ํ๊ธฐ ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ์ ์„ ์ถ”์ ํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

Access JWT๋งŒ ์‚ฌ์šฉํ•œ ์™„์ „ํ•œ ๋ฌด์ƒํƒœ ๊ตฌ์กฐ์—์„œ๋Š” ๋ฐœ๊ธ‰๋œ ํ† ํฐ์„ ๋งŒ๋ฃŒ ์ „์— ๊ฐ•์ œ๋กœ ๋ฌดํšจํ™”ํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ๋ณธ ์„œ๋น„์Šค์—๋Š” ์ต๋ช… ์ฑ„ํŒ… ์‹ ๊ณ ์™€ ํšŒ์› ํƒˆํ‡ด ๊ธฐ๋Šฅ์ด ์žˆ๊ณ , ํƒˆํ‡ด ๋˜๋Š” ๋ณด์•ˆ ์กฐ์น˜ ์‹œ ๋‹ค๋ฅธ ๊ธฐ๊ธฐ์˜ ๋กœ๊ทธ์ธ๋„ ์ข…๋ฃŒํ•ด์•ผ ํ•˜๋ฏ€๋กœ Access JWT๋Š” ๋ฌด์ƒํƒœ๋กœ ๊ฒ€์ฆํ•˜๋˜ Refresh Token๊ณผ ๋กœ๊ทธ์ธ ์ƒํƒœ๋Š” DB์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํ˜ผํ•ฉ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

Refresh Token์€ ์›๋ฌธ ๋Œ€์‹  ํ•ด์‹œ๋ฅผ ์ €์žฅํ•œ๋‹ค. Refresh JWT์—๋Š” ์„ธ์…˜ ์‹๋ณ„์ž์ธ auth_session_id๋ฅผ ํฌํ•จํ•˜๊ณ , ํ† ํฐ ๊ฐฑ์‹  ์‹œ ์„œ๋ช… ๊ฒ€์ฆ ํ›„ ํ•ด๋‹น ์„ธ์…˜์˜ ํ˜„์žฌ ํ•ด์‹œ์™€ ๋น„๊ตํ•œ๋‹ค. ์ •์ƒ ๊ฐฑ์‹  ์‹œ ์ƒˆ Refresh Token์„ ๋ฐœ๊ธ‰ํ•˜๊ณ  refresh_token_hash๋ฅผ ๊ต์ฒดํ•œ๋‹ค. ๋กœ๊ทธ์•„์›ƒ์ด๋‚˜ ํšŒ์› ํƒˆํ‡ด ์‹œ revoked_at์„ ์„ค์ •ํ•˜์—ฌ ์ดํ›„ ๊ฐฑ์‹ ์„ ์ฐจ๋‹จํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

Refresh Token ํšŒ์ „ ์ด๋ ฅ๊ณผ ํƒˆ์ทจ ํ† ํฐ ์žฌ์‚ฌ์šฉ ๋‚ด์—ญ์„ ์žฅ๊ธฐ๊ฐ„ ๊ฐ์‚ฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๊ฐœ๋ณ„ ํ† ํฐ์„ ์ €์žฅํ•˜๋Š” refresh_tokens ํ…Œ์ด๋ธ”์„ ๋ณ„๋„๋กœ ๋‘˜ ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ์ž๋ณ„ ํ™œ์„ฑ ์„ธ์…˜ ์กฐํšŒ๋ฅผ ์œ„ํ•ด (user_id, revoked_at), ๋งŒ๋ฃŒ ์„ธ์…˜ ์ •๋ฆฌ๋ฅผ ์œ„ํ•ด refresh_expires_at ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€ํ† ํ•œ๋‹ค.

๊ธฐ๊ธฐ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์ด ๊ฐ•ํ™”๋˜๋ฉด ์•ˆ์ •์ ์ธ ๊ธฐ๊ธฐ ์‹๋ณ„์„ ์œ„ํ•œ device_id, ํ”Œ๋žซํผ ๊ตฌ๋ถ„์„ ์œ„ํ•œ platform, ๋งˆ์ง€๋ง‰ ์‚ฌ์šฉ IP๋ฅผ ๋ณ„๋„๋กœ ๊ธฐ๋กํ•˜๋Š” last_ip_address ๋“ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. Access JWT๋ฅผ ์ฆ‰์‹œ ๋ฌดํšจํ™”ํ•ด์•ผ ํ•˜๋Š” ์ •์ฑ…์ด ์ƒ๊ธฐ๋ฉด ์งง์€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„๊ณผ ํ•จ๊ป˜ ์„ธ์…˜ ์ƒํƒœ ์กฐํšŒ ๋˜๋Š” jti ์ฐจ๋‹จ ๋ชฉ๋ก์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


3. push_subscriptions

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ํ‘ธ์‹œ ๊ตฌ๋…
์„ค๋ช… PWA์™€ Web Push API๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ๊ฐœ๋ณ„ ๊ธฐ๊ธฐ์— ์•Œ๋ฆผ์„ ๋ฐœ์†กํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ๋… ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์•Œ๋ฆผ ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ์‚ฌ์šฉ์ž์˜ ํ™œ์„ฑ ๊ตฌ๋…์„ ์กฐํšŒํ•ด ๋ชจ๋“  ๋“ฑ๋ก ๊ธฐ๊ธฐ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์†กํ•œ๋‹ค.
ํŽ˜์ด์ง€๊ฐ€ ์—ด๋ ค ์žˆ์œผ๋ฉด React๊ฐ€, ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋˜๋Š” ์ข…๋ฃŒ ์ƒํƒœ์—์„œ๋Š” Service Worker๊ฐ€ ์•Œ๋ฆผ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ์—ฌ๋Ÿฌ ๊ธฐ๊ธฐ ๊ตฌ๋…์ด ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋ฅผ ์ฐธ์กฐํ•˜๋ฏ€๋กœ users์™€ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
PK id
FK user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NOT NULL FK โ†’ users.id
registration_id BIGINT NOT NULL -
status ENUM('ACTIVE', 'REVOKED') NOT NULL; DEFAULT 'ACTIVE' -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ํ‘ธ์‹œ ๊ตฌ๋… ์‹๋ณ„์ž ์‚ฌ์šฉ์ž๋ณ„ ๋‹ค์ค‘ ๊ธฐ๊ธฐ ๊ตฌ๋…์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user_id ๊ตฌ๋… ์†Œ์œ  ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์ž๋ณ„ ํ™œ์„ฑ ๊ตฌ๋…์„ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•œ ์ฐธ์กฐ ํ‚ค๋‹ค.
registration_id ๋ณ„๋„๋กœ ๊ด€๋ฆฌ๋˜๋Š” Web Push ๋“ฑ๋ก ์ •๋ณด์˜ ์‹๋ณ„์ž ์ˆซ์žํ˜• ๋‚ด๋ถ€ ๋“ฑ๋ก ID๋ฅผ ์ฐธ์กฐํ•œ๋‹ค๋Š” ์ „์ œ์˜ ํƒ€์ž…์ด๋‹ค. ์‹ค์ œ ๊ตฌ๋… ๊ฐ์ฒด ์ž์ฒด๋ฅผ ์ €์žฅํ•œ๋‹ค๋ฉด ์•„๋ž˜ ํ™•์žฅ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
status ํ‘ธ์‹œ ๊ตฌ๋…์˜ ํ™œ์„ฑ ๋˜๋Š” ํ๊ธฐ ์ƒํƒœ ํ—ˆ์šฉ ์ƒํƒœ๊ฐ€ ๋ช…ํ™•ํžˆ ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ENUM์œผ๋กœ ๋ฌด๊ฒฐ์„ฑ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
created_at ๊ตฌ๋… ์ƒ์„ฑ ์‹œ๊ฐ ๊ธฐ๊ธฐ ๋“ฑ๋ก ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ๊ตฌ๋… ์ •๋ณด ์ตœ์ข… ์ˆ˜์ • ์‹œ๊ฐ ์ƒํƒœ ๋˜๋Š” ๊ตฌ๋… ์ •๋ณด์˜ ๋ณ€๊ฒฝ ์‹œ์ ์„ ์ €์žฅํ•œ๋‹ค.
deleted_at ๊ตฌ๋… ๋…ผ๋ฆฌ ์‚ญ์ œ ์‹œ๊ฐ ๊ตฌ๋… ์ด๋ ฅ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ๋ฐœ์†ก ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์Šค๋งˆํŠธํฐ, ํƒœ๋ธ”๋ฆฟ, PC ๋“ฑ ์—ฌ๋Ÿฌ ๊ธฐ๊ธฐ์—์„œ ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž์™€ ๊ตฌ๋…์„ 1:N ๊ด€๊ณ„๋กœ ๋ถ„๋ฆฌํ–ˆ๋‹ค. ๋ฐฑ์—”๋“œ๋Š” ACTIVE ์ƒํƒœ์ธ ๊ตฌ๋…๋งŒ ์กฐํšŒํ•˜์—ฌ ๋ฐœ์†กํ•˜๊ณ , ๋งŒ๋ฃŒ๋˜๊ฑฐ๋‚˜ ์‚ฌ์šฉ์ž๊ฐ€ ๊ถŒํ•œ์„ ์ฒ ํšŒํ•œ ๊ตฌ๋…์€ REVOKED๋กœ ์ „ํ™˜ํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

Web Push API์˜ ๊ตฌ๋… ๊ฐ์ฒด๋ฅผ DB์— ์ง์ ‘ ์ €์žฅํ•œ๋‹ค๋ฉด registration_id๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ endpoint, p256dh_key, auth_key, expiration_time, user_agent ๋“ฑ์„ ๋ณ„๋„ ์ปฌ๋Ÿผ ๋˜๋Š” ๊ตฌ๋… ์ƒ์„ธ ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. ๋™์ผ ๊ตฌ๋…์˜ ์ค‘๋ณต ์ €์žฅ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด endpoint ๋˜๋Š” ๋“ฑ๋ก ์ •๋ณด์— ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด์„ ๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

ํ‘ธ์‹œ ๊ณต๊ธ‰์ž๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด provider, platform์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๋ฐ˜๋ณต ๋ฐœ์†ก ์‹คํŒจ ํšŸ์ˆ˜์™€ ๋งˆ์ง€๋ง‰ ์„ฑ๊ณตยท์‹คํŒจ ์‹œ๊ฐ์„ ์ €์žฅํ•˜์—ฌ ์ž๋™ ํ๊ธฐ ์ •์ฑ…์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


4. calendar_connections

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์™ธ๋ถ€ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ
์„ค๋ช… ์‚ฌ์šฉ์ž์˜ ์™ธ๋ถ€ ์บ˜๋ฆฐ๋” ์—ฐ๋™ ์ƒํƒœ์™€ ์—ฐ๊ฒฐยทํ•ด์ œ ์‹œ๊ฐ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์™ธ๋ถ€ ์บ˜๋ฆฐ๋”์—์„œ ์ˆ˜์ง‘๋œ ์ผ์ •์„ ์ด๋ฒคํŠธ์™€ ์•Œ๋ฆผ ๊ธฐ๋Šฅ์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉ์ž๋ณ„ ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ์—ฌ๋Ÿฌ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ์ด ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋ฅผ ์ฐธ์กฐํ•˜๋ฏ€๋กœ users์™€ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
์‚ฌ์šฉ์ž๋Š” ์บ˜๋ฆฐ๋”๋ฅผ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์—ฌ๋Ÿฌ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.
PK id
FK user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NOT NULL FK โ†’ users.id
status ENUM('CONNECTED', 'DISCONNECTED', 'REAUTH_REQUIRED') NOT NULL; DEFAULT 'DISCONNECTED' -
connected_at DATETIME(6) NULL -
disconnected_at DATETIME(6) NULL -
updated_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ ์‹๋ณ„์ž ์‚ฌ์šฉ์ž๋ณ„ ์—ฌ๋Ÿฌ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ์„ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user_id ์บ˜๋ฆฐ๋”๋ฅผ ์—ฐ๊ฒฐํ•œ ์‚ฌ์šฉ์ž ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž์—๊ฒŒ ์—ฌ๋Ÿฌ ์—ฐ๊ฒฐ์„ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด PK๊ฐ€ ์•„๋‹Œ FK๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
status ์—ฐ๊ฒฐ๋จ, ์—ฐ๊ฒฐ ํ•ด์ œ, ์žฌ์ธ์ฆ ํ•„์š” ์ƒํƒœ ํ—ˆ์šฉ ์ƒํƒœ๊ฐ€ ์ •ํ•ด์ ธ ์žˆ์œผ๋ฏ€๋กœ ENUM์œผ๋กœ ์œ ํšจ๊ฐ’์„ ์ œํ•œํ•œ๋‹ค.
connected_at ์™ธ๋ถ€ ์บ˜๋ฆฐ๋”๊ฐ€ ์—ฐ๊ฒฐ๋œ ์‹œ๊ฐ ์—ฐ๊ฒฐ ์ „์ด๊ฑฐ๋‚˜ ์—ฐ๊ฒฐ ์ด๋ ฅ์ด ์—†์œผ๋ฉด NULL์ด๋‹ค.
disconnected_at ์™ธ๋ถ€ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ์ด ํ•ด์ œ๋œ ์‹œ๊ฐ ์—ฐ๊ฒฐ ์ƒํƒœ๋ผ๋ฉด NULL์ด๊ณ  ์—ฐ๊ฒฐ ํ•ด์ œ ์‹œ ์‹œ๊ฐ์„ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ์—ฐ๊ฒฐ ์ •๋ณด ์ตœ์ข… ์ˆ˜์ • ์‹œ๊ฐ ์—ฐ๊ฒฐ ์ƒํƒœ๋‚˜ ์ธ์ฆ ์ƒํƒœ์˜ ๋ณ€๊ฒฝ ์‹œ์ ์„ ๊ด€๋ฆฌํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ˜„์žฌ ๊ธฐํš์€ Kakao ํ†ก์บ˜๋ฆฐ๋” ๋‹จ์ผ ์—ฐ๊ฒฐ์„ ์ค‘์‹ฌ์œผ๋กœ ํ•˜์ง€๋งŒ, ํ–ฅํ›„ Google Calendar ๋“ฑ ์—ฌ๋Ÿฌ ์™ธ๋ถ€ ์บ˜๋ฆฐ๋”์—์„œ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•ด ์‚ฌ์šฉ์ž๋‹น ํ•˜๋‚˜์˜ ํ–‰์œผ๋กœ ์ œํ•œํ•˜์ง€ ์•Š์•˜๋‹ค. user_id ๋Œ€์‹  ๋ณ„๋„ id๋ฅผ PK๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์™€ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ์„ 1:N ๊ตฌ์กฐ๋กœ ํ™•์žฅํ–ˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

๋‹ค์ค‘ ์บ˜๋ฆฐ๋” ์—ฐ๊ฒฐ์„ ์‹ค์ œ๋กœ ๊ตฌ๋ถ„ํ•˜๋ ค๋ฉด provider, external_account_id, calendar_id, created_at ์ปฌ๋Ÿผ์ด ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•˜๋‹ค. ๋™์ผ ์™ธ๋ถ€ ๊ณ„์ •์˜ ์ค‘๋ณต ์—ฐ๊ฒฐ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด (user_id, provider, external_account_id)์— ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

OAuth Access Token์ด๋‚˜ Refresh Token์„ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค๋ฉด ํ˜„์žฌ ์ƒํƒœ ํ…Œ์ด๋ธ”์— ํ‰๋ฌธ์œผ๋กœ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์•”ํ˜ธํ™”๋œ ๋ณ„๋„ ์ธ์ฆ ์ •๋ณด ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค. ๋™๊ธฐํ™” ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด last_synced_at, sync_cursor, sync_error ๋“ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


5. user_taste_profiles

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์‚ฌ์šฉ์ž ์ทจํ–ฅ ํ”„๋กœํ•„
์„ค๋ช… AI ๋Œ€ํ™” ๋ถ„์„ ๊ฒฐ๊ณผ์™€ ์‚ฌ์šฉ์ž๊ฐ€ ์˜จ๋ณด๋”ฉ์—์„œ ์ง์ ‘ ์„ ํƒํ•œ ์ทจํ–ฅยท๊ด€์‹ฌ์‚ฌยท์ œํ•œ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ๊ฐœ์ธ ์ƒํ’ˆ ์ถ”์ฒœ๊ณผ ์„ ๋ฌผ ์ถ”์ฒœ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ์ตœ์‹  ์ทจํ–ฅ ์ •๋ณด๋ฅผ ํ†ตํ•ฉํ•ด ์ œ๊ณตํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ user_id๊ฐ€ PK์ด์ž FK์ด๋ฏ€๋กœ users์™€ 1:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
AI ๋Œ€ํ™” ๋ฐ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐฑ์‹ ๋˜๊ณ  ์ถ”์ฒœ ํ…Œ์ด๋ธ” ์ƒ์„ฑ์— ํ™œ์šฉ๋œ๋‹ค.
PK user_id
FK user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
user_id BIGINT NOT NULL PK, FK โ†’ users.id
recent_tastes JSON NOT NULL -
recent_interests JSON NOT NULL -
ai_summary TEXT NOT NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
selected_tastes JSON NULL; ์ตœ๋Œ€ 5๊ฐœ -
food_restrictions JSON NULL -
unwanted_product JSON NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
user_id ์ทจํ–ฅ ํ”„๋กœํ•„ ์†Œ์œ  ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์ž๋‹น ํ•˜๋‚˜์˜ ์ตœ์‹  ํ”„๋กœํ•„๋งŒ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด PK์™€ FK๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•œ๋‹ค.
recent_tastes AI๊ฐ€ ์ตœ๊ทผ ๋Œ€ํ™”์—์„œ ๋ถ„์„ํ•œ ์ทจํ–ฅ ํ‚ค์›Œ๋“œ์™€ ๊ด€๋ จ ๋ฐ์ดํ„ฐ ๋ถ„์„ ๊ฒฐ๊ณผ์˜ ํ•ญ๋ชฉ ์ˆ˜์™€ ๊ตฌ์กฐ๊ฐ€ ๊ฐ€๋ณ€์ ์ด๋ฏ€๋กœ JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.
recent_interests AI๊ฐ€ ๋ถ„์„ํ•œ ์ตœ๊ทผ ๊ด€์‹ฌ์‚ฌ ๊ด€์‹ฌ์‚ฌ ๋ชฉ๋ก๊ณผ ๋ถ€๊ฐ€ ์ •๋ณด๊ฐ€ ์œ ๋™์ ์ด๋ฏ€๋กœ JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.
ai_summary AI๊ฐ€ ์ƒ์„ฑํ•œ ์‚ฌ์šฉ์ž ์ทจํ–ฅ ์š”์•ฝ ๋ถ„์„ ๊ฒฐ๊ณผ์˜ ๋ฌธ์žฅ ๊ธธ์ด๊ฐ€ ์ผ์ •ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ TEXT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์ทจํ–ฅ ํ”„๋กœํ•„ ์ƒ์„ฑ ์‹œ๊ฐ ์ตœ์ดˆ ์ƒ์„ฑ ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ์ทจํ–ฅ ํ”„๋กœํ•„ ์ตœ์ข… ๊ฐฑ์‹  ์‹œ๊ฐ ์ตœ์‹  AI ๋ถ„์„ ๊ฒฐ๊ณผ๊ฐ€ ๋ฐ˜์˜๋œ ์‹œ์ ์„ ํ™•์ธํ•œ๋‹ค.
selected_tastes ์‚ฌ์šฉ์ž๊ฐ€ ์˜จ๋ณด๋”ฉ์—์„œ ์ง์ ‘ ์„ ํƒํ•œ ์ทจํ–ฅ ํ‚ค์›Œ๋“œ ์„ ํƒ ํ•ญ๋ชฉ์˜ ์กฐํ•ฉ์ด ๊ฐ€๋ณ€์ ์ด๋ฏ€๋กœ JSON์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ตœ๋Œ€ ๊ฐœ์ˆ˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ฒ€์ฆํ•œ๋‹ค.
food_restrictions ์•Œ๋ ˆ๋ฅด๊ธฐ, ์‹๋‹จ ๋“ฑ ์Œ์‹ ๊ด€๋ จ ์ œํ•œ ํ‚ค์›Œ๋“œ ๋ณต์ˆ˜์˜ ๊ฐ€๋ณ€ ํ•ญ๋ชฉ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.
unwanted_product ์‚ฌ์šฉ์ž๊ฐ€ ์ถ”์ฒœ๋ฐ›๊ณ  ์‹ถ์ง€ ์•Š์€ ์ƒํ’ˆ ๋˜๋Š” ์กฐ๊ฑด ์ œ์™ธ ๋Œ€์ƒ์˜ ์ข…๋ฅ˜์™€ ๊ฐœ์ˆ˜๊ฐ€ ๊ฐ€๋ณ€์ ์ด๋ฏ€๋กœ JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

์‚ฌ์šฉ์ž ํ•œ ๋ช…์€ ๊ฐ€์žฅ ์ตœ์‹  ์ƒํƒœ์˜ ์ทจํ–ฅ ํ”„๋กœํ•„ ํ•˜๋‚˜๋ฅผ ๊ฐ€์ง€๋ฏ€๋กœ user_id๋ฅผ PK๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค. ๋ถ„์„ ๊ฒฐ๊ณผ์™€ ์˜จ๋ณด๋”ฉ ์„ ํƒ์ง€๋Š” ๊ตฌ์กฐ์™€ ๊ธธ์ด๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„ JSON์œผ๋กœ ์ €์žฅํ•˜๋ฉฐ, ์„œ์ˆ ํ˜• AI ์š”์•ฝ์€ ๊ฐ€๋ณ€ ๊ธธ์ด๋ฅผ ๊ณ ๋ คํ•ด TEXT๋กœ ์ €์žฅํ•œ๋‹ค.

์ด ๋ฐ์ดํ„ฐ๋Š” ๊ฐœ์ธ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ƒ์„ฑ๋˜๋ฏ€๋กœ ํšŒ์› ํƒˆํ‡ด ์‹œ ๊ด€๋ จ ํ–‰์„ ํ•˜๋“œ ๋”œ๋ฆฌํŠธํ•˜๋Š” ์ •์ฑ…์„ ์ ์šฉํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ ํ…Œ์ด๋ธ”๊ณผ ๋‹ฌ๋ฆฌ deleted_at์„ ๋‘์ง€ ์•Š์•˜๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์ทจํ–ฅ ํ‚ค์›Œ๋“œ๋ณ„ ๊ฒ€์ƒ‰, ํ†ต๊ณ„, ๊ฐ€์ค‘์น˜ ๊ณ„์‚ฐ์ด ์ค‘์š”ํ•ด์ง€๋ฉด JSON ๋ฐ์ดํ„ฐ๋ฅผ ์ทจํ–ฅ ์ฝ”๋“œ ๋ฐ ์‚ฌ์šฉ์ž-์ทจํ–ฅ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ์ •๊ทœํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. JSON ๊ตฌ์กฐ ๋ณ€๊ฒฝ์— ๋Œ€๋น„ํ•ด schema_version ๋˜๋Š” ๋ถ„์„ ๋ชจ๋ธ ๋ฒ„์ „์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ทจํ–ฅ ๋ณ€ํ™” ์ด๋ ฅ์ด ํ•„์š”ํ•˜๋ฉด ํ˜„์žฌ ํ…Œ์ด๋ธ”์€ ์ตœ์‹  ์ƒํƒœ๋งŒ ์œ ์ง€ํ•˜๊ณ , ๋ณ„๋„์˜ ํ”„๋กœํ•„ ์Šค๋ƒ…์ƒท ๋˜๋Š” ๋ถ„์„ ์ด๋ ฅ ํ…Œ์ด๋ธ”์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ์Œ์‹ ์ œํ•œ ์ •๋ณด๋Š” ๋ฏผ๊ฐ ์ •๋ณด๊ฐ€ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ ‘๊ทผ ๊ถŒํ•œ, ์•”ํ˜ธํ™” ๋ฐ ๋ณด์กด ๊ธฐ๊ฐ„ ์ •์ฑ…์„ ๋ณ„๋„๋กœ ์ •์˜ํ•œ๋‹ค.


6. products

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ƒํ’ˆ
์„ค๋ช… ํฌ๋กค๋ง ๋˜๋Š” ์™ธ๋ถ€ API๋ฅผ ํ†ตํ•ด ์ˆ˜์ง‘ํ•œ ์ถ”์ฒœ ๋Œ€์ƒ ์ƒํ’ˆ์˜ ๊ธฐ๋ณธ ์ •๋ณด, ๊ฐ€๊ฒฉ, ํŒ๋งค์ฒ˜ ๋ฐ ๊ตฌ๋งค ๋งํฌ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ๊ฐœ์ธ ์ถ”์ฒœ, ์„ ๋ฌผ ์ถ”์ฒœ, ํด๋ฆญ, ํ”ผ๋“œ๋ฐฑ ๋ฐ ์ต๋ช… ์งˆ๋ฌธ ๊ธฐ๋Šฅ์—์„œ ๊ณตํ†ต์œผ๋กœ ์ฐธ์กฐํ•˜๋Š” ์ƒํ’ˆ ๊ธฐ์ค€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ personal_recommendations, gift_recommendations, product_clicks,
product_feedbacks, anonymous_rooms์™€ 1:N ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
PK id
FK ์—†์Œ

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
external_id VARCHAR(255) NULL -
name VARCHAR(300) NOT NULL -
category VARCHAR(100) NULL -
description TEXT NULL -
price DECIMAL(12, 2) NULL -
image_url VARCHAR(2048) NULL -
seller_name VARCHAR(200) NULL -
purchase_url VARCHAR(2048) NULL -
status ENUM('ACTIVE', 'SOLD_OUT', 'UNAVAILABLE') NOT NULL; DEFAULT 'ACTIVE' -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์„œ๋น„์Šค ๋‚ด๋ถ€ ์ƒํ’ˆ ์‹๋ณ„์ž ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ ์ถœ์ฒ˜์™€ ๋…๋ฆฝ๋œ ์ฐธ์กฐ ๊ธฐ์ค€์„ ์ œ๊ณตํ•˜๊ณ  ์ƒํ’ˆ ์ฆ๊ฐ€๋ฅผ ์ˆ˜์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
external_id ์™ธ๋ถ€ API๊ฐ€ ์ œ๊ณตํ•œ ์ƒํ’ˆ ์‹๋ณ„์ž ๊ณต๊ธ‰์ž๋ณ„ ์‹๋ณ„์ž ํ˜•์‹์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์–ด ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•œ๋‹ค. ํฌ๋กค๋ง ์ƒํ’ˆ์€ ์™ธ๋ถ€ ID๊ฐ€ ์—†์–ด NULL์ผ ์ˆ˜ ์žˆ๋‹ค.
name ์ƒํ’ˆ๋ช… ๋น„๊ต์  ๊ธด ์™ธ๋ถ€ ์ƒํ’ˆ๋ช…์„ ์ˆ˜์šฉํ•˜๋„๋ก ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ์„ค์ •ํ•œ๋‹ค.
category ์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ ์™ธ๋ถ€ ์ˆ˜์ง‘ ๋ฐ์ดํ„ฐ์˜ ๊ฐ€๋ณ€์ ์ธ ์นดํ…Œ๊ณ ๋ฆฌ ๊ฐ’์„ ์ˆ˜์šฉํ•œ๋‹ค.
description ์ƒํ’ˆ ์ƒ์„ธ ์„ค๋ช… ์„ค๋ช… ๊ธธ์ด๊ฐ€ ์ผ์ •ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ TEXT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
price ์ƒํ’ˆ ํŒ๋งค ๊ฐ€๊ฒฉ ๋ถ€๋™์†Œ์ˆ˜์  ์˜ค์ฐจ ์—†์ด ๊ธˆ์•ก์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด DECIMAL์„ ์‚ฌ์šฉํ•œ๋‹ค.
image_url ์ƒํ’ˆ ์ด๋ฏธ์ง€ URL ๊ธด ์™ธ๋ถ€ URL์„ ์ˆ˜์šฉํ•œ๋‹ค.
seller_name ํŒ๋งค์ฒ˜ ๋˜๋Š” ํŒ๋งค์ž ์ด๋ฆ„ ํŒ๋งค์ฒ˜๋ช…์˜ ๊ฐ€๋ณ€ ๊ธธ์ด๋ฅผ ์ˆ˜์šฉํ•œ๋‹ค.
purchase_url ์ƒํ’ˆ ๊ตฌ๋งค ํŽ˜์ด์ง€ URL ์™ธ๋ถ€ ๊ตฌ๋งค ๋งํฌ์˜ ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ๊ณ ๋ คํ•œ๋‹ค.
status ํŒ๋งค ๊ฐ€๋Šฅ, ํ’ˆ์ ˆ, ๊ตฌ๋งค ํŽ˜์ด์ง€ ์ด์šฉ ๋ถˆ๊ฐ€ ์ƒํƒœ ์ƒํƒœ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๊ณ  ๊ฐ’์˜ ๋ฌด๊ฒฐ์„ฑ์ด ์ค‘์š”ํ•˜๋ฏ€๋กœ ENUM์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์ƒํ’ˆ ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ ์‹œ๊ฐ ์ƒํ’ˆ์ด ์ตœ์ดˆ ์ˆ˜์ง‘๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ์ƒํ’ˆ ์ •๋ณด ์ตœ์ข… ๊ฐฑ์‹  ์‹œ๊ฐ ์žฌ๊ณ , ๊ฐ€๊ฒฉ, URL ๋“ฑ ์™ธ๋ถ€ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ฐฑ์‹ ๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
deleted_at ์ƒํ’ˆ ๋…ผ๋ฆฌ ์‚ญ์ œ ์‹œ๊ฐ ๊ณผ๊ฑฐ ์ถ”์ฒœยทํด๋ฆญยทํ”ผ๋“œ๋ฐฑ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์‹ ๊ทœ ๋…ธ์ถœ์—์„œ ์ œ์™ธํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋Š” API ๋˜๋Š” ํฌ๋กค๋ง์œผ๋กœ ์ˆ˜์ง‘๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์™ธ๋ถ€ ์‹๋ณ„์ž๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค. ๋‚ด๋ถ€ PK์ธ id๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์™ธ๋ถ€ ๊ณต๊ธ‰์ฒ˜์˜ ID ๋ณ€๊ฒฝ์ด๋‚˜ ์ˆ˜์ง‘ ๋ฐฉ์‹ ๋ณ€๊ฒฝ์ด ์ถ”์ฒœยทํด๋ฆญยทํ”ผ๋“œ๋ฐฑ ๊ด€๊ณ„์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋„๋ก ํ–ˆ๋‹ค.

์ƒํ’ˆ ์ƒํƒœ๋Š” ๊ตฌ๋งค URL ์ ‘๊ทผ ๊ฐ€๋Šฅ ์—ฌ๋ถ€์™€ ์žฌ๊ณ  ์ƒํƒœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ACTIVE, SOLD_OUT, UNAVAILABLE๋กœ ์ œํ•œํ–ˆ๋‹ค. ํ˜„์žฌ ์ƒํƒœ ์ข…๋ฅ˜์˜ ๋ณ€๋™ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ DB์—์„œ ENUM์œผ๋กœ ๋ฌด๊ฒฐ์„ฑ์„ ๊ด€๋ฆฌํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์—ฌ๋Ÿฌ API ๋˜๋Š” ์‡ผํ•‘๋ชฐ์—์„œ ๊ฐ™์€ ์™ธ๋ถ€ ID๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ source_type ๋˜๋Š” provider_id๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  (provider_id, external_id)์— ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. external_id IS NULL๋งŒ์œผ๋กœ ํฌ๋กค๋ง ์ƒํ’ˆ์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ๋ณด๋‹ค ๋ฐ์ดํ„ฐ ์ถœ์ฒ˜๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ €์žฅํ•˜๋Š” ํŽธ์ด ํ™•์žฅ์— ์œ ๋ฆฌํ•˜๋‹ค.

๋‹ค์ค‘ ํ†ตํ™”๋ฅผ ์ง€์›ํ•˜๋ฉด currency_code๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ฐ€๊ฒฉ ๋ณ€๋™ ๋ถ„์„์ด ํ•„์š”ํ•˜๋ฉด ๋ณ„๋„ ๊ฐ€๊ฒฉ ์ด๋ ฅ ํ…Œ์ด๋ธ”์„ ๋‘”๋‹ค. ์นดํ…Œ๊ณ ๋ฆฌ ๊ณ„์ธต, ๋‹ค์ค‘ ์ด๋ฏธ์ง€, ์—ฌ๋Ÿฌ ํŒ๋งค์ฒ˜๋ฅผ ์ง€์›ํ•˜๊ฒŒ ๋˜๋ฉด ๊ฐ๊ฐ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ์ •๊ทœํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.


7. personal_recommendations

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ๊ฐœ์ธ ์ƒํ’ˆ ์ถ”์ฒœ
์„ค๋ช… AI ๋Œ€ํ™”๋ฅผ ํ†ตํ•ด ๋ถ„์„ํ•œ ์‚ฌ์šฉ์ž์˜ ํ˜„์žฌ ํ•„์š”์— ์ ํ•ฉํ•œ ์ƒํ’ˆ ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์„ ๋ฌผ๋ณด๋‹ค๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ๊ตฌ๋งคํ•ด ์‚ฌ์šฉํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์ƒํ’ˆ์˜ ์ ์ˆ˜์™€ ์ถ”์ฒœ ์‚ฌ์œ ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users์™€ products ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ๊ฐ๊ฐ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ์˜ N:M ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.
PK (user_id, product_id)
FK user_id โ†’ users.id, product_id โ†’ products.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
user_id BIGINT NOT NULL PK(1), FK โ†’ users.id
product_id BIGINT NOT NULL PK(2), FK โ†’ products.id
score DECIMAL(8, 6) NOT NULL -
reason VARCHAR(500) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
user_id ์ถ”์ฒœ์„ ๋ฐ›๋Š” ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์ž ์ค‘์‹ฌ ์กฐํšŒ์™€ ์ค‘๋ณต ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋ณตํ•ฉ PK์˜ ์ฒซ ๋ฒˆ์งธ ์ปฌ๋Ÿผ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
product_id ์ถ”์ฒœ๋œ ์ƒํ’ˆ ๋™์ผ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฐ™์€ ์ƒํ’ˆ์ด ์ค‘๋ณต ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก ๋ณตํ•ฉ PK์— ํฌํ•จํ•œ๋‹ค.
score ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ ๊ฐ„ ์ถ”์ฒœ ์ ํ•ฉ๋„ ์ ์ˆ˜ ์ •๋ ฌ ๊ฒฐ๊ณผ์˜ ์ •๋ฐ€๋„์™€ ์žฌํ˜„์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ์ •์†Œ์ˆ˜์ ์„ ์‚ฌ์šฉํ•œ๋‹ค.
reason ์ƒํ’ˆ ์ถ”์ฒœ ์‚ฌ์œ  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœํ•˜๊ฑฐ๋‚˜ ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฅผ ํ•ด์„ํ•˜๋Š” ์งง์€ ์„ค๋ช…์„ ์ €์žฅํ•œ๋‹ค.
created_at ์ถ”์ฒœ ๊ฒฐ๊ณผ ์ƒ์„ฑ ์‹œ๊ฐ ์ถ”์ฒœ์ด ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ์ถ”์ฒœ ๊ฒฐ๊ณผ ์ตœ์ข… ๊ฐฑ์‹  ์‹œ๊ฐ ์ ์ˆ˜ ๋˜๋Š” ์ถ”์ฒœ ์‚ฌ์œ ๊ฐ€ ๊ฐฑ์‹ ๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

๋™์ผํ•œ ์ƒํ’ˆ์ด ๊ฐœ์ธ ์ถ”์ฒœ๊ณผ ์„ ๋ฌผ ์ถ”์ฒœ์— ๋ชจ๋‘ ํฌํ•จ๋  ์ˆ˜ ์žˆ์ง€๋งŒ ์ถ”์ฒœ ๋ชฉ์ ๊ณผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋Š” ์„ค๋ช…์ด ๋‹ค๋ฅด๋ฏ€๋กœ ๋‘ ํ…Œ์ด๋ธ”์„ ๋ถ„๋ฆฌํ–ˆ๋‹ค. user_id์™€ product_id๋ฅผ ๋ณตํ•ฉ PK๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผ ์‚ฌ์šฉ์ž-์ƒํ’ˆ ์กฐํ•ฉ์˜ ์ค‘๋ณต์„ ๋ฐฉ์ง€ํ•˜๊ณ , ์‚ฌ์šฉ์ž๋ณ„ ์ถ”์ฒœ ๋ชฉ๋ก์„ ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ํŒจํ„ด์— ๋งž์ท„๋‹ค.

๋Œ€๋ฆฌํ‚ค์™€ ๋ณตํ•ฉ UK ์กฐํ•ฉ๋ณด๋‹ค JPA ๋ณตํ•ฉํ‚ค ๊ตฌํ˜„์ด ๋ณต์žกํ•ด์ง€๋Š” ๋‹จ์ ์ด ์žˆ์ง€๋งŒ, ์ถ”์ฒœ ๊ฒฐ๊ณผ๋Š” ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ ์กฐํ•ฉ ์ž์ฒด๊ฐ€ ์‹๋ณ„์ž์ด๋ฉฐ ์ฝ๊ธฐ ์ค‘์‹ฌ ๋ฐ์ดํ„ฐ๋ผ๋Š” ์ ์„ ๊ณ ๋ คํ•ด ๋ณตํ•ฉ PK๋ฅผ ์„ ํƒํ–ˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ˜„์žฌ ๊ตฌ์กฐ๋Š” ์‚ฌ์šฉ์ž๋ณ„ ์ตœ์‹  ์ถ”์ฒœ ๊ฒฐ๊ณผ์— ์ ํ•ฉํ•˜๋‹ค. ์ถ”์ฒœ ์ด๋ ฅ, ๋ชจ๋ธ ๋น„๊ต, A/B ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•ด์ง€๋ฉด recommendation_batch_id, model_version, generated_at, expires_at์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ถ”์ฒœ ์‹คํ–‰ ๋‹จ์œ„ ํ…Œ์ด๋ธ”์„ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ์ž๋ณ„ ์ƒ์œ„ ์ถ”์ฒœ์„ ๋น ๋ฅด๊ฒŒ ์กฐํšŒํ•˜๋ ค๋ฉด (user_id, score) ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€ํ† ํ•˜๊ณ , ์ ์ˆ˜ ๋ฒ”์œ„๊ฐ€ ์ •ํ•ด์ ธ ์žˆ๋‹ค๋ฉด CHECK ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•œ๋‹ค.


8. gift_recommendations

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์„ ๋ฌผ ์ƒํ’ˆ ์ถ”์ฒœ
์„ค๋ช… ์‚ฌ์šฉ์ž์˜ ์ทจํ–ฅ์„ ๋ฐ”ํƒ•์œผ๋กœ ํ•ด๋‹น ์‚ฌ์šฉ์ž๊ฐ€ ์„ ๋ฌผ๋กœ ๋ฐ›๊ณ  ์‹ถ์–ด ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์ƒํ’ˆ ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์นœ๊ตฌ๊ฐ€ ์„ ๋ฌผ์„ ์„ ํƒํ•  ๋•Œ ์ถ”์ฒœ ์ ์ˆ˜, ์ถ”์ฒœ ์‚ฌ์œ  ๋ฐ ์ทจํ–ฅ ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users์™€ products ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ๊ฐ๊ฐ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ์˜ N:M ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.
PK (user_id, product_id)
FK user_id โ†’ users.id, product_id โ†’ products.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
user_id BIGINT NOT NULL PK(1), FK โ†’ users.id
product_id BIGINT NOT NULL PK(2), FK โ†’ products.id
score DECIMAL(8, 6) NOT NULL -
reason VARCHAR(500) NULL -
taste_keywords JSON NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
user_id ์„ ๋ฌผ ์ถ”์ฒœ์˜ ๋Œ€์ƒ ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์ž๋ณ„ ์„ ๋ฌผ ์ถ”์ฒœ ์กฐํšŒ์™€ ์ค‘๋ณต ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ๋ณตํ•ฉ PK์˜ ์ฒซ ๋ฒˆ์งธ ์ปฌ๋Ÿผ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.
product_id ์„ ๋ฌผ๋กœ ์ถ”์ฒœ๋œ ์ƒํ’ˆ ๋™์ผ ๋Œ€์ƒ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ฐ™์€ ์ƒํ’ˆ์ด ์ค‘๋ณต ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก ๋ณตํ•ฉ PK์— ํฌํ•จํ•œ๋‹ค.
score ์ทจํ–ฅ๊ณผ ์ƒํ’ˆ ๊ฐ„ ์„ ๋ฌผ ์ ํ•ฉ๋„ ์ ์ˆ˜ ์ •๋ฐ€ํ•œ ์ถ”์ฒœ ์ˆœ์œ„๋ฅผ ์žฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ์ •์†Œ์ˆ˜์ ์„ ์‚ฌ์šฉํ•œ๋‹ค.
reason ํ•ด๋‹น ์ƒํ’ˆ์„ ์„ ๋ฌผ๋กœ ์ถ”์ฒœํ•œ ์‚ฌ์œ  ์ถ”์ฒœ ๊ฒฐ๊ณผ์˜ ์„ค๋ช… ๊ฐ€๋Šฅ์„ฑ์„ ์œ„ํ•ด ์งง์€ ์„œ์ˆ ํ˜• ๋‚ด์šฉ์„ ์ €์žฅํ•œ๋‹ค.
taste_keywords ์ถ”์ฒœ์— ํ™œ์šฉ๋œ ์‚ฌ์šฉ์ž ์ทจํ–ฅ ํ‚ค์›Œ๋“œ ํ‚ค์›Œ๋“œ ๊ฐœ์ˆ˜์™€ ๊ตฌ์กฐ๊ฐ€ ๊ฐ€๋ณ€์ ์ด๋ฏ€๋กœ JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์ถ”์ฒœ ๊ฒฐ๊ณผ ์ƒ์„ฑ ์‹œ๊ฐ ์ถ”์ฒœ์ด ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ์ถ”์ฒœ ๊ฒฐ๊ณผ ์ตœ์ข… ๊ฐฑ์‹  ์‹œ๊ฐ ์ ์ˆ˜, ์‚ฌ์œ  ๋˜๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ๊ฐฑ์‹ ๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

๊ฐœ์ธ ์ถ”์ฒœ์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ํ•„์š”๋กœ ํ•  ์ƒํ’ˆ์„, ์„ ๋ฌผ ์ถ”์ฒœ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ์„ ๋ฌผํ•˜๊ธฐ ์ ํ•ฉํ•œ ์ƒํ’ˆ์„ ํ‘œํ˜„ํ•œ๋‹ค. ๋‘ ๋ฒ”์ฃผ์˜ ๊ฒฝ๊ณ„๊ฐ€ ์™„์ „ํžˆ ๋ฐฐํƒ€์ ์ด์ง€ ์•Š์•„ ๊ฐ™์€ ์ƒํ’ˆ์ด ์–‘์ชฝ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ถ”์ฒœ ๋ชฉ์ ๊ณผ ๋…ธ์ถœ ๋งฅ๋ฝ์ด ๋‹ค๋ฅด๋ฏ€๋กœ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

user_id์™€ product_id๋ฅผ ๋ณตํ•ฉ PK๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผ ๋Œ€์ƒ ์‚ฌ์šฉ์ž-์ƒํ’ˆ ์กฐํ•ฉ์˜ ์ค‘๋ณต์„ ๋ฐฉ์ง€ํ•˜๊ณ , ์‚ฌ์šฉ์ž๋ณ„ ์ถ”์ฒœ ๋ชฉ๋ก ์กฐํšŒ์— ๋งž๋Š” ํ‚ค ์ˆœ์„œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. taste_keywords๋ฅผ ํ•จ๊ป˜ ์ €์žฅํ•˜์—ฌ ์ถ”์ฒœ ๊ทผ๊ฑฐ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์„ค๋ช…ํ•˜๊ฑฐ๋‚˜ ๊ฒฐ๊ณผ๋ฅผ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์ƒ์ผ, ๊ธฐ๋…์ผ ๋“ฑ ์ถ”์ฒœ ์ƒํ™ฉ์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง€๋ฉด event_id ๋˜๋Š” recommendation_context๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ถ”์ฒœ ์š”์ฒญ์ž์— ๋”ฐ๋ผ์„œ๋„ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง„๋‹ค๋ฉด requester_user_id์™€ recipient_user_id๋ฅผ ๊ตฌ๋ถ„ํ•ด์•ผ ํ•œ๋‹ค.

์ถ”์ฒœ ๋ชจ๋ธ ์ด๋ ฅ๊ณผ A/B ํ…Œ์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•˜๋ฉด ์ถ”์ฒœ ์‹คํ–‰ ๋‹จ์œ„, ๋ชจ๋ธ ๋ฒ„์ „ ๋ฐ ๋งŒ๋ฃŒ ์‹œ๊ฐ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ํ‚ค์›Œ๋“œ๋ณ„ ๊ฒ€์ƒ‰์ด ์ค‘์š”ํ•ด์ง€๋ฉด taste_keywords๋ฅผ ์ •๊ทœํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.


9. product_clicks

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ƒํ’ˆ ํด๋ฆญ ๋ฐ ๊ตฌ๋งค ํ›„์† ํ™•์ธ
์„ค๋ช… ์‚ฌ์šฉ์ž๊ฐ€ ์ถ”์ฒœ ์ƒํ’ˆ์˜ ๊ตฌ๋งค ๋งํฌ๋ฅผ ํด๋ฆญํ•œ ์ด๋ ฅ๊ณผ ์ผ์ • ๊ธฐ๊ฐ„ ์ดํ›„ ์‹ค์ œ ๊ตฌ๋งค ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๋Š” ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์ถ”์ฒœ ์ƒํ’ˆ ํด๋ฆญ ํ›„ 7์ผ์ด ์ง€๋‚˜๋ฉด ๊ตฌ๋งค ์—ฌ๋ถ€๋ฅผ ์งˆ๋ฌธํ•˜๊ณ , ์‘๋‹ต ๊ฒฐ๊ณผ๋ฅผ ์ถ”์ฒœ ๋ฐ AI ํ•™์Šต ๋ฐ์ดํ„ฐ๋กœ ์ œ๊ณตํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ์—ฌ๋Ÿฌ ํด๋ฆญ ๋ ˆ์ฝ”๋“œ๊ฐ€ ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ์„ ๊ฐ๊ฐ ์ฐธ์กฐํ•˜๋ฏ€๋กœ users, products์™€ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
PK id
FK user_id โ†’ users.id, product_id โ†’ products.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NOT NULL FK โ†’ users.id
product_id BIGINT NOT NULL FK โ†’ products.id
recommendation_type ENUM('SELF', 'FRIEND') NOT NULL -
clicked_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
follow_up_at DATETIME(6) NOT NULL; clicked_at + 7์ผ -
follow_up_status ENUM('PENDING', 'ASKED', 'ANSWERED') NOT NULL; DEFAULT 'PENDING' -
purchase_status ENUM('NOT_SELECTED', 'PURCHASED', 'NOT_PURCHASED') NOT NULL; DEFAULT 'NOT_SELECTED' -
answered_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์ƒํ’ˆ ํด๋ฆญ ๋ฐ ํ›„์† ํ™•์ธ ๋ ˆ์ฝ”๋“œ ์‹๋ณ„์ž ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ ์กฐํ•ฉ์˜ ์ƒํƒœ๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user_id ๊ตฌ๋งค ๋งํฌ๋ฅผ ํด๋ฆญํ•œ ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์ž๋ณ„ ํด๋ฆญ ๋ฐ ํ›„์† ์งˆ๋ฌธ ๋Œ€์ƒ์„ ์กฐํšŒํ•œ๋‹ค.
product_id ํด๋ฆญ๋œ ์ƒํ’ˆ ์ƒํ’ˆ๋ณ„ ํด๋ฆญ๊ณผ ๊ตฌ๋งค ์ „ํ™˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ง‘๊ณ„ํ•œ๋‹ค.
recommendation_type ๋ณธ์ธ ๊ตฌ๋งค ์ถ”์ฒœ ๋˜๋Š” ์นœ๊ตฌ ์„ ๋ฌผ ์ถ”์ฒœ ๊ตฌ๋ถ„ ํด๋ฆญ ๊ฒฝ๋กœ๊ฐ€ ๋‘ ์ข…๋ฅ˜๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ENUM์„ ์‚ฌ์šฉํ•œ๋‹ค.
clicked_at ๊ฐ€์žฅ ์ตœ๊ทผ ๊ตฌ๋งค ๋งํฌ ํด๋ฆญ ์‹œ๊ฐ ํ›„์† ์งˆ๋ฌธ ๊ธฐ์ค€ ์‹œ๊ฐ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๋Œ€๊ธฐ ์ค‘ ์žฌํด๋ฆญํ•˜๋ฉด ์ตœ์‹  ์‹œ๊ฐ์œผ๋กœ ๊ฐฑ์‹ ํ•œ๋‹ค.
follow_up_at ๊ตฌ๋งค ์—ฌ๋ถ€ ์งˆ๋ฌธ ์˜ˆ์ • ์‹œ๊ฐ ๋ฐฐ์น˜ ์ž‘์—…์ด ์งˆ๋ฌธ ๋Œ€์ƒ์„ ์ง์ ‘ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ณ„์‚ฐ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•œ๋‹ค.
follow_up_status ์งˆ๋ฌธ ๋Œ€๊ธฐ, ์งˆ๋ฌธ ์™„๋ฃŒ, ์‘๋‹ต ์™„๋ฃŒ ์ƒํƒœ ์ •ํ•ด์ง„ ํ›„์† ์ฒ˜๋ฆฌ ๋‹จ๊ณ„๋ฅผ DB์—์„œ ์ œํ•œํ•œ๋‹ค.
purchase_status ๋ฏธ์‘๋‹ต, ๊ตฌ๋งคํ•จ, ๊ตฌ๋งคํ•˜์ง€ ์•Š์Œ ์ƒํƒœ ๊ตฌ๋งค ์—ฌ๋ถ€์™€ ์•„์ง ์„ ํƒํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ํ•œ๋‹ค.
answered_at ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ๋งค ์—ฌ๋ถ€์— ์‘๋‹ตํ•œ ์‹œ๊ฐ ์‘๋‹ต ์ „์—๋Š” NULL์ด๊ณ  ์‘๋‹ต ์™„๋ฃŒ ์‹œ ๊ธฐ๋กํ•œ๋‹ค.
created_at ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ ์‹œ๊ฐ ์ตœ์ดˆ ํด๋ฆญ ๊ธฐ๋ฐ˜ ๋ ˆ์ฝ”๋“œ ์ƒ์„ฑ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ๋ ˆ์ฝ”๋“œ ์ตœ์ข… ๊ฐฑ์‹  ์‹œ๊ฐ ์žฌํด๋ฆญ, ์งˆ๋ฌธ ๋˜๋Š” ์‘๋‹ต ์ƒํƒœ์˜ ๋ณ€๊ฒฝ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
deleted_at ๋ ˆ์ฝ”๋“œ ๋…ผ๋ฆฌ ์‚ญ์ œ ์‹œ๊ฐ ๋ถ„์„ ๋ฐ์ดํ„ฐ์˜ ์ด๋ ฅ์„ ์œ ์ง€ํ•˜๋ฉด์„œ ์—…๋ฌด ์กฐํšŒ์—์„œ ์ œ์™ธํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ ๊ตฌ๋งค ๋งํฌ๋ฅผ ํด๋ฆญํ•œ ๋’ค ์‹ค์ œ ๊ตฌ๋งค๋กœ ์ด์–ด์กŒ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ํด๋ฆญ ์‹œ๊ฐ๊ณผ ํ›„์† ์งˆ๋ฌธ ์ƒํƒœ๋ฅผ ํ•œ ํ…Œ์ด๋ธ”์—์„œ ๊ด€๋ฆฌํ•œ๋‹ค. ํด๋ฆญ ๋ชฉ์ ์€ ๋ณธ์ธ ๊ตฌ๋งค์™€ ์นœ๊ตฌ ์„ ๋ฌผ ๋‘ ์ข…๋ฅ˜๋กœ ํ•œ์ •๋˜๋ฏ€๋กœ recommendation_type์„ ENUM์œผ๋กœ ์ •์˜ํ–ˆ๋‹ค.

asked_at์€ ๋ณ„๋„๋กœ ๋‘์ง€ ์•Š์•˜๋‹ค. ์งˆ๋ฌธ ์˜ˆ์ • ์‹œ๊ฐ์ธ follow_up_at๊ณผ ํ˜„์žฌ ์ฒ˜๋ฆฌ ๋‹จ๊ณ„์ธ follow_up_status๋ฅผ ํ†ตํ•ด ์งˆ๋ฌธ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ›„์† ์งˆ๋ฌธ ๋Œ€๊ธฐ ์ค‘ ๊ฐ™์€ ์ƒํ’ˆ์„ ๋‹ค์‹œ ํด๋ฆญํ•˜๋ฉด clicked_at๊ณผ follow_up_at์„ ์ตœ์‹  ๊ฐ’์œผ๋กœ ๊ฐฑ์‹ ํ•˜์—ฌ ๋งˆ์ง€๋ง‰ ๊ด€์‹ฌ ์‹œ์ ์„ ๊ธฐ์ค€์œผ๋กœ 7์ผ์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ˜„์žฌ ์žฌํด๋ฆญ ๊ฐฑ์‹  ์ •์ฑ…์„ ์•ˆ์ •์ ์œผ๋กœ ์ ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ค ํ–‰์„ ๊ฐฑ์‹ ํ• ์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์‚ฌ์šฉ์ž-์ƒํ’ˆ-์ถ”์ฒœ์œ ํ˜• ๊ธฐ์ค€์ด ํ•„์š”ํ•˜๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ์ œ์–ดํ•˜๊ฑฐ๋‚˜ ํ™œ์„ฑ ํ›„์† ๋ ˆ์ฝ”๋“œ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๋ณ„๋„ ํ‚ค ๋ฐ ์œ ๋‹ˆํฌ ์ •์ฑ…์„ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ›„์† ์งˆ๋ฌธ ๋ฐฐ์น˜ ์กฐํšŒ๋ฅผ ์œ„ํ•ด (follow_up_status, follow_up_at) ์ธ๋ฑ์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ํด๋ฆญ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌ๊ฒŒ ์ฆ๊ฐ€ํ•˜๋ฉด ํด๋ฆญ ์›๋ณธ ์ด๋ฒคํŠธ์™€ ํ›„์† ๊ตฌ๋งค ํ™•์ธ ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ณ , clicked_at ๊ธฐ์ค€ ํŒŒํ‹ฐ์…”๋‹ ๋˜๋Š” ์•„์นด์ด๋น™์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ถ”์ฒœ ์„ฑ๊ณผ ๋ถ„์„์„ ์œ„ํ•ด recommendation_batch_id, source_screen, campaign_id ๋“ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


10. product_feedbacks

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ƒํ’ˆ ํ”ผ๋“œ๋ฐฑ
์„ค๋ช… ํŠน์ • ์ƒํ’ˆ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ธ์ •ยท๋ถ€์ • ํ‰๊ฐ€์™€ ๋ถ€์ • ์‚ฌ์œ ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค.
๊ธฐ๋Šฅ์  ์—ญํ•  ์‚ฌ์šฉ์ž๋ณ„ ์ƒํ’ˆ ์„ ํ˜ธ ์ •๋ณด๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ์ดํ›„ ์ถ”์ฒœ ๊ฒฐ๊ณผ ๋ฐ AI ํ•™์Šต ๋ฐ์ดํ„ฐ์— ํ™œ์šฉํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ์—ฌ๋Ÿฌ ํ”ผ๋“œ๋ฐฑ์ด ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž์™€ ์ƒํ’ˆ์„ ๊ฐ๊ฐ ์ฐธ์กฐํ•˜๋ฏ€๋กœ users, products์™€ N:1 ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง„๋‹ค.
(user_id, product_id) UK๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ํ•œ ๋ช…์ด ์ƒํ’ˆ ํ•˜๋‚˜์— ํ•˜๋‚˜์˜ ํ˜„์žฌ ํ”ผ๋“œ๋ฐฑ๋งŒ ๊ฐ€์ง€๋„๋ก ์ œํ•œํ•œ๋‹ค.
PK id
FK user_id โ†’ users.id, product_id โ†’ products.id
UK (user_id, product_id) โ€” README ์„ค๊ณ„ ์˜๋„์ด๋ฉฐ ์‹ค์ œ DDL์— ์ถ”๊ฐ€ ํ•„์š”

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NOT NULL; product_id์™€ ๋ณตํ•ฉ UNIQUE FK โ†’ users.id
product_id BIGINT NOT NULL; user_id์™€ ๋ณตํ•ฉ UNIQUE FK โ†’ products.id
feedback_type ENUM('POSITIVE', 'NEGATIVE') NOT NULL -
dislike_reason VARCHAR(500) NULL -
is_anonymous BOOLEAN NOT NULL; DEFAULT FALSE -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์ƒํ’ˆ ํ”ผ๋“œ๋ฐฑ ์‹๋ณ„์ž JPA์—์„œ ๋ณตํ•ฉํ‚ค๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ณต์žก๋„๋ฅผ ์ค„์ด๊ณ  ์“ฐ๊ธฐ ์ค‘์‹ฌ ํ…Œ์ด๋ธ”์˜ ํ–‰์„ ๋‹จ์ˆœํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user_id ํ”ผ๋“œ๋ฐฑ ์ž‘์„ฑ ์‚ฌ์šฉ์ž ์‚ฌ์šฉ์ž-์ƒํ’ˆ ์กฐํ•ฉ์˜ ์œ ์ผ์„ฑ์„ ๋ณด์žฅํ•˜๋ฉด์„œ ์‚ฌ์šฉ์ž ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
product_id ํ”ผ๋“œ๋ฐฑ ๋Œ€์ƒ ์ƒํ’ˆ ์‚ฌ์šฉ์ž-์ƒํ’ˆ ์กฐํ•ฉ์˜ ์œ ์ผ์„ฑ์„ ๋ณด์žฅํ•˜๋ฉด์„œ ์ƒํ’ˆ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•œ๋‹ค.
feedback_type ์ƒํ’ˆ์— ๋Œ€ํ•œ ๊ธ์ • ๋˜๋Š” ๋ถ€์ • ํ‰๊ฐ€ ํ—ˆ์šฉ ์ƒํƒœ๊ฐ€ ๋‘ ์ข…๋ฅ˜๋กœ ๊ณ ์ •๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ ENUM์„ ์‚ฌ์šฉํ•œ๋‹ค.
dislike_reason ๋ถ€์ • ํ‰๊ฐ€ ์‚ฌ์œ  ๋ถ€์ • ํ”ผ๋“œ๋ฐฑ์—์„œ๋งŒ ์„ ํƒ์ ์œผ๋กœ ์ž…๋ ฅํ•˜๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
is_anonymous ํ”ผ๋“œ๋ฐฑ ํ‘œ์‹œ ์‹œ ์ž‘์„ฑ์ž ์ต๋ช… ์ฒ˜๋ฆฌ ์—ฌ๋ถ€ ์ต๋ช… ์—ฌ๋ถ€๋ฅผ ์ฐธยท๊ฑฐ์ง“์œผ๋กœ ํ‘œํ˜„ํ•œ๋‹ค.
created_at ํ”ผ๋“œ๋ฐฑ ์ƒ์„ฑ ์‹œ๊ฐ ํ”ผ๋“œ๋ฐฑ์ด ์ตœ์ดˆ ๋“ฑ๋ก๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
updated_at ํ”ผ๋“œ๋ฐฑ ์ตœ์ข… ์ˆ˜์ • ์‹œ๊ฐ ํ‰๊ฐ€๋‚˜ ๋ถ€์ • ์‚ฌ์œ ๊ฐ€ ์ˆ˜์ •๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•œ๋‹ค.
deleted_at ํ”ผ๋“œ๋ฐฑ ๋…ผ๋ฆฌ ์‚ญ์ œ ์‹œ๊ฐ ํ”ผ๋“œ๋ฐฑ ์ด๋ ฅ์„ ๋ณด์กดํ•˜๋ฉด์„œ ์ผ๋ฐ˜ ์กฐํšŒ์—์„œ ์ œ์™ธํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

์‚ฌ์šฉ์ž ํ•œ ๋ช…์ด ํŠน์ • ์ƒํ’ˆ์— ๋Œ€ํ•ด ํ•˜๋‚˜์˜ ํ˜„์žฌ ํ‰๊ฐ€๋งŒ ๊ฐ€์ง€๋„๋ก (user_id, product_id) ๋ณตํ•ฉ ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ฒ˜์Œ์—๋Š” ๋‘ ์ปฌ๋Ÿผ์„ ๋ณตํ•ฉ PK๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ–ˆ์œผ๋‚˜, ์ด ํ…Œ์ด๋ธ”์€ ์ถ”์ฒœ ๊ฒฐ๊ณผ๋ณด๋‹ค ์“ฐ๊ธฐ์™€ ์ˆ˜์ •์ด ์ค‘์‹ฌ์ด๊ณ  JPA ๋ณตํ•ฉํ‚ค ๊ตฌํ˜„ ๋ณต์žก๋„์— ๋น„ํ•ด ํด๋Ÿฌ์Šคํ„ฐ๋“œ ์ธ๋ฑ์Šค์˜ ์ด์ ์ด ํฌ์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ ๋Œ€๋ฆฌํ‚ค id๋ฅผ PK๋กœ ์‚ฌ์šฉํ–ˆ๋‹ค.

๊ธ์ •๊ณผ ๋ถ€์ • ๋‘ ์ƒํƒœ๋งŒ ์กด์žฌํ•˜๋ฏ€๋กœ feedback_type์„ ENUM์œผ๋กœ ์ œํ•œํ•œ๋‹ค. dislike_reason์€ ๋ถ€์ • ํ‰๊ฐ€์ผ ๋•Œ๋งŒ ์˜๋ฏธ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ ์„ ํƒ๊ฐ’์œผ๋กœ ๋‘๋ฉฐ, ํ•ด๋‹น ์กฐ๊ฑด์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฒ€์ฆ ๋˜๋Š” CHECK ์ œ์•ฝ์กฐ๊ฑด์œผ๋กœ ๋ณด์™„ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ‰๊ฐ€ ์ˆ˜์ค€์ด ์„ธ๋ถ„ํ™”๋˜๋ฉด ๋ณ„์ ์ด๋‚˜ ์ ์ˆ˜ ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ถ€์ • ์‚ฌ์œ ๊ฐ€ ํ‘œ์ค€ํ™”๋˜๊ฑฐ๋‚˜ ๋ณต์ˆ˜ ์„ ํƒ์ด ํ•„์š”ํ•ด์ง€๋ฉด ์‚ฌ์œ  ์ฝ”๋“œ ํ…Œ์ด๋ธ”๊ณผ ํ”ผ๋“œ๋ฐฑ-์‚ฌ์œ  ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋…ผ๋ฆฌ ์‚ญ์ œ๋œ ํ–‰๋„ (user_id, product_id) ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด์„ ์ ์œ ํ•œ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ™์€ ์ƒํ’ˆ์— ๋‹ค์‹œ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ธธ ๋•Œ ๊ธฐ์กด ํ–‰์„ ๋ณต๊ตฌยท๊ฐฑ์‹ ํ• ์ง€, ํ”ผ๋“œ๋ฐฑ ์ด๋ ฅ์„ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ• ์ง€ ์ •์ฑ…์„ ์ •ํ•ด์•ผ ํ•œ๋‹ค. ์ถ”์ฒœ ๋ชจ๋ธ ํ•™์Šต ์‹œ ์ต๋ช… ์—ฌ๋ถ€์™€ ๋ฌด๊ด€ํ•˜๊ฒŒ ๋‚ด๋ถ€ ์‚ฌ์šฉ์ž ID๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ฐœ์ธ์ •๋ณด ๋ฐ ๋™์˜ ์ •์ฑ…๋„ ํ•จ๊ป˜ ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.





11. user_consents

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์‚ฌ์šฉ์ž ์•ฝ๊ด€ ๋™์˜
์„ค๋ช… ์‚ฌ์šฉ์ž๋ณ„ ์•ฝ๊ด€ ๋ฐ ๊ฐœ์ธ์ •๋ณดยทAI ํ™œ์šฉ ๋“ฑ์˜ ๋™์˜ ์ƒํƒœ์™€ ์ ์šฉ๋œ ์ •์ฑ… ๋ฒ„์ „, ๋™์˜ ๋ฐ ์ฒ ํšŒ ์‹œ์ ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ๋™์˜ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์–ด๋–ค ์ •์ฑ… ๋ฒ„์ „์„ ๊ธฐ์ค€์œผ๋กœ ๋™์˜ํ–ˆ๋Š”์ง€ ๊ด€๋ฆฌํ•˜๋ฉฐ, ๋™์˜ ์ฒ ํšŒ ์—ฌ๋ถ€ ๋ฐ ์‹œ์ ์„ ์ถ”์ ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N user_consents, consent_types 1 : N user_consents
PK user_id
FK user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
user_id BIGINT NOT NULL PK, FK โ†’ users.id
consent_id BIGINT NOT NULL PK, FK โ†’ consent_types_id
policy_version VARCHAR(50) NOT NULL -
agreed_at DATETIME(6) NULL -
withdrawn_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
user_id ์•ฝ๊ด€์— ๋™์˜ํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž users.id์™€ ๋™์ผํ•œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ FK ๊ด€๊ณ„๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•œ๋‹ค.
consent_id ์‚ฌ์šฉ์ž๊ฐ€ ๋™์˜ํ•˜๊ฑฐ๋‚˜ ๋™์˜ํ•˜์ง€ ์•Š์€ ํ•ญ๋ชฉ์˜ ์‹๋ณ„์ž ๋™์˜ ์ข…๋ฅ˜๋ฅผ ๋ฌธ์ž์—ด์ด๋‚˜ ENUM์œผ๋กœ ์ง์ ‘ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  consent_types์˜ ์‹๋ณ„์ž๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ๋™์˜ ํ•ญ๋ชฉ์˜ ์ถ”๊ฐ€ยท์ˆ˜์ •์— ๋Œ€์‘ํ•œ๋‹ค.
policy_version ํ•ด๋‹น ๋™์˜๊ฐ€ ์ด๋ฃจ์–ด์งˆ ๋‹น์‹œ ์ ์šฉ๋œ ์•ฝ๊ด€ ๋˜๋Š” ์ •์ฑ…์˜ ๋ฒ„์ „ ์ •์ฑ… ๋ฒ„์ „์€ ์ˆซ์ž๋ฟ ์•„๋‹ˆ๋ผ v1.0, 2026-09-01 ๋“ฑ ๋‹ค์–‘ํ•œ ํ‘œํ˜„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ๋ฌธ์ž์—ด ํƒ€์ž…์œผ๋กœ ์ €์žฅํ•œ๋‹ค.
agreed_at ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์ •์ฑ…์— ๋™์˜ํ•œ ์‹œ๊ฐ ๋™์˜ํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•˜๋ฉฐ, ๋งˆ์ดํฌ๋กœ์ดˆ ๋‹จ์œ„๊นŒ์ง€ ๊ธฐ๋กํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
withdrawn_at ์‚ฌ์šฉ์ž๊ฐ€ ๊ธฐ์กด ๋™์˜๋ฅผ ์ฒ ํšŒํ•œ ์‹œ๊ฐ ์•„์ง ์ฒ ํšŒํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
created_at ์‚ฌ์šฉ์ž ๋™์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์‚ฌ์šฉ์ž ๋™์˜ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ๊ฐ
updated_at ์‚ฌ์šฉ์ž ๋™์˜ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ ์‚ฌ์šฉ์ž ๋™์˜ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ
deleted_at ๋™์˜ ์ •๋ณด๋ฅผ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œํ•œ ์‹œ๊ฐ ๋™์˜ ์ •๋ณด๋ฅผ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œํ•œ ์‹œ๊ฐ

์„ค๊ณ„ ๊ทผ๊ฑฐ

user_consents๋Š” ์‚ฌ์šฉ์ž์™€ ๋™์˜ ํ•ญ๋ชฉ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค. ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋Š” ๊ฐœ์ธ์ •๋ณด ์ฒ˜๋ฆฌ๋ฐฉ์นจ, AI ํ™œ์šฉ ๋™์˜, ๋งˆ์ผ€ํŒ… ์ˆ˜์‹  ๋™์˜ ๋“ฑ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ๋™์˜ ํ•ญ๋ชฉ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋™์ผํ•œ ๋™์˜ ํ•ญ๋ชฉ ์—ญ์‹œ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ์šฉ๋˜๋ฏ€๋กœ users์™€ consent_types ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ user_consents๊ฐ€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌ์กฐ๋กœ ์„ค๊ณ„ํ•˜์˜€๋‹ค.

์ƒˆ๋กœ์šด ๋™์˜ ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ๊ธฐ์กด ํ•ญ๋ชฉ์˜ ์ด๋ฆ„, ์„ค๋ช…, ํ•„์ˆ˜ ์—ฌ๋ถ€, ํ™œ์„ฑ ์—ฌ๋ถ€๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•ด ๋™์˜ ์ข…๋ฅ˜๋ฅผ ENUM์ด๋‚˜ VARCHAR๋กœ user_consents ํ…Œ์ด๋ธ”์— ์ง์ ‘ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  ๋ณ„๋„์˜ consent_types ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค.

โ‡’ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์™€ ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋™์˜ ์ข…๋ฅ˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” ๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  (user_id, consent_id) ๋ณตํ•ฉ ๊ธฐ๋ณธํ‚ค๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ์ด ํ…Œ์ด๋ธ”์—์„œ ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๋Š” ๋ณธ์งˆ์ ์œผ๋กœ ํŠน์ • ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ๋™์˜ ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋™์˜ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•˜๋ฏ€๋กœ ๋‘ ์ปฌ๋Ÿผ์˜ ์กฐํ•ฉ ์ž์ฒด๊ฐ€ ๋น„์ฆˆ๋‹ˆ์Šค์ ์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฌ์šด ์‹๋ณ„์ž๊ฐ€ ๋œ๋‹ค. ๋˜ํ•œ ๋™์ผํ•œ ์‚ฌ์šฉ์ž์™€ ๋™์ผํ•œ ๋™์˜ ํ•ญ๋ชฉ์˜ ์กฐํ•ฉ์ด ์ค‘๋ณต ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ PK ์ œ์•ฝ์กฐ๊ฑด๋งŒ์œผ๋กœ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ ํ…Œ์ด๋ธ”์€ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ์ฐธ์กฐํ•˜์ง€ ์•Š๊ณ , ์‚ฌ์šฉ์ž์™€ ๋™์˜ ํ•ญ๋ชฉ ์‚ฌ์ด์˜ ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”์ด๋ผ ๋ณ„๋„ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•ด ์–ป๋Š” ์ด๋“์ด ํฌ์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ ๋ณตํ•ฉ ๊ธฐ๋ณธํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

โ†’ ORM ๋ณตํ•ฉํ‚ค ๊ตฌ์„ฑ ์œ„ํ•œ ์ถ”๊ฐ€ ์ž‘์—… ํ•„์š”

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ˜„์žฌ ๊ตฌ์กฐ์—์„œ๋Š” ์ƒˆ๋กœ์šด ๋™์˜ ์ข…๋ฅ˜๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ user_consents์˜ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  consent_types ํ…Œ์ด๋ธ”์— ์ƒˆ๋กœ์šด ๋™์˜ ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐœ์ธ์ •๋ณด ์ˆ˜์ง‘ยท์ด์šฉ ๋™์˜, AI ๋ฐ์ดํ„ฐ ํ™œ์šฉ ๋™์˜, ์นœ๊ตฌ ์ทจํ–ฅ ๊ณต์œ  ๋™์˜, ๋งˆ์ผ€ํŒ… ์ˆ˜์‹  ๋™์˜ ์™ธ์— ์ƒˆ๋กœ์šด ์ •์ฑ…์ด ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ์—๋„ ๋™์ผํ•œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์‚ฌ์šฉ์ž ๋˜๋Š” ๋™์˜ ํ•ญ๋ชฉ์„ ๊ธฐ์ค€์œผ๋กœ ์กฐํšŒํ•˜๋Š” ์š”์ฒญ์ด ์ฆ๊ฐ€ํ•˜๋”๋ผ๋„ ๋ณตํ•ฉ PK์˜ ์ฒซ ๋ฒˆ์งธ ์ปฌ๋Ÿผ์ธ user_id๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ „์ฒด ๋™์˜ ์ƒํƒœ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฐ˜๋Œ€๋กœ ํŠน์ • consent_id์— ๋™์˜ํ•œ ์ „์ฒด ์‚ฌ์šฉ์ž๋ฅผ ์กฐํšŒํ•˜๋Š” ํŒจํ„ด์ด ๋นˆ๋ฒˆํ•ด์ง€๋Š” ๊ฒฝ์šฐ consent_id ๋‹จ๋… ๋ณด์กฐ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.


12 notification_types

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์•Œ๋ฆผ ์ข…๋ฅ˜
์„ค๋ช… ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๋ฆผ ์ข…๋ฅ˜์™€ ์‚ฌ์šฉ์ž ์„ค์ • ๊ฐ€๋Šฅ ์—ฌ๋ถ€, ํ™œ์„ฑํ™” ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์‹ค์ œ ์ƒ์„ฑ๋œ ์•Œ๋ฆผ๊ณผ ์‚ฌ์šฉ์ž๋ณ„ ์•Œ๋ฆผ ์„ค์ •์—์„œ ๋™์ผํ•œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ notification_types 1 : N notifications, notification_types 1 : N user_notification_settings
PK id
FK ์—†์Œ

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
type VARCHAR(30) NOT NULL UK
name VARCHAR(50) NOT NULL -
is_configurable BOOLEAN NOT NULL; DEFAULT TRUE -
is_activated BOOLEAN NOT NULL; DEFAULT FALSE -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
deleted_at DATETIME(6) NULL -
updated_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ FK๋กœ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•œ ๋Œ€๋ฆฌํ‚ค์ด๋ฉฐ, ํ–ฅํ›„ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์ฆ๊ฐ€์— ์ถฉ๋ถ„ํ•œ ๋ฒ”์œ„๋ฅผ ํ™•๋ณดํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
type ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ CHAT, EVENT, FRIEND_JOIN ๋“ฑ ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๊ณ  ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ํ™œ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด VARCHAR๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
name ์‚ฌ์šฉ์ž ๋˜๋Š” ๊ด€๋ฆฌ์ž ํ™”๋ฉด์—์„œ ์‚ฌ์šฉํ•  ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์ด๋ฆ„ ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ํ‘œ์‹œ๋ช…์„ ์ €์žฅํ•˜๋ฉฐ ๊ธธ์ด๊ฐ€ ์ œํ•œ์ ์ธ ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ VARCHAR(50)์„ ์‚ฌ์šฉํ•œ๋‹ค.
is_configurable ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์•Œ๋ฆผ์˜ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ ์„ค์ • ๊ฐ€๋Šฅ/๋ถˆ๊ฐ€๋Šฅ์˜ ๋‘ ์ƒํƒœ๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ BOOLEAN์„ ์‚ฌ์šฉํ•œ๋‹ค.
is_activated ํ•ด๋‹น ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ํ˜„์žฌ ์„œ๋น„์Šค์—์„œ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ํ™œ์„ฑ/๋น„ํ™œ์„ฑ ๋‘ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด BOOLEAN์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ตœ์ดˆ ๋“ฑ๋ก๋œ ์‹œ๊ฐ ์ƒ์„ฑ ์‹œ์ ์„ ์ž๋™์œผ๋กœ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค์˜ ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ๊ทœ์น™๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
deleted_at ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ๊ธฐ์กด ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ์™€์˜ ์ฐธ์กฐ ๊ด€๊ณ„๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์•Œ๋ฆผ ์ข…๋ฅ˜ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ ์ˆ˜์ •๋˜์ง€ ์•Š์€ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

notification_types๋Š” ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„๋ฆฌํ•˜์˜€๋‹ค. ์•Œ๋ฆผ ์ข…๋ฅ˜๋Š” ์‹ค์ œ ์•Œ๋ฆผ์„ ์ €์žฅํ•˜๋Š” notifications์™€ ์‚ฌ์šฉ์ž์˜ ์•Œ๋ฆผ ์ˆ˜์‹  ์„ค์ •์„ ์ €์žฅํ•˜๋Š” user_notification_settings์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ, ๊ฐ ํ…Œ์ด๋ธ”์—์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ENUM์ด๋‚˜ VARCHAR๋กœ ์ค‘๋ณต ๊ด€๋ฆฌํ•  ๊ฒฝ์šฐ ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋  ๋•Œ ๋ณ€๊ฒฝ ์ง€์ ์ด ๋‹ค์ค‘ํ™” ๋œ๋‹ค.

๋”ฐ๋ผ์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ notification_types์—์„œ ์ค‘์•™ ๊ด€๋ฆฌํ•˜๊ณ  ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ๋Š” notification_type_id๋ฅผ ํ†ตํ•ด ์ฐธ์กฐํ•˜๋„๋ก ์„ค๊ณ„ํ•˜์˜€๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์•Œ๋ฆผ ์ข…๋ฅ˜ ์ถ”๊ฐ€ ์‹œ notification_types์— ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•Œ๋ฆผ ์ด๋ฆ„์ด๋‚˜ ์„ค์ • ๊ฐ€๋Šฅ ์—ฌ๋ถ€์™€ ๊ฐ™์€ ์†์„ฑ ์—ญ์‹œ ํ•˜๋‚˜์˜ ๊ด€๋ฆฌ ์ง€์ ์—์„œ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

notifications์™€ user_notification_settings์—์„œ๋Š” ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์„ธ๋ถ€ ์ •๋ณด ์ž์ฒด๋ณด๋‹ค ํ•ด๋‹น ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋ฏ€๋กœ ์ˆซ์žํ˜• ์‹๋ณ„์ž๋ฅผ FK๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ตฌ์กฐ๊ฐ€ ์ ํ•ฉํ•˜๋‹ค. notifications์—์„œ๋Š” notification_type_id๊ฐ€ notification_types.id๋ฅผ ์ฐธ์กฐํ•˜๋ฉฐ, user_notification_settings ์—ญ์‹œ ๋™์ผํ•œ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์‹๋ณ„์ž๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์‹ค์ œ ์•Œ๋ฆผ๊ณผ ์‚ฌ์šฉ์ž ์„ค์ • ๊ฐ„ ๋™์ผํ•œ ๋ถ„๋ฅ˜ ์ฒด๊ณ„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

code๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์—์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ฐ’์ด๋ฏ€๋กœ ์ค‘๋ณต๋œ ์ฝ”๋“œ๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š๋„๋ก UNIQUE ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์ƒˆ๋กœ์šด ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ notifications๋‚˜ user_notification_settings์˜ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  notification_types์— ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ธฐ์กด ์ฑ„ํŒ…, ์ด๋ฒคํŠธ, ์นœ๊ตฌ ๊ฐ€์ž… ์•Œ๋ฆผ ์™ธ์— ์„ ๋ฌผ ์ถ”์ฒœ, ์‹œ์Šคํ…œ ๊ณต์ง€ ๋“ฑ์˜ ์•Œ๋ฆผ์ด ์ถ”๊ฐ€ ๋˜๋”๋ผ๋„ ๋™์ผํ•œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•Œ๋ฆผ ์ข…๋ฅ˜๋ณ„ ์ •์ฑ…์ด ๋ณต์žกํ•ด์ง€๋Š” ๊ฒฝ์šฐ notification_types์— ์ถ”๊ฐ€ ์†์„ฑ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด default_enabled๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์˜ ๊ธฐ๋ณธ๊ฐ’์„ ์ข…๋ฅ˜๋ณ„๋กœ ๊ด€๋ฆฌํ•˜๊ฑฐ๋‚˜, category, priority, delivery_channel ๋“ฑ์˜ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์•Œ๋ฆผ ๋ถ„๋ฅ˜์™€ ์ „๋‹ฌ ์ •์ฑ…์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ Push, Email, SMS ๋“ฑ ์—ฌ๋Ÿฌ ์ „๋‹ฌ ์ฑ„๋„์„ ์ง€์›ํ•˜๊ณ  ์‚ฌ์šฉ์ž๋ณ„๋กœ ์ฑ„๋„๋งˆ๋‹ค ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ณ„๋„์˜ notification_channels ํ…Œ์ด๋ธ”์„ ์ถ”๊ฐ€ํ•˜๊ณ , notification_types์™€ ์ฑ„๋„ ๊ฐ„ ๊ด€๊ณ„๋ฅผ ๋ณ„๋„์˜ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.


13. user_notification_settings

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •
์„ค๋ช… ์‚ฌ์šฉ์ž๋ณ„ ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•œ ์ˆ˜์‹  ํ™œ์„ฑํ™” ์—ฌ๋ถ€๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ณ„๋กœ ์•Œ๋ฆผ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉฐ, ์•Œ๋ฆผ ๋ฐœ์†ก ์‹œ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ์„ค์ • ๊ฐ’์„ ์กฐํšŒํ•˜์—ฌ ๋ฐœ์†ก ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N user_notification_settings, notification_types 1 : N user_notification_settings
PK (user_id, notification_type_id)
FK user_id โ†’ users.id, notification_type_id โ†’ notification_types.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
user_id BIGINT NOT NULL PK, FK โ†’ users.id
notification_type_id BIGINT NOT NULL PK, FK โ†’ notification_types.id
is_enabled BOOLEAN NOT NULL; DEFAULT FALSE -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
user_id ์•Œ๋ฆผ ์„ค์ •์„ ๋ณด์œ ํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž users.id์™€ ๋™์ผํ•œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜์—ฌ FK ๊ด€๊ณ„๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ์œ ์ง€ํ•œ๋‹ค.
notification_type_id ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•œ ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์‹๋ณ„์ž ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋ฌธ์ž์—ด์ด๋‚˜ ENUM์œผ๋กœ ์ง์ ‘ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  notification_types์˜ ์‹๋ณ„์ž๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์•Œ๋ฆผ ์ข…๋ฅ˜ ๋ณ€๊ฒฝ ๋ฐ ํ™•์žฅ์— ๋Œ€์‘ํ•œ๋‹ค.
is_enabled ํ•ด๋‹น ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ ์ˆ˜์‹ ์„ ํ—ˆ์šฉํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€ ์ˆ˜์‹  ํ—ˆ์šฉ/๋น„ํ—ˆ์šฉ์˜ ๋‘ ์ƒํƒœ๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ BOOLEAN์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์ด ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์ƒ์„ฑ ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•˜๊ณ  ๋‹ค๋ฅธ ์‹œ๊ฐ„ ์ปฌ๋Ÿผ๊ณผ ํƒ€์ž… ๋ฐ ์ •๋ฐ€๋„๋ฅผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์ด ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ ์„ค์ • ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์€ ์ดˆ๊ธฐ ์ƒํƒœ์™€ ์ˆ˜์ •๋œ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
deleted_at ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ๋ฐ์ดํ„ฐ์˜ ๋ฌผ๋ฆฌ์  ์‚ญ์ œ ์—†์ด ๋น„ํ™œ์„ฑ ๋˜๋Š” ์‚ญ์ œ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

user_notification_settings๋Š” ์‚ฌ์šฉ์ž์™€ ์•Œ๋ฆผ ์ข…๋ฅ˜ ๊ฐ„์˜ ์„ค์ • ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค. ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋Š” ์ฑ„ํŒ…, ์ด๋ฒคํŠธ, ์นœ๊ตฌ ๊ฐ€์ž… ๋“ฑ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ์•Œ๋ฆผ ์„ค์ •์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ , ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์—ญ์‹œ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ์„ค์ • ๋Œ€์ƒ์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ users์™€ notification_types ์‚ฌ์ด์˜ N:M ๊ด€๊ณ„๋ฅผ user_notification_settings๊ฐ€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ตฌ์กฐ๋กœ ์„ค๊ณ„ํ•˜์˜€๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” ๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ๋‘์ง€ ์•Š๊ณ  (user_id, notification_type_id) ๋ณตํ•ฉ ๊ธฐ๋ณธํ‚ค๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ๋™์ผํ•œ ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ๋‘ ๊ฐœ ์ด์ƒ์˜ ์„ค์ • ๊ฐ’์„ ๊ฐ€์ง€๋Š” ๊ฒƒ์€ ๋น„์ฆˆ๋‹ˆ์Šค์ ์œผ๋กœ ์˜๋ฏธ๊ฐ€ ์—†์œผ๋ฏ€๋กœ (user_id, notification_type_id) ์กฐํ•ฉ์„ PK๋กœ ์‚ฌ์šฉํ•ด ๋™์ผํ•œ ์‚ฌ์šฉ์ž-์•Œ๋ฆผ ์ข…๋ฅ˜ ์กฐํ•ฉ์˜ ์ค‘๋ณต ์ƒ์„ฑ์„ DB ์ˆ˜์ค€์—์„œ ๋ฐฉ์ง€ํ•˜๋„๋ก ํ•˜์˜€๋‹ค.

๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ์—๋„ ๋™์ผํ•œ ์‚ฌ์šฉ์ž์™€ ๋™์ผํ•œ ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•œ ์ค‘๋ณต ์„ค์ •์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด (user_id, notification_type_id)์— UNIQUE ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ํ˜„์žฌ์ฒ˜๋Ÿผ ๋‹จ์ˆœํ•œ ์—ฐ๊ฒฐ ๊ด€๊ณ„์™€ ์„ค์ • ๊ฐ’๋งŒ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์—์„œ๋Š” ๋ณ„๋„์˜ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์ถ”๊ฐ€ํ–ˆ์„ ๊ฒฝ์šฐ ๊ฐ€์ ธ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์ด์ ์ด ํฌ์ง€ ์•Š๋‹ค๊ณ  ํŒ๋‹จํ•ด ๋ณตํ•ฉ ๊ธฐ๋ณธํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๋‹ค๋งŒ JPA ๋“ฑ์˜ ORM์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋ณตํ•ฉํ‚ค๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€์ ์ธ ๋งคํ•‘์ด ํ•„์š”ํ•˜๋‹ค.

โ‡’ ๋‹จ์ผ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ๋ณด๋‹ค ๊ตฌํ˜„ ๋ฐ ํ…Œ์ŠคํŠธ๊ฐ€ ๋‹ค์†Œ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์กด์žฌํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์ƒˆ๋กœ์šด ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ user_notification_settings ํ…Œ์ด๋ธ”์˜ ์ปฌ๋Ÿผ์ด๋‚˜ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  notification_types์— ์ƒˆ๋กœ์šด ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋“ฑ๋กํ•œ ๋’ค ์‚ฌ์šฉ์ž๋ณ„ ์„ค์ • ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ๋Š” ์•Œ๋ฆผ ์ข…๋ฅ˜๋ณ„ ํ™œ์„ฑํ™” ์—ฌ๋ถ€๋งŒ is_enabled ํ•˜๋‚˜๋กœ ๊ด€๋ฆฌํ•˜์ง€๋งŒ, ํ–ฅํ›„ Push, Email, SMS, ์นด์นด์˜คํ†ก ๋“ฑ ์—ฌ๋Ÿฌ ์•Œ๋ฆผ ์ „๋‹ฌ ์ฑ„๋„์„ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ๊ฐ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ notification_channels์™€ ๊ฐ™์€ ๋ณ„๋„์˜ ์ฑ„๋„ ํ…Œ์ด๋ธ”์„ ์ถ”๊ฐ€ํ•˜๊ณ  (user_id, notification_type_id, channel_id) ๋‹จ์œ„๋กœ ์„ค์ •์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ ๋ณตํ•ฉ PK์˜ ์ฒซ ๋ฒˆ์งธ ์ปฌ๋Ÿผ์ด user_id์ด๋ฏ€๋กœ ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ „์ฒด ์•Œ๋ฆผ ์„ค์ •์„ ์กฐํšŒํ•˜๋Š” ํŒจํ„ด์—์„œ๋Š” PK ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋งˆ์ดํŽ˜์ด์ง€๋‚˜ ์•Œ๋ฆผ ์„ค์ • ํ™”๋ฉด์—์„œ ํŠน์ • ์‚ฌ์šฉ์ž์˜ ๋ชจ๋“  ์•Œ๋ฆผ ์„ค์ •์„ ์กฐํšŒํ•˜๋Š” ์ฃผ์š” ํŒจํ„ด์— ์ ํ•ฉํ•˜๋‹ค.


14. friends

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์นœ๊ตฌ ๊ด€๊ณ„
์„ค๋ช… ์„œ๋น„์Šค ์‚ฌ์šฉ์ž ๊ฐ„์˜ ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ํŠน์ • ์‚ฌ์šฉ์ž๊ฐ€ ๋“ฑ๋กํ•œ ์นœ๊ตฌ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ , ์นœ๊ตฌ ์ฆ๊ฒจ์ฐพ๊ธฐ ์—ฌ๋ถ€ ๋ฐ ์นœ๊ตฌ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋Š” ์ด๋ฒคํŠธยท์ถ”์ฒœ ๋“ฑ์˜ ๊ธฐ๋Šฅ์—์„œ ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N friends (owner_user_id ๊ธฐ์ค€),
users 1 : N friends (friend_user_id ๊ธฐ์ค€), friends 1 : N events
PK id
FK owner_user_id โ†’ users.id, friend_user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
owner_user_id BIGINT NOT NULL FK โ†’ users.id , UK
friend_user_id BIGINT NOT NULL FK โ†’ users.id ,UK
is_favorite BOOLEAN NOT NULL; DEFAULT FALSE -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ์นœ๊ตฌ ๊ด€๊ณ„ ์ž์ฒด๋ฅผ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ๋‹ค๋ฅธ ์ฃผ์š” ์‹๋ณ„์ž์™€ ํƒ€์ž…์„ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
owner_user_id ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์†Œ์œ ํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž users.id๋ฅผ ์ฐธ์กฐํ•˜๋Š” FK์ด๋ฏ€๋กœ ๋™์ผํ•œ BIGINT ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
friend_user_id owner_user_id ์‚ฌ์šฉ์ž๊ฐ€ ์นœ๊ตฌ๋กœ ๋“ฑ๋กํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž users.id๋ฅผ ์ฐธ์กฐํ•˜๋Š” FK์ด๋ฏ€๋กœ ๋™์ผํ•œ BIGINT ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
is_favorite ํ•ด๋‹น ์นœ๊ตฌ๋ฅผ ์ฆ๊ฒจ์ฐพ๊ธฐ๋กœ ์ง€์ •ํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€ ์ฆ๊ฒจ์ฐพ๊ธฐ/์ผ๋ฐ˜์˜ ๋‘ ๊ฐ€์ง€ ์ƒํƒœ๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ BOOLEAN์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์นœ๊ตฌ ๋“ฑ๋ก ์‹œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ผ๋ฐ˜ ์นœ๊ตฌ๊ฐ€ ๋˜๋„๋ก FALSE๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

friends๋Š” ์‚ฌ์šฉ์ž ๊ฐ„์˜ ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด users์™€ ๋ณ„๋„์˜ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜์˜€๋‹ค. ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋Š” ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๋ฅผ ์นœ๊ตฌ๋กœ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๊ณ , ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž ์—ญ์‹œ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ์นœ๊ตฌ๋กœ ๋“ฑ๋ก๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž ๊ฐ„ ์ž๊ธฐ์ฐธ์กฐ ๊ด€๊ณ„๋ฅผ ๋ณ„๋„์˜ ๊ด€๊ณ„ ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด ํ‘œํ˜„ํ•˜์˜€๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์นœ๊ตฌ ๊ด€๊ณ„ ์ž์ฒด๊ฐ€ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ฐธ์กฐ๋˜๋Š” ๋Œ€์ƒ์ด ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ๋Š” friend_id ํ•˜๋‚˜๋งŒ์œผ๋กœ ํŠน์ • ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์นœ๊ตฌ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ด๋ฒคํŠธ, ์„ ๋ฌผ ์ถ”์ฒœ, ์•Œ๋ฆผ ๋“ฑ์˜ ๊ฒฝ์šฐ ๊ด€๊ณ„ ์‹๋ณ„์ž๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ์ „๋‹ฌํ•˜๊ณ  ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

(owner_user_id, friend_user_id)์— ๋ณตํ•ฉ UNIQUE ์ œ์•ฝ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ค‘๋ณต ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ DB ์ˆ˜์ค€์—์„œ ๋ฐฉ์ง€ํ•œ๋‹ค.

๋™์ผํ•œ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ์นœ๊ตฌ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ๋”๋ผ๋„ ๊ฐ ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์นœ๊ตฌ๋ฅผ ์ฆ๊ฒจ์ฐพ๊ธฐ๋กœ ์ง€์ •ํ–ˆ๋Š”์ง€๋Š” ์„œ๋กœ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— is_favorite๋Š” ์นœ๊ตฌ ๊ด€๊ณ„์— ์ข…์†๋˜๋Š” ์‚ฌ์šฉ์ž๋ณ„ ์†์„ฑ์ด๋ฏ€๋กœ users๊ฐ€ ์•„๋‹Œ friends์— ์ €์žฅํ•˜์˜€๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์นœ๊ตฌ ๊ด€๊ณ„์— ์ถ”๊ฐ€์ ์ธ ์‚ฌ์šฉ์ž๋ณ„ ์„ค์ •์ด ํ•„์š”ํ•ด์งˆ ๊ฒฝ์šฐ friends ํ…Œ์ด๋ธ”์— ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ id๋ฅผ ๋…๋ฆฝ์ ์ธ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ–ฅํ›„ events๋ฟ ์•„๋‹ˆ๋ผ ์นœ๊ตฌ ๊ธฐ๋ฐ˜ ์„ ๋ฌผ ์ถ”์ฒœ, ์นœ๊ตฌ๋ณ„ ์ทจํ–ฅ ์ •๋ณด, ์•Œ๋ฆผ ๋“ฑ์˜ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ๋„ friend_id ํ•˜๋‚˜๋ฅผ ํ†ตํ•ด ํŠน์ • ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์นœ๊ตฌ ๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋„๋ฉ”์ธ์ด ์ฆ๊ฐ€ํ•˜๋”๋ผ๋„ ๋ณตํ•ฉ FK๋ฅผ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๋ฐ˜๋ณตํ•ด์„œ ๊ตฌ์„ฑํ•˜์ง€ ์•Š๊ณ  ๊ด€๊ณ„๋ฅผ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์นœ๊ตฌ ๋ชฉ๋ก ์กฐํšŒ๊ฐ€ ์ฃผ์š” ์กฐํšŒ ํŒจํ„ด์ด๋ฏ€๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฆ๊ฐ€ํ•  ๊ฒฝ์šฐ owner_user_id๋ฅผ ํด๋Ÿฌ์Šคํ„ฐ๋“œ ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ๊ฒจ์ฐพ๊ธฐ ์นœ๊ตฌ ์กฐํšŒ๊ฐ€ ๋นˆ๋ฒˆํ•˜๋‹ค๋ฉด (owner_user_id, is_favorite) ํ˜•ํƒœ์˜ ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


15. events

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ด๋ฒคํŠธ
์„ค๋ช… ์‚ฌ์šฉ์ž ๋˜๋Š” ์นœ๊ตฌ์™€ ๊ด€๋ จ๋œ ์ƒ์ผ, ๊ธฐ๋…์ผ, ์ผ์ •, ๊ณตํœด์ผ ๋“ฑ์˜ ์ด๋ฒคํŠธ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์‚ฌ์šฉ์ž ๋ฐ ์นœ๊ตฌ์™€ ๊ด€๋ จ๋œ ์ผ์ •์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ , ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•Œ๋ฆผ ๋ฐ ์„ ๋ฌผ ์ถ”์ฒœ ๋“ฑ์˜ ๊ธฐ๋Šฅ์—์„œ ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ๋กœ ํ™œ์šฉํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N events, friends 1 : N events, events 1 : N notifications
PK id
FK user_id โ†’ users.id, friend_id โ†’ friends.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NULL FK โ†’ users.id
friend_id BIGINT NULL FK โ†’ friends.id
source_type VARCHAR(30) NOT NULL -
event_type VARCHAR(30) NOT NULL -
external_event_id VARCHAR(255) NULL -
title VARCHAR(255) NOT NULL -
event_date DATE NOT NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์ด๋ฒคํŠธ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ์ด๋ฒคํŠธ๊ฐ€ ์•Œ๋ฆผ ๋“ฑ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ฐธ์กฐ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ์ด๋ฏ€๋กœ ๋‹จ์ผ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด ์ฃผ์š” ์‹๋ณ„์ž ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user_id ์ด๋ฒคํŠธ์™€ ์ง์ ‘ ์—ฐ๊ด€๋œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ์‚ฌ์šฉ์ž ๋ณธ์ธ์˜ ์ผ์ • ๋“ฑ ์‚ฌ์šฉ์ž ๊ธฐ๋ฐ˜ ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ, ๋ชจ๋“  ์ด๋ฒคํŠธ๊ฐ€ ์‚ฌ์šฉ์ž ๋ณธ์ธ์—๊ฒŒ ์ง์ ‘ ๊ท€์†๋˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
friend_id ์ด๋ฒคํŠธ์™€ ์—ฐ๊ด€๋œ ์นœ๊ตฌ ๊ด€๊ณ„์˜ ์‹๋ณ„์ž ์นœ๊ตฌ ์ƒ์ผ์ด๋‚˜ ์นœ๊ตฌ ๊ด€๋ จ ๊ธฐ๋…์ผ ๋“ฑ ์นœ๊ตฌ ๊ธฐ์ค€ ์ด๋ฒคํŠธ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด friends.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
์‚ฌ์šฉ์ž ๋ณธ์ธ ์ด๋ฒคํŠธ์—์„œ๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
source_type ์ด๋ฒคํŠธ๊ฐ€ ์ƒ์„ฑ๋œ ์ถœ์ฒ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ฝ”๋“œ ์ด๋ฒคํŠธ ์ถœ์ฒ˜๊ฐ€ ์„œ๋น„์Šค ์šด์˜ ๊ณผ์ •์—์„œ ์ถ”๊ฐ€ยท๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ DB ENUM ๋Œ€์‹  VARCHAR์— ์ฝ”๋“œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ Enum ๋˜๋Š” ์ƒ์ˆ˜๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.
event_type ์ด๋ฒคํŠธ์˜ ์ข…๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์ฝ”๋“œ ์ƒ์ผ, ๊ธฐ๋…์ผ, ์ผ์ •, ๊ณตํœด์ผ ๋“ฑ ์ด๋ฒคํŠธ ์ข…๋ฅ˜๊ฐ€ ํ–ฅํ›„ ํ™•์žฅ๋  ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ DB ENUM ๋Œ€์‹  VARCHAR + ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ Enum ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.
external_event_id ์™ธ๋ถ€ ์บ˜๋ฆฐ๋” ๋˜๋Š” ์™ธ๋ถ€ ์„œ๋น„์Šค์—์„œ ์ด๋ฒคํŠธ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ID ์™ธ๋ถ€ ์„œ๋น„์Šค๋ณ„ ์‹๋ณ„์ž์˜ ํ˜•์‹๊ณผ ๊ธธ์ด๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ€๋ณ€ ๊ธธ์ด ๋ฌธ์ž์—ด ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด๋ถ€์—์„œ ์ง์ ‘ ์ƒ์„ฑ๋œ ์ด๋ฒคํŠธ์—๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์–ด NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
title ์ด๋ฒคํŠธ์˜ ์ œ๋ชฉ ์ผ์ • ๋ฐ ์ด๋ฒคํŠธ ์ œ๋ชฉ์€ ๋น„๊ต์  ๊ธธ์ด๊ฐ€ ์ œํ•œ๋œ ๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ VARCHAR(255)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
event_date ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋‚ ์งœ ํ˜„์žฌ ์ด๋ฒคํŠธ ๊ธฐ๋Šฅ์—์„œ๋Š” ์‹œ๊ฐ„๋ณด๋‹ค ๋‚ ์งœ ์ž์ฒด๊ฐ€ ์ค‘์š”ํ•˜๋ฏ€๋กœ ์‹œ๊ฐ„ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜์ง€ ์•Š๋Š” DATE ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์ƒ์„ฑ ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค์˜ ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ๊ทœ์น™์„ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์ด๋ฒคํŠธ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ ์•„์ง ์ˆ˜์ •๋˜์ง€ ์•Š์€ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
deleted_at ์ด๋ฒคํŠธ๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ๊ธฐ์กด ์•Œ๋ฆผ ๋ฐ ์™ธ๋ถ€ ์—ฐ๋™ ๋ฐ์ดํ„ฐ์™€์˜ ๊ด€๊ณ„๋ฅผ ๋ณด์กดํ•˜๋ฉด์„œ ์ด๋ฒคํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก Soft Delete ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

events๋Š” ์‚ฌ์šฉ์ž ๋ฐ ์นœ๊ตฌ์™€ ๊ด€๋ จ๋œ ์ƒ์ผ, ๊ธฐ๋…์ผ, ์ผ์ •, ๊ณตํœด์ผ ๋“ฑ์˜ ์ด๋ฒคํŠธ๋ฅผ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํ…Œ์ด๋ธ”์ด๋‹ค. ์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ๋Š” ์ดํ›„ ์•Œ๋ฆผ ์ƒ์„ฑ์ด๋‚˜ ์„ ๋ฌผ ์ถ”์ฒœ ๋“ฑ์˜ ๊ธฐ๋Šฅ์—์„œ ๊ธฐ์ค€ ๋ฐ์ดํ„ฐ๋กœ ํ™œ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋…๋ฆฝ์ ์ธ id๋ฅผ ๊ธฐ๋ณธํ‚ค๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

user_id์™€ friend_id๋Š” ์ด๋ฒคํŠธ์˜ ๋Œ€์ƒ ๋˜๋Š” ๊ท€์† ์ฃผ์ฒด๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์‚ฌ์šฉ์ž ๋ณธ์ธ์˜ ์ผ์ •์€ user_id๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ์นœ๊ตฌ์˜ ์ƒ์ผ์ด๋‚˜ ๊ธฐ๋…์ผ ๋“ฑ ์นœ๊ตฌ ๊ด€๊ณ„์— ์ข…์†๋œ ์ด๋ฒคํŠธ๋Š” friend_id๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ์ด๋ฒคํŠธ์˜ ์„ฑ๊ฒฉ์— ๋”ฐ๋ผ ๋‘ ์ปฌ๋Ÿผ ์ค‘ ํ•˜๋‚˜๋งŒ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.

ํ˜„์žฌ source_type๊ณผ event_type์€ ๋ณ„๋„์˜ ๋ณต์žกํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋‚˜ ๋น„์ฆˆ๋‹ˆ์Šค ์†์„ฑ์„ ๊ฐ€์ง€๋Š” ๋…๋ฆฝ์ ์ธ ์—”ํ‹ฐํ‹ฐ๋ผ๊ธฐ๋ณด๋‹ค ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋กœ์ง์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ๋‹จ์ˆœํ•œ ๋ถ„๋ฅ˜ ์ฝ”๋“œ์˜ ์„ฑ๊ฒฉ์ด ๊ฐ•ํ•ด ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•  ๊ฒฝ์šฐ ๋‹จ์ˆœํ•œ ์ฝ”๋“œ ๊ฐ’ ๊ด€๋ฆฌ์— ๋น„ํ•ด ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์™€ ๊ตฌํ˜„ ๋ณต์žก๋„๊ฐ€ ์ฆ๊ฐ€ํ•œ๋‹ค๊ณ  ํŒ๋‹จํ•˜์˜€๋‹ค.

๋”ฐ๋ผ์„œ ํ˜„์žฌ ์„ค๊ณ„์—์„œ๋Š” source_type๊ณผ event_type์„ VARCHAR ์ปฌ๋Ÿผ์— ์ €์žฅํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์˜ Enum์œผ๋กœ ํ—ˆ์šฉ ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ์„ ํƒํ•˜์˜€๋‹ค.

external_event_id๋Š” ์™ธ๋ถ€ ์บ˜๋ฆฐ๋” ๋“ฑ ์™ธ๋ถ€ ์„œ๋น„์Šค์—์„œ ์ œ๊ณตํ•˜๋Š” ์ด๋ฒคํŠธ์™€ ๋‚ด๋ถ€ ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์™ธ๋ถ€ ์„œ๋น„์Šค๋งˆ๋‹ค ID ํ˜•์‹์ด ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ˆซ์ž ํƒ€์ž…์œผ๋กœ ์ œํ•œํ•˜์ง€ ์•Š๊ณ  ๋ฌธ์ž์—ด ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ ์ถœ์ฒ˜ ๋˜๋Š” ์ด๋ฒคํŠธ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ DB ์Šคํ‚ค๋งˆ ๋ณ€๊ฒฝ ์—†์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ Enum์— ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ฐฉ์‹์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌ์™€ DB Migration์˜ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”๋ฏ€๋กœ ๋ฌด์ค‘๋‹จ ๋ฐฐํฌ ์‹œ์—๋„ ์ƒ๋Œ€์ ์œผ๋กœ ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์‹ ๊ทœ ์ด๋ฒคํŠธ ํƒ€์ž…์„ ๋จผ์ € ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋„๋ก ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ๋ฐฐํฌํ•œ ๋’ค ํ•ด๋‹น ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ ์ˆœ์„œ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ผ์ • ๋˜๋Š” ํŠน์ • ๋‚ ์งœ ๋ฒ”์œ„์˜ ์ด๋ฒคํŠธ ์กฐํšŒ๊ฐ€ ๋นˆ๋ฒˆํ•ด์งˆ ๊ฒฝ์šฐ (user_id, event_date), (friend_id, event_date) ๋“ฑ์˜ ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์‹ค์ œ ์กฐํšŒ ํŒจํ„ด๊ณผ ์‹คํ–‰ ๊ณ„ํš์„ ๊ธฐ์ค€์œผ๋กœ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


16. notification_types

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์•Œ๋ฆผ ์ข…๋ฅ˜
์„ค๋ช… ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์•Œ๋ฆผ ์œ ํ˜•๊ณผ ๊ฐ ์•Œ๋ฆผ์˜ ์„ค์ • ๊ฐ€๋Šฅ ์—ฌ๋ถ€ ๋ฐ ํ™œ์„ฑ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์‹ค์ œ ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ์™€ ์‚ฌ์šฉ์ž๋ณ„ ์•Œ๋ฆผ ์„ค์ •์—์„œ ๋™์ผํ•œ ์•Œ๋ฆผ ์œ ํ˜•์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ notification_types 1 : N notifications, notification_types 1 : N user_notification_settings
PK id
FK ์—†์Œ

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
type VARCHAR(30) NOT NULL UK
name VARCHAR(50) NOT NULL -
is_configurable BOOLEAN NOT NULL; DEFAULT TRUE -
is_activated BOOLEAN NOT NULL; DEFAULT FALSE -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์ฐธ์กฐํ•˜๊ธฐ ์œ„ํ•œ ๋Œ€๋ฆฌํ‚ค๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, ์„œ๋น„์Šค ๋‚ด ์ฃผ์š” ์‹๋ณ„์ž ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
type ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ํƒ€์ž… ์ฝ”๋“œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋Š” ์šด์˜ ์ค‘ ์ถ”๊ฐ€ยท๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ DB ENUM ๋Œ€์‹  VARCHAR๋กœ ์ €์žฅํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ Enum์œผ๋กœ ํ—ˆ์šฉ ๊ฐ’์„ ๊ด€๋ฆฌํ•œ๋‹ค.
name ํ™”๋ฉด ๋˜๋Š” ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ์—์„œ ํ‘œ์‹œํ•  ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์ด๋ฆ„ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋˜๋Š” ๋ช…์นญ์€ ๋‚ด๋ถ€ ์‹๋ณ„์šฉ ํƒ€์ž…๊ณผ ๋ถ„๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌํ•˜๋ฉฐ, ๋น„๊ต์  ์งง์€ ๋ฌธ์ž์—ด์ด๋ฏ€๋กœ VARCHAR(50)์„ ์‚ฌ์šฉํ•œ๋‹ค.
is_configurable ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์•Œ๋ฆผ์˜ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์ง์ ‘ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ ์‚ฌ์šฉ์ž ์„ค์ • ๊ฐ€๋Šฅ/๋ถˆ๊ฐ€๋Šฅ ๋‘ ์ƒํƒœ๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ BOOLEAN์„ ์‚ฌ์šฉํ•œ๋‹ค.
ํ–ฅํ›„ ํ•„์ˆ˜ ์•Œ๋ฆผ ์œ ํ˜•์„ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„ ์ •์ฑ… ์ปฌ๋Ÿผ์œผ๋กœ ๋ถ„๋ฆฌํ•œ๋‹ค.
is_activated ํ•ด๋‹น ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ํ˜„์žฌ ์„œ๋น„์Šค์—์„œ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ๋Š”์ง€ ์—ฌ๋ถ€ ํ™œ์„ฑ/๋น„ํ™œ์„ฑ ๋‘ ์ƒํƒœ๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด BOOLEAN์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  ์šด์˜ ์ƒํƒœ๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
created_at ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์ƒ์„ฑ ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ๊ทœ์น™๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์•Œ๋ฆผ ์ข…๋ฅ˜ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ ์ˆ˜์ • ์ด๋ ฅ์ด ์—†๋Š” ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
deleted_at ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ๊ธฐ์กด ์•Œ๋ฆผ ๋ฐ ์‚ฌ์šฉ์ž ์„ค์ • ๋ฐ์ดํ„ฐ์™€์˜ ์ฐธ์กฐ ๊ด€๊ณ„๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ์‹ ๊ทœ ์‚ฌ์šฉ๋งŒ ์ค‘๋‹จํ•  ์ˆ˜ ์žˆ๋„๋ก Soft Delete ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

notification_types๋Š” ์„œ๋น„์Šค์—์„œ ์‚ฌ์šฉ๋˜๋Š” ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ํ•˜๋‚˜์˜ ๊ธฐ์ค€์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”์ด๋‹ค. ์•Œ๋ฆผ ์ข…๋ฅ˜๋Š” ์‹ค์ œ ๋ฐœ์†ก๋œ ์•Œ๋ฆผ์„ ์ €์žฅํ•˜๋Š” notifications์™€ ์‚ฌ์šฉ์ž๋ณ„ ์•Œ๋ฆผ ์ˆ˜์‹  ์„ค์ •์„ ๊ด€๋ฆฌํ•˜๋Š” user_notification_settings์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ, ๊ฐ ํ…Œ์ด๋ธ”์—์„œ ํ•˜๋‚˜์˜ ๊ธฐ์ค€ ํ…Œ์ด๋ธ”์„ ์ฐธ์กฐํ•˜๋„๋ก ๊ตฌ์„ฑํ–ˆ๋‹ค.

์•Œ๋ฆผ ์ข…๋ฅ˜๋Š” ์„œ๋น„์Šค ์šด์˜ ๊ณผ์ •์—์„œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜๋ฉด์„œ ํ•จ๊ป˜ ์ฆ๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ๊ฐ’์ด๋ผ๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋Š” DB ์Šคํ‚ค๋งˆ์— ๊ฐ•ํ•˜๊ฒŒ ๊ฒฐํ•ฉ์‹œํ‚ค๊ธฐ๋ณด๋‹ค VARCHAR๋กœ ์ €์žฅํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ฝ”๋“œ Enum์„ ํ†ตํ•ด ํ—ˆ์šฉ๋˜๋Š” ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋„๋ก ์„ค๊ณ„ํ–ˆ๋‹ค.

notification_types๋ฅผ ๋ณ„๋„ ํ…Œ์ด๋ธ”๋กœ ๋‘” ์ด์œ ๋Š” ๋‹จ์ˆœํžˆ ์•Œ๋ฆผ ํƒ€์ž… ๋ฌธ์ž์—ด๋งŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์ด ์•„๋‹ˆ๋‹ค. ์•Œ๋ฆผ ์ข…๋ฅ˜๋ณ„๋กœ name, is_configurable, is_activated์™€ ๊ฐ™์€ ์ถ”๊ฐ€ ์†์„ฑ์„ ํ•จ๊ป˜ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์ž์ฒด๊ฐ€ ๋ณ„๋„์˜ ๊ด€๋ฆฌ ๋Œ€์ƒ์ด๋ผ๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.

is_configurable์€ ํ˜„์žฌ ์„œ๋น„์Šค ๊ธฐํš์ƒ ๋ชจ๋“  ์•Œ๋ฆผ์— ๋Œ€ํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ธฐ๋Šฅ์ด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ํ–ฅํ›„ ํ•„์ˆ˜ ์•Œ๋ฆผ์ด ์ถ”๊ฐ€๋  ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ์‚ฌ์ „์— ๋ถ„๋ฆฌํ•œ ์ปฌ๋Ÿผ์ด๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. type์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋น„์ฆˆ๋‹ˆ์Šค ์˜๋ฏธ๋ฅผ ๊ฐ€์ง€๋Š” ๊ฐ’์œผ๋กœ ํ–ฅํ›„ ๋ช…์นญ์ด ๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฉฐ, ์ด๋ฅผ PK๋กœ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๊ฐ’์„ ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  FK์— ์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์€ BIGINT id๋ฅผ ๊ด€๊ณ„ ์‹๋ณ„์ž๋กœ ์‚ฌ์šฉํ•˜๊ณ  type์€ ๋น„์ฆˆ๋‹ˆ์Šค ์‹๋ณ„ ์ฝ”๋“œ๋กœ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์ƒˆ๋กœ์šด ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ notifications ๋˜๋Š” user_notification_settings์˜ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  notification_types์— ์ƒˆ๋กœ์šด ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค. ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” type ์—ญ์‹œ DB ENUM์ด ์•„๋‹ˆ๋ฏ€๋กœ ์ƒˆ๋กœ์šด ์ฝ”๋“œ ์ถ”๊ฐ€๋กœ ์ธํ•œ ํ…Œ์ด๋ธ” DDL ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜์ง€ ์•Š๋Š”๋‹ค.

ํ–ฅํ›„ ํ•„์ˆ˜ ์•Œ๋ฆผ์ด ์ถ”๊ฐ€๋˜๋ฉด is_configurable = FALSE๋กœ ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ • ํ™”๋ฉด์—์„œ ์ œ์™ธํ•˜๊ฑฐ๋‚˜ ๋น„ํ™œ์„ฑํ™” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์„ค์ • ๊ฐ€๋Šฅ ์—ฌ๋ถ€์™€ ์‹ค์ œ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์•Œ๋ฆผ ์ •์ฑ…์ด ๋” ๋ณต์žกํ•ด์งˆ ๊ฒฝ์šฐ notification_types์— ์•Œ๋ฆผ ์šฐ์„ ์ˆœ์œ„, ๊ธฐ๋ณธ ํ™œ์„ฑํ™” ์—ฌ๋ถ€, ํ‘œ์‹œ ์นดํ…Œ๊ณ ๋ฆฌ ๋“ฑ์˜ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.


17. user_notification_settings

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •
์„ค๋ช… ์‚ฌ์šฉ์ž๋ณ„๋กœ ๊ฐ ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ณ„๋กœ ์ˆ˜์‹  ์—ฌ๋ถ€๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉฐ, ์•Œ๋ฆผ ์ƒ์„ฑ ๋˜๋Š” ๋ฐœ์†ก ์‹œ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ์„ค์ •๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์ˆ˜์‹  ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N user_notification_settings, notification_types 1 : N user_notification_settings
PK (user_id, notification_type_id)
FK user_id โ†’ users.id, notification_type_id โ†’ notification_types.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
user_id BIGINT NOT NULL PK, FK โ†’ users.id
notification_type_id BIGINT NOT NULL PK, FK โ†’ notification_types.id
is_enabled BOOLEAN NOT NULL; DEFAULT FALSE -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
user_id ์•Œ๋ฆผ ์„ค์ •์˜ ๋Œ€์ƒ์ด ๋˜๋Š” ์‚ฌ์šฉ์ž ์‹๋ณ„์ž users.id๋ฅผ ์ฐธ์กฐํ•˜๋Š” FK์ด๋ฏ€๋กœ ๋™์ผํ•œ BIGINT ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
notification_type_id ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•œ ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์‹๋ณ„์ž notification_types.id๋ฅผ ์ฐธ์กฐํ•˜๋Š” FK์ด๋ฏ€๋กœ ๋™์ผํ•œ BIGINT ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.
is_enabled ํ•ด๋‹น ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ์ˆ˜์‹ ์„ ํ—ˆ์šฉํ–ˆ๋Š”์ง€ ์—ฌ๋ถ€ ์ˆ˜์‹ /๋ฏธ์ˆ˜์‹  ๋‘ ์ƒํƒœ๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ BOOLEAN์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์ด ์ตœ์ดˆ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์ƒ์„ฑ ์‹œ์ ์„ ์ž๋™ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ๊ทœ์น™๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์ด ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ ์„ค์ • ๋ณ€๊ฒฝ ์ด๋ ฅ์ด ์—†๋Š” ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
deleted_at ์‚ฌ์šฉ์ž ์•Œ๋ฆผ ์„ค์ •์ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ์„ค์ • ์ด๋ ฅ์„ ๋ณด์กดํ•˜๊ฑฐ๋‚˜ ๋ณต๊ตฌ ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ Soft Delete ์šฉ๋„๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

user_notification_settings๋Š” ์‚ฌ์šฉ์ž์™€ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์‚ฌ์ด์˜ ์„ค์ • ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”์ด๋‹ค. ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋Š” ์—ฌ๋Ÿฌ ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•œ ์„ค์ •์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ณ , ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์—ญ์‹œ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ ์šฉ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ users์™€ notification_types ์‚ฌ์ด์˜ N : M ๊ด€๊ณ„๋ฅผ ํ•ด๋‹น ํ…Œ์ด๋ธ”์„ ํ†ตํ•ด ํ‘œํ˜„ํ–ˆ๋‹ค.

์ด ํ…Œ์ด๋ธ”์˜ ํ•˜๋‚˜์˜ ํ–‰์€ ํŠน์ • ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์•Œ๋ฆผ ์ข…๋ฅ˜์— ๋Œ€ํ•ด ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ˆ˜์‹  ์„ค์ •์„ ์˜๋ฏธํ•œ๋‹ค. ๋”ฐ๋ผ์„œ (user_id, notification_type_id) ์กฐํ•ฉ ์ž์ฒด๊ฐ€ ํ•˜๋‚˜์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ํ‚ค๊ฐ€ ๋œ๋‹ค.

๋ณตํ•ฉ ๊ธฐ๋ณธํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ MySQL InnoDB์˜ ํด๋Ÿฌ์Šคํ„ฐ๋“œ ์ธ๋ฑ์Šค ์—ญ์‹œ (user_id, notification_type_id) ์ˆœ์„œ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์ „์ฒด ์•Œ๋ฆผ ์„ค์ •์„ ์กฐํšŒํ•˜๋Š” ์ฃผ์š” ํŒจํ„ด์—์„œ๋Š” user_id๊ฐ€ PK์˜ ์„ ๋‘ ์ปฌ๋Ÿผ์ด๋ฏ€๋กœ ๋ณ„๋„์˜ user_id ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๊ธฐ๋ณธํ‚ค ์ธ๋ฑ์Šค๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ–ฅํ›„ ์•Œ๋ฆผ ์„ค์ •์— Push ์ˆ˜์‹  ์—ฌ๋ถ€ ์ด์™ธ์˜ ์ถ”๊ฐ€ ์†์„ฑ์ด ํ•„์š”ํ•ด์งˆ ๊ฒฝ์šฐ ํ•ด๋‹น ์‚ฌ์šฉ์ž-์•Œ๋ฆผ ์ข…๋ฅ˜ ๊ด€๊ณ„์— ์ข…์†๋˜๋Š” ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•Œ๋ฆผ ์ˆ˜์‹  ์‹œ๊ฐ„๋Œ€, ๋ฐฉํ•ด ๊ธˆ์ง€ ์‹œ๊ฐ„, ์•Œ๋ฆผ ๋นˆ๋„ ๋“ฑ์˜ ์„ค์ •์ด ํ•„์š”ํ•ด์ง„๋‹ค๋ฉด user_notification_settings์— ๊ด€๋ จ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ user_notification_settings์˜ ๊ฐœ๋ณ„ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ์ง์ ‘ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜, ํ•œ ์‚ฌ์šฉ์ž์™€ ์•Œ๋ฆผ ์ข…๋ฅ˜ ์กฐํ•ฉ์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋…๋ฆฝ์ ์ธ ์„ค์ • ๋ ˆ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค๋ฉด ํ˜„์žฌ ๋ณตํ•ฉ PK ๊ตฌ์กฐ๋ฅผ ์žฌ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋Œ€๋ฆฌํ‚ค id๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  (user_id, notification_type_id) ๋˜๋Š” ํ™•์žฅ๋œ ๋น„์ฆˆ๋‹ˆ์Šค ํ‚ค์— UNIQUE ์ œ์•ฝ์กฐ๊ฑด์„ ๋‘๋Š” ๊ตฌ์กฐ๊ฐ€ ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.


18. notification_events

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์•Œ๋ฆผ ์ด๋ฒคํŠธ
์„ค๋ช… ์„œ๋น„์Šค ๋‚ด ํŠน์ • ํ–‰์œ„๋‚˜ ์ด๋ฒคํŠธ๋กœ ์ธํ•ด ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ์˜ ์›์ธ ์ •๋ณด์™€ ๊ณตํ†ต ์•Œ๋ฆผ ๋‚ด์šฉ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์•Œ๋ฆผ ์ข…๋ฅ˜, ์•Œ๋ฆผ์„ ๋ฐœ์ƒ์‹œํ‚จ ์‚ฌ์šฉ์ž, ๊ด€๋ จ ๋ฆฌ์†Œ์Šค ๋ฐ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์ œ๋ชฉ๊ณผ ๋‚ด์šฉ์„ ์ €์žฅํ•˜๊ณ , ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ด๋ฒคํŠธ๋ฅผ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ์‹ค์ œ ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ์™€ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ notification_types 1 : N notification_events,
users 1 : N notification_events (actor_user_id ๊ธฐ์ค€),
notification_events 1 : N notifications
PK id
FK notification_type_id โ†’ notification_types.id,
actor_user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
notification_type_id BIGINT NOT NULL FK โ†’ notification_types.id
actor_user_id BIGINT NULL FK โ†’ users.id
resource_type VARCHAR(30) NULL -
resource_id BIGINT NULL -
title VARCHAR(255) NOT NULL -
content VARCHAR(500) NOT NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์•Œ๋ฆผ ์ด๋ฒคํŠธ๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ด๋ฒคํŠธ๋กœ ์—ฌ๋Ÿฌ ์ˆ˜์‹ ์ž์˜ ์•Œ๋ฆผ์ด ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๊ณ , notifications์—์„œ ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ๊ณตํ†ต์œผ๋กœ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋…๋ฆฝ์ ์ธ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์„œ๋น„์Šค ๋‚ด ์ฃผ์š” ์‹๋ณ„์ž์™€ ํƒ€์ž…์„ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
notification_type_id ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ์˜ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ฐ’ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ง์ ‘ ์ €์žฅํ•˜์ง€ ์•Š๊ณ  notification_types์˜ ์‹๋ณ„์ž๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์•Œ๋ฆผ ์ข…๋ฅ˜์˜ ์ด๋ฆ„, ์„ค์ • ๊ฐ€๋Šฅ ์—ฌ๋ถ€, ํ™œ์„ฑ ์ƒํƒœ ๋“ฑ์„ ์ค‘์•™์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
actor_user_id ์•Œ๋ฆผ ๋ฐœ์ƒ์˜ ์›์ธ์ด ๋œ ์‚ฌ์šฉ์ž ์‹๋ณ„์ž ์นœ๊ตฌ ๊ฐ€์ž…, ์ต๋ช… ๋ฉ”์‹œ์ง€ ๋“ฑ ํŠน์ • ์‚ฌ์šฉ์ž์˜ ํ–‰์œ„๋กœ ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ์˜ ํ–‰์œ„์ž๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ์‹œ์Šคํ…œ ์•Œ๋ฆผ์ฒ˜๋Ÿผ ํŠน์ • ํ–‰์œ„์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
resource_type ์•Œ๋ฆผ๊ณผ ๊ด€๋ จ๋œ ์›๋ณธ ๋ฆฌ์†Œ์Šค์˜ ์ข…๋ฅ˜ ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”์—์„œ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ, ์ผ์ •, ์‚ฌ์šฉ์ž ๋“ฑ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฆฌ์†Œ์Šค ์ข…๋ฅ˜๋ฅผ ๋ฌธ์ž์—ด๋กœ ์ €์žฅํ•œ๋‹ค. ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค ์ข…๋ฅ˜ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•ด DB ENUM ๋Œ€์‹  VARCHAR๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
resource_id ์•Œ๋ฆผ๊ณผ ๊ด€๋ จ๋œ ์›๋ณธ ๋ฆฌ์†Œ์Šค์˜ ์‹๋ณ„์ž resource_type์—์„œ ์ง€์ •ํ•œ ๋ฆฌ์†Œ์Šค์˜ ์‹๋ณ„์ž๋ฅผ ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ์„ ์„ ํƒํ–ˆ์„ ๋•Œ ๊ด€๋ จ ํ™”๋ฉด์ด๋‚˜ ๋ฐ์ดํ„ฐ๋กœ ์ด๋™ํ•˜๋Š” ๋ฐ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฆฌ์†Œ์Šค๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ์•Œ๋ฆผ์„ ๊ณ ๋ คํ•ด NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
title ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์•Œ๋ฆผ ์ œ๋ชฉ ์•Œ๋ฆผ ์ƒ์„ฑ ๋‹น์‹œ์˜ ์ œ๋ชฉ์„ ๊ทธ๋Œ€๋กœ ๋ณด์กดํ•˜๊ณ  ๋น ๋ฅด๊ฒŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ„๋„์˜ ๋ฌธ์ž์—ด ์ปฌ๋Ÿผ์œผ๋กœ ์ €์žฅํ•œ๋‹ค.
content ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ์•Œ๋ฆผ ๋‚ด์šฉ ์•Œ๋ฆผ์˜ ๊ฐ„๋‹จํ•œ ์„ค๋ช…์„ ์ €์žฅํ•˜๋ฉฐ ํ˜„์žฌ ์„œ๋น„์Šค์—์„œ ์•Œ๋ฆผ ๋ณธ๋ฌธ์˜ ์ตœ๋Œ€ ๊ธธ์ด๊ฐ€ ์ œํ•œ์ ์ธ ์งง์€ ๋ฌธ์ž์—ด์ด๋ผ๋Š” ์ ์„ ๊ณ ๋ คํ•ด VARCHAR(500)์„ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ์•Œ๋ฆผ ์ด๋ฒคํŠธ๊ฐ€ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์‹ค์ œ ์•Œ๋ฆผ์˜ ๋ฐœ์ƒ ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ๊ทœ์น™๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์•Œ๋ฆผ ์ด๋ฒคํŠธ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ ์ œ๋ชฉ, ๋‚ด์šฉ ๋˜๋Š” ๊ด€๋ จ ์ •๋ณด๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒฝ์šฐ ์ตœ์ข… ์ˆ˜์ • ์‹œ์ ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
deleted_at ์•Œ๋ฆผ ์ด๋ฒคํŠธ๋ฅผ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œํ•œ ์‹œ๊ฐ ์ด๋ฏธ ์ƒ์„ฑ๋œ notifications์™€์˜ ์ฐธ์กฐ ๊ด€๊ณ„๋ฅผ ์œ ์ง€ํ•˜๋ฉด์„œ ํ•ด๋‹น ์ด๋ฒคํŠธ๋ฅผ ์‹ ๊ทœ ์ฒ˜๋ฆฌ ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•  ์ˆ˜ ์žˆ๋„๋ก Soft Delete ์šฉ๋„๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

notification_events๋Š” ์•Œ๋ฆผ์˜ ๋ฐœ์ƒ ์›์ธ ๋ฐ ๊ณตํ†ต ์ •๋ณด์™€ ์‹ค์ œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ๊ฐœ๋ณ„ ์•Œ๋ฆผ ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

๊ธฐ์กด์ฒ˜๋Ÿผ notifications ํ…Œ์ด๋ธ”์—์„œ ์•Œ๋ฆผ ์ข…๋ฅ˜, ๋ฐœ์‹  ์‚ฌ์šฉ์ž, ์›๋ณธ ์ด๋ฒคํŠธ, ์ œ๋ชฉ ๋ฐ ๋‚ด์šฉ์„ ๋ชจ๋‘ ์ง์ ‘ ๊ด€๋ฆฌํ•˜๋ฉด ๋™์ผํ•œ ์ด๋ฒคํŠธ๋กœ ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ์ด ์ƒ์„ฑ๋˜๋Š” ๊ฒฝ์šฐ ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ˆ˜์‹ ์ž ์ˆ˜๋งŒํผ ๋ฐ˜๋ณต ์ €์žฅ๋  ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์•Œ๋ฆผ์˜ ๋ฐœ์ƒ ์›์ธ๊ณผ ๊ณตํ†ต ์ •๋ณด๋Š” notification_events์— ํ•œ ๋ฒˆ ์ €์žฅํ•˜๊ณ , ์‹ค์ œ ์ˆ˜์‹ ์ž๋ณ„ ์•Œ๋ฆผ์€ notifications์—์„œ notification_event_id๋ฅผ ์ฐธ์กฐํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

์•Œ๋ฆผ ์ข…๋ฅ˜๋Š” notification_type_id๋ฅผ ํ†ตํ•ด notification_types๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ฑ„ํŒ…, ์ด๋ฒคํŠธ, ์นœ๊ตฌ ๊ฐ€์ž… ๋“ฑ ์•Œ๋ฆผ ์ข…๋ฅ˜๊ฐ€ ์ถ”๊ฐ€๋˜๋”๋ผ๋„ notification_events์˜ ์Šคํ‚ค๋งˆ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋งˆ์Šคํ„ฐ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€๋ฅผ ํ†ตํ•ด ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

resource_type๊ณผ resource_id๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ์›๋ณธ ๋ฆฌ์†Œ์Šค๋ฅผ ํ•˜๋‚˜์˜ ๊ตฌ์กฐ๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

resource_type = 'ANONYMOUS_ROOM'
resource_id   = 100

resource_type = 'EVENT'
resource_id   = 200

resource_type = 'USER'
resource_id   = 300

์ด ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•Œ๋ฆผ ์ข…๋ฅ˜๋งˆ๋‹ค anonymous_room_id, event_id, friend_id์™€ ๊ฐ™์€ Nullable FK ์ปฌ๋Ÿผ์„ ๊ณ„์† ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๋ฆฌ์†Œ์Šค ์ข…๋ฅ˜๋ฅผ ์ˆ˜์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ resource_type, resource_id ์กฐํ•ฉ์€ ์‹ค์ œ DB FK๊ฐ€ ์•„๋‹Œ ๋…ผ๋ฆฌ์ ์ธ ์ฐธ์กฐ ๊ด€๊ณ„์ด๋‹ค. ๋”ฐ๋ผ์„œ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค๊ฐ€ ์‹ค์ œ ์กด์žฌํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋ฌด๊ฒฐ์„ฑ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค๋Š” ํŠธ๋ ˆ์ด๋“œ์˜คํ”„๊ฐ€ ์žˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์•Œ๋ฆผ์ด ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ์›๋ณธ ๋ฆฌ์†Œ์Šค ์ข…๋ฅ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋”๋ผ๋„ resource_type, resource_id ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ƒˆ๋กœ์šด FK ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์กด ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜๋ฉด ๋ฆฌ์†Œ์Šค๋ณ„ ์ฐธ์กฐ ๋ฌด๊ฒฐ์„ฑ์ด ์ค‘์š”ํ•ด์ง€๊ฑฐ๋‚˜ ํŠน์ • ๋ฆฌ์†Œ์Šค์˜ ์ถ”๊ฐ€ ์†์„ฑ์„ ์•Œ๋ฆผ ์ด๋ฒคํŠธ์—์„œ ์ง์ ‘ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ์ปค์งˆ ๊ฒฝ์šฐ ์•Œ๋ฆผ ์œ ํ˜•๋ณ„ ์ƒ์„ธ ํ…Œ์ด๋ธ”์„ ๋ถ„๋ฆฌํ•˜๊ฑฐ๋‚˜ ๋ณ„๋„์˜ ์•Œ๋ฆผ ๋ฆฌ์†Œ์Šค ๋งคํ•‘ ํ…Œ์ด๋ธ”์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋‹ค.

์•Œ๋ฆผ ์ด๋ฒคํŠธ๊ฐ€ ๋Œ€๋Ÿ‰์œผ๋กœ ์ฆ๊ฐ€ํ•  ๊ฒฝ์šฐ ์•Œ๋ฆผ ์ข…๋ฅ˜๋ณ„ ์กฐํšŒ๋ฅผ ์œ„ํ•ด (notification_type_id, created_at), ํŠน์ • ์‚ฌ์šฉ์ž์— ์˜ํ•ด ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ ์กฐํšŒ๋ฅผ ์œ„ํ•ด (actor_user_id, created_at) ๋“ฑ์˜ ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์‹ค์ œ ์กฐํšŒ ํŒจํ„ด๊ณผ ์‹คํ–‰ ๊ณ„ํš์— ๋”ฐ๋ผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

19. notifications

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์•Œ๋ฆผ
์„ค๋ช… ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ์‹ค์ œ ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์ด๋ฒคํŠธ, ์‚ฌ์šฉ์ž ํ™œ๋™, ์ต๋ช… ๋Œ€ํ™” ๋“ฑ ์„œ๋น„์Šค ๋‚ด ๋‹ค์–‘ํ•œ ํ–‰์œ„๋กœ ์ธํ•ด ์ƒ์„ฑ๋œ ์•Œ๋ฆผ์„ ์ˆ˜์‹ ์ž ๊ธฐ์ค€์œผ๋กœ ์ €์žฅํ•˜๊ณ , ์•Œ๋ฆผ ์ข…๋ฅ˜ยท์ฝ์Œ ์—ฌ๋ถ€ยท์œ ํšจ๊ธฐ๊ฐ„ ๋“ฑ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ events 1 : N notifications, users 1 : N notifications (sender_user_id ๊ธฐ์ค€),
users 1 : N notifications (receiver_user_id ๊ธฐ์ค€),
anonymous_rooms 1 : N notifications, notification_types 1 : N notifications
PK id
FK event_id โ†’ events.id, sender_user_id โ†’ users.id,
receiver_user_id โ†’ users.id, anonymous_room_id โ†’ anonymous_rooms.id,
notification_type_id โ†’ notification_types.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
event_id BIGINT NULL FK โ†’ events.id
sender_user_id BIGINT NULL FK โ†’ users.id
receiver_user_id BIGINT NOT NULL FK โ†’ users.id
anonymous_room_id BIGINT NULL FK โ†’ anonymous_rooms.id
notification_type_id BIGINT NOT NULL FK โ†’ notification_types.id
title VARCHAR(255) NOT NULL -
content VARCHAR(500) NULL -
read_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
expires_at DATETIME(6) NOT NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์•Œ๋ฆผ์„ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ๊ฐ ์•Œ๋ฆผ์€ ๋…๋ฆฝ์ ์ธ ๋ฐ์ดํ„ฐ๋กœ ์ƒ์„ฑ๋˜๊ณ  ์กฐํšŒยท์ฝ์Œ ์ฒ˜๋ฆฌ ๋“ฑ์˜ ๋Œ€์ƒ์ด ๋˜๋ฏ€๋กœ ๋‹จ์ผ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด ์ฃผ์š” ์‹๋ณ„์ž ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
event_id ํ•ด๋‹น ์•Œ๋ฆผ์„ ๋ฐœ์ƒ์‹œํ‚จ ์ด๋ฒคํŠธ์˜ ์‹๋ณ„์ž ์ƒ์ผ, ๊ธฐ๋…์ผ, ์ผ์ • ๋“ฑ์˜ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•Œ๋ฆผ์„ ์›๋ณธ ์ด๋ฒคํŠธ์™€ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
๋ชจ๋“  ์•Œ๋ฆผ์ด ์ด๋ฒคํŠธ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
sender_user_id ์•Œ๋ฆผ์„ ๋ฐœ์ƒ์‹œํ‚จ ์‚ฌ์šฉ์ž ๋˜๋Š” ๋ฐœ์‹  ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ์นœ๊ตฌ ๊ฐ€์ž…, ์ฝ• ์ฐŒ๋ฅด๊ธฐ, ๋ฉ”์‹œ์ง€ ๋“ฑ ์‚ฌ์šฉ์ž ํ–‰๋™์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ์•Œ๋ฆผ์—์„œ ๋ฐœ์‹ ์ž๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
์‹œ์Šคํ…œ ๋˜๋Š” ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ์•Œ๋ฆผ์—์„œ๋Š” ๋ฐœ์‹  ์‚ฌ์šฉ์ž๊ฐ€ ์—†์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
receiver_user_id ์•Œ๋ฆผ์„ ์ˆ˜์‹ ํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ๋ชจ๋“  ์•Œ๋ฆผ์€ ํŠน์ • ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๋ฏ€๋กœ ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•ด์•ผ ํ•˜๋ฉฐ users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
anonymous_room_id ์ต๋ช… ๋Œ€ํ™”์™€ ๊ด€๋ จ๋œ ์•Œ๋ฆผ์˜ ๋Œ€ํ™”๋ฐฉ ์‹๋ณ„์ž ์ต๋ช… ์งˆ๋ฌธ์ด๋‚˜ ๋‹ต๋ณ€ ๋“ฑ ์ต๋ช… ๋Œ€ํ™”์—์„œ ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ์„ ํ•ด๋‹น ๋Œ€ํ™”๋ฐฉ๊ณผ ์—ฐ๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ, ์ผ๋ฐ˜ ์•Œ๋ฆผ์—์„œ๋Š” ํ•„์š”ํ•˜์ง€ ์•Š์•„ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
notification_type_id ์•Œ๋ฆผ์˜ ์ข…๋ฅ˜๋ฅผ ์‹๋ณ„ํ•˜๋Š” ์‹๋ณ„์ž ์•Œ๋ฆผ ์ข…๋ฅ˜ ์ž์ฒด์˜ ์†์„ฑ๊ณผ ์ •์ฑ…์€ notification_types์—์„œ ๊ด€๋ฆฌํ•˜๊ณ , ์‹ค์ œ ์•Œ๋ฆผ์—์„œ๋Š” ํ•ด๋‹น ๋งˆ์Šคํ„ฐ ๋ฐ์ดํ„ฐ์˜ ์‹๋ณ„์ž๋งŒ ์ฐธ์กฐํ•˜๋„๋ก ํ•œ๋‹ค.
title ์•Œ๋ฆผ ๋ชฉ๋ก์— ํ‘œ์‹œ๋˜๋Š” ์ œ๋ชฉ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ๋˜๋Š” ๋น„๊ต์  ์งง์€ ๋ฌธ์ž์—ด์ด๋ฏ€๋กœ VARCHAR(255)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
content ์•Œ๋ฆผ์˜ ๊ฐ„๋‹จํ•œ ์ƒ์„ธ ๋‚ด์šฉ ์•Œ๋ฆผ ๋ชฉ๋ก์—์„œ ์ œ๋ชฉ๊ณผ ํ•จ๊ป˜ ํ‘œ์‹œํ•  ๋ณด์กฐ ์„ค๋ช…์„ ์ €์žฅํ•˜๋ฉฐ, ์งง์€ ์•ˆ๋‚ด ๋ฌธ๊ตฌ ์ˆ˜์ค€์œผ๋กœ ์ œํ•œํ•˜๊ธฐ ์œ„ํ•ด VARCHAR(500)์„ ์‚ฌ์šฉํ•œ๋‹ค.
๋‚ด์šฉ์ด ํ•„์š” ์—†๋Š” ์œ ํ˜•์„ ๊ณ ๋ คํ•˜์—ฌ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
read_at ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์•Œ๋ฆผ์„ ์ฝ์€ ์‹œ๊ฐ NULL์ด๋ฉด ์ฝ์ง€ ์•Š์€ ์•Œ๋ฆผ, ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ์ฝ์€ ์•Œ๋ฆผ์œผ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ฝ์€ ์ •ํ™•ํ•œ ์‹œ์ ๊นŒ์ง€ ํ•จ๊ป˜ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.
created_at ์•Œ๋ฆผ์ด ์ƒ์„ฑ๋œ ์‹œ๊ฐ ์•Œ๋ฆผ ๋ชฉ๋ก์˜ ์ตœ์‹ ์ˆœ ์ •๋ ฌ ๋ฐ ์ƒ์„ฑ ์‹œ์  ๊ธฐ๋ก์— ์‚ฌ์šฉํ•˜๋ฉฐ, ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
expires_at ํ•ด๋‹น ์•Œ๋ฆผ์˜ ์œ ํšจ๊ธฐ๊ฐ„์ด ์ข…๋ฃŒ๋˜๋Š” ์‹œ๊ฐ ์ผ์ • ๊ธฐ๊ฐ„ ์ดํ›„ ๋…ธ์ถœ ๋˜๋Š” ์ฒ˜๋ฆฌ ๋Œ€์ƒ์—์„œ ์ œ์™ธํ•ด์•ผ ํ•˜๋Š” ์•Œ๋ฆผ์˜ ๋งŒ๋ฃŒ ์‹œ์ ์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

notifications๋Š” ์‹ค์ œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ƒ์„ฑ๋œ ๊ฐœ๋ณ„ ์•Œ๋ฆผ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค. ํ•˜๋‚˜์˜ ์•Œ๋ฆผ ์ข…๋ฅ˜์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์‹ค์ œ ์•Œ๋ฆผ์ด ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ notification_types์™€ ๋ถ„๋ฆฌํ•˜๊ณ  notification_type_id๋ฅผ ํ†ตํ•ด ์ฐธ์กฐํ•˜๋„๋ก ๊ตฌ์„ฑํ–ˆ๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” id ๋‹จ์ผ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค. notifications์˜ ๊ฐ ํ–‰์€ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ๋˜๋Š” ํ•˜๋‚˜์˜ ๋…๋ฆฝ์ ์ธ ์•Œ๋ฆผ์„ ์˜๋ฏธํ•˜๋ฉฐ, ๋™์ผํ•œ ์ด๋ฒคํŠธ๋‚˜ ๋™์ผํ•œ ์‚ฌ์šฉ์ž ๊ฐ„ ํ–‰์œ„์—์„œ๋„ ์—ฌ๋Ÿฌ ์•Œ๋ฆผ์ด ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ receiver_user_id, notification_type_id ๋“ฑ์˜ ์กฐํ•ฉ๋งŒ์œผ๋กœ๋Š” ๊ฐ ์•Œ๋ฆผ์„ ์œ ์ผํ•˜๊ฒŒ ์‹๋ณ„ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ๋…๋ฆฝ์ ์ธ ์‹๋ณ„์ž๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๋˜ํ•œ ์•Œ๋ฆผ ์ฝ์Œ ์ฒ˜๋ฆฌ์™€ ์•Œ๋ฆผ ์ƒ์„ธ ์กฐํšŒ ๋“ฑ์˜ API์—์„œ ํŠน์ • ์•Œ๋ฆผ ํ•œ ๊ฑด์„ ์ง์ ‘ ์‹๋ณ„ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์œผ๋ฏ€๋กœ ๋‹จ์ผ id๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญ ๊ฒฝ๋กœ ๋ฐ ORM ๋งคํ•‘์„ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

event_id, sender_user_id, anonymous_room_id๋Š” ๋ชจ๋‘ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค. ์ด๋Š” ํ•˜๋‚˜์˜ ์•Œ๋ฆผ์ด ๋ชจ๋“  ์›๋ณธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋™์‹œ์— ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋ฒคํŠธ ์•Œ๋ฆผ์€ event_id๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ์‚ฌ์šฉ์ž ํ–‰๋™ ๊ธฐ๋ฐ˜ ์•Œ๋ฆผ์€ sender_user_id๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ต๋ช… ๋Œ€ํ™” ๊ด€๋ จ ์•Œ๋ฆผ์€ anonymous_room_id๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

receiver_user_id๋Š” NOT NULL๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ์•Œ๋ฆผ์€ ์ตœ์ข…์ ์œผ๋กœ ํŠน์ • ์‚ฌ์šฉ์ž์˜ ์•Œ๋ฆผ ๋ชฉ๋ก์— ๋…ธ์ถœ๋˜๋Š” ๋ฐ์ดํ„ฐ์ด๋ฏ€๋กœ ์–ด๋–ค ์‚ฌ์šฉ์ž๊ฐ€ ์•Œ๋ฆผ์„ ๋ฐ›๋Š”์ง€ ๋ฐ˜๋“œ์‹œ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

์•Œ๋ฆผ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฆ๊ฐ€ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž์˜ ์•Œ๋ฆผ ๋ชฉ๋ก ์กฐํšŒ๊ฐ€ ์ฃผ์š” ์กฐํšŒ ํŒจํ„ด์ด ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์œผ๋ฏ€๋กœ (receiver_user_id, created_at) ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฝ์ง€ ์•Š์€ ์•Œ๋ฆผ ์กฐํšŒ๊ฐ€ ๋นˆ๋ฒˆํ•  ๊ฒฝ์šฐ receiver_user_id, read_at, created_at์„ ํ™œ์šฉํ•˜๋Š” ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์‹ค์ œ ์ฟผ๋ฆฌ์™€ ์‹คํ–‰ ๊ณ„ํš์„ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

expires_at ๊ธฐ์ค€์œผ๋กœ ๋งŒ๋ฃŒ ์•Œ๋ฆผ์„ ์ •๋ฆฌํ•˜๋Š” ๋ฐฐ์น˜ ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜๋Š” ๊ฒฝ์šฐ ๋งŒ๋ฃŒ ๋ฐ์ดํ„ฐ ํƒ์ƒ‰ ์„ฑ๋Šฅ์„ ์œ„ํ•ด expires_at ์ธ๋ฑ์Šค ์ถ”๊ฐ€๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

์•Œ๋ฆผ ์ƒ์„ฑ์˜ ์ค‘๋ณต ๋ฐฉ์ง€๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์›๋ณธ ์ด๋ฒคํŠธ์˜ ์‹๋ณ„์ž์™€ ์•Œ๋ฆผ ์ข…๋ฅ˜ ๋“ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ณ„๋„์˜ deduplication_key๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹๋„ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.


20. anonymous_rooms

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ต๋ช… ๋Œ€ํ™”๋ฐฉ
์„ค๋ช… ํŠน์ • ์ƒํ’ˆ์— ๋Œ€ํ•ด ์งˆ๋ฌธ์ž์™€ ์ˆ˜์‹ ์ž๊ฐ€ ์ต๋ช…์œผ๋กœ ๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๋Š” ๋Œ€ํ™”๋ฐฉ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์ต๋ช… ์งˆ๋ฌธ ๊ธฐ๋Šฅ์—์„œ ๋Œ€ํ™”์˜ ์ฐธ์—ฌ์ž์™€ ๋Œ€์ƒ ์ƒํ’ˆ์„ ์—ฐ๊ฒฐํ•˜๊ณ , ์ต๋ช… ๋ฉ”์‹œ์ง€ ๋ฐ ๊ด€๋ จ ์•Œ๋ฆผ์ด ๋™์ผํ•œ ๋Œ€ํ™” ๋‹จ์œ„๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ products 1 : N anonymous_rooms, users 1 : N anonymous_rooms (questioner_user_id ๊ธฐ์ค€),
users 1 : N anonymous_rooms (recipient_user_id ๊ธฐ์ค€),
anonymous_rooms 1 : N anonymous_messages, anonymous_rooms 1 : N notifications
PK id
FK product_id โ†’ products.id, questioner_user_id โ†’ users.id, recipient_user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
product_id BIGINT NOT NULL FK โ†’ products.id , UK
questioner_user_id BIGINT NOT NULL FK โ†’ users.id , UK
recipient_user_id BIGINT NOT NULL FK โ†’ users.id
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
opened_at DATETIME(6) NULL -
expires_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์„ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ์ต๋ช… ๋Œ€ํ™”๋ฐฉ ์ž์ฒด๊ฐ€ ๋ฉ”์‹œ์ง€์™€ ์•Œ๋ฆผ ๋“ฑ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ฐธ์กฐ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ์ด๋ฏ€๋กœ ๋‹จ์ผ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด ์ฃผ์š” ์‹๋ณ„์ž ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
product_id ์ต๋ช… ์งˆ๋ฌธ์˜ ๋Œ€์ƒ์ด ๋˜๋Š” ์ƒํ’ˆ ์‹๋ณ„์ž ์ต๋ช… ๋Œ€ํ™”๊ฐ€ ํŠน์ • ์ƒํ’ˆ์— ๋Œ€ํ•œ ์งˆ๋ฌธ์„ ์ค‘์‹ฌ์œผ๋กœ ์ƒ์„ฑ๋˜๋ฏ€๋กœ ํ•ด๋‹น ์ƒํ’ˆ์„ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด products.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
questioner_user_id ์ต๋ช… ์งˆ๋ฌธ์„ ์‹œ์ž‘ํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ์งˆ๋ฌธ์ž์˜ ์‹ค์ œ ์‹๋ณ„ ์ •๋ณด๋Š” ์„œ๋น„์Šค ๋‚ด๋ถ€์—์„œ ๋ฉ”์‹œ์ง€ ์ฒ˜๋ฆฌ ๋ฐ ๊ถŒํ•œ ๊ฒ€์ฆ์„ ์œ„ํ•ด ํ•„์š”ํ•˜๋ฏ€๋กœ users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
recipient_user_id ์ต๋ช… ์งˆ๋ฌธ์„ ์ „๋‹ฌ๋ฐ›๋Š” ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ์งˆ๋ฌธ์„ ์ˆ˜์‹ ํ•˜๊ณ  ๋‹ต๋ณ€ํ•  ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
created_at ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์ด ์ƒ์„ฑ๋œ ์‹œ๊ฐ ๋Œ€ํ™”๋ฐฉ ์ƒ์„ฑ ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ๊ทœ์น™๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
opened_at ์ˆ˜์‹ ์ž๊ฐ€ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์„ ์ตœ์ดˆ๋กœ ํ™•์ธํ•œ ์‹œ๊ฐ ์•„์ง ๋Œ€ํ™”๋ฐฉ์„ ํ™•์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ์™€ ํ™•์ธํ•œ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉด์„œ ์ตœ์ดˆ ํ™•์ธ ์‹œ์ ๋„ ํ•จ๊ป˜ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋„๋ก NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
expires_at ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์˜ ์œ ํšจ๊ธฐ๊ฐ„์ด ์ข…๋ฃŒ๋˜๋Š” ์‹œ๊ฐ ์ต๋ช… ์งˆ๋ฌธ์˜ ์ด์šฉ ๊ฐ€๋Šฅ ๊ธฐ๊ฐ„์„ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ, ๋งŒ๋ฃŒ ์ •์ฑ…์ด ์ ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ•˜๋‚˜์˜ ๋Œ€ํ™”๋ฐฉ์—๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ anonymous_messages๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ต๋ช… ์งˆ๋ฌธ ๋˜๋Š” ๋‹ต๋ณ€์œผ๋กœ ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ ์—ญ์‹œ ํŠน์ • ์ต๋ช… ๋Œ€ํ™”๋ฐฉ๊ณผ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฉ”์‹œ์ง€ ๋ฐ์ดํ„ฐ์™€ ๋ณ„๋„๋กœ ๋Œ€ํ™”๋ฐฉ ์ž์ฒด๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. ์งˆ๋ฌธ์ž, ์ˆ˜์‹ ์ž, ์ƒํ’ˆ์˜ ์กฐํ•ฉ๋งŒ์œผ๋กœ๋„ ์–ด๋–ค ๊ด€๊ณ„์˜ ๋Œ€ํ™”์ธ์ง€ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋™์ผํ•œ ์งˆ๋ฌธ์ž๊ฐ€ ๋™์ผํ•œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋™์ผํ•œ ์ƒํ’ˆ์„ ๋Œ€์ƒ์œผ๋กœ ์„œ๋กœ ๋‹ค๋ฅธ ์‹œ์ ์— ์—ฌ๋Ÿฌ ์ต๋ช… ๋Œ€ํ™”๋ฅผ ์ƒ์„ฑํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•ด๋‹น ์ปฌ๋Ÿผ๋“ค์˜ ์กฐํ•ฉ์„ ํ•˜๋‚˜์˜ ๋Œ€ํ™”๋ฐฉ์„ ์œ ์ผํ•˜๊ฒŒ ์‹๋ณ„ํ•˜๋Š” ์ž์—ฐํ‚ค๋กœ ์‚ฌ์šฉํ•˜๊ธฐ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

ํ˜„์žฌ ๊ตฌ์กฐ์—์„œ๋Š” anonymous_messages.room_id์™€ notifications.anonymous_room_id๊ฐ€ anonymous_rooms.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด room_id ๋˜๋Š” anonymous_room_id ํ•˜๋‚˜๋งŒ์œผ๋กœ ํŠน์ • ๋Œ€ํ™”๋ฐฉ์„ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

questioner_user_id์™€ recipient_user_id๋Š” ๋ชจ๋‘ users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ์ต๋ช…์„ฑ์€ DB์—์„œ ์งˆ๋ฌธ์ž์˜ ์‹ ์›์„ ์ œ๊ฑฐํ•˜๋Š” ๋ฐฉ์‹์ด ์•„๋‹ˆ๋ผ ์ˆ˜์‹ ์ž์—๊ฒŒ ์งˆ๋ฌธ์ž์˜ ์‹ค์ œ ์‹๋ณ„ ์ •๋ณด๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ •์ฑ…์œผ๋กœ ๋ณด์žฅํ•œ๋‹ค.

opened_at์€ ์ตœ์ดˆ ํ™•์ธ ์‹œ๊ฐ ์ž์ฒด๋ฅผ ์ €์žฅํ•œ๋‹ค. NULL์ธ ๊ฒฝ์šฐ ์•„์ง ํ™•์ธํ•˜์ง€ ์•Š์€ ์ƒํƒœ๋กœ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๊ณ , ๊ฐ’์ด ์กด์žฌํ•˜๋ฉด ํ™•์ธ ์—ฌ๋ถ€๋ฟ ์•„๋‹ˆ๋ผ ์–ธ์ œ ๋Œ€ํ™”๋ฐฉ์„ ํ™•์ธํ–ˆ๋Š”์ง€๊นŒ์ง€ ํ•จ๊ป˜ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ค‘๋ณต ์ƒํƒœ ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

expires_at์€ ์ต๋ช… ์งˆ๋ฌธ์˜ ์œ ํšจ๊ธฐ๊ฐ„์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ๋Œ€ํ™”๋ฐฉ์„ ์ƒ์„ฑํ•  ๋•Œ ์œ ํšจ๊ธฐ๊ฐ„ ์ •์ฑ…์— ๋”ฐ๋ผ ๋งŒ๋ฃŒ ์‹œ๊ฐ์„ ๊ณ„์‚ฐํ•˜์—ฌ ์ €์žฅํ•˜๋ฉด ์กฐํšŒ ์‹œ ํ˜„์žฌ ์‹œ๊ฐ๊ณผ ๋น„๊ตํ•ด ํ™œ์„ฑํ™”๋œ ๋Œ€ํ™”๋ฐฉ๋งŒ ๋…ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ–ฅํ›„ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ ์ž์ฒด์˜ ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•ด์งˆ ๊ฒฝ์šฐ status ์ปฌ๋Ÿผ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ACTIVE, EXPIRED, CLOSED, BLOCKED ๋“ฑ์˜ ์ƒํƒœ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํ˜„์žฌ๋Š” expires_at ๋“ฑ์˜ ์‹œ๊ฐ ์ •๋ณด๋ฅผ ํ†ตํ•ด ์ƒํƒœ๋ฅผ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณ„๋„์˜ ์ƒํƒœ ์ปฌ๋Ÿผ์ด ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜์ง€๋Š” ์•Š๋‹ค.

๋Œ€ํ™”๋ฐฉ์ด ๋งŒ๋ฃŒ๋˜๋”๋ผ๋„ ๊ธฐ์กด ๋ฉ”์‹œ์ง€๋‚˜ ์•Œ๋ฆผ ๊ธฐ๋ก์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋ฌผ๋ฆฌ์ ์œผ๋กœ ๋Œ€ํ™”๋ฐฉ์„ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  expires_at์„ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉ์ž์—๊ฒŒ๋งŒ ๋…ธ์ถœ๋˜์ง€ ์•Š๋„๋ก ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํ–ฅํ›„ ๋ช…์‹œ์ ์ธ ์‚ญ์ œ ๊ธฐ๋Šฅ๊นŒ์ง€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ deleted_at์„ ์ถ”๊ฐ€ํ•˜์—ฌ Soft Delete ๊ตฌ์กฐ๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ต๋ช… ๋Œ€ํ™”๋ฐฉ ๋ชฉ๋ก ์กฐํšŒ๊ฐ€ ์ฆ๊ฐ€ํ•˜๋ฉด ์‚ฌ์šฉ์ž ์—ญํ• ์— ๋”ฐ๋ผ questioner_user_id ๋˜๋Š” recipient_user_id๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์กฐํšŒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ๋”ฐ๋ผ์„œ ์‹ค์ œ ์กฐํšŒ ํŒจํ„ด์— ๋”ฐ๋ผ (questioner_user_id, created_at) ๋˜๋Š” (recipient_user_id, created_at) ๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ถ”๊ฐ€๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋งŒ๋ฃŒ๋œ ๋Œ€ํ™”๋ฐฉ์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์น˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” expires_at ์ธ๋ฑ์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋งŒ๋ฃŒ ๋Œ€์ƒ ํƒ์ƒ‰ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.


21. anonymous_messages

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ต๋ช… ๋ฉ”์‹œ์ง€
์„ค๋ช… ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์—์„œ ์งˆ๋ฌธ์ž์™€ ์ˆ˜์‹ ์ž๊ฐ€ ์ฃผ๊ณ ๋ฐ›์€ ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์ต๋ช… ๋Œ€ํ™”๋ฐฉ๋ณ„ ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ์„ ์‹œ๊ฐ„ ์ˆœ์„œ๋Œ€๋กœ ์ €์žฅํ•˜๊ณ , ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ์žยท์ฝ์Œ ์—ฌ๋ถ€ ๋“ฑ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
ํ–ฅํ›„ ๋ฉ”์‹œ์ง€ ๋‹จ์œ„ ์‹ ๊ณ  ๋ฐ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ์—์„œ ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€๋ฅผ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ anonymous_rooms 1 : N anonymous_messages, users 1 : N anonymous_messages
PK id
FK room_id โ†’ anonymous_rooms.id, user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id VARCHAR(255) NOT NULL PK
room_id BIGINT NOT NULL FK โ†’ anonymous_rooms.id
user_id BIGINT NOT NULL FK โ†’ users.id
content VARCHAR(1000) NOT NULL -
read_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ๊ฐœ๋ณ„ ์ต๋ช… ๋ฉ”์‹œ์ง€๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ๋ฉ”์‹œ์ง€๋ฅผ ๋Œ€ํ™”๋ฐฉ ๋‚ด๋ถ€์˜ ์ˆœ์„œ๋งŒ์œผ๋กœ ์‹๋ณ„ํ•˜์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•œ ๋Œ€๋ฆฌํ‚ค์ด๋‹ค.
ํ–ฅํ›„ ๋ฉ”์‹œ์ง€ ๋‹จ์œ„ ์‹ ๊ณ ยท์ œ์žฌยท์กฐํšŒ ๋“ฑ์˜ ๊ธฐ๋Šฅ์—์„œ ํŠน์ • ๋ฉ”์‹œ์ง€๋ฅผ ์ง์ ‘ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
room_id ๋ฉ”์‹œ์ง€๊ฐ€ ์†ํ•œ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์˜ ์‹๋ณ„์ž ํ•˜๋‚˜์˜ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์— ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋˜๋ฏ€๋กœ ๊ฐ ๋ฉ”์‹œ์ง€๊ฐ€ ์–ด๋–ค ๋Œ€ํ™”์— ์†ํ•˜๋Š”์ง€ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด anonymous_rooms.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
user_id ๋ฉ”์‹œ์ง€๋ฅผ ์ž‘์„ฑํ•œ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ ๊ถŒํ•œ ๊ฒ€์ฆ ๋ฐ ์งˆ๋ฌธ์žยท์ˆ˜์‹ ์ž ๊ตฌ๋ถ„์„ ์œ„ํ•ด ์‹ค์ œ ์ž‘์„ฑ์ž์˜ ์‚ฌ์šฉ์ž ์‹๋ณ„์ž๋ฅผ ์ €์žฅํ•œ๋‹ค.
content ์‚ฌ์šฉ์ž๊ฐ€ ์ „์†กํ•œ ๋ฉ”์‹œ์ง€์˜ ๋ณธ๋ฌธ ์ต๋ช… ๋Œ€ํ™” ๋ฉ”์‹œ์ง€๋Š” ์ผ์ • ๊ธธ์ด ์ดํ•˜์˜ ๋ฌธ์ž์—ด๋กœ ์ œํ•œํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ VARCHAR(1000)์„ ์‚ฌ์šฉํ•œ๋‹ค.
read_at ์ƒ๋Œ€ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ์ฝ์€ ์‹œ๊ฐ NULL ์—ฌ๋ถ€๋ฅผ ํ†ตํ•ด ์ฝ์Œ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋ฉด์„œ ์‹ค์ œ ์ฝ์€ ์‹œ์ ๋„ ํ•จ๊ป˜ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
created_at ๋ฉ”์‹œ์ง€๊ฐ€ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ๋Œ€ํ™” ๋ฉ”์‹œ์ง€๋ฅผ ์‹œ๊ฐ„ ์ˆœ์„œ๋Œ€๋กœ ์กฐํšŒํ•˜๊ณ  ์ „์†ก ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ๋ฉ”์‹œ์ง€๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ ํ–ฅํ›„ ๋ฉ”์‹œ์ง€ ์ˆ˜์ • ๊ธฐ๋Šฅ ๋˜๋Š” ๊ด€๋ฆฌ ์ž‘์—…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ณ€๊ฒฝ ์‹œ์ ์„ ๊ธฐ๋กํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋ฉฐ, ์ˆ˜์ •๋˜์ง€ ์•Š์€ ์ดˆ๊ธฐ ์ƒํƒœ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
deleted_at ๋ฉ”์‹œ์ง€๊ฐ€ ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ๋ฉ”์‹œ์ง€ ์‚ญ์ œ ํ›„์—๋„ ์‹ ๊ณ ยท์šด์˜ ์ด๋ ฅ ๋“ฑ์˜ ํ•„์š”์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก Soft Delete ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ•˜๋‚˜์˜ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ์—์„œ๋Š” ์งˆ๋ฌธ์ž์™€ ์ˆ˜์‹ ์ž๊ฐ€ ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋Œ€ํ™”๋ฐฉ ์ •๋ณด์™€ ์‹ค์ œ ๋ฉ”์‹œ์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ 1 : N ๊ด€๊ณ„๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

๊ธฐ๋ณธํ‚ค๋Š” ๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

ํ˜„์žฌ ์„œ๋น„์Šค ๊ธฐํš์—์„œ๋Š” ์‹ ๊ณ  ๊ธฐ๋Šฅ์ด ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€๊ฐ€ ์•„๋‹Œ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ ๋‹จ์œ„๋กœ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ํ˜„์žฌ ์š”๊ตฌ์‚ฌํ•ญ๋งŒ ๊ณ ๋ คํ•˜๋ฉด ๋ฉ”์‹œ์ง€๋ฅผ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ์ง์ ‘ ์ฐธ์กฐํ•  ํ•„์š”๊ฐ€ ํฌ์ง€ ์•Š๋‹ค. ํ•˜์ง€๋งŒ ์„œ๋น„์Šค ์šด์˜ ๊ณผ์ •์—์„œ ํŠน์ • ๋ฉ”์‹œ์ง€๋งŒ์„ ์‹ ๊ณ ํ•˜๊ฑฐ๋‚˜ ์ œ์žฌํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ์ถ”๊ฐ€๋  ๊ฐ€๋Šฅ์„ฑ์„ ๊ณ ๋ คํ•˜์˜€๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ–ฅํ›„ ์‹ ๊ณ  ๊ธฐ๋Šฅ์ด ํ˜„์žฌ์˜ ๋Œ€ํ™”๋ฐฉ ๋‹จ์œ„์—์„œ ๋ฉ”์‹œ์ง€ ๋‹จ์œ„๊นŒ์ง€ ํ™•์žฅ๋  ๊ฒฝ์šฐ anonymous_messages.id๋ฅผ ์‹ ๊ณ  ๋Œ€์ƒ์˜ ์‹๋ณ„์ž๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ํ˜„์žฌ๋ถ€ํ„ฐ ๋ฉ”์‹œ์ง€๋ณ„๋Œ€๋ฆฌํ‚ค๋ฅผ ๋ถ€์—ฌํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ์กด ํ…Œ์ด๋ธ”์˜ PK ๊ตฌ์กฐ๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ์‹ ๊ณ  ํ…Œ์ด๋ธ”๊ณผ FK ๊ด€๊ณ„๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ต๋ช… ๋Œ€ํ™”์˜ ๋ฉ”์‹œ์ง€ ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•  ๊ฒฝ์šฐ ๊ฐ€์žฅ ์ฃผ์š”ํ•œ ์กฐํšŒ ํŒจํ„ด์€ ํŠน์ • ๋Œ€ํ™”๋ฐฉ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์‹œ๊ฐ„ ์ˆœ์„œ๋กœ ์กฐํšŒํ•˜๋Š” ํ˜•ํƒœ๊ฐ€ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๋‹ค. ๋”ฐ๋ผ์„œ (room_id, created_at) ๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ถ”๊ฐ€๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋™์ผํ•œ created_at์„ ๊ฐ€์ง€๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ์กด์žฌํ•  ๊ฐ€๋Šฅ์„ฑ๊นŒ์ง€ ๊ณ ๋ คํ•˜์—ฌ ์•ˆ์ •์ ์ธ ์ •๋ ฌ ๋˜๋Š” ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์ด ํ•„์š”ํ•˜๋‹ค๋ฉด (room_id, created_at, id) ํ˜•ํƒœ์˜ ์ธ๋ฑ์Šค๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ  created_at๊ณผ id๋ฅผ ํ•จ๊ป˜ ์ปค์„œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹๋„ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ ๋ฉ”์‹œ์ง€ ์ „์†ก ์žฌ์‹œ๋„๋กœ ์ธํ•œ ์ค‘๋ณต ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ํด๋ผ์ด์–ธํŠธ์—์„œ ์ƒ์„ฑํ•œ client_message_id๋ฅผ ๋ณ„๋„๋กœ ์ €์žฅํ•˜๊ณ  UNIQUE ์ œ์•ฝ์กฐ๊ฑด์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ์‹๋„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์„œ๋ฒ„๊ฐ€ ๋™์ผ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์ „๋‹ฌ๋ฐ›๋”๋ผ๋„ ๋™์ผ ๋ฉ”์‹œ์ง€๊ฐ€ ์ค‘๋ณต ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋Š” ์šฉ๋„๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


22. reports

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์‹ ๊ณ 
์„ค๋ช… ์ต๋ช… ๋Œ€ํ™”์—์„œ ๋ฐœ์ƒํ•œ ์‚ฌ์šฉ์ž ์‹ ๊ณ  ๋‚ด์—ญ๊ณผ ์‹ ๊ณ  ์ฒ˜๋ฆฌ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์‹ ๊ณ ์ž, ์‹ ๊ณ  ๋Œ€์ƒ ์‚ฌ์šฉ์ž, ์‹ ๊ณ  ๋Œ€์ƒ ๋Œ€ํ™”๋ฐฉ๊ณผ ์‹ ๊ณ  ์‚ฌ์œ ๋ฅผ ์ €์žฅํ•˜๊ณ  ์šด์˜์ž์˜ ์‹ ๊ณ  ์ฒ˜๋ฆฌ ์ƒํƒœ ๋ฐ ์Šน์ธ ์‹œ์ ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N reports (reporter_user_id ๊ธฐ์ค€),
users 1 : N reports (reported_user_id ๊ธฐ์ค€), anonymous_rooms 1 : N reports
PK id
FK reporter_user_id โ†’ users.id, reported_user_id โ†’ users.id, room_id โ†’ anonymous_rooms.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
reporter_user_id BIGINT NOT NULL FK โ†’ users.id
reported_user_id BIGINT NOT NULL FK โ†’ users.id UK
room_id BIGINT NOT NULL FK โ†’ anonymous_rooms.id UK
type VARCHAR(30) NOT NULL
reason VARCHAR(500) NULL -
status ENUM('PENDING', 'APPROVED', 'REJECTED') NOT NULL; DEFAULT 'PENDING' -
approved_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ์‹ ๊ณ  ๋‚ด์—ญ์„ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ๋™์ผํ•œ ์‚ฌ์šฉ์ž๋‚˜ ๋Œ€ํ™”๋ฐฉ์—์„œ ์—ฌ๋Ÿฌ ์‹ ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฐœ๋ณ„ ์‹ ๊ณ  ๊ฑด์„ ๋…๋ฆฝ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
reporter_user_id ์‹ ๊ณ ๋ฅผ ์š”์ฒญํ•œ ์‚ฌ์šฉ์ž ์‹๋ณ„์ž ์‹ ๊ณ  ์ฃผ์ฒด๋ฅผ ์‹๋ณ„ํ•˜๊ณ  ์ค‘๋ณต ์‹ ๊ณ  ๊ฒ€์ฆ ๋ฐ ์šด์˜ ์ฒ˜๋ฆฌ์— ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
reported_user_id ์‹ ๊ณ  ๋Œ€์ƒ ์‚ฌ์šฉ์ž์˜ ์‹๋ณ„์ž ์‹ ๊ณ ๋œ ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•˜๊ณ  ์‹ ๊ณ  ๋ˆ„์  ๋ฐ ์ œ์žฌ ํŒ๋‹จ ๋“ฑ์— ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
room_id ์‹ ๊ณ  ๋Œ€์ƒ์ด ๋˜๋Š” ์ต๋ช… ๋Œ€ํ™”๋ฐฉ ์‹๋ณ„์ž ํ˜„์žฌ ์„œ๋น„์Šค์—์„œ๋Š” ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€๊ฐ€ ์•„๋‹Œ ๋Œ€ํ™”๋ฐฉ ๋‹จ์œ„๋กœ ์‹ ๊ณ ํ•˜๋ฏ€๋กœ anonymous_rooms.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
type ์‹ ๊ณ  ์œ ํ˜• ์‹ ๊ณ  ์œ ํ˜•์€ ์„œ๋น„์Šค ์šด์˜ ๊ณผ์ •์—์„œ ์ถ”๊ฐ€ยท๋ณ€๊ฒฝ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ DB ENUM ๋Œ€์‹  VARCHAR(30)์œผ๋กœ ์ €์žฅํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ Enum์œผ๋กœ ํ—ˆ์šฉ ๊ฐ’์„ ๊ด€๋ฆฌํ•œ๋‹ค.
reason ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ์‹ ๊ณ  ์ƒ์„ธ ์‚ฌ์œ  ์ •ํ˜•ํ™”๋œ ์‹ ๊ณ  ์œ ํ˜• ์™ธ์— ์ถ”๊ฐ€ ์„ค๋ช…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ๋ฅผ ์ง€์›ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์ž์—ด๋กœ ์ €์žฅํ•˜๋ฉฐ, ์„ ํƒ ์ž…๋ ฅ์„ ๊ณ ๋ คํ•ด NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
status ์‹ ๊ณ  ์ฒ˜๋ฆฌ ์ƒํƒœ ์‹ ๊ณ  ์ฒ˜๋ฆฌ ํ๋ฆ„์„ ๊ตฌ์„ฑํ•˜๋Š” ์ƒํƒœ ๊ฐ’์€ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๊ณ  ํ—ˆ์šฉ๋˜์ง€ ์•Š์€ ์ƒํƒœ๊ฐ€ ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก DB ์ˆ˜์ค€์—์„œ ๊ฐ•์ œํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ ENUM์œผ๋กœ ๊ตฌ์„ฑํ•œ๋‹ค.
approved_at ์‹ ๊ณ ๊ฐ€ ์Šน์ธ๋œ ์‹œ๊ฐ ์Šน์ธ๋˜์ง€ ์•Š์€ ์‹ ๊ณ ์—์„œ๋Š” ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•˜๋ฉฐ, ์Šน์ธ ์—ฌ๋ถ€๋ฟ ์•„๋‹ˆ๋ผ ์‹ค์ œ ์Šน์ธ ์‹œ์ ๊นŒ์ง€ ๊ธฐ๋กํ•œ๋‹ค.
created_at ์‹ ๊ณ ๊ฐ€ ์ ‘์ˆ˜๋œ ์‹œ๊ฐ ์‹ ๊ณ  ์ƒ์„ฑ ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ํƒ€์ž…์„ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ•˜๋‚˜์˜ ๋Œ€ํ™”๋ฐฉ์ด๋‚˜ ๋™์ผํ•œ ์‚ฌ์šฉ์ž์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์‹ ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ณ  ๊ฐ๊ฐ์˜ ์‹ ๊ณ ๋Š” ๋…๋ฆฝ์ ์ธ ์ฒ˜๋ฆฌ ์ƒํƒœ๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ๊ธฐ๋ณธํ‚ค๋กœ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

ํ˜„์žฌ ์‹ ๊ณ  ๊ธฐ๋Šฅ์€ ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ์ต๋ช… ๋Œ€ํ™”๋ฐฉ ๋‹จ์œ„๋กœ ์‹ ๊ณ ํ•˜๋Š” ๊ตฌ์กฐ์ด๋ฏ€๋กœ room_id๋ฅผ ํ†ตํ•ด anonymous_rooms๋ฅผ ์ฐธ์กฐํ•œ๋‹ค. ์‹ ๊ณ  ์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ๋Š” ์‹ ๊ณ ๋ฅผ ์š”์ฒญํ•œ ์‚ฌ์šฉ์ž์™€ ์‹ ๊ณ  ๋Œ€์ƒ ์‚ฌ์šฉ์ž๋ฅผ ๋ชจ๋‘ ์‹๋ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ reporter_user_id, reported_user_id๋ฅผ ๊ฐ๊ฐ ๋ณ„๋„์˜ FK๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ํ˜„์žฌ DDL์—์„œ๋„ ๋‘ ์‚ฌ์šฉ์ž FK์™€ anonymous_rooms FK๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๋‹ค.

type๊ณผ status๋Š” ๋ชจ๋‘ ์ œํ•œ๋œ ๋ฌธ์ž์—ด ๊ฐ’์ด๋ผ๋Š” ์ ์—์„œ๋Š” ์œ ์‚ฌํ•˜์ง€๋งŒ, ๊ฐ’์˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ๊ณผ ๋น„์ฆˆ๋‹ˆ์Šค ์˜๋ฏธ๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋กœ ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

์‹ ๊ณ  ์œ ํ˜•์€ ์šด์˜ํ™˜๊ฒฝ ํ™•์žฅ์„ฑ ๊ณ ๋ คํ•ด DB ENUM์œผ๋กœ ๊ณ ์ •ํ•˜์ง€ ์•Š๊ณ  VARCHAR(30)์œผ๋กœ ์ €์žฅํ•˜๋ฉฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ฝ”๋“œ Enum์—์„œ ํ—ˆ์šฉ๋˜๋Š” ๊ฐ’์„ ๊ด€๋ฆฌํ•˜๋„๋ก ๊ตฌ์„ฑํ–ˆ๋‹ค.

status๋Š” ์‹ ๊ณ  ์œ ํ˜•๊ณผ ๋‹ฌ๋ฆฌ ์‹ ๊ณ  ์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์Šค ์ž์ฒด๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ํ˜„์žฌ DDL์—์„œ๋Š” PENDING, APPROVED, REJECTED ์„ธ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ์‹ ๊ณ ๊ฐ€ ์ ‘์ˆ˜๋˜๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ PENDING ์ƒํƒœ๋กœ ์ƒ์„ฑ๋œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ–ฅํ›„ ์ƒˆ๋กœ์šด ์‹ ๊ณ  ์œ ํ˜•์ด ์ถ”๊ฐ€๋˜๋”๋ผ๋„ type์ด VARCHAR(30)์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ DB ENUM ๋ณ€๊ฒฝ ์—†์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ Enum์— ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

์‹ ๊ณ  ์œ ํ˜•๋ณ„ ์ด๋ฆ„์ด๋‚˜ ์„ค๋ช…, ์‹ ๊ณ  ์ •์ฑ…, ์ž๋™ ์ œ์žฌ ๊ธฐ์ค€ ๋“ฑ ์ถ”๊ฐ€์ ์ธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•ด์ง€๋Š” ๊ฒฝ์šฐ์—๋Š” ํ˜„์žฌ ์ฝ”๋“œ Enum ๊ด€๋ฆฌ ๋ฐฉ์‹์„ ์œ ์ง€ํ•˜๊ธฐ๋ณด๋‹ค report_types์™€ ๊ฐ™์€ ๋งˆ์Šคํ„ฐ ํ…Œ์ด๋ธ”์„ ๋ณ„๋„๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ์•ˆ์„ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ˜„์žฌ๋Š” ๋Œ€ํ™”๋ฐฉ ๋‹จ์œ„ ์‹ ๊ณ ๋งŒ ์ง€์›ํ•˜์ง€๋งŒ ํ–ฅํ›„ ํŠน์ • ๋ฉ”์‹œ์ง€๋ฅผ ์‹ ๊ณ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ ์•ž์„œ anonymous_messages์— ๋ถ€์—ฌํ•œ ๋Œ€๋ฆฌํ‚ค๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ anonymous_message_id๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํŠน์ • ๋ฉ”์‹œ์ง€๋ฅผ ์ง์ ‘ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜ ์‹ ๊ณ  ๋Œ€์ƒ์˜ ๋ชจ๋ธ๋ง ๋ฐฉ์‹ ์ž์ฒด๋ฅผ ์žฌ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.


23. ai_chat_rooms

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… AI ๋Œ€ํ™”๋ฐฉ
์„ค๋ช… ์‚ฌ์šฉ์ž์™€ AI๊ฐ€ ์ฃผ๊ณ ๋ฐ›๋Š” ๋Œ€ํ™”๋ฅผ ํ•˜๋‚˜์˜ ๋Œ€ํ™” ๋‹จ์œ„๋กœ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  ์‚ฌ์šฉ์ž๋ณ„ AI ๋Œ€ํ™” ์„ธ์…˜์„ ์ƒ์„ฑํ•˜๊ณ  ๋Œ€ํ™” ์ƒํƒœ์™€ ์›๋ฌธ ์‚ญ์ œ ์˜ˆ์ • ์‹œ์ ์„ ๊ด€๋ฆฌํ•˜๋ฉฐ, AI ๋ฉ”์‹œ์ง€์™€ ์ทจํ–ฅ ๋ถ„์„ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์ผํ•œ ๋Œ€ํ™”๋ฐฉ ๋‹จ์œ„๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ users 1 : N ai_chat_rooms, ai_chat_rooms 1 : N ai_messages, ai_chat_rooms 1 : 1 taste_analyses
PK id
FK user_id โ†’ users.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
user_id BIGINT NOT NULL FK โ†’ users.id
status ENUM('ACTIVE', 'ANALYZING', 'COMPLETED') NOT NULL; DEFAULT 'ACTIVE' -
purge_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
deleted_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id AI ๋Œ€ํ™”๋ฐฉ์„ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ AI ๋Œ€ํ™”๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ณ  ๋ฉ”์‹œ์ง€์™€ ์ทจํ–ฅ ๋ถ„์„์—์„œ ํŠน์ • ๋Œ€ํ™”๋ฐฉ์„ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋…๋ฆฝ์ ์ธ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
user_id AI ๋Œ€ํ™”๋ฅผ ์ง„ํ–‰ํ•˜๋Š” ์‚ฌ์šฉ์ž ์‹๋ณ„์ž ์–ด๋–ค ์‚ฌ์šฉ์ž์˜ AI ๋Œ€ํ™”์ธ์ง€ ์‹๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด users.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
status AI ๋Œ€ํ™”๋ฐฉ์˜ ํ˜„์žฌ ์ง„ํ–‰ ์ƒํƒœ ๋Œ€ํ™” ์ง„ํ–‰ ์ƒํƒœ๊ฐ€ ACTIVE โ†’ ANALYZING โ†’ COMPLETED์™€ ๊ฐ™์ด ์ œํ•œ๋œ ์ƒํƒœ ์ง‘ํ•ฉ์œผ๋กœ ๊ด€๋ฆฌ๋˜๋ฏ€๋กœ DB ENUM์„ ํ†ตํ•ด ํ—ˆ์šฉ ๊ฐ€๋Šฅํ•œ ๊ฐ’์„ ์ œํ•œํ•œ๋‹ค.
purge_at AI ๋Œ€ํ™” ์›๋ฌธ์„ ์‚ญ์ œํ•  ์˜ˆ์ • ์‹œ๊ฐ ๋Œ€ํ™” ์›๋ฌธ ๋ณด๊ด€ ์ •์ฑ…์— ๋”ฐ๋ผ ์‚ญ์ œ ์˜ˆ์ • ์‹œ์ ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
์‚ญ์ œ ์˜ˆ์ • ์‹œ์ ์ด ์•„์ง ๊ฒฐ์ •๋˜์ง€ ์•Š์€ ์ƒํƒœ๋ฅผ ๊ณ ๋ คํ•˜์—ฌ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
created_at AI ๋Œ€ํ™”๋ฐฉ์ด ์ƒ์„ฑ๋œ ์‹œ๊ฐ ๋Œ€ํ™” ์ƒ์„ฑ ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ณ  ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at AI ๋Œ€ํ™”๋ฐฉ ์ •๋ณด๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ณ€๊ฒฝ๋œ ์‹œ๊ฐ ์ƒํƒœ ๋ณ€๊ฒฝ์ด๋‚˜ ์›๋ฌธ ์‚ญ์ œ ์˜ˆ์ • ์‹œ์  ๋ณ€๊ฒฝ ๋“ฑ์˜ ์ˆ˜์ • ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.
deleted_at AI ๋Œ€ํ™”๋ฐฉ์ด ๋…ผ๋ฆฌ์ ์œผ๋กœ ์‚ญ์ œ๋œ ์‹œ๊ฐ ๋Œ€ํ™”๋ฐฉ์„ ์ฆ‰์‹œ ๋ฌผ๋ฆฌ ์‚ญ์ œํ•˜์ง€ ์•Š๊ณ  ํ•„์š” ์‹œ ๋ณต๊ตฌ ๋˜๋Š” ์šด์˜ ๊ธฐ๋ก์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก Soft Delete ์šฉ๋„๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ AI์™€ ๋Œ€ํ™”๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ user_id ์ž์ฒด๋ฅผ ๊ธฐ๋ณธํ‚ค๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ๊ฐ๊ฐ์˜ ๋Œ€ํ™”๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

AI ๋Œ€ํ™”๋ฐฉ์€ ๋‹จ์ˆœํžˆ ์‚ฌ์šฉ์ž์™€ AI ์‚ฌ์ด์˜ ์—ฐ๊ฒฐ ๊ด€๊ณ„๋งŒ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ…Œ์ด๋ธ”์ด ์•„๋‹ˆ๋ผ ๋Œ€ํ™” ์ƒํƒœ, ์ƒ์„ฑ ์‹œ์ , ์›๋ฌธ ์‚ญ์ œ ์˜ˆ์ • ์‹œ์  ๋“ฑ ์ž์ฒด์ ์ธ ์ƒ๋ช…์ฃผ๊ธฐ์™€ ์ƒํƒœ๋ฅผ ๊ฐ€์ง€๋Š” ์—”ํ‹ฐํ‹ฐ์ด๋‹ค. ๋”ฐ๋ผ์„œ (user_id, ...)์™€ ๊ฐ™์€ ์ž์—ฐํ‚ค๋ฅผ ๊ตฌ์„ฑํ•˜๊ธฐ๋ณด๋‹ค ๋…๋ฆฝ์ ์ธ id๋ฅผ ํ†ตํ•ด ๋Œ€ํ™”๋ฐฉ ์ž์ฒด๋ฅผ ์‹๋ณ„ํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

์ทจํ–ฅ ๋ถ„์„์˜ ๊ฒฝ์šฐ ๊ฐœ๋ณ„ ๋ฉ”์‹œ์ง€๊ฐ€ ์•„๋‹ˆ๋ผ ํ•˜๋‚˜์˜ AI ๋Œ€ํ™”๋ฐฉ์„ ๊ธฐ์ค€์œผ๋กœ ์ˆ˜ํ–‰๋˜๋ฏ€๋กœ taste_analyses.room_id๊ฐ€ ai_chat_rooms.id๋ฅผ ์ฐธ์กฐํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ํ˜„์žฌ taste_analyses๋Š” room_id ์ž์ฒด๋ฅผ PK๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜์˜ AI ๋Œ€ํ™”๋ฐฉ์— ํ•˜๋‚˜์˜ ์ทจํ–ฅ ๋ถ„์„ ๋ฐ์ดํ„ฐ๋งŒ ์กด์žฌํ•˜๋Š” ๊ตฌ์กฐ์ด๋‹ค.

user_id๋Š” ๋Œ€ํ™”๋ฐฉ์˜ ์†Œ์œ ์ž๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ๋Œ€ํ™”๋ฐฉ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ users์™€ ai_chat_rooms๋Š” 1 : N ๊ด€๊ณ„๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค. ํ˜„์žฌ DDL์—์„œ๋„ user_id๊ฐ€ users.id๋ฅผ FK๋กœ ์ฐธ์กฐํ•œ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

๋Œ€ํ™”๋ฐฉ ์ œ๋ชฉ์ด๋‚˜ ๋งˆ์ง€๋ง‰ ๋ฉ”์‹œ์ง€ ์‹œ๊ฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ title, last_message_at ๋“ฑ์˜ ์ปฌ๋Ÿผ ์ถ”๊ฐ€๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ AI ๋Œ€ํ™” ๋ชฉ๋ก ํ™”๋ฉด์ด ์ถ”๊ฐ€๋˜์–ด ์ตœ๊ทผ ๋Œ€ํ™”๋ฐฉ์„ ์ž์ฃผ ์กฐํšŒํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด last_message_at์„ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์กฐํšŒ ์‹œ๋งˆ๋‹ค ai_messages์—์„œ MAX(created_at)์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ํšจ์œจ์ ์ผ ์ˆ˜ ์žˆ๋‹ค.

๋Œ€ํ™” ์›๋ฌธ ์‚ญ์ œ ์ •์ฑ…์ด ์‹ค์ œ ์šด์˜์— ์ ์šฉ๋˜๋Š” ๊ฒฝ์šฐ purge_at์„ ๊ธฐ์ค€์œผ๋กœ ์‚ญ์ œ ๋Œ€์ƒ ๋Œ€ํ™”๋ฐฉ์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์กฐํšŒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์œผ๋ฏ€๋กœ purge_at ์ธ๋ฑ์Šค ์ถ”๊ฐ€๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ–ฅํ›„ AI ๋Œ€ํ™” ์ƒํƒœ๊ฐ€ ACTIVE, ANALYZING, COMPLETED ์ด์™ธ์—๋„ FAILED, CANCELLED, EXPIRED ๋“ฑ์œผ๋กœ ์ž์ฃผ ํ™•์žฅ๋˜๊ณ  ๋ฐฐํฌ ๊ณผ์ •์—์„œ ์ƒํƒœ ๋ณ€๊ฒฝ์ด ๋นˆ๋ฒˆํ•ด์ง„๋‹ค๋ฉด DB ENUM ์œ ์ง€ ์—ฌ๋ถ€๋ฅผ ์žฌ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์‹œ์ ์—๋Š” VARCHAR(30) + ์ฝ”๋“œ Enum ๋ฐฉ์‹์ด ์šด์˜ ์œ ์—ฐ์„ฑ ์ธก๋ฉด์—์„œ ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.


24. ai_messages

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… AI ๋Œ€ํ™” ๋ฉ”์‹œ์ง€
์„ค๋ช… ์‚ฌ์šฉ์ž์™€ AI๊ฐ€ ๋Œ€ํ™”๋ฐฉ์—์„œ ์ฃผ๊ณ ๋ฐ›์€ ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  AI ๋Œ€ํ™”๋ฐฉ์—์„œ ๋ฐœ์ƒํ•œ ์‚ฌ์šฉ์ž ๋ฉ”์‹œ์ง€์™€ AI ์‘๋‹ต์„ ์ €์žฅํ•˜๊ณ , ๋ฉ”์‹œ์ง€ ๋ฐœ์‹  ์ฃผ์ฒด์™€ ์ƒ์„ฑ ์‹œ์ ์„ ๊ธฐ์ค€์œผ๋กœ ๋Œ€ํ™” ๋‚ด์—ญ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ai_chat_rooms 1 : N ai_messages
PK id
FK room_id โ†’ ai_chat_rooms.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
id BIGINT NOT NULL PK
room_id BIGINT NOT NULL FK โ†’ ai_chat_rooms.id
sender_type ENUM('USER', 'AI') NOT NULL -
content TEXT NOT NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
id ๋ฉ”์‹œ์ง€๋ฅผ ์‹๋ณ„ํ•˜๋Š” ๊ณ ์œ  ์‹๋ณ„์ž ํ•˜๋‚˜์˜ ๋Œ€ํ™”๋ฐฉ์—์„œ ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๊ฐ ๋ฉ”์‹œ์ง€๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์‹๋ณ„ํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
์„œ๋น„์Šค ๋‚ด ์ฃผ์š” ์‹๋ณ„์ž ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด BIGINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
room_id ๋ฉ”์‹œ์ง€๊ฐ€ ํฌํ•จ๋œ AI ๋Œ€ํ™”๋ฐฉ์˜ ์‹๋ณ„์ž ํ•˜๋‚˜์˜ ๋Œ€ํ™”๋ฐฉ์— ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์กด์žฌํ•˜๋Š” 1:N ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ai_chat_rooms.id๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.
sender_type ๋ฉ”์‹œ์ง€๋ฅผ ์ƒ์„ฑํ•œ ์ฃผ์ฒด ๋ฉ”์‹œ์ง€ ๋ฐœ์‹  ์ฃผ์ฒด๋Š” ์‚ฌ์šฉ์ž์™€ AI ๋‘ ์ข…๋ฅ˜๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ์ œํ•œ๋˜๋ฉฐ ๊ฐ’์˜ ๋ณ€๊ฒฝ ๋ฐ ํ™•์žฅ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์œผ๋ฏ€๋กœ DB ENUM์„ ์‚ฌ์šฉํ•œ๋‹ค.
content ์‚ฌ์šฉ์ž ๋˜๋Š” AI๊ฐ€ ์ „์†กํ•œ ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ AI ์‘๋‹ต์€ ๋ฉ”์‹œ์ง€ ๊ธธ์ด๊ฐ€ ๊ฐ€๋ณ€์ ์ด๊ณ  ๋น„๊ต์  ๊ธด ํ…์ŠคํŠธ๊ฐ€ ์ €์žฅ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ณ ์ •๋œ ๊ธธ์ด๋ฅผ ์ง€์ •ํ•˜๋Š” VARCHAR๋ณด๋‹ค TEXT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
created_at ๋ฉ”์‹œ์ง€๊ฐ€ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ๋Œ€ํ™” ๋ฉ”์‹œ์ง€์˜ ์ƒ์„ฑ ์‹œ์  ๊ธฐ๋ก ๋ฐ ๋ฉ”์‹œ์ง€ ์ˆœ์„œ ํŒ๋‹จ์— ์‚ฌ์šฉํ•˜๋ฉฐ ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

ํ•˜๋‚˜์˜ ai_chat_rooms์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฉ”์‹œ์ง€๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ room_id๋ฅผ FK๋กœ ๋‘์–ด ai_chat_rooms์™€ 1:N ๊ด€๊ณ„๋กœ ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

๊ฐ ๋ฉ”์‹œ์ง€๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์‹๋ณ„๋  ํ•„์š”๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ๊ธฐ๋ณธํ‚ค๋กœ ์‚ฌ์šฉํ•˜์˜€๋‹ค. (room_id, created_at) ๋“ฑ์˜ ์กฐํ•ฉ์„ ํ†ตํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ ๋™์ผ ์‹œ๊ฐ์— ์—ฌ๋Ÿฌ ๋ฉ”์‹œ์ง€๊ฐ€ ์ƒ์„ฑ๋  ๊ฐ€๋Šฅ์„ฑ์„ ์™„์ „ํžˆ ๋ฐฐ์ œํ•˜๊ธฐ ์–ด๋ ต๊ณ , ํŠน์ • ๋ฉ”์‹œ์ง€ ์กฐํšŒ ๋ฐ ํ–ฅํ›„ ๋ฉ”์‹œ์ง€ ๋‹จ์œ„ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ๋‹จ์ผ ์‹๋ณ„์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌํ•˜๋ฏ€๋กœ ๋ณ„๋„์˜ id๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๋ณ„๋„์˜ sender_user_id๋ฅผ ๋‘์ง€ ์•Š์€ ์ด์œ ๋Š” AI ๋Œ€ํ™”๋ฐฉ์˜ ์‚ฌ์šฉ์ž๋ฅผ ai_chat_rooms๋ฅผ ํ†ตํ•ด ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๊ณ , sender_type = 'USER'์ธ ๊ฒฝ์šฐ ํ•ด๋‹น ๋Œ€ํ™”๋ฐฉ์˜ ์‚ฌ์šฉ์ž๊ฐ€ ๋ฐœ์‹ ์ž๋ผ๋Š” ๊ด€๊ณ„๊ฐ€ ๋ช…ํ™•ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ˜„์žฌ์ฒ˜๋Ÿผ ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž์™€ AI๊ฐ€ ๋Œ€ํ™”ํ•˜๋Š” ๊ตฌ์กฐ์—์„œ๋Š” ๋ฉ”์‹œ์ง€๋งˆ๋‹ค ์‚ฌ์šฉ์ž ID๋ฅผ ์ค‘๋ณต ์ €์žฅํ•  ํ•„์š”์„ฑ์ด ๋‚ฎ๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

๋„๋Œ€ํ™” ๋‚ด ๋ฉ”์‹œ์ง€๊ฐ€ ์ฆ๊ฐ€ํ•  ๊ฒฝ์šฐ ํŠน์ • ๋Œ€ํ™”๋ฐฉ์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์ด ์ฃผ์š” ์กฐํšŒ ํŒจํ„ด์ด ๋˜๋ฏ€๋กœ (room_id, created_at, id) ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค. ํŠนํžˆ ๋ฉ”์‹œ์ง€ ๋ชฉ๋ก์„ ์ปค์„œ ๊ธฐ๋ฐ˜ ํŽ˜์ด์ง€๋„ค์ด์…˜์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๊ฒฝ์šฐ created_at๊ณผ id๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ผํ•œ ์ƒ์„ฑ ์‹œ๊ฐ์„ ๊ฐ€์ง„ ๋ฉ”์‹œ์ง€์— ๋Œ€ํ•ด์„œ ์กฐํšŒ ์ˆœ์„œ๋ฅผ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

AI ์‘๋‹ต ์ƒ์„ฑ ์‹คํŒจ๋‚˜ ์žฌ์ƒ์„ฑ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋  ๊ฒฝ์šฐ status, error_code, regenerated_from_message_id ๋“ฑ์˜ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ฉ”์‹œ์ง€ ์ƒ์„ฑ ์ƒํƒœ ๋ฐ ๋ฉ”์‹œ์ง€ ๊ฐ„ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.


25. taste_analyses

ํ•ญ๋ชฉ ๋‚ด์šฉ
ํ•œ๊ธ€ ํ…Œ์ด๋ธ”๋ช… ์ทจํ–ฅ ๋ถ„์„
์„ค๋ช… AI ๋Œ€ํ™” ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒ์„ฑ๋œ ์‚ฌ์šฉ์ž์˜ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ์™€ ๋ถ„์„ ์ง„ํ–‰ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋Š” ํ…Œ์ด๋ธ”
๊ธฐ๋Šฅ์  ์—ญํ•  AI ๋Œ€ํ™”๋ฐฉ์—์„œ ์ˆ˜ํ–‰๋˜๋Š” ์ทจํ–ฅ ๋ถ„์„์˜ ์ง„ํ–‰ ์ƒํƒœ, ์ž„์‹œ ๋ถ„์„ ๊ฒฐ๊ณผ ๋ฐ ์‚ฌ์šฉ์ž์˜ ๋ถ„์„ ๊ฒฐ๊ณผ ์Šน์ธ ์—ฌ๋ถ€๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.
์ฃผ์š” ๊ด€๊ณ„ ai_chat_rooms 1 : 1 taste_analyses
PK room_id
FK room_id โ†’ ai_chat_rooms.id

์ปฌ๋Ÿผ ๋ชฉ๋ก

์ปฌ๋Ÿผ๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ œ์•ฝ์กฐ๊ฑด / ๊ธฐ๋ณธ๊ฐ’ PK/FK
room_id BIGINT NOT NULL PK, FK โ†’ ai_chat_rooms.id
status ENUM('QUEUED', 'RUNNING', 'SUCCEEDED', 'FAILED') NOT NULL; DEFAULT 'QUEUED' -
progress TINYINT NOT NULL; DEFAULT 0 -
progress_message VARCHAR(255) NULL -
candidate_result JSON NULL -
decision ENUM('PENDING', 'ACCEPTED', 'REJECTED') NOT NULL; DEFAULT 'PENDING' -
completed_at DATETIME(6) NULL -
decided_at DATETIME(6) NULL -
created_at DATETIME(6) NOT NULL; DEFAULT CURRENT_TIMESTAMP(6) -
updated_at DATETIME(6) NULL -
์ปฌ๋Ÿผ๋ช… ์ปฌ๋Ÿผ ์„ค๋ช… ๋ฐ์ดํ„ฐ ํƒ€์ž… ์„ ํƒ ๊ทผ๊ฑฐ
room_id ์ทจํ–ฅ ๋ถ„์„์ด ์ˆ˜ํ–‰๋œ AI ๋Œ€ํ™”๋ฐฉ์˜ ์‹๋ณ„์ž ํ•˜๋‚˜์˜ AI ๋Œ€ํ™”๋ฐฉ์—๋Š” ํ•˜๋‚˜์˜ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ๋งŒ ์กด์žฌํ•˜๋ฏ€๋กœ ๋ณ„๋„์˜ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๋ถ€๋ชจ ํ…Œ์ด๋ธ”์˜ PK๋ฅผ ๊ทธ๋Œ€๋กœ PK ๋ฐ FK๋กœ ์‚ฌ์šฉํ•˜์—ฌ 1:1 ๊ด€๊ณ„๋ฅผ ํ‘œํ˜„ํ•œ๋‹ค.
status ์ทจํ–ฅ ๋ถ„์„ ์ž‘์—…์˜ ํ˜„์žฌ ์ง„ํ–‰ ์ƒํƒœ ๋ถ„์„ ์ž‘์—…์˜ ์ƒํƒœ๋Š” ๋Œ€๊ธฐ, ์‹คํ–‰ ์ค‘, ์„ฑ๊ณต, ์‹คํŒจ๋ผ๋Š” ์ œํ•œ๋œ ์ƒํƒœ ์ „์ด๋ฅผ ํ‘œํ˜„ํ•˜๋ฉฐ ์šด์˜ ์ค‘ ์ž„์˜์˜ ๊ฐ’์ด ์ถ”๊ฐ€๋˜๋Š” ์„ฑ๊ฒฉ์ด ์•„๋‹ˆ๋ฏ€๋กœ DB ENUM์œผ๋กœ ํ—ˆ์šฉ ๊ฐ’์„ ์ œํ•œํ•œ๋‹ค.
progress ์ทจํ–ฅ ๋ถ„์„ ์ง„ํ–‰๋ฅ  ๋ถ„์„ ์ง„ํ–‰๋ฅ ์„ 0~100 ์ˆ˜์ค€์˜ ์ž‘์€ ์ •์ˆ˜ ๊ฐ’์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฏ€๋กœ TINYINT๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
progress_message ํ˜„์žฌ ๋ถ„์„ ์ง„ํ–‰ ์ƒํƒœ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ˆ๋‚ดํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์‹œ์ง€ ์ง„ํ–‰ ๋‹จ๊ณ„์— ๋”ฐ๋ฅธ ์งง์€ ์•ˆ๋‚ด ๋ฌธ๊ตฌ๋ฅผ ์ €์žฅํ•˜๋Š” ์šฉ๋„์ด๋ฏ€๋กœ VARCHAR(255)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋ฅผ ๊ณ ๋ คํ•ด NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
candidate_result ์‚ฌ์šฉ์ž ์Šน์ธ ์ „ ์ƒ์„ฑ๋œ ์ž„์‹œ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ๋Š” ์„ ํ˜ธ ํ•ญ๋ชฉ, ๋น„์„ ํ˜ธ ํ•ญ๋ชฉ, ๊ด€์‹ฌ์‚ฌ ๋“ฑ ์—ฌ๋Ÿฌ ๊ตฌ์กฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์–ด ๊ตฌ์กฐ์  ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ๋กœ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก JSON์„ ์‚ฌ์šฉํ•œ๋‹ค.
decision ์ƒ์„ฑ๋œ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ฒฐ์ • ์ƒํƒœ ์‚ฌ์šฉ์ž์˜ ๊ฒฐ์ •์€ ๋Œ€๊ธฐ, ์Šน์ธ, ๊ฑฐ์ ˆ์ด๋ผ๋Š” ๋ช…ํ™•ํ•˜๊ณ  ์ œํ•œ๋œ ์ƒํƒœ๋งŒ ๊ฐ€์ง€๋ฉฐ ๊ฐ’์˜ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์œผ๋ฏ€๋กœ DB ENUM์„ ์‚ฌ์šฉํ•œ๋‹ค.
completed_at ์ทจํ–ฅ ๋ถ„์„ ์ž‘์—…์ด ์™„๋ฃŒ๋œ ์‹œ๊ฐ ๋ถ„์„์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์—๋Š” ์™„๋ฃŒ ์‹œ๊ฐ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•˜๋ฉฐ ์„œ๋น„์Šค ๋‚ด ์‹œ๊ฐ„ ์ปฌ๋Ÿผ๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
decided_at ์‚ฌ์šฉ์ž๊ฐ€ ๋ถ„์„ ๊ฒฐ๊ณผ์— ๋Œ€ํ•ด ์Šน์ธ ๋˜๋Š” ๊ฑฐ์ ˆ์„ ๊ฒฐ์ •ํ•œ ์‹œ๊ฐ ์‚ฌ์šฉ์ž์˜ ๊ฒฐ์ •์ด ์ด๋ฃจ์–ด์ง€๊ธฐ ์ „์—๋Š” ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ NULL์„ ํ—ˆ์šฉํ•œ๋‹ค.
created_at ์ทจํ–ฅ ๋ถ„์„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ์„ฑ๋œ ์‹œ๊ฐ ๋ถ„์„ ์ž‘์—…์˜ ์ƒ์„ฑ ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ ์„œ๋น„์Šค์˜ ์‹œ๊ฐ„ ํƒ€์ž…๊ณผ ํ†ต์ผํ•˜๊ธฐ ์œ„ํ•ด DATETIME(6)์„ ์‚ฌ์šฉํ•œ๋‹ค.
updated_at ์ทจํ–ฅ ๋ถ„์„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ˆ˜์ •๋œ ์‹œ๊ฐ ๋ถ„์„ ์ง„ํ–‰๋ฅ , ์ƒํƒœ, ๋ถ„์„ ๊ฒฐ๊ณผ ๋ฐ ์‚ฌ์šฉ์ž ๊ฒฐ์ • ๋“ฑ์ด ๋ณ€๊ฒฝ๋œ ์‹œ์ ์„ ๊ธฐ๋กํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

์„ค๊ณ„ ๊ทผ๊ฑฐ

taste_analyses๋Š” AI ๋Œ€ํ™”๋ฐฉ์˜ ๋Œ€ํ™” ๋‚ด์šฉ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š” ์ทจํ–ฅ ๋ถ„์„ ์ž‘์—…๊ณผ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ํ…Œ์ด๋ธ”์ด๋‹ค. ๋ถ„์„ ์ž‘์—…์˜ ์ง„ํ–‰ ์ƒํƒœ๋ฟ ์•„๋‹ˆ๋ผ ๋ถ„์„ ์™„๋ฃŒ ํ›„ ์ƒ์„ฑ๋œ ์ž„์‹œ ๊ฒฐ๊ณผ์™€ ์‚ฌ์šฉ์ž์˜ ์Šน์ธ ์—ฌ๋ถ€๊นŒ์ง€ ํ•˜๋‚˜์˜ ๋ถ„์„ ์ƒ๋ช…์ฃผ๊ธฐ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

ํ•˜๋‚˜์˜ ai_chat_rooms์— ๋Œ€ํ•ด ํ•˜๋‚˜์˜ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ๋งŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ํ˜„์žฌ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์ด๋ฏ€๋กœ room_id๋ฅผ taste_analyses์˜ ๊ธฐ๋ณธํ‚ค์ด์ž ์™ธ๋ž˜ํ‚ค๋กœ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

๋ณ„๋„์˜ id ๋Œ€๋ฆฌํ‚ค๋ฅผ ๋‘๋Š” ๊ฒฝ์šฐ์—๋„ ํ•˜๋‚˜์˜ ๋Œ€ํ™”๋ฐฉ์— ํ•˜๋‚˜์˜ ๋ถ„์„ ๊ฒฐ๊ณผ๋งŒ ์กด์žฌํ•œ๋‹ค๋Š” ๊ทœ์น™์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•ด ๊ฒฐ๊ตญ room_id์— UNIQUE ์ œ์•ฝ์กฐ๊ฑด์ด ์ถ”๊ฐ€๋กœ ํ•„์š”ํ•˜๋‹ค. ๋˜ํ•œ ํ˜„์žฌ taste_analyses ์ž์ฒด๋ฅผ ๋‹ค๋ฅธ ํ…Œ์ด๋ธ”์—์„œ ๋…๋ฆฝ์ ์œผ๋กœ ์ฐธ์กฐํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ์‹๋ณ„์ž๋ฅผ ์ถ”๊ฐ€ํ–ˆ์„ ๊ฒฝ์šฐ ์ด๋“์ด ํฌ์ง€ ์•Š๋‹ค.

๋”ฐ๋ผ์„œ ๋ถ€๋ชจ์ธ ai_chat_rooms.id๋ฅผ ์ž์‹์˜ PK๋กœ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ์‹๋ณ„ ๊ด€๊ณ„๋กœ ์„ค๊ณ„ํ•˜์—ฌ ai_chat_rooms์™€ taste_analyses์˜ ๊ด€๊ณ„๋ฅผ 1:1๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜์˜€๋‹ค.

ํ–ฅํ›„ ํ™•์žฅ์„ฑ

ํ˜„์žฌ๋Š” ํ•˜๋‚˜์˜ AI ๋Œ€ํ™”๋ฐฉ์— ํ•˜๋‚˜์˜ ์ทจํ–ฅ ๋ถ„์„ ๊ฒฐ๊ณผ๋งŒ ์กด์žฌํ•œ๋‹ค๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์„ ๊ธฐ์ค€์œผ๋กœ room_id๋ฅผ PK๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค.

ํ–ฅํ›„ ๋™์ผํ•œ ๋Œ€ํ™”๋ฐฉ์— ๋Œ€ํ•ด ์ทจํ–ฅ ๋ถ„์„์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์žฌ์ˆ˜ํ–‰ํ•˜๊ณ  ๊ฐ๊ฐ์˜ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ ฅ์œผ๋กœ ๋ณด์กดํ•ด์•ผ ํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์ด ์ƒ๊ธด๋‹ค๋ฉด ํ˜„์žฌ์˜ 1:1 ๊ตฌ์กฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์ด ๊ฒฝ์šฐ taste_analyses.id์™€ ๊ฐ™์€ ๋ณ„๋„์˜ ๋Œ€๋ฆฌํ‚ค๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  room_id๋ฅผ ์ผ๋ฐ˜ FK๋กœ ๋ณ€๊ฒฝํ•˜์—ฌ ai_chat_rooms 1 : N taste_analyses ๊ตฌ์กฐ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ถ„์„ ์žฌ์‹œ๋„๊ฐ€ ๋‹จ์ˆœํžˆ ์‹คํŒจํ•œ ์ž‘์—…์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋Š” ์ˆ˜์ค€์ด๊ณ  ์ด์ „ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋ณ„๋„์˜ ์ด๋ ฅ์œผ๋กœ ๋ณด์กดํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ํ˜„์žฌ ๋ ˆ์ฝ”๋“œ์˜ status, progress, candidate_result ๋“ฑ์„ ๊ฐฑ์‹ ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ˜„์žฌ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

candidate_result ๋‚ด๋ถ€ ํŠน์ • ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ƒ‰์ด๋‚˜ ์ง‘๊ณ„๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ JSON ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ ์ค‘ ์ฃผ์š” ์กฐํšŒ ๋Œ€์ƒ์€ ๋ณ„๋„ ์ปฌ๋Ÿผ ๋˜๋Š” ์ •๊ทœํ™”๋œ ํ…Œ์ด๋ธ”๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค.



API

  1. [API ์ธ์ฆ ํ๋ฆ„](API ์ธ์ฆ ํ๋ฆ„ ๋งํฌ)
  2. [API ์‘๋‹ต ๊ทœ๊ฒฉ](์‘๋‹ต ๊ทœ๊ฒฉ ๋งํฌ)
  3. [์—๋Ÿฌ ๋ฉ”์„ธ์ง€ ๋ชฉ๋ก](์—๋Ÿฌ ๋ชฉ๋ก ๋งํฌ)

๋ฐฐํฌ ํ™˜๊ฒฝ ๋ฐ CI/CD ํŒŒ์ดํ”„๋ผ์ธ

๊ด€๋ จ ๊ตฌ์„ฑ ๋ฐ ํŒŒ์ดํ”„๋ผ์ธ ์„ค๋ช… ์ž‘์„ฑ


์ฝ”๋“œ ํ’ˆ์งˆ ๊ด€๋ฆฌ ๋„๊ตฌ

์˜ˆ์‹œ

๋„๊ตฌ ์—ญํ•  ๋ชฉ์ 
.editorconfig
Checkstyle
JaCoCo
Java Test Fixtures
SonarQube
โš ๏ธ **GitHub.com Fallback** โš ๏ธ