작업 공간, 보드, 목록, 카드, 감사 로그/활동 및 구성원 역할을 모두 갖춘 엔드투엔드 풀스택과 트렐로 클론을 만드는 방법을 배웁니다.
- Tailwind
- React.js
- Next.js (14)
- Prisma
- MySQL
npx create-next-app@latest trello-clone
Need to install the following packages:
create-next-app@14.0.3
Ok to proceed? (y) y
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
npx shadcn-ui@latest init
✔ Would you like to use TypeScript (recommended)? … no / yes
✔ Which style would you like to use? › Default
✔ Which color would you like to use as base color? › Neutral
✔ Where is your global CSS file? … app/globals.css
✔ Would you like to use CSS variables for colors? … no / yes
✔ Where is your tailwind.config.js located? … tailwind.config.ts
✔ Configure the import alias for components: … @/components
✔ Configure the import alias for utils: … @/lib/utils
✔ Are you using React Server Components? … no / yes
✔ Write configuration to components.json. Proceed? … yes
✔ Writing components.json...
✔ Initializing project...
✔ Installing dependencies...
Success! Project initialization completed.
- 폴더와 관련한 Route 시스템 설명
- folder/page.tsx: /folder 의 page 표시
- (folder)/page.tsx: 폴더명이 없는것과 동일
- (folder)/layout.tsx: children 으로 ReactNode 를 선언해야 하위 폴더 적용(공통 작업 구현 이점)
- (folder)/folder1/page.tsx: /folder1 의 page 표시
- (folder)/folder2/page.tsx: /folder2 의 page 표시
- api/folder/route.ts: ts 로 파일을 생성
- /api/folder 로 route 에 있는 method 로 API 호출
- layout 추가
- navbar, footer 추가
- page 작업
- layout 안에 들어가는 ReactNode
- 컨텐츠 구성
- font, ui 구현
- Navbar 추가
- Footer 추가
- Logo 컴포넌트 추가
- svg 이미지 적용
- next/font/local
const headingFont = localFont({ src: "../public/fonts/font.woff2", }); 사용: cn("some class names", headingFont.className)
- next/font/google
const textFont = Poppins({ subsets: ["latin"], weight: [ "100", "200", "300", "400", "500", "600", "700", "800", "900", ], }); 사용: cn("some class names", textFont.className)
- 메타 데이터에 들어갈 name, description 추가
- 프로젝트 생성
- 디펜던시 설치
npm install @clerk/nextjs
- .env 작성
ClerkProvider
추가middleware
추가export default authMiddleware({ publicRoutes: ["/"] });
- authMiddleware
publicRoutes
추가
- authMiddleware
sign-in/up
페이지 추가- .env - Sign 관련 URL 추가
- Clerk 대시보드에서 Organization 활성화
- app/(platform)/(clerk)/select-org/[[...select-org]]/page.tsx 추가
- app/(platform)/(dashboard)/organization/[organizationId]/page.tsx 추가
- app/(platform)/(dashboard)/layout.tsx 추가
- middleware.ts
- afterAuth 추가
- components/ui/button.tsx
- variant primary 생성
- app/(platform)/(dashboard)/organization/layout.tsx 추가
- 사이드바 추가를 위한 상위 레이아웃
- app/(platform)/(dashboard)/_components/mobile-sidebar.tsx 추가
- app/(platform)/(dashboard)/organization/[organizationId]/_components/org-control.tsx 추가
- app/(platform)/(dashboard)/_components/sidebar.tsx 추가
- hooks/use-mobile-sidebar.ts 추가
- npm i usehooks-ts
- 타입스크립트로 작성되어 바로 사용할 수 있는 React 후크 라이브러리.
- npx shadcn-ui@latest add skeleton
- 콘텐츠가 로드되는 동안 플레이스홀더를 표시하는 데 사용합니다.
- npx shadcn-ui@latest add accordion
- 콘텐츠의 섹션을 각각 표시하는 세로로 쌓인 대화형 제목 집합입니다.
- npx shadcn-ui@latest add separator
- 콘텐츠를 시각적 또는 의미론적으로 구분합니다.
- npm i zustand
- 단순화된 플럭스 원리를 사용하는 작고 빠르며 확장 가능한 베어본 상태 관리 솔루션
- npx shadcn-ui@latest add sheet
- 대화 상자 구성 요소를 확장하여 화면의 기본 콘텐츠를 보완하는 콘텐츠를 표시합니다.
- app/(platform)/(dashboard)/organization/[organizationId]/settings/page.tsx 추가
- npx prisma init
- create database - mysql 데터베이스 생성
- prisma.prisma 모델(테이블) 추가
- app/(platform)/(dashboard)/organization/[organizationId]/page.tsx 수정
- app/(platform)/(dashboard)/organization/[organizationId]/board.tsx 추가
- app/(platform)/(dashboard)/organization/[organizationId]/form.tsx 추가
- app/(platform)/(dashboard)/organization/[organizationId]/form-input.tsx 추가
- npm i -D prisma
- npm i @prisma/client
- npm i zod
- npx shadcn-ui@latest add input
- lib/create-safe-action.ts 추가
- 서버 액션 관련 정의
- hooks/use-action.ts 추가
- 서버 액션 정의를 사용하는 훅
- 추상화된 액션을 사용해서 보드 만들기 리팩토링
- actions/create-board/index.ts 추가
- actions/create-board/schema.ts 추가
- actions/create-board/types.ts 추가
- app/(platform)/(dashboard)/organization/[organizationId]/form.tsx 수정
- app/(platform)/(dashboard)/organization/[organizationId]/form.tsx 수정
- FormInput, FormSubmit 교체
- Form 관련 컴포넌트 분리
- components/form/form-errors.tsx
- components/form/form-input.tsx
- components/form/form-submit.tsx
- npx shadcn-ui@latest add label
- app/(platform)/(dashboard)/organization/[organizationId] 폴더 파일 정리
- form 관련 컴포넌트 제거
- app/(platform)/(dashboard)/organization/[organizationId]/page.tsx 수정
- app/(platform)/(dashboard)/organization/[organizationId]/_components/info.tsx 추가
- 보드 정보
- app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx 추가
- components/hint.tsx 툴팁 추가
- components/form/form-popover.tsx 팝오버 추가
- components/ui/popover.tsx 수정
- PopoverClose 추가
- app/(platform)/layout.tsx 토스트 추가
- npx shadcn-ui@latest add tooltip
- npx shadcn-ui@latest add popover
- npm i sonner
- 토스트
- unsplash 앱 생성
- 이미지 제공
- lib/unsplash.ts 추가
- unsplash API 를 사용해서 이미지 가져오기
- components/form/form-picker.tsx 추가
- 랜덤 이미지 선택
- components/form/form-popover.tsx 수정
- form-picker 사용
- next.config.js 수정
- 이미지 remotePatterns 추가
- constants/images.ts 추가
- 기본 이미지 추가(오류 발생시 사용할 기본 이미지 추가)
- prisma/schema.prisma 모델 수정
- 모델 수정 후 prisma migrate
- npx prisma migrate reset -> yes
- npx prisma db push
- npx prisma generate
- 모델 수정 후 prisma migrate
- app/(platform)/(dashboard)/_components/navbar.tsx 수정
- navbar 에서도 board 를 만들수 있도록 FormPopover 로 버튼 감싸기
asChild
: 컴포넌트의 렌더링을 단일 자식 엘리먼트에 위임합니다.
- npm i unsplash-js
- app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx 수정
- BoardList 구현
- app/(platform)/(dashboard)/organization/[organizationId]/page.tsx 수정
- Suspense 추가 및 스켈레톤 UI 적용
Suspense
:- 무언가를 기다릴 때 사용합니다.
- children이 로딩되기 전에 fallback을 보여줄 수 있습니다.
- app/(platform)/(dashboard)/board/[boardId]/page.tsx 추가
- app/(platform)/(dashboard)/board/[boardId]/layout.tsx 추가
- 배경 이미지 추가(화면에 가득찬 이미지 추가)
<div className="relative h-full bg-no-repeat bg-cover bg-center" style={{backgroundImage: `url(${board.imageFullUrl})`}} >
- 배경 이미지 추가(화면에 가득찬 이미지 추가)
- app/(platform)/(dashboard)/board/[boardId]/_components/board-navbar.tsx 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/board-title-form.tsx 추가
- components/ui/button.tsx 수정
- transparent variant 추가
- components/ui/input.tsx 수정
- focus-visible:ring-offset-2 -> focus-visible:ring-offset-0 수정
- actions/delete-board 추가
- index.ts
- schema.ts
- types.s
- app/(platform)/(dashboard)/board/[boardId]/_components/board-navbar.tsx 수정
- 옵션 버튼 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/board-options.tsx 추가
- 옵션 팝오버
- 보드 삭제
- npm i lodash
- array, collection, date 등 데이터의 필수적인 구조를 쉽게 다룰 수 있게끔 하는데에 사용
- npm i -D @types/lodash
- prisma/schema.prisma 수정
- List, Card 모델 추가
- npx prisma migrate reset | npx prisma db push | npx prisma generate
- List 관련 컴포넌트 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-container.tsx
- app/(platform)/(dashboard)/board/[boardId]/_components/list-form.tsx
- app/(platform)/(dashboard)/board/[boardId]/_components/list-wrapper.tsx
- app/(platform)/(dashboard)/board/[boardId]/_components/list-form.tsx 수정
- DB에 리스트 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-container.tsx 수정
- app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx 추가
- 리스트를 구성하는 개별 아이템 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-header.tsx 추가
- 리스트 아이템 헤더
- actions/update-list 리스트 업데이트 액션 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-header.tsx 수정
- app/(platform)/(dashboard)/board/[boardId]/_components/list-options.tsx 추가
- 옵션 컴포넌트 생성
- Action 추가
- actions/delete-list
- actions/copy-list
- app/(platform)/(dashboard)/board/[boardId]/_components/list-header.tsx 수정
- 옵션 컴포넌트 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-header.tsx 수정
- app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx 수정
- 카드 컴포넌트 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/card-form.tsx 추가
- 카드 컴포넌트 구현
- components/form/form-textarea.tsx
- textarea form 컴포넌트 구현
- Action 추가
- actions/create-card
- app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx 수정
- CardItem 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx
- CardItem 컴포넌트 생성
- app/(platform)/(dashboard)/board/[boardId]/_components/card-form.tsx 수정
- 카드를 추가 할수 있도록 Action 연결
- npx shadcn-ui@latest add textarea
- useFormStatus()
- 마지막 form 제출의 상태 정보를 제공하는 훅입니다.
- app/(platform)/(dashboard)/board/[boardId]/_components/list-container.tsx 수정
- 컨테이너에 DragDropContext 추가, 리스트를 드래그 하기 위해 ListItem 에 Droppable 컴포넌트 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-item.tsx 수정
- 리스트 아이템을 드래그 할 수 있게 Draggable 추가
- 리스트 아이템의 카드 드래그 하기 위해 CardItem 영역에 Droppable 컴포넌트 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx 수정
- CardItem을 드래그 할 수 있게 Draggable 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/list-container.tsx 수정
- onDragEnd 구현으로 리스트 이동, 카드 이동, 카드를 다른 리스트로 이동등의 드래그앤드롭 기능 추가
- Actions 추가
- actions/update-list-order
- 리스트의 이동 시 데이터 저장
- actions/update-card-order
- 카드의 이동 시 데이터 저장
- app/(platform)/(dashboard)/board/[boardId]/_components/list-container.tsx 수정
- execute 실행 및 드래그로 순서 변경
- actions/update-list-order
- npm i @hello-pangea/dnd
- React 드래그 앤 드롭
- hooks/use-card-modal.ts 생성
- card modal 커스텀 훅 생성
- components/modals/card-modal/index.tsx 생성
- 공통으로 사용 할 CardModal 컴포넌트 추가
- use-card-modal 커스텀 훅을 사용해서 모달 구성
- components/providers/modal-provider.tsx 생성
- CardModal 을 감싸고 있는 컴포넌트
- app/(platform)/layout.tsx 수정
- 하위 페이지에서 공통으로 모달을 사용 할 수 있게 상위 layout 에 ModalProvider 컴포넌트를 추가
- app/(platform)/(dashboard)/board/[boardId]/_components/card-item.tsx 수정
- useCardModal 을 사용해서 카드 클릭시 모달이 뜨도록 변경
- components/ui/dialog.tsx 수정
- DialogOverlay(다이얼로그 박스 바깥 배경 영역) 색상 변경
- components/providers/query-provider.tsx 생성
- react-query 를 사용하기 위한 프로바이더
- app/(platform)/layout.tsx 수정
- QueryProvider 를 추가
- app/api/cards/[cardId]/route.ts 생성
- 카드 타이틀 조회용 Get API 추가
- lib/fetchers.ts 생성
- url 을 전달해서 응답을 받아오는 lib 추가
- components/modals/card-modal/index.tsx 수정
- API 로 타이틀 가져와서 표시
- components/modals/header.tsx 생성
- 카드모달 헤더 구성
- 스켈레톤 생성
- actions/update-card 생성
- 카드 타이틀 업데이트를 위한 action
- components/modals/header.tsx 수정
- 헤더에 카드 타이틀 업데이트 액션 연동
- npx shadcn-ui@latest add dialog
- npm i @tanstack/react-query
- TS/JS, React, Solid, Vue 및 Svelte를 위한 강력한 비동기 상태 관리
- Array.splice(start, deleteCount) : 엘리먼트를 배열에서 삭제하거나 그 자리에 새로운 엘리먼트 삽입, 반환값은 삭제된 엘리먼트
- components/modals/card-modal/description.tsx 생성
- textarea 추가
- components/modals/card-modal/actions.tsx 생성
- copy, delete 액션 추가
- components/modals/card-modal/index.tsx 수정
- Description 추가
- Actions 추가
- actions/update-card/schema.ts 수정
- schema title 옵셔널로 수정
- components/ui/button.tsx 수정
- variant - gray 추가
- size - inline 추가
- actions/copy-card 생성
- 카드 복사 기능
- actions/delete-card 생성
- 카드 삭제 기능
- components/ui/dialog.tsx 수정
- DialogContent - max-w-3xl 로 최대 넓이 수정
- prisma/schema.prisma 수정
- AuditLog 모델 추가
- npx prisma db push
- npx prisma generate
- lib/create-audit-log.ts 생성
- 로그 생성 lib 추가
- app/api/cards/[cardId]/logs/route.ts 생성
- 로그 정보 API 추가
- actions/create-card/index.ts 수정
- 카드 생성시 로그도 생성하도록 추가
- components/modals/card-modal/activity.tsx 생성
- 카드 다이얼로그 내 Activity 컴포넌트 추가
- lib/generate-log-message.ts 생성
- 로그정보를 기반으로 공통으로 데이터 format 을 적용
- components/activity-item.tsx 생성
- activity 정보 표시를 위한 컴포넌트 추가
- actions 수정
- board, list, card
- copy, delete, update 에 AuditLog 추가
- components/modals/card-modal/description.tsx 수정
- 로그 추가
- components/modals/card-modal/header.tsx 수정
- 로그 추가
- app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx 생성
- Activity 페이지 생성
- app/(platform)/(dashboard)/organization/[organizationId]/activity/_components/activity-list.tsx 생성
- Activity 리스트 컴포넌트 생성
- npx shadcn-ui@latest add avatar
- npm i date-fns
- prisma/schema.prisma 수정
- OrgLimit model 추가
- constants/boards.ts 생성
- 무료 보드 갯수 상수 추가
- lib/org-limit.ts 생성
- org 관련 정보를 db 에서 가져오는 작업
- app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx 수정
- 무료 보드 남은갯수 표시
- actions/create-board/index.ts 수정
- 보드 생성시 limit 증가
- limit 초과시 에러
- actions/delete-board/index.ts 수정
- 보드 삭제시 limit 감소
- lib/stripe.ts 생성
- stripe 사용 설정
- lib/subscription.ts 생성
- 구독 정보
- .env 수정
- stripe secret key 추가
- 기본 도메인 추가
- components/modals/pro-modal.tsx 생성
- pro 모달 생성
- hooks/use-pro-modal.ts 생성
- pro 모달 hook 생성
- components/providers/modal-provider.tsx 수정
- pro 모달 추가
- lib/utils.ts 수정
- 절대 주소 + path 함수 추가
- components/form/form-popover.tsx 수정
- 보드 생성 팝오버에 ProModal 추가
- actions/stripe-redirect 생성
- stripe 결제 정보 생성
- Stripe CLI Webhook 연결
- stripe login
- stripe listen --forward-to localhost:3000/api/webhook
- secret 복사
.env
: STRIPE_WEBHOOK_SECRET 에 scret 붙여넣기- middleware.ts 수정
publicRoutes: ["/", "/api/webhook"]
webhook 추가
- app/(platform)/(dashboard)/organization/[organizationId]/_components/board-list.tsx 수정
- 프로 버전 체크 및 Unlimited 적용
- actions/create-board/index.ts 수정
- 프로 버전 체크
- app/(platform)/(dashboard)/organization/[organizationId]/_components/info.tsx 수정
- Pro | Free 정보 받아서 표시
- Pro | Free 정보 표시
- app/(platform)/(dashboard)/organization/[organizationId]/page.tsx
- app/(platform)/(dashboard)/organization/[organizationId]/activity/page.tsx
- app/(platform)/(dashboard)/organization/[organizationId]/billing/page.tsx 생성
- Billing 페이지 추가
- app/(platform)/(dashboard)/organization/[organizationId]/billing/_components/subscription-button.tsx 생성
- Billing 페이지 구독/구독 관리 버튼 추가
- Stripe > Customer portal 테스트 링크 활성화
- Active test link
- npm i stripe
Stripe
- Stripe Project Account 생성
- Developer 탭 진입
- API Keys 정보 입력
- package.json 수정
- postinstall - prisma generate 추가
- vercel 배포