Skip to content

twbeatles/smartclipboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

58 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๐Ÿ“‹ SmartClipboard Pro v10.6

๊ณ ๊ธ‰ ํด๋ฆฝ๋ณด๋“œ ๋งค๋‹ˆ์ € - PyQt6 ๊ธฐ๋ฐ˜์˜ ํ˜„๋Œ€์ ์ด๊ณ  ๊ฐ•๋ ฅํ•œ ํด๋ฆฝ๋ณด๋“œ ๊ด€๋ฆฌ ๋„๊ตฌ

Version Python Platform License


โœจ ์ฃผ์š” ๊ธฐ๋Šฅ

๐Ÿ“‹ ํด๋ฆฝ๋ณด๋“œ ํžˆ์Šคํ† ๋ฆฌ

  • ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€, ๋งํฌ, ์ฝ”๋“œ, ์ƒ‰์ƒ, ํŒŒ์ผ/ํด๋” ์ž๋™ ๋ถ„๋ฅ˜ ๋ฐ ์ €์žฅ
  • ์ตœ๋Œ€ 500๊ฐœ ํ•ญ๋ชฉ ์ €์žฅ (์„ค์ • ๊ฐ€๋Šฅ)
  • ๐Ÿ“Œ ์ค‘์š” ํ•ญ๋ชฉ ๊ณ ์ • ๋ฐ ๋“œ๋ž˜๊ทธ ์ •๋ ฌ ๊ธฐ๋Šฅ
  • ๐Ÿท๏ธ ํƒœ๊ทธ ์‹œ์Šคํ…œ์œผ๋กœ ํ•ญ๋ชฉ ์ •๋ฆฌ
  • โญ ๋ถ๋งˆํฌ ๊ธฐ๋Šฅ์œผ๋กœ ์ฆ๊ฒจ์ฐพ๊ธฐ ๊ด€๋ฆฌ
  • ๐Ÿ“ ์ปฌ๋ ‰์…˜ ๊ธฐ๋Šฅ์œผ๋กœ ํ•ญ๋ชฉ ๊ทธ๋ฃนํ™”
  • ๐Ÿ“ ํ•ญ๋ชฉ๋ณ„ ๋ฉ”๋ชจ ์ฒจ๋ถ€ ๊ธฐ๋Šฅ
  • ํŒŒ์ผ ๋ณต์‚ฌ๋Š” ๋‹ค์ค‘ ์„ ํƒ์„ ํ•˜๋‚˜์˜ FILE ํ•ญ๋ชฉ์œผ๋กœ ์ €์žฅํ•˜๊ณ , paste-last/๋ฏธ๋‹ˆ ์ฐฝ/์„ ํƒ ๋ถ™์—ฌ๋„ฃ๊ธฐ์—์„œ ๋กœ์ปฌ file URL ํด๋ฆฝ๋ณด๋“œ๋ฅผ ๋ณต์›

๐Ÿ”’ ๋ณด์•ˆ ๋ณด๊ด€ํ•จ

  • PBKDF2-HMAC-SHA256 + Fernet ๊ธฐ๋ฐ˜ ์•”ํ˜ธํ™”๋กœ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ ์•ˆ์ „ ๋ณด๊ด€
  • ๋งˆ์Šคํ„ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ธฐ๋ฐ˜ ์ž ๊ธˆ
  • v10.2: ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ•๋„ ๊ฒ€์ฆ (8์ž ์ด์ƒ, ์ˆซ์ž+ํŠน์ˆ˜๋ฌธ์ž)
  • 5๋ถ„ ์ž๋™ ์ž ๊ธˆ ํƒ€์ด๋จธ
  • ๋งˆ์Šคํ„ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์‹œ ๊ธฐ์กด ๋ณด๊ด€ ํ•ญ๋ชฉ ์ „์ฒด ์žฌ์•”ํ˜ธํ™”
  • ๋ณตํ˜ธํ™” ํ›„ ํด๋ฆฝ๋ณด๋“œ๋กœ ๋ณต์‚ฌํ•œ ํ…์ŠคํŠธ๋Š” 30์ดˆ ๋’ค ์ž๋™ ์‚ญ์ œ
  • ์„ค์ • ์†์ƒ ์‹œ ์ž ๊ธˆ ํ™”๋ฉด์—์„œ Reset ๋ณด๊ด€ํ•จ์œผ๋กœ ๋ณต๊ตฌ ๊ฐ€๋Šฅ

โšก ํด๋ฆฝ๋ณด๋“œ ์•ก์…˜ ์ž๋™ํ™”

  • ํŒจํ„ด ๋งค์นญ ๊ธฐ๋ฐ˜ ์ž๋™ ์ฒ˜๋ฆฌ
  • v10.2: URL ์ œ๋ชฉ ๊ฐ€์ ธ์˜ค๊ธฐ ๊ฐœ์„  (ํƒ€์ž„์•„์›ƒ/์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ•ํ™”)
  • fetch_title์€ ์ฒซ URL๋งŒ ์ถ”์ถœํ•˜๋ฉฐ ๋กœ์ปฌ/์‚ฌ์„ค/๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฃผ์†Œ๋Š” ๋ณด์•ˆ์ƒ ์ฐจ๋‹จ
  • ์ „ํ™”๋ฒˆํ˜ธ ์ž๋™ ํฌ๋งทํŒ… (02, ์ผ๋ฐ˜ ์ง€์—ญ๋ฒˆํ˜ธ, 0505, 1588/1661/1800๋ฅ˜ ๋Œ€ํ‘œ๋ฒˆํ˜ธ ํฌํ•จ)
  • ์ด๋ฉ”์ผ ์ •๊ทœํ™”
  • ํ…์ŠคํŠธ ๋ณ€ํ™˜ (๋Œ€์†Œ๋ฌธ์ž, ํŠธ๋ฆผ ๋“ฑ)
  • ๋™๊ธฐ ํ…์ŠคํŠธ ์•ก์…˜(format_phone/format_email/transform)์€ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ™์€ history row์™€ clipboard์— ๋‹ค์‹œ ๋ฐ˜์˜ํ•˜๊ณ , ๊ฐ™์€ ๋ฐฐ์น˜์˜ ํ›„์† ์•ก์…˜์€ ๋ณ€ํ™˜๋œ ํ…์ŠคํŠธ ๊ธฐ์ค€์œผ๋กœ ํ‰๊ฐ€
  • v10.2: ์ •๊ทœ์‹ ํŒจํ„ด ์œ ํšจ์„ฑ ๊ฒ€์ฆ

๐Ÿ—‘๏ธ ํœด์ง€ํ†ต ๊ธฐ๋Šฅ

  • ์‚ญ์ œ ํ•ญ๋ชฉ 7์ผ๊ฐ„ ๋ณด๊ด€ ํ›„ ์ž๋™ ์˜๊ตฌ ์‚ญ์ œ
  • v10.2: ํœด์ง€ํ†ต ๋‹ค์ด์–ผ๋กœ๊ทธ ๋‹ค์ค‘ ์„ ํƒ ์ง€์›
  • ์›ํด๋ฆญ ๋ณต์› ๋ฐ ์˜๊ตฌ ์‚ญ์ œ
  • ์‹คํ–‰ ์ทจ์†Œ ๊ฐ€๋Šฅํ•œ ์•ˆ์ „ํ•œ ์‚ญ์ œ
  • ์ „์ฒด ๊ธฐ๋ก ์‚ญ์ œ๋„ ๊ณ ์ • ํ•ญ๋ชฉ์„ ์ œ์™ธํ•˜๊ณ  ํœด์ง€ํ†ต ์ด๋™์œผ๋กœ ์ฒ˜๋ฆฌ

๐Ÿ“„ ํ…์ŠคํŠธ ์Šค๋‹ˆํŽซ

  • ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ํ…์ŠคํŠธ ํ…œํ”Œ๋ฆฟ ์ €์žฅ
  • v10.2: ์Šค๋‹ˆํŽซ ์ˆ˜์ • ๊ธฐ๋Šฅ ์ถ”๊ฐ€
  • ์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ์ •๋ฆฌ
  • ๋”๋ธ”ํด๋ฆญ/๋ฒ„ํŠผ์œผ๋กœ ์ฆ‰์‹œ ๋ณต์‚ฌ
  • ์•ฑ ๋‚ด๋ถ€ ์ „์šฉ ๋‹จ์ถ•ํ‚ค(shortcut) ๋“ฑ๋ก ๋ฐ ์‹คํ–‰ ์ง€์›
  • ๊ธฐ๋ณธ ๋‹จ์ถ•ํ‚ค/๊ธ€๋กœ๋ฒŒ ํ•ซํ‚ค/๋‹ค๋ฅธ ์Šค๋‹ˆํŽซ๊ณผ์˜ ์ถฉ๋Œ ๊ฒ€์ฆ

๐Ÿ“ค ๋‚ด๋ณด๋‚ด๊ธฐ/๊ฐ€์ ธ์˜ค๊ธฐ

  • JSON, CSV, Markdown ๋‚ด๋ณด๋‚ด๊ธฐ / JSON, CSV ๊ฐ€์ ธ์˜ค๊ธฐ ์ง€์›
  • ๋‚ ์งœ ๋ฐ ํƒ€์ž… ํ•„ํ„ฐ๋ง
  • JSON์€ IMAGE ํ•ญ๋ชฉ์„ image_data_b64๋กœ ๋ณด์กดํ•˜๋ฉฐ, CSV/Markdown์€ ์ด๋ฏธ์ง€ ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋งŒ ๊ธฐ๋ก
  • FILE ํ•ญ๋ชฉ์€ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋Œ€์‹  ๊ฒฝ๋กœ ๋ชฉ๋ก๋งŒ ๋‚ด๋ณด๋‚ด๋ฉฐ, JSON์€ file_paths/file_path, CSV/Markdown์€ newline ๊ฒฝ๋กœ ๋ชฉ๋ก์„ ์‚ฌ์šฉ
  • JSON ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ชจ๋“œ (ํžˆ์Šคํ† ๋ฆฌ ํ•ญ๋ชฉ์˜ ํƒœ๊ทธ/๋ฉ”๋ชจ/๋ถ๋งˆํฌ + ์ปฌ๋ ‰์…˜ ์ •์˜/ID ๋งคํ•‘ ์ •๋ณด ํฌํ•จ, ์Šค๋‹ˆํŽซ/๊ทœ์น™/ํ•ซํ‚ค/๋ณด์•ˆ ๋ณด๊ด€ํ•จ ์ œ์™ธ)
  • JSON import๋Š” ISO-8601/tz timestamp๋ฅผ ์›๋ณธ ์‹œ๊ฐ ๊ธฐ์ค€ ์•ฑ ํ‘œ์ค€ ์‹œ๊ฐ ๋ฌธ์ž์—ด๋กœ ์ •๊ทœํ™”ํ•˜๊ณ , ์™„์ „ ๋ถˆ๋Ÿ‰ timestamp๋Š” import ์‹œ๊ฐ์œผ๋กœ ๋Œ€์ฒด
  • CSV import๋Š” ์ด๋ฏธ์ง€ ํ”Œ๋ ˆ์ด์Šคํ™€๋” row๋ฅผ ๋ณต์›ํ•˜์ง€ ์•Š์œผ๋ฉฐ, JSON import๋Š” remap ์‹คํŒจ/๋ˆ„๋ฝ๋œ collection_id๋ฅผ NULL๋กœ ์ •๋ฆฌ
  • JSON import๊ฐ€ ์ƒˆ ์ปฌ๋ ‰์…˜์„ ๋งŒ๋“ค๋ฉด ๋ฉ”์ธ ์ƒ๋‹จ ์ปฌ๋ ‰์…˜ ํ•„ํ„ฐ ์˜ต์…˜์„ ์ฆ‰์‹œ ์ƒˆ๋กœ๊ณ ์นจ
  • FILE ํ•ญ๋ชฉ์€ ๋ณต์› ์ „์— ๋ชฉ๋ก/์ƒ์„ธ/๋ฏธ๋‹ˆ ์ฐฝ์—์„œ ๋ˆ„๋ฝ ๊ฒฝ๋กœ(stale) ์—ฌ๋ถ€๋ฅผ ๋ฏธ๋ฆฌ ํ‘œ์‹œ
  • ๋ฐฑ์—… ๋ฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์šฉ์ด

๐ŸŽจ UI/UX

  • ๊ธ€๋ž˜์Šค๋ชจํ”ผ์ฆ˜ ๋””์ž์ธ
  • 5๊ฐ€์ง€ ํ…Œ๋งˆ: ๐ŸŒ™ ๋‹คํฌ, โ˜€๏ธ ๋ผ์ดํŠธ, ๐ŸŒŠ ์˜ค์…˜, ๐Ÿ’œ ํผํ”Œ, ๐ŸŒŒ ๋ฏธ๋“œ๋‚˜์ž‡
  • v10.1: ํ–ฅ์ƒ๋œ ๋งˆ์ดํฌ๋กœ ์ธํ„ฐ๋ž™์…˜ (ํ˜ธ๋ฒ„/ํฌ์ปค์Šค ํšจ๊ณผ)
  • ์˜จ๋ณด๋”ฉ ๊ฐ€์ด๋“œ๊ฐ€ ํฌํ•จ๋œ ๋นˆ ์ƒํƒœ UI
  • ํ”Œ๋กœํŒ… ํ† ์ŠคํŠธ ์•Œ๋ฆผ (์Šฌ๋ผ์ด๋“œ ์• ๋‹ˆ๋ฉ”์ด์…˜)
  • ๋ฏธ๋‹ˆ ์ฐฝ ๋ชจ๋“œ ์ง€์›
  • ์ƒ๋‹จ ์ปฌ๋ ‰์…˜ ํ•„ํ„ฐ(์ „์ฒด/๋ฏธ๋ถ„๋ฅ˜/๊ฐœ๋ณ„ ์ปฌ๋ ‰์…˜)

โŒจ๏ธ ๊ธ€๋กœ๋ฒŒ ํ•ซํ‚ค

๋‹จ์ถ•ํ‚ค ๊ธฐ๋Šฅ
Ctrl+Shift+V ๋ฉ”์ธ ์ฐฝ ํ‘œ์‹œ
Alt+V ๋ฏธ๋‹ˆ ์ฐฝ ํ† ๊ธ€
Ctrl+Shift+Z ๊ฐ€์žฅ ์ตœ๊ทผ ๋ณต์‚ฌ ํ•ญ๋ชฉ ์ฆ‰์‹œ ๋ถ™์—ฌ๋„ฃ๊ธฐ

๐Ÿ–ฅ๏ธ ์‹œ์Šคํ…œ ์š”๊ตฌ์‚ฌํ•ญ

  • OS: Windows 10/11
  • Python: 3.10-3.14 (์†Œ์Šค ์‹คํ–‰/๋กœ์ปฌ ๋นŒ๋“œ ๊ฒ€์ฆ ๊ธฐ์ค€)
  • ๋ฉ”๋ชจ๋ฆฌ: 50MB ์ด์ƒ

๐Ÿ“ฆ ์„ค์น˜

๋ฐฉ๋ฒ• 1: ์‹คํ–‰ ํŒŒ์ผ (๊ถŒ์žฅ)

Releases์—์„œ SmartClipboard.exe ๋‹ค์šด๋กœ๋“œ

๋ฐฉ๋ฒ• 2: ์†Œ์Šค์—์„œ ์‹คํ–‰

pip install -r requirements.txt
python "ํด๋ฆฝ๋ชจ๋“œ ๋งค๋‹ˆ์ €.py"

๐Ÿ“„ ์˜์กด์„ฑ

ํ•„์ˆ˜

PyQt6>=6.4.0
keyboard>=0.13.5

์„ ํƒ์  (๊ธฐ๋Šฅ ํ™•์žฅ)

cryptography>=41.0.0    # ๋ณด์•ˆ ๋ณด๊ด€ํ•จ ์•”ํ˜ธํ™”
requests>=2.28.0        # URL ์ œ๋ชฉ ๊ฐ€์ ธ์˜ค๊ธฐ
beautifulsoup4>=4.11.0  # HTML ํŒŒ์‹ฑ
qrcode[pil]>=7.3        # QR ์ฝ”๋“œ ์ƒ์„ฑ
Pillow>=9.0.0           # ์ด๋ฏธ์ง€ ์ฒ˜๋ฆฌ

๐Ÿ”จ ๋นŒ๋“œ

python scripts/preflight_local.py
pyinstaller --clean smartclipboard.spec

๊ฒฐ๊ณผ๋ฌผ: dist/SmartClipboard.exe (smartclipboard.spec๋Š” upx=True๋กœ ์š”์ฒญํ•˜์ง€๋งŒ, ์‹ค์ œ ๋นŒ๋“œ ์ถœ๋ ฅ์€ ๋กœ์ปฌ UPX ๋„๊ตฌ ๊ฐ€์šฉ์„ฑ์— ๋”ฐ๋ผ Enabled ๋˜๋Š” Disabled๋กœ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์Œ)

payload์™€ manifest๋งŒ ๋‹ค์‹œ ์ƒ์„ฑํ•ด์•ผ ํ•  ๋•Œ๋Š”:

python scripts/build_legacy_payload.py --src smartclipboard_app/legacy_main_src.py --out smartclipboard_app/legacy_main_payload.marshal --smoke-import

์œ„ ๋ช…๋ น์€ legacy_main_payload.marshal๊ณผ ํ•จ๊ป˜ legacy_main_payload.manifest.json๋„ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

โœ… ๋กœ์ปฌ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ

python scripts/preflight_local.py

preflight_local.py๋Š” payload ์žฌ์ƒ์„ฑ, payload smoke import, py_compile, unittest(test_payload_sync ํฌํ•จ)์„ ์ˆœ์ฐจ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ ํ•ต์‹ฌ ํšŒ๊ท€ ๋ฒ”์œ„์—๋Š” test_core, test_ui_dialogs_widgets, test_payload_sync, test_legacy_loader, test_migration_collections, test_legacy_ui_contracts, test_signal_snapshot, test_public_surfaces๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. pyright๋Š” ๋ณ„๋„ ๋‹จ๊ณ„์ด๋ฉฐ ๋ฃจํŠธ pyrightconfig.json ๊ธฐ์ค€์œผ๋กœ ํ˜„ํ–‰ ์œ ์ง€๋ณด์ˆ˜ ๋Œ€์ƒ๋งŒ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ repo-wide pyright์—๋Š” smartclipboard_core/db_parts/*.py mixin attribute typing ๋…ธ์ด์ฆˆ๊ฐ€ ๋‚จ์•„ ์žˆ์œผ๋ฏ€๋กœ, ๋กœ์ปฌ ๊ฒŒ์ดํŠธ๋Š” preflight_local.py์ด๊ณ  pyright๋Š” ๋ณ€๊ฒฝ ํŒŒ์ผ ๊ธฐ์ค€ ๋ณด์กฐ ๊ฒ€์ฆ์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Windows ๋กœ์ปฌ ํ…Œ์ŠคํŠธ๋Š” ์‹œ์Šคํ…œ temp ๊ถŒํ•œ ์ด์Šˆ๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด repo ๋ฃจํŠธ์˜ .tmp-unittest/ ํ•˜์œ„ ์ž„์‹œ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

ํ•„์š” ์‹œ payload ์žฌ์ƒ์„ฑ ๋‹จ๊ณ„๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋ ค๋ฉด:

python scripts/preflight_local.py --skip-payload-build

optional dependency๊นŒ์ง€ CI์™€ ๊ฐ™์€ ๊ฐ•๋„๋กœ ํ™•์ธํ•˜๋ ค๋ฉด ์œ„ strict ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ preflight_local.py๋Š” cryptography, requests, bs4, qrcode, PIL ๋ˆ„๋ฝ์„ ๊ฒฝ๊ณ ๋งŒ ์ถœ๋ ฅํ•˜๊ณ  ๊ณ„์† ์ง„ํ–‰ํ•˜์ง€๋งŒ, strict ๋ชจ๋“œ์™€ CI๋Š” ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

python scripts/preflight_local.py --skip-payload-build --strict-optional-deps

๐Ÿค– CI (GitHub Actions)

  • ์›Œํฌํ”Œ๋กœ์šฐ ํŒŒ์ผ: .github/workflows/ci.yml
  • ์‹คํ–‰ ํ™˜๊ฒฝ: windows-latest
  • Python ๋งคํŠธ๋ฆญ์Šค: 3.10, 3.11, 3.12, 3.13
  • ๊ฐ ๋งคํŠธ๋ฆญ์Šค์—์„œ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    • payload ๋นŒ๋“œ + smoke import
    • python scripts/preflight_local.py --skip-payload-build --strict-optional-deps

๐Ÿ”Ž ์ •์  ๋ถ„์„ (Pylance/Pyright)

pyright
  • ๋ฃจํŠธ pyrightconfig.json์ด ๊ณต์‹ ๋ถ„์„ ๋ฒ”์œ„๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ ๋ฒ”์œ„์—๋Š” ํ˜„ํ–‰ ์œ ์ง€๋ณด์ˆ˜ ๋Œ€์ƒ(ํด๋ฆฝ๋ชจ๋“œ ๋งค๋‹ˆ์ €.py, smartclipboard_app/, smartclipboard_core/, tests/)๋งŒ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค.
  • ๋ ˆ๊ฑฐ์‹œ ๋ณด๊ด€๋ณธ legacy/ํด๋ฆฝ๋ชจ๋“œ ๋งค๋‹ˆ์ € (legacy).py์™€ ์†Œ์Šค ์Šค๋ƒ…์ƒท smartclipboard_app/legacy_main_src.py๋Š” ํ˜ธํ™˜์„ฑ ์ฐธ์กฐ์šฉ์ด๋ฏ€๋กœ ๊ธฐ๋ณธ ๋ถ„์„์—์„œ ์ œ์™ธ๋ฉ๋‹ˆ๋‹ค.

โŒจ๏ธ ์•ฑ ๋‚ด ๋‹จ์ถ•ํ‚ค

๋‹จ์ถ•ํ‚ค ๊ธฐ๋Šฅ
Ctrl+F ๊ฒ€์ƒ‰์ฐฝ ํฌ์ปค์Šค
Ctrl+C ์„ ํƒ ํ•ญ๋ชฉ ๋ณต์‚ฌ
Ctrl+P ๊ณ ์ •/ํ•ด์ œ ํ† ๊ธ€
Ctrl+G ๊ตฌ๊ธ€ ๊ฒ€์ƒ‰
Enter ๋ณต์‚ฌ ํ›„ ๋ถ™์—ฌ๋„ฃ๊ธฐ
Delete ์„ ํƒ ํ•ญ๋ชฉ ์‚ญ์ œ
Escape ์ฐฝ ์ˆจ๊ธฐ๊ธฐ

๐Ÿ“ v10.5 ๋ณ€๊ฒฝ์‚ฌํ•ญ

๐Ÿš€ ๋น„๋™๊ธฐ ์‹œ์Šคํ…œ (Async)

  • URL ์ œ๋ชฉ ๊ฐ€์ ธ์˜ค๊ธฐ ๋น„๋™๊ธฐํ™”: ๋„คํŠธ์›Œํฌ ์š”์ฒญ ์‹œ UI ํ”„๋ฆฌ์ง• ํ˜„์ƒ ์™„์ „ ํ•ด๊ฒฐ
  • Worker ํด๋ž˜์Šค ๋ฐ ์Šค๋ ˆ๋“œํ’€ ๋„์ž… (Background Processing)
  • ์ฆ‰๊ฐ์ ์ธ ํด๋ฆฝ๋ณด๋“œ ๋ฐ˜์‘์„ฑ ๋ฐ ์ฒ˜๋ฆฌ ์ƒํƒœ ์‹œ๊ฐํ™” (Fetching...)

๐Ÿ›ก๏ธ ๋ฐ์ดํ„ฐ ์•ˆ์ „์„ฑ & ์ตœ์ ํ™”

  • ์ž๋™ DB ๋ฐฑ์—…: ๋งค์ผ 1ํšŒ backups/ ํด๋”์— DB ์ž๋™ ๋ฐฑ์—… (์ตœ๊ทผ 7์ผ ๋ณด๊ด€)
  • ํด๋ฆฝ๋ณด๋“œ ๋ชจ๋‹ˆํ„ฐ ๋ฆฌ์…‹: ํŠธ๋ ˆ์ด ๋ฉ”๋‰ด > ๊ณ ๊ธ‰ > ๋ชจ๋‹ˆํ„ฐ ์žฌ์‹œ์ž‘ ๊ธฐ๋Šฅ (์ฒด์ธ ๋Š๊น€ ํ•ด๊ฒฐ)
  • ์ด๋ฏธ์ง€ ํžˆ์Šคํ† ๋ฆฌ ์ œํ•œ: ์ด๋ฏธ์ง€ ํ•ญ๋ชฉ์€ ์ตœ์‹  20๊ฐœ๋งŒ ์œ ์ง€ํ•˜์—ฌ DB ์šฉ๋Ÿ‰ ์ตœ์ ํ™”

๐ŸŽจ UI ๊ฐœ์„ 

  • ๊ฐ€๋…์„ฑ ํ–ฅ์ƒ: UI ๊ธฐ๋ณธ ํฐํŠธ๋ฅผ **'๋ง‘์€ ๊ณ ๋”•(Malgun Gothic)'**์œผ๋กœ ๋ณ€๊ฒฝ
  • ํ…์ŠคํŠธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์˜์—ญ ํฐํŠธ ๊ฐ€๋…์„ฑ ๊ฐœ์„ 

๐Ÿ“ v10.6 ๋ณ€๊ฒฝ์‚ฌํ•ญ

๐Ÿ”ง ๋“œ๋ž˜๊ทธ์•ค๋“œ๋กญ ์ˆ˜์ •

  • ๊ณ ์ • ํ•ญ๋ชฉ ์ˆœ์„œ ๋ณ€๊ฒฝ: ๋“œ๋ž˜๊ทธ ์‹œ ๋ฐ์ดํ„ฐ ์†์‹ค ๋ฒ„๊ทธ ์ˆ˜์ •
  • DragDropMode ๋ณ€๊ฒฝ์œผ๋กœ Qt ์ž๋™ ํ–‰ ์‚ญ์ œ ๋ฐฉ์ง€
  • eventFilter ์žฌ์„ค๊ณ„ (DragEnter/DragMove/Drop ๋ถ„๋ฆฌ ์ฒ˜๋ฆฌ)

๐Ÿ›ก๏ธ DB ์•ˆ์ •์„ฑ ๊ฐ•ํ™”

  • toggle_pin: ์ƒˆ ๊ณ ์ • ํ•ญ๋ชฉ pin_order ์ž๋™ ์ดˆ๊ธฐํ™”
  • soft_delete, restore_item: rollback ์ถ”๊ฐ€
  • add_snippet, update_snippet, delete_snippet: rollback/return ์ถ”๊ฐ€
  • set_setting: rollback ์ถ”๊ฐ€
  • update_url_title: URL ์ œ๋ชฉ ์บ์‹œ ์ €์žฅ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€
  • ์‚ญ์ œ/๋ณต์› ์‹œ ํœด์ง€ํ†ต ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(tags/note/bookmark/collection/pin/use_count) ๋ณด์กด
  • ๊ณ ์ • ํ•ญ๋ชฉ ์ˆœ์„œ ๊ฐฑ์‹ ์„ ํŠธ๋žœ์žญ์…˜ ์ผ๊ด„ ์ฒ˜๋ฆฌ๋กœ ๋ณ€๊ฒฝ(update_pin_orders)

๐Ÿ“ Collections API ๊ตฌํ˜„

  • add_collection(): ์ปฌ๋ ‰์…˜ ์ƒ์„ฑ
  • get_collections(): ๋ชฉ๋ก ์กฐํšŒ
  • update_collection(): ์ˆ˜์ •
  • delete_collection(): ์‚ญ์ œ (ํ•ญ๋ชฉ ์—ฐ๊ฒฐ ํ•ด์ œ)
  • assign_to_collection(): ํ•ญ๋ชฉ ํ• ๋‹น/ํ•ด์ œ
  • get_items_by_collection(): ์ปฌ๋ ‰์…˜๋ณ„ ์กฐํšŒ
  • ๋ฉ”์ธ ์ƒ๋‹จ ์ƒ์‹œ ํ•„ํ„ฐ๋กœ ์ „์ฒด/๋ฏธ๋ถ„๋ฅ˜/์ปฌ๋ ‰์…˜ ์ฆ‰์‹œ ์กฐํšŒ ์ง€์›

โŒจ๏ธ ํ•ซํ‚ค/๋ฐฑ์—… ๋™์ž‘ ๋ณด๊ฐ•

  • ํ•ซํ‚ค ์„ค์ • ์ €์žฅ ์ฆ‰์‹œ register_hotkeys() ์žฌ๋“ฑ๋ก (์žฌ์‹œ์ž‘ ๋ถˆํ•„์š”)
  • ์ž๋™ ๋ฐฑ์—…์„ "์•ฑ ์‹œ์ž‘ 1ํšŒ"์—์„œ "์‹ค์งˆ์  ์ผ 1ํšŒ"๋กœ ๋ณด๊ฐ• (1์‹œ๊ฐ„ ์ฃผ๊ธฐ ๋‚ ์งœ ๋ณ€๊ฒฝ ๊ฐ์‹œ)

๐Ÿ› ๏ธ 2026-03-25 ๊ตฌํ˜„ ๋ฐ˜์˜

  • cleanup()์ด timestamp ASC, id ASC ๊ธฐ์ค€์œผ๋กœ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ํ•ญ๋ชฉ๋ถ€ํ„ฐ ์ •๋ฆฌ๋˜๋„๋ก ์ˆ˜์ •
  • ์ „์ฒด ๊ธฐ๋ก ์‚ญ์ œ๊ฐ€ ์˜๊ตฌ ์‚ญ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ณ ์ • ์ œ์™ธ ํ›„ ํœด์ง€ํ†ต ์ด๋™์œผ๋กœ ๋™์ž‘
  • JSON ์žฌ-import ์‹œ ์ปฌ๋ ‰์…˜ ์ด๋ฆ„์„ ์ •๊ทœํ™”ํ•ด ๊ธฐ์กด ์ปฌ๋ ‰์…˜์„ ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์ค‘๋ณต ์ƒ์„ฑ์„ ๋ฐฉ์ง€
  • CSV/Markdown ๋‚ด๋ณด๋‚ด๊ธฐ๋„ JSON๊ณผ ๋™์ผํ•œ ๋‚ ์งœยทํƒ€์ž… ํ•„ํ„ฐ๋ฅผ ์ ์šฉํ•˜๊ณ  ์ด๋ฏธ์ง€ ํ•ญ๋ชฉ์€ ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋กœ ๊ธฐ๋ก
  • ์Šค๋‹ˆํŽซ shortcut UI์™€ ์•ฑ ๋‚ด๋ถ€ ๋‹จ์ถ•ํ‚ค ์‹คํ–‰ ๊ฒฝ๋กœ๋ฅผ ์—ฐ๊ฒฐ
  • ๋ณต์‚ฌ ๊ทœ์น™/ํด๋ฆฝ๋ณด๋“œ ์•ก์…˜ ๋‹ค์ด์–ผ๋กœ๊ทธ์— ์ƒ์„ฑยท์ˆ˜์ •ยท์‚ญ์ œยท์šฐ์„ ์ˆœ์œ„ ์ด๋™์„ ๋ชจ๋‘ ๋ฐ˜์˜
  • ์ปฌ๋ ‰์…˜ ๊ด€๋ฆฌ ๋‹ค์ด์–ผ๋กœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ด๋ฆ„ ์ค‘๋ณต/๋นˆ ๊ฐ’ ๊ฒ€์ฆ์„ ์ ์šฉ
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ ๋งˆ์Šคํ„ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ๊ณผ ๋ณตํ˜ธํ™” ํด๋ฆฝ๋ณด๋“œ 30์ดˆ ์ž๋™ ์‚ญ์ œ๋ฅผ ์ถ”๊ฐ€
  • ํ•ซํ‚ค ์ €์žฅ ์‹คํŒจ ์‹œ ์ด์ „ ๊ธ€๋กœ๋ฒŒ ํ•ซํ‚ค ์ƒํƒœ๋กœ ๋กค๋ฐฑ๋˜๋„๋ก ๋ณด๊ฐ•

๐Ÿ› ๏ธ 2026-03 ์ •ํ•ฉ์„ฑ ํŒจ์น˜

  • fetch_title ์•ก์…˜ ๊ฒฝ๋กœ๊ฐ€ ํ…์ŠคํŠธ ์ „์ฒด๊ฐ€ ์•„๋‹Œ ์ฒซ URL๋งŒ ์ถ”์ถœํ•ด ์ œ๋ชฉ ์š”์ฒญํ•˜๋„๋ก ๋ณด๊ฐ•
  • ๋นˆ ๊ฒ€์ƒ‰(q == "")์—์„œ๋„ ํƒœ๊ทธ/๋ถ๋งˆํฌ/์ปฌ๋ ‰์…˜/๋ฏธ๋ถ„๋ฅ˜ ๋ณตํ•ฉ ํ•„ํ„ฐ๋ฅผ ๋™์‹œ ์ ์šฉํ•˜๋„๋ก ๊ฒ€์ƒ‰ ๊ฒฝ๋กœ ํ†ตํ•ฉ
  • TrashDialog ๋‹ค์ค‘ ์„ ํƒ(ExtendedSelection)์„ ๋ช…์‹œํ•ด ๋ฌธ์„œ์™€ ์‹ค์ œ ๋™์ž‘ ์ •ํ•ฉ์„ฑ ํ™•๋ณด
  • ๋ฏธ๋‹ˆ ์ฐฝ ๋”๋ธ”ํด๋ฆญ ๋ณต์‚ฌ ์‹œ is_internal_copy๋ฅผ ์„ค์ •ํ•ด ์ž๊ธฐ ์žฌ์ˆ˜์ง‘ ๋ฃจํ”„ ๋ฐฉ์ง€
  • update_always_on_top()์—์„œ ์ฐฝ ๊ฐ€์‹œ์„ฑ ๋ณด์กด ๊ฐ€๋“œ ์ ์šฉ (--minimized ์‹œ์ž‘ ์•ˆ์ •์„ฑ ๊ฐœ์„ )
  • JSON ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์— collections ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•˜๊ณ  import ์‹œ ์ปฌ๋ ‰์…˜ ID remap ์ง€์›

๐Ÿ› ๏ธ 2026-03-19 ๊ตฌํ˜„ ์•ˆ์ •ํ™” ํŒจ์น˜

  • add_snippet()์˜ ๋Ÿฐํƒ€์ž„ datetime ๋ˆ„๋ฝ์„ ์ˆ˜์ •ํ•ด ์‹ ๊ทœ ์Šค๋‹ˆํŽซ ์ €์žฅ ๊ฒฝ๋กœ ๋ณต๊ตฌ
  • ๋™์ผ ๋น„์ด๋ฏธ์ง€ ํ…์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ๋ณต์‚ฌํ•˜๋ฉด ๊ธฐ์กด row์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ(tags/note/bookmark/collection/pin/use_count)๋ฅผ ์œ ์ง€ํ•œ ์ฑ„ timestamp/content/type๋งŒ ๊ฐฑ์‹ 
  • ์ผ๋ฐ˜ ํžˆ์Šคํ† ๋ฆฌ/๋ถ๋งˆํฌ/์ปฌ๋ ‰์…˜/๋ฏธ๋ถ„๋ฅ˜/๋นˆ ๊ฒ€์ƒ‰ fallback์˜ unpinned ์ •๋ ฌ์„ timestamp DESC, id DESC๋กœ ํ†ต์ผ
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ ๋ณต์‚ฌ, ์Šค๋‹ˆํŽซ ์‚ฌ์šฉ, URL ๋ณต์‚ฌ ๊ฒฝ๋กœ์—์„œ smartclipboard_app.ui.clipboard_guard.mark_internal_copy()๋ฅผ ํ†ตํ•ด ๋‚ด๋ถ€ ๋ณต์‚ฌ ํ”Œ๋ž˜๊ทธ๋ฅผ ๋จผ์ € ์„ธํŒ…
  • JSON export/import๊ฐ€ IMAGE ํ•ญ๋ชฉ์„ image_data_b64๋กœ round-trip
  • pinned drag-drop helper์˜ Qt ์ฐธ์กฐ ๋ˆ„๋ฝ์„ ์ˆ˜์ •

๐Ÿ› ๏ธ 2026-04-08 ๊ตฌํ˜„ ๋ฆฌ์Šคํฌ ๋ณด๊ฐ•

  • ํ† ์ŠคํŠธ ํ˜ธ์ถœ์„ detail/duration/toast_type ํ‚ค์›Œ๋“œ ๊ธฐ์ค€์œผ๋กœ ์ •๋ฆฌํ•˜๊ณ , URL ์ œ๋ชฉ ์ฒ˜๋ฆฌ ์ค‘ ์˜ˆ์™ธ๊ฐ€ ๋‚˜๋„ clipboard.dataChanged๊ฐ€ ๋ฐ˜๋“œ์‹œ ์žฌ์—ฐ๊ฒฐ๋˜๋„๋ก ๋ณด๊ฐ•
  • Ctrl+Shift+Z๊ฐ€ ํ‘œ์‹œ ์ˆœ์„œ๊ฐ€ ์•„๋‹Œ ์‹ค์ œ ์ตœ๊ทผ ๋ณต์‚ฌ ํ•ญ๋ชฉ(timestamp DESC, id DESC)์„ ๋ถ™์—ฌ๋„ฃ๋„๋ก ์ •ํ•ฉ์„ฑ ์ˆ˜์ •
  • ํ…Œ์ด๋ธ” ์‚ฌ์šฉ์ž ์ •๋ ฌ์ด ๋‚ด๋ฆผ์ฐจ์ˆœ์ด์–ด๋„ pinned-first ์ •์ฑ…์ด ๊นจ์ง€์ง€ ์•Š๋„๋ก pinned/unpinned ๊ทธ๋ฃน์„ ๋ถ„๋ฆฌ ์ •๋ ฌ
  • ์ปฌ๋ ‰์…˜ ์‚ญ์ œ ์‹œ deleted_history.collection_id๋„ NULL๋กœ ์ •๋ฆฌํ•˜๊ณ , ๋ณต์› ์‹œ ์‚ญ์ œ๋œ ์ปฌ๋ ‰์…˜ ์ฐธ์กฐ๋Š” ์ž๋™์œผ๋กœ NULL ๋ณต์›
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ์€ ๋งˆ์Šคํ„ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ์งํ›„ ์—ด๋ฆฐ ๋‹ค์ด์–ผ๋กœ๊ทธ์—์„œ๋„ ์ตœ์‹  ์•”ํ˜ธ๋ฌธ์„ ๋‹ค์‹œ ์กฐํšŒํ•ด ๋ณต์‚ฌ ๋ฒ„ํŠผ์ด ๊ณ„์† ๋™์ž‘ํ•˜๋„๋ก ์ˆ˜์ •
  • ์ข…๋ฃŒ/๋ณต์› ์‹œ ๋น„๋™๊ธฐ URL ์ œ๋ชฉ worker ๊ฒฐ๊ณผ๊ฐ€ ๋‹ซํžŒ DB๋กœ ๋“ค์–ด์˜ค์ง€ ์•Š๋„๋ก ClipboardActionManager.shutdown() ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€

๐Ÿ› ๏ธ 2026-04-10 ์•ˆ์ •ํ™” + ํŒŒ์ผ Clipboard ์ง€์›

  • FILE ํƒ€์ž…์„ ์ถ”๊ฐ€ํ•ด ๋กœ์ปฌ ํŒŒ์ผ/ํด๋” ๋ณต์‚ฌ๋ฅผ ๋‹ค์ค‘ ๊ฒฝ๋กœ ํ•˜๋‚˜์˜ ํžˆ์Šคํ† ๋ฆฌ ํ•ญ๋ชฉ์œผ๋กœ ์ €์žฅ
  • history.file_path๋ฅผ FILE ์ฒซ ๊ฒฝ๋กœ ์ €์žฅ์šฉ์œผ๋กœ ํ™œ์„ฑํ™”ํ•˜๊ณ , ๋™์ผ path ์ง‘ํ•ฉ ์žฌ๋ณต์‚ฌ ์‹œ ๊ธฐ์กด metadata๋ฅผ ์œ ์ง€ํ•œ ์ฑ„ row๋ฅผ ๊ฐฑ์‹ 
  • paste-last/๋ฏธ๋‹ˆ ์ฐฝ/์„ ํƒ ๋ถ™์—ฌ๋„ฃ๊ธฐ/๋”๋ธ”ํด๋ฆญ ๋ณต์› ๊ฒฝ๋กœ๊ฐ€ QMimeData + file URL ํด๋ฆฝ๋ณด๋“œ๋ฅผ ๋‹ค์‹œ ๊ตฌ์„ฑํ•˜๋„๋ก ๋ณด๊ฐ•
  • ์ผ๋ถ€ ํŒŒ์ผ๋งŒ ๋‚จ์•„ ์žˆ์œผ๋ฉด ๋‚จ์€ ๊ฒฝ๋กœ๋งŒ ๋ณต์›ํ•˜๊ณ , ๋ชจ๋‘ ์‚ฌ๋ผ์กŒ์œผ๋ฉด ๊ฒฝ๊ณ ๋งŒ ํ‘œ์‹œํ•˜๊ณ  clipboard/paste๋Š” ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Œ
  • JSON export/import๋Š” FILE์˜ file_paths/file_path/newline content๋ฅผ ๋ชจ๋‘ ์ง€์›ํ•˜๊ณ , CSV/Markdown์€ ๊ฒฝ๋กœ ๋ชฉ๋ก๋งŒ ๊ธฐ๋ก
  • CSV import๋Š” IMAGE ํ”Œ๋ ˆ์ด์Šคํ™€๋” row๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ , JSON import๋Š” ISO timestamp๋ฅผ ์›๋ณธ ์‹œ๊ฐ ๊ธฐ์ค€ ์•ฑ ํ‘œ์ค€ ์‹œ๊ฐ์œผ๋กœ ์ •๊ทœํ™”ํ•˜๋ฉฐ ๊ณ ์•„ collection_id๋ฅผ NULL๋กœ ์ •๋ฆฌ
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ unlock() ์‹คํŒจ ์‹œ fernet/is_unlocked ์ƒํƒœ๋ฅผ ์›์ž์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•ด ์ž˜๋ชป๋œ ์žฌ์‹œ๋„ ํ›„ ๋ฐ˜์ฏค ์—ด๋ฆฐ ์ƒํƒœ๊ฐ€ ๋‚จ์ง€ ์•Š๋„๋ก ์ˆ˜์ •

๐Ÿ› ๏ธ 2026-04-11 ๊ธฐ๋Šฅ ๋ฆฌ๋ทฐ ํ›„์† ๋ฐ˜์˜

  • fetch_title์€ URL ํ›„ํ–‰ ๋ฌธ์žฅ๋ถ€ํ˜ธ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ , ๋กœ์ปฌ/์‚ฌ์„ค/๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฃผ์†Œ์™€ ๋น„ HTML ์‘๋‹ต์„ ์ œ๋ชฉ ์กฐํšŒ ๋Œ€์ƒ์—์„œ ์ œ์™ธ
  • ์ „ํ™”๋ฒˆํ˜ธ ์ž๋™ ํฌ๋งท ๋ฒ”์œ„๋ฅผ 02, ์ผ๋ฐ˜ ์ง€์—ญ๋ฒˆํ˜ธ, 0505, 15xx/16xx/18xx ๋Œ€ํ‘œ๋ฒˆํ˜ธ๊นŒ์ง€ ํ™•์žฅ
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ์€ salt/verification ์„ค์ •์„ ํ•จ๊ป˜ ์ €์žฅํ•˜๊ณ , ์†์ƒ ์ƒํƒœ์—์„œ๋Š” ์ž ๊ธˆ ํ™”๋ฉด Reset ๋ณด๊ด€ํ•จ์œผ๋กœ ์„ค์ •๊ฐ’๊ณผ ์ €์žฅ ํ•ญ๋ชฉ์„ ์ดˆ๊ธฐํ™” ๋ณต๊ตฌ
  • ๋ณต์‚ฌ ๊ทœ์น™์˜ custom_replace๋Š” ๋นˆ ๋ฌธ์ž์—ด ์น˜ํ™˜์„ ํ—ˆ์šฉํ•ด โ€œ์‚ญ์ œ ์น˜ํ™˜โ€์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์™„ํ™”
  • FILE ํ•ญ๋ชฉ์€ ๋ชฉ๋ก/์ƒ์„ธ/๋ฏธ๋‹ˆ ์ฐฝ์—์„œ ๋ˆ„๋ฝ ํŒŒ์ผ ์ˆ˜๋ฅผ ๋ฏธ๋ฆฌ ๋ณด์—ฌ ์ฃผ์–ด ๋ถ™์—ฌ๋„ฃ๊ธฐ ์ „์— stale ์ƒํƒœ๋ฅผ ํ™•์ธ ๊ฐ€๋Šฅ
  • JSON ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ฌธ๊ตฌ๋ฅผ ์‹ค์ œ ๋ฒ”์œ„(ํžˆ์Šคํ† ๋ฆฌ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ + ์ปฌ๋ ‰์…˜) ๊ธฐ์ค€์œผ๋กœ ์ •๋ฆฌํ•˜๊ณ , ๊ด€๋ จ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€

๐Ÿ“ v10.3 ๋ณ€๊ฒฝ์‚ฌํ•ญ

๐Ÿ”ฒ ๋ฏธ๋‹ˆ ์ฐฝ ๊ฐœ์„ 

  • ๋ฏธ๋‹ˆ ํด๋ฆฝ๋ณด๋“œ ์ฐฝ On/Off ์˜ต์…˜ ์ถ”๊ฐ€ (์„ค์ • > ์ผ๋ฐ˜ > ๋ฏธ๋‹ˆ ์ฐฝ)
  • ๋น„ํ™œ์„ฑํ™” ์‹œ Alt+V ๋‹จ์ถ•ํ‚ค ๋“ฑ๋ก ํ•ด์ œ
  • ์„ค์ • ๋ณ€๊ฒฝ ์‹œ ์žฌ์‹œ์ž‘ ์—†์ด ์ฆ‰์‹œ ์ ์šฉ

๐Ÿ”’ ๋ณด์•ˆ ๊ฐ•ํ™”

  • Google ๊ฒ€์ƒ‰ URL ์ธ์ฝ”๋”ฉ ์ถ”๊ฐ€ (ํŠน์ˆ˜๋ฌธ์ž ์ฒ˜๋ฆฌ)
  • Import ์‹œ ํƒ€์ž… ์œ ํšจ์„ฑ ๊ฒ€์ฆ (์ž˜๋ชป๋œ ํƒ€์ž… ์ž๋™ ๋ณต๊ตฌ)

โšก ์„ฑ๋Šฅ ๊ฐœ์„ 

  • ํด๋ฆฝ๋ณด๋“œ ๊ฐ์ง€ ๋””๋ฐ”์šด์Šค ๊ฐœ์„  (๋น ๋ฅธ ์—ฐ์† ๋ณต์‚ฌ ์‹œ ์ค‘๋ณต ํ˜ธ์ถœ ๋ฐฉ์ง€)
  • export_json ๋‚ ์งœ ํ•„ํ„ฐ๋ง ๊ธฐ๋Šฅ ๊ตฌํ˜„ (date_from ํŒŒ๋ผ๋ฏธํ„ฐ)

๐Ÿ› ๏ธ ์ฝ”๋“œ ํ’ˆ์งˆ

  • TYPE_ICONS ์ƒ์ˆ˜ ํ†ต์ผ (3๊ฐœ ์œ„์น˜์—์„œ ์ค‘๋ณต ์ œ๊ฑฐ)
  • empty_trash() rollback ์ถ”๊ฐ€ (DB ์ผ๊ด€์„ฑ ๋ณด์žฅ)

๐Ÿ“ v10.2 ๋ณ€๊ฒฝ์‚ฌํ•ญ

๐Ÿ” ๋ณด์•ˆ ๊ฐ•ํ™”

  • ๋งˆ์Šคํ„ฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ•๋„ ๊ฒ€์ฆ ์ถ”๊ฐ€ (8์ž ์ด์ƒ, ์ˆซ์ž+ํŠน์ˆ˜๋ฌธ์ž ํ•„์ˆ˜)
  • URL ์ œ๋ชฉ ๊ฐ€์ ธ์˜ค๊ธฐ ํƒ€์ž„์•„์›ƒ ์„ค์ • (๊ธฐ๋ณธ 5์ดˆ)
  • ์•ก์…˜ ํŒจํ„ด ์ •๊ทœ์‹ ์œ ํšจ์„ฑ ๊ฒ€์ฆ

๐Ÿ—‘๏ธ ํœด์ง€ํ†ต ๊ฐœ์„ 

  • ํœด์ง€ํ†ต ๋‹ค์ด์–ผ๋กœ๊ทธ ๋‹ค์ค‘ ์„ ํƒ ์ง€์›
  • ์„ ํƒ ํ•ญ๋ชฉ ์ผ๊ด„ ๋ณต์›/์‚ญ์ œ ๊ธฐ๋Šฅ
  • ๋นˆ ํœด์ง€ํ†ต ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€ ๊ฐœ์„ 

๐Ÿ“„ ์Šค๋‹ˆํŽซ ํŽธ์ง‘

  • ์Šค๋‹ˆํŽซ ์ˆ˜์ • ๋‹ค์ด์–ผ๋กœ๊ทธ ์ถ”๊ฐ€
  • ๋”๋ธ”ํด๋ฆญ์œผ๋กœ ์Šค๋‹ˆํŽซ ํŽธ์ง‘ ๊ฐ€๋Šฅ
  • ํŽธ์ง‘ ์‹œ ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ€๊ฒฝ ์ง€์›

๐Ÿ”ง ํ•ซํ‚ค ์•ˆ์ •์„ฑ

  • ํ•ซํ‚ค ๋“ฑ๋ก/ํ•ด์ œ ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๊ฐ•ํ™”
  • ์•ฑ ์ข…๋ฃŒ ์‹œ ์•ˆ์ „ํ•œ ํ•ซํ‚ค ํ•ด์ œ
  • ์ถฉ๋Œ ํ•ซํ‚ค ๊ฐ์ง€ ๋ฐ ๊ฒฝ๊ณ 

โฑ๏ธ ํด๋ฆฐ์—… ํƒ€์ด๋จธ

  • ๋งŒ๋ฃŒ๋œ ์ž„์‹œ ํ•ญ๋ชฉ ์ž๋™ ์ •๋ฆฌ (1์‹œ๊ฐ„ ์ฃผ๊ธฐ)
  • ํœด์ง€ํ†ต ๋งŒ๋ฃŒ ํ•ญ๋ชฉ ์ž๋™ ์‚ญ์ œ (1์‹œ๊ฐ„ ์ฃผ๊ธฐ)
  • QTimer ๊ธฐ๋ฐ˜ ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ

๐Ÿ“ v10.1 ๋ณ€๊ฒฝ์‚ฌํ•ญ

โšก ์„ฑ๋Šฅ ์ตœ์ ํ™”

  • load_data() UI ์ผ๊ด„ ๋ Œ๋”๋ง (setUpdatesEnabled)
  • hashlib ๋ชจ๋“ˆ ๋ ˆ๋ฒจ import ์ด๋™
  • TYPE_ICONS ์ƒ์ˆ˜ ์ถ”์ถœ๋กœ ๋ฃจํ”„ ๋‚ด ๋”•์…”๋„ˆ๋ฆฌ ์ƒ์„ฑ ์ œ๊ฑฐ
  • DB ์ธ๋ฑ์Šค ์ถ”๊ฐ€ (pinned, type, timestamp, bookmark)

๐ŸŽจ UI/UX ๊ฐœ์„ 

  • ๋ฒ„ํŠผ ํ˜ธ๋ฒ„/ํฌ์ปค์Šค ํšจ๊ณผ ๊ฐ•ํ™” (2px ํ…Œ๋‘๋ฆฌ, ํฌ์ปค์Šค ๋ง)
  • ํ…Œ์ด๋ธ” ํ–‰ ํ˜ธ๋ฒ„ ์‹œ ์ขŒ์ธก ํ”„๋ผ์ด๋จธ๋ฆฌ ์ปฌ๋Ÿฌ ๋ณด๋”
  • ์„ ํƒ ํ•ญ๋ชฉ ํฐํŠธ ๊ตต๊ธฐ ๊ฐ•์กฐ
  • ๋นˆ ์ƒํƒœ์—์„œ ๋‹จ์ถ•ํ‚ค ๊ฐ€์ด๋“œ ํฌํ•จ ์˜จ๋ณด๋”ฉ UI

๐Ÿ”ง ์ฝ”๋“œ ํ’ˆ์งˆ

  • SecureVaultManager.unlock() ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์„ธ๋ถ„ํ™”
  • UI_TEXTS ์ƒ์ˆ˜ ์ถ”๊ฐ€ (๋‹ค๊ตญ์–ด ์ง€์› ๋Œ€๋น„)

๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

smartclipboard/
โ”œโ”€โ”€ ํด๋ฆฝ๋ชจ๋“œ ๋งค๋‹ˆ์ €.py                # ์™ธ๋ถ€ ํ˜ธํ™˜ ํŒŒ์‚ฌ๋“œ
โ”œโ”€โ”€ pyrightconfig.json               # Pylance/pyright ๋ถ„์„ ๋ฒ”์œ„
โ”œโ”€โ”€ requirements.txt                 # Python ์˜์กด์„ฑ
โ”œโ”€โ”€ smartclipboard.spec              # PyInstaller ๋นŒ๋“œ ์„ค์ •
โ”œโ”€โ”€ smartclipboard_app/
โ”‚   โ”œโ”€โ”€ bootstrap.py
โ”‚   โ”œโ”€โ”€ legacy_main.py               # legacy payload loader
โ”‚   โ”œโ”€โ”€ legacy_payload.py            # payload manifest/hash helper
โ”‚   โ”œโ”€โ”€ legacy_main_payload.marshal  # ๋Ÿฐํƒ€์ž„ payload
โ”‚   โ”œโ”€โ”€ legacy_main_payload.manifest.json  # Python/source sync manifest
โ”‚   โ”œโ”€โ”€ features/                   # ๊ธฐ๋Šฅ ๋„๋ฉ”์ธ ๊ตฌํ˜„์ฒด
โ”‚   โ”œโ”€โ”€ managers/
โ”‚   โ””โ”€โ”€ ui/
โ”‚       โ”œโ”€โ”€ clipboard_guard.py       # internal copy flag helper
โ”‚       โ””โ”€โ”€ mainwindow_parts/        # legacy ํ˜ธํ™˜ shim (์‹ค๊ตฌํ˜„์€ features/)
โ”œโ”€โ”€ smartclipboard_core/
โ”‚   โ”œโ”€โ”€ actions.py
โ”‚   โ”œโ”€โ”€ automation/                 # ClipboardActionManager ๋ถ„๋ฆฌ ๊ตฌํ˜„
โ”‚   โ”œโ”€โ”€ database.py
โ”‚   โ”œโ”€โ”€ db_parts/                   # mixin facade + ํ•˜์œ„ subpackage
โ”‚   โ””โ”€โ”€ worker.py
โ”œโ”€โ”€ tests/
โ””โ”€โ”€ legacy/                          # ์ฐธ์กฐ์šฉ ๋ ˆ๊ฑฐ์‹œ ๋ณด๊ด€๋ณธ

๐Ÿ—„๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์กฐ

ํ…Œ์ด๋ธ” ์šฉ๋„
history ํด๋ฆฝ๋ณด๋“œ ํžˆ์Šคํ† ๋ฆฌ ์ €์žฅ
snippets ํ…์ŠคํŠธ ์Šค๋‹ˆํŽซ ์ €์žฅ
settings ์•ฑ ์„ค์ • (ํ…Œ๋งˆ, ํ•ซํ‚ค ๋“ฑ)
copy_rules ๋ณต์‚ฌ ๊ทœ์น™
secure_vault ์•”ํ˜ธํ™”๋œ ๋ณด์•ˆ ํ•ญ๋ชฉ
clipboard_actions ์ž๋™ํ™” ์•ก์…˜ ๊ทœ์น™
collections ์ปฌ๋ ‰์…˜ ์ •๋ณด
deleted_history ํœด์ง€ํ†ต (7์ผ ๋ณด๊ด€)

๐ŸŽฏ ์‚ฌ์šฉ ํŒ

  1. ๋น ๋ฅธ ์ ‘๊ทผ: Ctrl+Shift+V๋กœ ์–ธ์ œ๋“  ํžˆ์Šคํ† ๋ฆฌ ํ™•์ธ
  2. ๋ฏธ๋‹ˆ ๋ชจ๋“œ: Alt+V๋กœ ์ž‘์€ ์ฐฝ์—์„œ ๋น ๋ฅด๊ฒŒ ํ•ญ๋ชฉ ์„ ํƒ
  3. ๊ณ ์ • ํ•ญ๋ชฉ: ์ž์ฃผ ์“ฐ๋Š” ํ…์ŠคํŠธ๋Š” ๐Ÿ“Œ ๊ณ ์ •ํ•˜์—ฌ ์ƒ๋‹จ์— ์œ ์ง€
  4. ํƒœ๊ทธ ํ™œ์šฉ: ๊ด€๋ จ ํ•ญ๋ชฉ๋ผ๋ฆฌ ํƒœ๊ทธ๋กœ ๋ถ„๋ฅ˜
  5. ๋ณด์•ˆ ๋ณด๊ด€ํ•จ: ๋น„๋ฐ€๋ฒˆํ˜ธ, API ํ‚ค ๋“ฑ ๋ฏผ๊ฐ ์ •๋ณด๋Š” ์•”ํ˜ธํ™” ๋ณด๊ด€
  6. ์Šค๋‹ˆํŽซ: ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ด๋ฉ”์ผ ์„œ๋ช…, ํ…œํ”Œ๋ฆฟ ๋“ฑ์€ ์Šค๋‹ˆํŽซ์œผ๋กœ ์ €์žฅ

๐Ÿงฉ ๊ฐœ๋ฐœ์ž/๋ฆฌํŒฉํ† ๋ง ๋…ธํŠธ

  • smartclipboard_app/legacy_main.py๋Š” ๋ ˆ๊ฑฐ์‹œ ๋Ÿฐํƒ€์ž„์„ ๋กœ๋“œํ•˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ชจ๋“ˆ์ž…๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ๊ฐ’(๊ถŒ์žฅ): payload ๋ชจ๋“œ (smartclipboard_app/legacy_main_payload.marshal) (env: ๋ฏธ์„ค์ • ๋˜๋Š” SMARTCLIPBOARD_LEGACY_IMPL=payload)
  • payload๋Š” legacy_main_payload.manifest.json์œผ๋กœ ํ˜„์žฌ Python minor/source hash๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  • payload ๋กœ๋”ฉ ์‹คํŒจ(ํŒŒ์ผ ๋ˆ„๋ฝ/ํŒŒ์‹ฑ ์‹คํŒจ/manifest ๋ถˆ์ผ์น˜/์‹คํ–‰ ์‹คํŒจ) ์‹œ legacy_main_src.py๋กœ ์ž๋™ ํด๋ฐฑํ•˜๋ฉฐ, LEGACY_IMPL_ACTIVE/LEGACY_IMPL_FALLBACK_REASON ์ƒ์ˆ˜๋กœ ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์†Œ์Šค ๋ชจ๋“œ(์ •์  ๋ถ„์„/ํด๋ž˜์Šค/์‹œ๊ทธ๋„ ์ถ”์ ์šฉ): env SMARTCLIPBOARD_LEGACY_IMPL=src
  • ๋ณต์›๋œ ์›๋ณธ ์†Œ์Šค: smartclipboard_app/legacy_main_src.py (์›๋ณธ: legacy/ํด๋ฆฝ๋ชจ๋“œ ๋งค๋‹ˆ์ € (legacy).py)
  • Pylance/pyright๋Š” ๋ฃจํŠธ pyrightconfig.json์„ ๊ธฐ์ค€์œผ๋กœ ํ˜„ํ–‰ ์œ ์ง€๋ณด์ˆ˜ ์ฝ”๋“œ๋งŒ ๊ฒ€์‚ฌํ•ฉ๋‹ˆ๋‹ค.
  • ์ง์ ‘ clipboard.setText()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ๋กœ๋Š” smartclipboard_app.ui.clipboard_guard.mark_internal_copy()๋ฅผ ๋จผ์ € ๊ฑฐ์ณ ์ž๊ธฐ ์žฌ์ˆ˜์ง‘ ๋ฃจํ”„๋ฅผ ํ”ผํ•ฉ๋‹ˆ๋‹ค.
  • JSON export/import๋Š” IMAGE ํ•ญ๋ชฉ์šฉ image_data_b64 round-trip์„ ์ง€์›ํ•˜๊ณ , CSV/Markdown์€ ์ด๋ฏธ์ง€ BLOB๋ฅผ ์˜๋„์ ์œผ๋กœ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.
  • FILE ํ•ญ๋ชฉ์€ ๊ฒฝ๋กœ ๋ชฉ๋ก ์ค‘์‹ฌ์œผ๋กœ ๋™์ž‘ํ•˜๋ฉฐ, JSON์€ file_paths/file_path, CSV/Markdown์€ newline path content๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • FILE ํ•ญ๋ชฉ์€ ๋ณต์› ์‹œ์ ๋ฟ ์•„๋‹ˆ๋ผ ๋ชฉ๋ก/์ƒ์„ธ/๋ฏธ๋‹ˆ ์ฐฝ์—์„œ ๋ˆ„๋ฝ ๊ฒฝ๋กœ ์ˆ˜๋ฅผ ๋จผ์ € ๋ณด์—ฌ์ฃผ๋ฉฐ, ์ผ๋ถ€๋งŒ ๋‚จ์•„ ์žˆ์œผ๋ฉด ๋ถ€๋ถ„ ๋ณต์› ์ •์ฑ…์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • import ๋ฌด๊ฒฐ์„ฑ ์ •์ฑ…์ƒ CSV ์ด๋ฏธ์ง€ ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋Š” ๋ณต์›ํ•˜์ง€ ์•Š๊ณ , JSON์—์„œ ๋งคํ•‘ ๋ถˆ๊ฐ€ collection_id๋Š” NULL, ๋น„ํ‘œ์ค€ timestamp๋Š” ์ •๊ทœํ™” ๋˜๋Š” import ์‹œ๊ฐ์œผ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.
  • fetch_title์€ ์ฒซ URL๋งŒ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋ฉฐ, ๋กœ์ปฌ/์‚ฌ์„ค/๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ฃผ์†Œ ์ฐจ๋‹จ๊ณผ HTML ์‘๋‹ต ์ œํ•œ์„ ๊ธฐ๋ณธ ์ •์ฑ…์œผ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ์€ vault_salt์™€ vault_verification์ด ํ•จ๊ป˜ ์žˆ์–ด์•ผ ์ •์ƒ ๊ตฌ์„ฑ์œผ๋กœ ๊ฐ„์ฃผํ•˜๋ฉฐ, ์†์ƒ ์ƒํƒœ๋Š” Reset ๋ณต๊ตฌ ํ๋ฆ„์„ ํ†ตํ•ด ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ์กด ๋ชจ๋“ˆ๋Ÿฌ ๋ ˆ์ด์•„์›ƒ README๋Š” legacy/README (modular).md์— ๋ณด๊ด€๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

โš ๏ธ ์•Œ๋ ค์ง„ ์ œํ•œ์‚ฌํ•ญ

  • Windows ์ „์šฉ (macOS/Linux ๋ฏธ์ง€์›)
  • ์ผ๋ถ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ธ€๋กœ๋ฒŒ ํ•ซํ‚ค ์ถฉ๋Œ ๊ฐ€๋Šฅ
  • ์ด๋ฏธ์ง€ ํžˆ์Šคํ† ๋ฆฌ๋Š” ํฌ๊ธฐ์— ๋”ฐ๋ผ DB ์šฉ๋Ÿ‰ ์ฆ๊ฐ€
  • ์Šค๋‹ˆํŽซ ๋‹จ์ถ•ํ‚ค๋Š” ์•ฑ์ด ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋Š” ์•ฑ ๋‚ด๋ถ€ ๋‹จ์ถ•ํ‚ค๋กœ ์ œํ•œ

๐Ÿค ๊ธฐ์—ฌ

๋ฒ„๊ทธ ๋ฆฌํฌํŠธ, ๊ธฐ๋Šฅ ์ œ์•ˆ, PR ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!


๐Ÿ“œ ๋ผ์ด์„ ์Šค

MIT License


Made with โค๏ธ by MySmartTools
ยฉ 2025-2026

2026-04-12 Stabilization Notes

  • ExportImportManager ๊ณต๊ฐœ ๋ฉ”์„œ๋“œ๋Š” ๊ณ„์† int๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ƒ์„ธ ๊ฒฐ๊ณผ๋Š” last_import_report / last_export_report์— ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค.
  • JSON/CSV import๋Š” ์‹œ์ž‘ ์ „์— backups/pre_import_YYYYMMDD_HHMMSS.db ๋ฐฑ์—…์„ ๋งŒ๋“ค๊ณ  ํŒŒ์ผ ๋‹จ์œ„ ๋‹จ์ผ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋ฐ˜์˜๋˜์–ด, ์ค‘๊ฐ„ ์‹คํŒจ ์‹œ ์ „์ฒด rollback ๋ฉ๋‹ˆ๋‹ค.
  • search_items()๋Š” FTS-first ์ •์ฑ…์„ ์œ ์ง€ํ•˜๋ฉด์„œ FTS 0๊ฑด์ผ ๋•Œ๋งŒ LIKE ๋ณด์™„ ๊ฒ€์ƒ‰์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. _last_search_fallback์€ ์‹ค์ œ FTS ์˜ค๋ฅ˜์ผ ๋•Œ๋งŒ UI ๊ฒฝ๊ณ ์šฉ์œผ๋กœ ์ผœ์ง‘๋‹ˆ๋‹ค.
  • ClipboardActionManager๋Š” ์ „์šฉ QThreadPool(maxThreadCount=4)๊ณผ URL ๊ธฐ์ค€ in-flight dedupe/cache๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋Šฆ๊ฒŒ ๋„์ฐฉํ•œ title ๊ฒฐ๊ณผ๋Š” ํ˜„์žฌ row์˜ ์ฒซ URL์ด ์—ฌ์ „ํžˆ ๊ฐ™์€ ๊ฒฝ์šฐ์—๋งŒ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.
  • history.file_signature ์ปฌ๋Ÿผ๊ณผ ์ธ๋ฑ์Šค๋ฅผ ์‚ฌ์šฉํ•ด FILE ์ค‘๋ณต ํŒ๋ณ„์„ ์ „์ฒด row ์ˆœํšŒ ๋Œ€์‹  canonicalized path signature lookup์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณด์•ˆ ๋ณด๊ด€ํ•จ ๋ณตํ˜ธํ™” ํ…์ŠคํŠธ๋Š” ํ”„๋กœ์„ธ์Šค ๋‚ด armed clipboard state๋กœ ์ถ”์ ๋˜๋ฉฐ, 30์ดˆ ์กฐ๊ฑด๋ถ€ clear์™€ ์•ฑ ์ข…๋ฃŒ ์‹œ ์ฆ‰์‹œ clear๋ฅผ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ์„ค์ • ์ €์žฅ ์‹œ mini_window_enabled ๋ณ€๊ฒฝ์œผ๋กœ ํ•ซํ‚ค ์žฌ๋“ฑ๋ก์ด ์‹คํŒจํ•˜๋ฉด ๊ทธ ์„ค์ •๋งŒ ๋˜๋Œ๋ฆฌ๊ณ  ์‹ค์ œ _last_hotkey_error๋ฅผ ๊ฒฝ๊ณ ๋กœ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
  • smartclipboard.spec์€ ์ด๋ฒˆ ์•ˆ์ •ํ™” ๊ธฐ์ค€์œผ๋กœ payload manifest(legacy_main_payload.manifest.json)๊นŒ์ง€ ํฌํ•จํ•˜๋„๋ก ์ •๋ฆฌ๋˜์–ด ์žˆ์œผ๋ฉฐ, ๋ณ„๋„ ์ถ”๊ฐ€ hidden import ์ฆ์„ค์€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

2026-04-16 Functional Follow-up

  • ClipboardActionManager์˜ ๋™๊ธฐ ํ…์ŠคํŠธ ์•ก์…˜(format_phone, format_email, transform)์€ ์ˆœ์ฐจ์ ์œผ๋กœ working text๋ฅผ ๊ฐฑ์‹ ํ•˜๋ฉฐ, fetch_title์€ ๋™๊ธฐ ์น˜ํ™˜์ด ๋๋‚œ ์ตœ์ข… ํ…์ŠคํŠธ์—์„œ URL์„ ๋‹ค์‹œ ์ถ”์ถœํ•ฉ๋‹ˆ๋‹ค.
  • ์•ก์…˜ ๊ฒฐ๊ณผ๊ฐ€ ํ…์ŠคํŠธ ์น˜ํ™˜์ด๋ฉด history row(content/type/url_title/file_path/file_signature)์™€ clipboard๋ฅผ ํ•จ๊ป˜ ๊ฐฑ์‹ ํ•ด UI/์ €์žฅ์†Œ/์‹ค์ œ clipboard๊ฐ€ ๊ฐ™์€ ๊ฐ’์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • JSON import๋กœ ์ปฌ๋ ‰์…˜์ด ์ถ”๊ฐ€๋˜๋ฉด refresh_collection_filter_options()๋ฅผ ๋จผ์ € ํ˜ธ์ถœํ•ด ๋ฉ”์ธ ์ƒ๋‹จ ํ•„ํ„ฐ๊ฐ€ ์ฆ‰์‹œ ์ตœ์‹  ๋ชฉ๋ก์„ ๋ฐ˜์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋Š” query๊ฐ€ ์žˆ์„ ๋•Œ DB/FTS relevance ์ˆœ์„œ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์œ ์ง€ํ•˜๊ณ , ์‚ฌ์šฉ์ž๊ฐ€ ํ—ค๋” ์ •๋ ฌ์„ ์ง์ ‘ ๋ฐ”๊พผ ๊ฒฝ์šฐ์—๋งŒ client-side sort override๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒ€์ƒ‰ 0๊ฑด/๋นˆ ํžˆ์Šคํ† ๋ฆฌ ๊ฒฝ๋กœ์—์„œ๋„ update_status_bar(0)์„ ํ˜ธ์ถœํ•ด ์ด์ „ ์นด์šดํŠธ๊ฐ€ ๋‚จ์ง€ ์•Š๋„๋ก ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

MainWindow ๋ถ„ํ•  ๊ตฌ์กฐ (2026-03-07)

  • smartclipboard_app/legacy_main_src.py์˜ MainWindow ๊ณต๊ฐœ ๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋Š” ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.
  • ์‹ค์ œ ๊ตฌํ˜„์€ smartclipboard_app/features/ ๋„๋ฉ”์ธ ํŒจํ‚ค์ง€๋กœ ์ด๋™ํ–ˆ๊ณ , smartclipboard_app/ui/mainwindow_parts/๋Š” import ํ˜ธํ™˜์šฉ shim์œผ๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.
    • features/settings: ํ…Œ๋งˆ/QSS/controller
    • features/shell_ui: ๋ฉ”์ธ ๋ ˆ์ด์•„์›ƒ, drag-drop, UI controller
    • features/history: ๋ฉ”๋‰ด/ํ…Œ์ด๋ธ”/view/controller
    • features/clipboard: runtime pipeline/controller
    • features/tray_hotkey: ์‹œ์Šคํ…œ ํŠธ๋ ˆ์ด/ํ•ซํ‚ค/controller
    • features/shell: ์ƒํƒœ๋ฐ”/์ •๋ฆฌ/์ข…๋ฃŒ controller
  • ์‹œ๊ทธ๋„ ์Šค๋ƒ…์ƒท ๊ฒ€์ฆ(scripts/refactor_signal_snapshot.py, tests/test_signal_snapshot.py)์€ legacy_main_src.py์™€ shim+feature ๊ตฌํ˜„ ํŒŒ์ผ์„ ํ•จ๊ป˜ ์Šค์บ”ํ•ฉ๋‹ˆ๋‹ค.
  • ๋กœ์ปฌ ์‚ฌ์ „๊ฒ€์ฆ(scripts/preflight_local.py)์˜ py_compile ๋‹จ๊ณ„๋Š” ui/**/*.py, features/**/*.py, db_parts/**/*.py, automation/**/*.py๋ฅผ ์žฌ๊ท€ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œ ์ •ํ•ฉ์„ฑ ๊ธฐ์ค€ (2026-04-13)

  • ์‹คํ–‰/๋นŒ๋“œ/๊ฒ€์ฆ ๊ธฐ์ค€ ๋ฌธ์„œ๋Š” ๋ฃจํŠธ README.md์ด๋ฉฐ, claude.md, .gemini/GEMINI.md, legacy/README (modular).md๋Š” ๋™์ผ ๊ธฐ์ค€์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค.
  • ๊ถŒ์žฅ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ๊ธฐ์ค€์€ test_core, test_ui_dialogs_widgets, test_payload_sync, test_legacy_loader, test_migration_collections, test_legacy_ui_contracts, test_signal_snapshot, test_public_surfaces์ž…๋‹ˆ๋‹ค.
  • PyInstaller ๊ธฐ์ค€(smartclipboard.spec)์€ payload ๋ฐ์ดํ„ฐ(legacy_main_payload.marshal)์™€ payload manifest(legacy_main_payload.manifest.json)๋ฅผ ํ•จ๊ป˜ ํฌํ•จํ•˜๊ณ , smartclipboard_core, smartclipboard_app.ui.mainwindow_parts ํ•˜์œ„ ๋ชจ๋“ˆ์„ hidden import๋กœ ์ž๋™ ์ˆ˜์ง‘ํ•˜๋ฉฐ, payload์—์„œ ์ง์ ‘ ์ฐธ์กฐํ•˜๋Š” ๋Œ€ํ™”์ƒ์ž ๋ชจ๋“ˆ(smartclipboard_app.ui.dialogs.collections ํฌํ•จ)์„ ๋ช…์‹œ์ ์œผ๋กœ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • 2026-04-13 ๊ธฐ์ค€ ์ถ”๊ฐ€ ํŒจํ‚ค์ง• ์ž์‚ฐ์€ payload manifest 1๊ฑด์ด๋ฉฐ, ํ˜„์žฌ spec์— ๋ฐ˜์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Refactor Layout (2026-03-12)

  • smartclipboard_core/database.py is now a composition entrypoint.
  • Database implementation now keeps flat facades in smartclipboard_core/db_parts/*.py and subpackages in:
    • db_parts/search/
    • db_parts/automation/
    • db_parts/catalog/
    • db_parts/retention/
  • smartclipboard_core/actions.py is a public facade; implementation lives in smartclipboard_core/automation/.
  • smartclipboard_app/managers/export_import.py / secure_vault.py are public facades; implementations live in smartclipboard_app/features/import_export/ and smartclipboard_app/features/vault/.
  • scripts/preflight_local.py now compiles both mainwindow_parts/*.py and db_parts/*.py.
  • Added surface-guard test: tests/test_public_surfaces.py and baseline tests/baseline/clipboarddb_public_methods.txt.

2026-04-15 Structure Refactor Delta

  • legacy_main_src.MainWindow now composes feature controllers (clipboard, history/table, tray_hotkey, lifecycle, settings, shell_ui) while preserving public method signatures.
  • smartclipboard_app/features/shared/state.py provides WindowState, WindowServices, WindowWidgets bundles and bind_window_facets() for controller synchronization.
  • smartclipboard_app/ui/controllers/*.py and ui/mainwindow_parts/*.py remain compatibility layers so external imports and payload contracts stay intact.
  • smartclipboard.spec now collects smartclipboard_app.features and smartclipboard_core.automation submodules as hidden imports in addition to the legacy shim modules.

Packages

 
 
 

Contributors

Languages