- ํ๋ก์ ํธ ์๊ฐ ๋ฐ ๊ฐ์
- ๊ธฐ์ ์คํ ๋ฐ ๊ฐ๋ฐ ํ๊ฒฝ
- User Flow
- UI ๊ตฌ์ฑ ์์
- ํต์ฌ ๊ธฐ๋ฅ ๋ฐ ์ฝ๋
- ํธ๋ฌ๋ธ์ํ
- Branch ์ ๋ต
- ๋ฌธ์
- User Test
- ํ๊ณ
- ํ๋ก์ ํธ ๊ธฐ๊ฐ : 2024.07.29 ~ 2024.08.28
- ๋ฐฐํฌ URL ๐
- Notion ๐
Foomee
ํ๋ก์ ํธ๋ ์ฌ์ฉ์๊ฐ ์์ ์ ๊ฑด๊ฐ์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋๋ก ๋๊ธฐ ์ํ ๊ฐ์ธ ๋ง์ถคํ ์๋จ ๊ธฐ๋ก, ๋ถ์ ์๋น์ค
์
๋๋ค.
์์ฝ์ฒ ์์์ฑ๋ถ API๋ฅผ ํ์ฉํ์ฌ ์ฌ์ฉ์๊ฐ ์ญ์ทจํ ์์์ ์์ ์ฑ๋ถ์ ์ ํํ๊ฒ ๋ถ์
ํ๋ฉฐ, ์๋จ๊ณผ ์ฒด์ค ๊ธฐ๋ก
์ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ํ, ์๊ฐ์ ์ฐจํธ
๋ก ๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ง๊ด์ ์ผ๋ก ํ์
ํ ์ ์์ผ๋ฉฐ, ์ฑ๋ด์ ํตํด ๊ฐ์ธ ๋ง์ถคํ ์๋จ ํผ๋๋ฐฑ
์ ์ ๊ณตํจ์ผ๋ก์จ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๊ณ ์ ํฉ๋๋ค. ์ด ํ๋ก์ ํธ๋ ์ฌ์ฉ์๋ค์ด ๋ณด๋ค ํจ๊ณผ์ ์ผ๋ก ๊ฑด๊ฐ์ ์ ์งํ๊ณ ๊ฐ์ ํ ์ ์๋๋ก ๋๋ ๊ฒ์ ๋ชฉํ๋ก ํฉ๋๋ค.
- ์์ ์ฑ๋ถ ๋ถ์
- ์์์ฑ๋ถ API๋ฅผ ํ์ฉํ์ฌ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ์๋จ์ ์์ ์ฑ๋ถ์ ๋ถ์ํฉ๋๋ค.
- ์ผ์ผ ์ญ์ทจ๋๊ณผ ๊ถ์ฅ ์ญ์ทจ๋์ ๋น๊ตํ์ฌ ๊ฑด๊ฐ ์ํ๋ฅผ ๋ชจ๋ํฐ๋งํฉ๋๋ค.
- ์๋จ ๋ฐ ์ฒด์ค ๊ธฐ๋ก
- ์ฌ์ฉ์๊ฐ ์ญ์ทจํ ์์๊ณผ ์ฒด์ค์ ์ผ๋ณ๋ก ๊ธฐ๋กํ ์ ์์ต๋๋ค.
- ๊ธฐ๋ก๋ ๋ฐ์ดํฐ๋ฅผ ์บ๋ฆฐ๋ ํ์์ผ๋ก ์ ๊ณตํ์ฌ, ์๋จ๊ณผ ์ฒด์ค ๋ณํ๋ฅผ ํ๋์ ์ฝ๊ฒ ํ์ธํ ์ ์์ต๋๋ค.
- ๋ฐ์ดํฐ ์๊ฐํ
- ์ฌ์ฉ์์ ์๋จ ๋ฐ ์ฒด์ค ๋ฐ์ดํฐ๋ฅผ ๋ค์ํ ์ฐจํธ๋ก ์๊ฐํํฉ๋๋ค.
- ์นผ๋ก๋ฆฌ ์ญ์ทจ, ์์์ ๋น์จ, ์ฒด์ค ๋ณํ ๋ฑ์ ์ง๊ด์ ์ผ๋ก ํ์ธํ ์ ์์ต๋๋ค.
- ์ฑ๋ด ํผ๋๋ฐฑ
OPENAI API
๋ฅผ ํ์ฉํด ์ฌ์ฉ์์ ์๋จ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ๋กฌํํธ๋ฅผ ์์ฑํฉ๋๋ค.- ์ฑ๋ด์ด ๊ฐ์ธ ๋ง์ถคํ ํผ๋๋ฐฑ์ ์ ๊ณตํฉ๋๋ค.
- ์ฝ์ด:
Next.js
,Typescript
- Style:
tailwindCSS
- ํต์ :
FetchAPI
- ์ํ๊ด๋ฆฌ:
Zustand
- ๋น๋ ๋ฐ ๋ฐฐํฌ:
AWS EC2
,Vercel
,Github Actions
- ๊ธฐํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ:
nivo chart
,next-auth
,react-hook-form
,react-calendar
,moment
,react-spinners
,swiper
,react-markdown
- Formatter:
eslint
,prettier
- ํจํค์ง ๊ด๋ฆฌ:
pnpm
- API: ๊ณต๊ณต๋ฐ์ดํฐํฌํธ | ์์์ฑ๋ถ ๋ฐ์ดํฐ ๐,
OPENAI API
- DB:
MongoDB
- ์ฌ์ฉ์์ ์๋จ ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฅ๋ฐ์, ์ด๋ฅผ ๋ถ์ํ๋ ๋ฐ ์ ํฉํ ํ๋กฌํํธ๋ฅผ ์์ฑํ๊ณ , OpenAI์ gpt-4o-mini ๋ชจ๋ธ์ ์ด์ฉํด ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํฉ๋๋ค.
chatAction.ts
// ํ๋กฌํํธ ์์ฑ
const newPrompt = `์ค๋ ๋ด๊ฐ ๋จน์ ์๋จ์ ๋ถ์ํด์ค! ์๋จ์ ${result} ์ด์ผ. ๊ฒฐ๊ณผ์์ ์๋จ ์์ฝ์ ๊ฐ๋จํ๊ฒ ์์๋ช
๋ง ํ์ํ๊ณ , ์์์ฑ๋ถ ๊ณ์ฐ์ ์ ์ธํด์ค.`;
('use server');
import OpenAI from 'openai';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export async function getChatResponse(prompt: string) {
try {
const completion = await openai.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content:
'๋น์ ์ ์์ ์ ๋ฌธ๊ฐ์
๋๋ค. ์ฃผ์ด์ง ์๋จ์ ๋ถ์ํ์ฌ ์์ ์ฑ๋ถ, ๊ท ํ, ๊ฑด๊ฐ์ ๋ํ ํ๊ฐ๋ฅผ ์ ๊ณตํ๊ณ , ํ์ํ ๊ฒฝ์ฐ ๊ฐ์ ์ฌํญ์ ์ ์ํ์ธ์. ๋ต๋ณ์ ํ๊ตญ์ด๋ก ์ ๊ณตํ์ธ์.',
},
{ role: 'user', content: prompt },
],
});
return completion.choices[0].message.content;
} catch (error) {
console.error('Error fetching from OpenAI:', error);
}
}
- GitHub Actions๋ฅผ ์ฌ์ฉํ์ฌ ์ฝ๋๊ฐ ๋ฉ์ธ ๋ธ๋์น์ ํธ์๋ ๋ ์๋์ผ๋ก ๋น๋ํ๊ณ
AWS EC2
์ ๋ฐฐํฌ๋๋ CI/CD ํ์ดํ๋ผ์ธ์ ๊ตฌํํ์ต๋๋ค.
.github/workflows/depoly.yml
name: Deploy Next.js to EC2
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
- name: Install pnpm
run: |
curl -L https://github.com/pnpm/pnpm/releases/download/v7.18.1/pnpm-linux-x64 -o /usr/local/bin/pnpm
chmod +x /usr/local/bin/pnpm
- name: Install dependencies
run: pnpm install
- name: Build Next.js app
env:
NEXT_PUBLIC_API_SERVER: ${{ secrets.NEXT_PUBLIC_API_SERVER }}
NEXT_PUBLIC_DELAY: ${{ secrets.NEXT_PUBLIC_DELAY }}
NEXT_PUBLIC_LIMIT: ${{ secrets.NEXT_PUBLIC_LIMIT }}
NEXT_PUBLIC_TRIAL_EMAIL: ${{ secrets.NEXT_PUBLIC_TRIAL_EMAIL }}
NEXT_PUBLIC_TRIAL_PW: ${{ secrets.NEXT_PUBLIC_TRIAL_PW }}
NEXT_PUBLIC_API_KEY: ${{ secrets.NEXT_NEXT_PUBLIC_API_KEY }}
NEXT_PUBLIC_CLIENT_ID: ${{ secrets.NEXT_PUBLIC_CLIENT_ID }}
run: pnpm run build
- name: Add EC2 to known hosts
run: |
mkdir -p ~/.ssh
ssh-keyscan -H ${{ secrets.EC2_HOST }} >> ~/.ssh/known_hosts
- name: Compress build folder
run: tar -czf next-app.tar.gz .next package.json node_modules public
- name: Copy files to EC2
env:
EC2_HOST: ${{ secrets.EC2_HOST }}
EC2_USER: ${{ secrets.EC2_USER }}
EC2_KEY: ${{ secrets.EC2_KEY }}
run: |
echo "${{ secrets.EC2_KEY }}" > ec2_key.pem
chmod 600 ec2_key.pem
scp -i ec2_key.pem next-app.tar.gz ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }}:/home/${{ secrets.EC2_USER }}/
- name: Deploy on EC2
env:
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET }}
NEXTAUTH_URL: ${{ secrets.NEXTAUTH_URL }}
AUTH_TRUST_HOST: ${{ secrets.AUTH_TRUST_HOST }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
AUTH_GITHUB_CLIENT_ID: ${{ secrets.AUTH_GITHUB_CLIENT_ID }}
AUTH_GITHUB_CLIENT_SECRET: ${{ secrets.AUTH_GITHUB_CLIENT_SECRET }}
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
NAVER_CLIENT_ID: ${{ secrets.NAVER_CLIENT_ID }}
NAVER_CLIENT_SECRET: ${{ secrets.NAVER_CLIENT_SECRET }}
KAKAO_CLIENT_ID: ${{ secrets.KAKAO_CLIENT_ID }}
KAKAO_CLIENT_SECRET: ${{ secrets.KAKAO_CLIENT_SECRET }}
KAKAO_REDIRECT_URI: ${{ secrets.KAKAO_REDIRECT_URI }}
run: |
ssh -i ec2_key.pem ${{ secrets.EC2_USER }}@${{ secrets.EC2_HOST }} << 'EOF'
cd /home/${{ secrets.EC2_USER }}
tar -xzf next-app.tar.gz
pnpm install --production
echo "NEXTAUTH_SECRET=${{ secrets.NEXTAUTH_SECRET }}" >> .env
echo "NEXTAUTH_URL=${{ secrets.NEXTAUTH_URL }}" >> .env
echo "AUTH_TRUST_HOST=${{ secrets.AUTH_TRUST_HOST }}" >> .env
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" >> .env
echo "AUTH_GITHUB_CLIENT_ID=${{ secrets.AUTH_GITHUB_CLIENT_ID }}" >> .env
echo "AUTH_GITHUB_CLIENT_SECRET=${{ secrets.AUTH_GITHUB_CLIENT_SECRET }}" >> .env
echo "GOOGLE_CLIENT_ID=${{ secrets.GOOGLE_CLIENT_ID }}" >> .env
echo "GOOGLE_CLIENT_SECRET=${{ secrets.GOOGLE_CLIENT_SECRET }}" >> .env
echo "NAVER_CLIENT_ID=${{ secrets.NAVER_CLIENT_ID }}" >> .env
echo "NAVER_CLIENT_SECRET=${{ secrets.NAVER_CLIENT_SECRET }}" >> .env
echo "KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }}" >> .env
echo "KAKAO_CLIENT_SECRET=${{ secrets.KAKAO_CLIENT_SECRET }}" >> .env
echo "KAKAO_REDIRECT_URI=${{ secrets.KAKAO_REDIRECT_URI }}" >> .env
sudo npm install -g pm2
pm2 stop all || true
pm2 start npm --name "foomee-app" -- run start
pm2 save
EOF
์ถ๊ฐ ์์
- ๋ชจ๋ฐ์ผ ์ฌ์ฉ์์ ๊ฒฝํ์ ๊ฐ์ ํ๊ธฐ ์ํด, ํ์ด์ง๋ค์ด์ ๋์ ๋ฌดํ ์คํฌ๋กค ๊ธฐ๋ฅ์ ๊ตฌํํ์ฌ ์ฌ์ฉ์์ ํธ์์ฑ์ ๋์์ต๋๋ค.
Intersection Observer API
๋ฅผ ํ์ฉํ์ฌ ์คํฌ๋กค ์ด๋ฒคํธ๋ก ์ธํ ์ฑ๋ฅ ์ ํ๋ฅผ ๋ฐฉ์งํ๊ณ , ๋ถ๋๋ฌ์ด ๋ฌดํ ์คํฌ๋กค ๊ฒฝํ์ ์ ๊ณตํฉ๋๋ค.
useInfiniteScroll.ts
import { useEffect, useRef, useCallback } from 'react';
interface UseInfiniteScrollProps {
hasMore: boolean;
loadMore: () => void;
}
const useInfiniteScroll = ({ hasMore, loadMore }: UseInfiniteScrollProps) => {
const observerRef = useRef<IntersectionObserver | null>(null);
const lastElementRef = useRef<HTMLDivElement | null>(null);
const handleObserver = useCallback(
(entries: IntersectionObserverEntry[]) => {
const target = entries[0];
if (target.isIntersecting && hasMore) {
loadMore();
}
},
[hasMore, loadMore],
);
useEffect(() => {
if (observerRef.current) observerRef.current.disconnect();
observerRef.current = new IntersectionObserver(handleObserver);
if (lastElementRef.current) {
observerRef.current.observe(lastElementRef.current);
}
return () => {
if (observerRef.current) {
observerRef.current.disconnect();
}
};
}, [handleObserver]);
return { lastElementRef };
};
export default useInfiniteScroll;
NextAuth v5๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ด๋ฒ ์์
๋ก๊ทธ์ธ์ ๊ตฌํํ๋ ๊ณผ์ ์์ expires_in
ํ๋์ ํ์
์ค๋ฅ๋ก ์ธํด OperationProcessingError
๊ฐ ๋ฐ์ํ์ต๋๋ค.
๋ค์ด๋ฒ์ OAuth2.0 ์๋ต์์ expires_in
๊ฐ์ด ๊ณต์ ๋ฌธ์์ ๋ฌ๋ฆฌ ๋ฌธ์์ด๋ก ๋ฐํ๋๋ ๋ฌธ์ ์์ต๋๋ค.
OAuth2.0 ์คํ์ ๋ฐ๋ฅด๋ฉด expires_in
ํ๋๋ ์ซ์ํ์ด์ด์ผ ํ์ง๋ง, ๋ค์ด๋ฒ๋ ์ด ๋ถ๋ถ์ ๋ฌธ์์ด๋ก ๋ฐํํ๊ณ ์์๊ณ , ์ด๋ก ์ธํด NextAuth์์ ์ด๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์๊ฒผ์ต๋๋ค.
๋ฌธ์ ํด๊ฒฐ์ ์ํด ๋ค์ด๋ฒ ๊ฐ๋ฐ์ ํฌ๋ผ์์ ๊ด๋ จ ์ค๋ฅ์ ๋ํ ๋ค์ด๋ฒ์ ๋ต๋ณ์ ํ์ธํ์ต๋๋ค. ๋ค์ด๋ฒ ์ธก์ ํ์ฌ OAuth2.0 ์คํ๊ณผ ๋ค๋ฅด๊ฒ ๋์ํ๊ณ ์์์ ์ธ์ ํ๋ฉด์๋, ๊ธฐ์กด ์คํ์ ์์ ํ๊ธฐ๋ ์ด๋ ต๋ค๋ ์ ์ฅ์ ๋ฐํ์ต๋๋ค.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด expires_in
ํ๋๊ฐ ๋ฌธ์์ด ํ์
์ด์ด๋ ๋ฌธ์ ์์ด ์ฒ๋ฆฌํ ์ ์๋ forked ๋ฒ์ ์ oauth4webapi
ํจํค์ง๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
์ด๋ฅผ ์ํด pnpm
์ ์ฌ์ฉํ์ฌ oauth4webapi
ํจํค์ง๋ฅผ ์ค๋ฒ๋ผ์ด๋ํ์ต๋๋ค.
// package.json
...
"pnpm": {
"overrides": {
"oauth4webapi": "npm:@jacobkim/oauth4webapi@^2.10.4"
}
}
์ด ์ค์ ์ ํตํด ๋ค์ด๋ฒ์ ๋นํ์ค ์๋ต์ ์ฒ๋ฆฌํ ์ ์๋ ์ปค์คํฐ๋ง์ด์ฆ๋ oauth4webapi
ํจํค์ง๋ฅผ ์ฌ์ฉํ ์ ์์์ต๋๋ค.
์ด๋ฅผ ํตํด NextAuth์์ ๋ค์ด๋ฒ ๋ก๊ทธ์ธ์ ๊ตฌํํ ์ ์์๊ณ , ์ถ๊ฐ์ ์ผ๋ก pnpm
์ ๋์
ํ๋ฉด์ ํจํค์ง๋ฅผ ๋์ฑ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์์ต๋๋ค.
main - develop - feature
- main : ํ๋ก๋์ ์ฉ ๋ธ๋์น (๋ฐฐํฌ์ฉ)
- develop : ํตํฉ ๋ฐ ํ ์คํธ์ฉ ๋ธ๋์น (๊ธฐ๋ฅ ๋ณํฉ)
- feat/์ด์๋ฒํธ-๊ธฐ๋ฅ : ๊ธฐ๋ฅ๋ณ ์์ ์ฉ ๋ธ๋์น
keyword | description |
---|---|
FEAT | ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ |
FIX | ๋ฒ๊ทธ ์์ |
DOCS | ๋ฌธ์ ์์ |
DELETE | ๊ธฐ๋ฅ์ด ์ญ์ ๋ ๋ |
STYLE | ์ฝ๋ ํฌ๋งทํ , ์ธ๋ฏธ์ฝ๋ก ๋๋ฝ, ์ฝ๋ ๋ณ๊ฒฝ์ด ์๋ ๊ฒฝ์ฐ |
CHORE | ๋น๋ ์ ๋ฌด ์์ , ํจํค์ง ๋งค๋์ ์์ |
DESIGN | CSS ๋ฑ ์ฌ์ฉ์ UI ๋์์ธ ๋ณ๊ฒฝ |
REFACTOR | ์ฝ๋ ๋ฆฌํฉํ ๋ง |
TEST | ํ ์คํธ |
INIT | ํ๋ก์ ํธ ์ด๊ธฐ ์์ฑ |
RENAME | ํ์ผ ํน์ ํด๋๋ช ์ ์์ ํ๊ฑฐ๋ ์ฎ๊ธฐ๋ ์์ |
REMOVE | ํ์ผ์ ์ญ์ ํ๋ ์์ ๋ง ์ํํ ๊ฒฝ์ฐ |
๐จ Figma | ์์ด์ดํ๋ ์
- ๊ตฌ๊ธ ํผ์ ์ด์ฉํ ์ฌ์ฉ์ ํผ๋๋ฐฑ ์์ง
- https://forms.gle/6RnAgbz5A2LDZHvS8
์ด๋ฒ ํ๋ก์ ํธ๋ ๊ฐ์ธ ํ๋ก์ ํธ์์๋ ๋ถ๊ตฌํ๊ณ , ์ต๋ํ ํ ํ๋ก์ ํธ์ฒ๋ผ ์ฒด๊ณ์ ์ผ๋ก ์งํํ๊ณ ์ ๋ ธ๋ ฅํ์ต๋๋ค. Eslint์ Prettier ์ค์ ์ ํตํด ์ฝ๋ ์คํ์ผ์ ์ผ๊ด๋๊ฒ ์ ์งํ๊ณ , GitHub์ Issue, PR ํ ํ๋ฆฟ, Git์ Commit ํ ํ๋ฆฟ์ ํ์ฉํ์ฌ ์ฝ๋ ๋ณ๊ฒฝ ์ฌํญ์ ๋ช ํํ๊ฒ ๊ธฐ๋กํ๊ณ ์ถ์ ํ ์ ์๋๋ก ํ์ต๋๋ค. ๋ํ, ๊ฐ๋ฐ ๊ณผ์ ์ ์ฒด๊ณ์ ์ผ๋ก ๋ฌธ์ํํ์ฌ, ๋ค๋ฅธ ์ฌ๋์ด ํ๋ก์ ํธ๋ฅผ ์ดํดํ๊ณ ์ปค๋ฎค๋์ผ์ด์ ํ ์ ์๋๋ก ์ ๊ฒฝ์จ์ ์์ ์ ์งํํ์ต๋๋ค.
ํ๋ก ํธ์๋์ ์ญํ ์ ์ฌ์ฉ์๊ฐ ๊ณ ๋ฏผํ์ง ์๊ณ ์ธ ์ ์๋ ๊ฒฝํ์ ๊ตฌํํ๋ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ด๋ฒ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ์ฌ์ฉ์๊ฐ ๊ณ ๋ฏผํ์ง ์๊ณ ์ง๊ด์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ฅ๊ณผ ํ๋ฉด์ ๊ตฌํํ๊ธฐ ์ํด ๊ณ ๋ฏผํ์ต๋๋ค.
- ์ฐ์ ์์๊ฐ ๋ฎ์ ๊ธฐ๋ฅ์ ๊ตฌํ
- ์ ์ ํ ์คํธ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ชจ๋ฐ์ผ ์ต์ ํ ๋ฐ ์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์
- AI ๋ถ์ ๊ธฐ๋ฅ ํ์ฅ: ์ฃผ๊ฐ ๋ฐ ์๊ฐ ๋ ํฌํธ ์์ฑ ๊ธฐ๋ฅ ์ถ๊ฐ
- ๋ ์์ ์ธ ์์์ฑ๋ถ DB ๊ตฌ์ถ: ์ฌ์ฉ์๊ฐ ์ง์ ์์์ฑ๋ถ ์ ๋ ฅํ๋ ๊ธฐ๋ฅ, ์์ ๊ฒ์ ์ต์ ํ
ํ์์ ๊ด์ฌ์ด ๋ง์๋ ํฌ์ค์ผ์ด ๋ถ์ผ์ ์ฑ์ ๊ธฐํ๋ถํฐ ์ ์๊น์ง ์ง์ ์งํํ๋ฉด์, ํ๋ก์ ํธ์ ๋ ํฐ ์ ์ ์ ๊ฐ์ง๊ณ ์ํ ์ ์์์ต๋๋ค. ํผ์์ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ค ๋ณด๋, ์ฃผ์ด์ง ๊ธฐ๊ฐ ๋ด์ ์์ฑํ ์ ์์์ง์ ๋ํ ์๋ฐ๊ฐ์ด ์์์ต๋๋ค. ํ์ง๋ง ๊ธฐ๊ฐ ๋ด์ ๊ธฐํ, ๋์์ธ, ๊ฐ๋ฐ์ ํ ์ฌ์ดํด์ ๋ฌด์ฌํ ๋ง์น ์ ์์ด์ ํ ๋จ๊ณ ์ฑ์ฅํ๋ ๊ณ๊ธฐ๊ฐ ๋ ๊ฒ ๊ฐ์ต๋๋ค. ํนํ, ์ด์ ์๋ ์๋ํ์ง ๋ชปํ๋ AI์ ๊ฐ์ ๊ธฐ์ ๋ค์ ์ ์ฉํด ๋ณผ ์ ์์๋ ์ ์ด ๋งค์ฐ ์ฆ๊ฑฐ์ ์ต๋๋ค. ์์ผ๋ก ๋ฆฌํฉํ ๋ง ๊ณผ์ ์ ํตํด ๋์ฑ ์์ฑ๋ ๋์ ์๋น์ค๋ฅผ ๋ง๋ค์ด ๋๊ฐ๊ณ ์ถ์ต๋๋ค.