ALPACO ํ๋ก ํธ์๋ ์ ํ๋ฆฌ์ผ์ด์
ALPACO (AI Learning PAth COmpanion)๋ ํ๋ก๊ทธ๋๋ฐ ๋ฐ ๊ด๋ จ ๋ถ์ผ์์ ์ฌ์ฉ์์ ํ์ต ์ฌ์ ์ ์ง์ํ๋๋ก ์ค๊ณ๋ ํ๋์ ์ธ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ์ด ํ๋ก ํธ์๋๋ Next.js, TypeScript, Tailwind CSS๋ก ๊ตฌ์ถ๋์ด ๋ฐ์ํ ๋ฐ ๋ํํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค. ์ธ์ฆ์ ์ํ AWS Cognito, ๋ง์ดํฌ๋ก์๋น์ค ์ ๊ทผ์ ์ํ API Gateway, ํธ์คํ ๋ฐ ์ฝํ ์ธ ์ ์ก์ ์ํ S3/CloudFront ๋ฑ ๋ค์ํ ๋ฐฑ์๋ ์๋น์ค์ ํตํฉ๋ฉ๋๋ค.
๋ชฉ์ฐจ
- ์ฃผ์ ๊ธฐ๋ฅ
- ๊ธฐ์ ์คํ
- ์ฌ์ ์ค๋น ์ฌํญ
- ์์ํ๊ธฐ
- ํ๋ก์ ํธ ๊ตฌ์กฐ
- ํ๋ก๋์ ๋น๋
- ๋ฐฐํฌ
- ๋ฆฐํ ๋ฐ ํฌ๋งทํ
- ์ฃผ์ Next.js ์ค์ (
next.config.ts
) - ์คํ์ผ๋ง (Tailwind CSS)
- TypeScript ์ค์
- ๋ ์์๋ณด๊ธฐ
์ฃผ์ ๊ธฐ๋ฅ
- ์ฌ์ฉ์ ์ธ์ฆ: AWS Cognito๋ฅผ ํตํ ์์ ํ ํ์๊ฐ์ , ๋ก๊ทธ์ธ ๋ฐ ์ฌ์ฉ์ ๊ด๋ฆฌ.
- ๋ํํ ๋ฌธ์ ํด๊ฒฐ: ์ฝ๋ฉ ๋ฌธ์ ์ธํฐํ์ด์ค (Monaco ๊ธฐ๋ฐ ์ฝ๋ ํธ์ง๊ธฐ ์ฌ์ฉ ๊ฐ๋ฅ์ฑ).
- Markdown ์ฝํ
์ธ ํ์:
react-markdown
์ ์ฌ์ฉํ ๋ฆฌ์น ํ ์คํธ ์ฝํ ์ธ ๋ ๋๋ง. - ๋ฐ์ํ ๋์์ธ: Tailwind CSS๋ฅผ ์ฌ์ฉํ ๋ค์ํ ํ๋ฉด ํฌ๊ธฐ์ ์ ์ํ๋ UI.
- ๋์ UI ์์: Framer Motion์ ์ฌ์ฉํ ์ ๋๋ฉ์ด์ ๋ฐ Sonner๋ฅผ ์ฌ์ฉํ ์๋ฆผ.
- ํฌ๊ธฐ ์กฐ์ ๊ฐ๋ฅ ํจ๋: ์ ์ฐํ ๋ ์ด์์ ์กฐ์ ์ ์ํจ.
- ๊ตฌ๋ฌธ ๊ฐ์กฐ: ์ฝ๋ ์ค๋ํซ์ ๋ช ํํ๊ฒ ํ์.
- ๋ฐฑ์๋ ์๋น์ค ์ฐ๋: ๋ฌธ์ ์์ฑ, ์ฝ๋ ์ฑ์ , ์ปค๋ฎค๋ํฐ ๊ธฐ๋ฅ, ์ฑ๋ด ์ํธ์์ฉ์ ์ํ ๋ค์ํ API ์ฐ๊ฒฐ.
๊ธฐ์ ์คํ
- ํ๋ ์์ํฌ: Next.js (v15.x, ๊ฐ๋ฐ ์ Turbopack ์ฌ์ฉ)
- ์ธ์ด: TypeScript
- UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ: React (v19)
- ์คํ์ผ๋ง: Tailwind CSS (v3.3) with PostCSS and Autoprefixer
- ์ธ์ฆ: AWS Amplify (AWS Cognito ์ฐ๋)
- ์ํ ๊ด๋ฆฌ: React Context / Hooks (Amplify ๋ฐ ์ผ๋ฐ์ ์ธ React ํจํด์์ ์์)
- ์ฝ๋ ํธ์ง๊ธฐ (์ปดํฌ๋ํธ): @monaco-editor/react
- Markdown ๋ ๋๋ง:
react-markdown
,remark-gfm
,rehype-raw
- UI ์ปดํฌ๋ํธ & ์ ํธ๋ฆฌํฐ:
@heroicons/react
(์์ด์ฝ)react-resizable-panels
(๋ ์ด์์)react-syntax-highlighter
(์ฝ๋ ํ์)sonner
(ํ ์คํธ ์๋ฆผ)framer-motion
(์ ๋๋ฉ์ด์ )date-fns
(๋ ์ง ์ ํธ๋ฆฌํฐ)
- ๋ฆฐํ
: ESLint (
eslint-config-next
์ฌ์ฉ) - ๋ฐฐํฌ: AWS S3 (์ ์ ์น์ฌ์ดํธ ํธ์คํ ) + AWS CloudFront (CDN)
์ฌ์ ์ค๋น ์ฌํญ
- Node.js (LTS ๋ฒ์ ๊ถ์ฅ, ์: v18.x, v20.x)
- ํจํค์ง ๋งค๋์ :
- ํ๋ก์ ํธ์ AWS ๊ณ์ ์ ๊ทผ ๊ถํ (๋ฐฑ์๋ ์๋น์ค์ ํ๊ฒฝ ๋ณ์ ๊ฐ ํ์).
์์ํ๊ธฐ
์ ์ฅ์ ๋ณต์
git clone <repository-url>
cd capstone-2025-04/frontend
์์กด์ฑ ์ค์น
์ ํธํ๋ ํจํค์ง ๋งค๋์ ๋ฅผ ์ ํํ์ฌ ์ฌ์ฉํ์ธ์:
# npm ์ฌ์ฉ ์
npm install
# yarn ์ฌ์ฉ ์
yarn install
# pnpm ์ฌ์ฉ ์
pnpm install
# bun ์ฌ์ฉ ์
bun install
ํ๊ฒฝ ๋ณ์ ์ค์
์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐฑ์๋ ์๋น์ค์ ์ฐ๊ฒฐํ๋ ค๋ฉด ์ฌ๋ฌ ํ๊ฒฝ ๋ณ์๊ฐ ํ์ํฉ๋๋ค.
- ์ํ ํ๊ฒฝ ํ์ผ์ ๋ณต์ฌํฉ๋๋ค:
cp .env.local.sample .env.local
-
.env.local
ํ์ผ์ ํธ์งํ๊ณ ๊ฐ์ ์ฑ์๋๋ค. ์ด ๊ฐ๋ค์ ์ผ๋ฐ์ ์ผ๋ก ๋ฐฑ์๋ ์ธํ๋ผ ๋ฐฐํฌ(์:infrastructure/app
Terraform ๋ชจ๋์ Cognito, API Gateway, CloudFront ์ถ๋ ฅ) ๊ฒฐ๊ณผ๋ก๋ถํฐ ์ป์ต๋๋ค.# .env.local # ๋ธ๋ผ์ฐ์ ์์ ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก NEXT_PUBLIC_ ์ ๋์ฌ๋ก ์์ํด์ผ ํฉ๋๋ค. # AWS ์ค์ NEXT_PUBLIC_AWS_REGION=ap-northeast-2 # ์ฌ์ฉํ๋ AWS ๋ฆฌ์ # AWS Cognito (`infrastructure/auth` Terraform ์ถ๋ ฅ๊ฐ) NEXT_PUBLIC_COGNITO_USER_POOL_ID=YOUR_USER_POOL_ID NEXT_PUBLIC_COGNITO_CLIENT_ID=YOUR_APP_CLIENT_ID NEXT_PUBLIC_COGNITO_DOMAIN=YOUR_COGNITO_AUTH_DOMAIN # ์: alpaco-auth-prod.auth.ap-northeast-2.amazoncognito.com # ์ ํ๋ฆฌ์ผ์ด์ ๊ธฐ๋ณธ URL (`infrastructure/app` Terraform ์ถ๋ ฅ๊ฐ: cloudfront_distribution_domain_name ๋๋ ์ฌ์ฉ์ ์ ์ ๋๋ฉ์ธ) NEXT_PUBLIC_APP_BASE_URL=YOUR_CLOUDFRONT_OR_CUSTOM_DOMAIN_NAME # ์: https://d2rgzjzynamwq2.cloudfront.net ๋๋ https://www.alpaco.us # API Gateway ํธ์ถ URL (๊ฐ ๋ฐฑ์๋ Terraform ์ถ๋ ฅ๊ฐ) NEXT_PUBLIC_COMMUNITY_API_BASE_URL=YOUR_COMMUNITY_API_GATEWAY_INVOKE_URL NEXT_PUBLIC_PROBLEM_GENERATION_API_BASE_URL=YOUR_PROBLEM_GEN_API_GATEWAY_INVOKE_URL NEXT_PUBLIC_PROBLEM_API_BASE_URL=YOUR_PROBLEM_API_GATEWAY_INVOKE_URL NEXT_PUBLIC_CODE_GRADER_BASE_URL=YOUR_CODE_GRADER_API_GATEWAY_INVOKE_URL NEXT_PUBLIC_SUBMISSIONS_API_BASE_URL=YOUR_SUBMISSIONS_API_GATEWAY_INVOKE_URL # ์ฑ๋ด API ์๋ํฌ์ธํธ (API Gateway ๋๋ WebSocket API๋ฅผ ์ํ ํน์ CloudFront ๋ฐฐํฌ์ผ ์ ์์) NEXT_PUBLIC_CHATBOT_API_ENDPOINT=YOUR_CHATBOT_API_ENDPOINT
์ฐธ๊ณ :
.env.local
ํ์ผ์.gitignore
์ ํฌํจ๋์ด ์์ผ๋ฉฐ, ์ ์ฅ์์ ์ ๋๋ก ์ปค๋ฐํด์๋ ์ ๋ฉ๋๋ค.
๊ฐ๋ฐ ์๋ฒ ์คํ
์์กด์ฑ ์ค์น ๋ฐ .env.local
์ค์ ํ:
npm run dev
# ๋๋
yarn dev
# ๋๋
pnpm dev
# ๋๋
bun dev
์ ํ๋ฆฌ์ผ์ด์
์ ์ผ๋ฐ์ ์ผ๋ก http://localhost:3000์์ ์ฌ์ฉํ ์ ์์ต๋๋ค. Next.js ๊ฐ๋ฐ ์๋ฒ๋ package.json
์ ๋ช
์๋ ๋๋ก ๋ ๋น ๋ฅธ ๋น๋๋ฅผ ์ํด Turbopack์ ์ฌ์ฉํฉ๋๋ค.
ํ๋ก์ ํธ ๊ตฌ์กฐ
์ผ๋ฐ์ ์ธ Next.js ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค:
frontend/
โโโ public/ # ์ ์ ์์
(ํ๋น์ฝ, ์ด๋ฏธ์ง ๋ฑ)
โโโ src/
โ โโโ app/ # Next.js App Router (๋ ์ด์์, ํ์ด์ง, ๋ผ์ฐํธ ํธ๋ค๋ฌ)
โ โโโ components/ # ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ React ์ปดํฌ๋ํธ
โ โโโ api/ # API ํด๋ผ์ด์ธํธ ํจ์ (์: API Gateway์ ์ํธ์์ฉ)
โ โโโ hooks/ # ์ฌ์ฉ์ ์ ์ React Hooks
โ โโโ lib/ # ์ ํธ๋ฆฌํฐ ํจ์, ์ค์ (์: Amplify ์ค์ )
โ โโโ styles/ # ์ ์ญ ์คํ์ผ, Tailwind ๊ธฐ๋ณธ ์คํ์ผ
โ โโโ ... # ๊ธฐํ ํน์ ๋๋ ํ ๋ฆฌ (์ปจํ
์คํธ, ํ์
๋ฑ)
โโโ .env.local # ๋ก์ปฌ ํ๊ฒฝ ๋ณ์ (Gitignored)
โโโ .env.local.sample # ์ํ ํ๊ฒฝ ๋ณ์
โโโ next.config.ts # Next.js ์ค์
โโโ tailwind.config.js # Tailwind CSS ์ค์
โโโ postcss.config.js # PostCSS ์ค์
โโโ tsconfig.json # TypeScript ์ค์
โโโ eslint.config.mjs # ESLint ์ค์ (์๋ก์ด flat config ํ์)
โโโ package.json # ํ๋ก์ ํธ ์์กด์ฑ ๋ฐ ์คํฌ๋ฆฝํธ
โโโ README.md # ์ด ํ์ผ
ํ๋ก๋์ ๋น๋
ํ๋ก๋์ ์ ์ํด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น๋(์ ์ ์ต์คํฌํธ)ํ๋ ค๋ฉด:
npm run build
์ด ๋ช ๋ น์ด๋ ๋ค์์ ์ํํฉ๋๋ค:
- ์ฝ๋ ๋ฆฐํธ (Next.js ๋น๋ ํ๋ก์ธ์ค์ ๋ฐ๋ผ).
- TypeScript ๋ฐ React ์ฝ๋ ์ปดํ์ผ.
out/
๋๋ ํ ๋ฆฌ์ ์ ์ HTML, CSS, JavaScript ํ์ผ ์์ฑ. ์ด๋next.config.ts
์output: "export"
์ค์ ๋๋ฌธ์ ๋๋ค.
๋ฐฐํฌ
๋ฐฐํฌ ์ ๋ต
ํ๋ก ํธ์๋๋ AWS S3์ ์ ์ ์ฌ์ดํธ๋ก ๋ฐฐํฌ๋๋ฉฐ, AWS CloudFront๋ฅผ ํตํด ์ ์ธ๊ณ์ ์ผ๋ก ์ ๊ณต๋ฉ๋๋ค. ์ด ์ ๊ทผ ๋ฐฉ์์ ๋ค์์ ํ์ฉํฉ๋๋ค:
- ์ ์ ์ต์คํฌํธ: Next.js์
output: "export"
๊ธฐ๋ฅ์ ์ฌ์ดํธ์ ์์ ํ ์ ์ ๋ฒ์ ์ ์์ฑํฉ๋๋ค. - S3: ์ ๋ ดํ๊ณ ์์ ์ ์ธ ์ ์ ํ์ผ ํธ์คํ .
- CloudFront: ๊ธ๋ก๋ฒ ์ฝํ ์ธ ์ ์ก(CDN), HTTPS/SSL ์ข ๋ฃ(ACM ์ธ์ฆ์ ์ฌ์ฉ), ์ฌ์ฉ์ ์ ์ ๋๋ฉ์ธ ์ง์.
- Origin Access Control (OAC): S3 ๋ฒํท ์ฝํ ์ธ ๊ฐ CloudFront๋ฅผ ํตํด์๋ง ์ ๊ทผ ๊ฐ๋ฅํ๋๋ก ๋ณด์ฅ.
์ธํ๋ผ (Terraform)
AWS ์ธํ๋ผ(S3 ๋ฒํท, CloudFront ๋ฐฐํฌ, ACM ์ธ์ฆ์, Route 53 ๋ ์ฝ๋, GitHub Actions์ฉ IAM ์ญํ )๋ Terraform์ ์ํด ํ๋ก๋น์ ๋๋๊ณ ๊ด๋ฆฌ๋ฉ๋๋ค. ๊ด๋ จ Terraform ์ค์ ์ capstone-2025-04/infrastructure/app/
๋๋ ํ ๋ฆฌ์ ์์ต๋๋ค. ์ธํ๋ผ ์ค์ ์ ๋ํ ์์ธํ ๋ด์ฉ์ ํด๋น ๋๋ ํ ๋ฆฌ์ README.md
๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
Terraform์ ์ํด ์์ฑ๋๋ ์ฃผ์ ์ธํ๋ผ ๊ตฌ์ฑ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
aws_s3_bucket
:out/
๋๋ ํ ๋ฆฌ์ ์ ์ ๋น๋ ์ถ๋ ฅ์ ์ ์ฅํฉ๋๋ค.aws_cloudfront_distribution
: S3์์ ์ฝํ ์ธ ๋ฅผ ์ ๊ณตํ๊ณ SSL ๋ฐ ์ฌ์ฉ์ ์ ์ ๋๋ฉ์ธ์ ์ฒ๋ฆฌํฉ๋๋ค.aws_acm_certificate
: ์ฌ์ฉ์ ์ ์ ๋๋ฉ์ธ(alpaco.us
๋ฐwww.alpaco.us
,auth.alpaco.us
์ ๊ฐ์ ํ์ ๋๋ฉ์ธ)์ ๋ํ HTTPS์ฉ.aws_route53_record
: ์ฌ์ฉ์ ์ ์ ๋๋ฉ์ธ์ CloudFront ๋ฐฐํฌ๋ก ์ง์ ํฉ๋๋ค.aws_cloudfront_function
: ํด๋ผ์ด์ธํธ ์ธก ๋ผ์ฐํ ์ ์ํ URL ์ฌ์์ฑ์ ์ฒ๋ฆฌํฉ๋๋ค.aws_iam_role
(GitHub Actions์ฉ): GitHub Actions๊ฐ S3์ ๋ฐฐํฌํ๊ณ CloudFront๋ฅผ ๋ฌดํจํํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค.
GitHub Actions๋ฅผ ์ด์ฉํ CI/CD
๋ฐฐํฌ๋ GitHub Actions๋ฅผ ์ฌ์ฉํ์ฌ ์๋ํ๋ฉ๋๋ค. ์ํฌํ๋ก์ฐ(capstone-2025-04/.github/workflows/deploy.yml
์ ์์น)๋ ์ผ๋ฐ์ ์ผ๋ก ํน์ ํธ๋ฆฌ๊ฑฐ(์: master
๋ธ๋์น ๋๋ release/**
๋ธ๋์น๋ก ํธ์) ๋ฐ์ ์ ๋ค์ ๋จ๊ณ๋ฅผ ์ํํฉ๋๋ค:
- ์ฝ๋ ์ฒดํฌ์์ (
actions/checkout@v4
): ์ต์ ์ฝ๋๋ฅผ ๊ฐ์ ธ์ต๋๋ค. ํธ์๋ ์ฐธ์กฐ(๋ธ๋์น ๋๋ ํ๊ทธ)๋ฅผ ์ฒดํฌ์์ํฉ๋๋ค. - Node.js ์ค์ (
actions/setup-node@v4
): Node.js 20 ๋ฒ์ ์ ์ค์ ํ๊ณfrontend/package-lock.json
์ ์ฌ์ฉํ์ฌ npm ์บ์๋ฅผ ๊ตฌ์ฑํฉ๋๋ค. - (์ ํ์ ) OIDC ํ ํฐ ๋๋ฒ๊น : OIDC ํ ํฐ ๊ฒ์ ๋ฐ ํ์ด๋ก๋ ๋์ฝ๋ฉ์ ์๋ํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํฉ๋๋ค.
- AWS ์๊ฒฉ ์ฆ๋ช
๊ตฌ์ฑ (
aws-actions/configure-aws-credentials@v4
): GitHub Secrets (AWS_IAM_ROLE_ARN
,AWS_REGION
)์ ์ ์ฅ๋ ์ ๋ณด๋ฅผ ์ฌ์ฉํ์ฌ OIDC๋ฅผ ํตํด IAM ์ญํ ์ ์์ํ์ฌ AWS์ ์์ ํ๊ฒ ์ ๊ทผํฉ๋๋ค. - ์์กด์ฑ ์ค์น:
./frontend
๋๋ ํ ๋ฆฌ์์npm install
์ ์คํํฉ๋๋ค. - Next.js ์ ์ ์ฌ์ดํธ ๋น๋:
./frontend
๋๋ ํ ๋ฆฌ์์npm run build
๋ฅผ ์คํํฉ๋๋ค. ๋น๋ ํ๋ก์ธ์ค์ ํ์ํNEXT_PUBLIC_
ํ๊ฒฝ ๋ณ์๋ค์ด GitHub Secrets๋ก๋ถํฐ ์ฃผ์ ๋ฉ๋๋ค.NEXT_PUBLIC_AWS_REGION
NEXT_PUBLIC_COGNITO_USER_POOL_ID
NEXT_PUBLIC_COGNITO_CLIENT_ID
NEXT_PUBLIC_COGNITO_DOMAIN
NEXT_PUBLIC_APP_BASE_URL
:https://$
(CloudFront ๋๋ฉ์ธ ๋๋ ์ฌ์ฉ์ ์ ์ ๋๋ฉ์ธ)- ๊ฐ API ์๋น์ค์
NEXT_PUBLIC_*_API_BASE_URL
๋ฐNEXT_PUBLIC_CHATBOT_API_ENDPOINT
- S3์ ํ์ผ ๋๊ธฐํ:
aws s3 sync ./frontend/out s3://$ --delete
๋ช ๋ น์ ์ฌ์ฉํ์ฌ ๋น๋๋out/
๋๋ ํ ๋ฆฌ์ ๋ด์ฉ์ S3 ๋ฒํท์ ๋๊ธฐํํ๊ณ , ๊ธฐ์กด์ ์์ง๋ง ์ ๋น๋์๋ ์๋ ํ์ผ์ ์ญ์ ํฉ๋๋ค. - CloudFront ์บ์ ๋ฌดํจํ:
aws cloudfront create-invalidation --distribution-id $ --paths "/*"
๋ช ๋ น์ ์ฌ์ฉํ์ฌ CloudFront ์บ์๋ฅผ ๋ฌดํจํํ์ฌ ์ฌ์ฉ์๊ฐ ์ต์ ๋ฒ์ ์ ๋ฐ์ ์ ์๋๋ก ํฉ๋๋ค.
๋ฐฐํฌ์ ํ์ํ GitHub Secrets:
AWS_IAM_ROLE_ARN
: GitHub Actions๊ฐ ์ฌ์ฉํ IAM ์ญํ ์ ARN (์:arn:aws:iam::897722694537:role/alpaco-github-actions-deploy-role-production
)AWS_REGION
: AWS ๋ฆฌ์ (์:ap-northeast-2
)AWS_S3_BUCKET_NAME
: ๋์ S3 ๋ฒํท ์ด๋ฆ (์:alpaco-frontend-production-alpaco-frontend-bucket
)AWS_CLOUDFRONT_DISTRIBUTION_ID
: CloudFront ๋ฐฐํฌ ID (์:E3Q5IEHTZGF1U5
)ROUTE53_DOMAIN_NAME
: ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ธฐ๋ณธ ๋๋ฉ์ธ ์ด๋ฆ (์:www.alpaco.us
๋๋d2rgzjzynamwq2.cloudfront.net
)NEXT_PUBLIC_AWS_REGION
: ํ๋ก ํธ์๋ ๋น๋ ์ ์ฌ์ฉ๋ AWS ๋ฆฌ์ NEXT_PUBLIC_COGNITO_USER_POOL_ID
: Cognito ์ฌ์ฉ์ ํ IDNEXT_PUBLIC_COGNITO_CLIENT_ID
: Cognito ์ฑ ํด๋ผ์ด์ธํธ IDNEXT_PUBLIC_COGNITO_DOMAIN
: Cognito ์ธ์ฆ ๋๋ฉ์ธNEXT_PUBLIC_COMMUNITY_API_BASE_URL
: ์ปค๋ฎค๋ํฐ API Gateway URLNEXT_PUBLIC_CHATBOT_API_ENDPOINT
: ์ฑ๋ด API ์๋ํฌ์ธํธNEXT_PUBLIC_PROBLEM_GENERATION_API_BASE_URL
: ๋ฌธ์ ์์ฑ API Gateway URLNEXT_PUBLIC_PROBLEM_API_BASE_URL
: ๋ฌธ์ API Gateway URLNEXT_PUBLIC_CODE_GRADER_BASE_URL
: ์ฝ๋ ์ฑ์ ๊ธฐ API Gateway URLNEXT_PUBLIC_SUBMISSIONS_API_BASE_URL
: ์ ์ถ API Gateway URL
์ด ๊ฐ๋ค์ infrastructure/app
Terraform ๋ชจ๋์ ์ถ๋ ฅ์ด๊ฑฐ๋ ํด๋น ๋ฐฑ์๋ ์๋น์ค ์ค์ ์์ ํ์๋ฉ๋๋ค.
URL ์ฌ์์ฑ์ ์ํ CloudFront ํจ์
์ด ์ ํ๋ฆฌ์ผ์ด์
์ ์ ์ ์ผ๋ก ์ต์คํฌํธ๋๋ฏ๋ก, S3์์ /profile
๊ณผ ๊ฐ์ ๊ฒฝ๋ก์ ์ง์ ์ ๊ทผํ๋ฉด ํด๋น ํ์ผ์ด ์๊ธฐ ๋๋ฌธ์ 403/404 ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. S3๋ /profile/index.html
์ ๊ธฐ๋ํฉ๋๋ค. infrastructure/app
Terraform ์ค์ ์๋ CloudFront ๋ฐฐํฌ์ โ๋ทฐ์ด ์์ฒญ(Viewer Request)โ ์ด๋ฒคํธ์ ์ฐ๊ฒฐ๋ aws_cloudfront_function
(url_rewrite_function
)์ด ํฌํจ๋์ด ์์ต๋๋ค. ์ด ํจ์๋ URI๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ฌ์์ฑํฉ๋๋ค:
- URI๊ฐ
/
๋ก ๋๋๋ฉดindex.html
์ ์ถ๊ฐํฉ๋๋ค. - URI์ ํ์ผ ํ์ฅ์๊ฐ ์๋ ๊ฒฝ์ฐ(์:
/profile
),/index.html
์ ์ถ๊ฐํฉ๋๋ค.
์ด๋ฅผ ํตํด ํด๋ผ์ด์ธํธ ์ธก ๋ผ์ฐํ
์ด ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ๊ณ ํ์ด์ง ์๋ก๊ณ ์นจ ์ ์ ์ ํ index.html
ํ์ผ์ด ๋ก๋๋์ด Next.js๊ฐ ๋ผ์ฐํ
์ ์ฒ๋ฆฌํ ์ ์๋๋ก ํฉ๋๋ค. ๋ํ, CloudFront์์ ๋ฐ์ํ๋ 403 ๋ฐ 404 ์ค๋ฅ๋ 200 ์ํ ์ฝ๋์ ํจ๊ป /index.html
์ ๋ฐํํ๋๋ก ๊ตฌ์ฑ๋์ด Next.js ํด๋ผ์ด์ธํธ ์ธก ๋ผ์ฐํฐ์ ๋ผ์ฐํ
์ ์์ํฉ๋๋ค.
๋ฆฐํ ๋ฐ ํฌ๋งทํ
์ฝ๋๋ฒ ์ด์ค๋ฅผ ๋ฆฐํธํ๋ ค๋ฉด:
npm run lint
์ด ํ๋ก์ ํธ๋ React, JSX ์ ๊ทผ์ฑ, TypeScript์ ๋ํ ๊ท์น์ ํฌํจํ๋ eslint-config-next
์ค์ ์ ์ฌ์ฉํ๋ ESLint๋ฅผ ์ฌ์ฉํฉ๋๋ค. ESLint ์ค์ ์ eslint.config.mjs
์ ์์ต๋๋ค.
์ฃผ์ Next.js ์ค์ (next.config.ts
)
next.config.ts
ํ์ผ์๋ ์ ์ ์ฌ์ดํธ ์์ฑ์ ์ํ ์ค์ํ ์ค์ ์ด ํฌํจ๋์ด ์์ต๋๋ค:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "export", // ์ ์ HTML ์ต์คํฌํธ ํ์ฑํ
trailingSlash: true, // URL ๋์ ์ฌ๋์ ์ถ๊ฐ (์: /about/ ๋์ /about) (S3 ํธํ์ฑ)
reactStrictMode: true,
images: {
unoptimized: true, // Next.js ์ด๋ฏธ์ง ์ต์ ํ API ๋นํ์ฑํ (`next export`์ ํ์)
},
};
export default nextConfig;
output: "export"
: ์ด๊ฒ์ด ํต์ฌ์ ๋๋ค. Next.js์๊ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ S3์ ๊ฐ์ ์ ์ ์น ์๋ฒ์์ ํธ์คํ ํ ์ ์๋ ์ ์ HTML, CSS, JavaScript ํ์ผ ๋ชจ์์ผ๋ก ๋น๋ํ๋๋ก ์ง์ํฉ๋๋ค.trailingSlash: true
: S3๊ฐ ์น์ฌ์ดํธ ํธ์คํ ์ฉ์ผ๋ก ๊ตฌ์ฑ๋๊ฑฐ๋ CloudFront๋ฅผ ํตํด ์ ๊ทผ๋ ๋ S3 ๊ฐ์ฒด ํ์ธ์ ๋์์ด ๋ฉ๋๋ค. S3๋ ์ข ์ข ์ฌ๋์๋ก ๋๋๋ ๋๋ ํ ๋ฆฌ์ ์ ์ฌํ ๊ฒฝ๋ก์์ ๋ ์ ์๋ํฉ๋๋ค.images: { unoptimized: true }
: ๊ธฐ๋ณธ Next.js ์ด๋ฏธ์ง ์ต์ ํ API๋ Node.js ์๋ฒ๊ฐ ํ์ํฉ๋๋ค. ์ ์ ์ต์คํฌํธ์ ๊ฒฝ์ฐ ์ด๋ฏธ์ง๋ ์ ์ ์์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด์ผ ํ๋ฏ๋ก ์ต์ ํ๊ฐ ๋นํ์ฑํ๋ฉ๋๋ค. ํ์ํ ๊ฒฝ์ฐ ์ด๋ฏธ์ง ์ต์ ํ๋ ์ผ๋ฐ์ ์ผ๋ก ๋น๋ ์ ๋๋ CloudFront ๊ธฐ๋ฅ์ ํตํด ์ฒ๋ฆฌ๋ฉ๋๋ค(์ฌ๊ธฐ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ตฌ์ฑ๋์ง ์์).
์คํ์ผ๋ง (Tailwind CSS)
์ด ํ๋ก์ ํธ๋ ์ ํธ๋ฆฌํฐ ์ฐ์ ์คํ์ผ๋ง์ ์ํด Tailwind CSS๋ฅผ ์ฌ์ฉํฉ๋๋ค.
- ์ค์ :
tailwind.config.js
- PostCSS:
postcss.config.js
(Tailwind ๋ฐ Autoprefixer ํตํฉ) - ์ฌ์ฉ์ ์ ์:
tailwind.config.js
์๋ ์ฌ์ฉ์ ์ ์ ์์ ํ๋ ํธ(primary
,secondary
๋ฑ) ๋ฐ ํคํ๋ ์ ์ ๋๋ฉ์ด์ (slideDown
)์ด ํฌํจ๋ฉ๋๋ค. - ํ์ดํฌ๊ทธ๋ํผ:
@tailwindcss/typography
ํ๋ฌ๊ทธ์ธ์ ๋งํฌ๋ค์ด์ผ๋ก ์์ฑ๋ ์ฝํ ์ธ ์คํ์ผ๋ง์ ์ํด ํฌํจ๋์ด ์์ต๋๋ค.
TypeScript ์ค์
์ด ํ๋ก์ ํธ๋ TypeScript์ฉ์ผ๋ก ์ค์ ๋์ด ์์ต๋๋ค.
- ์ค์ :
tsconfig.json
- ์ฃผ์ ์ค์ :
target: "ES2017"
module: "esnext"
moduleResolution: "bundler"
(์ต์ ๋ชจ๋ ํ์ธ ๋ฐฉ์)jsx: "preserve"
strict: true
(๋ชจ๋ ์๊ฒฉํ ํ์ ๊ฒ์ฌ ์ต์ ํ์ฑํ)noEmit: true
(TypeScript ์ปดํ์ผ๋ฌ๋ JS๋ฅผ ์์ฑํ์ง ์์; Next.js๊ฐ ์ฒ๋ฆฌ)paths: { "@/*": ["./src/*"] }
(src
๋๋ ํ ๋ฆฌ์์ ์ ๋ ๊ฒฝ๋ก ์ํฌํธ ํ์ฉ, ์:import MyComponent from '@/components/MyComponent'
).
๋ ์์๋ณด๊ธฐ
์ด ํ๋ก์ ํธ์์ ์ฌ์ฉ๋ ๊ธฐ์ ์ ๋ํด ๋ ์์๋ณด๋ ค๋ฉด ๋ค์ ์๋ฃ๋ฅผ ์ฐธ์กฐํ์ญ์์ค:
- Next.js ๋ฌธ์ - Next.js ๊ธฐ๋ฅ ๋ฐ API์ ๋ํด ์์๋ณด์ธ์.
- Learn Next.js - ๋ํํ Next.js ํํ ๋ฆฌ์ผ.
- React ๋ฌธ์
- Tailwind CSS ๋ฌธ์
- TypeScript ๋ฌธ์
- AWS Amplify ๋ฌธ์
- Terraform ๋ฌธ์
- AWS CloudFront ๋ฌธ์
- GitHub Actions ๋ฌธ์