2026 상명대학교 졸업 프로젝트
분산된 광고 데이터를 하나의 대시보드로 광고 성과를 통합하고 AI가 분석해 드립니다
🏆 상명대학교 교내 창업아이디어 경진대회 대상
🏆 모두의 창업 공모전 1기 선정 · 본선 진출
WhereYouAd는 Google, Naver, Meta 3개 광고 플랫폼의 성과 데이터를 단일 대시보드에 통합하는 B2B SaaS입니다. 팀 단위 워크스페이스로 멤버가 협업하며, AI 분석 리포트를 생성하고 PDF로 저장할 수 있습니다.
WhereYouAd Frontend는 Vite + React 기반의 2026 캡스톤 졸업 프로젝트입니다. 실시간 차트, 워크스페이스 권한 관리, AI 스트리밍, SSE 기반 클릭 스트림 등 복잡한 상태와 비동기 흐름을 중심으로 인프라 레이어를 직접 설계·구현합니다.
- Google·Naver·Meta 통합 KPI 대시보드
- SSE 실시간 클릭 스트림 및 이상 트래픽 감지
- AI 분석 리포트 (요약·예산 추천·이메일 전송)
- 트래킹 링크 생성 (shortURL + UTM)
- 가상 광고 + 트래픽 시뮬레이터
- 팀 워크스페이스 + RBAC
- 기간별 상세 분석 타임라인
- Tech Stack
- Getting Started
- Scripts
- Environment Variables
- Project Structure
- CI/CD
- Conventions
- Contributors
| Category | Stack |
|---|---|
| Core | React 19, TypeScript 5.9, Vite 6.4 + @vitejs/plugin-react-swc |
| Routing | React Router DOM v7 |
| Server State | TanStack React Query v5 |
| Client State | Zustand v5 |
| HTTP | Axios |
| Form / Validation | React Hook Form, Zod v4 |
| Styling | Tailwind CSS v4 + @tailwindcss/vite |
| Animation | Framer Motion |
| Chart | ApexCharts |
| Toast | Sonner |
| AI Streaming | @microsoft/fetch-event-source (SSE + JWT 헤더 지원) |
| Markdown | react-markdown (AI 리포트 렌더링) |
| Test | Vitest (단위), Playwright (E2E) |
| Docs | Storybook 8 + Chromatic (시각 회귀) |
| Deploy | AWS S3 + CloudFront |
| Quality | ESLint v9 (flat config 4파일 분리), Prettier, Husky, lint-staged, Commitlint |
node -v
# v20.x.xnpm installnpm run devnpm run build| Command | Description |
|---|---|
npm run dev |
Vite 개발 서버를 실행합니다. |
npm run build |
TypeScript 빌드 후 Vite 프로덕션 빌드를 생성합니다. |
npm run lint |
ESLint로 전체 코드를 검사합니다. |
npm run preview |
빌드 결과를 로컬에서 미리 확인합니다. |
npm run prepare |
Husky Git hook을 설치합니다. |
npm run test |
Vitest로 단위 테스트를 실행합니다. |
npm run test:watch |
Vitest watch 모드로 실행합니다. |
src
├── api # 도메인별 axios 호출 함수 (순수 fetch 레이어)
│ ├── auth/ # 로그인·회원가입·토큰 재발급
│ ├── dashboard/ # overview, platform, aiAnalysis
│ ├── ads/ # 캠페인 목록·상세
│ ├── integration/ # Google/Naver/Meta OAuth 연동
│ └── workspace/ # 워크스페이스·멤버 관리
│
├── hooks # 도메인별 커스텀 훅
│ ├── customQuery.ts # useCoreQuery / useCoreMutation 추상화
│ ├── auth/
│ ├── dashboard/
│ ├── ads/
│ ├── common/
│ ├── integration/
│ └── sidebar/
│
├── lib # 앱 수준 인프라
│ ├── axiosInstance.ts # axios 인스턴스 + 401 refreshSubscribers 큐 패턴
│ ├── queryClient.ts # QueryClient (4xx 즉시 실패 / 5xx 1회 재시도)
│ ├── queryKeys.ts # QUERY_KEYS 중앙 상수 팩토리
│ └── loadable.tsx # React.lazy + Suspense 헬퍼 (code splitting)
│
├── store # Zustand 전역 상태
│ ├── useAuthStore.ts # accessToken 메모리 저장, isTokenInitialized
│ ├── useWorkspaceStore.ts # selectedOrgId, myRole
│ ├── useSidebarStore.ts # isCollapsed
│ └── useModalStore.ts # type-safe 전역 모달 레지스트리
│
├── utils
│ ├── dashboard/
│ │ ├── metricRegistry.ts # 지표 포맷·레이블 SSOT (16파일 → 1곳)
│ │ ├── metricsToKpis.ts # API 응답 → KPI 카드 Props 변환
│ │ └── downloadChart.ts
│ └── auth/
│
├── components
│ ├── common/ # Button, Card, Modal, Input 등 (+ .stories)
│ ├── dashboard/ # ai-report, charts, overview, platform
│ ├── sidebar/ # Sidebar, WorkspaceSwitcher
│ └── modal/ # ModalProvider, 전역 모달 컴포넌트
│
├── layout
│ ├── GlobalLayout.tsx # Toaster + ModalProvider + useTokenRefresh
│ ├── auth/AuthLayout.tsx
│ ├── main/MainLayout.tsx # Sidebar + 헤더 + Outlet
│ └── workspace/
│
├── pages # 라우트 단위 페이지
├── routes # createBrowserRouter + AuthGuard + RoleGuard
├── styles
│ ├── tokens.css # @theme {} 블록 디자인 토큰 (별도 config 파일 없음)
│ └── print.css
└── types # 도메인별 TypeScript 인터페이스
@/는 src/를 가리킵니다.
import { QUERY_KEYS } from "@/lib/queryKeys";
import { useCoreQuery } from "@/hooks/customQuery";| 워크플로 | 트리거 | 내용 |
|---|---|---|
ci.yaml |
PR → develop / main | ESLint lint → Vitest test → TypeScript build 검증 |
main.yaml |
push → main | S3 업로드 → CloudFront 캐시 무효화 → Discord 알림 |
chromatic.yml |
push → develop | Storybook 시각 회귀 테스트 (Chromatic) |
feature/#1-descriptionfix/#1-descriptionstyle/#1-descriptiondocs/#1-descriptionsetting/#1-descriptionrefactor/#1-description
Conventional Commits 규칙을 따릅니다. commitlint로 자동 검증됩니다.
feat: add AI analysis report streamingfix: prevent duplicate token reissue on parallel 401refactor: consolidate metric format logic into METRIC_REGISTRYdocs: update README
- PR 제목은
[Feature/#1] 작업 내용형식을 권장합니다. - GitHub Issue를 먼저 등록하고 PR 본문에
closes #이슈번호를 포함합니다. - 리뷰 기준은
.cursor/rules/always.mdc를 따릅니다.
- 저장 전 ESLint와 Prettier 규칙을 맞춥니다.
simple-import-sort규칙에 따라 import 순서를 유지합니다.api/,lib/는components/,pages/에 의존하지 않도록 import 방향을 지킵니다.- 서버 상태는 TanStack Query, UI 상태는 Zustand, 폼 상태는 React Hook Form으로 분리합니다.
- SVG는
vite-plugin-svgr를 통해 React 컴포넌트로 사용합니다.
프론트엔드 TEAM LEADER |
프론트엔드 |
프론트엔드 |