smarteye-backend / scripts /DB /final E-R Diagram.md
AkJeond's picture
refactor(database): DB μŠ€ν‚€λ§ˆ μˆ˜μ • 및 μ„±λŠ₯ μ΅œμ ν™” λ¬Έμ„œ μΆ”κ°€
7aae924

🎯 μ΅œμ’… E-R λ‹€μ΄μ–΄κ·Έλž¨ (v2)

πŸ“Š μ΅œμ’… ν…Œμ΄λΈ” ꡬ성 (총 12개)

번호 ν…Œμ΄λΈ”λͺ… μ£Όμš” 속성 μ„€λͺ…
1 users user_id, email, name, role, api_key, password_hash μ‚¬μš©μž 계정
2 document_types doc_type_id, type_name, model_name, sorting_method λ¬Έμ„œ νƒ€μž… μ •μ˜ (μˆ˜μ •)
3 projects project_id, user_id, doc_type_id, project_name, total_pages, status ν”„λ‘œμ νŠΈ/μ„Έμ…˜
4 pages page_id, project_id, page_number, image_path, analysis_status νŽ˜μ΄μ§€ 정보
5 layout_elements element_id, page_id, class_name, bbox_x/y/width/height λ ˆμ΄μ•„μ›ƒ μš”μ†Œ (μˆ˜μ •)
6 text_contents text_id, element_id, ocr_text, ocr_confidence OCR κ²°κ³Ό
7 ai_descriptions ai_desc_id, element_id, description, ai_model AI μ„€λͺ…
8 question_groups question_group_id, page_id, anchor_element_id, start_y, end_y 문제 κ·Έλ£Ή (μˆ˜μ •)
9 question_elements qe_id, question_group_id, element_id, order_in_question 문제-μš”μ†Œ λ§€ν•‘
10 text_versions version_id, page_id, user_id, content, version_number, version_type ν…μŠ€νŠΈ 버전 관리
11 formatting_rules rule_id, doc_type_id, class_name, prefix, suffix, indent_level ν¬λ§·νŒ… κ·œμΉ™
12 combined_results combined_id, project_id, combined_text, combined_stats 톡합 λ¬Έμ„œ μΊμ‹œ

πŸ”· μ΅œμ’… E-R λ‹€μ΄μ–΄κ·Έλž¨ (μ‹œκ°ν™”)

                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                    β”‚           users                     β”‚
                                    │─────────────────────────────────────│
                                    β”‚ PK: user_id                         β”‚
                                    β”‚     email (UNIQUE)                  β”‚
                                    β”‚     name                            β”‚
                                    β”‚     role (admin/teacher/student)    β”‚
                                    β”‚     api_key (μ•”ν˜Έν™”)                β”‚
                                    β”‚     password_hash                   β”‚
                                    β”‚     created_at                      β”‚
                                    β”‚     updated_at                      β”‚
                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                β”‚
                                                β”‚ 1:N (ν•œ μ‚¬μš©μžλŠ” μ—¬λŸ¬ ν”„λ‘œμ νŠΈ 생성)
                                                ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚                    document_types (μˆ˜μ •)                      β”‚
                    │───────────────────────────────────────────────────────────────│
                    β”‚ PK: doc_type_id                                               β”‚
                    β”‚     type_name (worksheet/document/form) UNIQUE                β”‚
                    β”‚     model_name (SmartEyeSsen/DocLayout-YOLO)                  β”‚
(μˆ˜μ •)              β”‚     sorting_method (question_based/reading_order)             β”‚
                    β”‚     description                                               β”‚
                    β”‚     created_at, updated_at                                    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                β”‚
                                                β”‚ 1:N (ν•œ νƒ€μž…μœΌλ‘œ μ—¬λŸ¬ ν”„λ‘œμ νŠΈ)
                                                ↓
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚                      projects                                 β”‚
                    │───────────────────────────────────────────────────────────────│
                    β”‚ PK: project_id                                                β”‚
                    β”‚ FK: user_id β†’ users(user_id)                                  β”‚
                    β”‚ FK: doc_type_id β†’ document_types(doc_type_id)                 β”‚
                    β”‚     project_name                                              β”‚
                    β”‚     total_pages (μžλ™ 계산)                                   β”‚
                    β”‚     analysis_mode (auto/manual/hybrid)                        β”‚
                    β”‚     status (created/in_progress/completed/error)              β”‚
                    β”‚     created_at, updated_at                                    β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚                           β”‚
                                    β”‚ 1:N                       β”‚ 1:1
                                    β”‚                           β”‚
                                    ↓                           ↓
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β”‚              pages                    β”‚   β”‚      combined_results           β”‚
        │───────────────────────────────────────│   │─────────────────────────────────│
        β”‚ PK: page_id                           β”‚   β”‚ PK: combined_id                 β”‚
        β”‚ FK: project_id β†’ projects(project_id) β”‚   β”‚ FK: project_id (UNIQUE)         β”‚
        β”‚     page_number                       β”‚   β”‚     combined_text (LONGTEXT)    β”‚
        β”‚     image_path                        β”‚   β”‚     combined_stats (JSON)       β”‚
        β”‚     image_width, image_height         β”‚   β”‚     generated_at                β”‚
        β”‚     analysis_status (pending/         β”‚   β”‚     updated_at                  β”‚
        β”‚         processing/completed/error)   β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚     processing_time                   β”‚
        β”‚     created_at, analyzed_at           β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                    β”‚                       β”‚
                    β”‚ 1:N                   β”‚ 1:N
                    β”‚                       β”‚
                    ↓                       ↓
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚    layout_elements (μˆ˜μ •)        β”‚  β”‚        text_versions                 β”‚
    │────────────────────────────────│  │──────────────────────────────────────│
    β”‚ PK: element_id                 β”‚  β”‚ PK: version_id                       β”‚
    β”‚ FK: page_id β†’ pages(page_id)   β”‚  β”‚ FK: page_id β†’ pages(page_id)         β”‚
    β”‚     class_name                 β”‚  β”‚ FK: user_id β†’ users(user_id)         β”‚
    β”‚     confidence                 β”‚  β”‚     content (TEXT)                   β”‚
    β”‚     bbox_x, bbox_y             β”‚  β”‚     version_number                   β”‚
    β”‚     bbox_width, bbox_height    β”‚  β”‚     version_type (original/          β”‚
    β”‚     area (μžλ™ 계산)            β”‚  β”‚         auto_formatted/user_edited)  β”‚
    β”‚     y_position (μžλ™ 계산)      β”‚  β”‚     is_current (TRUE/FALSE)          β”‚
    β”‚     x_position (μžλ™ 계산)      β”‚  β”‚     created_at                       β”‚
(μ‚­μ œ)β”‚     (order_index)              β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
    β”‚     created_at                 β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                β”‚
                β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚ 1:1 (OCR)            β”‚ 1:1 (AI)             β”‚ 1:N (μžμ‹ μš”μ†Œ)      β”‚ 1:1 (액컀)
                β”‚                      β”‚                      β”‚                      β”‚
                ↓                      ↓                      ↓                      ↓ (관계 μΆ”κ°€)
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚   text_contents     β”‚  β”‚  ai_descriptions    β”‚  β”‚   question_elements      β”‚ β”‚ question_groups (μˆ˜μ •) β”‚
    │─────────────────────│  │─────────────────────│  │──────────────────────────│ │────────────────────────│
    β”‚ PK: text_id         β”‚  β”‚ PK: ai_desc_id      β”‚  β”‚ PK: qe_id                β”‚ β”‚ PK: question_group_id  β”‚
    β”‚ FK: element_id      β”‚  β”‚ FK: element_id      β”‚  β”‚ FK: question_group_id    β”‚ β”‚ FK: page_id            β”‚
    β”‚     (UNIQUE)        β”‚  β”‚     (UNIQUE)        β”‚  β”‚ FK: element_id           β”‚ β”‚ FK: anchor_element_id  β”‚ (μˆ˜μ •)
    β”‚     ocr_text (TEXT) β”‚  β”‚     description     β”‚  β”‚     order_in_question    β”‚ β”‚     (UNIQUE)           β”‚
    β”‚     ocr_engine      β”‚  β”‚     ai_model        β”‚  β”‚     created_at           β”‚ β”‚     start_y, end_y     β”‚
    β”‚     ocr_confidence  β”‚  β”‚     prompt_used     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚     element_count      β”‚
    β”‚     language        β”‚  β”‚     created_at      β”‚                β”‚              β”‚     created_at         β”‚
    β”‚     created_at      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                β”‚ N:1          β”‚ (μ‚­μ œ) (question_number) β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                                         β”‚              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                                    β”‚                           ↑
                                                                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                                        1:N (그룹은 μ—¬λŸ¬ μžμ‹ μš”μ†Œλ₯Ό 가짐)

                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                        β”‚              formatting_rules                       β”‚
                        │─────────────────────────────────────────────────────│
                        β”‚ PK: rule_id                                         β”‚
                        β”‚ FK: doc_type_id β†’ document_types(doc_type_id)       β”‚
                        β”‚     class_name                                      β”‚
                        β”‚     prefix, suffix                                  β”‚
                        β”‚     indent_level                                    β”‚
                        β”‚     font_size, font_weight                          β”‚
                        β”‚     created_at, updated_at                          β”‚
                        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”— 관계(Relationships) 상세 μ„€λͺ… (μˆ˜μ •)

1️⃣ users ↔ projects (1:N)

- ν•œ μ‚¬μš©μžλŠ” μ—¬λŸ¬ ν”„λ‘œμ νŠΈ 생성 κ°€λŠ₯
- ν•œ ν”„λ‘œμ νŠΈλŠ” ν•œ λͺ…μ˜ μ‚¬μš©μžμ—κ²Œλ§Œ 속함
- FK: projects.user_id β†’ users.user_id
- ON DELETE CASCADE: μ‚¬μš©μž μ‚­μ œ μ‹œ ν”„λ‘œμ νŠΈλ„ μ‚­μ œ

2️⃣ document_types ↔ projects (1:N)

- ν•œ λ¬Έμ„œ νƒ€μž…(worksheet/document)으둜 μ—¬λŸ¬ ν”„λ‘œμ νŠΈ 생성 κ°€λŠ₯
- ν•œ ν”„λ‘œμ νŠΈλŠ” ν•˜λ‚˜μ˜ λ¬Έμ„œ νƒ€μž…λ§Œ 가짐
- FK: projects.doc_type_id β†’ document_types.doc_type_id
- ON DELETE RESTRICT: νƒ€μž… μ‚¬μš© 쀑이면 μ‚­μ œ λΆˆκ°€

3️⃣ projects ↔ pages (1:N)

- ν•œ ν”„λ‘œμ νŠΈλŠ” μ—¬λŸ¬ νŽ˜μ΄μ§€ 포함
- ν•œ νŽ˜μ΄μ§€λŠ” ν•˜λ‚˜μ˜ ν”„λ‘œμ νŠΈμ—λ§Œ 속함
- FK: pages.project_id β†’ projects.project_id
- ON DELETE CASCADE: ν”„λ‘œμ νŠΈ μ‚­μ œ μ‹œ νŽ˜μ΄μ§€λ„ μ‚­μ œ
- 트리거: νŽ˜μ΄μ§€ μΆ”κ°€ μ‹œ projects.total_pages μžλ™ 증가

4️⃣ projects ↔ combined_results (1:1)

- ν•œ ν”„λ‘œμ νŠΈλŠ” ν•˜λ‚˜μ˜ 톡합 κ²°κ³Ό μΊμ‹œλ§Œ 가짐
- ν•œ 톡합 κ²°κ³ΌλŠ” ν•˜λ‚˜μ˜ ν”„λ‘œμ νŠΈμ—λ§Œ 속함
- FK: combined_results.project_id β†’ projects.project_id (UNIQUE)
- ON DELETE CASCADE: ν”„λ‘œμ νŠΈ μ‚­μ œ μ‹œ μΊμ‹œλ„ μ‚­μ œ

5️⃣ pages ↔ layout_elements (1:N)

- ν•œ νŽ˜μ΄μ§€λŠ” μ—¬λŸ¬ λ ˆμ΄μ•„μ›ƒ μš”μ†Œ 포함
- ν•œ μš”μ†ŒλŠ” ν•˜λ‚˜μ˜ νŽ˜μ΄μ§€μ—λ§Œ 속함
- FK: layout_elements.page_id β†’ pages.page_id
- ON DELETE CASCADE: νŽ˜μ΄μ§€ μ‚­μ œ μ‹œ μš”μ†Œλ„ μ‚­μ œ

6️⃣ pages ↔ text_versions (1:N)

- ν•œ νŽ˜μ΄μ§€λŠ” μ—¬λŸ¬ ν…μŠ€νŠΈ 버전 가짐 (1, 2, 3, ...)
- ν•œ 버전은 ν•˜λ‚˜μ˜ νŽ˜μ΄μ§€μ—λ§Œ 속함
- FK: text_versions.page_id β†’ pages.page_id
- ON DELETE CASCADE: νŽ˜μ΄μ§€ μ‚­μ œ μ‹œ λͺ¨λ“  버전 μ‚­μ œ
- UNIQUE KEY: (page_id, version_number) - νŽ˜μ΄μ§€ λ‚΄ 버전 번호 쀑볡 λ°©μ§€

7️⃣ layout_elements ↔ text_contents (1:1)

- ν•œ λ ˆμ΄μ•„μ›ƒ μš”μ†ŒλŠ” ν•˜λ‚˜μ˜ OCR 결과만 가짐
- ν•œ OCR κ²°κ³ΌλŠ” ν•˜λ‚˜μ˜ μš”μ†Œμ—λ§Œ 속함
- FK: text_contents.element_id β†’ layout_elements.element_id (UNIQUE)
- ON DELETE CASCADE: μš”μ†Œ μ‚­μ œ μ‹œ OCR 결과도 μ‚­μ œ

8️⃣ layout_elements ↔ ai_descriptions (1:1)

- ν•œ λ ˆμ΄μ•„μ›ƒ μš”μ†Œ(figure/table/flowchart)λŠ” ν•˜λ‚˜μ˜ AI μ„€λͺ…λ§Œ 가짐
- ν•œ AI μ„€λͺ…은 ν•˜λ‚˜μ˜ μš”μ†Œμ—λ§Œ 속함
- FK: ai_descriptions.element_id β†’ layout_elements.element_id (UNIQUE)
- ON DELETE CASCADE: μš”μ†Œ μ‚­μ œ μ‹œ AI μ„€λͺ…도 μ‚­μ œ

9️⃣ pages ↔ question_groups (1:N)

- ν•œ νŽ˜μ΄μ§€λŠ” μ—¬λŸ¬ 문제 κ·Έλ£Ή 포함
- ν•œ 문제 그룹은 ν•˜λ‚˜μ˜ νŽ˜μ΄μ§€μ—λ§Œ 속함
- FK: question_groups.page_id β†’ pages.page_id
- ON DELETE CASCADE: νŽ˜μ΄μ§€ μ‚­μ œ μ‹œ 문제 그룹도 μ‚­μ œ

πŸ”Ÿ (μ‹ κ·œ) layout_elements ↔ question_groups (1:1)

- '액컀' μš”μ†Œμ™€ '문제 κ·Έλ£Ή' κ°„μ˜ 관계
- ν•œ λ ˆμ΄μ•„μ›ƒ μš”μ†Œ(액컀)λŠ” ν•˜λ‚˜μ˜ 문제 그룹만 생성 κ°€λŠ₯
- ν•œ 문제 그룹은 ν•˜λ‚˜μ˜ 액컀 μš”μ†Œμ— μ˜ν•΄ 생성됨
- FK: question_groups.anchor_element_id β†’ layout_elements.element_id
- ON DELETE CASCADE: 액컀 μš”μ†Œ μ‚­μ œ μ‹œ, κ·Έλ£Ή 및 ν•˜μœ„ μš”μ†Œ λ§€ν•‘(question_elements)도 연쇄 μ‚­μ œ

1️⃣1️⃣ question_groups ↔ question_elements (1:N)

- '문제 κ·Έλ£Ή'κ³Ό 'μžμ‹ μš”μ†Œ' λ§€ν•‘ κ°„μ˜ 관계
- ν•œ 문제 그룹은 μ—¬λŸ¬ μžμ‹ μš”μ†Œ(ν…μŠ€νŠΈ, κ·Έλ¦Ό, 선택지 λ“±)λ₯Ό 포함
- ν•œ λ§€ν•‘ λ ˆμ½”λ“œλŠ” ν•˜λ‚˜μ˜ 문제 κ·Έλ£Ήμ—λ§Œ 속함
- FK: question_elements.question_group_id β†’ question_groups.question_group_id
- ON DELETE CASCADE: 문제 κ·Έλ£Ή μ‚­μ œ μ‹œ 맀핑도 μ‚­μ œ

1️⃣2️⃣ layout_elements ↔ question_elements (N:1)

- 'μžμ‹ μš”μ†Œ'와 'λ§€ν•‘' κ°„μ˜ 관계
- ν•œ λ ˆμ΄μ•„μ›ƒ μš”μ†Œ(μžμ‹)λŠ” ν•˜λ‚˜μ˜ 문제 κ·Έλ£Ήμ—λ§Œ 속함 (N:1)
- (ν•œ λ¬Έμ œλŠ” μ—¬λŸ¬ μžμ‹ μš”μ†Œλ₯Ό 가짐)
- FK: question_elements.element_id β†’ layout_elements.element_id
- ON DELETE CASCADE: μžμ‹ μš”μ†Œ μ‚­μ œ μ‹œ 맀핑도 μ‚­μ œ
- UNIQUE KEY: (question_group_id, element_id) - 쀑볡 λ§€ν•‘ λ°©μ§€

1️⃣3️⃣ document_types ↔ formatting_rules (1:N)

- ν•œ λ¬Έμ„œ νƒ€μž…μ€ μ—¬λŸ¬ ν¬λ§·νŒ… κ·œμΉ™ 가짐
- ν•œ κ·œμΉ™μ€ ν•˜λ‚˜μ˜ λ¬Έμ„œ νƒ€μž…μ—λ§Œ 속함
- FK: formatting_rules.doc_type_id β†’ document_types.doc_type_id
- ON DELETE CASCADE: νƒ€μž… μ‚­μ œ μ‹œ κ·œμΉ™λ„ μ‚­μ œ
- UNIQUE KEY: (doc_type_id, class_name) - νƒ€μž…λ³„ 클래슀 κ·œμΉ™ 쀑볡 λ°©μ§€