README_KO.md

August 11, 2026 ยท View on GitHub

๐ŸŒ ๋‹ค๋ฅธ ์–ธ์–ด: ไธญๆ–‡ ยท English ยท ๆ—ฅๆœฌ่ชž ยท Franรงais ยท Deutsch ยท ะ ัƒััะบะธะน ยท Espaรฑol

WeChat ์Šคํƒ€์ผ์˜ ์ข…๋‹จ๊ฐ„ ์•”ํ˜ธํ™” ๋ฉ”์‹ ์ €. ๋ฌด์ƒํƒœ ECDH + XSalsa20-Poly1305 ๋ฉ”์‹œ์ง€๋ณ„ ์•”ํ˜ธํ™”, ์‹ค์‹œ๊ฐ„ ์˜์ƒ ํ†ตํ™”, Cloudflare R2 ํŒŒ์ผ ์ €์žฅ, ๋‹ค๊ตญ์–ด ์ง€์› ๋ฐ iOS PWA ๋ฐฐํฌ ์ง€์›.

Rust React TypeScript MySQL Redis WebRTC License: AGPL v3

Deploy on Zeabur

Version

Google Play App Store Windows Mac


๐Ÿ“ธ ์Šคํฌ๋ฆฐ์ƒท (ํด๋ฆญํ•˜์—ฌ ํ™•์žฅ) ui1 ui2 ui3 ui4 ui5 ui6 ui7 ui8 ui9 ui10 ui11 ui12 ui13 ui14 ui15 ui16 ui17 ui18

๊ธฐ๋Šฅ

๊ธฐ๋Šฅ์„ค๋ช…
๐Ÿ” ์ข…๋‹จ๊ฐ„ ์•”ํ˜ธํ™”๋ฌด์ƒํƒœ ECDH + XSalsa20-Poly1305 โ€” ๋ฉ”์‹œ์ง€๋ณ„ ์ž„์‹œ ํ‚ค ์ƒ์„ฑ, ์ˆœ๋ฐฉํ–ฅ ๋น„๋ฐ€์„ฑ, Signal ๋ฐฉ์‹ ์•ˆ์ „ ๋ฒˆํ˜ธ ๊ฒ€์ฆ
๐Ÿ—๏ธ ์ œ๋กœ ์ง€์‹ ์„œ๋ฒ„์„œ๋ฒ„์—๋Š” ์•”ํ˜ธ๋ฌธ๋งŒ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ์ธ ํ‚ค๋Š” ์ ˆ๋Œ€ ๊ธฐ๊ธฐ ๋ฐ–์œผ๋กœ ์œ ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
๐Ÿ“น ์˜์ƒ ๋ฐ ์Œ์„ฑ ํ†ตํ™”1:1 ํ†ตํ™”์™€ ํšŒ์˜ ๋ชจ๋‘ LiveKit SFU ์‚ฌ์šฉ (์ตœ๋Œ€ 100๋ช…), ์ „์ฒด ์Œ์†Œ๊ฑฐ ๋ฐ ๊ฐ•์˜ ๋ชจ๋“œ
๐ŸŽ™๏ธ ์Œ์„ฑ ๋ณ€์กฐ์Œ์„ฑ ๋ฉ”์‹œ์ง€, 1:1 ํ†ตํ™”, ๊ทธ๋ฃน ํ†ตํ™”์—์„œ ์‹ค์‹œ๊ฐ„ ์Œ์„ฑ ํšจ๊ณผ โ€” 3๊ฐ€์ง€ ๋ชจ๋“œ (0.8x ์ €์Œ / 1.0x ์ผ๋ฐ˜ / 1.2x ๊ณ ์Œ), Web Audio API ๊ธฐ๋ฐ˜
๐Ÿ“ฑ ์„ธ์…˜ ์œ ์ง€30๋ถ„ Access Token๊ณผ ์ž๋™ ์—ฐ์žฅ๋˜๋Š” 90์ผ ๊ธฐ๊ธฐ Refresh Session. ๋„คํŠธ์›Œํฌ/IP/VPN/ํ”„๋ก์‹œ ๋ณ€๊ฒฝ ํ›„์—๋„ ๋น„๋ฐ€๋ฒˆํ˜ธ ์—†์ด ์ž๋™ ๋ณต๊ตฌ
๐Ÿ“จ ์‹ ๋ขฐ์„ฑ ์žˆ๋Š” ๋ฉ”์‹œ์ง€ ๋™๊ธฐํ™”์–‘๋ฐฉํ–ฅ ํ•˜ํŠธ๋น„ํŠธ, ๋ฐ˜๊ฐœ๋ฐฉ ์—ฐ๊ฒฐ ๊ฐ์ง€, ์˜๊ตฌ ๋ณด๋‚ผ ํŽธ์ง€ํ•จ, ๋ฉฑ๋“ฑ ๋ฉ”์‹œ์ง€ ID ๋ฐ ์„œ๋ฒ„ ์‹œํ€€์Šค ์ปค์„œ ๊ธฐ๋ฐ˜ ๋ˆ„๋ฝ ๋ณต๊ตฌ
๐Ÿ“ด ์˜คํ”„๋ผ์ธ ์ ‘๊ทผ๊ณ„์ •๋ณ„๋กœ ์—ฐ๋ฝ์ฒ˜, ๊ทธ๋ฃน, ๋Œ€ํ™”๋‹น ์ตœ๋Œ€ 2,000๊ฐœ ๋ฉ”์‹œ์ง€, ๋ชจ๋จผํŠธ, ํƒ€์ž„๋ผ์ธ ๋ฐ ๋ฏธ๋””์–ด๋ฅผ ์บ์‹œํ•˜๋ฉฐ ์˜คํ”„๋ผ์ธ ์ „์†ก์€ ์ž๋™ ์žฌ์‹œ๋„
๐Ÿ”Ž Unicode ์นœ๊ตฌ ๊ฒ€์ƒ‰IME ์กฐํ•ฉ ๋ณดํ˜ธ, NFC ์ •๊ทœํ™” ๋ฐ UTF-8 ์ฟผ๋ฆฌ ์ธ์ฝ”๋”ฉ์œผ๋กœ ์ค‘๊ตญ์–ด ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ๋ณ„๋ช…์„ ์•ˆ์ •์ ์œผ๋กœ ๊ฒ€์ƒ‰
๐Ÿ‘ฅ ๊ทธ๋ฃน ์ฑ„ํŒ…์ตœ๋Œ€ 2000๋ช…, "์•”ํ˜ธํ™”" / "๋น„์•”ํ˜ธํ™”" ๋ชจ๋“œ ์ „ํ™˜ ๊ฐ€๋Šฅ (๊ทธ๋ฃน ์†Œ์œ ์ž๋งŒ ์ „ํ™˜ ๊ฐ€๋Šฅ, ์ „ํ™˜ ์‹œ ์ฑ„ํŒ… ๊ธฐ๋ก ์‚ญ์ œ). ์•”ํ˜ธํ™” ๋ชจ๋“œ๋Š” Signal ์Šคํƒ€์ผ Sender Key ํ”„๋กœํ† ์ฝœ (XSalsa20-Poly1305 ๋Œ€์นญ ์•”ํ˜ธํ™” + ECDH ํ‚ค ๋ฐฐํฌ) ์‚ฌ์šฉ โ€” ๊ทธ๋ฃน ๋ฉค๋ฒ„๋งŒ ๋ฉ”์‹œ์ง€ ๋ณตํ˜ธํ™” ๊ฐ€๋Šฅ, ์•”ํ˜ธํ™” ๋ชจ๋“œ์—์„œ๋Š” ๋ด‡ ์‚ฌ์šฉ ๋ถˆ๊ฐ€. ๋ฐฉํ•ด ๊ธˆ์ง€ ๋ชจ๋“œ, ๋ฉค๋ฒ„ ๊ด€๋ฆฌ
๐Ÿ‘ซ ์นœ๊ตฌ ์‹œ์Šคํ…œ์นœ๊ตฌ ์š”์ฒญ ์‹œ ์ตœ๋Œ€ 512์ž ๋ฉ”์‹œ์ง€์™€ ํ•จ๊ป˜ ์Šน์ธ ํ•„์š”; ์‚ฌ์šฉ์ž ์ง€์ • ๋ณ„๋ช…; ๋‹ค์ค‘ ํƒœ๊ทธ ๋ถ„๋ฅ˜
โฑ๏ธ ๋ฉ”์‹œ์ง€ ์ž๋™ ์‚ญ์ œ5๋‹จ๊ณ„ (์—†์Œ / 1์ผ / 3์ผ / 1์ฃผ์ผ / 1๊ฐœ์›”), DM์—์„œ๋Š” ์–‘์ชฝ ๋ชจ๋‘ ์„ค์ • ๊ฐ€๋Šฅ, ๊ทธ๋ฃน์—์„œ๋Š” ์†Œ์œ ์ž๋งŒ ์„ค์ • ๊ฐ€๋Šฅ
๐Ÿ”” ํ‘ธ์‹œ ์•Œ๋ฆผWeb Push (VAPID) + FCM + OneSignal + ntfy + APNS 5์ฑ„๋„ โ€” ์˜คํ”„๋ผ์ธ ์‚ฌ์šฉ์ž์—๊ฒŒ๋„ ์ „๋‹ฌ (iOS ๋„ค์ดํ‹ฐ๋ธŒ + Google ์„œ๋น„์Šค ์—†๋Š” ์ค‘๊ตญ์‚ฐ Android ์ง€์›)
๐ŸŒ ๋‹ค๊ตญ์–ด ์ง€์›์ค‘๊ตญ์–ด, ์˜์–ด, ์ผ๋ณธ์–ด, ํ•œ๊ตญ์–ด, ํ”„๋ž‘์Šค์–ด, ๋…์ผ์–ด, ๋Ÿฌ์‹œ์•„์–ด, ์ŠคํŽ˜์ธ์–ด โ€” ์ž๋™ ๊ฐ์ง€ + ์ˆ˜๋™ ์ „ํ™˜
๐Ÿ“ฑ iOS โ€” ๊ธฐ์—… ์ธ์ฆ์„œ ๋ถˆํ•„์š”Safari์—์„œ "ํ™ˆ ํ™”๋ฉด์— ์ถ”๊ฐ€" PWA ๋ฐฉ์‹์œผ๋กœ Apple ์„œ๋ช… ์—†์ด ์˜๊ตฌ์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
๐Ÿ“ฑ Android ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑGoogle Play์—์„œ ๋‹ค์šด๋กœ๋“œ ๊ฐ€๋Šฅ, FCM ํ‘ธ์‹œ ์•Œ๋ฆผ ์ง€์›
๐Ÿ“ฑ iOS ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑApp Store์—์„œ ๋‹ค์šด๋กœ๋“œ ๊ฐ€๋Šฅ, APNS ํ‘ธ์‹œ ์•Œ๋ฆผ ์ง€์›
๐Ÿ–ฅ๏ธ Windows ๋ฐ์Šคํฌํ†ฑ ํด๋ผ์ด์–ธํŠธWindows ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐ์Šคํฌํ†ฑ ์•ฑ, ์—ฌ๊ธฐ์—์„œ ๋‹ค์šด๋กœ๋“œ
๐ŸŽ Mac ๋ฐ์Šคํฌํ†ฑ ํด๋ผ์ด์–ธํŠธMac ๋„ค์ดํ‹ฐ๋ธŒ ๋ฐ์Šคํฌํ†ฑ ์•ฑ, ์—ฌ๊ธฐ์—์„œ ๋‹ค์šด๋กœ๋“œ
๐Ÿ’ฌ ๋ฆฌ์น˜ ๋ฉ”์‹œ์ง€ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€, ์˜์ƒ, ๋ฌธ์„œ ํŒŒ์ผ, ์Œ์„ฑ ๋ฉ”์‹œ์ง€, 200+ ์ด๋ชจ์ง€, Telegram ์Šคํ‹ฐ์ปค ํŒฉ, ์ˆ˜์‹  ํ™•์ธ, ์ž…๋ ฅ ์ค‘ ํ‘œ์‹œ
๐Ÿ“ค ํŒŒ์ผ ์—…๋กœ๋“œํŒŒ์ผ๋‹น ์ตœ๋Œ€ 500MB, Cloudflare R2 ๋˜๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ, ์ง„ํ–‰๋ฅ  ์• ๋‹ˆ๋ฉ”์ด์…˜
๐ŸŒ ๋ชจ๋จผํŠธWeChat ์Šคํƒ€์ผ ์†Œ์…œ ํ”ผ๋“œ: ํ…์ŠคํŠธ + ์ตœ๋Œ€ 9์žฅ ์‚ฌ์ง„ ๋˜๋Š” 1๊ฐœ ์˜์ƒ (โ‰ค 10๋ถ„), ์ข‹์•„์š”, ๋Œ“๊ธ€, ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ๊ณต๊ฐœ ๋ฒ”์œ„ ์„ค์ •
๐Ÿ‘ค ์‚ฌ์šฉ์ž ํ”„๋กœํ•„์—ฐ๋ฝ์ฒ˜ ํ”„๋กœํ•„ ํŽ˜์ด์ง€, ์–‘๋ฐฉํ–ฅ ๋ชจ๋จผํŠธ ๊ฐœ์ธ์ •๋ณด ์ œ์–ด
๐Ÿ“ฐ ํƒ€์ž„๋ผ์ธ์ƒค์˜คํ™์Šˆ ์Šคํƒ€์ผ ๊ณต๊ฐœ ํ”ผ๋“œ โ€” 2์—ด ๋งค๊ฑฐ์ง„ ๋ ˆ์ด์•„์›ƒ, ์ต๋ช… ๊ฒŒ์‹œ, ์ข‹์•„์š” ๋ฐ ๋Œ“๊ธ€
๐Ÿท๏ธ ์นœ๊ตฌ ํƒœ๊ทธ์นœ๊ตฌ์—๊ฒŒ ์—ฌ๋Ÿฌ ํƒœ๊ทธ ํ• ๋‹น (12์ƒ‰ ํŒ”๋ ˆํŠธ), ํƒœ๊ทธ๋ณ„ ์—ฐ๋ฝ์ฒ˜ ํ•„ํ„ฐ๋ง
๐Ÿ—‚๏ธ R2 ์˜ค๋ธŒ์ ํŠธ ์Šคํ† ๋ฆฌ์ง€์ด๋ฏธ์ง€/์Œ์„ฑ ํŒŒ์ผ์šฉ Cloudflare R2 โ€” ์„ ํƒ์  ๊ณต๊ฐœ CDN URL
๐Ÿ”‘ 2๋‹จ๊ณ„ ์ธ์ฆ (2FA)Google Authenticator ํ˜ธํ™˜ TOTP, 8๊ฐœ ๋ณต๊ตฌ ์ฝ”๋“œ, ๋กœ๊ทธ์ธ ์‹œ ์ ์šฉ
๐Ÿ“ท QR ์ฝ”๋“œ ์Šค์บ” ๋ฐ ๊ณต์œ QR ์ฝ”๋“œ๋กœ ์นœ๊ตฌ ์ถ”๊ฐ€ ๋˜๋Š” ๊ทธ๋ฃน ์ฐธ์—ฌ, ๋งŒ๋ฃŒ ๊ธฐ๊ฐ„ ์„ค์ • ๊ฐ€๋Šฅ
๐Ÿ—๏ธ ์…€ํ”„ ํ˜ธ์ŠคํŒ…Docker Compose, Zeabur ์›ํด๋ฆญ, ๋˜๋Š” Vercel์— ํ”„๋ก ํŠธ์—”๋“œ ๋ฐฐํฌ
๐ŸŒ ํ”„๋ก์‹œ ์„ค์ •SOCKS5 / HTTP / HTTPS ํ”„๋ก์‹œ ์ง€์› โ€” ๋กœ๊ทธ์ธ ๋ฐ ์„ค์ • ํŽ˜์ด์ง€์—์„œ ์„œ๋ฒ„ ์ฃผ์†Œ, ํฌํŠธ, ์‚ฌ์šฉ์ž ์ด๋ฆ„, ๋น„๋ฐ€๋ฒˆํ˜ธ ์„ค์ • ๊ฐ€๋Šฅ
๐Ÿ›ก๏ธ ์ฝ˜ํ…์ธ  ๊ด€๋ฆฌ์‚ฌ์šฉ์ž ์‹ ๊ณ  (6๊ฐ€์ง€ ์นดํ…Œ๊ณ ๋ฆฌ) + ์‚ฌ์šฉ์ž ์ฐจ๋‹จ (๊ฒŒ์‹œ๋ฌผ/๋ฉ”์‹œ์ง€ ์ฆ‰์‹œ ์ˆจ๊น€) + ์ด์šฉ์•ฝ๊ด€ (EULA)
๐Ÿ”ง ๊ด€๋ฆฌ์ž ํŒจ๋„๋‚ด์žฅ ์›น ๊ด€๋ฆฌ ๋Œ€์‹œ๋ณด๋“œ (/admin, ๊ฒฝ๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ), ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณดํ˜ธ, ์‹ ๊ณ  ๊ฒ€ํ† , ์ฝ˜ํ…์ธ  ์‚ญ์ œ, ์‚ฌ์šฉ์ž ์ฐจ๋‹จ โ€” 8๊ฐœ ์–ธ์–ด ์ง€์›

v2.3.9 ์—…๋ฐ์ดํŠธ

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

v2.3.8 ์—…๋ฐ์ดํŠธ

  • QR ์Šค์บ๋„ˆ ์นด๋ฉ”๋ผ ์‹œ์ž‘ ํ›„ ๋’ค๋กœ ๊ฐ€๊ธฐ ๋ฒ„ํŠผ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋˜ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์œผ๋ฉฐ, ๋‹ซ์„ ๋•Œ ์นด๋ฉ”๋ผ๋ฅผ ์ฆ‰์‹œ ์ค‘์ง€ํ•˜๊ณ  ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ์กด ์นœ๊ตฌ์—๊ฒŒ ์ค‘๋ณต ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์นœ๊ตฌ ๊ด€๊ณ„๊ฐ€ ์†์ƒ๋˜๋˜ ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์œผ๋ฉฐ, ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์— โ€˜์ด๋ฏธ ์นœ๊ตฌ์ž…๋‹ˆ๋‹คโ€™๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.
  • ์ข…๋‹จ๊ฐ„ ์•”ํ˜ธํ™” ์งํ›„ ๋ฐœ์‹  ๊ฐœ์ธ ๋ฉ”์‹œ์ง€์˜ ๋‚™๊ด€์  ๊ฐ์ฒด์— ์•”ํ˜ธ๋ฌธ์„ ๊ธฐ๋กํ•˜์—ฌ ์„œ๋ฒ„ ํ™•์ธ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์•ˆ ํ‰๋ฌธ์ด ์ž ์‹œ ์ €์žฅ๋˜์ง€ ์•Š๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์Œ์„ฑ ๋ฉ”์‹œ์ง€๋Š” ์ตœ๋Œ€ 120์ดˆ์—์„œ ์ž๋™ ์ค‘์ง€๋˜๋ฉฐ ์Œ์„ฑ ๋ณ€์กฐ ๊ฒฐ๊ณผ์—๋„ ๊ฐ™์€ ์ œํ•œ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋…น์Œ๊ณผ ํ†ตํ™” ์ค‘ ํ™”๋ฉด์„ ์ผœ ๋‘๊ณ  ํŽ˜์ด์ง€๋ฅผ ๋– ๋‚  ๋•Œ ๋…น์Œ ์žฅ์น˜์™€ ํƒ€์ด๋จธ๋ฅผ ํ™•์‹คํžˆ ํ•ด์ œํ•ฉ๋‹ˆ๋‹ค.
  • Android๋Š” Android Keystore์™€ AES-256-GCM์œผ๋กœ ํ‚ค์™€ ์บ์‹œ๋„ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค. Web ํด๋ผ์ด์–ธํŠธ๋Š” ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

์„ธ์…˜ ๋ณต๊ตฌ์™€ ๋ฉ”์‹œ์ง€ ์‹ ๋ขฐ์„ฑ

PaperPhonePlus๋Š” ๋กœ์ปฌ ๊ณ„์ • ์ƒํƒœ, ์‹ค์‹œ๊ฐ„ ์—ฐ๊ฒฐ ์ƒํƒœ, ๋ฉ”์‹œ์ง€ ๋™๊ธฐํ™” ์ƒํƒœ๋ฅผ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. WebSocket์ด ์—ด๋ ค ์žˆ์–ด๋„ ์„œ๋ฒ„์˜ auth_ok๋ฅผ ๋ฐ›๊ธฐ ์ „์—๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์—ฐ๊ฒฐ๋กœ ๊ฐ„์ฃผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์–‘๋ฐฉํ–ฅ ping/pong์œผ๋กœ VPN/IP ๋ณ€๊ฒฝ, Wi-Fi/๋ชจ๋ฐ”์ผ ์ „ํ™˜, ์•ฑ ์ผ์‹œ ์ค‘๋‹จ์œผ๋กœ ์ƒ๊ธฐ๋Š” ๋ฐ˜๊ฐœ๋ฐฉ ์—ฐ๊ฒฐ์„ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.

  • Access Token์€ 30๋ถ„ ๋™์•ˆ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๊ธฐ Refresh Token์€ 90์ผ ๋™์•ˆ ์œ ํšจํ•˜๋ฉฐ ํ™œ๋ฐœํžˆ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ ์—ฐ์žฅ๋˜์–ด ๋น„๋ฐ€๋ฒˆํ˜ธ ์žฌ์ž…๋ ฅ ์—†์ด ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.
  • ์ด์ „ ๋ฒ„์ „์—์„œ ์ด๋ฏธ ๋กœ๊ทธ์ธํ•œ ๊ธฐ๊ธฐ๋Š” ๊ธฐ์กด Token์ด ์œ ํšจํ•œ ๋™์•ˆ ์ž๋™ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฏธ ๋งŒ๋ฃŒ๋œ ๊ฒฝ์šฐ์—๋งŒ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•œ ๋ฒˆ ์ง์ ‘ ๋กœ๊ทธ์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ๋ฐœ์‹  ๋ฉ”์‹œ์ง€์—๋Š” ์•ˆ์ •์ ์ธ client_msg_id๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ACK๋ฅผ ๋ฐ›์ง€ ๋ชปํ•œ ๋ฉ”์‹œ์ง€๋Š” ์˜๊ตฌ ๋กœ์ปฌ ๋ณด๋‚ผ ํŽธ์ง€ํ•จ์— ๋‚จ์•„ ๊ฐ™์€ ID๋กœ ์žฌ์ „์†ก๋˜๋ฉฐ, ์„œ๋ฒ„ ๊ณ ์œ  ์ œ์•ฝ ์กฐ๊ฑด์ด ์ค‘๋ณต ์ €์žฅ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์ €์žฅ๋œ ๋ฉ”์‹œ์ง€์—๋Š” ๋‹จ์กฐ ์ฆ๊ฐ€ํ•˜๋Š” server_seq๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ธ์ฆ, ์žฌ์—ฐ๊ฒฐ, ํฌ๊ทธ๋ผ์šด๋“œ ๋ณต๊ท€ ํ›„ ์ปค์„œ ๊ธฐ๋ฐ˜์œผ๋กœ ๋ˆ„๋ฝ๋œ ๋ฉ”์‹œ์ง€๋ฅผ ๋™๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ช…์‹œ์  ๋กœ๊ทธ์•„์›ƒ๊ณผ ๊ธฐ๊ธฐ ์ทจ์†Œ๋Š” ์žฅ๊ธฐ ์„œ๋ฒ„ ์„ธ์…˜์„ ๋ฌดํšจํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ์ „์†ก ์˜ค๋ฅ˜์™€ IP ๋ณ€๊ฒฝ์€ ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

Important

์—…๊ทธ๋ ˆ์ด๋“œ ์‹œ server๋ฅผ ๋จผ์ € ๋ฐฐํฌํ•˜๊ณ  client๋ฅผ ๋‚˜์ค‘์— ๋ฐฐํฌํ•˜์„ธ์š”. server๋Š” ์‹ ๋ขฐ์„ฑ DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ์ž๋™ ์ ์šฉยท๊ฒ€์ฆํ•˜๋ฉฐ ํ•„์ˆ˜ ์—ด์ด ์—†์œผ๋ฉด ์‹œ์ž‘ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ์—…๊ทธ๋ ˆ์ด๋“œ ์ „์— MySQL์„ ๋ฐฑ์—…ํ•˜์„ธ์š”.


๊ธฐ์ˆ  ์Šคํƒ

๋ฐฑ์—”๋“œ (server/)
  Rust (Axum 0.8) โ€” ๊ณ ์„ฑ๋Šฅ ๋น„๋™๊ธฐ ์›น ํ”„๋ ˆ์ž„์›Œํฌ
  sqlx + MySQL 8.0 โ€” ์‚ฌ์šฉ์ž/๋ฉ”์‹œ์ง€ ์˜์†ํ™”
  deadpool-redis + Redis 7 โ€” ์˜จ๋ผ์ธ ์ƒํƒœ + ํฌ๋กœ์Šค ๋…ธ๋“œ ๋ผ์šฐํŒ…
  aws-sdk-s3 โ€” Cloudflare R2 ํŒŒ์ผ ์ €์žฅ์†Œ (S3 ํ˜ธํ™˜ API)
  argon2 + jsonwebtoken ์ธ์ฆ

ํ”„๋ก ํŠธ์—”๋“œ (client/)
  React 19 + TypeScript + Vite 6
  Zustand ์ƒํƒœ ๊ด€๋ฆฌ
  libsodium-wrappers-sumo (WebAssembly โ€” Curve25519 / XSalsa20-Poly1305)
  WebRTC API โ€” ์˜์ƒ/์Œ์„ฑ ํ†ตํ™”
  Web Audio API โ€” ์‹ค์‹œ๊ฐ„ ์Œ์„ฑ ๋ณ€์กฐ (ScriptProcessorNode ์˜ค๋””์˜ค ์ฒด์ธ)
  PWA: manifest.json + Service Worker

์•”ํ˜ธํ™” ๋ ˆ์ด์–ด
  ๋ฌด์ƒํƒœ ECDH + XSalsa20-Poly1305 โ€” ๋ฉ”์‹œ์ง€๋ณ„ ์ž„์‹œ ํ‚คํŽ˜์–ด ์ƒ์„ฑ
  4๋‹จ๊ณ„ ํ‚ค ์ €์žฅ: memory โ†’ localStorage โ†’ sessionStorage โ†’ IndexedDB
  ๋ชจ๋“  ๊ฐœ์ธ ํ‚ค๋Š” ๊ธฐ๊ธฐ์—๋งŒ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค โ€” ์„œ๋ฒ„๋กœ ์ „์†ก๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

๐Ÿ“– ์ƒ์„ธ ๋ฐฐํฌ ๊ฐ€์ด๋“œ (ไธญๆ–‡) | Deployment Guide (English) โ€” Zeabur + Vercel ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฐํฌ, Docker Compose + Nginx ๋กœ์ปฌ ๋ฐฐํฌ ๋ฐ ํด๋ผ์ด์–ธํŠธ ์„œ๋ฒ„ ์ฃผ์†Œ ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ๋‹จ๊ณ„๋ณ„ ์ „์ฒด ๊ฐ€์ด๋“œ.

์˜ต์…˜ 0: Zeabur ์›ํด๋ฆญ ํด๋ผ์šฐ๋“œ ๋ฐฐํฌ

Deploy on Zeabur

Zeabur ํ†ตํ™” ๋„คํŠธ์›Œํฌ ์ œํ•œ: ํ…œํ”Œ๋ฆฟ์€ WebSocket/API 7880๊ณผ ICE/TCP 7881๋กœ LiveKit์„ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค. ํ˜„์žฌ Zeabur๋Š” UDP ์„œ๋น„์Šค ํฌํŠธ๋ฅผ ๋…ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ 1:1 ํ†ตํ™”์™€ ํšŒ์˜๋Š” TCP ํด๋ฐฑ์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜ ํ†ตํ™”์—๋Š” LiveKit Cloud ๋˜๋Š” UDP๋ฅผ ์ง€์›ํ•˜๋Š” VM์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.

์„œ๋ฒ„ Nginx ๊ตฌ์„ฑ

๋‘ ๋„๋ฉ”์ธ์šฉ ํ”„๋กœ๋•์…˜ ์„ค์ • deploy/nginx/paperphone-plus.conf์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค. api.example.com๊ณผ meeting.example.com์„ ์‹ค์ œ ๋„๋ฉ”์ธ์œผ๋กœ ๋ฐ”๊พธ๊ณ  TLS ์ธ์ฆ์„œ๋ฅผ ๋ฐœ๊ธ‰ํ•œ ๋’ค ํŒŒ์ผ์„ /etc/nginx/sites-available/paperphone-plus์— ๋ณต์‚ฌํ•˜์—ฌ ํ™œ์„ฑํ™”ํ•˜๊ณ  sudo nginx -t && sudo systemctl reload nginx๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ์—๋Š” LIVEKIT_URL=wss://meeting.example.com์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. Nginx๋Š” API์™€ WebSocket๋งŒ ํ”„๋ก์‹œํ•˜๋ฏ€๋กœ TCP 7881๊ณผ UDP 7882๋Š” ํ˜ธ์ŠคํŠธ ๋ฐ ํด๋ผ์šฐ๋“œ ๋ฐฉํ™”๋ฒฝ์—์„œ ์ง์ ‘ ๊ฐœ๋ฐฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Tip

๊ณ ๊ธ‰: Zeabur + Vercel ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฐํฌ Zeabur์— ๋ฐฐํฌํ•œ ํ›„ client ์„œ๋น„์Šค๋ฅผ ์ˆ˜๋™์œผ๋กœ ์‚ญ์ œํ•˜๊ณ  ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ Vercel์— ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์•„๋ž˜ ์˜ต์…˜ 2 ์ฐธ์กฐ). ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด server/MySQL/Redis๋Š” Zeabur์—์„œ ํ˜ธ์ŠคํŒ…๋˜๊ณ  ํ”„๋ก ํŠธ์—”๋“œ๋Š” Vercel์˜ ๊ธ€๋กœ๋ฒŒ CDN์œผ๋กœ ๊ฐ€์†๋ฉ๋‹ˆ๋‹ค. ํ”„๋ก ํŠธ์—”๋“œ์—๋Š” Vercel์—์„œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค โ€” ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์˜ต์…˜ 1: Docker Compose (๊ถŒ์žฅ)

git clone <repo-url> && cd paperphone-plus
cp server/.env.example server/.env
# ํŽธ์ง‘: DB_PASS / JWT_SECRET / LIVEKIT_URL ๋“ฑ
docker compose up -d
open http://localhost

์˜ต์…˜ 2: Vercel์— ํ”„๋ก ํŠธ์—”๋“œ ๋ฐฐํฌ

# 1. ์ด ์ €์žฅ์†Œ๋ฅผ ํฌํฌํ•ฉ๋‹ˆ๋‹ค
# 2. Vercel์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ: Root Directory = client/, Build = npm run build, Output = dist/
#    ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค
# 3. Docker ๋˜๋Š” Zeabur๋ฅผ ํ†ตํ•ด ๋ฐฑ์—”๋“œ๋ฅผ ๋ฐฐํฌํ•ฉ๋‹ˆ๋‹ค
# 4. Vercel์— ๋ฐฐํฌ๋œ ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ์—ด๊ณ  ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์—์„œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์ฃผ์†Œ๋ฅผ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค
#    ์˜ˆ: https://your-server.zeabur.app

์˜ต์…˜ 3: ๋กœ์ปฌ ๊ฐœ๋ฐœ

# ๋ฐฑ์—”๋“œ (Rust)
cd server && cp .env.example .env && cargo run --release

# ํ”„๋ก ํŠธ์—”๋“œ (React)
cd client && npm install && npm run dev

์Œ์„ฑ ๋ณ€์กฐ

์Œ์„ฑ ๋ฉ”์‹œ์ง€, 1:1 ํ†ตํ™”, ๊ทธ๋ฃน ํ†ตํ™” ๋ชจ๋‘ ์‹ค์‹œ๊ฐ„ ์Œ์„ฑ ๋ณ€์กฐ๋ฅผ ์ง€์›ํ•˜๋ฉฐ 3๊ฐ€์ง€ ๋ชจ๋“œ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

๋ชจ๋“œ์†๋„ํšจ๊ณผ
๐Ÿข ๋А๋ฆฌ๊ฒŒ0.8x๋” ๊นŠ๊ณ  ๋‚ฎ์€ ์Œ์„ฑ โ€” ์ต๋ช…์„ฑ์— ์ ํ•ฉ
๐Ÿ”Š ์ผ๋ฐ˜1.0x์›๋ž˜ ์Œ์„ฑ, ์ฒ˜๋ฆฌ ์—†์Œ
๐Ÿ‡ ๋น ๋ฅด๊ฒŒ1.2x๋” ๋†’์€ ์Œ์„ฑ โ€” ์žฌ๋ฏธ์žˆ๊ณ  ์žฅ๋‚œ์Šค๋Ÿฌ์šด ํšจ๊ณผ

์ž‘๋™ ์›๋ฆฌ: Web Audio API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ค๋””์˜ค ์ฒ˜๋ฆฌ ์ฒด์ธ (AudioContext โ†’ MediaStreamSource โ†’ ScriptProcessorNode โ†’ MediaStreamDestination)์„ ๊ตฌ์ถ•ํ•˜๊ณ  ๋งˆ์ดํฌ ์ž…๋ ฅ์˜ ํ”ผ์น˜/์†๋„๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์กฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

  • ์Œ์„ฑ ๋ฉ”์‹œ์ง€: ๋…น์Œ ์ค‘ ์Œ์„ฑ ๋ชจ๋“œ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๋ณด๋‚ด์ง„ .webm ํŒŒ์ผ์—๋Š” ์ด๋ฏธ ์Œ์„ฑ ํšจ๊ณผ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด ์ˆ˜์‹ ์ž๊ฐ€ ์›๋ž˜ ์Œ์„ฑ์„ ๋ณต์›ํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ์ง„์ •ํ•œ ์ต๋ช… ๋ฉ”์‹œ์ง€๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
  • 1:1 / ๊ทธ๋ฃน ํ†ตํ™”: ํ†ตํ™” ์ค‘ ์Œ์„ฑ ๋ณ€์กฐ ๋ฒ„ํŠผ์„ ํƒญํ•˜์—ฌ ๋ชจ๋“œ๋ฅผ ์ˆœํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ฒ˜๋ฆฌ๋œ ์˜ค๋””์˜ค ํŠธ๋ž™์ด LiveKit LocalAudioTrack.replaceTrack()์„ ํ†ตํ•ด ์›๋ž˜ ํŠธ๋ž™์„ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค

์„œ๋ฒ„ ์ธก ์„ค์ •์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค. ์Œ์„ฑ ๋ณ€์กฐ๋Š” ์ „์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.


ํ™˜๊ฒฝ ๋ณ€์ˆ˜

๋ณ€์ˆ˜์„ค๋ช…๊ธฐ๋ณธ๊ฐ’
PORT์„œ๋ฒ„ ํฌํŠธ3000
JWT_SECRETJWT ์„œ๋ช… ํ‚ค (ํ”„๋กœ๋•์…˜์—์„œ ๋ฐ˜๋“œ์‹œ ๋ณ€๊ฒฝํ•˜์„ธ์š”)dev_secret
DB_HOST / DB_PASS / DB_NAMEMySQL ์—ฐ๊ฒฐ ์ •๋ณดโ€”
REDIS_HOST / REDIS_PASSRedis ์—ฐ๊ฒฐ ์ •๋ณดโ€”
R2_ACCOUNT_IDCloudflare ๊ณ„์ • IDโ€”
R2_ACCESS_KEY_IDR2 API ํ† ํฐ ์•ก์„ธ์Šค ํ‚คโ€”
R2_SECRET_ACCESS_KEYR2 API ํ† ํฐ ์‹œํฌ๋ฆฟ ํ‚คโ€”
R2_BUCKETR2 ๋ฒ„ํ‚ท ์ด๋ฆ„โ€”
R2_PUBLIC_URLR2 ๊ณต๊ฐœ ๊ธฐ๋ณธ URL (์„ ํƒ ์‚ฌํ•ญ)โ€”
LIVEKIT_URL๋ชจ๋“  ํ†ตํ™”์— ์‚ฌ์šฉํ•˜๋Š” ๊ณต๊ฐœ LiveKit WebSocket URLโ€”
LIVEKIT_API_KEY์„œ๋ฒ„์™€ LiveKit์ด ๊ณต์œ ํ•˜๋Š” API Keyโ€”
LIVEKIT_API_SECRET์„œ๋ฒ„์™€ LiveKit์ด ๊ณต์œ ํ•˜๋Š” API Secretโ€”
VAPID_PUBLIC_KEYWeb Push VAPID ๊ณต๊ฐœ ํ‚ค (์„ ํƒ ์‚ฌํ•ญ)โ€”
VAPID_PRIVATE_KEYWeb Push VAPID ๊ฐœ์ธ ํ‚ค (์„ ํƒ ์‚ฌํ•ญ)โ€”
VAPID_SUBJECTVAPID ์—ฐ๋ฝ์ฒ˜ ์ด๋ฉ”์ผ (์„ ํƒ ์‚ฌํ•ญ)mailto:admin@paperphoneplus.app
FCM_PROJECT_IDFirebase ํ”„๋กœ์ ํŠธ ID (์„ ํƒ ์‚ฌํ•ญ, Capacitor Android)โ€”
FCM_CLIENT_EMAILFirebase ์„œ๋น„์Šค ๊ณ„์ • ์ด๋ฉ”์ผ (์„ ํƒ ์‚ฌํ•ญ)โ€”
FCM_PRIVATE_KEYFirebase ์„œ๋น„์Šค ๊ณ„์ • ๊ฐœ์ธ ํ‚ค (์„ ํƒ ์‚ฌํ•ญ, \n ์ด์Šค์ผ€์ดํ”„ ๋ฐ ์‹ค์ œ ์ค„๋ฐ”๊ฟˆ ๋ชจ๋‘ ์ง€์›; ์•„๋ž˜ ์ฐธ์กฐ)โ€”
FCM_RELAY_SECRETFCM ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์‹œํฌ๋ฆฟ (์„ ํƒ ์‚ฌํ•ญ, ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ์— ์„ค์ •ํ•˜์—ฌ ์—”๋“œํฌ์ธํŠธ ํ™œ์„ฑํ™”)โ€”
FCM_RELAY_URLFCM ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด URL (์„ ํƒ ์‚ฌํ•ญ, ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„์—์„œ ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ๋กœ ์—ฐ๊ฒฐ)โ€”
FCM_RELAY_KEYFCM ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์ธ์ฆ ํ‚ค (์„ ํƒ ์‚ฌํ•ญ, ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ์˜ FCM_RELAY_SECRET๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค)โ€”
ONESIGNAL_APP_IDOneSignal App ID (์„ ํƒ ์‚ฌํ•ญ)โ€”
ONESIGNAL_REST_KEYOneSignal REST API Key (์„ ํƒ ์‚ฌํ•ญ)โ€”
ONESIGNAL_RELAY_SECRETOneSignal ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์‹œํฌ๋ฆฟ (์„ ํƒ ์‚ฌํ•ญ, ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ์— ์„ค์ •ํ•˜์—ฌ ์—”๋“œํฌ์ธํŠธ ํ™œ์„ฑํ™”)โ€”
ONESIGNAL_RELAY_URLOneSignal ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด URL (์„ ํƒ ์‚ฌํ•ญ, ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„์—์„œ ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ๋กœ ์—ฐ๊ฒฐ)โ€”
ONESIGNAL_RELAY_KEYOneSignal ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์ธ์ฆ ํ‚ค (์„ ํƒ ์‚ฌํ•ญ, ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ์˜ ONESIGNAL_RELAY_SECRET๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค)โ€”
NTFY_BASE_URLntfy ์„œ๋ฒ„ URL (์„ ํƒ ์‚ฌํ•ญ, ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ณต๊ฐœ ntfy.sh ์‚ฌ์šฉ)https://ntfy.sh
NTFY_TOKENntfy ์ธ์ฆ ํ† ํฐ (์„ ํƒ ์‚ฌํ•ญ, ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„์šฉ)โ€”
APNS_TEAM_IDApple Developer Team ID (์„ ํƒ ์‚ฌํ•ญ, iOS ๋„ค์ดํ‹ฐ๋ธŒ ํ‘ธ์‹œ)โ€”
APNS_KEY_IDAPNS ์ธ์ฆ ํ‚ค ID (์„ ํƒ ์‚ฌํ•ญ)โ€”
APNS_PRIVATE_KEYAPNS .p8 ๊ฐœ์ธ ํ‚ค ๋‚ด์šฉ (์„ ํƒ ์‚ฌํ•ญ, \n ์ด์Šค์ผ€์ดํ”„ ์ง€์›)โ€”
APNS_BUNDLE_IDiOS ์•ฑ Bundle Identifier (์„ ํƒ ์‚ฌํ•ญ)โ€”
APNS_SANDBOXAPNS ์ƒŒ๋“œ๋ฐ•์Šค ๋ชจ๋“œ (์„ ํƒ ์‚ฌํ•ญ, ๊ฐœ๋ฐœ/TestFlight์šฉ true)false
APNS_RELAY_SECRETํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์‹œํฌ๋ฆฟ (์„ ํƒ ์‚ฌํ•ญ, ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ์— ์„ค์ •ํ•˜์—ฌ ์—”๋“œํฌ์ธํŠธ ํ™œ์„ฑํ™”)โ€”
APNS_RELAY_URLํ‘ธ์‹œ ๋ฆด๋ ˆ์ด URL (์„ ํƒ ์‚ฌํ•ญ, ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„์—์„œ ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ๋กœ ์—ฐ๊ฒฐ)โ€”
APNS_RELAY_KEYํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์ธ์ฆ ํ‚ค (์„ ํƒ ์‚ฌํ•ญ, ๋ฆด๋ ˆ์ด ํ˜ธ์ŠคํŠธ์˜ APNS_RELAY_SECRET๊ณผ ์ผ์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค)โ€”
TELEGRAM_BOT_TOKENTelegram Bot Token (์„ ํƒ ์‚ฌํ•ญ)โ€”
STICKER_PACKS์ปค์Šคํ…€ ์Šคํ‹ฐ์ปค ํŒฉ (์„ ํƒ ์‚ฌํ•ญ, name:label)๊ธฐ๋ณธ 12๊ฐœ ๋‚ด์žฅ
ADMIN_PATH๊ด€๋ฆฌ์ž ํŒจ๋„ URL ๊ฒฝ๋กœ/admin
ADMIN_PASSWORD๊ด€๋ฆฌ์ž ํŒจ๋„ ๋น„๋ฐ€๋ฒˆํ˜ธ (ํ”„๋กœ๋•์…˜์—์„œ ๋ฐ˜๋“œ์‹œ ๋ณ€๊ฒฝํ•˜์„ธ์š”)admin123

FCM ๊ฐœ์ธ ํ‚ค ์ค„๋ฐ”๊ฟˆ ์ฒ˜๋ฆฌ

Firebase ์„œ๋น„์Šค ๊ณ„์ • JSON์˜ private_key ํ•„๋“œ์—๋Š” PEM ํ˜•์‹์˜ RSA ๊ฐœ์ธ ํ‚ค๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์œผ๋ฉฐ, ๊ฐ 64์ž ์ค„ ์‚ฌ์ด์— ์‹ค์ œ ์ค„๋ฐ”๊ฟˆ ๋ฌธ์ž (\n, ASCII 0x0A)๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋งŽ์€ ๋ฐฐํฌ ํ”Œ๋žซํผ (Zeabur, Vercel, Railway, Docker)์€ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๋‹จ์ผ ํ–‰ ๋ฌธ์ž์—ด๋กœ ์ €์žฅํ•˜์—ฌ \n์„ ๋ฆฌํ„ฐ๋Ÿด ๋‘ ๋ฌธ์ž ์‹œํ€€์Šค \ + n์œผ๋กœ ๋ณ€ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด FCM ํ‘ธ์‹œ ์•Œ๋ฆผ ์‹คํŒจ์˜ ๊ฐ€์žฅ ํ”ํ•œ ์›์ธ์ž…๋‹ˆ๋‹ค โ€” PEM ํŒŒ์„œ๊ฐ€ ์กฐ์šฉํžˆ ์‹คํŒจํ•˜๊ณ  ํ‘ธ์‹œ ์•Œ๋ฆผ์ด ์ „์†ก๋˜์ง€ ์•Š์œผ๋ฉฐ, ์˜ค๋ฅ˜ ๋กœ๊ทธ๋„ ๋‚จ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค: fcm.rs๊ฐ€ ๋ฆฌํ„ฐ๋Ÿด \n ์‹œํ€€์Šค๋ฅผ ํŒŒ์‹ฑ ์ „์— ์‹ค์ œ ์ค„๋ฐ”๊ฟˆ์œผ๋กœ ์ •๊ทœํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ํ˜•์‹ ๋ชจ๋‘ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค:

  • ๋‹จ์ผ ํ–‰ (ํด๋ผ์šฐ๋“œ ํ”Œ๋žซํผ ๊ถŒ์žฅ): JSON ํŒŒ์ผ์˜ private_key ๊ฐ’์„ \n ์ด์Šค์ผ€์ดํ”„์™€ ํ•จ๊ป˜ ๊ทธ๋Œ€๋กœ ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”:

    FCM_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----\nMIIEvQ...\n-----END PRIVATE KEY-----\n
    
  • ์—ฌ๋Ÿฌ ํ–‰ (.env ํŒŒ์ผ์šฉ): ์ „์ฒด PEM ๋‚ด์šฉ์„ ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ๊ณ  ์‹ค์ œ ์ค„๋ฐ”๊ฟˆ์„ ์‚ฌ์šฉํ•˜์„ธ์š”:

    FCM_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
    MIIEvQ...
    -----END PRIVATE KEY-----"
    
ํ”Œ๋žซํผ๊ถŒ์žฅ ํ˜•์‹๋น„๊ณ 
Zeabur๋‹จ์ผ ํ–‰ (\n ์ด์Šค์ผ€์ดํ”„)Variables ํŒจ๋„์— JSON ๊ฐ’์„ ์ง์ ‘ ๋ถ™์—ฌ๋„ฃ๊ธฐ
Docker / docker-compose๋‘˜ ๋‹ค ๊ฐ€๋Šฅ์—ฌ๋Ÿฌ ํ–‰์€ YAML | ์‚ฌ์šฉ; ๋‹จ์ผ ํ–‰์€ .env์—์„œ
Vercel / Railway๋‹จ์ผ ํ–‰ (\n ์ด์Šค์ผ€์ดํ”„)์ž…๋ ฅ ํ•„๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‹ค์ œ ์ค„๋ฐ”๊ฟˆ์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
Linux .env ํŒŒ์ผ์—ฌ๋Ÿฌ ํ–‰ (๋”ฐ์˜ดํ‘œ ์‚ฌ์šฉ)๋”ฐ์˜ดํ‘œ๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๋‹ซํ˜€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”

๋ฌธ์ œ ํ•ด๊ฒฐ: FCM ๋ณ€์ˆ˜๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์ง€๋งŒ Android ํ‘ธ์‹œ๊ฐ€ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ์„œ๋ฒ„ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜์„ธ์š”:

  • [FCM] No access token available โ†’ ๊ฐœ์ธ ํ‚ค ํ˜•์‹ ์˜ค๋ฅ˜ (์ค„๋ฐ”๊ฟˆ ๋ฌธ์ œ)
  • [FCM] โœ… Push sent to user xxx โ†’ FCM ์ „์†ก ์ •์ƒ, ํด๋ผ์ด์–ธํŠธ ์ธก ๋ฌธ์ œ
  • FCM ๋กœ๊ทธ๊ฐ€ ์ „ํ˜€ ์—†์Œ โ†’ FCM_PROJECT_ID๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ fcm_tokens ํ…Œ์ด๋ธ”์— ํ† ํฐ์ด ์—†์Œ

ntfy ํ‘ธ์‹œ (Google ์„œ๋น„์Šค ์—†๋Š” ์ค‘๊ตญ์‚ฐ Android ๊ธฐ๊ธฐ)

Google Mobile Services๊ฐ€ ์—†๋Š” Android ๊ธฐ๊ธฐ (Huawei, Xiaomi, OPPO, vivo ๋“ฑ)์˜ ๊ฒฝ์šฐ, PaperPhonePlus์€ ntfy๋ฅผ ํ†ตํ•œ ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์„ค์ • (์„ค์ • ๋ถˆํ•„์š”): ๊ณต๊ฐœ ntfy.sh ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€ ์„ค์ •์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

์„ ํƒ์  ์„ค์ • (์…€ํ”„ ํ˜ธ์ŠคํŒ… ntfy ์„œ๋ฒ„์šฉ):

NTFY_BASE_URL=https://your-ntfy-server.com
NTFY_TOKEN=your_optional_auth_token

์‚ฌ์šฉ์ž ์„ค์ • ํ๋ฆ„:

  1. ntfy ์•ฑ์„ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค (Google Play / F-Droid / ์ง์ ‘ ๋‹ค์šด๋กœ๋“œ)
  2. PaperPhonePlus ์„ค์ •์„ ์—ด๊ณ  "ntfy ํ‘ธ์‹œ" ์นด๋“œ๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค
  3. ํ‘œ์‹œ๋œ ํ† ํ”ฝ ์ด๋ฆ„์„ ๋ณต์‚ฌํ•˜๊ณ  ntfy ์•ฑ์—์„œ ๊ตฌ๋…ํ•ฉ๋‹ˆ๋‹ค
  4. "ํ‘ธ์‹œ ๋“ฑ๋ก"์„ ํƒญํ•˜์—ฌ ๋“ฑ๋ก์„ ์™„๋ฃŒํ•ฉ๋‹ˆ๋‹ค

๋ณด์•ˆ ์ฐธ๊ณ : ntfy ์•Œ๋ฆผ์—๋Š” ์•Œ๋ฆผ ์ œ๋ชฉ๊ณผ ์š”์•ฝ์ด ํ‰๋ฌธ์œผ๋กœ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค (์‹ค์ œ ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ์ด ์•„๋‹˜). ๋” ๋†’์€ ๋ณด์•ˆ์„ ์œ„ํ•ด ntfy ์„œ๋ฒ„๋ฅผ ์…€ํ”„ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜์„ธ์š”.

APNS ํ‘ธ์‹œ (iOS ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ)

APNS (Apple Push Notification Service)๋Š” Capacitor๋กœ ๋นŒ๋“œ๋œ iOS ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ์— ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๊ฐ€์ง€ ์„ค์ • ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค:

์˜ต์…˜ A: ์ง์ ‘ ์„ค์ • (์•ฑ ๊ฐœ๋ฐœ์ž ์„œ๋ฒ„)

  1. Apple Developer์— ๋กœ๊ทธ์ธ โ†’ Certificates, Identifiers & Profiles โ†’ Keys
  2. + ํด๋ฆญํ•˜์—ฌ ์ƒˆ Key ์ƒ์„ฑ โ†’ Apple Push Notifications service (APNs) ์ฒดํฌ โ†’ ๋“ฑ๋ก
  3. .p8 ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ (โš ๏ธ ํ•œ ๋ฒˆ๋งŒ ๋‹ค์šด๋กœ๋“œ ๊ฐ€๋Šฅ!) ๋ฐ Key ID ๊ธฐ๋ก
  4. Apple Developer Membership ํŽ˜์ด์ง€์—์„œ Team ID ๊ธฐ๋ก (10์ž ์˜์ˆซ์ž)
  5. server/.env์— ์ถ”๊ฐ€:
APNS_TEAM_ID=AB12CD34EF
APNS_KEY_ID=LH4Z9YN3P7
APNS_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIGTAgEA...(.p8 ํŒŒ์ผ ๋‚ด์šฉ)...\n-----END PRIVATE KEY-----"
APNS_BUNDLE_ID=com.yourcompany.paperphoneplus
APNS_SANDBOX=false

APNS_SANDBOX: ๊ฐœ๋ฐœ/TestFlight ๋นŒ๋“œ์˜ ๊ฒฝ์šฐ true, App Store ํ”„๋กœ๋•์…˜์˜ ๊ฒฝ์šฐ false๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

์˜ต์…˜ B: ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ๊ฒฝ์œ  (์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„)

๋‹ค๋ฅธ ์‚ฌ๋žŒ์˜ iOS ์•ฑ (์˜ˆ: App Store์—์„œ ๋‹ค์šด๋กœ๋“œ)์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐœ๋ฐœ์ž์˜ Apple ์ž๊ฒฉ ์ฆ๋ช…์ด ์—†์œผ๋ฏ€๋กœ APNS ํ‘ธ์‹œ๋ฅผ ์ง์ ‘ ์ „์†กํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

์ž‘๋™ ๋ฐฉ์‹:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„     โ”‚  HTTP  โ”‚  ์•ฑ ๊ฐœ๋ฐœ์ž ์„œ๋ฒ„           โ”‚  APNS  โ”‚  Apple  โ”‚
โ”‚  (Apple ์ž๊ฒฉ ์ฆ๋ช… ์—†์Œ)โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚  (.p8 Key + ๋ฆด๋ ˆ์ด ๋ณด์œ )  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ†’โ”‚  โ”€โ”€โ†’ ๐Ÿ“ฑ โ”‚
โ”‚                       โ”‚       โ”‚                          โ”‚       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚  APNS_RELAY_URL=...   โ”‚       โ”‚  APNS_TEAM_ID=...        โ”‚
โ”‚  APNS_RELAY_KEY=...   โ”‚       โ”‚  APNS_RELAY_SECRET=...   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

1๋‹จ๊ณ„: ์•ฑ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฆด๋ ˆ์ด ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค

์•ฑ ๊ฐœ๋ฐœ์ž์˜ ์„œ๋ฒ„ (์ด๋ฏธ APNS ์ž๊ฒฉ ์ฆ๋ช…์ด ์žˆ๋Š”)์—์„œ ๋ฆด๋ ˆ์ด ์‹œํฌ๋ฆฟ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค:

# ์•ฑ ๊ฐœ๋ฐœ์ž ์„œ๋ฒ„ .env (์ด๋ฏธ APNS_TEAM_ID ๋“ฑ์ด ์„ค์ •๋˜์–ด ์žˆ์Œ)
APNS_RELAY_SECRET=a_long_random_shared_secret

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด POST /api/push-relay/apns ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์—”๋“œํฌ์ธํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ํ™œ์„ฑํ™”๋ฉ๋‹ˆ๋‹ค.

2๋‹จ๊ณ„: ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์‚ฌ์šฉ์ž๊ฐ€ ๋ฆด๋ ˆ์ด๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค

์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„๋Š” ๋‘ ๊ฐœ์˜ ๋ณ€์ˆ˜๋งŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค โ€” Apple ์ž๊ฒฉ ์ฆ๋ช…์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค:

# ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„ .env
APNS_RELAY_URL=https://app-developer-server.com
APNS_RELAY_KEY=the_shared_secret_from_step_1

์ž‘๋™ ๋ฐฉ์‹:

  1. ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„๊ฐ€ ์˜คํ”„๋ผ์ธ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹  โ†’ ๋กœ์ปฌ apns_tokens ํ…Œ์ด๋ธ”์—์„œ ์‚ฌ์šฉ์ž์˜ iOS ๊ธฐ๊ธฐ ํ† ํฐ์„ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค
  2. ๊ธฐ๊ธฐ ํ† ํฐ + ํ‘ธ์‹œ ์ œ๋ชฉ/๋ณธ๋ฌธ์„ HTTP POST๋กœ ๋ฆด๋ ˆ์ด์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค
  3. ๋ฆด๋ ˆ์ด๊ฐ€ ํ‚ค๋ฅผ ๊ฒ€์ฆํ•œ ํ›„ ์ž์ฒด APNS ์ž๊ฒฉ ์ฆ๋ช…์„ ์‚ฌ์šฉํ•˜์—ฌ Apple์— ์ „์†กํ•ฉ๋‹ˆ๋‹ค
  4. ๋ฆด๋ ˆ์ด๊ฐ€ ๋งŒ๋ฃŒ๋œ ํ† ํฐ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค; ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„๊ฐ€ ์ž๋™์œผ๋กœ ๋กœ์ปฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค

์šฐ์„ ์ˆœ์œ„: ๋กœ์ปฌ APNS ์ž๊ฒฉ ์ฆ๋ช… โ†’ ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด โ†’ ๊ฑด๋„ˆ๋›ฐ๊ธฐ (๋ฌด์Œ). ๋‘˜ ๋‹ค ์„ค์ •๋œ ๊ฒฝ์šฐ ๋กœ์ปฌ ์ง์ ‘ ์—ฐ๊ฒฐ์ด ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ณด์•ˆ ์ฐธ๊ณ : ๋ฆด๋ ˆ์ด๋Š” ํ‘ธ์‹œ ์•Œ๋ฆผ ์ œ๋ชฉ๊ณผ ์š”์•ฝ๋งŒ ์ „์†กํ•ฉ๋‹ˆ๋‹ค (์˜ˆ: "๋ˆ„๊ตฐ๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค"), ์‹ค์ œ ๋ฉ”์‹œ์ง€ ๋‚ด์šฉ์€ ์ „์†กํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ธฐ๊ธฐ ํ† ํฐ์œผ๋กœ๋Š” ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด (์ „์ฒด ์ฑ„๋„)

๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๊ฒŒ์‹œํ•œ ์•ฑ (์˜ˆ: App Store/Google Play์—์„œ)์„ ์‚ฌ์šฉํ•˜๋Š” ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„ ์šด์˜์ž์˜ ๊ฒฝ์šฐ, ๊ฐœ๋ฐœ์ž์˜ ํ‘ธ์‹œ ์ž๊ฒฉ ์ฆ๋ช… (Apple .p8 Key / Firebase ์„œ๋น„์Šค ๊ณ„์ • / OneSignal API Key)์ด ์—†์Šต๋‹ˆ๋‹ค.

ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด ์‹œ์Šคํ…œ์€ APNS, FCM, OneSignal ์ฑ„๋„์— ๋Œ€ํ•œ ๋ฆด๋ ˆ์ด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค:

์•ฑ ๊ฐœ๋ฐœ์ž๊ฐ€ ์„œ๋ฒ„์—์„œ ๋ฆด๋ ˆ์ด ์—”๋“œํฌ์ธํŠธ๋ฅผ ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค:

# ์•ฑ ๊ฐœ๋ฐœ์ž ์„œ๋ฒ„ .env
APNS_RELAY_SECRET=a_long_random_string
FCM_RELAY_SECRET=a_long_random_string
ONESIGNAL_RELAY_SECRET=a_long_random_string

์…€ํ”„ ํ˜ธ์ŠคํŒ… ์‚ฌ์šฉ์ž๋Š” ๋ฆด๋ ˆ์ด URL๊ณผ ํ‚ค๋งŒ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค โ€” ํ‘ธ์‹œ ์„œ๋น„์Šค ์ž๊ฒฉ ์ฆ๋ช…์ด ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค:

# ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„ .env
# APNS (iOS ๋„ค์ดํ‹ฐ๋ธŒ ํ‘ธ์‹œ)
APNS_RELAY_URL=https://app-developer-server.com
APNS_RELAY_KEY=shared_secret

# FCM (Android ๋„ค์ดํ‹ฐ๋ธŒ ํ‘ธ์‹œ)
FCM_RELAY_URL=https://app-developer-server.com
FCM_RELAY_KEY=shared_secret

# OneSignal (Median.co ๋ž˜ํ•‘ ์•ฑ)
ONESIGNAL_RELAY_URL=https://app-developer-server.com
ONESIGNAL_RELAY_KEY=shared_secret

์šฐ์„ ์ˆœ์œ„: ๋กœ์ปฌ ์ž๊ฒฉ ์ฆ๋ช… โ†’ ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด โ†’ ๊ฑด๋„ˆ๋›ฐ๊ธฐ (๋ฌด์Œ). ๋‘˜ ๋‹ค ์„ค์ •๋œ ๊ฒฝ์šฐ ๋กœ์ปฌ ์ง์ ‘ ์—ฐ๊ฒฐ์ด ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค.


๊ณต์‹ ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด

์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„ ์šด์˜์ž๋Š” ๊ณต์‹ ํ‘ธ์‹œ ๋ฆด๋ ˆ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ‘ธ์‹œ ์ž๊ฒฉ ์ฆ๋ช…์„ ์„ค์ •ํ•˜์ง€ ์•Š๊ณ ๋„ iOS/Android ํ‘ธ์‹œ ์•Œ๋ฆผ์„ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

# 2026-05-18
APNS_RELAY_URL=https://619.chat
APNS_RELAY_KEY=EzmpqftbsENaRUO6BTABxLV96q7RuEDyokXJr1DWdDjL54cLg7yXVUQqydCQvxrX
FCM_RELAY_URL=https://619.chat
FCM_RELAY_KEY=EzmpqftbsENaRUO6BTABxLV96q7RuEDyokXJr1DWdDjL54cLg7yXVUQqydCQvxrX
ONESIGNAL_RELAY_URL=https://619.chat
ONESIGNAL_RELAY_KEY=EzmpqftbsENaRUO6BTABxLV96q7RuEDyokXJr1DWdDjL54cLg7yXVUQqydCQvxrX

์œ„ ์ค„์„ ์…€ํ”„ ํ˜ธ์ŠคํŒ… ์„œ๋ฒ„์˜ .env ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜์„ธ์š”.


๋ผ์ด์„ ์Šค

์ด ํ”„๋กœ์ ํŠธ๋Š” GNU Affero General Public License v3.0 (AGPL-3.0) ํ•˜์— ๋ผ์ด์„ ์Šค๊ฐ€ ๋ถ€์—ฌ๋ฉ๋‹ˆ๋‹ค.