ERD - Team-likelion-3rd-Project/likelion-devops-7th-3rd-team01 GitHub Wiki
ERD (๊ฐ๋ )
erDiagram
users ||--o{ questions : "์ง๋ฌธํ๋ค"
users ||--o{ saved_articles : "์ ์ฅํ๋ค"
users {
bigint user_id PK
varchar email UK
varchar password "BCrypt"
varchar nickname
datetime created_at
datetime updated_at
}
questions {
bigint question_id PK
bigint user_id FK
varchar query_text
varchar status "PENDING PROCESSING COMPLETED REJECTED FAILED"
text answer
json sources "๊ทผ๊ฑฐ ๊ธฐ์ฌ"
datetime saved_at "์ง๋ฌธ ์ ์ฅ(๋ณ), NULL์ด๋ฉด ์ ์ฅ ์ ํจ"
datetime created_at
datetime started_at
datetime completed_at
}
saved_articles {
bigint saved_article_id PK
bigint user_id FK
varchar title
varchar url "user_id์ ํจ๊ป UK"
varchar press
datetime published_at
datetime created_at "์ ์ฅ ์๊ฐ"
}
news_articles {
bigint article_id PK
varchar category
varchar title
text description
varchar press
varchar url UK
datetime published_at
datetime collected_at
}
news_issues {
bigint issue_id PK
varchar category
datetime generated_at "์์ฝ ๋ฐฐ์น ์๊ฐ"
int rank_no
varchar title
text summary "ํ ์ค ์์ฝ"
json key_points "ํต์ฌ ํฌ์ธํธ"
json timeline "์ ๊ฐ ํ๋ฆ (๊ทผ๊ฑฐ ๊ธฐ์ฌ๋ก ๋ง๋ฆ)"
json glossary "์ฉ์ด ํ์ด"
json sources "๊ทผ๊ฑฐ ๊ธฐ์ฌ"
boolean mock
}
-
news_articles(์์งํ ์๋ฌธ, ์ง๋ฌธ ๋ต๋ณ์ ๊ทผ๊ฑฐ ๊ฒ์ ๋์)์news_issues(30๋ถ๋ง๋ค ๋ง๋ ๋ถ์ผ๋ณ ์์ฝ)๋ ์ฌ์ฉ์์ ๋ฌด๊ดํ ํ ์ด๋ธ์ด๋ผ ๊ด๊ณ์ ์ด ์๋ค. -
์๊ฐ ์ปฌ๋ผ์ ๋ชจ๋
DATETIME(UTC ์ ์ฅ, ์๋ต ์ +09:00์ผ๋ก ๋ณํ). -
๋ฌธ์์
utf8mb4. -
๋ถ์ผ ์ฝ๋(
category):AI,IT_GENERAL,MOBILE_TELECOM,COMPUTER,INTERNET,SCIENCE(IT 6๊ฐ ๋ถ์ผ, docs/api-spec.md)
์ ์ : users
| ์ปฌ๋ผ | ํ์ | ๋น๊ณ |
|---|---|---|
user_id |
BIGINT |
PK, Auto Increment |
email |
VARCHAR(255) |
NOT NULL, UNIQUE |
password |
VARCHAR(255) |
NOT NULL, BCrypt ํด์ |
nickname |
VARCHAR(20) |
NOT NULL |
created_at |
DATETIME |
NOT NULL, Default CURRENT_TIMESTAMP |
updated_at |
DATETIME |
NOT NULL, Default CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP |
์ง๋ฌธ: questions
| ์ปฌ๋ผ | ํ์ | ๋น๊ณ |
|---|---|---|
question_id |
BIGINT |
PK, Auto Increment |
user_id |
BIGINT |
NOT NULL, FK (users.user_id) ON DELETE CASCADE |
query_text |
VARCHAR(500) |
NOT NULL |
status |
VARCHAR(20) |
NOT NULL (PENDING, PROCESSING, COMPLETED, REJECTED, FAILED) |
answer |
TEXT |
NULL |
sources |
JSON |
NULL, ๊ทผ๊ฑฐ ๊ธฐ์ฌ [{press, title, url, publishedAt}] |
saved_at |
DATETIME |
NULL, ์ง๋ฌธ ์ ์ฅ(๋ณ) ์๊ฐ. NULL์ด๋ฉด ์ ์ฅ ์ ํจ |
created_at |
DATETIME |
NOT NULL, Default CURRENT_TIMESTAMP |
started_at |
DATETIME |
NULL, ์์ปค๊ฐ ์ฒ๋ฆฌ ์์ํ ์๊ฐ (๊ธฐ๋ก์ฉ. 60์ด ํ์์์์ created_at ๊ธฐ์ค) |
completed_at |
DATETIME |
NULL |
์ธ๋ฑ์ค
(user_id, created_at): ์ง๋ฌธ ๊ธฐ๋ก ๋ชฉ๋ก, ํ๋ฃจ ์ง๋ฌธ ํ์ ์ง๊ณ(user_id, saved_at): ์ ์ฅํ ์ง๋ฌธ ๋ชฉ๋ก(status, created_at): ์ค๋๋PENDING์ฌํฌ์ , 60์ด ํ์์์ ํ์
๊ธฐ์กด
saved_questionsํ ์ด๋ธ์questions.saved_at์ผ๋ก ๋์ฒดํ๋ค. ์ง๋ฌธ 1๊ฐ์ ๋ณ์ ํ๋๋ฟ์ด๋ผ ๋ณ๋ ํ ์ด๋ธ์ด ํ์ ์๊ณ , ๊ธฐ๋ก์ ์ญ์ ํ๋ฉด ๋ณ๋ ๊ฐ์ด ์ฌ๋ผ์ง๋ ๊ท์น์ด ์ ์ ๋ก ์ง์ผ์ง๋ค.
์ ์ฅํ ๊ธฐ์ฌ: saved_articles
| ์ปฌ๋ผ | ํ์ | ๋น๊ณ |
|---|---|---|
saved_article_id |
BIGINT |
PK, Auto Increment |
user_id |
BIGINT |
NOT NULL, FK (users.user_id) ON DELETE CASCADE |
title |
VARCHAR(255) |
NOT NULL |
url |
VARCHAR(512) |
NOT NULL, http(s) ์ฃผ์๋ง |
press |
VARCHAR(100) |
NULL |
published_at |
DATETIME |
NULL |
created_at |
DATETIME |
NOT NULL, Default CURRENT_TIMESTAMP (์ ์ฅ ์๊ฐ) |
์ธ๋ฑ์ค
UNIQUE (user_id, url): ๊ฐ์ ๊ธฐ์ฌ๋ฅผ ๋ ๋ฒ ์ ์ฅํ์ง ์๋๋ค(user_id, created_at): ์ ์ฅํ ๊ธฐ์ฌ ๋ชฉ๋ก (์ต๊ทผ ์ ์ฅ ์)
๋ถ์ผ ํ์ด์ง์ ๊ทผ๊ฑฐ ๊ธฐ์ฌ ํ๋๋ฅผ ์ ์ฅํ๋ค. ์๋ณธ(
news_articles)์ 7์ผ ๋ค ์ง์์ง๋ฏ๋กnews_articles๋ฅผ ๊ฐ๋ฆฌํค์ง ์๊ณ ๋ด์ฉ์ ๋ณต์ฌํด ๋๋ค.
์์ง ๊ธฐ์ฌ: news_articles
| ์ปฌ๋ผ | ํ์ | ๋น๊ณ |
|---|---|---|
article_id |
BIGINT |
PK, Auto Increment |
category |
VARCHAR(20) |
NOT NULL, ๋ถ์ผ ์ฝ๋ |
title |
VARCHAR(255) |
NOT NULL |
description |
TEXT |
NULL, RSS๊ฐ ์ฃผ๋ ๊ธฐ์ฌ ์์ฝ๋ฌธ |
press |
VARCHAR(100) |
NULL |
url |
VARCHAR(512) |
NOT NULL, UNIQUE (๊ฐ์ ๊ธฐ์ฌ ์ค๋ณต ์์ง ๋ฐฉ์ง. ์ฌ๋ฌ ๋ถ์ผ ํผ๋์ ๊ฐ์ ๊ธฐ์ฌ๊ฐ ์์ด๋ ํ ๋ถ์ผ์๋ง ์ ์ฅ) |
published_at |
DATETIME |
NULL |
collected_at |
DATETIME |
NOT NULL, Default CURRENT_TIMESTAMP |
์ธ๋ฑ์ค
(category, collected_at)FULLTEXT (title, description) WITH PARSER ngram: ์ง๋ฌธ๊ณผ ๊ด๋ จ๋ ๊ธฐ์ฌ ๊ฒ์ (ํ๊ตญ์ด ๋์)
๋ถ์ผ ์์ฝ: news_issues
| ์ปฌ๋ผ | ํ์ | ๋น๊ณ |
|---|---|---|
issue_id |
BIGINT |
PK, Auto Increment |
category |
VARCHAR(20) |
NOT NULL, ๋ถ์ผ ์ฝ๋ |
generated_at |
DATETIME |
NOT NULL, ์์ฝ ๋ฐฐ์น ์๊ฐ (๊ฐ์ ๋ฐฐ์น์ ์ด์๋ ๊ฐ์ ๊ฐ) |
rank_no |
INT |
NOT NULL, ๋ถ์ผ ์์์์ ์์ (1๋ถํฐ, ํ์ 1~3) |
title |
VARCHAR(255) |
NOT NULL |
summary |
TEXT |
NOT NULL, ํ ์ค ์์ฝ |
key_points |
JSON |
NOT NULL, ํต์ฌ ํฌ์ธํธ ["...", ...] |
timeline |
JSON |
NOT NULL, ์ ๊ฐ ํ๋ฆ [{date, text}]. ๊ทผ๊ฑฐ ๊ธฐ์ฌ์ ๋ฐํ์ผยท์ ๋ชฉ์ผ๋ก ๋ง๋ ๋ค (AI๊ฐ ๋ง๋ค์ง ์์). ๋น ๋ฐฐ์ด ๊ฐ๋ฅ |
glossary |
JSON |
NOT NULL, ์ฉ์ด ํ์ด [{term, description}]. ๋น ๋ฐฐ์ด ๊ฐ๋ฅ |
sources |
JSON |
NOT NULL, [{press, title, url, publishedAt}] |
mock |
BOOLEAN |
NOT NULL, mock AI๋ก ๋ง๋ ์์ฝ ์ฌ๋ถ |
์ธ๋ฑ์ค: (category, generated_at). ๋ถ์ผ๋ณ๋ก ๊ฐ์ฅ ์ต๊ทผ generated_at์ ์ด์๋ค์ ๋ณด์ฌ์ค๋ค. ๊ฐฑ์ ์ ์คํจํ๋ฉด ์ ํ์ด ์๊ธฐ์ง ์์ผ๋ฏ๋ก ์ง์ ์์ฝ์ด ๊ทธ๋๋ก ๋ณด์ธ๋ค.
Redis์๋ ํยท๋ถ์ผ ์๋ต์ ์บ์๋ง ํ๋ค (ํค news:v2:home, news:v2:category:{๋ถ์ผ}, TTL 30๋ถ. ์๋ต ๋ชจ์์ด ๋ฐ๋๋ฉด ๋ฒ์ ์ ์ฌ๋ฆฐ๋ค). ์์ฝ ๋ฐฐ์น๊ฐ ๋๋๋ฉด ์บ์๋ฅผ ๋น์ ์ ์์ฝ์ด ๋ฐ๋ก ๋ณด์ธ๋ค. Redis๊ฐ ์ฃฝ์ผ๋ฉด DB์์ ๋ฐ๋ก ์ฝ๋๋ค.
๋ง์ด๊ทธ๋ ์ด์ (Flyway)
| ๋ฒ์ | ๋ด์ฉ |
|---|---|
V1 |
์ด๊ธฐ ์คํค๋ง: users, questions, saved_articles, news_articles, news_issues ๋ฐ FKยท์ธ๋ฑ์ค |
V2 |
IT 6๊ฐ ๋ถ์ผ๋ก ๋ณ๊ฒฝ: ์ ๋ถ์ผ ๋ฐ์ดํฐ(news_issues, news_articles) ์ญ์ , ์ ์ฅํ ๊ธฐ์ฌ ๊ธฐ๋ฅ ์ ์ธ๋ก saved_articles ์ญ์ |
V3 |
๋ถ์ผ ๊ฐํธ(GAME ์ ์ธ, AI ์ถ๊ฐ): GAME ๊ธฐ์ฌ ์ญ์ . ์ด์ ์์ธ ํ๋ ์ถ๊ฐ: ์ news_issues ์ญ์ ํ key_pointsยทtimelineยทglossary ์ปฌ๋ผ ์ถ๊ฐ (๋ค์ ๋ฐฐ์น๊ฐ ๋ค์ ์ฑ์) |
V4 |
์ ์ฅํ ๊ธฐ์ฌ ๊ธฐ๋ฅ ๋ณต๊ตฌ (FE ๋ง์ดํ์ด์ง): saved_articles ๋ค์ ์์ฑ |