# ๐Ÿ“˜ ํ”„๋กœ์ ํŠธ ๋ช…์„ธ์„œ (Project Specification) **ํ”„๋กœ์ ํŠธ๋ช…:** VOC Notification System (๋ถ€์‚ฐ๊ตํ†ต๊ณต์‚ฌ VOC ์ˆ˜์ง‘/์•Œ๋ฆผ/๋ณด๊ณ ์„œ ์ƒ์„ฑ๊ธฐ) **๋ฒ„์ „:** v1.2 **์•„ํ‚คํ…์ฒ˜:** MVC ํŒจํ„ด (Model-View-Controller) **ํ”„๋ ˆ์ž„์›Œํฌ:** CustomTkinter (UI), DrissionPage (Scraping), SQLite (DB), ReportLab/HWP Automation (Report) --- ## ๐Ÿ—๏ธ 1. ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์š” (Architecture Overview) ์ด ํ”„๋กœ์ ํŠธ๋Š” ๋ถ€์‚ฐ๊ตํ†ต๊ณต์‚ฌ ํ™ˆํŽ˜์ด์ง€์˜ '๊ณ ๊ฐ์˜ ์†Œ๋ฆฌ(VOC)' ๊ฒŒ์‹œํŒ์„ ์ž๋™ ์ˆ˜์ง‘ํ•˜๊ณ , ํŠน์ • ํ‚ค์›Œ๋“œ/๋ถ€์„œ ๊ด€๋ จ ๊ฒŒ์‹œ๊ธ€์ด ๋ฐœ์ƒํ•˜๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ์•Œ๋ฆผ์„ ์ œ๊ณตํ•˜๋ฉฐ, ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ HWP/PDF ๋ณด๊ณ ์„œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ์Šคํฌํ†ฑ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‹ค. ### ๐Ÿ“ฆ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ (Directory Structure) ``` d:\py_train\voc_noti\app\ โ”œโ”€โ”€ main.py # ๐Ÿš€ [Entry Point] ์•ฑ ์‹คํ–‰ ์ง„์ž…์ . Controller ์ดˆ๊ธฐํ™” ๋ฐ ์‹คํ–‰. โ”œโ”€โ”€ assets\ # ๐ŸŽจ [Assets] ์•„์ด์ฝ˜, ํฐํŠธ, DLL ๋“ฑ ์ •์  ์ž์› โ”‚ โ”œโ”€โ”€ app_icon.png # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์•„์ด์ฝ˜ โ”‚ โ”œโ”€โ”€ GmarketSansTTFMedium.ttf # ์ปค์Šคํ…€ ํฐํŠธ โ”‚ โ”œโ”€โ”€ FilePathCheckerModule.dll # HWP ๋ณด์•ˆ ์Šน์ธ ๋ชจ๋“ˆ โ”‚ โ””โ”€โ”€ VOC_Sample.hwp # ๋ณด๊ณ ์„œ ํ…œํ”Œ๋ฆฟ โ”œโ”€โ”€ data\ # ๐Ÿ’พ [Data] ์„ค์ • ํŒŒ์ผ ๋ฐ DB โ”‚ โ”œโ”€โ”€ config.json # ์‚ฌ์šฉ์ž ์„ค์ • (์—ญ๋ช… ๋ฆฌ์ŠคํŠธ ๋“ฑ) โ”‚ โ”œโ”€โ”€ settings.json # ์•ฑ ์‹คํ–‰ ์„ค์ • (๋กœ๊ทธ์ธ ์ •๋ณด, ํ‚ค์›Œ๋“œ ๋“ฑ) โ”‚ โ””โ”€โ”€ voc.db # SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค โ”œโ”€โ”€ controllers\ # ๐ŸŽฎ [Controller] โ”‚ โ””โ”€โ”€ controller.py # ๋ฉ”์ธ ์ปจํŠธ๋กค๋Ÿฌ (AppController) โ”œโ”€โ”€ models\ # ๐Ÿง  [Model] โ”‚ โ””โ”€โ”€ model.py # Pydantic ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (VOCPost) โ”œโ”€โ”€ services\ # ๐Ÿ•ต๏ธ [Service] ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง โ”‚ โ”œโ”€โ”€ scraper_service.py # ์›น ์Šคํฌ๋ž˜ํ•‘ (DrissionPage) โ”‚ โ””โ”€โ”€ report_service.py # ๋ณด๊ณ ์„œ ์ƒ์„ฑ (HWP/PDF Automation) โ”œโ”€โ”€ utils\ # ๐Ÿ› ๏ธ [Utils] โ”‚ โ””โ”€โ”€ database.py # DB ์ ‘๊ทผ (DAO) โ””โ”€โ”€ view\ # ๐ŸŽจ [View] UI ๋ ˆ์ด์–ด (CustomTkinter) โ”œโ”€โ”€ __init__.py โ”œโ”€โ”€ theme.py # ํฐํŠธ(Gmarket Sans) ๋ฐ ํ…Œ๋งˆ ๊ด€๋ฆฌ โ”œโ”€โ”€ ui_utils.py # ์ž์‚ฐ ๋กœ๋” (AssetLoader) โ”œโ”€โ”€ components\ # ์žฌ์‚ฌ์šฉ ์ปดํฌ๋„ŒํŠธ โ””โ”€โ”€ dialogs\ # ๊ฐ์ข… ํŒ์—… ๋‹ค์ด์–ผ๋กœ๊ทธ ``` --- ## ๐Ÿง  2. ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (Data Model) : `VOCPost` `app/models/model.py`์— ์ •์˜๋œ Pydantic ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•œ๋‹ค. | ํ•„๋“œ๋ช… | ํƒ€์ž… | ์„ค๋ช… | |---|---|---| | `id` | `str` | ์ ‘์ˆ˜ ๋ฒˆํ˜ธ (PK) | | `title` | `str` | ๊ฒŒ์‹œ๊ธ€ ์ œ๋ชฉ | | `writer` | `str` | ์ž‘์„ฑ์ž | | `date` | `str` | ์ž‘์„ฑ ์ผ์ž | | `department` | `str` | ๋‹ด๋‹น ๋ถ€์„œ | | `is_public` | `int` | ๊ณต๊ฐœ ์—ฌ๋ถ€ (1/0) | | `status` | `str` | ์ฒ˜๋ฆฌ ์ƒํƒœ | | `content` | `str` | ๋ณธ๋ฌธ ๋‚ด์šฉ | | `answer` | `str` | ๋‹ต๋ณ€ ๋‚ด์šฉ | | `line_str` | `str` | ํ˜ธ์„  (์œ ์ถ” ์ •๋ณด) | | `train_details` | `dict` | ์—ด์ฐจ ์ƒ์„ธ ์ •๋ณด | --- ## ๐ŸŽฎ 3. ์ฃผ์š” ๊ธฐ๋Šฅ ๋ฐ ๊ตฌํ˜„ ์ƒ์„ธ (Key Features) ### 3.1 ๐Ÿ•ต๏ธโ€โ™‚๏ธ ์›น ์Šคํฌ๋ž˜ํ•‘ (`VOCScraper`) - **๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ:** `DrissionPage` - **๊ธฐ๋Šฅ:** - ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ ๋กœ๊ทธ์ธ ๋ฐ ์„ธ์…˜ ์œ ์ง€. - ๋ชฉ๋ก ํŽ˜์ด์ง€ ์ˆœํšŒ ๋ฐ ์‹ ๊ทœ/์—…๋ฐ์ดํŠธ ๊ฐ์ง€. - ์ƒ์„ธ ํŽ˜์ด์ง€ ํŒŒ์‹ฑ (๋ณธ๋ฌธ, ๋‹ต๋ณ€). ### 3.2 ๐Ÿ“„ ๋ณด๊ณ ์„œ ์ƒ์„ฑ (`ReportService`) - **HWP ๋ณด๊ณ ์„œ:** - **๋ณด์•ˆ ๋ชจ๋“ˆ:** `app/assets/FilePathCheckerModule.dll`์„ ์‚ฌ์šฉํ•˜์—ฌ ํŒŒ์ผ ์ ‘๊ทผ ๊ฒฝ๊ณ ์ฐฝ์„ ์–ต์ œํ•จ. - **๋™์ž‘ ๋ฐฉ์‹:** ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์— DLL ๋“ฑ๋ก ํ›„ `hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckDLL")` ํ˜ธ์ถœ. - **์ž๋™ํ™”:** ํ…œํ”Œ๋ฆฟ(`VOC_Sample.hwp`)์˜ ๋ˆ„๋ฆ„ํ‹€(Field)์— ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™ ์ž…๋ ฅ. - **์ •๋ณด ์œ ์ถ”:** ๋ณธ๋ฌธ ํ…์ŠคํŠธ ๋ถ„์„์„ ํ†ตํ•ด ๊ด€๋ จ ํ˜ธ์„ (1ํ˜ธ์„  ๋“ฑ) ๋ฐ ์—ด์ฐจ ๋ฐฉํ–ฅ(์ƒ์„ /ํ•˜์„ )์„ ์ž๋™ ํŒ๋‹จ. - **PDF ๋ณด๊ณ ์„œ:** - **๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ:** `ReportLab` - `Malgun Gothic` ํฐํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•œ๊ธ€ ๊นจ์ง ๋ฐฉ์ง€. ### 3.3 ๐ŸŽจ UI ๋ฐ ํ…Œ๋งˆ (`ThemeManager`) - **ํฐํŠธ:** `app/assets/GmarketSansTTFMedium.ttf`๋ฅผ ๋™์ ์œผ๋กœ ๋กœ๋“œํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ์ ์šฉ. - **์Šคํƒ€์ผ:** ๋‹คํฌ/๋ผ์ดํŠธ ๋ชจ๋“œ ์ง€์›, `blue` ์ปฌ๋Ÿฌ ํ…Œ๋งˆ. ### 3.4 ๐Ÿ”” ์•Œ๋ฆผ ์‹œ์Šคํ…œ (Notification) - **๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ:** `winotify` - **์‹œ์ž‘ ์•Œ๋ฆผ:** ์•ฑ ์‹คํ–‰ ์‹œ ์œˆ๋„์šฐ ํ† ์ŠคํŠธ(Popup) ์•Œ๋ฆผ์„ ํ†ตํ•ด ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰ ์—ฌ๋ถ€๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ฆ‰์‹œ ์ธ์ง€์‹œํ‚ด. - **ํŠธ๋ ˆ์ด ์•„์ด์ฝ˜:** `pystray`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‹œ์Šคํ…œ ํŠธ๋ ˆ์ด์— ์ƒ์ฃผํ•˜๋ฉฐ, ์•„์ด์ฝ˜ ์šฐํด๋ฆญ์œผ๋กœ ์ฐฝ ์—ด๊ธฐ/์ข…๋ฃŒ ์ œ์–ด ๊ฐ€๋Šฅ. ## ๐Ÿ“ฆ 4. ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ (Build & Deployment) ### 4.1 cx_Freeze ์„ค์ • - **๊ธฐ๋ฐ˜:** `setup.py`๋ฅผ ํ†ตํ•ด exe ํŒŒ์ผ ์ƒ์„ฑ. - **๊ฒฝ๋กœ ์ฒ˜๋ฆฌ:** `utils/path_utils.py`๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ(`__file__` ๊ธฐ์ค€)๊ณผ ๋นŒ๋“œ ํ™˜๊ฒฝ(`sys.executable` ๊ธฐ์ค€)์˜ ์—์…‹/์„ค์ • ํŒŒ์ผ ๊ฒฝ๋กœ ์ฐจ์ด๋ฅผ ์ž๋™์œผ๋กœ ๋ณด์ •. - **ํฌํ•จ ํŒŒ์ผ:** - `assets/`: ์•„์ด์ฝ˜, ํฐํŠธ, HWP ๋ณด์•ˆ DLL, ๋ณด๊ณ ์„œ ํ…œํ”Œ๋ฆฟ ํฌํ•จ. - `data/`: ์‚ฌ์šฉ์ž ์„ค์ •(settings.json) ๋ฐ ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ ํฌํ•จ. - **์ฃผ์˜์‚ฌํ•ญ:** `setup.py`์˜ `include_files` ์˜ต์…˜์ด ๋นŒ๋“œ๋œ exe ํด๋” ๋ฃจํŠธ์— ํ•ด๋‹น ํด๋”๋“ค์„ ๋ณต์‚ฌํ•˜๋„๋ก ์„ค์ •๋จ. ### 5. ๋ฐ”์ด๋ธŒ ์ฝ”๋”ฉ (Vibe Coding) ์›์น™ ์ค€์ˆ˜ - **ํ•œ๊ตญ์–ด ์šฐ์„ :** ๋ชจ๋“  ๋ฌธ์„œ, ์ฃผ์„, ๋กœ๊ทธ๋Š” ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑ. - **์™„๊ฒฐ์„ฑ:** ๋ชจ๋“  ๊ธฐ๋Šฅ์€ Mock์ด ์•„๋‹Œ ์‹ค์ œ ๋™์ž‘ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„. - **์‚ฌ์šฉ์ž ์นœํ™”์ :** ๋ณต์žกํ•œ ์„ค์ • ์—†์ด ์‹คํ–‰๋งŒ์œผ๋กœ ๋™์ž‘ํ•˜๋„๋ก ๊ตฌ์„ฑ (๋ณด์•ˆ ๋ชจ๋“ˆ ์ž๋™ ๋“ฑ๋ก ๋“ฑ).