Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
f9a745d
feat: 플랫폼 연동 목록 mock 데이터 및 타입 추가
YermIm May 23, 2026
48f1464
feat: 플랫폼 연동 UI 및 라우드 연결
YermIm May 24, 2026
f3b4391
feat: 플랫폼 연동 UI 및 라우드 연결
YermIm May 24, 2026
ce93ffd
feat: 사이드바에 뱃지 추가
YermIm May 24, 2026
8693a0a
feat: skeleton ui
YermIm May 24, 2026
3986318
fix: 워크스페이스 설정페이지 MEMBER에게는 읽기전용으로 보이도록 수정권한 삭제
jjjsun May 27, 2026
c46e3d6
fix: 사용하지 않는 useIsAdmin 훅 파일제거
jjjsun May 27, 2026
917c1f3
style: disabled시 Textarea 텍스트컬러를 Input컬러와 동일하도록 수정
jjjsun May 27, 2026
a868385
fix: 사이드바 MEMBER/ADMIN 메뉴 필터링
jjjsun May 27, 2026
6d7c294
feat: 카드 세부사항 및 추후 연동 플랫폼 추가
YermIm Jun 2, 2026
c5f9ab9
chore: 머지 및 충돌 해결
YermIm Jun 3, 2026
276e955
chore: 주석 삭제
YermIm Jun 6, 2026
e3a8a6b
fix: 코드래빗 리뷰 반영
YermIm Jun 7, 2026
72ba2cf
refactor: IRoasRanking 타입을 provider.ts로 통합
Seojegyeong Jun 17, 2026
8a84416
refactor: 공통 dashboard 타입을 common.ts로 분리
Seojegyeong Jun 17, 2026
332bef6
refactor: IBudgetsResponse/IBudgetStatus를 IBudgetResponse로 통합
Seojegyeong Jun 17, 2026
e46b561
refactor: useOverviewBudget/usePlatformBudget를 useBudget으로 통합
Seojegyeong Jun 17, 2026
4cd1892
refactor: KPI 변환 로직을 metricsToKpis 유틸로 통합
Seojegyeong Jun 17, 2026
b47597b
refactor: 플랫폼 circle 로고 맵을 PLATFORM_CIRCLE_LOGO_MAP 상수로 추출
Seojegyeong Jun 17, 2026
a31f4c4
style: 플랫폼 로고 크기 h-8 w-8으로 통일
Seojegyeong Jun 17, 2026
9f0f161
style: rounded-[24px]를 Tailwind 토큰 rounded-3xl로 교체
Seojegyeong Jun 17, 2026
2feeb92
refactor: minute 문자열 파싱 로직을 parseMinuteToTimestamp 유틸로 추출
Seojegyeong Jun 17, 2026
c25d9cd
style: 불필요한 주석 제거
Seojegyeong Jun 17, 2026
d5334cc
refactor: AllPlatformTrafficChart parseMinuteToTimestamp 적용, usePlatf…
Seojegyeong Jun 17, 2026
1d2b586
fix: provider 키 정규화 및 parseMinuteToTimestamp 유효성 검증 추가, 장식용 로고 aria-h…
Seojegyeong Jun 17, 2026
72e0bc6
style: rounded-[24px]를 Tailwind 토큰 rounded-3xl로 교체
Seojegyeong Jun 17, 2026
c9bc8ba
setting: 팀 공용 Cursor 규칙 always.mdc 추가 및 private 규칙 제거
Seojegyeong Jun 17, 2026
b1abd22
fix: URL에 workspaceId 없을때 selectedOrgId 기준 role fallback 적용
jjjsun Jun 17, 2026
0e81d3e
style: base.css에서 disabled 버튼 cursor-not-allowed 처리
jjjsun Jun 17, 2026
fe025ce
fix: 워크스페이스 URL 진입시 선택 워크스페이스 서버 저장
jjjsun Jun 17, 2026
3564022
fix: 오타 수정 및 버튼 css 수정
jjjsun Jun 17, 2026
c9215a4
Merge pull request #234 from WhereYouAd/feature/#233
YermIm Jun 17, 2026
a22c63a
Merge pull request #246 from WhereYouAd/setting/#237
Seojegyeong Jun 18, 2026
d9ed691
Merge remote-tracking branch 'origin/develop' into refactor/#229
Seojegyeong Jun 18, 2026
a7e59f1
Merge pull request #245 from WhereYouAd/refactor/#229
Seojegyeong Jun 18, 2026
b1632a2
fix: 코드래빗 수정사항 반영
jjjsun Jun 18, 2026
402ecbc
Merge branch 'develop' into fix/#242
jjjsun Jun 18, 2026
2657b9d
fix: 충돌 해결시 생긴 버그 수정
jjjsun Jun 18, 2026
9372f28
refactor: queryKey 상수 중앙화
Seojegyeong Jun 18, 2026
cd0a2fb
refactor: AI 리포트 queryKey에서 accessToken 제거
Seojegyeong Jun 18, 2026
1b12d94
feat: 플랫폼 연동 목록 API 연동
YermIm Jun 18, 2026
3b09c71
feat: Google OAuth 시작 연동
YermIm Jun 18, 2026
d20e1dc
feat: Meta OAuth 시작 연동
YermIm Jun 18, 2026
18f490e
Merge pull request #247 from WhereYouAd/fix/#242
jjjsun Jun 18, 2026
4d9e2ee
Merge branch 'develop' of https://github.com/WhereYouAd/WhereYouAd-Fr…
Seojegyeong Jun 18, 2026
62bf30a
Merge pull request #248 from WhereYouAd/refactor/#238
Seojegyeong Jun 18, 2026
b00055d
feat: 타임라인 데이터 API 타입 매핑 정리
jjjsun Jun 20, 2026
b07f691
refactor: 지표 메타데이터 Registry 중앙화 및 미사용 mock 제거
Seojegyeong Jun 20, 2026
89f91d7
refactor: dead export 및 미사용 mock export 정리
Seojegyeong Jun 20, 2026
2cc35ac
refactor: PlatformDetailCard KPI를 metricsToKpis로 통일
Seojegyeong Jun 20, 2026
3bb4105
refactor: CTR 델ta 계산 수정 및 플랫폼 metrics 캐시 통합
Seojegyeong Jun 20, 2026
4e9e130
refactor: CTR ctrDelta 역산 계산 제거
Seojegyeong Jun 20, 2026
507c966
refactor: BudgetGaugeChart 예산 포맷 Registry 연동
Seojegyeong Jun 20, 2026
aaa45c0
refactor: 랭킹 증감 포맷 Registry 연동 및 미사용 profile 정리
Seojegyeong Jun 20, 2026
7291405
refactor: utils 도메인 폴더 정리 및 loadable lib 이동
Seojegyeong Jun 20, 2026
1564599
feat: UI 데이터 타입 정리
jjjsun Jun 20, 2026
6fb94e8
feat: 생성 모달 폼 스텁
jjjsun Jun 20, 2026
b30a98e
feat: 성과 요약 패널 데이터 스텁
jjjsun Jun 21, 2026
8821828
feat: mock데이터 생성
jjjsun Jun 21, 2026
08ee0ee
fix: 오타수정
jjjsun Jun 21, 2026
6471f34
fix: platform 타입을 기존에 같은 도메인 값인 dashboard와 동일한 유니온 타입으로 지정
jjjsun Jun 21, 2026
45fe9fe
fix: mock데이터 수정
jjjsun Jun 21, 2026
68b6df5
refactor: 비교 테이블 클릭수 열 교체 및 플랫폼 대시보드 로딩 정리
Seojegyeong Jun 21, 2026
0b77a58
docs: metricRegistry 구조 및 API 매핑 주석 추가
Seojegyeong Jun 21, 2026
8c3c164
feat: 랜딩페이지 GuideTimeline에 하드코딩된 숫자 모아두기
jjjsun Jun 21, 2026
c7a9036
feat: 날짜 헤더 UI 구현
jjjsun Jun 21, 2026
12eae8b
feat: 세로선과 바 올려둘 영역 UI 구현
jjjsun Jun 21, 2026
557f74d
feat: 타임라인 위 바 UI 구현
jjjsun Jun 21, 2026
1827fd5
feat: Storybook으로 UI구현한 조각 합치기
jjjsun Jun 21, 2026
648bd4d
chore: TimelineBar 이름 추가
jjjsun Jun 21, 2026
11368dd
feat: 성과 state 기준 수정 및 통일, 디자인 수정
jjjsun Jun 21, 2026
9dea3ea
fix: 코드래빗 수정사항 반영
jjjsun Jun 21, 2026
e122a08
style: kebabIcon 위치 위아래 중앙으로 변경, rounded 축소
jjjsun Jun 21, 2026
f387a5e
Merge pull request #251 from WhereYouAd/feature/#250
jjjsun Jun 22, 2026
1b2560d
feat: 기간설정 상수파일 생성
jjjsun Jun 22, 2026
eb14bff
feat: Naver 광고 계정 연동 API 연동
YermIm Jun 22, 2026
c4239f8
feat: 타임라인 기간 선택 컴포넌트 UI 구현
jjjsun Jun 22, 2026
ced9cfb
fix: 코드래빗 수정사항 반영
jjjsun Jun 22, 2026
5a9fa80
feat: 성과요약패널 기본 틀 UI 구현
jjjsun Jun 22, 2026
8b213cf
refactor: 지표 포맷 기준 통일 및 컨텍스트별 포맷 함수 제거
Seojegyeong Jun 23, 2026
efcaca6
docs: metricsToKpis 함수 설명 주석 추가 및 OVERVIEW_KPI_BINDINGS 필드 주석 보완
Seojegyeong Jun 23, 2026
b8ef3d7
fix: KRW 금액 포맷을 formatCurrencyRounded로 통일
Seojegyeong Jun 23, 2026
92ce58d
Merge pull request #258 from WhereYouAd/refactor/#239
Seojegyeong Jun 23, 2026
5258325
fix: 에러 처리 수정
YermIm Jun 23, 2026
2c53f42
refactor: queryClient 싱글턴 import를 useQueryClient() 훅으로 교체
Seojegyeong Jun 23, 2026
d7eed7c
fix: secretKey 제외
YermIm Jun 23, 2026
5a04d1f
fix: 미지원 provider 명시적 에러 처리
YermIm Jun 23, 2026
0411023
chore: develop 병합 및 충돌 해결
YermIm Jun 23, 2026
8f0e53a
Merge pull request #259 from WhereYouAd/refactor/#240
Seojegyeong Jun 23, 2026
d9b8102
refactor: retry 전략 세분화 — 4xx 즉시 실패, 5xx만 1회 재시도
Seojegyeong Jun 23, 2026
ce52414
refactor: invalidateQueries 반환값 묵시 버림 제거 — void 명시
Seojegyeong Jun 23, 2026
33dca40
fix: WorkspaceSwitcher setIsOpen 순서 교정 — 캐시 갱신 완료 후 드롭다운 닫기
Seojegyeong Jun 23, 2026
38b9718
refactor: invalidateQueries void → await 전환 — 모달 닫기가 후속인 케이스
Seojegyeong Jun 23, 2026
8896a8e
Merge pull request #260 from WhereYouAd/refactor/#241
Seojegyeong Jun 23, 2026
e2c05e5
fix: 바 너비 최소 1칸그려지도록 수정
jjjsun Jun 23, 2026
1440bfe
feat: 타임라인 성과 요약 패널 UI 구현 완료
jjjsun Jun 23, 2026
b20e752
feat: 성과요약 패널 디자인 수정
jjjsun Jun 23, 2026
7711a21
fix: 전체 화면일때 최대 너비 더 길게 수정
jjjsun Jun 23, 2026
11a6aa6
fix: 코드래빗 수정사항 반영
jjjsun Jun 23, 2026
ad295b6
Merge pull request #256 from WhereYouAd/feature/#254
jjjsun Jun 23, 2026
c4146d3
fix: 사이드바 아이콘 스타일 통일 및 접기 버튼 호버 크기 조정
Seojegyeong Jun 24, 2026
6ce7c60
Merge pull request #262 from WhereYouAd/bugfix/#249
Seojegyeong Jun 24, 2026
bdbceea
style: shadow-Soft-xs 삭제후 section 외곽 border 처리로 변경
jjjsun Jun 24, 2026
7803b95
style: KPI지표만 border대신 shadow-Soft로 변경, 내부 텍스트 왼쪽 마진 1추가
jjjsun Jun 24, 2026
d93b159
Merge pull request #255 from WhereYouAd/feature/#244
YermIm Jun 24, 2026
754b627
Merge branch 'develop' into feature/#252
jjjsun Jun 24, 2026
5a982f4
Merge branch 'develop' into feature/#257
jjjsun Jun 24, 2026
fb67e42
Merge pull request #253 from WhereYouAd/feature/#252
jjjsun Jun 25, 2026
902d09d
Merge pull request #261 from WhereYouAd/feature/#257
jjjsun Jun 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions .cursor/rules/always.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
description: WhereYouAd 팀 공용 Cursor 규칙 — 레포를 열면 자동 적용
alwaysApply: true
---

# WhereYouAd Frontend — 팀 공용 Cursor 규칙

## 강제 규칙 (에이전트 최우선)

1. **색**: `src/styles/tokens.css` `@theme` 토큰만. 토큰 **이름 변경·임의 색 추가 금지**.
2. **스타일링**: `var(--*)`·인라인 hex·임의 `bg-[#...]` **금지** → `bg-*` `text-*` `border-*` 유틸만. 조건부 클래스는 `twMerge`.
3. **SVG**: `fill`/`stroke="currentColor"`, 색은 `text-*`. React는 `*.svg?react` + `@/` import.
4. **"디자인 변경 금지"** 요청 시: **색상 클래스만** (spacing·타이포·DOM 변경 금지).
5. **상태**: UI → Zustand (`src/store/`) · 서버 → react-query (`src/hooks/`) · 폼 → RHF. 스토어에 서버 데이터·전역 폼값 금지.
6. **범위**: 요청·연 파일 기준 최소 diff. 요청 없는 파일 수정·리팩터·README 등 문서 생성 금지.
7. **커밋**: 사용자 요청 시만. 제목 **1줄** `type: subject` (commitlint). `push`·PR·`commit --amend`·`push --force`는 요청 없으면 금지.
8. **머지·리베이스 충돌**: UI·레이아웃·간격·타이포·`rounded` 등 **디자인은 현재 브랜치 우선**. API·타입·버그픽스는 합리적으로 합침. 색·토큰은 1–2 유지.

```tsx
// ❌ bg-[#4b74f5] style={{ color: "var(--color-primary-400)" }}
// ✅ twMerge("bg-primary-400", disabled && "opacity-50")

// ❌ <Icon fill="#1877f2" /> // ❌ useQuery를 컴포넌트에서 직접 정의
// ✅ <Icon className="text-platform-meta" /> // ✅ useCoreQuery (customQuery.ts)
```

---

## 코딩 패턴

### 데이터·API

- **API 호출**: `src/api/`만. `axiosInstance`(일반) / `authInstance`(쿠키·인증) 사용.
- **서버 상태 훅**: `useCoreQuery` · `useCoreMutation` (`src/hooks/customQuery.ts`). `useQuery`/`useMutation` 직접 사용 지양.
- **환경 변수**: `VITE_API_BASE_URL` 등 `import.meta.env.VITE_*`만. `.env` 커밋 금지.
- **목 데이터**: `*.mock.ts`로 분리. 프로덕션 API·훅에 mock 혼입 금지.

### 타입·import

- API·요청/응답: `I*` (예: `ILoginRequest`) · 유니온·옵션: `T*` · props: `I*Props`.
- 공통 타입 `src/types/` · 도메인별 `src/types/{도메인}/` · props 등 로컬 타입은 파일 상단.
- import는 `@/` 별칭. 저장 시 `eslint-plugin-simple-import-sort` 자동 정렬 (수동 정렬 불필요).

### UI·컴포넌트

- 버튼·입력·모달·카드 등은 `components/common/` **재사용 우선**. 없을 때만 도메인 폴더에 추가.
- 페이지 `pages/` · 조각 UI `components/{도메인}/` · 라우트·가드 `routes/`.
- 로딩: `components/common/skeleton/Skeleton` + 도메인 `*Skeleton.tsx`.
- 사용자 알림: `sonner` `toast`. 차트·외부 라이브러리 색도 `@theme` 토큰에 맞출 것.

---

## 프로젝트·환경

광고 성과·워크스페이스 관리 FE (2026 Capstone) · 팀: 서제경, 박재선, 임예림

| Core | React 19, TS, Vite, react-router-dom v7 |
| State | zustand · react-query · RHF + zod |
| Style | Tailwind v4 — `tokens.css` · `utilities.css` · `base.css` → `index.css` |
| Quality | ESLint, Prettier, husky, lint-staged, commitlint, Playwright |

**Node** v20 LTS · **pnpm** · `dev` / `build` / `lint` / `test:e2e` / `storybook`

**브랜치**: `main` · `develop` · `feature/#N` · `fix/#N` · `refactor/#N`

```
src/api assets components constants hooks layout lib pages routes store types utils
```

---

## Git·PR·Cursor 활용

**commit type**: `feat` `fix` `docs` `style` `refactor` `test` `chore` `ci` `setting`

**PR**: `[Type/#이슈번호] 작업 요약` · P1 필수 · P2 권장 · P3 제안 · P4 Nit

**팀원 프롬프트 팁** (규칙 대체 아님, 요청 품질용):

- 이슈 번호·브랜치·**관련 파일 @참조**를 함께 적기 (`@LandingGuide.tsx` 등).
- UI 작업 시 **"디자인 변경 금지"** / **"색만 변경"** 등 제약을 명시.
- API·타입 변경 시 백엔드 스펙·에러 케이스를 함께 전달.
- 작업 후 `pnpm run lint` 통과 확인. E2E는 `E2E_USER_EMAIL` / `E2E_USER_PASSWORD` 필요.
117 changes: 0 additions & 117 deletions .cursor/rules/private-always.mdc

This file was deleted.

6 changes: 3 additions & 3 deletions src/api/dashboard/overview.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ICommonResponse } from "@/types/common/common";
import type {
IBudgetsResponse,
IBudgetResponse,
IMetricsResponse,
IRoasRankingsParams,
IRoasRankingsResponse,
Expand All @@ -25,8 +25,8 @@ export const getOverview = async (
export const getBudget = async (
orgId: number,
providerType?: TProviderType,
): Promise<IBudgetsResponse> => {
const { data } = await axiosInstance.get<ICommonResponse<IBudgetsResponse>>(
): Promise<IBudgetResponse> => {
const { data } = await axiosInstance.get<ICommonResponse<IBudgetResponse>>(
`/api/dashboard/budgets`,
{ params: { orgId, ...(providerType ? { providerType } : {}) } },
);
Expand Down
32 changes: 32 additions & 0 deletions src/api/integration/google.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { ICommonResponse } from "@/types/common/common";

import { axiosInstance } from "@/lib/axiosInstance";

interface IGoogleLoginResponse {
redirectUrl: string;
}

/**
* Google Ads OAuth 시작.
*
* Accept: application/json → 302 Location을 JSON redirectUrl로 받은 뒤
* window.location으로 이동 (XHR이 Google에 직접 가지 않음).
*
* 로컬: vite dev middleware가 302 → JSON 변환
* 운영: 백엔드가 동일 JSON 응답 필요
*/
export async function startGoogleOAuthLogin(orgId: number): Promise<void> {
const { data } = await axiosInstance.get<
ICommonResponse<IGoogleLoginResponse>
>("/api/google/login", {
params: { orgId },
headers: { Accept: "application/json" },
});

const redirectUrl = data.data?.redirectUrl;
if (!redirectUrl) {
throw new Error("Google 연동 URL을 받지 못했습니다.");
}

window.location.assign(redirectUrl);
}
32 changes: 32 additions & 0 deletions src/api/integration/meta.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { ICommonResponse } from "@/types/common/common";

import { axiosInstance } from "@/lib/axiosInstance";

interface IMetaAuthUrlResponse {
authUrl: string;
}

/**
* Meta Ads OAuth 시작.
*
* Accept: application/json → authUrl(JSON) 또는 302 Location을 받은 뒤
* window.location으로 이동 (XHR이 Meta에 직접 가지 않음).
*
* 로컬: vite dev middleware가 302 → JSON 변환
* 운영: 백엔드가 동일 JSON 응답 필요
*/
export async function startMetaOAuthLogin(orgId: number): Promise<void> {
const { data } = await axiosInstance.get<
ICommonResponse<IMetaAuthUrlResponse>
>("/api/meta/auth-url", {
params: { orgId },
headers: { Accept: "application/json" },
});

const authUrl = data.data?.authUrl;
if (!authUrl) {
throw new Error("Meta 연동 URL을 받지 못했습니다.");
}

window.location.assign(authUrl);
}
17 changes: 17 additions & 0 deletions src/api/integration/naver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { ICommonResponse } from "@/types/common/common";
import type {
INaverConnectResponseData,
INaverCredentialsRequest,
} from "@/types/integration/naver";

import { axiosInstance } from "@/lib/axiosInstance";

export async function connectNaverAccount(
orgId: number,
body: INaverCredentialsRequest,
): Promise<void> {
await axiosInstance.post<ICommonResponse<INaverConnectResponseData>>(
`/api/platform/${orgId}/accounts/naver`,
body,
);
}
13 changes: 13 additions & 0 deletions src/api/integration/platformAccounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ICommonResponse } from "@/types/common/common";
import type { IPlatformAccountsResponseData } from "@/types/integration/platformConnection";

import { axiosInstance } from "@/lib/axiosInstance";

export const getPlatformAccounts = async (
orgId: number,
): Promise<IPlatformAccountsResponseData> => {
const { data } = await axiosInstance.get<
ICommonResponse<IPlatformAccountsResponseData>
>(`/api/platform/${orgId}/accounts`);
return data.data;
};
3 changes: 3 additions & 0 deletions src/assets/icon/sidebar/connect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading