๐Ÿ“– ALPACO ์ปค๋ฎค๋‹ˆํ‹ฐ API: ๊ธฐ๋Šฅ ๋ฐ ๊ธฐ์ˆ  ๊ฐ€์ด๋“œ

1. ๊ฐœ์š”

ALPACO ์ปค๋ฎค๋‹ˆํ‹ฐ API๋Š” ๊ฒŒ์‹œ๋ฌผ, ๋Œ“๊ธ€, ์ข‹์•„์š” ์ƒ์„ฑ ๋ฐ ๊ด€๋ฆฌ๋ฅผ ํฌํ•จํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ์„ ์œ„ํ•œ ๋ฐฑ์—”๋“œ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. AWS ์„œ๋ฒ„๋ฆฌ์Šค ๊ธฐ์ˆ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ถ•๋œ ๊ฒฌ๊ณ ํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•˜๋ฉฐ ์•ˆ์ „ํ•œ API๋ฅผ ๋ชฉํ‘œ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ์—์„œ๋Š” ๊ธฐ๋Šฅ, ๊ธฐ๋ณธ ๊ธฐ์ˆ , ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ๋ฐ ๋ฐฐํฌ ์ ˆ์ฐจ๋ฅผ ์ž์„ธํžˆ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ ๊ฒฝ๋กœ: capstone-2025-04 API ์ธํ”„๋ผ ๊ฒฝ๋กœ: infrastructure/api Lambda ์†Œ์Šค ๊ฒฝ๋กœ: backend/lambdas/community-lambda-functions/

2. ์ฃผ์š” ๊ธฐ๋Šฅ

  • ๊ฒŒ์‹œ๋ฌผ ๊ด€๋ฆฌ:
    • ์ƒˆ ๊ฒŒ์‹œ๋ฌผ ์ž‘์„ฑ (ํ…์ŠคํŠธ ๊ธฐ๋ฐ˜, Markdown ์ง€์›).
    • ์„ ํƒ์ ์œผ๋กœ ๊ฒŒ์‹œ๋ฌผ์„ ํŠน์ • ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฌธ์ œ์™€ ์—ฐ๊ฒฐ.
    • ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก ๊ฒ€์ƒ‰ (ํŽ˜์ด์ง€๋„ค์ด์…˜).
    • ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์˜ ์ƒ์„ธ ์ •๋ณด ๊ฒ€์ƒ‰.
    • ๊ธฐ์กด ๊ฒŒ์‹œ๋ฌผ ์—…๋ฐ์ดํŠธ (์ œ๋ชฉ, ๋‚ด์šฉ).
    • ๊ฒŒ์‹œ๋ฌผ ์‚ญ์ œ (๊ด€๋ จ ๋Œ“๊ธ€๋„ ํ•จ๊ป˜ ์‚ญ์ œ).
  • ๋Œ“๊ธ€ ๊ด€๋ฆฌ:
    • ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์— ๋Œ“๊ธ€ ์ž‘์„ฑ.
    • ๊ฒŒ์‹œ๋ฌผ์˜ ๋ชจ๋“  ๋Œ“๊ธ€ ๊ฒ€์ƒ‰ (ํŽ˜์ด์ง€๋„ค์ด์…˜, ์ƒ์„ฑ ๋‚ ์งœ ๊ธฐ์ค€ ์ •๋ ฌ).
    • ๋Œ“๊ธ€ ์‚ญ์ œ.
  • ์ข‹์•„์š” ๊ด€๋ฆฌ:
    • ๊ฒŒ์‹œ๋ฌผ ์ข‹์•„์š”/์ข‹์•„์š” ์ทจ์†Œ.
    • ๊ฒŒ์‹œ๋ฌผ์˜ ์ข‹์•„์š” ์ˆ˜ ์ถ”์ .
  • ์‚ฌ์šฉ์ž ์ธ์ฆ:
    • Amazon Cognito๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘์š” ์ž‘์—…(์ƒ์„ฑ, ์—…๋ฐ์ดํŠธ, ์‚ญ์ œ, ์ข‹์•„์š”) ๋ณด์•ˆ.
    • ์ฝ๊ธฐ ์ž‘์—…(๊ฒŒ์‹œ๋ฌผ ๊ฐ€์ ธ์˜ค๊ธฐ, ๋Œ“๊ธ€ ๊ฐ€์ ธ์˜ค๊ธฐ)์€ ๊ณต๊ฐœ ์•ก์„ธ์Šค.
  • ๋ฐ์ดํ„ฐ ์˜์†์„ฑ:
    • Amazon DynamoDB๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฒŒ์‹œ๋ฌผ๊ณผ ๋Œ“๊ธ€์„ ์ €์žฅํ•˜๊ณ  ํšจ์œจ์ ์ธ ์ฟผ๋ฆฌ ํŒจํ„ด ์‚ฌ์šฉ.

3. ๊ธฐ์ˆ  ์Šคํƒ

  • ๋ฐฑ์—”๋“œ ๋กœ์ง:
    • AWS Lambda: ๊ฐ API ์ž‘์—…์„ ์œ„ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์‹คํ–‰ํ•˜๋Š” ์„œ๋ฒ„๋ฆฌ์Šค ํ•จ์ˆ˜ (Node.js 20.x ๋Ÿฐํƒ€์ž„).
    • AWS Lambda Layer: Lambda ํ•จ์ˆ˜์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ณต์œ  Node.js ์˜์กด์„ฑ(์˜ˆ: uuid)์„ ํŒจํ‚ค์ง•ํ•œ ๋ ˆ์ด์–ด.
  • API ๋…ธ์ถœ:
    • Amazon API Gateway: Lambda ํ•จ์ˆ˜๋ฅผ HTTP ์—”๋“œํฌ์ธํŠธ๋กœ ๋…ธ์ถœํ•˜๋Š” RESTful API. ์š”์ฒญ ๋ผ์šฐํŒ…, ๊ถŒํ•œ ๋ถ€์—ฌ, CORS ์ฒ˜๋ฆฌ.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค:
    • Amazon DynamoDB: ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฐ์ดํ„ฐ(๊ฒŒ์‹œ๋ฌผ, ๋Œ“๊ธ€) ์ €์žฅ์„ ์œ„ํ•œ NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค. ํšจ์œจ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์œ„ํ•ด ๊ธ€๋กœ๋ฒŒ ๋ณด์กฐ ์ธ๋ฑ์Šค(GSI)๋กœ ์„ค๊ณ„.
  • ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ:
    • Amazon Cognito: ์‚ฌ์šฉ์ž ํ’€์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž ID๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ๋ณดํ˜ธ๋œ API ์—”๋“œํฌ์ธํŠธ์— JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ์ œ๊ณต.
  • ์ฝ”๋“œํ˜• ์ธํ”„๋ผ (IaC):
    • Terraform: ๋ชจ๋“  AWS ๋ฆฌ์†Œ์Šค๋ฅผ ์„ ์–ธ์ ์œผ๋กœ ์ •์˜ํ•˜๊ณ  ํ”„๋กœ๋น„์ €๋‹.
      • ์ƒํƒœ ๊ด€๋ฆฌ: AWS S3 (Terraform ์ƒํƒœ ํŒŒ์ผ์šฉ) ๋ฐ DynamoDB (์ƒํƒœ ์ž ๊ธˆ์šฉ).
  • CI/CD:
    • GitHub Actions: main ๋ธŒ๋žœ์น˜์— ํ‘ธ์‹œ ์‹œ ์ธํ”„๋ผ ๋ฐ Lambda ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•œ ์ž๋™ํ™”๋œ ์›Œํฌํ”Œ๋กœ์šฐ. ์•ˆ์ „ํ•œ AWS ์ธ์ฆ์„ ์œ„ํ•ด OIDC ํ™œ์šฉ.
  • ํ”„๋ก ํŠธ์—”๋“œ (์—ฐ๋™ ์ง€์ ):
    • Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜.
    • ํ”„๋ก ํŠธ์—”๋“œ ์ธ์ฆ ๋ฐ Cognito์™€์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ์œ„ํ•œ AWS Amplify.
    • API Gateway๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ์ปค์Šคํ…€ API ํด๋ผ์ด์–ธํŠธ (communityApi.ts - ๊ฐœ๋…์ ).

4. API ์—”๋“œํฌ์ธํŠธ

API๋Š” /community ๊ธฐ๋ณธ ๊ฒฝ๋กœ ํ•˜์œ„์— ๋ฐฐํฌ๋ฉ๋‹ˆ๋‹ค. ์ „์ฒด ํ˜ธ์ถœ URL์€ Terraform ๋ฐฐํฌ์˜ ์ถœ๋ ฅ ๊ฐ’์ž…๋‹ˆ๋‹ค (์˜ˆ: https://{api_id}.execute-api.{region}.amazonaws.com/{stage}/community).

๋ฉ”์„œ๋“œ ๊ฒฝ๋กœ ์ธ์ฆ ํ•„์š” Lambda ํ•จ์ˆ˜ ์„ค๋ช…
POST /community โœ… ์˜ˆ createPost ์ƒˆ ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ฒŒ์‹œ๋ฌผ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
GET /community โฌœ ์•„๋‹ˆ์š” getAllPosts ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜๋œ ๋ชฉ๋ก์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
GET /community/{postId} โฌœ ์•„๋‹ˆ์š” getPost ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์˜ ์ƒ์„ธ ์ •๋ณด๋ฅผ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
PATCH /community/{postId} โœ… ์˜ˆ updatePost ๊ธฐ์กด ๊ฒŒ์‹œ๋ฌผ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
DELETE /community/{postId} โœ… ์˜ˆ deletePost ๊ฒŒ์‹œ๋ฌผ๊ณผ ๊ด€๋ จ ๋Œ“๊ธ€์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
POST /community/{postId}/like โœ… ์˜ˆ likePost ๊ฒŒ์‹œ๋ฌผ์— ์ข‹์•„์š”๋ฅผ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ์ทจ์†Œํ•ฉ๋‹ˆ๋‹ค.
POST /community/{postId}/comments โœ… ์˜ˆ createComment ๊ฒŒ์‹œ๋ฌผ์— ์ƒˆ ๋Œ“๊ธ€์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
GET /community/{postId}/comments โฌœ ์•„๋‹ˆ์š” getComments ๊ฒŒ์‹œ๋ฌผ์˜ ํŽ˜์ด์ง€๋„ค์ด์…˜๋œ ๋Œ“๊ธ€ ๋ชฉ๋ก์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
DELETE /community/{postId}/comments/{commentId} โœ… ์˜ˆ deleteComment ํŠน์ • ๋Œ“๊ธ€์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.
OPTIONS ์œ„์˜ ๋ชจ๋“  ๊ฒฝ๋กœ โฌœ ์•„๋‹ˆ์š” API Gateway MOCK CORS ์‚ฌ์ „ ์š”์ฒญ(preflight request)์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ธ์ฆ: โ€œโœ… ์˜ˆโ€๋กœ ํ‘œ์‹œ๋œ ์—”๋“œํฌ์ธํŠธ๋Š” Amazon Cognito์—์„œ ์–ป์€ JWT ID ํ† ํฐ์„ ํฌํ•จํ•˜๋Š” Authorization ํ—ค๋”๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: Authorization: Bearer <your_cognito_id_token>.

์š”์ฒญ/์‘๋‹ต ์˜ˆ์‹œ (๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ):

  • ์š”์ฒญ: POST /community
    // ํ—ค๋”:
    // Content-Type: application/json
    // Authorization: Bearer <token>
    {
      "title": "๋ฌธ์ œ X์— ๋Œ€ํ•œ ๋‚˜์˜ ์ฒซ ๊ฒŒ์‹œ๋ฌผ",
      "content": "์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์ด๋ ‡์Šต๋‹ˆ๋‹ค...\n\n```python\nprint('hello')\n```",
      "problemId": "optional-problem-uuid", // ์„ ํƒ ์‚ฌํ•ญ
      "author": "์‚ฌ์šฉ์ž๋‹‰๋„ค์ž„" // ์‚ฌ์šฉ์ž ํ‘œ์‹œ ์ด๋ฆ„
    }
    
  • ์‘๋‹ต (201 Created):
    {
      "message": "๊ฒŒ์‹œ๊ธ€์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.",
      "postId": "generated-uuid-for-post",
      "author": "์‚ฌ์šฉ์ž๋‹‰๋„ค์ž„",
      "title": "๋ฌธ์ œ X์— ๋Œ€ํ•œ ๋‚˜์˜ ์ฒซ ๊ฒŒ์‹œ๋ฌผ",
      "content": "์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์ด๋ ‡์Šต๋‹ˆ๋‹ค...\n\n```python\nprint('hello')\n```",
      "createdAt": "iso-timestamp",
      "problemId": "optional-problem-uuid" // ๋˜๋Š” null
    }
    

5. ๋ฐ์ดํ„ฐ ๋ชจ๋ธ (DynamoDB)

๋‹จ์ผ DynamoDB ํ…Œ์ด๋ธ”(๊ธฐ๋ณธ๊ฐ’: alpaco-Community-production)์— ๋ชจ๋“  ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

  • ํ…Œ์ด๋ธ” ์ด๋ฆ„: ${var.project_name}-Community-${var.environment}
  • ๊ธฐ๋ณธ ํ‚ค:
    • PK: ํŒŒํ‹ฐ์…˜ ํ‚ค
    • SK: ์ •๋ ฌ ํ‚ค
  • ์†์„ฑ (ํ•ต์‹ฌ):
    • PK (๋ฌธ์ž์—ด): ๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ๊ณผ ๋Œ“๊ธ€ ํ•ญ๋ชฉ ๋ชจ๋‘์— ๋Œ€ํ•ด postId.
    • SK (๋ฌธ์ž์—ด):
      • ๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ: "POST"
      • ๋Œ“๊ธ€ ํ•ญ๋ชฉ: "COMMENT#{commentId}"
    • userId (๋ฌธ์ž์—ด): ์ž‘์„ฑ์ž/๋Œ“๊ธ€ ์ž‘์„ฑ์ž์˜ Cognito ์‚ฌ์šฉ์ž ID.
    • author (๋ฌธ์ž์—ด): ์ž‘์„ฑ์ž/๋Œ“๊ธ€ ์ž‘์„ฑ์ž์˜ ํ‘œ์‹œ ์ด๋ฆ„.
    • title (๋ฌธ์ž์—ด): ๊ฒŒ์‹œ๋ฌผ ์ œ๋ชฉ (๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์—๋งŒ ํ•ด๋‹น).
    • content (๋ฌธ์ž์—ด): ๊ฒŒ์‹œ๋ฌผ ๋˜๋Š” ๋Œ“๊ธ€ ๋‚ด์šฉ (Markdown).
    • createdAt (๋ฌธ์ž์—ด): ISO 8601 ํƒ€์ž„์Šคํƒฌํ”„.
    • updatedAt (๋ฌธ์ž์—ด): ISO 8601 ํƒ€์ž„์Šคํƒฌํ”„ (๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์šฉ).
    • likesCount (์ˆซ์ž): ์ข‹์•„์š” ์ˆ˜ (๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์šฉ).
    • likedUsers (๋ฌธ์ž์—ด ์ง‘ํ•ฉ): ๊ฒŒ์‹œ๋ฌผ์„ ์ข‹์•„ํ•œ userId ์ง‘ํ•ฉ (๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์šฉ).
    • commentCount (์ˆซ์ž): ๊ฒŒ์‹œ๋ฌผ์˜ ๋Œ“๊ธ€ ์ˆ˜ (๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์šฉ).
    • problemId (๋ฌธ์ž์—ด): ์—ฐ๊ด€๋œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฌธ์ œ์˜ ์„ ํƒ์  ID (๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์šฉ).
    • commentId (๋ฌธ์ž์—ด): ๋Œ“๊ธ€์˜ ๊ณ ์œ  ID (๋Œ“๊ธ€ ํ•ญ๋ชฉ์šฉ, SK์˜ ์ผ๋ถ€์ด๊ธฐ๋„ ํ•จ).
  • ๊ธ€๋กœ๋ฒŒ ๋ณด์กฐ ์ธ๋ฑ์Šค (GSI):
    1. postOnlyIndex:
      • ๋ชฉ์ : ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์„ ์ƒ์„ฑ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ํšจ์œจ์ ์œผ๋กœ ๋‚˜์—ด. getAllPosts Lambda์—์„œ ์‚ฌ์šฉ.
      • GSI1PK (๋ฌธ์ž์—ด): "POST" (๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ ํ•ญ๋ชฉ์— ๋Œ€ํ•œ ์ƒ์ˆ˜).
      • GSI1SK (๋ฌธ์ž์—ด): createdAt ํƒ€์ž„์Šคํƒฌํ”„.
      • ํ”„๋กœ์ ์…˜: ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก ๋ณด๊ธฐ์— ํ•„์š”ํ•œ ์†์„ฑ ํฌํ•จ (PK, title, author, createdAt, likesCount, commentCount, problemId, userId).
      • ์ฐธ๊ณ : createPost Lambda๋Š” ์ƒˆ ๊ฒŒ์‹œ๋ฌผ์— ๋Œ€ํ•ด GSI1PK์™€ GSI1SK๋ฅผ ์ž‘์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    2. commentSortIndex:
      • ๋ชฉ์ : ํŠน์ • ๊ฒŒ์‹œ๋ฌผ์˜ ๋ชจ๋“  ๋Œ“๊ธ€์„ ์ƒ์„ฑ ์‹œ๊ฐ„์ˆœ์œผ๋กœ ํšจ์œจ์ ์œผ๋กœ ๋‚˜์—ด. getComments Lambda์—์„œ ์‚ฌ์šฉ.
      • PK (๋ฌธ์ž์—ด): postId (๊ธฐ๋ณธ ํ…Œ์ด๋ธ” PK๋ฅผ GSI ํ•ด์‹œ ํ‚ค๋กœ ์žฌ์‚ฌ์šฉ).
      • createdAt (๋ฌธ์ž์—ด): ๋Œ“๊ธ€์˜ createdAt ํƒ€์ž„์Šคํƒฌํ”„ (๊ธฐ์กด ์†์„ฑ์„ GSI ๋ฒ”์œ„ ํ‚ค๋กœ ์žฌ์‚ฌ์šฉ).
      • ํ•„ํ„ฐ: Lambda๋Š” ์ด GSI๋ฅผ ์ฟผ๋ฆฌํ•  ๋•Œ SK๊ฐ€ COMMENT#๋กœ ์‹œ์ž‘ํ•˜๋Š”์ง€ ์ถ”๊ฐ€๋กœ ํ•„ํ„ฐ๋งํ•ฉ๋‹ˆ๋‹ค.
      • ํ”„๋กœ์ ์…˜: ๋Œ“๊ธ€ ๋ชฉ๋ก ๋ณด๊ธฐ์— ํ•„์š”ํ•œ ์†์„ฑ ํฌํ•จ (content, author, commentId, userId, SK).

6. Lambda ํ•จ์ˆ˜

backend/lambdas/community-lambda-functions/์— ์œ„์น˜ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ํ•จ์ˆ˜๋Š” Node.js 20.x ๋Ÿฐํƒ€์ž„์„ ์‚ฌ์šฉํ•˜๊ณ , ๊ณตํ†ต IAM ์‹คํ–‰ ์—ญํ• ์„ ๊ณต์œ ํ•˜๋ฉฐ, common-deps Lambda ๋ ˆ์ด์–ด๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. COMMUNITY_TABLE_NAME ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. _modified.mjs ์ ‘๋ฏธ์‚ฌ๋Š” ํ˜„์žฌ ์ธํ”„๋ผ์— ๋งž๊ฒŒ ์ˆ˜์ •๋œ ๋ฒ„์ „์ž„์„ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค (์˜ˆ: AWS SDK v3 ์‚ฌ์šฉ, ํŠน์ • DynamoDB ์ƒํ˜ธ์ž‘์šฉ).

  • ๊ฒŒ์‹œ๋ฌผ ํ•จ์ˆ˜:
    • createPost_modified.mjs: GSI ํ‚ค ์ž‘์„ฑ์„ ํฌํ•จํ•˜์—ฌ ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ฑ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • deletePost_modified.mjs: ๊ฒŒ์‹œ๋ฌผ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋Œ“๊ธ€์„ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ์†Œ์œ ๊ถŒ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • getAllPosts_modified.mjs: postOnlyIndex๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€๋„ค์ด์…˜๋œ ๊ฒฐ๊ณผ๋กœ ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    • getPost_modified.mjs: ID๋กœ ๋‹จ์ผ ๊ฒŒ์‹œ๋ฌผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    • likePost_modified.mjs: ๊ฒŒ์‹œ๋ฌผ์˜ likedUsers ์ง‘ํ•ฉ์— ์‚ฌ์šฉ์ž๋ฅผ ์ถ”๊ฐ€/์ œ๊ฑฐํ•˜๊ณ  likesCount๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
    • updatePost_modified.mjs: ๊ฒŒ์‹œ๋ฌผ ์ œ๋ชฉ/๋‚ด์šฉ์„ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค. ์†Œ์œ ๊ถŒ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ๋Œ“๊ธ€ ํ•จ์ˆ˜:
    • comment/createComment_modified.mjs: ๋Œ“๊ธ€์„ ์ƒ์„ฑํ•˜๊ณ  ๋ถ€๋ชจ ๊ฒŒ์‹œ๋ฌผ์˜ commentCount๋ฅผ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์ฆ๊ฐ€์‹œํ‚ต๋‹ˆ๋‹ค.
    • comment/deleteComment_modified.mjs: ๋Œ“๊ธ€์„ ์‚ญ์ œํ•˜๊ณ  ๋ถ€๋ชจ ๊ฒŒ์‹œ๋ฌผ์˜ commentCount๋ฅผ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ๊ฐ์†Œ์‹œํ‚ต๋‹ˆ๋‹ค. ์†Œ์œ ๊ถŒ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • comment/getComments_modified.mjs: commentSortIndex๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์‹œ๋ฌผ์˜ ๋Œ“๊ธ€์„ ํŽ˜์ด์ง€๋„ค์ด์…˜ํ•˜๊ณ  ์ •๋ ฌํ•˜์—ฌ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

7. ์ฝ”๋“œํ˜• ์ธํ”„๋ผ (Terraform)

์ธํ”„๋ผ๋Š” infrastructure/api/์— ์œ„์น˜ํ•œ Terraform์œผ๋กœ ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

  • ์ฃผ์š” ํŒŒ์ผ:
    • providers.tf: AWS ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • backend.tf: S3 ์›๊ฒฉ ์ƒํƒœ ๋ฐฑ์—”๋“œ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค (key = "api/community/terraform.tfstate").
    • variables.tf: ์ž…๋ ฅ ๋ณ€์ˆ˜ (๋ฆฌ์ „, ํ”„๋กœ์ ํŠธ ์ด๋ฆ„, ํ™˜๊ฒฝ)๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • outputs.tf: API Gateway ํ˜ธ์ถœ URL๊ณผ ๊ฐ™์€ ์ถœ๋ ฅ ๊ฐ’์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • iam.tf: IAM ์—ญํ•  (Lambda ์‹คํ–‰, API Gateway CloudWatch ๋กœ๊น…) ๋ฐ ์ •์ฑ… (DynamoDB ์ ‘๊ทผ)์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • dynamodb.tf: Community DynamoDB ํ…Œ์ด๋ธ” ๋ฐ GSI๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • layer.tf: layers/common-deps/nodejs/์˜ common-deps Lambda ๋ ˆ์ด์–ด๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
    • lambdas.tf: ๋ชจ๋“  aws_lambda_function ๋ฆฌ์†Œ์Šค๋ฅผ ์ •์˜ํ•˜๋ฉฐ, ../../backend/lambdas/community-lambda-functions/์—์„œ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์••์ถ•ํ•ฉ๋‹ˆ๋‹ค.
    • apigateway.tf: API Gateway (REST API, ๋ฆฌ์†Œ์Šค, ๋ฉ”์„œ๋“œ, ํ†ตํ•ฉ, Cognito Authorizer, ๋ฐฐํฌ, ์Šคํ…Œ์ด์ง€)๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ์›๊ฒฉ ์ƒํƒœ: infrastructure/backend-setup ๋ชจ๋“ˆ์—์„œ ์ƒ์„ฑ๋œ S3 ๋ฒ„ํ‚ท(alpaco-tfstate-bucket-kmu)๊ณผ DynamoDB ํ…Œ์ด๋ธ”(alpaco-tfstate-lock-table)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • Cognito ์˜์กด์„ฑ: cognito/terraform.tfstate ์›๊ฒฉ ์ƒํƒœ์—์„œ Cognito ์‚ฌ์šฉ์ž ํ’€ ARN์„ ์ฝ์–ด API Gateway Authorizer๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ์ดˆ๊ธฐํ™” ๋ฐ ๋ฐฐํฌ:
    # infrastructure/api๋กœ ์ด๋™
    cd infrastructure/api
    
    # ์ดˆ๊ธฐํ™” (ํ”Œ๋ ˆ์ด์Šคํ™€๋”๋ฅผ ์‹ค์ œ ๊ฐ’์œผ๋กœ ๊ต์ฒด)
    terraform init \
      -backend-config="bucket=<YOUR_TFSTATE_BUCKET_NAME>" \
      -backend-config="key=api/community/terraform.tfstate" \
      -backend-config="region=<YOUR_AWS_REGION>" \
      -backend-config="dynamodb_table=<YOUR_TFSTATE_LOCK_TABLE_NAME>"
    
    # ๋ณ€๊ฒฝ ๊ณ„ํš ๊ฒ€ํ† 
    terraform plan
    
    # ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ ์šฉ
    terraform apply
    

8. CI/CD (GitHub Actions)

์ž๋™ํ™”๋Š” .github/workflows/deploy-api.yml์— ์ •์˜๋œ GitHub Actions ์›Œํฌํ”Œ๋กœ์šฐ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค (PLAN.md ์ฐธ์กฐ).

  • ํŠธ๋ฆฌ๊ฑฐ: backend/lambdas/community/** ๋˜๋Š” infrastructure/api/**์— ์˜ํ–ฅ์„ ๋ฏธ์น˜๋Š” main ๋ธŒ๋žœ์น˜๋กœ์˜ ํ‘ธ์‹œ.
  • ์ธ์ฆ: OpenID Connect (OIDC)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ AWS์—์„œ IAM ์—ญํ• ์„ ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜์ž„ํ•˜์—ฌ ์žฅ๊ธฐ ์ž๊ฒฉ ์ฆ๋ช…์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋‹จ๊ณ„:
    1. ์ฝ”๋“œ ์ฒดํฌ์•„์›ƒ.
    2. Node.js ์„ค์ •.
    3. Lambda ๋ ˆ์ด์–ด ์˜์กด์„ฑ์„ ์ค€๋น„ํ•˜๊ธฐ ์œ„ํ•ด infrastructure/api/layers/common-deps/nodejs/์—์„œ npm install ์‹คํ–‰.
    4. secrets.AWS_IAM_ROLE_ARN_API์˜ ์—ญํ•  ARN์„ ์‚ฌ์šฉํ•˜์—ฌ OIDC๋ฅผ ํ†ตํ•ด AWS ์ž๊ฒฉ ์ฆ๋ช… ์„ค์ •.
    5. infrastructure/api ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์—์„œ terraform init (secrets์˜ ๋ฐฑ์—”๋“œ ์„ค์ • ์‚ฌ์šฉ), terraform plan, terraform apply ์‹คํ–‰.
  • ํ•„์ˆ˜ Secrets:
    • AWS_IAM_ROLE_ARN_API: GitHub Actions๊ฐ€ ์ˆ˜์ž„ํ•  IAM ์—ญํ• ์˜ ARN.
    • AWS_REGION: ๋Œ€์ƒ AWS ๋ฆฌ์ „.
    • TF_STATE_BUCKET: Terraform ์ƒํƒœ์šฉ S3 ๋ฒ„ํ‚ท.
    • TF_STATE_LOCK_TABLE: Terraform ์ƒํƒœ ์ž ๊ธˆ์šฉ DynamoDB ํ…Œ์ด๋ธ”.

9. ํ”„๋ก ํŠธ์—”๋“œ ์—ฐ๋™

ํ”„๋ก ํŠธ์—”๋“œ(Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜)๋Š” ์ด API์™€ ์ƒํ˜ธ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค.

  • API ํด๋ผ์ด์–ธํŠธ: API ํ˜ธ์ถœ์„ ์บก์Аํ™”ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐœ๋…์ ์ธ communityApi.ts(๋˜๋Š” ์œ ์‚ฌํ•œ ์„œ๋น„์Šค ๋ชจ๋“ˆ)๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
  • ์—”๋“œํฌ์ธํŠธ ์„ค์ •: API Gateway ํ˜ธ์ถœ URL์€ ์ผ๋ฐ˜์ ์œผ๋กœ ํ™˜๊ฒฝ ๋ณ€์ˆ˜(์˜ˆ: NEXT_PUBLIC_API_ENDPOINT)๋ฅผ ํ†ตํ•ด ํ”„๋ก ํŠธ์—”๋“œ์— ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.
  • ์ธ์ฆ:
    • AWS Amplify์˜ useAuthenticator ํ›…์ด ์‚ฌ์šฉ์ž ์ธ์ฆ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • Amplify Auth์˜ fetchAuthSession์„ ์‚ฌ์šฉํ•˜์—ฌ ํ˜„์žฌ ์‚ฌ์šฉ์ž์˜ JWT ID ํ† ํฐ์„ ๊ฒ€์ƒ‰ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ณดํ˜ธ๋œ API ํ˜ธ์ถœ(์ƒ์„ฑ, ์—…๋ฐ์ดํŠธ, ์‚ญ์ œ, ์ข‹์•„์š”)์˜ ๊ฒฝ์šฐ ์ด JWT ํ† ํฐ์ด Authorization ํ—ค๋”์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค: Authorization: Bearer <id_token>.
    • ์‚ฌ์šฉ์ž ์†์„ฑ(์˜ˆ: ํŽ˜์ด๋กœ๋“œ ๋˜๋Š” UI์— ์‚ฌ์šฉํ•  nickname ๋˜๋Š” sub (userId์šฉ))์€ fetchUserAttributes๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
  • ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ: ํ”„๋ก ํŠธ์—”๋“œ ์ปดํฌ๋„ŒํŠธ๋Š” API ์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ์ข…์ข… ํ† ์ŠคํŠธ ์•Œ๋ฆผ(์˜ˆ: sonner ์‚ฌ์šฉ)์„ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.
  • ์˜ˆ์ œ ํŽ˜์ด์ง€:
    • frontend/src/app/community/page.tsx: ๊ฒŒ์‹œ๋ฌผ ๋ชฉ๋ก ํ‘œ์‹œ ๋ฐ ๊ฒŒ์‹œ๋ฌผ ์ƒ์„ธ ์ •๋ณด ํ‘œ์‹œ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    • frontend/src/app/community/create/page.tsx: ์ƒˆ ๊ฒŒ์‹œ๋ฌผ ์ž‘์„ฑ์„ ์œ„ํ•œ ํผ์ž…๋‹ˆ๋‹ค.
    • frontend/src/app/community/edit/page.tsx: ๊ธฐ์กด ๊ฒŒ์‹œ๋ฌผ ์ˆ˜์ •์„ ์œ„ํ•œ ํผ์ž…๋‹ˆ๋‹ค.

10. CORS ์„ค์ •

CORS(Cross-Origin Resource Sharing)๋Š” API Gateway์—์„œ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

  • ๊ฐ ๋ฆฌ์†Œ์Šค ๊ฒฝ๋กœ์— ๋Œ€ํ•ด OPTIONS ๋ฉ”์„œ๋“œ๊ฐ€ MOCK ํ†ตํ•ฉ์œผ๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค.
  • ์ด๋Ÿฌํ•œ OPTIONS ๋ฉ”์„œ๋“œ ๋ฐ ์‹ค์ œ ์—”๋“œํฌ์ธํŠธ ๋ฉ”์„œ๋“œ์—๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‘๋‹ต ํ—ค๋”๊ฐ€ ํฌํ•จ๋ฉ๋‹ˆ๋‹ค:
    • Access-Control-Allow-Origin: '*' (ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ํŠน์ • ํ”„๋ก ํŠธ์—”๋“œ URL)
    • Access-Control-Allow-Methods: 'POST,GET,PATCH,DELETE,OPTIONS' (๋ฆฌ์†Œ์Šค๋งˆ๋‹ค ๋‹ค๋ฆ„)
    • Access-Control-Allow-Headers: 'Content-Type,Authorization,X-Amz-Date,X-Api-Key,X-Amz-Security-Token'
  • Lambda ํ•จ์ˆ˜๋„ ์‘๋‹ต์— CORS ํ—ค๋”๋ฅผ ํฌํ•จํ•˜์—ฌ ๊ฒฌ๊ณ ์„ฑ์„ ๋†’์ด์ง€๋งŒ, API Gateway๊ฐ€ ๊ธฐ๋ณธ ์ฒ˜๋ฆฌ๊ธฐ์ž…๋‹ˆ๋‹ค.

์ด ๊ฐ€์ด๋“œ๋Š” ALPACO ์ปค๋ฎค๋‹ˆํ‹ฐ API ์‹œ์Šคํ…œ์— ๋Œ€ํ•œ ํฌ๊ด„์ ์ธ ์ดํ•ด๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ณ„ Terraform ํŒŒ์ผ ๋ฐ Lambda ์†Œ์Šค ์ฝ”๋“œ๋Š” ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„ ์‚ฌํ•ญ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.