๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ™‹๐Ÿป‍โ™‚๏ธ HB/๐Ÿ’ป Projects

๋™์•„๋ฆฌ ํšŒ์› ๊ด€๋ฆฌ ํŽ˜์ด์ง€ (์–ด๋“œ๋ฏผ ํŽ˜์ด์ง€ / Admin Page)

by ํ™ฉ๋ณด์žฌ์œค 2024. 8. 14.

์•ˆ๋…•ํ•˜์„ธ์š” ๐Ÿ˜Š

์ด๋ฒˆ ์—ฌ๋ฆ„๋ฐฉํ•™ ์‹œ์ž‘๊ณผ ๋™์‹œ์— ์‹ค์‹œํ•˜๊ฒŒ ๋œ ์ž‘์€ ํ”„๋กœ์ ํŠธ ํ•˜๋‚˜๋ฅผ ์†Œ๊ฐœ๋“œ๋ฆฌ๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.

FE / BE ๊ฐœ๋ฐœ์ด ์ฒ˜์Œ์ด๋ผ ๋งŽ์ด ์„œํˆด์ง€๋งŒ '์žฌ๋ฏธ์žˆ๋Š”๊ฑฐ ๋งŒ๋“ค์—ˆ๊ตฌ๋งŒ' ๊ฐ™์€ ๊ด€์ ์œผ๋กœ ๋ด์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค!

 

ํ”„๋กœ์ ํŠธ ์‹œ์ž‘ ๊ณ„๊ธฐ

 

2024๋…„ 1ํ•™๊ธฐ ๋ชจ ์ค‘์•™๋™์•„๋ฆฌ์—์„œ ์ž„์›์ง์„ ๋งก๊ณ  ์žˆ๋˜ ์ €๋Š” ํ•™๊ธฐ ๋ง์— ํฐ ์œ„๊ธฐ๋ฅผ ๋งž์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ ๋™์•„๋ฆฌ ๋‚ด ๋ถ€์„œ์—์„œ ํ•ด์•ผ ํ•  ์ผ์„ ์ œ๋•Œ ํ•˜์ง€ ๋ชปํ•ด ํšŒ์›๋“ค์˜ ํ™œ๋™ ์ธ์ • ์‹ ์ฒญ์„œ๊ฐ€ ์ œ์ถœ๋˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ  ํ‰์†Œ ํ™œ๋™ ์ธ์ • ์‹ ์ฒญ์„œ ์ œ์ถœํ•  ๋•Œ ํ•„์š”ํ•œ ์„œ๋ฅ˜๊ฐ€ ์ˆ˜์ž‘์—…์ด๊ณ  ์‚ฌ๋žŒ์ด ํ•˜๋Š” ์ผ์ด๋‹ค ๋ณด๋‹ˆ ์˜ค๋ฅ˜๊ฐ€ ๋งŽ๋‹ค๊ณ  ์ƒ๊ฐํ•ด "์ด ๋ชจ๋“  ๊ฒƒ์„ ์ž๋™ํ™”ํ•˜๊ณ  ํด๋ฆญ ๋ช‡ ๋ฒˆ์œผ๋กœ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด๋ณด์ž!"๋ผ๋Š” ์ทจ์ง€๋กœ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

ํ”„๋กœ์ ํŠธ ์„ค๊ณ„

 

์ฒ˜์Œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•  ๋•Œ ๊ฐ€์žฅ ๋ง‰๋ง‰ํ–ˆ๋˜ ๊ฒƒ์€ ๋ฐ”๋กœ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ์„ ํƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ €๋Š” ํ•  ์ค„ ์•„๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๊ฐ€ ํŒŒ์ด์ฌ ๋ฐ–์— ์—†์—ˆ๊ณ , ์›น๊ณผ ์„œ๋ฒ„๋ฅผ ์„ค๊ณ„ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฌด์กฐ๊ฑด JS๋ฅผ ํ•  ์ค„ ์•Œ์•„์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŒŒ์ด์ฌ์˜ ํ”„๋ ˆ์ž„์›Œํฌ ์ค‘ Flask๋ผ๋Š” ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›น์‚ฌ์ด๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๊ณ , ํ”Œ๋ผ์Šคํฌ์™€ ํ•™๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐฐ์šด MySQL์„ ์‚ฌ์šฉํ•˜์—ฌ FE / BE ๊ฐ€ ํ†ตํ•ฉ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ธฐ๋กœ ๊ณ„ํšํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ์•„ํ‚คํ…์ฒ˜

Member Page๋Š” ํ˜„์žฌ ์ง„ํ–‰ํ˜•์ด๋ฏ€๋กœ ์ถ” ํ›„์— ํฌ์ŠคํŒ…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

ํ•„์ˆ˜ ๊ธฐ๋Šฅ ๊ณ„ํš ๋ฐ ๋ฐฐํฌ

 

ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ•˜๋ฉด์„œ ์ƒ๊ฐํ•œ ๊ธฐ๋Šฅ์€ ํฌ๊ฒŒ ๋‘ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ, ํšŒ์› ๊ด€๋ฆฌ๊ธฐ๋Šฅ๊ณผ ํ™œ๋™ ๊ด€๋ฆฌ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ์ด ๋‘ ๊ธฐ๋Šฅ๋“ค์„ ์„ธ๋ถ€์ ์œผ๋กœ ๋‚˜๋ˆ„๊ฒŒ ๋œ๋‹ค๋ฉด 

 

ํšŒ์› ๊ด€๋ฆฌ ๊ธฐ๋Šฅ

  • ํšŒ์› ๋“ฑ๋ก: ์ƒˆ๋กœ์šด ํšŒ์› ์ •๋ณด๋ฅผ DB์— ์ถ”๊ฐ€
  • ํšŒ์› ์กฐํšŒ: ๋“ฑ๋ก๋œ ๋ชจ๋“  ํšŒ์› ๋˜๋Š” ํŠน์ • ํšŒ์›์˜ ์ •๋ณด ์กฐํšŒ
  • ํšŒ์› ์ •๋ณด ์ˆ˜์ •: ํšŒ์›์˜ ์ •๋ณด๋ฅผ ์ˆ˜์ •
  • ํšŒ์› ์‚ญ์ œ: ๋” ์ด์ƒ ํ™œ๋™ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ž…ํšŒ๋น„๋ฅผ ๋‚ด์ง€ ์•Š์€ ํšŒ์› ์‚ญ์ œ
  • ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๊ด€๋ฆฌ: ํ™œ๋™ ์‹ ์ฒญ ํ›„ ๋ถˆ์ฐธํ•˜๋Š” ํšŒ์›์„ ์กฐํšŒํ•˜์—ฌ ๋‹ค์Œ ํ™œ๋™ ์ฐธ์—ฌ๋ฅผ ์ œํ•œ

ํ™œ๋™ ๊ด€๋ฆฌ ๊ธฐ๋Šฅ

  • ํ™œ๋™ ์ถ”๊ฐ€: ์ƒˆ๋กœ์šด ํ™œ๋™์„ ๋“ฑ๋กํ•˜๊ณ , ํ™œ๋™๋ช…, ๋‚ ์งœ, ์ฐธ์—ฌ ์ธ์› ๋“ฑ์˜ ์ •๋ณด ๋“ฑ๋ก
  • ํ™œ๋™ ์กฐํšŒ: ๋“ฑ๋ก๋œ ๋ชจ๋“  ํ™œ๋™ ๋˜๋Š” ํŠน์ • ํ™œ๋™์˜ ์ •๋ณด ์กฐํšŒ
  • ํ™œ๋™ ์ˆ˜์ •: ํ™œ๋™ ์ •๋ณด ์ˆ˜์ •
  • ํ™œ๋™ ์ฐธ์—ฌ ํ˜„ํ™ฉ ์กฐํšŒ: ๊ฐ ํ™œ๋™์— ์ฐธ์—ฌํ•œ ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ
  • ํ™œ๋™ ์ฐธ์—ฌ ์—ฌ๋ถ€ ์ˆ˜์ •: ํšŒ์›์˜ ํ™œ๋™ ์ฐธ์—ฌ ์—ฌ๋ถ€ ์ˆ˜์ • (์ถœ์„๋ถ€ ๊ฐœ๋…)
  • ํ™œ๋™ ์ฐธ์—ฌ์ž ํŒ€ ๋ถ„๋ฐฐ: ํ™œ๋™ ์ฐธ์—ฌ์ž๋ฅผ ํŒ€์œผ๋กœ ๋‚˜๋ˆ•๋‹ˆ๋‹ค. (์„ฑ๋ณ„ ๊ณ ๋ ค ๊ฐ€๋Šฅ)

๊ทธ๋ฆฌ๊ณ  ์ด ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋‹นํ•˜๊ฒŒ ๋  MySQL์— PyMySQL ๋ชจ๋“ˆ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ๊ฐ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ๋” ๊ณ„ํšํ–ˆ์Šต๋‹ˆ๋‹ค.

 

๋””์ž์ธ

๋””์ž์ธ์€ Figma ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋””์ž์ธํ•˜์˜€๊ณ , Plugins ์ค‘์— ์™„์„ฑ๋œ ๋””์ž์ธ์„ HTML๊ณผ CSS๋กœ ๋‚ด๋ณด๋‚ด ์ฃผ๋Š” ๊ฒƒ์ด ์žˆ์–ด ์ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ HTML์„ ์ƒ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ์ „์ฒด์ ์ธ ๋””์ž์ธ์˜ ํ”„๋ ˆ์ž„์„ ์ถ”์ถœํ•ด ์ค„ ๋ฟ, input ํƒœ๊ทธ์™€ button ํƒœ๊ทธ๋“ค์€ ์ถ”์ถœํ•ด์ฃผ์ง€ ๋ชปํ•˜๊ณ  ๋ชจ๋“  ๋””์ž์ธ๋œ ํ•ญ๋ชฉ๋“ค์„ div ํƒœ๊ทธ๋กœ ์ถ”์ถœํ•ด ์ค„ ๋ฟ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ์ด๋ฅผ ์•Œ๋งž์€ ํƒœ๊ทธ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ CSS์— ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ๋„ ํ•˜๊ณ  ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•˜์ง€๋งŒ์€ ์•Š์€ ์ž‘์—…์ด์—ˆ์Šต๋‹ˆ๋‹ค.

 

์™„์„ฑ๋œ ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ ๋ชจ์Šต

 

์ดˆ๊ธฐ์— ๊ณ„ํšํ–ˆ๋˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ์—๋Š” ํฌ๊ฒŒ ๋ฌธ์ œ์—†์ด ์›ํ™œํ•˜๊ฒŒ ์ˆ˜ํ–‰ํ–ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ œ๊ฐ€ ๊ฐ„๊ณผํ–ˆ๋˜ ๊ฒƒ์ด ์žˆ์—ˆ์œผ๋‹ˆ ๋ฐ”๋กœ ์›น์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ฐฐํฌ์˜€์Šต๋‹ˆ๋‹ค. ๋ฌด๋ฃŒ ํ˜ธ์ŠคํŒ… ์„œ๋น„์Šค๋ฅผ ํ•ด์ฃผ๋Š” ๊ณณ์€ ๋งŽ์ง€๋งŒ Flask๋ฅผ ํ˜ธ์ŠคํŒ… ํ•ด์ฃผ๋Š” ๊ณณ์€ ๋งŽ์ง€ ์•Š์•˜๊ณ , Flask ๋ฐฐํฌ๋กœ ์œ ๋ช…ํ•œ Heroku๋Š” ์ „๊ฒฉ ์œ ๋ฃŒํ™” ์„ ์–ธ, Ngrok์€ ์‰ฝ๊ฒŒ ํ„ฐ๋„๋ง์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋„๋ฉ”์ธ ์—ฐ๊ฒฐ ์‹œ ์œ ๋ฃŒ, ์ด๋ฏธ ์‚ฌ์šฉํ•ด ๋ฒ„๋ฆฐ AWS 1๋…„ ๋ฌด๋ฃŒ ์„œ๋น„์Šค.. ๊ฒฐ๊ตญ Vercel๋กœ ํ˜ธ์ŠคํŒ… ํ•˜๊ธฐ๋กœ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด ๋˜ํ•œ ์–ด๋ ค์› ๋Š”๋ฐ์š”, Vercel์—์„œ๋Š” Flask๋ฅผ ๊ณต์‹ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ตฌ๊ธ€๋ง์œผ๋กœ ์ฐพ์•„๋‚ธ ๊ฒฐ๊ณผ root dir์— Vercel.json ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์ฃผ๋ฉด Vercel ๋ฐฐํฌ ์‹œ ์ด๋ฅผ ์ธ์‹ํ•˜์—ฌ app.py๋ฅผ ์‹คํ–‰์‹œ์ผœ ์ค€๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

 

## Vercel.json

{
    "version": 2,
    "builds": [
      {
        "src": "app.py",
        "use": "@vercel/python"
      }
    ],
    "routes": [
      {
        "src": "/(.*)",
        "dest": "/app.py"
      }
    ]
  }

 

## Hearder ์€ ์ด์ œ ๋ชป ๋„ฃ๋”๋ผ๊ณ ์š”.. ##

 

์ด์™€ ๊ด€๋ จํ•ด์„œ ๊ณต์‹ ๋ฌธ์„œ๋„ ์‚ดํŽด๋ณด์•˜์ง€๋งŒ ์–„ํŒํ•œ ์ €์˜ ์ง€์‹์œผ๋กœ๋Š” ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์› ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์œ„์™€ ๊ฐ™์ด ์„ค์ •ํ•ด ๋‘๊ณ  ๋ฐฐํฌ๊ฐ€ ๋˜๊ธธ๋ž˜ ๊ทธ ์ดํ›„๋กœ๋Š” ๊ฑด๋“ค์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. 

 

Vercel์—์„œ ์›น์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐฐํฌ ํ›„ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋˜ ๋™์•„๋ฆฌ ๋ถ€์„œ์˜ ๋ถ€์›์—๊ฒŒ ๋ถ€ํƒํ•˜์—ฌ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๊ณ , ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํšŒ์›์˜ ์„ฑ๋ณ„์„ 0๊ณผ 1๋กœ ํ•ด์„œ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅ๋˜๋˜ ๊ฒƒ์„ '๋‚จ', '์—ฌ'๋กœ ๋ฐ”์ธ๋”ฉํ•˜์—ฌ ์ถœ๋ ฅํ•ด ๋‹ฌ๋ผ๋Š” ๊ฒƒ์„ ๋ถ€ํƒ๋ฐ›์•˜๊ณ , ๊ฐ„๋‹จํžˆ ํ”ผ๋“œ๋ฐฑ์„ ์ˆ˜ํ–‰ ํ•˜์˜€์Šต๋‹ˆ๋‹ค. 

 

์ดํ›„ ์›น์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ๊ฒฝํ—˜์ด ๋งŽ์€ ์นœ๊ตฌ์—๊ฒŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์•„ํ‚คํ…์ฒ˜์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ธฐ ์œ„ํ•ด ๋น„๊ณต๊ฐœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ดˆ๋Œ€ํ•ด ์คฌ์Šต๋‹ˆ๋‹ค. ๋Œ์•„์˜ค๋Š” ๋ง์€ "์šฐ์™€ ์–ด๋–ป๊ฒŒ ์ด๋Ÿฐ ์ƒ๊ฐ์„...!". ๋ฌผ๋ก  ์ข‹์€ ๋œป์ด ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค. 

 

๋ฌธ์ œ์ 

  • FE / BE ํ†ตํ•ฉ์œผ๋กœ ์ธํ•œ ์•ˆ์ •์„ฑ ๋ฌธ์ œ
  • ๊ธฐ๋Šฅ ์ˆ˜ํ–‰๋งˆ๋‹ค ์ƒ์„ฑ๋˜๋Š” DB ์ปค์„œ๋กœ ์ธํ•œ ์„ฑ๋Šฅ์ €ํ•˜

์ด ๋ฌธ์ œ์ ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ณ ์ž ์ €๋Š” Flask๋กœ REST API๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ–ˆ๊ณ , flask_restful ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ api๋ฅผ ๋ฐฐํฌํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ƒ๊ฐ๋ณด๋‹ค flask_restful์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€ ์•Š์•˜๊ณ , ์›๋ž˜ ์žˆ๋˜ ์ฝ”๋“œ๋“ค์„ ๊ฐ€์ ธ์™€์„œ api๋กœ ๋ถ„๋ฆฌ๋งŒ ํ•˜๋ฉด ๋˜๋Š” ์ž‘์—…์ด๋‹ค ๋ณด๋‹ˆ ๊ตฌ์ถ• ์‹œ๊ฐ„์€ ๋งŽ์ด ๊ฑธ๋ฆฌ์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ DB์˜ ์ปค์„œ๋ฌธ์ œ๋„ ์ปค์„œ๋ฅผ ์žฌํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐ”๊พธ์–ด ์„ฑ๋Šฅ์ €ํ•˜๋ฅผ ํ”ผํ•ด ๊ฐ”์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ FE์™€ BE๊ฐ€ ๋‚˜๋‰˜๊ฒŒ ๋˜์ž ์—„์ฒญ๋‚œ ์†๋„์ฐจ์ด๊ฐ€ ๋‚ฌ๊ณ , ์ œ ๋งˆ์Œ์„ ์„ค๋ ˆ๊ฒŒ ํ•˜๊ธฐ์—” ์ถฉ๋ถ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

 

 

๊ทธ๋ ‡๊ฒŒ ํ•„์ˆ˜๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์„ ๋งˆ์น˜๊ณ  FE์™€ BE๊นŒ์ง€ ๋ถ„๋ฆฌํ•˜๊ณ  ๋‚˜์„œ ์ด ๊ด€๋ฆฌ์žํŽ˜์ด์ง€๋ฅผ ์‚ฌ์šฉํ•  ์ž„์›๋“ค์„ ์œ„ํ•ด 'ํ™œ๋™ ์ฐธ์—ฌ์ž ํŒ€ ๋ถ„๋ฐฐ'์™€ ๊ฐ™์€ ํŽธ์˜๊ธฐ๋Šฅ ๊ฐœ๋ฐœ์„ ํ•˜๊ธฐ๋กœ ๋งˆ์Œ๋จน์—ˆ์Šต๋‹ˆ๋‹ค.

 

ํŽธ์˜๊ธฐ๋Šฅ ๊ฐœ๋ฐœ

 

์ถ”๊ฐ€ํ•œ ํŽธ์˜๊ธฐ๋Šฅ

  • ํšŒ์›๋ณ„ ํ™œ๋™ ๋‚ด์—ญ ๋ณด๊ณ ์„œ: ํŠน์ • ํšŒ์›์˜ ๋ชจ๋“  ํ™œ๋™ ๋‚ด์—ญ์„ Excel ํŒŒ์ผ๋กœ ๋‹ค์šด๋กœ๋“œ
  • QR ์ฝ”๋“œ ์ƒ์„ฑ: ๊ฐ ํ™œ๋™์— ๋Œ€ํ•œ QR ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฐธ์—ฌ ํ™•์ธ
  • ์˜ˆ์•ฝ ์‹œ์Šคํ…œ: ํšŒ์›๋“ค์ด ํ™œ๋™์— ๋ฏธ๋ฆฌ ์ฐธ์—ฌ๋ฅผ ์˜ˆ์•ฝํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ ์ œ๊ณต
  • ์นด์นด์˜คํ†ก ์•Œ๋ฆผ ๊ธฐ๋Šฅ(์ตœ์ข… ๊ด€๋ฆฌ์ž์šฉ): ์ƒˆ๋กœ์šด ํ™œ๋™ ์ถ”๊ฐ€, ์ฐธ์—ฌ ๋งˆ๊ฐ ๋“ฑ ์ค‘์š”ํ•œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์นด์นด์˜คํ†ก ์•Œ๋ฆผ์„ ์ œ๊ณต

ํšŒ์›๋ณ„ ํ™œ๋™ ๋‚ด์—ญ ๋ณด๊ณ ์„œ๋Š” ํšŒ์›๋“ค์˜ ํ™œ๋™ ์‹œ๊ฐ„ ์ธ์ • ์„œ๋ฅ˜๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ๊ผญ ํ•„์š”ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์›๋ž˜๋Š” ํ™œ๋™์ž ๋ช…๋‹จ์„ ์ข…์ด๋กœ ๋ฝ‘์•„์„œ ๋ณธ์ธ์˜ ์ด๋ฆ„์— ์„œ๋ช…์„ ํ•˜๋Š” ์‹์œผ๋กœ ์ฐธ์—ฌ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ณ , ์ฐธ์—ฌ์ž๋“ค์˜ ์„ฑ๋ช…๊ณผ ๊ฐœ์ธ์ •๋ณด๋ฅผ ํ•˜๋‚˜์”ฉ ์—‘์…€ํŒŒ์ผ๋กœ ์ž‘์„ฑํ•˜์˜€์ง€๋งŒ DB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ง€๊ธˆ์€ ์ฐธ์—ฌ์ž๋“ค๋งŒ ์ž๋™์œผ๋กœ ์ถ”๋ ค ์ œ์ถœ ํ˜•์‹์— ๋งž๊ฒŒ Excel ํŒŒ์ผ์„ ์ž‘์„ฑํ•˜๋„๋ก ํ•˜์˜€๊ณ , ์ด๋Š” Openpyxl ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

@app.route('/download-excel/<date>/<id>')
def download_excel(date, id):
    response_data = session.get('response_data')

    if response_data:
        file_path = './form.xlsx'

        # ๊ธฐ์กด ํŒŒ์ผ ์—ด๊ธฐ
        workbook = openpyxl.load_workbook(file_path)

        # ํŠน์ • ํ–‰(์˜ˆ: 5๋ฒˆ์งธ ํ–‰)๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€
        start_row = 4
        add_data_to_excel(workbook, start_row, response_data)

        # ์—‘์…€ ํŒŒ์ผ์„ ๋ฉ”๋ชจ๋ฆฌ ๋‚ด์˜ ๋ฐ”์ด๋„ˆ๋ฆฌ ์ŠคํŠธ๋ฆผ์— ์ €์žฅ
        output = io.BytesIO()
        workbook.save(output)
        output.seek(0)

        session.pop('response_data', None)

        # ํŒŒ์ผ์„ ์‘๋‹ต์œผ๋กœ ๋ฐ˜ํ™˜
        return send_file(
            output,
            as_attachment=True,
            download_name=f"{date}_ํ™œ๋™๋ช…๋‹จ.xlsx",
            mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        )
    
    return render_template('404.html')

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

๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์—์„œ ํ™œ๋™์„ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜, ํšŒ์›์ด ํšŒ์›๊ฐ€์ž…์„ ํ•˜๊ฑฐ๋‚˜, ํ™œ๋™ ์˜ˆ์•ฝ์„ ์˜คํ”ˆํ•  ๋•Œ ๋“ฑ ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์—์„œ ์ผ์–ด๋‚˜๋Š” ๋ชจ๋“  ํ–‰์œ„๋Š” ๊ทธ ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ์ตœ์ข… ๊ด€๋ฆฌ์ž(๋™์•„๋ฆฌ์žฅ)์˜ ์นด์นด์˜คํ†ก์œผ๋กœ ์ „์†ก๋˜๋„๋ก ๊ตฌ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์ฒ˜์Œ์—๋Š” ์นด์นด์˜คํ†ก ์ฑ„๋„์„ ์ƒ์„ฑํ•˜์—ฌ ๋ชจ๋“  ์ž„์›๋“ค์ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›๊ฒŒ ํ•˜๋„๋ก ๊ตฌ์„ฑํ•˜๋ ค ํ–ˆ์ง€๋งŒ, ์นด์นด์˜คํ†ก ์ฑ„๋„ ๋ฉ”์‹œ์ง€ ์ „์†ก ๋ฌด๋ฃŒ ํšŸ์ˆ˜๊ฐ€ ์—†์–ด์ง์— ๋”ฐ๋ผ KakaoTalk Develops์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ƒ์„ฑ ํ›„ REST API๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์•„ '๋‚˜์—๊ฒŒ ๋ณด๋‚ด๊ธฐ' ๊ธฐ๋Šฅ์œผ๋กœ๋งŒ ์นด์นด์˜คํ†ก ๋ฉ”์‹œ์ง€๋ฅผ ์ „์†ก๋ฐ›๊ฒŒ ํ•ด ๋‘์—ˆ์Šต๋‹ˆ๋‹ค.

 

+ ์ถ”๊ฐ€์ ์œผ๋กœ ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์˜ URL์ด ๋…ธ์ถœ๋˜์–ด๋„ ๋ฌด๋‹จ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋จผ์ € ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค๋ฉด ์ž„์›์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด DB์—์„œ ํšŒ์›๋“ค์˜ ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ํ…Œ์ด๋ธ”์—์„œ ์ž„์›๋“ค๋งŒ ๋นผ์„œ ๋ทฐ๋ฅผ ๋งŒ๋“ค์—ˆ๊ณ , ์ด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์ผ๋ฐ˜ ํšŒ์›๋“ค์€ ๋กœ๊ทธ์ธ ์‹œ๋„ ์‹œ ๋ณธ์ธ์˜ ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ๋งž๊ฒŒ ์ž…๋ ฅํ•ด๋„ ๋กœ๊ทธ์ธ์ด ๊ฑฐ๋ถ€๋˜๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

 

+ API์˜ ๋ฒ„์ „๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด Flask์˜ Blueprint๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์™€ ํšŒ์› ํŽ˜์ด์ง€์—์„œ ์“ฐ๋Š” API๋ฅผ ๋ถ„๋ฆฌ์‹œ์ผœ ๋†จ์Šต๋‹ˆ๋‹ค.  ์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌ์‹œ์ผœ ๋†“์œผ๋‹ˆ API์˜ ํ˜•์ƒ๊ด€๋ฆฌ ๋˜ํ•œ ์‰ฌ์›Œ์ง€๋Š” ํšจ๊ณผ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

+ BE๋ฅผ ์ง€์ธ์˜ AWS ์•„์ด๋””๋ฅผ ๋นŒ๋ ค EC2์— ๊ตฌ์ถ•ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

 

 

 

์‚ฌ์ง„ ์ถœ์ฒ˜

Flask : https://justkode.tistory.com/10
MySQL : https://velog.io/@leo3179/MySQL-%EB%A6%AC%EB%B7%B0
Vercel : https://www.hatimeria.com/services/vercel
Flask-RESTful API : https://ubeezy.netlify.app/flask-rest-api/
Openpyxl : https://hogelog.com/python/openpyxl-excel-chart-1.html
qrcode : https://www.geeksforgeeks.org/python-generate-qr-code-using-pyqrcode-module/
kakao developers : https://developers.kakao.com/tool/resource/developers