{"id":51262437,"url":"https://github.com/prgrms-fullcycle-devcourse/webfull_9_10_todam","last_synced_at":"2026-06-29T13:01:20.673Z","repository":{"id":359557658,"uuid":"1246479847","full_name":"prgrms-fullcycle-devcourse/webfull_9_10_todam","owner":"prgrms-fullcycle-devcourse","description":"당신의 작품이 머무는 시간, 토담","archived":false,"fork":false,"pushed_at":"2026-06-14T01:10:04.000Z","size":7463,"stargazers_count":2,"open_issues_count":7,"forks_count":0,"subscribers_count":0,"default_branch":"dev","last_synced_at":"2026-06-14T03:10:39.157Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://todam.app","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/prgrms-fullcycle-devcourse.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-22T08:28:43.000Z","updated_at":"2026-06-14T01:10:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/prgrms-fullcycle-devcourse/webfull_9_10_todam","commit_stats":null,"previous_names":["prgrms-fullcycle-devcourse/webfull_9_10_todam"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/prgrms-fullcycle-devcourse/webfull_9_10_todam","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prgrms-fullcycle-devcourse%2Fwebfull_9_10_todam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prgrms-fullcycle-devcourse%2Fwebfull_9_10_todam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prgrms-fullcycle-devcourse%2Fwebfull_9_10_todam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prgrms-fullcycle-devcourse%2Fwebfull_9_10_todam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/prgrms-fullcycle-devcourse","download_url":"https://codeload.github.com/prgrms-fullcycle-devcourse/webfull_9_10_todam/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/prgrms-fullcycle-devcourse%2Fwebfull_9_10_todam/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34927687,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-29T13:01:19.526Z","updated_at":"2026-06-29T13:01:20.665Z","avatar_url":"https://github.com/prgrms-fullcycle-devcourse.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg width=\"1680\" height=\"320\" alt=\"NotionCover\" src=\"https://github.com/user-attachments/assets/3bb70bc7-6f13-41d3-990f-e7fed0705569\" /\u003e\n\n# 토담 - 공방 원데이 클래스 예약 플랫폼 \u003cimg alt=\"todam_logo\" src=\"https://github.com/user-attachments/assets/4da1b0e6-9337-4124-9447-97ab7ccc4182\"  margin-right=\"10\" align=\"left\" width=\"100\"/\u003e\u003c/a\u003e\n\n![License](https://img.shields.io/badge/license-MIT-blue)\n\n\n\n\u003cdiv align=\"left\" margin-left=\"200\"\u003e\n\n\n토담은 사용자가 공방의 클래스를 탐색하고 예약하며,\u003cbr /\u003e 파트너는 공방, 클래스, 예약, 작품의 진행 상태를 유저에게 안내하고 관리할 수 있는 공방/예약 운영 플랫폼입니다.\n\n\u003c/div\u003e\n\n\u003cbr /\u003e\n\n## 🧩 Quick Link\n\n- 🏠 [서비스 바로가기](https://todam.app)\n- 🎬 [데모 영상](https://youtu.be/gK5Zry9Wcy4)\n- 📚 [전체 문서 보기](#-documents)\n\n\u003cbr /\u003e\n\n## 👋 Introduction\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=\"1920\" height=\"1080\" alt=\"1\" src=\"https://github.com/user-attachments/assets/f789e958-b483-4667-a53a-feaf20d97611\" /\u003e\n  \u003cimg width=\"1920\" height=\"1080\" alt=\"2\" src=\"https://github.com/user-attachments/assets/e7276a29-6adc-4511-9341-70f7943080ad\" /\u003e\n  \u003cimg width=\"1920\" height=\"1080\" alt=\"3\" src=\"https://github.com/user-attachments/assets/9768aa3f-1d2a-4d7b-b620-291d874d4927\" /\u003e\n  \u003cimg width=\"1920\" height=\"1080\" alt=\"4\" src=\"https://github.com/user-attachments/assets/8c980e2b-c5eb-4703-88e4-3764dbf90133\" /\u003e\n\u003c/p\u003e\n\ntodam은 공방 원데이 클래스를 찾고 예약하는 사용자, 공방을 운영하는 파트너, 서비스를 관리하는 운영자를 위한 흐름을 제공합니다.\n\n- **사용자**: 공방 및 클래스 탐색, 예약 신청, 작품 진행 상황 조회, 리뷰 작성\n- **파트너**: 공방 및 클래스 등록, 예약/일정 관리, 작품 진행 관리, 사업자 인증\n- **운영자**: 파트너 승인, 공방 검수, 신고 처리, 서비스 운영 관리\n\n\u003e **기간**: 2026.05.18 ~ 2026.06.18\u003cbr /\u003e\n\u003e **팀 구성**: FE 3명, BE 2명\n\n\u003cbr /\u003e\n\n## 🏛️ Architecture\n\n\u003cimg width=\"1563\" height=\"1006\" alt=\"system architecture (1)\" src=\"https://github.com/user-attachments/assets/76a8f3c3-53ae-4e7c-a13f-d390dd4eb079\" /\u003e\n\n- `web(Next.js)`은 클래스 참여자/파트너 화면을 제공하고, `api(NestJS)`는 인증·예약·작품·공방·알림 도메인을 처리합니다.\n- 데이터는 `RDS(PostgreSQL)`, 큐와 인증 코드는 `Redis`, 이미지는 `S3 presigned URL` 기반 업로드로 관리합니다.\n- 메일은 `AWS SES`, 웹 푸시는 `FCM`으로 발송하며, 배포는 GitHub Actions → ECR → EC2 흐름으로 진행합니다.\n\n\u003cbr /\u003e\n\n## 🧠 Key Design Points\n\n### 🔐 1. 역할별 접근 흐름 분리\n\n사용자, 파트너, 운영자 흐름을 분리하고 각 화면에서 필요한 권한만 노출합니다. 서버에서는 인증 상태, 파트너 승인 여부, 리소스 소유권을 함께 검증해 권한 상승을 방지합니다.\n\n### 📅 2. 예약 시점 타임슬롯 자동 생성\n\n공방 운영시간, 예약 간격, 예약 제한, 기존 예약 수를 기준으로 예약 가능한 시간을 계산합니다. 프론트엔드는 가능한 시간만 선택지로 보여주고, 서버는 예약 생성 시점에 타임슬롯을 생성한 뒤 다시 검증해 동시 예약 시에도 정원 초과 없이 처리합니다.\n\n### 🔄 3. 예약·작품 상태의 단일 기준\n\n예약 상태와 작품 제작 단계는 서버에서 `displayState`로 계산해 내려줍니다. 예를 들어 제작 중 구간은 건조·초벌·유약·재벌 단계까지 서버가 결정하고, 프론트엔드는 같은 응답 값을 사용자 화면, 마이페이지, 파트너 화면에서 일관되게 렌더링합니다.\n\n### 🔔 4. 알림과 사용자 피드백\n\n예약 확정, 취소, 작품 상태 변경 같은 이벤트는 인앱 알림과 웹 푸시로 전달합니다. 알림 발송은 비동기로 분리해 핵심 예약·작품 흐름이 외부 발송 실패에 영향을 받지 않도록 했습니다.\n\n### 🪪 5. 파트너 등록과 이미지 업로드\n\n파트너는 사업자등록증과 공방 이미지를 업로드해 공방 등록을 진행합니다. 이미지는 S3 presigned URL로 직접 업로드하고, 사업자등록증은 OCR과 진위확인 API를 통해 검증합니다.\n\n\u003cbr /\u003e\n\n## 🖥️ Tech Stack\n\n**Common**\n\n![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript\u0026logoColor=white)\n![Turborepo](https://img.shields.io/badge/Turborepo-EF4444?logo=turborepo\u0026logoColor=white)\n![pnpm](https://img.shields.io/badge/pnpm-F69220?logo=pnpm\u0026logoColor=white)\n\n**Frontend**\n\n![Next.js](https://img.shields.io/badge/Next.js%2016-000000?logo=nextdotjs\u0026logoColor=white)\n![React](https://img.shields.io/badge/React%2019-61DAFB?logo=react\u0026logoColor=black)\n![TanStack Query](https://img.shields.io/badge/TanStack%20Query-FF4154?logo=reactquery\u0026logoColor=white)\n![Zustand](https://img.shields.io/badge/Zustand-433E38?logo=react\u0026logoColor=white)\n![Tailwind CSS](https://img.shields.io/badge/Tailwind%20CSS%20v4-06B6D4?logo=tailwindcss\u0026logoColor=white)\n![Storybook](https://img.shields.io/badge/Storybook-FF4785?logo=storybook\u0026logoColor=white)\n\n**Backend**\n\n![NestJS](https://img.shields.io/badge/NestJS%2011-E0234E?logo=nestjs\u0026logoColor=white)\n![Prisma](https://img.shields.io/badge/Prisma%207-2D3748?logo=prisma\u0026logoColor=white)\n![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql\u0026logoColor=white)\n![Redis](https://img.shields.io/badge/Redis-DC382D?logo=redis\u0026logoColor=white)\n![BullMQ](https://img.shields.io/badge/BullMQ-E0234E?logo=redis\u0026logoColor=white)\n![JWT](https://img.shields.io/badge/JWT-000000?logo=jsonwebtokens\u0026logoColor=white)\n![Swagger](https://img.shields.io/badge/Swagger-85EA2D?logo=swagger\u0026logoColor=black)\n![Zod](https://img.shields.io/badge/Zod-3E67B1?logo=zod\u0026logoColor=white)\n\n**Infra \u0026 External**\n\n![AWS EC2](https://img.shields.io/badge/EC2-FF9900?logo=amazonec2\u0026logoColor=white)\n![AWS S3](https://img.shields.io/badge/S3-569A31?logo=amazons3\u0026logoColor=white)\n![AWS SES](https://img.shields.io/badge/SES-DD344C?logo=amazonsimpleemailservice\u0026logoColor=white)\n![Amazon RDS](https://img.shields.io/badge/RDS-527FFF?logo=amazonrds\u0026logoColor=white)\n![Nginx](https://img.shields.io/badge/Nginx-009639?logo=nginx\u0026logoColor=white)\n![Docker](https://img.shields.io/badge/Docker-2496ED?logo=docker\u0026logoColor=white)\n![GitHub Actions](https://img.shields.io/badge/GitHub%20Actions-2088FF?logo=githubactions\u0026logoColor=white)\n![Cloudflare](https://img.shields.io/badge/Cloudflare-F38020?logo=cloudflare\u0026logoColor=white)\n![Google Vision](https://img.shields.io/badge/Cloud%20Vision-4285F4?logo=googlecloud\u0026logoColor=white)\n![Firebase](https://img.shields.io/badge/FCM-FFCA28?logo=firebase\u0026logoColor=black)\n\n\u003cbr /\u003e\n\n## 📂 Directory Structure\n\n```text\ntodam/\n├── apps/\n│   ├── api/        # NestJS 백엔드\n│   ├── web/        # Next.js 클래스 참여자·파트너 서비스\n│   ├── admin/      # Vite 운영자 서비스\n│   └── storybook/  # 공통 UI 문서화\n├── packages/\n│   ├── shared/             # 공통 enum, type, schema, 상태 계산\n│   ├── ui/                 # web/admin 공통 UI 컴포넌트\n│   ├── config/             # 환경변수 검증\n│   ├── eslint-config/      # 공유 ESLint 설정\n│   └── typescript-config/  # 공유 TypeScript 설정\n├── docs/          # 요구사항, API, 실행 계획, 컨벤션 문서\n├── docker/        # 로컬/배포 인프라 구성\n└── scripts/       # 개발 보조 스크립트\n```\n\n\u003cbr /\u003e\n\n## 🗄️ Database Schema\n\n\u003cimg width=\"3757\" height=\"2445\" alt=\"todam (9)\" src=\"https://github.com/user-attachments/assets/fd3a40b8-c035-4299-98db-c953383ed283\" /\u003e\n\n\u003e 사용자는 공방과 클래스를 탐색해 예약을 생성하고, 예약 이후 작품 제작 상태, 배송, 리뷰, 알림 데이터가 연결됩니다.  \n\u003e 파트너는 공방과 클래스 운영 정보, 예약 가능 시간, 사업자 인증 정보, 작품 제작 진행 상태를 관리합니다.\n\n\u003cbr /\u003e\n\n## 📚 Documents\n\n- [기능 요구사항](docs/requirements.md)\n- [API 명세](docs/api/apispec.md)\n- [시스템 아키텍처](ARCHITECTURE.md)\n- [UI/디자인 규칙](DESIGN.md)\n- [코드/환경 컨벤션](docs/conventions/README.md)\n\n\u003cbr /\u003e\n\n## 👥 Contributors\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eProfile\u003c/th\u003e\n    \u003cth width=\"72\"\u003eName\u003c/th\u003e\n    \u003cth\u003eRole\u003c/th\u003e\n    \u003cth\u003eContributions\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"https://github.com/nogglee.png\" width=\"56\" alt=\"nogglee profile\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://github.com/nogglee\"\u003e이은지\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003eFE\u003c/td\u003e\n    \u003ctd\u003e디자인 시스템 · FSD 설계 · 파트너 전용 기능 · 인증 · 온보딩 게이트 · 알림 FCM · PWA · CI/CD · AI 자동화\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"https://github.com/codingguri.png\" width=\"56\" alt=\"codingguri profile\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://github.com/codingguri\"\u003e이승훈\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003eFE\u003c/td\u003e\n    \u003ctd\u003e공통 폼 · 인터랙션 UI · 로그인 · OAuth 플로우 · 온보딩 바텀시트 · 예약 시간 표기\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"https://github.com/yundlab.png\" width=\"56\" alt=\"yundlab profile\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://github.com/yundlab\"\u003e한윤지\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003eFE\u003c/td\u003e\n    \u003ctd\u003e공통 UI · FSD 정합 · 인증 · 공방 · 예약 FE · 작품 · 리뷰 · 마이 FE · MSW→실 BE 전환 주도\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"https://github.com/taesongxxxx.png\" width=\"56\" alt=\"taesongxxxx profile\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://github.com/taesongxxxx\"\u003e최태성\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003eBE\u003c/td\u003e\n    \u003ctd\u003eDB 스키마 · 마이그레이션 · 파트너 도메인 API 전체 · 타임슬롯 · 상태 전이 · OCR · 진위확인 게이트 · BE AWS 배포\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"https://github.com/chocofanta01.png\" width=\"56\" alt=\"chocofanta01 profile\" /\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://github.com/chocofanta01\"\u003e이재혁\u003c/a\u003e\u003c/td\u003e\n    \u003ctd align=\"center\"\u003eBE\u003c/td\u003e\n    \u003ctd\u003eAPI 계약 · 정합 문서화 · 회원 인증 · 소셜 OAuth · 공방 · 예약 · 작품 BE · 알림 BE 파이프라인\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprgrms-fullcycle-devcourse%2Fwebfull_9_10_todam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprgrms-fullcycle-devcourse%2Fwebfull_9_10_todam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprgrms-fullcycle-devcourse%2Fwebfull_9_10_todam/lists"}