Submissions API & ํ๋ก ํธ์๋ ์ฐ๋ (capstone-2025-04)
1. ๊ฐ์
์ด ๋ชจ๋์ ํ๋ก๊ทธ๋๋ฐ ๊ฒฝ์ง๋ํ ์ ์ถ(Submission) ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ๋ฐฑ์๋ ์๋น์ค์ธ โSubmissions APIโ๋ฅผ ๊ตฌํํฉ๋๋ค. ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ด API๋ฅผ ํตํด ์ ์ถ ๋ชฉ๋ก์ ํ์ํ๊ณ , ํํฐ๋งํ๋ฉฐ, ๊ฐ๋ณ ์ ์ถ์ ์์ธ ์ ๋ณด๋ฅผ ๋ณผ ์ ์๋๋ก ์ค๊ณ๋์์ต๋๋ค.
API๋ AWS API Gateway์ AWS Lambda๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌ์ถ๋์์ผ๋ฉฐ, ์ ์ถ ๊ธฐ๋ก์ ์ ์ฅํ๋ DynamoDB ํ
์ด๋ธ(์ด๋ code-execution-service
๋ชจ๋์์ ๊ด๋ฆฌ)๊ณผ ์ํธ ์์ฉํฉ๋๋ค. ํ๋ก ํธ์๋ ์ฐ๋์ ์ด API๋ฅผ ์ฌ์ฉํ๋ Next.js/React ํ์ด์ง๋ฅผ ํตํด ์์ฐ๋ฉ๋๋ค.
2. ์ฃผ์ ๊ธฐ๋ฅ
- ์ ์ถ ๋ชฉ๋ก ์กฐํ: ๋ชจ๋ ์ ์ถ ๋๋ ๋ค์ํ ๊ธฐ์ค์ผ๋ก ํํฐ๋ง๋ ์ ์ถ ๋ชฉ๋ก์ ํ์ด์ง๋ค์ด์ (pagination)ํ์ฌ ๊ฐ์ ธ์ต๋๋ค.
- ์ ์ถ ํํฐ๋ง:
userId
(์ ์ถํ ์ฌ์ฉ์์ ID) ๊ธฐ์คproblemId
(์๋ํ ๋ฌธ์ ์ ID) ๊ธฐ์คauthor
(์ ์ถ์์ ๋๋ค์/์ฌ์ฉ์๋ช ) ๊ธฐ์คproblemTitleTranslated
(๋ฒ์ญ๋ ๋ฌธ์ ์ ๋ชฉ์ ๋ํ ๋ถ๋ถ ๋๋ ์ ์ฒด ์ผ์น) ๊ธฐ์คuserId
์problemId
์กฐํฉauthor
์problemId
์กฐํฉ
- ์ ์ถ ์ ๋ ฌ:
submissionTime
๊ธฐ์ค์ผ๋ก ์ค๋ฆ์ฐจ์(ASC
) ๋๋ ๋ด๋ฆผ์ฐจ์(DESC
) ์ ๋ ฌํฉ๋๋ค. - ํ์ด์ง๋ค์ด์
: ํจ์จ์ ์ธ ๋ฐ์ดํฐ ๋ก๋ฉ์ ์ํด
pageSize
์lastEvaluatedKey
๋ฅผ ์ง์ํฉ๋๋ค. - ํน์ ์ ์ถ ์กฐํ:
submissionId
๋ฅผ ์ฌ์ฉํ์ฌ ๋จ์ผ ์ ์ถ์ ์ ์ฒด ์์ธ ์ ๋ณด(์ฌ์ฉ์ ์ฝ๋userCode
ํฌํจ)๋ฅผ ๊ฐ์ ธ์ต๋๋ค. - CORS ์ง์: API Gateway ์์ค์์ ์ค์ ํ๊ณ , ์ฌ์ ์์ฒญ(preflight request)์ ์ํด Lambda์์๋ ๊ฐํํฉ๋๋ค.
- ๋ก๊น : API Gateway ์ ๊ทผ ๋ก๊ทธ ๋ฐ Lambda ์คํ ๋ก๊ทธ๋ CloudWatch Logs๋ก ์ ์ก๋ฉ๋๋ค.
- ์ฝ๋ํ ์ธํ๋ผ (Infrastructure as Code): ๋ชจ๋ AWS ๋ฆฌ์์ค๋ Terraform์ ์ฌ์ฉํ์ฌ ํ๋ก๋น์ ๋๋ฉ๋๋ค.
3. ์ํคํ ์ฒ
์์คํ ์ ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ๋ฅผ ๋ฐ๋ฆ ๋๋ค:
- ํ๋ก ํธ์๋ (Next.js/React): ์ฌ์ฉ์๋
/submissions
ํ์ด์ง์ ์ํธ์์ฉํฉ๋๋ค. - API ํด๋ผ์ด์ธํธ (
submissionApi.ts
): Submissions API๋ก HTTP GET ์์ฒญ์ ๋ณด๋ ๋๋ค. - AWS API Gateway (
submissions_api
):/submissions
๋ฆฌ์์ค์GET
๋ฐOPTIONS
๋ฉ์๋๋ฅผ ๋ ธ์ถํฉ๋๋ค.GET
์์ฒญ์get_submission
Lambda ํจ์๋ก ๋ผ์ฐํ ํฉ๋๋ค (AWS_PROXY ํตํฉ).- CORS ์ฌ์ ์์ฒญ์ ์ํด MOCK ํตํฉ์ผ๋ก
OPTIONS
์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค.
- AWS Lambda (
get_submission
):- Node.js 20.x ๋ฒ์ ์ ํจ์์ ๋๋ค.
- API Gateway ์ด๋ฒคํธ์์ ์ฟผ๋ฆฌ ๋ฌธ์์ด ํ๋ผ๋ฏธํฐ๋ฅผ ํ์ฑํฉ๋๋ค.
submissionId
๊ฐ ์์ผ๋ฉด DynamoDB ํ ์ด๋ธ์ ๋ํดGetItem
์์ ์ ์ํํฉ๋๋ค.- ๊ทธ๋ ์ง ์์ผ๋ฉด, ํํฐ์ ๋ฐ๋ผ ์ ์ ํ ๊ธ๋ก๋ฒ ๋ณด์กฐ ์ธ๋ฑ์ค(GSI)๋ฅผ ํ์ฉํ์ฌ DynamoDB ํ
์ด๋ธ์
Query
์์ ์ ๊ตฌ์ฑํ๊ณ ์คํํฉ๋๋ค. - ์ ์ถ ๋ฐ์ดํฐ(๋๋ ์ค๋ฅ)๋ฅผ API Gateway๋ก ๋ฐํํฉ๋๋ค.
- AWS DynamoDB (
code-execution-service
์์ ๊ด๋ฆฌ):Submissions
ํ ์ด๋ธ์ ๋ชจ๋ ์ ์ถ ๊ธฐ๋ก์ ์ ์ฅํฉ๋๋ค.- Lambda์์ ์ฌ์ฉ๋๋ GSI:
ProblemIdSubmissionTimeIndex
(problemId-submissionTime)UserIdSubmissionTimeIndex
(userId-submissionTime)AllSubmissionsByTimeIndex
(is_submission-submissionTime, โ๋ชจ๋ ์ ์ถโ์ฉ)AuthorSubmissionTimeIndex
(author-submissionTime)
- AWS IAM: Lambda๊ฐ DynamoDB์ ์ ๊ทผํ๊ณ API Gateway๊ฐ ๋ก๊ทธ๋ฅผ ์์ฑํ๋ ๋ฐ ํ์ํ ๊ถํ์ ์ ๊ณตํฉ๋๋ค.
- AWS CloudWatch Logs: ๋ชจ๋ํฐ๋ง ๋ฐ ๋๋ฒ๊น ์ ์ํด API Gateway ๋ฐ Lambda์ ๋ก๊ทธ๋ฅผ ์ ์ฅํฉ๋๋ค.
4. ๊ธฐ์ ์คํ
- ๋ฐฑ์๋:
- AWS API Gateway (Regional Endpoint)
- AWS Lambda (Node.js 20.x, arm64 ์ํคํ ์ฒ)
- AWS DynamoDB (AWS SDK v3 for JavaScript๋ฅผ ํตํด ์ ๊ทผ)
- AWS IAM
- AWS CloudWatch Logs
- ์ฝ๋ํ ์ธํ๋ผ:
- Terraform (~> 5.0)
- ํ๋ก ํธ์๋ ํด๋ผ์ด์ธํธ (
submissionApi.ts
):- TypeScript
- Fetch API
- ํ๋ก ํธ์๋ UI (
submissions/page.tsx
):- Next.js 13+ (App Router)
- React
- TypeScript
- Tailwind CSS (ํด๋์ค๋ช ์ผ๋ก ์ ์ถ)
date-fns
(๋ ์ง ํฌ๋งทํ )sonner
(ํ ์คํธ ์๋ฆผ)
5. API ์๋ํฌ์ธํธ ์์ธ ์ ๋ณด
๋ชจ๋ ์๋ํฌ์ธํธ๋ API Gateway ์คํ
์ด์ง ํธ์ถ URL์ ๊ธฐ์ค์ผ๋ก ํฉ๋๋ค (์: https://{api_id}.execute-api.{region}.amazonaws.com/{stage_name}
).
5.1. ์ ์ถ ์กฐํ (๋ชฉ๋ก ๋๋ ํน์ ๊ฑด)
- ๊ฒฝ๋ก:
/submissions
- ๋ฉ์๋:
GET
- ์ค๋ช
: ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ์ ๋ฐ๋ผ ์ ์ถ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๊ฑฐ๋,
submissionId
๊ฐ ์ ๊ณต๋ ๊ฒฝ์ฐ ๋จ์ผ ์ ์ถ์ ๊ฐ์ ธ์ต๋๋ค. - ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ:
submissionId
(๋ฌธ์์ด, ์ ํ ์ฌํญ): ์ ๊ณต๋ ๊ฒฝ์ฐ, ID๋ก ํน์ ์ ์ถ์ ๊ฐ์ ธ์ต๋๋ค. ๋ค๋ฅธ ํํฐ๋ ๋ฌด์๋ฉ๋๋ค.userId
(๋ฌธ์์ด, ์ ํ ์ฌํญ): ์ฌ์ฉ์์ ๊ณ ์ ์๋ณ์๋ก ํํฐ๋งํฉ๋๋ค.problemId
(๋ฌธ์์ด, ์ ํ ์ฌํญ): ๋ฌธ์ ์ ๊ณ ์ ์๋ณ์๋ก ํํฐ๋งํฉ๋๋ค.author
(๋ฌธ์์ด, ์ ํ ์ฌํญ): ์์ฑ์์ ๋๋ค์์ผ๋ก ํํฐ๋งํฉ๋๋ค.problemTitleTranslated
(๋ฌธ์์ด, ์ ํ ์ฌํญ): ๋ฒ์ญ๋ ๋ฌธ์ ์ ๋ชฉ์ ๋ํ ๋์๋ฌธ์ ๊ตฌ๋ถ ๋ถ๋ถ ๋ฌธ์์ด ์ผ์น๋ก ํํฐ๋งํฉ๋๋ค.pageSize
(์ซ์, ์ ํ ์ฌํญ, ๊ธฐ๋ณธ๊ฐ: 20): ํ์ด์ง๋น ๋ฐํํ ํญ๋ชฉ ์์ ๋๋ค.lastEvaluatedKey
(๋ฌธ์์ด, ์ ํ ์ฌํญ): ๋ค์ ํ์ด์ง๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํ ์ด์ ์๋ต์lastEvaluatedKey
์ ๋๋ค. URL ์ธ์ฝ๋ฉ๋ JSON ๋ฌธ์์ด์ ๋๋ค.sortOrder
(๋ฌธ์์ด, ์ ํ ์ฌํญ, ๊ธฐ๋ณธ๊ฐ: โDESCโ):submissionTime
์ ๋ํ ์ ๋ ฌ ์์์ ๋๋ค. โASCโ ๋๋ โDESCโ๋ฅผ ํ์ฉํฉ๋๋ค.
- ์ธ์ฆ:
NONE
(๊ณต๊ฐ์ ์ผ๋ก ์ ๊ทผ ๊ฐ๋ฅ,apigateway.tf
์์AWS_IAM
๋๋ Cognito๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅ) - ์ฑ๊ณต ์๋ต (200 OK):
// ๋ชฉ๋ก ์ฟผ๋ฆฌ์ ๊ฒฝ์ฐ { "items": [ { "submissionId": "unique-submission-id-1", "problemId": "problem-abc-123", "problemTitle": "Original Problem Title", // ํญ์ ์กด์ฌํ์ง ์์ ์ ์์ "problemTitleTranslated": "๋ฒ์ญ๋ ๋ฌธ์ ์ ๋ชฉ", "userId": "user-xyz-789", "author": "AlpacoCoder", "status": "ACCEPTED", // ๋๋ WRONG_ANSWER, TIME_LIMIT_EXCEEDED ๋ฑ "submissionTime": "2023-10-27T10:30:00.123Z", // ISO 8601 ๋ฌธ์์ด (DynamoDB ์ ๋ ฌ ํค) "executionTime": 0.123, // ์ด "language": "python", "errorMessage": null // ๋๋ ์ํ๊ฐ ์ค๋ฅ์ธ ๊ฒฝ์ฐ ์ค๋ฅ ์ธ๋ถ ์ ๋ณด // submissionId๋ก ์กฐํ ์ userCode๋ ์ฌ๊ธฐ์ ํฌํจ๋ ์ ์์ (ํ๋ก์ ์ /๊ฐ์ ธ์ค๊ธฐ ๋ ๊ฒฝ์ฐ) } // ... ๋ ๋ง์ ํญ๋ชฉ๋ค ], "lastEvaluatedKey": "URL_ENCODED_JSON_STRING_OR_NULL", "count": 1, // ์ด ์๋ต์ ํญ๋ชฉ ์ "scannedCount": 1 // DynamoDB์์ ์ค์บํ ํญ๋ชฉ ์ (ํํฐ ํจ์จ์ฑ๊ณผ ๊ด๋ จ๋จ) } // ํน์ submissionId ์ฟผ๋ฆฌ์ ๊ฒฝ์ฐ (Lambda์์ ๋์ผํ ๊ตฌ์กฐ๋ก ๋ํ๋จ) { "items": [ { "submissionId": "specific-submission-id", "problemId": "problem-def-456", "problemTitleTranslated": "ํน์ ๋ฌธ์ ์ ๋ชฉ", "userId": "user-abc-123", "author": "TestUser", "status": "RUNTIME_ERROR", "submissionTime": "2023-10-28T12:00:00.000Z", "executionTime": 0.050, "language": "javascript", "userCode": "console.log('hello world'); // ์ค์ ์ฌ์ฉ์ ์ฝ๋", "errorMessage": "TypeError: undefined is not a function" } ], "lastEvaluatedKey": null, "count": 1, "scannedCount": 1 }
- ์ค๋ฅ ์๋ต:
400 Bad Request
: ์๋ชป๋lastEvaluatedKey
ํ์์ ๋๋ค.404 Not Found
:submissionId
๊ฐ ์ ๊ณต๋์์ง๋ง ์ ์ถ์ ์ฐพ์ ์ ์๋ ๊ฒฝ์ฐ์ ๋๋ค.500 Internal Server Error
: ์๋ฒ ์ธก ์ค๋ฅ (์: Lambda ๊ตฌ์ฑ ์ค๋ฅ, DynamoDB ์ ๊ทผ ๋ฌธ์ ).
5.2. CORS ์ฌ์ ์์ฒญ (Preflight)
- ๊ฒฝ๋ก:
/submissions
- ๋ฉ์๋:
OPTIONS
- ์ค๋ช : ๋ธ๋ผ์ฐ์ ๋ก๋ถํฐ์ CORS ์ฌ์ ์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค.
- ์๋ต (200 OK):
- ๋ค์ ํค๋๋ฅผ ํฌํจํฉ๋๋ค:
Access-Control-Allow-Origin: '*'
(์ค์ ๊ฐ๋ฅ)Access-Control-Allow-Methods: 'GET,OPTIONS'
Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'
- ๋ค์ ํค๋๋ฅผ ํฌํจํฉ๋๋ค:
6. Lambda ํจ์ (getSubmission.mjs
)
์์น: capstone-2025-04/backend/lambdas/submissions-api/getSubmission.mjs
- ๋ชฉ์ :
- API Gateway ํ๋ก์ ํตํฉ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.
- CORS๋ฅผ ์ํด
OPTIONS
์์ฒญ์ ์๋ตํฉ๋๋ค. - ์ฟผ๋ฆฌ ๋ฌธ์์ด ํ๋ผ๋ฏธํฐ๋ฅผ ํ์ฑํฉ๋๋ค.
- DynamoDB์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ต๋๋ค:
submissionId
๊ฐ ์์ผ๋ฉดGetItemCommand
๋ฅผ ์ฌ์ฉํฉ๋๋ค.- ๋ชฉ๋ก/ํํฐ๋ง๋ ์์ฒญ์ ๊ฒฝ์ฐ ์ ์ ํ GSI์
KeyConditionExpression
/FilterExpression
์ ์ฌ์ฉํ์ฌQueryCommand
๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- API Gateway๋ฅผ ์ํ ์๋ต ํ์์ ์ง์ ํฉ๋๋ค.
- ํ๊ฒฝ ๋ณ์:
SUBMISSIONS_TABLE_NAME
: ์ ์ถ์ ์ ์ฅํ๋ DynamoDB ํ ์ด๋ธ์ ์ด๋ฆ (code-execution-service
์๊ฒฉ ์ํ์์ ๊ฐ์ ธ์ด).AWS_NODEJS_CONNECTION_REUSE_ENABLED
: AWS SDK์ TCP ์ฐ๊ฒฐ ์ฌ์ฌ์ฉ์ ํ์ฑํํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํค๋ ค๋ฉด โ1โ๋ก ์ค์ ํฉ๋๋ค.
- ์ฃผ์ ๋ก์ง:
- GSI ์ ํ:
userId
,problemId
๋๋author
ํ๋ผ๋ฏธํฐ์ ๋ฐ๋ผ GSI๋ฅผ ๋์ ์ผ๋ก ์ ํํฉ๋๋ค. ํน์ ์ํฐํฐ ํํฐ๊ฐ ์ ๊ณต๋์ง ์์ผ๋ฉดAllSubmissionsByTimeIndex
๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. - ํ๋ก์ ์
ํํ์ (Projection Expression): ์ฝ๊ธฐ ์ฉ๋์ ์ต์ ํํ๊ณ ํ์ด๋ก๋ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ธฐ ์ํด DynamoDB์์ ๊ฒ์ํ ํน์ ์์ฑ์ ์ ํํฉ๋๋ค. ์ฐธ๊ณ :
submissionId
๋ก ๊ฐ์ ธ์ฌ ๋ Lambda๋ ํด๋น ํญ๋ชฉ์ ๋ชจ๋ ์์ฑ(userCode
ํฌํจ)์ ๊ฒ์ํฉ๋๋ค. - ์ค๋ฅ ์ฒ๋ฆฌ: DynamoDB ์์ ๋ฐ ํ๋ผ๋ฏธํฐ ํ์ฑ์ ์ํ ๊ธฐ๋ณธ try-catch ๋ธ๋ก์ ๋๋ค.
unmarshallItem
ํฌํผ ํจ์:GetItemCommand
๊ฒฐ๊ณผ์ ๋ํด DynamoDB์ ์์ฑ ๊ฐ ํ์(์:{ "S": "stringValue" }
)์ ํ์ค JavaScript ๊ฐ์ฒด๋ก ๋ณํํฉ๋๋ค.DynamoDBDocumentClient
๋QueryCommand
์ ๋ํด ์ด๋ฅผ ์๋์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค.
- GSI ์ ํ:
7. ํ๋ก ํธ์๋ ์ฐ๋
7.1. API ํด๋ผ์ด์ธํธ (capstone-2025-04/frontend/src/api/submissionApi.ts
)
SUBMISSIONS_API_BASE_URL
:NEXT_PUBLIC_SUBMISSIONS_API_BASE_URL
ํ๊ฒฝ ๋ณ์๋ฅผ ํตํด ์ค์ ๋ฉ๋๋ค.getSubmissions(params)
:GetSubmissionsParams
๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ฅผ ๊ตฌ์ฑํฉ๋๋ค./submissions
์๋ํฌ์ธํธ๋กGET
์์ฒญ์ ๋ณด๋ ๋๋ค.Promise<GetSubmissionsResponse>
๋ฅผ ๋ฐํํฉ๋๋ค.
getSubmissionById(submissionId)
:submissionId
ํ๋ผ๋ฏธํฐ๋ก/submissions
์๋ํฌ์ธํธ๋ฅผ ์ฟผ๋ฆฌํฉ๋๋ค.- ๋์ผํ ์ ์ถ ID์ ๋ํ ์ค๋ณต API ํธ์ถ์ ์ค์ด๊ธฐ ์ํด 5๋ถ ๋ง๋ฃ ์๊ฐ์ ๊ฐ๋จํ ์ธ๋ฉ๋ชจ๋ฆฌ ์บ์(
submissionCache
)๋ฅผ ํฌํจํฉ๋๋ค. - Markdown ํธํ์ฑ์ ์ํด
language
๊ฐ ์๋ฌธ์์ธ์ง ํ์ธํ๊ณ , ์๋ ๊ฒฝ์ฐ โplaintextโ๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ค์ ํฉ๋๋ค. SubmissionSummary
๊ฐuserCode
๋ฅผ ํฌํจํ๋Promise<SubmissionSummary>
๋ฅผ ๋ฐํํฉ๋๋ค.
handleApiResponse
: ์ผ๋ฐ์ ์ธ ์๋ต ์ฒ๋ฆฌ ๋ฐ ์ค๋ฅ ํ์ฑ์ ์ํ ์ ํธ๋ฆฌํฐ ํจ์์ ๋๋ค.
7.2. ์ ์ถ ํ์ด์ง (capstone-2025-04/frontend/src/app/submissions/page.tsx
)
- ์ํ ๊ด๋ฆฌ: ์ ์ถ ๋ชฉ๋ก, ๋ก๋ฉ ์ํ, ์ค๋ฅ ๋ฉ์์ง, ํํฐ(
filterProblemTitle
,filterAuthor
), ์ ๋ ฌ ์์ ๋ฐ ํ์ด์ง๋ค์ด์ (lastEvaluatedKey
,hasMore
)์ ์ํดuseState
๋ฅผ ์ฌ์ฉํฉ๋๋ค. - ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ:
useEffect
์useCallback
์ผ๋ก ๋ฉ๋ชจ์ด์ง๋fetchSubmissions
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์์ ์ํํฉ๋๋ค:- ์ด๊ธฐ ๋ฐ์ดํฐ ๋ก๋.
- ํํฐ ๋๋ ์ ๋ ฌ ์์๊ฐ ๋ณ๊ฒฝ๋ ๋ ๋ฐ์ดํฐ ๋ค์ ๊ฐ์ ธ์ค๊ธฐ.
handleLoadMore
ํจ์๋ ์ ์ฅ๋lastEvaluatedKey
๋ฅผ ์ฌ์ฉํ์ฌ ํ์ ํ์ด์ง๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
- ํํฐ๋ง UI: โ๋ฌธ์ ์ ๋ชฉ (ํ๊ธ)โ ๋ฐ โ์์ฑ์โ์ ๋ํ ์ ๋ ฅ ํ๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ์ ๋ ฌ UI: ์ ๋ ฌ ์์(ASC/DESC)๋ฅผ ์ ํํ๋ ๋๋กญ๋ค์ด์ ๋๋ค.
- ํ์:
- ์ ์ถ๋ฌผ์ ํ ์ด๋ธ์ ๋ ๋๋งํฉ๋๋ค.
- ์ ์ถ ID๋ฅผ ๊ฒฐ๊ณผ ํ์ด์ง(
/coding-test/result?id={problemId}&submissionId={submissionId}
)๋ก ์ฐ๊ฒฐํฉ๋๋ค. - ๋ฌธ์ ์ ๋ชฉ์ ๋ฌธ์ ํ์ด ํ์ด์ง(
/coding-test/solve?id={problemId}
)๋ก ์ฐ๊ฒฐํฉ๋๋ค. date-fns
๋ฅผ ์ฌ์ฉํ์ฌsubmissionTime
์ ํฌ๋งทํฉ๋๋ค.- ์ ์ ํ ์คํ์ผ๊ณผ ํ๊ธ ํ ์คํธ๋ก ์ํ๋ฅผ ํ์ํฉ๋๋ค.
- ์ค๋ฅ ์ฒ๋ฆฌ: ๊ฐ์ ธ์ค๊ธฐ๊ฐ ์คํจํ๋ฉด
toast
์๋ฆผ ๋ฐ ์ธ๋ผ์ธ ๋ฉ์์ง๋ฅผ ์ฌ์ฉํ์ฌ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. - ๋ก๋ฉ ํ์๊ธฐ: ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ ์ค์ ๋ก๋ฉ ์คํผ๋๋ฅผ ํ์ํฉ๋๋ค.
- Suspense: ์ด๊ธฐ ํ์ด์ง ๋ก๋ ๋๋ ๊ฒฝ๋ก ์ ํ ์ค ๋ ๋์ ๋ก๋ฉ UX๋ฅผ ์ํด
SubmissionsContent
๋ฅผ ๋ํํฉ๋๋ค.
8. ์ธํ๋ผ (Terraform)
์์น: capstone-2025-04/infrastructure/submissions-api/
8.1. ์ฃผ์ ๋ฆฌ์์ค ์ ์:
aws_api_gateway_rest_api.submissions_api
: ์ฃผ API Gateway ์ธ์คํด์ค์ ๋๋ค.aws_api_gateway_resource.submissions_resource
:/submissions
๊ฒฝ๋ก์ ๋๋ค.aws_api_gateway_method.submissions_get
:/submissions
์ ๋ํGET
๋ฉ์๋์ ๋๋ค.request_parameters
: API Gateway์์ ์ธ์ํ๋ ์์ ์ฟผ๋ฆฌ ๋ฌธ์์ด ํ๋ผ๋ฏธํฐ๋ฅผ ์ ์ํฉ๋๋ค.- ์ฐธ๊ณ : ํ์ฌ
apigateway.tf
ํ์ผ์request_parameters
์๋submissionId
,author
,problemTitleTranslated
๊ฐ ๋๋ฝ๋์ด ์์ต๋๋ค. Lambda๋ ์ด๋ฅผ ์ฒ๋ฆฌํ์ง๋ง, API Gateway ๋ฉ์๋ ์ ์์ ์ถ๊ฐํ๋ฉด ๋ฌธ์ํ ๋ฐ Gateway ์์ค์์์ ์์ฒญ ์ ํจ์ฑ ๊ฒ์ฌ์ ์ ์ฉํ ์ ์์ต๋๋ค.
- ์ฐธ๊ณ : ํ์ฌ
aws_api_gateway_integration.submissions_get_lambda_integration
:GET
๋ฉ์๋๋ฅผget_submission
Lambda์ ํตํฉํฉ๋๋ค.aws_api_gateway_method.submissions_options
&aws_api_gateway_integration.submissions_options_mock_integration
: CORSOPTIONS
์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค.aws_api_gateway_deployment.submissions_api_deployment
&aws_api_gateway_stage.submissions_api_stage
: API๋ฅผ ๋ฐฐํฌํ๊ณ ์คํ ์ด์งํฉ๋๋ค. ์คํ ์ด์ง์๋ ์ ๊ทผ ๋ก๊น ๊ตฌ์ฑ์ด ํฌํจ๋ฉ๋๋ค.aws_cloudwatch_log_group.submissions_api_gateway_logs
: API Gateway ์ ๊ทผ ๋ก๊ทธ๋ฅผ ์ํ ๋ก๊ทธ ๊ทธ๋ฃน์ ๋๋ค.aws_iam_role.get_submission_lambda_role
:get_submission
Lambda๋ฅผ ์ํ IAM ์ญํ ์ ๋๋ค.aws_iam_policy.get_submission_dynamodb_policy
: Lambda๊ฐ Submissions DynamoDB ํ ์ด๋ธ(GSI ํฌํจ)์์Query
๋ฐGetItem
์ ์ํํ ์ ์๋๋ก ํ์ฉํ๋ IAM ์ ์ฑ ์ ๋๋ค.aws_iam_role.api_gateway_cloudwatch_role_submissions
: API Gateway๊ฐ CloudWatch๋ก ๋ก๊ทธ๋ฅผ ํธ์ํ๊ธฐ ์ํ IAM ์ญํ ์ ๋๋ค.aws_lambda_function.get_submission
: Lambda ํจ์ ์ ์์ ๋๋ค.../../backend/lambdas/submissions-api/getSubmission.mjs
์์ ์ฝ๋๋ฅผ ํจํค์งํฉ๋๋ค.- ํ๊ฒฝ ๋ณ์
SUBMISSIONS_TABLE_NAME
(์๊ฒฉ ์ํ์์ ๊ฐ์ ธ์ด) ๋ฐAWS_NODEJS_CONNECTION_REUSE_ENABLED
๋ฅผ ์ค์ ํฉ๋๋ค.
aws_lambda_permission.apigw_invoke_get_submission
: API Gateway๊ฐ Lambda๋ฅผ ํธ์ถํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค.data.terraform_remote_state.code_execution_service
: S3์ ์ ์ฅ๋code-execution-service
Terraform ์ํ์์ ์ถ๋ ฅ(DynamoDB ํ ์ด๋ธ ์ด๋ฆ ๋ฐ ARN)์ ๊ฐ์ ธ์ต๋๋ค.
8.2. ๋ฐฑ์๋ ๊ตฌ์ฑ (backend.tf
):
- Terraform ์ํ๋ S3 ๋ฒํท(
alpaco-tfstate-bucket-kmu
)์ ์ ์ฅ๋๋ฉฐ ์ํ ์ ๊ธ์ ์ํด DynamoDB(alpaco-tfstate-lock-table
)๋ฅผ ์ฌ์ฉํฉ๋๋ค.
8.3. ๋ณ์ (variables.tf
):
aws_region
,project_name
,environment
,common_tags
์ ๊ฐ์ ๊ณตํต ๋ณ์๋ฅผ ์ ์ํฉ๋๋ค.- Lambda ๊ด๋ จ ๊ตฌ์ฑ:
lambda_runtime
,lambda_code_base_path
,get_submission_handler
,lambda_memory_size
,lambda_timeout
. code-execution-service
์ ๋ํ ์๊ฒฉ ์ํ ๊ตฌ์ฑ์ ๋๋ค.
8.4. ์ถ๋ ฅ (outputs.tf
):
get_submission_lambda_name
: ๋ฐฐํฌ๋ Lambda ํจ์์ ์ด๋ฆ์ ๋๋ค.submissions_api_invoke_url
: API Gateway ์คํ ์ด์ง๋ฅผ ํธ์ถํ๊ธฐ ์ํ ๊ธฐ๋ณธ URL์ ๋๋ค.
9. ๋ฐฐํฌ ์ ์ ์กฐ๊ฑด
- ํ์ํ ๊ถํ์ ๊ฐ์ง AWS ๊ณ์ ๋ฐ ๊ตฌ์ฑ๋ AWS CLI ์๊ฒฉ ์ฆ๋ช .
- Terraform CLI (๋ฒ์ ~> 5.0) ์ค์น.
- Node.js ๋ฐ npm/yarn (๋ฏธ๋ฆฌ ๋น๋๋ zip์ผ๋ก
archive_file
์ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ Lambda ํจํค์ง ๋ฐ ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ฉ). code-execution-service
๋ชจ๋์ด ์ฑ๊ณต์ ์ผ๋ก ๋ฐฐํฌ๋์ด์ผ ํฉ๋๋ค. ์ด ๋ชจ๋์ DynamoDB ํ ์ด๋ธ ์ธ๋ถ ์ ๋ณด์ ๋ํด ํด๋น ๋ชจ๋์ S3 ์๊ฒฉ ์ํ์ ์์กดํ๊ธฐ ๋๋ฌธ์ ๋๋ค. Terraform ์ํ๋ฅผ ์ํ S3 ๋ฒํท(alpaco-tfstate-bucket-kmu
)๊ณผ DynamoDB ํ ์ด๋ธ(alpaco-tfstate-lock-table
)์ด ์กด์ฌํด์ผ ํฉ๋๋ค.
10. ์ค์ ๋ฐ ๋ฐฐํฌ
- ๋ฆฌํฌ์งํ ๋ฆฌ ๋ณต์ :
git clone <your-repository-url> cd capstone-2025-04/infrastructure/submissions-api
-
Lambda ์ฝ๋ ์กด์ฌ ํ์ธ: Lambda ํจ์ ์ฝ๋
getSubmission.mjs
๊ฐvar.lambda_code_base_path
(๊ธฐ๋ณธ๊ฐ:../../backend/lambdas/submissions-api/getSubmission.mjs
)๋ก ์ง์ ๋ ๊ฒฝ๋ก์ ์๋์ง ํ์ธํฉ๋๋ค. - ๋ณ์ ๊ตฌ์ฑ (ํ์ํ ๊ฒฝ์ฐ):
variables.tf
๋ฅผ ๊ฒํ ํ๊ณ , ๊ธฐ๋ณธ๊ฐ์ด ์ ํฉํ์ง ์์ ๊ฒฝ์ฐterraform.tfvars
ํ์ผ์ ์์ฑํ๊ฑฐ๋ ๋ช ๋ น์ค์ ํตํด ๋ณ์๋ฅผ ์ฌ์ ์ํฉ๋๋ค. ํ์ธํ ์ฃผ์ ๋ณ์:aws_region
project_name
environment
code_execution_service_tfstate_bucket
code_execution_service_tfstate_key
(์ด๊ฒ์ดcode-execution-service
์ ์ฌ๋ฐ๋ฅธ ์ํ ํ์ผ์ ๊ฐ๋ฆฌํค๋์ง ํ์ธ)
- Terraform ์ด๊ธฐํ:
terraform init
- ๋ฐฐํฌ ๊ณํ:
terraform plan
๊ณํ์ ๊ฒํ ํ์ฌ ์์๋๋ ๋ฆฌ์์ค๊ฐ ์์ฑ/์์ ๋๋์ง ํ์ธํฉ๋๋ค.
- ๊ตฌ์ฑ ์ ์ฉ:
terraform apply
๋ฉ์์ง๊ฐ ํ์๋๋ฉด
yes
๋ฅผ ์ ๋ ฅํ์ฌ ํ์ธํฉ๋๋ค. -
API ํธ์ถ URL ๊ธฐ๋ก: ์ฑ๊ณต์ ์ผ๋ก ๋ฐฐํฌ๋๋ฉด Terraform์
submissions_api_invoke_url
์ ์ถ๋ ฅํฉ๋๋ค. ์ด๊ฒ์ด API์ ๊ธฐ๋ณธ URL์ ๋๋ค. ์์:https://abcdef123.execute-api.ap-northeast-2.amazonaws.com/production
- ํ๋ก ํธ์๋ ๊ตฌ์ฑ ์
๋ฐ์ดํธ: ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์
(์: Next.js์ ๊ฒฝ์ฐ
.env.local
ํ์ผ)์์NEXT_PUBLIC_SUBMISSIONS_API_BASE_URL
ํ๊ฒฝ ๋ณ์๋ฅผ ์ด์ ๋จ๊ณ์์ ์ป์submissions_api_invoke_url
๋ก ์ค์ ํฉ๋๋ค.NEXT_PUBLIC_SUBMISSIONS_API_BASE_URL=https://abcdef123.execute-api.ap-northeast-2.amazonaws.com/production
ํ๊ฒฝ ๋ณ์๊ฐ ์ ์ฉ๋๋๋ก ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ ๋น๋/์์ํฉ๋๋ค.
11. ํฅํ ๊ฐ์ ์ฌํญ / ๊ณ ๋ ค ์ฌํญ
- ์ธ์ฆ: API๊ฐ ๊ณต๊ฐ๋์ด์๋ ์ ๋๋ ๊ฒฝ์ฐ ๊ฐ๋ ฅํ ์ธ์ฆ(์: AWS IAM, Amazon Cognito)์ ๊ตฌํํฉ๋๋ค.
- ์ ๋ ฅ ์ ํจ์ฑ ๊ฒ์ฌ: API Gateway ์์ค ๋๋ Lambda ๋ด์ ๋ณด๋ค ํฌ๊ด์ ์ธ ์ ๋ ฅ ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- ์ค๋ฅ ์ธ๋ถํ: API์์ ๋ณด๋ค ๊ตฌ์ฒด์ ์ธ ์ค๋ฅ ์ฝ๋์ ๋ฉ์์ง๋ฅผ ์ ๊ณตํฉ๋๋ค.
- ๊ณ ๊ธ ๊ฒ์: ๋ณด๋ค ๋ณต์กํ ๊ฒ์ ๊ธฐ๋ฅ(์: ๋ฌธ์ ์ ๋ชฉ ๋๋ ์ฝ๋์ ๋ํ ์ ์ฒด ํ ์คํธ ๊ฒ์, ๋ ์ง ๋ฒ์ ํํฐ๋ง)์ ๊ตฌํํฉ๋๋ค.
- ์บ์ฑ: ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒฝ์ฐ ์์ฃผ ์ ๊ทผ๋๊ณ ๊ฐ์ธํ๋์ง ์์ ๋ฐ์ดํฐ์ ๋ํด API Gateway ์์ค ์บ์ฑ์ ๊ณ ๋ คํฉ๋๋ค.
- Dead Letter Queue (DLQ): ์ฒ๋ฆฌ ์คํจ๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํด Lambda ํจ์์ DLQ๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
- ๋ฉฑ๋ฑ์ฑ(Idempotency): POST/PUT/DELETE ์์ ์ด ์ถ๊ฐ๋๋ ๊ฒฝ์ฐ ๋ฉฑ๋ฑ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
- ํ ์คํธ: Lambda ํจ์์ ๋ํ ๋จ์ ํ ์คํธ ๋ฐ API์ ๋ํ ํตํฉ ํ ์คํธ๋ฅผ ์ถ๊ฐํฉ๋๋ค.
- API Gateway ์์ฒญ ํ๋ผ๋ฏธํฐ:
apigateway.tf
์aws_api_gateway_method.submissions_get
์ ์ ์๋request_parameters
๋ฅผ Lambda์์ ์ง์ํ๋ ๋ชจ๋ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ(submissionId
,author
,problemTitleTranslated
๋ฑ)์ ์ผ์น์ํต๋๋ค.
12. ๋ฌธ์ ํด๊ฒฐ
- API Gateway 5xx ์ค๋ฅ (Internal Server Error ๋ฑ):
- API Gateway์ ๋ํ CloudWatch Logs (
/aws/api-gateway/{api_name}/{stage_name}
)๋ฅผ ํ์ธํฉ๋๋ค. get_submission
Lambda ํจ์์ ๋ํ CloudWatch Logs (/aws/lambda/{project_name}-getSubmission-{environment}
)๋ฅผ ํ์ธํฉ๋๋ค. ํธ์ถ ์ค๋ฅ, ๊ถํ ๋ฌธ์ (์: DynamoDB ์ ๊ทผ ๊ฑฐ๋ถ) ๋๋ ์ฝ๋ ์ค๋ฅ๋ฅผ ์ฐพ์ต๋๋ค.
- API Gateway์ ๋ํ CloudWatch Logs (
- ๋ธ๋ผ์ฐ์ ์ CORS ์ค๋ฅ:
- API Gateway์์
OPTIONS
๋ฉ์๋๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋์๋์ง ํ์ธํฉ๋๋ค. Access-Control-Allow-Origin
ํค๋๊ฐ ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค๋ฆฌ์ง๊ณผ ์ผ์นํ๋์ง (๋๋ ๊ฐ๋ฐ์ฉ์ผ๋ก*
์ธ์ง) ํ์ธํฉ๋๋ค.- ํน์ CORS ์ค๋ฅ ๋ฉ์์ง์ ๋ํด ๋ธ๋ผ์ฐ์ ์ฝ์์ ํ์ธํฉ๋๋ค.
- API Gateway์์
- Lambda ์๊ฐ ์ด๊ณผ:
- ์์ฒญ ์๊ฐ์ด ์ด๊ณผ๋๋ ๊ฒฝ์ฐ CloudWatch์์ Lambda ์คํ ์๊ฐ์ ํ์ธํฉ๋๋ค. ํ์ํ ๊ฒฝ์ฐ
var.lambda_timeout
์ ๋๋ฆฝ๋๋ค. - DynamoDB ์ฟผ๋ฆฌ๋ฅผ ์ต์ ํํฉ๋๋ค (GSI๊ฐ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉ๋๋์ง ํ์ธํ๊ณ ์ค์บ๋ ํญ๋ชฉ์ ์ค์).
- ์์ฒญ ์๊ฐ์ด ์ด๊ณผ๋๋ ๊ฒฝ์ฐ CloudWatch์์ Lambda ์คํ ์๊ฐ์ ํ์ธํฉ๋๋ค. ํ์ํ ๊ฒฝ์ฐ
- Terraform ์ ์ฉ ์คํจ:
- Terraform์ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ์ฃผ์ ๊น๊ฒ ์ฝ์ต๋๋ค. ์ข ์ข ๊ถํ ๋ฌธ์ , ์๋ชป ๊ตฌ์ฑ๋ ๋ฆฌ์์ค ๋๋ ์ข ์์ฑ ๋ฌธ์ ๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
code-execution-service
์ ๋ํ ์๊ฒฉ ์ํ์ ์ ๊ทผํ ์ ์๊ณ ์์ ์ถ๋ ฅ์ ํฌํจํ๋์ง ํ์ธํฉ๋๋ค.