From 0989926f6eb948e28364d12f5bfbcc8814e48f3c Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 10 Apr 2026 22:28:45 +0900 Subject: [PATCH 1/4] =?UTF-8?q?refactor(analytics):=20provider=20=E2=86=92?= =?UTF-8?q?=20adapter=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/analytics/index.ts | 14 +++++++------- .../src/{providers => adapters}/amplitude.ts | 2 +- .../src/{providers => adapters}/console.ts | 2 +- .../analytics/src/{providers => adapters}/noop.ts | 2 +- packages/analytics/src/analytics.ts | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) rename packages/analytics/src/{providers => adapters}/amplitude.ts (95%) rename packages/analytics/src/{providers => adapters}/console.ts (86%) rename packages/analytics/src/{providers => adapters}/noop.ts (75%) diff --git a/packages/analytics/index.ts b/packages/analytics/index.ts index e940f80d..ad59b9ab 100644 --- a/packages/analytics/index.ts +++ b/packages/analytics/index.ts @@ -1,6 +1,6 @@ import { analytics } from './src/analytics'; -import { amplitudeProvider } from './src/providers/amplitude'; -import { consoleProvider } from './src/providers/console'; +import { amplitudeAdapter } from './src/adapters/amplitude'; +import { consoleAdapter } from './src/adapters/console'; export type { AnalyticsProvider, UserProperties } from './src/types'; export type * from './src/ampli'; @@ -13,16 +13,16 @@ interface InitAnalyticsOptions { export const initAnalytics = ({ apiKey, isDev }: InitAnalyticsOptions): void => { if (isDev || !apiKey) { - analytics.setProvider(consoleProvider); + analytics.setProvider(consoleAdapter); return; } try { - amplitudeProvider.init(apiKey); - analytics.setProvider(amplitudeProvider); + amplitudeAdapter.init(apiKey); + analytics.setProvider(amplitudeAdapter); } catch (error) { - console.error('[Analytics] Failed to initialize Amplitude, falling back to console provider', error); - analytics.setProvider(consoleProvider); + console.error('[Analytics] Failed to initialize Amplitude, falling back to console adapter', error); + analytics.setProvider(consoleAdapter); } }; diff --git a/packages/analytics/src/providers/amplitude.ts b/packages/analytics/src/adapters/amplitude.ts similarity index 95% rename from packages/analytics/src/providers/amplitude.ts rename to packages/analytics/src/adapters/amplitude.ts index 37a785fa..18009f6d 100644 --- a/packages/analytics/src/providers/amplitude.ts +++ b/packages/analytics/src/adapters/amplitude.ts @@ -2,7 +2,7 @@ import { Identify, identify, setUserId, reset, track, initAll } from '@amplitude import type { AnalyticsProvider, UserProperties } from '../types'; -export const amplitudeProvider: AnalyticsProvider = { +export const amplitudeAdapter: AnalyticsProvider = { init(apiKey: string) { initAll(apiKey, { analytics: { diff --git a/packages/analytics/src/providers/console.ts b/packages/analytics/src/adapters/console.ts similarity index 86% rename from packages/analytics/src/providers/console.ts rename to packages/analytics/src/adapters/console.ts index 5bf131a8..81ffc850 100644 --- a/packages/analytics/src/providers/console.ts +++ b/packages/analytics/src/adapters/console.ts @@ -1,6 +1,6 @@ import type { AnalyticsProvider } from '../types'; -export const consoleProvider: AnalyticsProvider = { +export const consoleAdapter: AnalyticsProvider = { init: (_apiKey) => console.log('[Analytics] init'), track: (name, props) => console.log('[Analytics] track', name, props ?? {}), identify: (userId, userProperties) => console.log('[Analytics] identify', { userId, ...userProperties }), diff --git a/packages/analytics/src/providers/noop.ts b/packages/analytics/src/adapters/noop.ts similarity index 75% rename from packages/analytics/src/providers/noop.ts rename to packages/analytics/src/adapters/noop.ts index 52b0062f..59007fe5 100644 --- a/packages/analytics/src/providers/noop.ts +++ b/packages/analytics/src/adapters/noop.ts @@ -1,6 +1,6 @@ import type { AnalyticsProvider } from '../types'; -export const noopProvider: AnalyticsProvider = { +export const noopAdapter: AnalyticsProvider = { init: () => {}, track: () => {}, identify: (_userId: string) => {}, diff --git a/packages/analytics/src/analytics.ts b/packages/analytics/src/analytics.ts index e49b2090..611c28f6 100644 --- a/packages/analytics/src/analytics.ts +++ b/packages/analytics/src/analytics.ts @@ -1,7 +1,7 @@ -import { noopProvider } from './providers/noop'; +import { noopAdapter } from './adapters/noop'; import type { AnalyticsProvider, UserProperties } from './types'; -let provider: AnalyticsProvider = noopProvider; +let provider: AnalyticsProvider = noopAdapter; export const analytics = { setProvider(newProvider: AnalyticsProvider): void { From b7143377e5e346688605d476697c4cc74baeb2a9 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 10 Apr 2026 22:28:48 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix(amplitude):=20AmplitudeProvider=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EB=B9=84=EC=9D=B8=EC=A6=9D=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20API=20=ED=98=B8=EC=B6=9C=20=EC=B0=A8?= =?UTF-8?q?=EB=8B=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/App.tsx | 20 ++++++------------- .../src/providers/AmplitudeProvider.tsx | 19 ++++++++++++++++++ apps/client/src/shared/apis/queries.ts | 1 + 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 apps/client/src/providers/AmplitudeProvider.tsx diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx index 9abf403b..adb15a6a 100644 --- a/apps/client/src/App.tsx +++ b/apps/client/src/App.tsx @@ -1,22 +1,14 @@ -import { analytics } from '@pinback/analytics'; import { router } from '@routes/router'; -import { useGetAmplitudeUserProperties } from '@shared/apis/queries'; -import { useEffect } from 'react'; +import AmplitudeProvider from 'src/providers/AmplitudeProvider'; import { RouterProvider } from 'react-router-dom'; import './App.css'; function App() { - const { data: userProperties } = useGetAmplitudeUserProperties(); - - useEffect(() => { - if (!userProperties) return; - analytics.identify( - String(userProperties.userId), - userProperties.jobRole ? { job_role: userProperties.jobRole } : undefined - ); - }, [userProperties]); - - return ; + return ( + + + + ); } export default App; diff --git a/apps/client/src/providers/AmplitudeProvider.tsx b/apps/client/src/providers/AmplitudeProvider.tsx new file mode 100644 index 00000000..2cf66bf1 --- /dev/null +++ b/apps/client/src/providers/AmplitudeProvider.tsx @@ -0,0 +1,19 @@ +import { analytics } from '@pinback/analytics'; +import { useGetAmplitudeUserProperties } from '@shared/apis/queries'; +import { useEffect, type PropsWithChildren } from 'react'; + +const AmplitudeProvider = ({ children }: PropsWithChildren) => { + const { data: userProperties } = useGetAmplitudeUserProperties(); + + useEffect(() => { + if (!userProperties) return; + analytics.identify( + String(userProperties.userId), + userProperties.jobRole ? { job_role: userProperties.jobRole } : undefined + ); + }, [userProperties]); + + return <>{children}; +}; + +export default AmplitudeProvider; diff --git a/apps/client/src/shared/apis/queries.ts b/apps/client/src/shared/apis/queries.ts index 7498dbb3..7e9d699f 100644 --- a/apps/client/src/shared/apis/queries.ts +++ b/apps/client/src/shared/apis/queries.ts @@ -229,6 +229,7 @@ export const useGetAmplitudeUserProperties = queryFn: getAmplitudeUserProperties, staleTime: Infinity, retry: false, + enabled: authStorage.hasAccessToken(), }); }; From 0f1a81035f550b500df833b0515c4a1fb3eb65e7 Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 10 Apr 2026 22:28:51 +0900 Subject: [PATCH 3/4] =?UTF-8?q?fix(auth):=20403=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=EC=97=90=EC=84=9C=20token=20refresh=20=EC=8B=9C=EB=8F=84=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/client/src/shared/apis/setting/axiosInstance.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/client/src/shared/apis/setting/axiosInstance.ts b/apps/client/src/shared/apis/setting/axiosInstance.ts index 8cd853a0..76f814ed 100644 --- a/apps/client/src/shared/apis/setting/axiosInstance.ts +++ b/apps/client/src/shared/apis/setting/axiosInstance.ts @@ -76,7 +76,7 @@ apiRequest.interceptors.response.use( if ( error.response && - (error.response.status === 401 || error.response.status === 403) && + error.response.status === 401 && !originalRequest._retry && !isNoAuth && !isLoginPage From 1696bb84b7103e632348982e3ca4758e4b1687fa Mon Sep 17 00:00:00 2001 From: constantly-dev Date: Fri, 10 Apr 2026 22:28:53 +0900 Subject: [PATCH 4/4] =?UTF-8?q?refactor(onboarding):=20GoogleCallback=20?= =?UTF-8?q?=EC=84=B8=EC=85=98=20=EC=A0=80=EC=9E=A5=20=EC=88=9C=EC=84=9C=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/onBoarding/GoogleCallback.tsx | 77 +++++++++---------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/apps/client/src/pages/onBoarding/GoogleCallback.tsx b/apps/client/src/pages/onBoarding/GoogleCallback.tsx index 6812524b..dacbcb9a 100644 --- a/apps/client/src/pages/onBoarding/GoogleCallback.tsx +++ b/apps/client/src/pages/onBoarding/GoogleCallback.tsx @@ -6,76 +6,71 @@ import { useQueryClient } from '@tanstack/react-query'; import { useEffect } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; +const REDIRECT_URI = import.meta.env.VITE_GOOGLE_REDIRECT_URI; + const GoogleCallback = () => { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const queryClient = useQueryClient(); - useEffect(() => { - const code = searchParams.get('code'); + const saveSession = (params: { + accessToken: string | null; + refreshToken: string | null; + email: string; + userId: string; + hasJob?: boolean; + }) => { + const { accessToken, refreshToken, email, userId, hasJob } = params; - if (!code) { - alert('로그인 실패. 다시 시도해주세요.'); - navigate('/onboarding?step=SOCIAL_LOGIN'); - return; + authStorage.setUserIdentity(email, userId); + + if (accessToken) { + authStorage.setAccessToken(accessToken); + extensionBridge.syncToken(accessToken); } - loginWithCode(code); - }, []); + if (refreshToken) { + authStorage.setRefreshToken(refreshToken); + } - const handleUserLogin = ( - isUser: boolean, - accessToken: string | null, - refreshToken: string | null, - hasJob?: boolean - ) => { - if (isUser) { - if (accessToken) { - authStorage.setAccessToken(accessToken); - extensionBridge.syncToken(accessToken); - } - - if (refreshToken) { - authStorage.setRefreshToken(refreshToken); - } - - if (typeof hasJob === 'boolean') { - authStorage.setHasJob(hasJob); - } - navigate('/'); - } else { - navigate('/onboarding?step=JOB'); + if (typeof hasJob === 'boolean') { + authStorage.setHasJob(hasJob); } }; - const redirectUri = import.meta.env.VITE_GOOGLE_REDIRECT_URI; - const loginWithCode = async (code: string) => { try { const res = await apiRequest.post( '/api/v3/auth/google', - { - code, - uri: redirectUri, - }, - { - withCredentials: true, - } + { code, uri: REDIRECT_URI }, + { withCredentials: true } ); const { isUser, userId, email, accessToken, refreshToken, hasJob } = res.data.data; - authStorage.setUserIdentity(email, userId); + saveSession({ accessToken, refreshToken, email, userId, hasJob }); queryClient.invalidateQueries({ queryKey: ['amplitudeUserProperties'] }); - handleUserLogin(isUser, accessToken, refreshToken, hasJob); + navigate(isUser ? '/' : '/onboarding?step=JOB'); } catch (error) { console.error('로그인 오류:', error); navigate('/onboarding?step=SOCIAL_LOGIN'); } }; + useEffect(() => { + const code = searchParams.get('code'); + + if (!code) { + alert('로그인 실패. 다시 시도해주세요.'); + navigate('/onboarding?step=SOCIAL_LOGIN'); + return; + } + + loginWithCode(code); + }, []); + return (