AIλ₯Ό λ¨μ μ§λ¬ΈΒ·λ΅λ³ λꡬμμ μ€μ μμ νλ¦μ μ€κ³νλ λκ΅¬λ‘ νμ₯νλ νμ΅ νλ«νΌ
LearningLMμ μ΄κΈ μ¬μ©μκ° μμ±ν AIλ₯Ό λ¨μν βμ§λ¬Ένλ©΄ λ΅λ³μ λ°λ μ±λ΄βμΌλ‘λ§ μ¬μ©νλ λ¨κ³μμ λ²μ΄λ, μ€μ μμ λͺ©μ μ λ§λ AI νμ© νλ¦μ μ΄ν΄νκ³ μ§μ μ‘°ν©ν΄ λ³Ό μ μλλ‘ λλ νμ΅ νλ«νΌμ λλ€.
LearningLMμ μ€μ AI μλν μ€ν λκ΅¬κ° μλλΌ, μ¬μ©μκ° AI νμ© λ°©μμ νμ΅νκ³ , νν 리μΌμ λ°λΌκ°λ©°, μμ λ§μ μν¬νλ‘μ°λ₯Ό ꡬμ±ν΄ 보λ νλ‘ νΈμλ μ€μ¬μ νμ΅ μλΉμ€μ λλ€.
νμ¬ LearningLM νλ‘ νΈμλλ Vercelμ λ°°ν¬λμ΄ μμ΅λλ€.
- Production URL: https://umc-learning-lm-fe.vercel.app
- Repository: https://github.com/UMCLearningLM/UMCLearningLM_FE
- Production Branch:
main - Build Command:
npm run build - Output Directory:
dist
main λΈλμΉμ λ³κ²½ μ¬νμ΄ λ°μλλ©΄ Vercelμμ νλ‘λμ
λ°°ν¬λ₯Ό μ§νν©λλ€. Pull Requestμ κΈ°λ₯ κ°λ° λΈλμΉλ Vercel Preview Deploymentλ₯Ό ν΅ν΄ λ³ν© μ μ μ€μ νλ©΄μ νμΈν μ μμ΅λλ€.
LearningLMμ AI μ¬μ© κ²½νμ΄ λΆμ‘±ν μ΄κΈ μ¬μ©μκ° ν둬ννΈ μ λ ₯μλ§ λ¨Έλ¬΄λ₯΄μ§ μκ³ , λͺ©μ μ λ§λ AI νμ© νλ¦μ λ¨κ³μ μΌλ‘ μ΄ν΄νλλ‘ λλ κ²μ λͺ©νλ‘ ν©λλ€.
- AI νμ© νλ¦ νμ΅: λ¨μ μ§λ¬ΈΒ·λ΅λ³μ λμ΄ μμ λͺ©μ μ λ§λ AI μ¬μ© λ¨κ³λ₯Ό νμ΅ν©λλ€.
- νν λ¦¬μΌ κΈ°λ° μ΄ν΄: 곡μ νν 리μΌμ ν΅ν΄ AI νμ© μ¬λ‘μ κ΅¬μ± λ°©μμ μ΅νλλ€.
- μν¬νλ‘μ° μ‘°ν© κ²½ν: Studioμμ μ§μ λΈλ‘κ³Ό λ¨κ³λ₯Ό ꡬμ±νλ©° AI νμ© κ΅¬μ‘°λ₯Ό 체νν©λλ€.
- μ μ₯κ³Ό 곡μ : μμ±ν μν¬νλ‘μ°λ₯Ό μ μ₯νκ³ , λ€λ₯Έ μ¬μ©μμ μμλ₯Ό νμν μ μμ΅λλ€.
LearningLMμ μ¬μ©μκ° AI νμ©λ²μ λ°°μ°κ³ , μ§μ ꡬμ±νκ³ , μ μ₯νκ±°λ 곡μ νλ νλ¦μ μ€μ¬μΌλ‘ μ€κ³λ©λλ€.
- μλΉμ€μ ν΅μ¬ κ°μΉμ μ£Όμ κΈ°λ₯μ μκ°ν©λλ€.
- μ¬μ©μκ° Official Tutorials, Studio, Public Library λ± μ£Όμ κΈ°λ₯μΌλ‘ μ§μ ν μ μλλ‘ μλ΄ν©λλ€.
- μ΄κΈ μ¬μ©μλ₯Ό μν 곡μ AI νμ© νν λ¦¬μΌ λͺ©λ‘μ μ 곡ν©λλ€.
- κ²μ, λμ΄λ, μΉ΄ν κ³ λ¦¬ νν°λ₯Ό ν΅ν΄ μνλ νν 리μΌμ νμν©λλ€.
- νν 리μΌμ ν΅ν΄ AIλ₯Ό νμ©νλ νλ¦κ³Ό κ° λ¨κ³μ μλ―Έλ₯Ό νμ΅ν©λλ€.
- μ νν νν 리μΌμ λͺ©μ , κ΅¬μ± λ¨κ³, μμ κ²°κ³Όλ₯Ό νμΈν©λλ€.
- μ¬μ©μλ μλ΄μ λ°λΌ λ¨κ³λ³ AI νμ© νλ¦μ λ°λΌκ° μ μμ΅λλ€.
- νν λ¦¬μΌ μμ μ Guided Studioλ‘ μ΄λνμ¬ λ―Έλ¦¬ ꡬμ±λ νλ¦μ νμ΅ν©λλ€.
- μ¬μ©μκ° μ§μ AI νμ© μν¬νλ‘μ°λ₯Ό ꡬμ±νλ ν΅μ¬ μμ 곡κ°μ λλ€.
- Guided Studioμ Create Studioλ‘ κ΅¬λΆνμ¬ μ΄κΈμμ μμ μ μ μ¬μ©μλ₯Ό λͺ¨λ μ§μν©λλ€.
- μ λ ₯, 컨ν μ€νΈ, νλ‘μΈμ€, κ²ν , κ²°κ³Ό λ Έλλ₯Ό μ‘°ν©νμ¬ νλμ μμ νλ¦μ λ§λλλ€.
@xyflow/reactλ₯Ό νμ©νμ¬ λ Έλ λ°°μΉ, μ°κ²°, μ΄λμ΄ κ°λ₯ν μν¬νλ‘μ° νΈμ§ νλ©΄μ ꡬμ±ν©λλ€.
- μ¬μ©μκ° κ΅¬μ±ν μν¬νλ‘μ°μ νλ¦μ 미리 νμΈν©λλ€.
- νμ λΈλ‘κ³Ό μ¬λ‘―μ΄ λͺ¨λ μ±μμ‘λμ§ κ²μ¦ν©λλ€.
- κ΅¬μ± λ¨κ³κ° λ Όλ¦¬μ μΌλ‘ μ΄μ΄μ§λμ§ νμΈνκ³ μμ κ²°κ³Όλ₯Ό μ΄ν΄λ΄ λλ€.
- κ²μ¦ κ²°κ³Όλ
PASS,INSUFFICIENT,PENDINGλ±μ μνλ‘ ννν μ μλλ‘ μ€κ³ν©λλ€.
- μ¬μ©μκ° μ μ₯ν νν 리μΌκ³Ό μν¬νλ‘μ°λ₯Ό κ΄λ¦¬ν©λλ€.
- μ΄μ μ λ§λ νλ¦μ λ€μ νμΈνκ±°λ μμ ν μ μμ΅λλ€.
- μ§μ λ§λ νλ¦κ³Ό Public Libraryμμ 볡μ¬ν νλ¦μ ꡬλΆνμ¬ κ΄λ¦¬ν©λλ€.
- λ€λ₯Έ μ¬μ©μκ° κ³΅μ ν μν¬νλ‘μ°λ₯Ό νμν©λλ€.
- κ²μ, μΉ΄ν κ³ λ¦¬, λμ΄λ νν°λ₯Ό ν΅ν΄ λ€μν νμ© μ¬λ‘λ₯Ό νμΈν©λλ€.
- κ³΅κ° μν¬νλ‘μ°λ₯Ό μμ μ μ μ₯μλ‘ λ³΅μ¬ν λ€ Studioμμ μμ ν μ μμ΅λλ€.
- Google OAuth λ‘κ·ΈμΈκ³Ό μ΄λ©μΌ κΈ°λ° μΈμ¦ νλ©΄μ μ 곡ν©λλ€.
- λ‘κ·ΈμΈ, νμκ°μ , λΉλ°λ²νΈ μ°ΎκΈ°, μΈμ¦ μ±κ³΅Β·μ€ν¨ νλ©΄μ ν¬ν¨ν©λλ€.
- μ μ₯, 곡μ , κ°μΈ μν¬νλ‘μ° κ΄λ¦¬ κΈ°λ₯κ³Ό μ°κ²°λ©λλ€.
LearningLM νλ‘ νΈμλλ μ¬μ©μκ° AI νμ© νλ¦μ μμ°μ€λ½κ² μ΄ν΄ν μ μλλ‘ νλ©΄ νλ¦, μν κ΄λ¦¬, λ¨κ³λ³ μΈν°λμ μ μ§μ€ν©λλ€.
- Learning Flow μ€μ¬ μ€κ³: νν λ¦¬μΌ νμλΆν° Studio μ μ, Preview, μ μ₯κΉμ§ μ΄μ΄μ§λ νμ΅ νλ¦μ μ 곡ν©λλ€.
- State-Driven UI: μ¬μ©μκ° μ νν νν 리μΌ, λΈλ‘, μν¬νλ‘μ° λ¨κ³μ λ°λΌ νλ©΄ μνκ° λμ μΌλ‘ λ³κ²½λ©λλ€.
- Node-Based Workflow Editor:
@xyflow/reactλ₯Ό μ¬μ©νμ¬ λΈλ‘κ³Ό λ Έλλ₯Ό μκ°μ μΌλ‘ λ°°μΉνκ³ μ°κ²°νλ Studioλ₯Ό ꡬνν©λλ€. - Workflow Preview: μ¬μ©μκ° κ΅¬μ±ν AI νμ© νλ¦μ 미리 νμΈνκ³ κ²ν ν μ μλλ‘ μ€κ³ν©λλ€.
- Reusable Components: λ²νΌ, μΉ΄λ, λ°°μ§, μ λ ₯ νΌ, μ ν μ»΄ν¬λνΈ λ± λ°λ³΅λλ UIλ₯Ό κ³΅μ© μ»΄ν¬λνΈλ‘ λΆλ¦¬ν©λλ€.
- Accessible UI Foundation: Base UIμ κ³΅ν΅ UI μ»΄ν¬λνΈλ₯Ό νμ©νμ¬ ν€λ³΄λ μ‘°μκ³Ό μν ννμ κ³ λ €ν©λλ€.
- Feature-based Architecture: κΈ°λ₯ λ¨μλ‘ ν΄λλ₯Ό λΆλ¦¬νμ¬ μ μ§λ³΄μμ±κ³Ό νμ ν¨μ¨μ λμ λλ€.
- Utility-based Styling: Tailwind CSSμ CVAλ₯Ό νμ©νμ¬ μ»΄ν¬λνΈμ ν¬κΈ°μ μνλ³ μ€νμΌμ κ΄λ¦¬ν©λλ€.
- SPA Routing: React Router DOMμ κΈ°λ°μΌλ‘ Home, Tutorial, Studio, Storage, Library, Auth νλ©΄μ μ°κ²°ν©λλ€.
React, TypeScript, Viteλ₯Ό κΈ°λ°μΌλ‘ νλ©°, μ μ§λ³΄μμ±μ μν΄ κΈ°λ₯ λ¨μ Feature-based Architectureλ₯Ό λ°λ¦ λλ€.
| λΆλ₯ | κΈ°μ | λΉκ³ |
|---|---|---|
| Core | React, TypeScript | UI κ΅¬μ± λ° μ μ νμ κ²μ¬ |
| Build | Vite | κ°λ° μλ² λ° νλ‘λμ λΉλ |
| Routing | React Router DOM | SPA λΌμ°ν λ° λμ κ²½λ‘ κ΄λ¦¬ |
| Workflow Editor | @xyflow/react |
Studio λ Έλ λ°°μΉ, μ°κ²°, μ΄λ |
| Server State | TanStack Query | API λ°μ΄ν° μ‘°ν, μΊμ±, λκΈ°ν |
| Client State | Zustand | Studioμ μΈμ¦ κ΄λ ¨ μ μ μν κ΄λ¦¬ |
| Network | Axios | HTTP λΉλκΈ° ν΅μ |
| Style | Tailwind CSS | μ νΈλ¦¬ν° κΈ°λ° μ€νμΌλ§ |
| UI Foundation | Base UI, shadcn | μ κ·Όμ±μ κ³ λ €ν UI κΈ°λ° μ»΄ν¬λνΈ |
| Animation | tw-animate-css | UI μ ν λ° μ λλ©μ΄μ μ νΈλ¦¬ν° |
| Variant Styling | class-variance-authority | μ»΄ν¬λνΈ μνμ ν¬κΈ°λ³ μ€νμΌ κ΄λ¦¬ |
| Class Utilities | clsx, tailwind-merge | μ‘°κ±΄λΆ ν΄λμ€ λ° Tailwind ν΄λμ€ λ³ν© |
| Icons | lucide-react, react-icons | κ³΅ν΅ μμ΄μ½ λ° λΈλλ μμ΄μ½ |
| Font | Geist Variable | μ μ κΈ°λ³Έ ν°νΈ |
| Package Manager | npm | ν¨ν€μ§ λ° μ κΈ νμΌ κ΄λ¦¬ |
| Quality | ESLint, TypeScript | μ½λ νμ§ λ° νμ μ€λ₯ κ²μ¬ |
| Deploy | Vercel | νλ‘λμ λ° Preview Deployment |
Studioμ λ Έλ κΈ°λ° μν¬νλ‘μ° νΈμ§ νλ©΄μ ꡬμ±νκΈ° μν΄ μ¬μ©ν©λλ€.
μ£Όμ μ¬μ© λͺ©μ :
- μν¬νλ‘μ° λ Έλ λ λλ§
- λ Έλ κ° μ°κ²°μ νν
- λ Έλ λλκ·Έ λ° μμΉ λ³κ²½
- μΊλ²μ€ μ΄λκ³Ό νλΒ·μΆμ
- μ λ ₯, 컨ν μ€νΈ, νλ‘μΈμ€, κ²ν , κ²°κ³Ό λ Έλ μ°κ²°
- μ νν λ Έλμ Inspector μν μ°λ
import { ReactFlow } from '@xyflow/react'
import '@xyflow/react/dist/style.css'μλ²μμ μ λ¬λ°λ νν 리μΌ, μν¬νλ‘μ°, Public Library λ°μ΄ν°λ₯Ό κ΄λ¦¬νκΈ° μν΄ μ¬μ©ν©λλ€.
import {
QueryClient,
QueryClientProvider,
} from '@tanstack/react-query'
const queryClient = new QueryClient()μ£Όμ μ¬μ© λμ:
- νν λ¦¬μΌ λͺ©λ‘ λ° μμΈ μ‘°ν
- μν¬νλ‘μ° μ μ₯ λ° μμ
- Public Library μ‘°ν
- μ¬μ©μ μ μ₯μ μ‘°ν
- μλ² λ°μ΄ν° μΊμ±κ³Ό μ¬μμ²
Studioμ λ Έλ, λΈλ‘, μ ν μν λ± ν΄λΌμ΄μΈνΈ μ€μ¬ μνλ₯Ό κ΄λ¦¬νκΈ° μν΄ μ¬μ©ν©λλ€.
μ£Όμ κ΄λ¦¬ λμ:
- νμ¬ μ νν λ Έλ
- Studio λͺ¨λ
- λ Έλμ μ°κ²°μ λͺ©λ‘
- μν¬νλ‘μ° μ λͺ© λ° μ€λͺ
- νμ μ¬λ‘― μ λ ₯ μν
- κ²μ¦ λ° μ μ₯ μν
- λ‘κ·ΈμΈ μ¬μ©μ μν
Button, Slider λ± κ³΅μ© UIμ κΈ°λ°μΌλ‘ μ¬μ©ν©λλ€.
μ§μ μμ±ν LearningLM λμμΈ μμ€ν κ³Ό κ²°ν©νμ¬ μ¬μ¬μ© κ°λ₯ν κ³΅μ© μ»΄ν¬λνΈλ₯Ό ꡬμ±ν©λλ€.
λ²νΌ, λ°°μ§, μν μ»΄ν¬λνΈμ variantμ size μ€νμΌμ κ΄λ¦¬ν©λλ€.
const buttonVariants = cva(
'inline-flex items-center justify-center',
{
variants: {
variant: {
default: 'bg-primary text-white',
secondary: 'bg-secondary',
},
size: {
sm: 'h-8 px-3',
lg: 'h-11 px-6',
},
},
},
)μ΄ νλ‘μ νΈλ Node.js v20 LTS μ΄μ νκ²½μ κΆμ₯ν©λλ€.
node -v
npm -vgit clone https://github.com/UMCLearningLM/UMCLearningLM_FE.git
cd UMCLearningLM_FEnpm installνμλ€κ³Ό package-lock.jsonμ κΈ°λ‘λ λμΌν ν¨ν€μ§ λ²μ μ μ€μΉνλ €λ©΄ μλ λͺ
λ Ήμ΄λ₯Ό μ¬μ©ν©λλ€.
npm ciμΌλ°μ μΌλ‘ μ ν¨ν€μ§λ₯Ό μΆκ°νμ§ μκ³ νλ‘μ νΈλ₯Ό μ€ννκ±°λ CI νκ²½μμ μ€μΉν λλ npm ci μ¬μ©μ κΆμ₯ν©λλ€.
λ£¨νΈ λλ ν 리μ .env νμΌμ μμ±νκ³ νμν νκ²½ λ³μλ₯Ό μ€μ ν©λλ€.
VITE_API_BASE_URL=http://localhost:8080/apiViteμμ λΈλΌμ°μ μ½λμ λ
ΈμΆν νκ²½ λ³μλ λ°λμ VITE_ μ λμ¬λ₯Ό μ¬μ©ν΄μΌ ν©λλ€.
νκ²½ λ³μ μ¬μ© μμ:
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL.env νμΌμλ μλ² μ£Όμλ κ°μΈ κ°λ° νκ²½ μ€μ μ΄ ν¬ν¨λ μ μμΌλ―λ‘ Gitμ 컀λ°νμ§ μμ΅λλ€.
npm run devλΈλΌμ°μ μμ μλ μ£Όμλ‘ μ μν©λλ€.
http://localhost:5173npm run buildνμ¬ λΉλ λͺ λ Ήμ TypeScript νλ‘μ νΈ κ²μ¬μ Vite λΉλλ₯Ό ν¨κ» μ€νν©λλ€.
{
"build": "tsc -b && vite build"
}λΉλ κ²°κ³Όλ dist λλ ν 리μ μμ±λ©λλ€.
npm run previewLearningLMμ κΈ°λ₯ μ€μ¬ μν€ν μ²λ₯Ό κΈ°λ°μΌλ‘ ν©λλ€. νλ©΄, μ»΄ν¬λνΈ, ν , API λ‘μ§μ κΈ°λ₯ λ¨μλ‘ λͺ¨μ κ΄λ¦¬ν©λλ€.
src/
βββ assets/ # μ΄λ―Έμ§, μμ΄μ½, ν°νΈ λ± μ μ 리μμ€
β
βββ components/ # μ μ κ³΅μ© UI μ»΄ν¬λνΈ
β βββ layout/ # Header, Footer, PageContainer, Section
β βββ ui/ # Button, Input, Select, Card, Badge λ±
β
βββ api/ # κΈ°λ₯λ³ API μμ² ν¨μ λ° νμ
β βββ auth/ # λ‘κ·ΈμΈ, νμκ°μ
API
β βββ tutorial/ # νν λ¦¬μΌ κ΄λ ¨ API
β βββ workflow/ # μν¬νλ‘μ° μμ±, μ μ₯, μ‘°ν API
β βββ library/ # Public Library κ΄λ ¨ API
β
βββ features/ # ν΅μ¬ λλ©μΈλ³ κΈ°λ₯ λͺ¨μ
β βββ auth/
β β βββ components/
β β βββ hooks/
β β βββ utils/
β β
β βββ home/
β β βββ components/
β β βββ hooks/
β β
β βββ tutorial/
β β βββ components/
β β βββ data/
β β βββ hooks/
β β βββ utils/
β β
β βββ studio/
β β βββ components/
β β β βββ node/ # Studio κ³΅ν΅ λ
Έλ UI
β β β βββ block/ # λ
Έλλ³ λΈλ‘ μ€μ UI
β β β βββ editor/ # Studio νΈμ§ μμ
β β β βββ preview/ # Preview κ΄λ ¨ UI
β β βββ hooks/
β β βββ types/
β β βββ utils/
β β
β βββ storage/
β β βββ components/
β β βββ data/
β β βββ hooks/
β β βββ utils/
β β
β βββ library/
β β βββ components/
β β βββ data/
β β βββ hooks/
β β βββ utils/
β β
β βββ user/
β βββ components/
β βββ hooks/
β βββ utils/
β
βββ pages/ # λΌμ°νΈ νμ΄μ§, features 쑰립
β βββ auth/
β β βββ Login.tsx
β β βββ GoogleLogin.tsx
β β βββ GoogleLoginSuccess.tsx
β β βββ GoogleLoginError.tsx
β β
β βββ home/
β β βββ HomePage.tsx
β β
β βββ tutorial/
β β βββ OfficialTutorialPage.tsx
β β βββ TutorialDetailPage.tsx
β β
β βββ studio/
β β βββ StudioPage.tsx
β β βββ GuidedStudioPage.tsx
β β βββ CreateStudioPage.tsx
β β
β βββ storage/
β β βββ MyStoragePage.tsx
β β βββ WorkflowDetailPage.tsx
β β
β βββ library/
β β βββ PublicLibraryPage.tsx
β β βββ LibraryDetailPage.tsx
β β
β βββ dev/ # κ³΅ν΅ μ»΄ν¬λνΈ λ° Studio λ
Έλ ν
μ€νΈ
β
βββ routes/
β βββ router.tsx
β
βββ services/
β βββ axiosInstance.ts
β
βββ store/
β βββ authStore.ts
β βββ workflowStore.ts
β
βββ types/
β βββ auth.ts
β βββ tutorial.ts
β βββ workflow.ts
β
βββ lib/
β βββ utils.ts # cn λ± UI κ³΅μ© μ νΈλ¦¬ν°
β
βββ utils/
β
βββ App.tsx
βββ main.tsx
βββ index.css
- Colocation: νΉμ κΈ°λ₯μμλ§ μ°μ΄λ μ»΄ν¬λνΈλ
features/κΈ°λ₯λͺ /componentsμμ λ‘λλ€. - Barrel Exports:
index.tsλ₯Ό νμ©νμ¬ import κ²½λ‘λ₯Ό μ 리ν©λλ€. - Absolute Import:
../../λμ@/features/userμ κ°μ μ λ κ²½λ‘λ₯Ό μ¬μ©ν©λλ€. - Feature First: νμ΄μ§λ κΈ°λ₯ μ»΄ν¬λνΈλ₯Ό 쑰립νκ³ , μ€μ UIμ λ‘μ§μ
featuresλ΄λΆμμ κ΄λ¦¬ν©λλ€. - Page Responsibility:
pagesλ λΌμ°ν νλΌλ―Έν°μ κΈ°λ₯ 쑰립μ λ΄λΉνκ³ λ³΅μ‘ν λΉμ¦λμ€ λ‘μ§μ μ§μ ν¬ν¨νμ§ μμ΅λλ€. - Server / Client State Separation: API λ°μ΄ν°λ TanStack Query, νΈμ§ μ€μΈ UI μνλ Zustand λλ μ§μ μνλ‘ κ΄λ¦¬ν©λλ€.
| κ΅¬λΆ | νλ©΄ | μ€λͺ |
|---|---|---|
| Home | Home | μλΉμ€ μκ° λ° μ£Όμ κΈ°λ₯ μ§μ |
| Tutorial | Official Tutorials | 곡μ νν λ¦¬μΌ λͺ©λ‘ |
| Tutorial | Tutorial Detail | νν λ¦¬μΌ μμΈ μ 보 |
| Tutorial | Tutorial Start | νν λ¦¬μΌ λ¨κ³λ³ μ§ν |
| Studio | Studio | μν¬νλ‘μ° μ μ λ©μΈ νλ©΄ |
| Studio | Guided Studio | μλ΄ κΈ°λ° μν¬νλ‘μ° μ μ |
| Studio | Create Studio | μμ μ μ μν¬νλ‘μ° νΈμ§ |
| Studio | Preview | μ μν νλ¦ λ―Έλ¦¬λ³΄κΈ° |
| Storage | My Storage | μ μ₯ν νν λ¦¬μΌ λ° μν¬νλ‘μ° λͺ©λ‘ |
| Storage | Workflow Detail | μ μ₯λ μν¬νλ‘μ° μμΈ |
| Library | Public Library | κ³΅κ° μν¬νλ‘μ° νμ |
| Library | Library Detail | κ³΅κ° μν¬νλ‘μ° μμΈ |
| Auth | Login | λ‘κ·ΈμΈ |
| Auth | Signup | νμκ°μ |
| Auth | Password Find | λΉλ°λ²νΈ μ°ΎκΈ° |
| Auth | OAuth Result | Google λ‘κ·ΈμΈ μ±κ³΅ λ° μ€ν¨ μ²λ¦¬ |
Home
βββ Official Tutorials
β βββ Tutorial Detail
β βββ Tutorial Start
β βββ Guided Studio
β βββ Validation / Preview
β βββ My Storage
β
βββ Create Studio
β βββ Validation / Preview
β βββ My Storage
β
βββ Public Library
βββ Library Detail
βββ Copy Workflow
βββ Studio
βββ My Storage
LearningLMμ createBrowserRouterμ RouterProviderλ₯Ό μ¬μ©νμ¬ SPA λΌμ°ν
μ ꡬμ±ν©λλ€.
import { RouterProvider } from 'react-router-dom'
import { router } from './routes/router'
function App() {
return <RouterProvider router={router} />
}
export default Appμ£Όμ κ²½λ‘ μμ:
/
βββ official-tutorials
β βββ :tutorialId
βββ studio
β βββ :workflowId/edit
βββ my-storage
β βββ workflows/:workflowId
βββ public-library
β βββ :libraryId
βββ login
βββ register
βββ pw-find
λͺ¨λ μ± λΌμ°ν
μ src/routes/router.tsxμμ κ΄λ¦¬ν©λλ€. μ»΄ν¬λνΈ λ΄λΆμμ λ³λμ BrowserRouterλ₯Ό μμ±νμ§ μμ΅λλ€.
main: λ°°ν¬ κ°λ₯ν μμ λ²μ dev: κ°λ° ν΅ν© λΈλμΉfeature/*: κΈ°λ₯ κ°λ° λΈλμΉ
νμ
/κΈ°λ₯λͺ
_μμ±μ| νμ | μ€λͺ | μμ |
|---|---|---|
| feat | μλ‘μ΄ κΈ°λ₯ μΆκ° | feat/login_seongmin |
| fix | λ²κ·Έ μμ | fix/studio-preview_seongmin |
| design | μ€νμΌ λ° UI μμ | design/home-layout_seongmin |
| refactor | μ½λ ꡬ쑰 κ°μ | refactor/workflow-store_seongmin |
| docs | λ¬Έμ μμ | docs/readme_seongmin |
μ»€λ° λ©μμ§λ Conventional Commits κ·μΉμ λ°λ¦ λλ€.
feat: λ‘κ·ΈμΈ νμ΄μ§ ꡬν
fix: Studio Preview λ λλ§ μ€λ₯ μμ
design: Home CTA λ²νΌ μ€νμΌ μμ
refactor: workflow store ꡬ쑰 λΆλ¦¬
docs: README λ°°ν¬ μ 보 μΆκ°PRμ μ¬λ¦¬κΈ° μ μλ λͺ λ Ήμ΄λ₯Ό μ€ννμ¬ νμ μ€λ₯, λΉλ μ€λ₯, λ¦°νΈ μ€λ₯λ₯Ό νμΈν©λλ€.
npm run build
npm run lintνμ¬ npm run buildμλ TypeScript κ²μ¬κ° ν¬ν¨λμ΄ μμ΅λλ€.
tsc -b && vite buildλ°λΌμ λ³λμ type-check μ€ν¬λ¦½νΈλ₯Ό μΆκ°νμ§ μμ μνμμλ npm run buildλ‘ νμ
κ²μ¬μ λΉλλ₯Ό ν¨κ» νμΈν©λλ€.
LearningLMμ Vercelμμ main λΈλμΉλ₯Ό κΈ°μ€μΌλ‘ νλ‘λμ
λ°°ν¬λ₯Ό μ§νν©λλ€.
main push
β Vercel Build
β TypeScript Check
β Vite Production Build
β dist λ°°ν¬
νμ¬ νλ‘λμ μ£Όμ:
https://umc-learning-lm-fe.vercel.appPull Request λλ κΈ°λ₯ λΈλμΉλ₯Ό μ격 μ μ₯μμ Pushνλ©΄ Vercel Preview Deploymentλ₯Ό μ¬μ©ν μ μμ΅λλ€.
Preview Deploymentλ₯Ό ν΅ν΄ λ€μ λ΄μ©μ λ³ν© μ μ νμΈν©λλ€.
- νμ΄μ§ λΌμ°ν
- λ°μν λ μ΄μμ
- νκ²½ λ³μ μ°κ²°
- API νΈμΆ μ£Όμ
- Studio μΊλ²μ€ λ λλ§
- Public Libraryμ Storage νλ©΄
- μ§μ URL μ κ·Όκ³Ό μλ‘κ³ μΉ¨
Vercel νλ‘μ νΈμμ λ€μ κ°μ μ¬μ©ν©λλ€.
| νλͺ© | κ° |
|---|---|
| Framework Preset | Vite |
| Install Command | npm ci λλ npm install |
| Build Command | npm run build |
| Output Directory | dist |
| Node.js Version | 20.x |
| Production Branch | main |
Vercel Dashboardμμ μλ κ²½λ‘λ‘ μ΄λνμ¬ νκ²½ λ³μλ₯Ό λ±λ‘ν©λλ€.
Project
β Settings
β Environment Variables
μμ:
VITE_API_BASE_URL=https://api.example.com/apiνκ²½ λ³μλ νμμ λ°λΌ Production, Preview, Development νκ²½λ³λ‘ ꡬλΆνμ¬ λ±λ‘ν©λλ€.
νκ²½ λ³μλ₯Ό μΆκ°νκ±°λ μμ ν λ€μλ κΈ°μ‘΄ λ°°ν¬μ μλμΌλ‘ μ μ©λμ§ μμ μ μμΌλ―λ‘ Redeployλ₯Ό μ§νν©λλ€.
LearningLMμ React Router κΈ°λ° SPAμ΄λ―λ‘ /official-tutorials/1, /public-library/1κ³Ό κ°μ κ²½λ‘μμ λΈλΌμ°μ μλ‘κ³ μΉ¨μ νμ λ Vercelμ΄ ν΄λΉ κ²½λ‘μ μ€μ νμΌμ μ°ΎμΌλ €κ³ ν μ μμ΅λλ€.
μ§μ κ²½λ‘ μ κ·Ό μ 404 μ€λ₯κ° λ°μνλ€λ©΄ νλ‘μ νΈ λ£¨νΈμ vercel.jsonμ μΆκ°ν©λλ€.
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}μ΄ μ€μ μ λͺ¨λ νλ‘ νΈμλ κ²½λ‘λ₯Ό index.htmlλ‘ μ λ¬νκ³ , μ΄ν React Routerκ° μ€μ νλ©΄μ λ λλ§νλλ‘ ν©λλ€.
npm ci
npm run build
npm run lintλΉλκ° μλ£λλ©΄ μλ λͺ λ Ήμ΄λ‘ νλ‘λμ κ²°κ³Όλ₯Ό λ‘컬μμ νμΈν μ μμ΅λλ€.
npm run previewNode.jsμ npm λ²μ μ νμΈν©λλ€.
node -v
npm -vNode.js v20 μ΄μ μ¬μ©μ κΆμ₯ν©λλ€.
package-lock.jsonκ³Ό λμΌν λ²μ μ μ€μΉν΄μΌ νλ€λ©΄ λ€μ λͺ
λ Ήμ΄λ₯Ό μ¬μ©ν©λλ€.
npm ciVS Codeμμ TypeScript μλ²λ₯Ό μ¬μμν©λλ€.
Ctrl + Shift + P
β TypeScript: Restart TS Servertsconfig.app.jsonκ³Ό vite.config.tsμ @ aliasκ° λͺ¨λ μ€μ λμ΄ μλμ§λ νμΈν©λλ€.
ν¨ν€μ§ μ€μΉ μ¬λΆμ .env νμΌμ΄ μ‘΄μ¬νλμ§ νμΈν©λλ€.
npm install
npm run devνκ²½ λ³μ μ΄λ¦μ΄ VITE_λ‘ μμνλμ§ νμΈν©λλ€.
VITE_API_BASE_URL=https://api.example.com/apiVercel νκ²½ λ³μλ₯Ό μμ ν λ€μλ Redeployλ₯Ό μ§νν©λλ€.
React Routerμ SPA κ²½λ‘λ₯Ό Vercelμ΄ μ€μ νμΌ κ²½λ‘λ‘ ν΄μν΄μ λ°μν μ μμ΅λλ€.
νλ‘μ νΈ λ£¨νΈμ λ€μ vercel.jsonμ μΆκ°ν©λλ€.
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}@xyflow/react κΈ°λ³Έ CSSκ° importλμ΄ μλμ§ νμΈν©λλ€.
import '@xyflow/react/dist/style.css'μ μμΌλ‘ μ¬μ©ν κ²½μ° main.tsx λλ Studio μ§μ
νμΌμμ ν λ²λ§ importν©λλ€.
νμ¬ package.jsonμλ λ³λμ type-check μ€ν¬λ¦½νΈκ° μμ μ μμ΅λλ€.
νμ¬ λΉλ λͺ λ Ήμ TypeScript κ²μ¬κ° ν¬ν¨λμ΄ μμΌλ―λ‘ λ€μ λͺ λ Ήμ΄λ₯Ό μ¬μ©ν©λλ€.
npm run buildλ³λμ λͺ
λ Ήμ΄κ° νμν κ²½μ° package.jsonμ μλ μ€ν¬λ¦½νΈλ₯Ό μΆκ°ν μ μμ΅λλ€.
{
"scripts": {
"type-check": "tsc -b"
}
}λ¬Έμμ¬νμ ν Discord λλ Notionμ 곡μ λ νλ‘ νΈμλ μ±λμ μ΄μ©ν΄ μ£ΌμΈμ.