Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/dx search params #103

Merged
merged 20 commits into from
Nov 26, 2024
Merged

Feature/dx search params #103

merged 20 commits into from
Nov 26, 2024

Conversation

guesung
Copy link
Owner

@guesung guesung commented Nov 26, 2024

Summary by CodeRabbit

릴리스 노트

  • 신규 기능

    • useSupabaseClientQuery 후크 추가: Supabase 클라이언트를 더 효율적으로 관리합니다.
    • ExtensionDialog 컴포넌트 추가: 확장 프로그램 설치 및 업데이트 알림을 사용자에게 제공합니다.
    • SearchParams 클래스 추가: 검색 매개변수를 쉽게 관리할 수 있도록 합니다.
    • LocalStorage 클래스 추가: 로컬 스토리지와의 상호작용을 단순화합니다.
  • 버그 수정

    • 여러 컴포넌트에서 Supabase 클라이언트 접근 방식을 개선하여 일관성을 높였습니다.
  • 문서화

    • 새로운 모듈 및 후크에 대한 설명 추가.
  • 리팩토링

    • 구성 상수 및 URL 관리 방식을 통합하여 코드 유지 관리성을 향상시켰습니다.

Copy link

coderabbitai bot commented Nov 26, 2024

Walkthrough

이 풀 리퀘스트는 여러 파일에 대한 변경 사항을 포함하며, 주요 변경 사항은 .coderabbit.yaml 파일의 base_branches 필드를 빈 배열에서 'master''develop'으로 업데이트한 것입니다. 또한, URL 관리 방식을 개선하고, Supabase 클라이언트와 관련된 여러 후크를 추가하거나 수정했습니다. 여러 구성 요소에서의 URL 및 상수 사용을 중앙 집중화하여 코드 유지 관리성을 높였습니다.

Changes

파일 경로 변경 요약
.coderabbit.yaml base_branches 필드를 []에서 ['master', 'develop']으로 업데이트
chrome-extension/lib/background/index.ts URL 관련 상수를 CONFIG 객체로 통합, chrome.runtime.onInstalled에서 로그인 페이지 URL 동적 변경
chrome-extension/utils/openai.ts OpenAI API 키를 CONFIG.openApiKey로 업데이트
package.json "test:jest": "vitest" 스크립트 추가, 새로운 의존성 추가 및 기존 의존성 업데이트
packages/shared/package.json ./utils/web 모듈의 내보내기 제거, ./modules/local-storage./modules/search-params 내보내기 추가
packages/shared/src/constants/*.ts 여러 상수를 CONFIG 객체로 통합
packages/shared/src/hooks/*.ts 여러 후크에서 Supabase 클라이언트 관리 방식을 변경
packages/web/package.json "type-check" 스크립트 추가, 의존성 제거
pages/web/src/app/[lng]/login/components/* 여러 컴포넌트에서 import 경로 업데이트 및 코드 리팩토링
packages/shared/src/modules/local-storage/*.ts LocalStorage 클래스 추가 및 관련 상수 정의
packages/shared/src/modules/search-params/*.ts SearchParams 클래스 추가 및 관련 타입 정의

Possibly related PRs

  • Feature: 최적화 #97: 이 PR은 README.md 파일의 업데이트를 포함하고 있으며, 주요 PR의 .coderabbit.yaml 구성 파일과는 직접적인 관련이 없습니다.
  • Feature/ux #101: 이 PR은 Extension.ts 파일의 변경 사항을 포함하며, 관련 값들을 통합하는 새로운 객체 EXTENSION을 도입합니다. 이는 .coderabbit.yaml 파일의 base_branches 필드와 관련된 구성 관리에 영향을 미칠 수 있습니다.

🐰 변화의 축제, 기쁨이 넘쳐나네!
새로운 가지, 새로운 길, 함께 나아가리!
코드의 흐름이 더욱 매끄럽고,
우리의 꿈이 현실로 다가오리!
마스터와 개발, 두 손을 맞잡고,
함께 나아가자, 더 밝은 미래로! 🌟

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/web/src/app/auth/callback/route.ts

Oops! Something went wrong! :(

ESLint: 8.57.0

ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct.

The config "next/core-web-vitals" was referenced from the config file in "/packages/web/.eslintrc.json".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@guesung
Copy link
Owner Author

guesung commented Nov 26, 2024

@coderabbitai full review

Copy link

coderabbitai bot commented Nov 26, 2024

✅ Actions performed

Full review triggered.

@guesung
Copy link
Owner Author

guesung commented Nov 26, 2024

@coderabbitai full review

Copy link

coderabbitai bot commented Nov 26, 2024

✅ Actions performed

Full review triggered.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 35

🧹 Outside diff range and nitpick comments (97)
packages/web/src/modules/search-params/constant.ts (1)

1-1: 각 검색 매개변수의 용도를 문서화하는 것이 좋겠습니다.

각 검색 매개변수(id, isWish, category)의 목적과 사용 사례를 설명하는 JSDoc 주석을 추가하면 코드의 유지보수성이 향상될 것 같습니다.

다음과 같이 문서화를 추가해보세요:

+/**
+ * 검색 매개변수 키 상수
+ * @constant
+ * @description
+ * - id: 메모의 고유 식별자
+ * - isWish: 찜 목록 여부
+ * - category: 메모의 카테고리
+ */
export const SEARCH_PARAMS_KEYS = ['id', 'isWish', 'category'] as const;
pages/side-panel/src/types/Input.ts (1)

1-4: 인터페이스에 문서화 추가 필요

인터페이스의 구조와 타입은 적절하게 정의되어 있습니다. 하지만 더 나은 개발자 경험을 위해 JSDoc 주석을 추가하는 것이 좋겠습니다.

다음과 같이 문서화를 추가해보세요:

+/**
+ * 메모 입력을 위한 인터페이스
+ * @property memo - 메모 내용
+ * @property isWish - 위시리스트 여부
+ */
export interface MemoInput {
  memo: string;
  isWish: boolean;
}
packages/shared/src/utils/Environment.ts (1)

1-3: 코드는 간단하고 명확해 보입니다.

중앙 집중식 설정 관리로의 전환이 잘 이루어졌습니다. 코드가 간단하면서도 목적이 명확합니다.

이러한 중앙 집중식 설정 관리 방식은 다음과 같은 이점이 있습니다:

  • 설정 값의 일관성 유지
  • 타입 안정성 향상
  • 설정 변경 시 유지보수 용이성
packages/web/src/app/[lng]/memos/types/Input.ts (2)

1-3: 타입 정의가 명확하고 간단합니다!

인터페이스가 잘 정의되어 있습니다. 다만, 카테고리 값의 유효성을 보장하기 위해 문자열 리터럴 유니온 타입 사용을 고려해보시는 것은 어떨까요?

예시:

export interface CategoryInput {
-  category: string;
+  category: 'work' | 'personal' | 'shopping' | 'etc';  // 실제 사용되는 카테고리 값으로 대체
}

5-7: 메모 입력 타입이 잘 정의되어 있습니다!

타입 정의가 명확하고 재사용 가능하도록 잘 설계되어 있습니다. 보안과 데이터 무결성을 위해 몇 가지 제안사항이 있습니다:

다음과 같은 개선사항을 고려해보세요:

export type MemoInput = {
-  memo: string;
+  memo: string & { length: 1 } | { maxLength: 1000 };  // 메모 길이 제한 추가
+  createdAt?: Date;  // 선택적으로 생성 시간 추가
};
packages/shared/src/constants/Cookie.ts (1)

1-5: 문서화 개선을 제안합니다.

각 쿠키 키의 용도와 예상되는 값 형식을 설명하는 JSDoc 주석을 추가하면 좋을 것 같습니다.

다음과 같이 문서화를 추가해보세요:

+/**
+ * 애플리케이션에서 사용되는 쿠키 키 상수들
+ * @property {string} accessToken - 사용자 인증 액세스 토큰을 위한 쿠키 키
+ * @property {string} refreshToken - 토큰 갱신을 위한 리프레시 토큰 쿠키 키
+ * @property {string} sideBarState - 사이드바 상태 저장을 위한 쿠키 키
+ */
 export const COOKIE_KEY = {
   accessToken: 'access_token',
   refreshToken: 'refresh_token',
   sideBarState: 'sidebar_state',
 };
chrome-extension/utils/openai.ts (1)

Line range hint 1-7: 환경 변수 사용을 고려해보세요.

프로덕션 환경에서는 API 키를 환경 변수로 관리하는 것을 권장드립니다. 이는 보안을 강화하고 다양한 환경에서의 설정 관리를 용이하게 만들 것입니다.

다음과 같은 방식을 고려해보세요:

import { CONFIG } from '@extension/shared/constants';
import OpenAI from 'openai';

export const openai = new OpenAI({
-  apiKey: CONFIG.openApiKey,
+  apiKey: process.env.OPENAI_API_KEY || CONFIG.openApiKey,
});
packages/shared/src/utils/String.ts (1)

1-4: 함수 이름 변경이 적절합니다만, 코드를 더 간결하게 만들 수 있습니다.

isStringArray에서 checkStringArray로의 이름 변경은 함수의 목적을 더 명확하게 표현합니다.

다음과 같이 코드를 더 간결하게 작성할 수 있습니다:

-export const checkStringArray = (value: unknown): value is string[] => {
-  if (Array.isArray(value) && value.every(item => typeof item === 'string')) return true;
-  return false;
-};
+export const checkStringArray = (value: unknown): value is string[] =>
+  Array.isArray(value) && value.every(item => typeof item === 'string');
packages/shared/src/constants/Supabase.ts (2)

5-5: 타입 안정성 개선 제안

schemaMemo 속성에만 as const를 적용하는 것보다, 객체 전체에 적용하는 것이 더 일관성 있습니다.


1-1: 상수 이름 컨벤션 제안

상수 객체의 이름이 SUPABASE인데, 일반적으로 타입스크립트에서는 이런 설정 객체의 경우 SupabaseConfig와 같은 명명이 더 일반적입니다.

packages/web/src/modules/local-storage/type.ts (1)

3-5: 타입 정의가 명확하고 잘 구조화되어 있습니다.

  • UpdateVersionType은 시맨틱 버저닝 패턴을 잘 따르고 있습니다.
  • LocalStorageKeyType은 기존 키들과 버전 타입을 효과적으로 통합했습니다.

다만, 각 타입의 용도와 예시를 JSDoc 주석으로 추가하면 더 좋을 것 같습니다.

다음과 같이 문서화를 추가해보세요:

+/**
+ * 업데이트 버전을 나타내는 문자열 타입
+ * @example 'updateVersion1.0.0', 'updateVersion2.1.3'
+ */
 export type UpdateVersionType = `updateVersion${number}.${number}.${number}`;

+/**
+ * 로컬 스토리지에서 사용되는 모든 키 타입
+ * @example 'guide', 'install', 'updateVersion1.0.0'
+ */
 export type LocalStorageKeyType = (typeof LOCAL_STORAGE_KEY)[number] | UpdateVersionType;
vitest.config.ts (2)

7-7: 테스트 파일 패턴을 더 포괄적으로 확장하는 것을 고려해보세요.

현재 *.test.ts 파일만 포함하고 있어, TypeScript와 JavaScript 테스트 파일을 모두 지원하도록 패턴을 확장하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안합니다:

-    include: ['**/*.test.ts'],
+    include: ['**/*.test.{js,jsx,ts,tsx}'],

4-10: 설정이 기본적인 테스트 환경을 적절히 구성하고 있습니다.

기본적인 Vitest 설정이 잘 구성되어 있습니다. 하지만 다음 설정들을 추가로 고려해보시기 바랍니다:

  • 테스트 환경 설정 (node/jsdom)
  • 코드 커버리지 리포트 설정
  • 테스트 타임아웃 설정

다음과 같은 추가 설정을 제안합니다:

 export default defineConfig({
   plugins: [react()],
   test: {
     include: ['**/*.test.ts'],
     globals: true,
+    environment: 'jsdom',
+    coverage: {
+      reporter: ['text', 'json', 'html'],
+    },
+    testTimeout: 10000,
   },
 });
packages/web/src/modules/search-params/type.ts (1)

4-5: 타입 안전성 개선을 위한 제안

SearchParamValueType을 키에 따라 더 구체적으로 정의하고, 튜플 대신 Record 타입을 사용하는 것을 고려해보세요.

-export type SearchParamValueType = string;
-export type SearchParamType = [SearchParamKeyType, SearchParamValueType];
+export type SearchParamValueType<T extends SearchParamKeyType> =
+  T extends 'isWish' ? 'true' | 'false' :
+  T extends 'category' ? 'work' | 'personal' | 'shopping' :
+  string;
+export type SearchParamType = Record<SearchParamKeyType, string>;
packages/shared/src/constants/Url.ts (2)

1-6: URL 상수들의 구조화가 잘 되었습니다!

타입 안정성을 더욱 강화하기 위해 TypeScript의 const assertion을 사용하는 것을 추천드립니다.

-export const URL = {
+export const URL = {
   guideKo: 'https://guesung.notion.site/8a740938aa6547b88d09dbab7cb2222b',
   guideEn: 'https://guesung.notion.site/10d89de02fde803c99c9e3027c2d10d5',
   googleForm: 'https://forms.gle/qHkL7PeknaCy5QfY6',
   chromeStore: 'https://chromewebstore.google.com/detail/web-memo/eaiojpmgklfngpjddhoalgcpkepgkclh',
-};
+} as const;

1-6: URL 상수들에 대한 문서화를 추가하면 좋을 것 같습니다.

각 URL의 용도와 목적을 명확히 하기 위해 JSDoc 주석을 추가하는 것을 제안드립니다.

+/**
+ * 애플리케이션에서 사용되는 외부 URL 상수들
+ * @property {string} guideKo - 한국어 가이드 문서 URL
+ * @property {string} guideEn - 영어 가이드 문서 URL
+ * @property {string} googleForm - 사용자 피드백 폼 URL
+ * @property {string} chromeStore - Chrome 웹 스토어 확장 프로그램 페이지 URL
+ */
export const URL = {
  guideKo: 'https://guesung.notion.site/8a740938aa6547b88d09dbab7cb2222b',
  guideEn: 'https://guesung.notion.site/10d89de02fde803c99c9e3027c2d10d5',
  googleForm: 'https://forms.gle/qHkL7PeknaCy5QfY6',
  chromeStore: 'https://chromewebstore.google.com/detail/web-memo/eaiojpmgklfngpjddhoalgcpkepgkclh',
};
packages/web/tsconfig.json (1)

15-15: 더 최신 버전의 ECMAScript 타겟 사용을 고려해보세요

ES2015는 상대적으로 오래된 버전입니다. 최신 브라우저들은 더 새로운 ECMAScript 버전을 지원하므로, 다음 사항들을 고려해보시기 바랍니다:

  1. ES2020 또는 그 이상의 버전을 타겟으로 설정하면 더 현대적인 JavaScript 기능들을 활용할 수 있습니다.
  2. 프로젝트의 브라우저 지원 요구사항을 확인하고, 그에 맞는 적절한 타겟을 선택하세요.

다음과 같이 수정하는 것을 제안드립니다:

-    "target": "ES2015"
+    "target": "ES2020"
pages/side-panel/src/utils/Url.ts (1)

1-10: URL 생성 로직 중복을 제거하는 것이 좋겠습니다.

두 함수가 비슷한 URL 생성 로직을 공유하고 있습니다. 이를 하나의 유틸리티 함수로 추출하면 코드 재사용성이 향상될 것 같습니다.

다음과 같은 리팩토링을 제안드립니다:

const createMemoUrl = (params: { id?: number; wish?: boolean }) => {
  const searchParams = new URLSearchParams();
  if (params.wish) searchParams.append('wish', 'true');
  if (params.id) searchParams.append('id', String(params.id));
  
  const query = searchParams.toString();
  return `${CONFIG.webUrl}/memos${query ? `?${query}` : ''}`;
};

export const getMemoUrl = (id?: number) => createMemoUrl({ id });
export const getMemoWishListUrl = (id?: number) => createMemoUrl({ id, wish: true });
packages/shared/src/hooks/extension/useSupabaseClientQuery.ts (1)

5-11: Suspense 동작에 대한 문서화가 필요합니다.

useSuspenseQuery를 사용함으로써 발생하는 Suspense 동작과 에러 처리 방식에 대한 주석 설명이 필요합니다.

다음과 같이 문서화를 추가하는 것을 제안드립니다:

+/**
+ * Supabase 클라이언트를 가져오는 훅입니다.
+ * 
+ * @remarks
+ * - Suspense를 사용하므로 상위에 Suspense 바운더리가 필요합니다.
+ * - 실패 시 1회 재시도합니다.
+ * - 에러 발생 시 ErrorBoundary로 처리되어야 합니다.
+ */
export default function useSupabaseClientQuery() {
packages/web/src/modules/local-storage/util.ts (2)

3-5: 에러 처리와 반환 타입을 개선하면 좋을 것 같습니다.

localStorage 작업은 실패할 수 있으므로, 에러 처리를 추가하고 반환 타입을 명시하는 것이 좋습니다.

다음과 같이 개선해보세요:

-export const setLocalStorageTrue = (key: LocalStorageKeyType) => {
+export const setLocalStorageTrue = (key: LocalStorageKeyType): boolean => {
+  try {
     LocalStorage.set(key, LOCAL_STORAGE_VALUE_MAP.true);
+    return true;
+  } catch (error) {
+    console.error(`로컬 스토리지 설정 실패: ${key}`, error);
+    return false;
+  }
 };

1-9: 전체적인 모듈 구조에 대한 제안

  1. 로컬 스토리지 작업에 대한 통합된 에러 처리 전략을 수립하는 것이 좋습니다.
  2. 이러한 유틸리티 함수들에 대한 단위 테스트 추가를 고려해주세요.
  3. 로컬 스토리지 키와 값에 대한 상수를 별도의 설정 파일로 분리하는 것을 추천드립니다.

단위 테스트 코드 작성에 도움이 필요하시다면 말씀해 주세요.

packages/web/src/modules/local-storage/LocalStorage.ts (1)

8-10: 값 유효성 검사 및 에러 처리가 필요합니다.

JSON.stringify 과정에서 발생할 수 있는 순환 참조나 기타 에러에 대한 처리가 필요합니다.

다음과 같이 개선하는 것을 제안합니다:

-  static set(key: LocalStorageKeyType, value: unknown) {
-    localStorage.setItem(key, JSON.stringify(value));
-  }
+  static set(key: LocalStorageKeyType, value: unknown): boolean {
+    try {
+      if (value === undefined) {
+        console.warn('undefined 값은 저장할 수 없습니다.');
+        return false;
+      }
+      localStorage.setItem(key, JSON.stringify(value));
+      return true;
+    } catch (error) {
+      console.error(`로컬 스토리지에 데이터 저장 중 오류 발생: ${key}`, error);
+      return false;
+    }
+  }
packages/web/src/constants/Config.ts (1)

3-7: 타입 정의와 문서화를 추가하면 좋을 것 같습니다.

다음과 같이 TypeScript 인터페이스와 JSDoc 주석을 추가하는 것을 제안드립니다:

+/** 애플리케이션 설정 값들을 정의하는 인터페이스 */
+interface AppConfig {
+  /** 웹 애플리케이션의 기본 URL */
+  webUrl: string;
+  /** Supabase 서비스 URL */
+  supabaseUrl: string;
+  /** Supabase 익명 인증 키 */
+  supabaseAnonKey: string;
+}

+/** 애플리케이션 전역 설정 */
-export const CONFIG = {
+export const CONFIG: AppConfig = {
   webUrl: getSafeConfig('NEXT_PUBLIC_WEB_URL', process.env.NEXT_PUBLIC_WEB_URL),
   supabaseUrl: getSafeConfig('NEXT_PUBLIC_SUPABASE_URL', process.env.NEXT_PUBLIC_SUPABASE_URL),
   supabaseAnonKey: getSafeConfig('NEXT_PUBLIC_SUPABASE_ANON_KEY', process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY),
 };
packages/web/src/hooks/useSupabaseClient.ts (2)

7-10: 에러 처리 및 타입 안전성 개선 필요

getSupabaseClientBrowser 함수의 안정성을 높이기 위한 개선사항을 제안드립니다:

다음과 같이 수정하는 것을 고려해보세요:

-function getSupabaseClientBrowser() {
+function getSupabaseClientBrowser(): MemoSupabaseClient {
   if (client) return client;
-  return getSupabaseClient();
+  try {
+    client = getSupabaseClient();
+    return client;
+  } catch (error) {
+    console.error('Supabase 클라이언트 초기화 실패:', error);
+    throw error;
+  }
 }

12-14: 구현이 적절하나, 정리(cleanup) 로직 추가 고려

현재 구현은 적절하지만, 컴포넌트 언마운트 시 클라이언트 연결을 정리하는 것이 좋을 수 있습니다.

다음과 같은 개선을 고려해보세요:

 function useSupabaseClient() {
-  return useMemo(getSupabaseClientBrowser, []);
+  const supabase = useMemo(getSupabaseClientBrowser, []);
+  useEffect(() => {
+    return () => {
+      // 필요한 경우 클라이언트 정리 로직 추가
+      if (client) {
+        client = undefined;
+      }
+    };
+  }, []);
+  return supabase;
 }
packages/shared/src/utils/extension/Storage.ts (1)

16-17: 쿠키 관리 로직 개선 제안

현재 구현은 잘 되어있지만, 다음과 같은 개선사항을 고려해보시면 좋을 것 같습니다:

  1. 쿠키 관련 작업을 위한 전용 훅이나 유틸리티 클래스 생성
  2. 에러 처리 로직 추가
  3. 타입 안전성을 위한 상수 타입 정의

이러한 개선사항들은 코드의 재사용성과 안정성을 높일 수 있습니다.

pages/content-ui/src/index.tsx (1)

Line range hint 1-15: 아키텍처 변경에 대한 제안

코드가 상당히 간소화되었으나, 개발 환경에서만 작동하는 기능(isProduction 체크)이 메인 로직에 직접 포함되어 있습니다. 이는 프로덕션/개발 환경의 분리가 명확하지 않을 수 있습니다.

다음과 같은 구조 개선을 제안드립니다:

+import { Environment } from '@extension/shared/types';
+
+const initializeDevTools = async () => {
+  attachShadowTree({
+    shadowHostId: OPEN_SIDE_PANEL_ID,
+    shadowTree: <OpenSidePanelButton />,
+  });
+};
+
+const initialize = async () => {
+  responsePageContent();
+  
+  if (!isProduction) {
+    await initializeDevTools();
+  }
+};
+
+initialize();

이렇게 변경하면:

  1. 개발 도구 관련 로직이 명확히 분리됩니다
  2. 초기화 프로세스가 더 체계적으로 관리됩니다
  3. 향후 환경별 기능 추가가 용이해집니다
packages/web/src/modules/search-params/useSearchParams.ts (3)

9-9: URL 생성 로직 개선 제안

getUrl 함수에서 검색 파라미터가 없는 경우에 대한 처리가 필요할 수 있습니다. 또한 URL 인코딩이 올바르게 처리되는지 확인이 필요합니다.

다음과 같이 개선을 제안합니다:

-  const getUrl = () => `${pathname}${searchParam.getSearchParams()}`;
+  const getUrl = () => {
+    const params = searchParam.getSearchParams();
+    return params ? `${pathname}${params}` : pathname;
+  };

11-14: 객체 스프레드 연산자 사용에 대한 주의사항

searchParam 객체를 스프레드하는 것은 타입 안전성을 저해할 수 있습니다. 필요한 메서드만 명시적으로 노출하는 것이 더 안전할 수 있습니다.

필요한 메서드만 명시적으로 반환하는 것을 고려해보세요:

return {
  get: searchParam.get.bind(searchParam),
  getAll: searchParam.getAll.bind(searchParam),
  add: searchParam.add.bind(searchParam),
  remove: searchParam.remove.bind(searchParam),
  getUrl,
};

4-15: 커스텀 훅의 메모이제이션 고려

useSearchParams 훅이 리렌더링될 때마다 새로운 객체와 함수를 생성합니다. 성능 최적화를 위해 메모이제이션을 고려해볼 수 있습니다.

다음과 같이 useMemouseCallback을 사용하여 최적화할 수 있습니다:

export default function useSearchParams() {
  const searchParams = useSearchParamsNext();
  const pathname = usePathname();

  const searchParam = useMemo(
    () => new SearchParams([...searchParams.entries()] as SearchParamType[]),
    [searchParams]
  );

  const getUrl = useCallback(
    () => `${pathname}${searchParam.getSearchParams()}`,
    [pathname, searchParam]
  );

  return useMemo(
    () => ({
      ...searchParam,
      getUrl,
    }),
    [searchParam, getUrl]
  );
}
packages/web/src/hooks/useGetExtensionManifest.ts (1)

5-17: 로딩 상태 관리 추가 제안

사용자 경험 향상을 위해 로딩 상태를 추가하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안합니다:

 export default function useGetExtensionManifest() {
   const [manifest, setManifest] = useState<chrome.runtime.Manifest | undefined | null>(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const [error, setError] = useState<Error | null>(null);

   useDidMount(() => {
     let isSubscribed = true;
     try {
+      setIsLoading(true);
       requestGetExtensionManifest(manifest => {
-        if (isSubscribed) setManifest(manifest);
+        if (isSubscribed) {
+          setManifest(manifest);
+          setIsLoading(false);
+        }
       });
     } catch (e) {
       if (isSubscribed) {
         setManifest(undefined);
+        setError(e instanceof Error ? e : new Error('알 수 없는 오류가 발생했습니다.'));
+        setIsLoading(false);
       }
     }
     return () => {
       isSubscribed = false;
     };
   });

-  return manifest;
+  return { manifest, isLoading, error };
 }
packages/shared/src/hooks/supabase/useSupabaseUser.ts (1)

16-19: 반환 구조를 최적화할 수 있습니다.

현재 구현에서는 query.data를 user로 다시 할당하고 있는데, 이는 불필요한 중복일 수 있습니다. 다음과 같은 개선을 고려해보세요:

  return {
    ...query,
-   user: query.data,
+   user: query.data.user
  };

이렇게 하면 user 객체에 직접 접근할 수 있어 사용성이 개선됩니다. 또한 다음과 같이 타입을 더 명확하게 지정할 수 있습니다:

type UseSupabaseUserReturn = {
  user: UserResponse['data']['user'];
} & Omit<UseSuspenseQueryResult<UserResponse, Error>, 'data'>;
packages/web/src/modules/local-storage/constant.ts (2)

1-3: 정규식 패턴의 가독성 개선이 필요합니다

정규식 패턴을 더 명확하고 유지보수하기 쉽게 분리하는 것이 좋을 것 같습니다.

다음과 같이 변경을 제안드립니다:

-const REGEXR_UPDATE_VERSION_VERSION = /^updateVersion\d+\.\d+\.\d+$/;
+const VERSION_PATTERN = '\\d+\\.\\d+\\.\\d+';
+const REGEXR_UPDATE_VERSION_VERSION = new RegExp(`^updateVersion(?<version>${VERSION_PATTERN})$`);

8-8: 각 키의 용도에 대한 문서화가 필요합니다

LOCAL_STORAGE_KEY 배열의 각 키가 어떤 목적으로 사용되는지 명확하지 않습니다. JSDoc 주석을 추가하여 각 키의 용도를 설명해주세요.

다음과 같이 문서화를 추가하는 것을 제안드립니다:

+/**
+ * 로컬 스토리지 키 목록
+ * @property guide - 사용자 가이드 표시 여부
+ * @property updateVersion - 앱 업데이트 버전 정보
+ * @property install - 앱 설치 상태
+ */
export const LOCAL_STORAGE_KEY = ['guide', 'updateVersion', 'install'] as const;
packages/web/src/app/[lng]/memos/page.tsx (1)

Line range hint 1-19: 성능 최적화를 위한 제안

서버 컴포넌트에서 메모 데이터를 가져오는 현재 구조는 적절하나, 다음과 같은 최적화를 고려해 보시기 바랍니다:

  • Next.js의 fetch cache 활용
  • 정적 메모 데이터에 대한 ISR(Incremental Static Regeneration) 적용 검토
packages/web/src/app/[lng]/login/page.tsx (1)

Line range hint 9-24: 에러 처리 개선 제안

현재 구현에서 getSupabaseClient()checkUserLogin() 호출 시 발생할 수 있는 예외 상황에 대한 처리가 누락되어 있습니다. 사용자 경험 향상을 위해 에러 처리를 추가하는 것이 좋을 것 같습니다.

다음과 같은 개선을 제안드립니다:

 export default async function page({ params: { lng } }: LanguageParams) {
-  const supabaseClient = getSupabaseClient();
-  const isUserLogin = await checkUserLogin(supabaseClient);
+  try {
+    const supabaseClient = getSupabaseClient();
+    const isUserLogin = await checkUserLogin(supabaseClient);
 
-  if (isUserLogin) redirect(PATHS.memos);
-  return (
-    <main className="relative flex h-full items-center justify-center">
-      <LoginSection lng={lng} />
-      <PersonalInformationInfo lng={lng} />
-    </main>
-  );
+    if (isUserLogin) redirect(PATHS.memos);
+    return (
+      <main className="relative flex h-full items-center justify-center">
+        <LoginSection lng={lng} />
+        <PersonalInformationInfo lng={lng} />
+      </main>
+    );
+  } catch (error) {
+    console.error('로그인 페이지 로드 중 오류 발생:', error);
+    return (
+      <main className="relative flex h-full items-center justify-center">
+        <div>로그인 페이지를 불러오는 중 문제가 발생했습니다. 잠시 후 다시 시도해 주세요.</div>
+      </main>
+    );
+  }
 }
packages/shared/tsconfig.json (1)

14-15: 빌드 출력 구성 개선사항

선언 파일 생성 및 출력 디렉토리 구성이 개선되었습니다:

  • 선언 맵 생성 활성화
  • 내부 구현 세부사항 제거
  • 일관된 출력 디렉토리 구조

이는 타입 정의 품질과 패키지 배포 구조를 개선합니다.

패키지 배포 시 package.jsontypes 필드가 dist 디렉토리를 올바르게 참조하는지 확인하세요.

Also applies to: 22-24

packages/web/src/modules/i18n/server.js (1)

Line range hint 6-21: 구현이 깔끔하나 문서화가 필요합니다.

전반적인 구현이 잘 되어 있으며, i18next의 모범 사례를 잘 따르고 있습니다. 다만, 다음 사항들에 대한 문서화를 추가하면 좋을 것 같습니다:

  • 각 함수의 파라미터 설명
  • 반환값 형식
  • 사용 예시

다음과 같은 JSDoc 문서화를 추가하는 것을 제안합니다:

+/**
+ * i18next 인스턴스를 초기화합니다.
+ * @param {string} lng - 사용할 언어 코드
+ * @param {string|string[]} ns - 사용할 네임스페이스
+ * @returns {Promise<i18n>} 초기화된 i18next 인스턴스
+ */
 const initI18next = async (lng, ns) => {

+/**
+ * 번역 유틸리티 함수와 i18next 인스턴스를 반환합니다.
+ * @param {string} lng - 사용할 언어 코드
+ * @param {string|string[]} ns - 사용할 네임스페이스
+ * @param {Object} options - 추가 옵션
+ * @param {string} [options.keyPrefix] - 키 접두사
+ * @returns {Promise<{t: TFunction, i18n: i18n}>} 번역 함수와 i18next 인스턴스
+ */
 export default async function useTranslation(lng, ns, options = {}) {
packages/shared/src/hooks/supabase/useCategoryPostMutation.ts (1)

10-10: 낙관적 업데이트 구현 제안

낙관적 업데이트를 구현하면 사용자 경험을 크게 향상시킬 수 있습니다. React Query의 onMutate를 활용하여 구현하는 것을 추천드립니다.

다음과 같이 구현할 수 있습니다:

 export default function useCategoryPostMutation({ supabaseClient }: UseCategoryPostMutationProps) {
   const queryClient = useQueryClient();
 
   return useMutation<CategorySupabaseResponse, Error, CategoryTable['Insert']>({
     mutationFn: postCategoryProps => insertCategory(supabaseClient, postCategoryProps),
+    onMutate: async (newCategory) => {
+      await queryClient.cancelQueries({ queryKey: QUERY_KEY.category() });
+      const previousCategories = queryClient.getQueryData(QUERY_KEY.category());
+      queryClient.setQueryData(QUERY_KEY.category(), (old: CategorySupabaseResponse[] = []) => [
+        ...old,
+        { ...newCategory, id: 'temp-id' },
+      ]);
+      return { previousCategories };
+    },
     onSuccess: () => {
       queryClient.invalidateQueries({ queryKey: QUERY_KEY.category() });
     },
+    onError: (err, newCategory, context) => {
+      queryClient.setQueryData(QUERY_KEY.category(), context?.previousCategories);
+    }
   });
 }
packages/shared/src/utils/Sentry.ts (1)

Line range hint 25-25: 릴리즈 버전 관리 개선 제안

현재 릴리즈 버전이 하드코딩되어 있습니다. 이를 package.json의 version 필드나 환경 변수를 통해 동적으로 관리하는 것이 좋습니다.

다음과 같은 방식으로 개선할 수 있습니다:

-    release: '0.3.1',
+    release: process.env.NEXT_PUBLIC_APP_VERSION || CONFIG.version,
packages/shared/src/hooks/supabase/useMemosQuery.ts (1)

Line range hint 13-23: 에러 처리에 대한 문서화가 필요합니다.

훅의 구현은 잘 되어있지만, 다음 사항들에 대한 문서화를 추가하면 좋을 것 같습니다:

  • 발생 가능한 에러 타입들
  • 에러 처리 방법
  • 재시도 정책

다음과 같은 JSDoc 문서를 추가하는 것을 제안드립니다:

+/**
+ * Supabase를 사용하여 메모 목록을 조회하는 훅
+ * @param supabaseClient - Supabase 클라이언트 인스턴스
+ * @param useQueryProps - React Query 옵션
+ * @throws {Error} 데이터베이스 연결 실패 시
+ * @throws {Error} 인증 오류 발생 시
+ * @returns {Object} 쿼리 결과 및 메모 데이터
+ */
export default function useMemosQuery({ supabaseClient, ...useQueryProps }: UseMemosQueryProps)
packages/web/src/app/[lng]/login/components/LoginSection/ExtensionVersion.tsx (2)

14-14: 조기 반환문을 더 명시적으로 개선하세요

현재 조기 반환문이 너무 간단하여 디버깅이 어려울 수 있습니다.

다음과 같이 개선하는 것을 고려해보세요:

-  if (!manifest) return;
+  if (!manifest) {
+    console.debug('확장 프로그램 매니페스트를 찾을 수 없습니다.');
+    return null;
+  }

17-19: 버전 비교 로직을 별도 함수로 분리하세요

버전 비교 로직을 컴포넌트에서 직접 처리하는 것보다 별도의 유틸리티 함수로 분리하면 재사용성과 테스트 용이성이 향상됩니다.

다음과 같은 구조를 제안합니다:

const isLatestVersion = (current: string, latest: string) => current === latest;

const getVersionMessage = (manifest: Manifest, t: TFunction) => {
  return isLatestVersion(manifest.version, EXTENSION.lastVersion)
    ? t('version.itIsLastVersion')
    : `${t('version.installedVersion')} : ${manifest.version} | ${t('version.lastVersion')} : ${EXTENSION.lastVersion}`;
};

그리고 컴포넌트에서는 다음과 같이 사용:

-      {manifest.version === EXTENSION.lastVersion
-        ? t('version.itIsLastVersion')
-        : `${t('version.installedVersion')} : ${manifest.version} | ${t('version.lastVersion')} : ${EXTENSION.lastVersion}`}
+      {getVersionMessage(manifest, t)}
packages/shared/src/constants/Config.ts (1)

6-17: 구성이 잘 중앙화되었습니다만, 문서화가 필요합니다.

환경 설정을 하나의 CONFIG 객체로 통합한 것은 좋은 접근 방식입니다. 하지만 각 설정 값의 용도와 예상되는 값에 대한 JSDoc 문서를 추가하면 좋을 것 같습니다.

다음과 같이 문서화를 추가하는 것을 제안합니다:

+/**
+ * 애플리케이션 전역 환경 설정
+ * @property {string} webUrl - 웹 애플리케이션 URL
+ * @property {string} supabaseUrl - Supabase 인스턴스 URL
+ * @property {string} supabaseAnonKey - Supabase 익명 인증 키
+ * @property {string} sentryDsn - Sentry 모니터링 DSN
+ * @property {string} sentryAuthToken - Sentry 인증 토큰
+ * @property {'development' | 'production'} nodeEnv - 현재 실행 환경
+ * @property {'development' | 'production'} makeWebhookNotionApi - Notion API 웹훅 환경
+ * @property {string} openApiKey - OpenAI API 키
+ */
 export const CONFIG = {
packages/shared/src/hooks/supabase/useMemoQuery.ts (1)

26-29: 타입 안정성을 개선할 수 있습니다.

반환 값의 타입을 명시적으로 정의하면 타입 안정성이 향상될 것 같습니다.

다음과 같이 개선해보시는 건 어떨까요?:

+interface MemoQueryResult {
+  memo: MemoSupabaseResponse['data'][number] | null;
+  isLoading: boolean;
+  isError: boolean;
+  error: Error | null;
+}
+
-return {
+return {
   ...query,
   memo: query.data,
-};
+} as MemoQueryResult;
packages/web/src/hooks/useLanguage.ts (2)

Line range hint 6-7: 몇 가지 개선 사항을 제안드립니다.

  1. REGEXR_PATHNAME_LANGAUGE 상수명에 오타가 있습니다 ('LANGAUGE' → 'LANGUAGE').
  2. useEffect의 의존성 배열에 pathname을 추가하는 것이 좋습니다.
  3. 정규식 매칭 결과에 대한 타입 안전성을 높일 수 있습니다.

다음과 같이 수정하는 것을 제안드립니다:

-const REGEXR_PATHNAME_LANGAUGE = /^\/(\w+)\/.+/;
+const REGEXR_PATHNAME_LANGUAGE = /^\/(\w+)\/.+/;

 useEffect(() => {
   const pathnameLanguage = pathname.match(REGEXR_PATHNAME_LANGAUGE)?.[1];
   
   if (!pathnameLanguage) return;
   
   setLanguage(pathnameLanguage as Language);
-}, []);
+}, [pathname]);

Line range hint 23-29: 언어 값 검증 로직 추가를 제안드립니다.

setLanguageRouter 함수에서 언어 값에 대한 유효성 검사가 없습니다. 잘못된 언어 값이 전달될 경우 사용자 경험에 영향을 줄 수 있습니다.

다음과 같은 개선을 제안드립니다:

 const setLanguageRouter = (value: Language) => {
+  const validLanguages = Object.values(Language);
+  if (!validLanguages.includes(value)) {
+    console.error(`Invalid language value: ${value}`);
+    return;
+  }
+
   const pathnameWithoutLanguage = pathname.match(REGEXR_PATHNAME_WITHOUT_LANGUAGE)?.[1];
 
   if (!pathnameWithoutLanguage) return;
packages/web/src/app/auth/callback-email/route.ts (1)

Line range hint 23-29: 심각: 리프레시 토큰이 잘못된 키로 저장되고 있습니다

COOKIE_KEY.sideBarState를 사용하여 리프레시 토큰을 저장하는 것은 심각한 문제입니다:

  1. 키 이름이 저장하는 데이터와 일치하지 않아 혼란을 야기할 수 있습니다
  2. 다른 부분에서 사이드바 상태를 읽으려고 할 때 리프레시 토큰이 노출될 수 있습니다

다음과 같이 수정하는 것을 제안합니다:

- cookieStore.set(COOKIE_KEY.sideBarState, sessionData.session.refresh_token, {
+ cookieStore.set(COOKIE_KEY.refreshToken, sessionData.session.refresh_token, {
packages/web/src/app/[lng]/memos/components/MemoView/index.tsx (1)

Line range hint 22-24: 메모 필터링 로직을 더 명확하게 개선할 수 있습니다.

현재 이중 느낌표(!!)를 사용한 불리언 변환이 다소 암시적입니다. 또한 필터링 로직을 더 명확하게 표현할 수 있습니다.

다음과 같이 개선해보세요:

  const filteredMemos = memos
-   ?.filter(memo => isWish === !!memo.isWish)
-   .filter(memo => (category ? memo.category?.name === category : true));
+   ?.filter(memo => isWish === Boolean(memo.isWish))
+   .filter(memo => !category || memo.category?.name === category);
packages/web/src/app/[lng]/memos/setting/component/Setting/index.tsx (1)

Line range hint 19-28: 접근성 개선을 위한 번역 키 추가 제안

SelectItem의 언어 텍스트("한글", "English")도 번역 시스템을 통해 관리하면 좋을 것 같습니다.

다음과 같이 수정을 제안드립니다:

          <SelectContent>
-            <SelectItem value="ko">한글</SelectItem>
-            <SelectItem value="en">English</SelectItem>
+            <SelectItem value="ko">{t('setting.language.korean')}</SelectItem>
+            <SelectItem value="en">{t('setting.language.english')}</SelectItem>
          </SelectContent>
packages/web/src/app/[lng]/memos/components/MemoSidebar/SidebarMenuItemAddCategory.tsx (1)

Line range hint 1-42: 전반적인 컴포넌트 구조에 대한 제안

컴포넌트의 기능성은 잘 구현되어 있지만, 다음과 같은 개선사항을 고려해보시기 바랍니다:

  1. 폼 제출 후 입력 필드 초기화
  2. 카테고리 생성 실패 시 에러 처리
  3. 입력 필드에 대한 유효성 검사 추가

다음과 같이 수정하는 것을 제안드립니다:

  const { register, handleSubmit } = useForm<CategoryInput>({
    defaultValues: {
      category: '',
    },
  });

- const { mutate: mutateCategoryPost } = useCategoryPostMutation({ supabaseClient });
+ const { mutate: mutateCategoryPost, isError } = useCategoryPostMutation({ supabaseClient });

- const onSubmit = handleSubmit(({ category }) => {
-   mutateCategoryPost({ name: category });
- });
+ const onSubmit = handleSubmit(({ category }) => {
+   mutateCategoryPost(
+     { name: category },
+     {
+       onSuccess: () => {
+         setIsEditMode(false);
+         reset();
+       },
+     }
+   );
+ });

  if (isEditMode)
    return (
      <form onSubmit={onSubmit}>
-       <Input {...register('category')} />
+       <Input
+         {...register('category', {
+           required: '카테고리명을 입력해주세요',
+           minLength: { value: 2, message: '최소 2자 이상 입력해주세요' },
+         })}
+         error={isError ? '카테고리 생성에 실패했습니다' : undefined}
+       />
      </form>
    );
packages/web/src/app/[lng]/memos/utils/guide.ts (2)

Line range hint 19-24: setInterval 정리가 필요합니다

setInterval이 생성되지만 정리되지 않고 있습니다. 메모리 누수를 방지하기 위해 cleanup이 필요합니다.

다음과 같이 수정을 제안드립니다:

        onPopoverRender: () => {
-         setInterval(() => {
+         const intervalId = setInterval(() => {
            requestGetSidePanelOpen(() => {
              if (driverObj.getActiveIndex() !== 0) return;
              driverObj.moveNext();
            });
          }, 500);
+         return () => clearInterval(intervalId);
        },

Line range hint 28-33: 플랫폼별 단축키 안내가 필요합니다

현재 Command + S 단축키는 macOS 사용자를 위한 안내입니다. Windows/Linux 사용자를 위해 Ctrl + S도 함께 안내하는 것이 좋겠습니다.

다음과 같이 수정을 제안드립니다:

-       description: `잘하셨어요 !\n이제 이 사이드 패널에서 메모를 기록하실 수 있답니다.\n메모를 입력하고, Command + S를 눌러 저장해보세요.\n메모 테두리가 파랑색 테두리에서 기본 테두리로 돌아왔다면 저장에 성공한 거에요!\n또한, 3초마다 자동으로 저장되니 안심하세요 ☺️`,
+       description: `잘하셨어요 !\n이제 이 사이드 패널에서 메모를 기록하실 수 있답니다.\n메모를 입력하고, Command + S (Windows/Linux의 경우 Ctrl + S)를 눌러 저장해보세요.\n메모 테두리가 파랑색 테두리에서 기본 테두리로 돌아왔다면 저장에 성공한 거에요!\n또한, 3초마다 자동으로 저장되니 안심하세요 ☺️`,
packages/web/src/app/components/Introduction.tsx (1)

21-23: URL 참조 방식이 개선되었습니다.

URL.chromeStore를 사용하는 방식으로 변경된 것이 적절합니다. 다만, 접근성 향상을 위해 버튼에 aria-label을 추가하는 것을 고려해보세요.

다음과 같이 aria-label을 추가하는 것을 제안합니다:

-<button className="btn btn-primary text-xl">chrome에 추가하기</button>
+<button className="btn btn-primary text-xl" aria-label="크롬 웹스토어에서 확장 프로그램 설치하기">chrome에 추가하기</button>
pages/side-panel/src/components/MemoHeader.tsx (1)

17-18: 메모 URL 처리 로직이 개선되었습니다.

getMemoUrl 함수를 사용하여 URL을 생성하는 방식이 더 모듈화되었습니다. 하지만 memoDataundefined일 때의 처리가 필요할 수 있습니다.

다음과 같이 안전한 처리를 추가하는 것을 고려해보세요:

-    const memoUrl = getMemoUrl(memoData?.id);
+    if (!memoData?.id) return;
+    const memoUrl = getMemoUrl(memoData.id);
packages/web/src/utils/middleware.ts (1)

쿠키 보안 설정이 일관되지 않습니다.

middleware.ts 파일의 쿠키 설정에서 보안 관련 옵션이 누락되어 있습니다. 다른 파일들(callback-email/route.ts)에서는 적절한 보안 설정을 사용하고 있으나, middleware에서는 이러한 보안 설정이 적용되지 않았습니다.

다음 보안 설정을 추가해야 합니다:

  • httpOnly: true
  • secure: process.env.NODE_ENV === 'production'
  • sameSite: 'lax'

특히 서버 쿠키 설정 부분(request.cookies.set)에서 options 매개변수가 완전히 누락되어 있습니다.

🔗 Analysis chain

Line range hint 12-26: 쿠키 보안 설정 검증이 필요합니다.

Supabase 클라이언트 초기화 부분이 CONFIG 객체를 사용하도록 잘 변경되었습니다. 하지만 쿠키 처리와 관련된 보안 설정을 검증해야 합니다.

다음 스크립트를 실행하여 쿠키 관련 보안 설정을 확인하세요:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 쿠키 보안 설정 검증

# 쿠키 옵션 설정 확인
rg -A 5 "cookies\.set.*options" 

# Supabase 설정 관련 파일 검색
fd -e ts -e js -x grep -l "createServerClient.*options"

Length of output: 508


Script:

#!/bin/bash
# Check cookie handling and security settings in middleware and related files

# Search for cookie-related code in middleware
rg -A 10 "createServerClient" packages/web/src/utils/middleware.ts

# Find Supabase client configuration
fd -e ts -e js -x rg -l "supabase.*config"

# Search for cookie options or security settings
rg -A 5 "cookie.*options|secure.*cookie|httpOnly|sameSite"

# Check if there are any other middleware files
fd middleware

Length of output: 3619

packages/web/src/middleware.ts (1)

Line range hint 9-42: 미들웨어 구현에 대한 개선 제안

전반적인 구현은 잘 되어있지만, 다음과 같은 개선사항을 고려해보시기 바랍니다:

  1. URL 조작 로직을 별도의 유틸리티 함수로 분리
  2. 언어 감지 로직에 대한 에러 처리 강화
  3. 타입 안전성 개선을 위한 상수 enum화 고려

다음과 같은 리팩토링을 제안드립니다:

+import { LanguageCode } from './types';

-const languages = ['ko', 'en'] as const;
+enum LanguageCode {
+  KO = 'ko',
+  EN = 'en'
+}

+function buildLocalizedUrl(url: URL, language: LanguageCode): URL {
+  return new URL(`/${language}${url.pathname}${url.search}`, url.href);
+}

또한 다음 사항들을 고려해보시기 바랍니다:

  • 언어 설정 변경 시 성능 최적화를 위한 캐싱 전략
  • 국제화 관련 설정의 중앙 관리를 위한 설정 파일 도입
packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts (3)

7-11: 타입 안전성 개선 제안

함수의 반환 타입이 명시적으로 정의되어 있지 않습니다. 타입 안전성을 높이기 위해 반환 타입을 명시적으로 정의하는 것이 좋습니다.

다음과 같이 개선할 수 있습니다:

export const getExtensionDialogInfo = (
  lng: Language,
  manifest: ReturnType<typeof useExtensionDialog>['manifest'],
  dialogType?: DialogType,
- ) => {
+ ): typeof EXTENSION_DIALOG_INFO_ALL[DialogType] | undefined => {

12-14: 오류 처리 개선 제안

dialogType이 없을 때 단순히 undefined를 반환하는 것보다 더 명시적인 처리가 필요할 수 있습니다.

다음과 같이 개선할 수 있습니다:

- if (!dialogType) return;
+ if (!dialogType) {
+   console.warn('dialogType이 제공되지 않았습니다.');
+   return undefined;
+ }

1-42: 테스트 및 에러 바운더리 추가 권장

이 유틸리티 함수에 대한 단위 테스트와 에러 바운더리가 필요합니다. 특히 다음 사항들을 고려해야 합니다:

  • 다양한 dialogType 값에 대한 테스트
  • 잘못된 manifest 데이터 처리
  • i18n 관련 에러 처리

테스트 코드 작성을 도와드릴까요?

packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts (3)

11-11: 타입 정의에 JSDoc 문서화 추가 제안

DialogType 타입에 대한 설명과 각 유니온 타입 값의 의미를 JSDoc으로 문서화하면 좋을 것 같습니다.

+/**
+ * 확장 프로그램 다이얼로그의 표시 유형을 정의합니다.
+ * @typedef {('install'|'update')} DialogType
+ * - 'install': 최초 설치 다이얼로그
+ * - 'update': 업데이트 알림 다이얼로그
+ */
 export type DialogType = 'install' | 'update';

24-33: 로컬 스토리지 키 상수화 및 에러 처리 개선이 필요합니다

로컬 스토리지 키를 문자열 리터럴로 사용하는 것은 오타의 위험이 있습니다. 또한, 로컬 스토리지 접근 시 발생할 수 있는 예외 처리가 필요합니다.

+const STORAGE_KEYS = {
+  INSTALL: 'install',
+  UPDATE: 'updateVersion'
+} as const;
+
-if (!isExtensionInstalled && !checkLocalStorageTrue('install')) {
+if (!isExtensionInstalled && !checkLocalStorageTrue(STORAGE_KEYS.INSTALL)) {
   setDialogType('install');
   setOpen(true);
   return;
 }
-if (isExtensionNotLastVersion && !checkLocalStorageTrue('updateVersion')) {
+if (isExtensionNotLastVersion && !checkLocalStorageTrue(STORAGE_KEYS.UPDATE)) {
   setDialogType('update');
   setOpen(true);
   return;
 }

41-48: 반환 타입 명시적 정의가 필요합니다

훅의 반환 타입을 명시적으로 정의하면 타입 안전성이 향상됩니다.

+interface ExtensionDialogHookReturn {
+  open: boolean;
+  setOpen: (open: boolean) => void;
+  dialogType: DialogType | undefined;
+  manifest: chrome.runtime.ManifestV3 | undefined | null;
+  handleClose: (localStorageKey: keyof typeof STORAGE_KEYS) => void;
+}
+
-export default function useExtensionDialog() {
+export default function useExtensionDialog(): ExtensionDialogHookReturn {
packages/web/src/app/[lng]/memos/layout.tsx (1)

24-24: 쿠키 키 접근 방식이 개선되었습니다.

COOKIE_KEY.sideBarState를 사용하는 방식으로 변경되어 타입 안정성이 향상되었습니다. 하지만 쿠키 값의 타입 검증이 필요할 수 있습니다.

다음과 같이 타입 안정성을 더욱 강화할 수 있습니다:

-  const defaultOpen = cookieStore.get(COOKIE_KEY.sideBarState)?.value === 'true';
+  const sideBarState = cookieStore.get(COOKIE_KEY.sideBarState)?.value;
+  const defaultOpen = sideBarState === 'true' || false;
packages/web/src/modules/i18n/locales/ko/translation.json (2)

37-42: 설치 다이얼로그의 메시지가 친절하고 명확합니다.

다만, 설치 취소 시의 제한사항이나 결과에 대한 안내 메시지를 추가하면 좋을 것 같습니다.

다음과 같이 취소 버튼의 텍스트를 수정하는 것을 제안드립니다:

-    "cancel": "설치하지 않고 이용하기",
+    "cancel": "설치하지 않고 이용하기 (일부 기능 제한)",

43-50: 버전 다이얼로그의 플레이스홀더 사용이 적절합니다.

{{currentVersion}}{{lastVersion}}의 플레이스홀더를 올바르게 사용하고 있습니다. 하지만 버전 비교를 위해 추가적인 메시지가 필요할 수 있습니다.

다음과 같은 메시지 추가를 제안드립니다:

     "description": "현재 버전 {{currentVersion}}에서 새로운 버전 {{lastVersion}}으로 업데이트할 수 있습니다.",
+    "versionCompare": "현재 버전보다 {{diffCount}}개의 업데이트가 있습니다.",
     "itIsLastVersion": "최신 버전입니다.",
packages/shared/src/hooks/supabase/useMemoPostMutation.ts (1)

Line range hint 15-35: 성공 핸들러의 에러 처리를 개선해주세요.

성공 핸들러 내부에서 발생할 수 있는 NoMemosError에 대한 처리가 누락되어 있습니다. 이는 뮤테이션 플로우를 중단시킬 수 있습니다.

다음과 같이 개선하는 것을 제안드립니다:

    onSuccess: async (result, variables, context) => {
+     try {
        const { data: newData } = result;

        await queryClient.cancelQueries({ queryKey: QUERY_KEY.memos() });

        const previousMemos = queryClient.getQueryData<MemoSupabaseResponse>(QUERY_KEY.memos());

        if (!previousMemos || !newData) throw new NoMemosError();

        const { data: previousMemosData } = previousMemos;

        if (!previousMemosData) throw new NoMemosError();

        const newMemosData = newData.concat(previousMemosData);

        await queryClient.setQueryData(QUERY_KEY.memos(), { ...previousMemos, data: newMemosData });

        useMutationProps.onSuccess?.(result, variables, context);

        return { previousMemos };
+     } catch (error) {
+       console.error('메모 업데이트 중 오류 발생:', error);
+       // 이전 상태로 복원하는 로직 추가 가능
+       throw error;
+     }
    },
packages/shared/src/utils/extension/Supabase.ts (1)

Line range hint 9-24: 메모리 관리 개선이 필요할 수 있습니다.

현재 구현에서는 함수가 호출될 때마다 새로운 Supabase 클라이언트 인스턴스가 생성됩니다. 이는 잠재적인 메모리 누수로 이어질 수 있습니다.

다음과 같은 싱글톤 패턴 구현을 고려해보세요:

+let supabaseClientInstance: Database | null = null;

 export const getSupabaseClient = async () => {
   try {
+    if (supabaseClientInstance) return supabaseClientInstance;
     
     const supabaseClientInstance = createClient<Database>...
packages/web/package.json (2)

Line range hint 1-57: 패키지 버전 업데이트 권장

일부 패키지들의 버전이 최신 버전과 차이가 있습니다. 보안 및 성능 향상을 위해 업데이트를 고려해보시기 바랍니다.

특히 다음 패키지들의 업데이트를 검토해보시면 좋겠습니다:

  • eslint (9.9.1)
  • next (14.2.10)
  • react (18.3.1)

@supabase/ssr 패키지 제거에 대한 마이그레이션 검토가 완료되었습니다.

코드베이스 분석 결과, @supabase/ssr 패키지가 여전히 사용되고 있으며 제거되지 않았음을 확인했습니다. 다음 파일들에서 해당 패키지를 import하여 사용 중입니다:

  • packages/web/src/utils/supabase.server.ts
  • packages/web/src/utils/middleware.ts
  • packages/web/src/utils/supabase.client.ts

따라서 package.json에서 해당 패키지가 제거된 것은 의도치 않은 실수로 보이며, 의존성을 다시 추가해야 합니다.

🔗 Analysis chain

Line range hint 1-57: 의존성 패키지들의 호환성 및 보안 검토가 필요합니다.

@supabase/ssr 패키지가 제거되었는데, 이와 관련된 기능들이 정상적으로 마이그레이션 되었는지 확인이 필요합니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 제거된 @supabase/ssr 패키지의 사용처를 검색하고 의존성 충돌을 확인합니다.

# @supabase/ssr 임포트 검색
echo "Checking for any remaining @supabase/ssr imports..."
rg "from ['\"']@supabase/ssr" 

# package-lock.json이나 yarn.lock에서 의존성 충돌 확인
echo "Checking for dependency conflicts in lock files..."
fd -e json -e lock

Length of output: 1716


Script:

#!/bin/bash
# Check the implementation of files using @supabase/ssr to understand the migration status
echo "Checking supabase.server.ts implementation..."
cat packages/web/src/utils/supabase.server.ts

echo -e "\nChecking middleware.ts implementation..."
cat packages/web/src/utils/middleware.ts

echo -e "\nChecking supabase.client.ts implementation..."
cat packages/web/src/utils/supabase.client.ts

# Search for any new Supabase client implementation that might have replaced @supabase/ssr
echo -e "\nChecking for alternative Supabase client implementations..."
rg "supabase" --type ts

Length of output: 19194

packages/web/src/modules/i18n/client.js (2)

Line range hint 13-23: 동적 import에 대한 에러 처리 개선이 필요합니다

현재 구현에서는 locale 파일의 동적 import 실패에 대한 처리가 없습니다. 사용자 경험 향상을 위해 에러 처리를 추가하는 것이 좋겠습니다.

다음과 같은 개선을 제안드립니다:

 .use(resourcesToBackend((language, namespace) => import(`./locales/${language}/${namespace}.json`)))
+.use(resourcesToBackend(async (language, namespace) => {
+  try {
+    return await import(`./locales/${language}/${namespace}.json`);
+  } catch (error) {
+    console.error(`Failed to load locale: ${language}/${namespace}`, error);
+    return {};
+  }
+}))

Line range hint 44-51: 쿠키 설정의 중앙화가 필요합니다

쿠키 설정 옵션이 직접 코드에 하드코딩되어 있습니다. 이러한 설정은 별도의 설정 파일로 분리하여 관리하는 것이 좋습니다.

설정을 분리하여 관리하는 방식을 제안드립니다:

+// cookieConfig.js
+export const COOKIE_CONFIG = {
+  path: '/',
+  maxAge: 365 * 24 * 60 * 60,
+  secure: process.env.NODE_ENV === 'production',
+  sameSite: 'strict',
+};

-    setCookie(cookieName, lng, {
-      path: '/',
-      maxAge: 365 * 24 * 60 * 60,
-      secure: process.env.NODE_ENV === 'production',
-      sameSite: 'strict',
-    });
+    setCookie(cookieName, lng, COOKIE_CONFIG);
packages/shared/src/utils/Supabase.ts (2)

Line range hint 26-31: 사용자 인증 관련 타입 안정성과 에러 처리를 개선해주세요.

checkUserLogin 함수에서 옵셔널 체이닝을 사용하고 있지만, 더 명확한 타입 가드와 에러 처리가 필요합니다.

다음과 같은 개선을 제안드립니다:

 export const checkUserLogin = async (supabaseClient: MemoSupabaseClient) => {
-  const user = await supabaseClient.auth.getUser();
-  return !!user?.data?.user;
+  try {
+    const { data: { user }, error } = await supabaseClient.auth.getUser();
+    if (error) throw error;
+    return !!user;
+  } catch (error) {
+    console.error('사용자 인증 확인 중 오류 발생:', error);
+    return false;
+  }
 };

Line range hint 32-37: 카테고리 테이블 참조 방식의 일관성이 필요합니다.

메모 작업에서는 SUPABASE.schemaMemo를 사용하는 반면, 카테고리 작업에서는 하드코딩된 문자열을 사용하고 있습니다.

다음과 같이 상수를 사용하도록 수정을 제안드립니다:

 export const getCategories = async (supabaseClient: MemoSupabaseClient) =>
-  supabaseClient.from('category').select('*').order('created_at', { ascending: false });
+  supabaseClient.from(SUPABASE.schemaCategory).select('*').order('created_at', { ascending: false });

 export const insertCategory = async (supabaseClient: MemoSupabaseClient, categoryRequest: CategoryTable['Insert']) =>
-  supabaseClient.from('category').insert(categoryRequest).select();
+  supabaseClient.from(SUPABASE.schemaCategory).insert(categoryRequest).select();
packages/shared/src/hooks/supabase/useMemoPatchMutation.ts (2)

13-15: 인터페이스에 JSDoc 문서를 추가하면 좋을 것 같습니다.

타입 정의는 잘 되어있지만, 인터페이스의 목적과 각 프로퍼티의 역할을 설명하는 문서가 있으면 더 좋을 것 같습니다.

다음과 같이 문서를 추가해보세요:

+/**
+ * useMemoPatchMutation 훅의 프로퍼티 인터페이스
+ * @property supabaseClient - Supabase 클라이언트 인스턴스
+ */
interface UseMemoPatchMutationProps extends UseMutationOptions<MutationData, MutationError, MutationVariables> {
  supabaseClient: MemoSupabaseClient;
}

Line range hint 17-39: 최적화 업데이트 로직을 별도 함수로 분리하면 좋을 것 같습니다.

onMutate 콜백 내부의 로직이 다소 복잡합니다. 이 로직을 별도의 유틸리티 함수로 분리하면 코드의 가독성과 테스트 용이성이 향상될 것 같습니다.

다음과 같은 리팩토링을 제안합니다:

+const updateMemoOptimistically = async (
+  queryClient: QueryClient,
+  id: MemoRow['id'],
+  memoRequest: MemoTable['Update']
+) => {
+  await queryClient.cancelQueries({ queryKey: QUERY_KEY.memos() });
+  const previousMemos = queryClient.getQueryData<MemoSupabaseResponse>(QUERY_KEY.memos());
+
+  if (!previousMemos) throw new NoMemosError();
+
+  const { data: previousMemosData } = previousMemos;
+
+  if (!previousMemosData) throw new NoMemosError();
+
+  const currentMemoIndex = previousMemosData.findIndex(memo => memo.id === id);
+  const currentMemoBase = previousMemosData.find(memo => memo.id === id);
+
+  if (currentMemoIndex === -1 || !currentMemoBase) throw new NoMemoError();
+
+  previousMemosData.splice(currentMemoIndex, 1, { ...currentMemoBase, ...memoRequest });
+
+  await queryClient.setQueryData(QUERY_KEY.memos(), { ...previousMemos, data: previousMemosData });
+
+  return { previousMemos };
+};

export default function useMemoPatchMutation({ supabaseClient, ...useMutationProps }: UseMemoPatchMutationProps) {
  const queryClient = useQueryClient();

  return useMutation<MutationData, MutationError, MutationVariables>({
    ...useMutationProps,
    mutationFn: async ({ id, memoRequest }) => await updateMemo(supabaseClient, id, memoRequest),
-    onMutate: async ({ id, memoRequest }) => {
-      await queryClient.cancelQueries({ queryKey: QUERY_KEY.memos() });
-      const previousMemos = queryClient.getQueryData<MemoSupabaseResponse>(QUERY_KEY.memos());
-
-      if (!previousMemos) throw new NoMemosError();
-
-      const { data: previousMemosData } = previousMemos;
-
-      if (!previousMemosData) throw new NoMemosError();
-
-      const currentMemoIndex = previousMemosData.findIndex(memo => memo.id === id);
-      const currentMemoBase = previousMemosData.find(memo => memo.id === id);
-
-      if (currentMemoIndex === -1 || !currentMemoBase) throw new NoMemoError();
-
-      previousMemosData.splice(currentMemoIndex, 1, { ...currentMemoBase, ...memoRequest });
-
-      await queryClient.setQueryData(QUERY_KEY.memos(), { ...previousMemos, data: previousMemosData });
-
-      return { previousMemos };
-    },
+    onMutate: async ({ id, memoRequest }) => 
+      await updateMemoOptimistically(queryClient, id, memoRequest),
  });
}
packages/web/src/app/[lng]/memos/components/legacy/MemoTable.tsx (1)

Line range hint 44-46: 삭제 버튼의 UX 개선이 필요합니다.

현재 삭제 버튼이 단순히 'x'로만 표시되어 있어 사용자 경험이 부족합니다. 다음과 같은 개선을 제안드립니다:

-              <button type="button" onClick={() => handleDeleteClick(memo.id)} className="w-full text-center">
-                x
-              </button>
+              <button
+                type="button"
+                onClick={() => handleDeleteClick(memo.id)}
+                className="btn btn-error btn-sm w-full text-center"
+              >
+                삭제
+              </button>

추가로 고려해볼 사항들:

  1. 삭제 중 로딩 상태 표시
  2. 기본 confirm 대신 모달 사용
  3. 실수로 인한 삭제 방지를 위한 추가 확인 절차
packages/web/src/app/components/ExtensionDialog/index.tsx (1)

34-51: 접근성 개선이 필요합니다.

다이얼로그 컴포넌트의 접근성을 개선할 수 있습니다.

다음과 같은 개선사항을 제안드립니다:

<Dialog open={open} onOpenChange={setOpen}>
-  <DialogContent>
+  <DialogContent aria-describedby="dialog-description">
    <DialogHeader>
      <DialogTitle>{extensionDialogInfo.message.title}</DialogTitle>
-     <DialogDescription>{extensionDialogInfo.message.description}</DialogDescription>
+     <DialogDescription id="dialog-description">{extensionDialogInfo.message.description}</DialogDescription>
    </DialogHeader>
    <DialogFooter>
      {extensionDialogInfo.message.cancel && (
-       <Button onClick={handleCloseClick} variant="secondary">
+       <Button onClick={handleCloseClick} variant="secondary" aria-label={extensionDialogInfo.message.cancel}>
          {extensionDialogInfo.message.cancel}
        </Button>
      )}
-     <Button onClick={handleUpdateClick}>{extensionDialogInfo.message.ok}</Button>
+     <Button onClick={handleUpdateClick} aria-label={extensionDialogInfo.message.ok}>{extensionDialogInfo.message.ok}</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>
packages/web/src/modules/search-params/SearchParams.ts (3)

6-14: 생성자의 null 체크 최적화가 필요합니다.

12번 라인의 옵셔널 체이닝은 불필요합니다. 10번 라인에서 Set이 생성되었음이 보장되므로, non-null 단언을 사용할 수 있습니다.

다음과 같이 수정하는 것을 제안합니다:

- this.#searchParamsMap.get(key)?.add(value);
+ this.#searchParamsMap.get(key)!.add(value);

16-23: get 메서드의 동작을 명확히 문서화해주세요.

get 메서드가 첫 번째 값만 반환하는 것은 예상치 못한 동작을 초래할 수 있습니다.

메서드 위에 다음과 같은 JSDoc 주석 추가를 제안합니다:

/**
 * 주어진 키에 대한 첫 번째 값을 반환합니다.
 * 여러 값이 있는 경우 첫 번째 값만 반환되며, 값이 없는 경우 빈 문자열을 반환합니다.
 */

25-45: add 메서드에도 동일한 null 체크 최적화가 필요합니다.

29번 라인의 옵셔널 체이닝도 불필요합니다. 27번 라인에서 Set이 생성되었음이 보장됩니다.

다음과 같이 수정하는 것을 제안합니다:

- this.#searchParamsMap.get(key)?.add(value);
+ this.#searchParamsMap.get(key)!.add(value);
packages/web/src/utils/supabase.server.ts (2)

Line range hint 13-26: 설정 관리 개선 제안

현재 구현은 잘 작동하지만, 더 나은 타입 안전성과 유지보수성을 위해 다음과 같은 개선을 고려해보세요:

  1. CONFIG 객체에 대한 타입 검증 추가
  2. 환경 변수 누락에 대한 명시적인 에러 처리
+const validateConfig = () => {
+  if (!CONFIG.supabaseUrl || !CONFIG.supabaseAnonKey) {
+    throw new Error('Missing required Supabase configuration');
+  }
+};

 export const getSupabaseClient = () => {
+  validateConfig();
   if (supabaseClient) return supabaseClient;

Line range hint 29-67: 인증 구현에 대한 보안 검토

인증 구현이 전반적으로 잘 되어 있습니다. 몇 가지 보안 관련 제안사항입니다:

  1. OAuth 리다이렉트 URL이 올바르게 구성되어 있음
  2. 에러 처리가 적절히 구현되어 있음
  3. 로그아웃 시 토큰 정리가 완벽함

추가 보안을 위한 제안:

  • CSRF 토큰 구현 고려
  • 로그인 시도 횟수 제한 추가
packages/web/src/modules/i18n/locales/en/translation.json (2)

13-20: 에러 메시지 섹션 추가 필요

현재 성공 메시지만 포함되어 있습니다. 사용자 경험 향상을 위해 다음과 같은 에러 상황에 대한 메시지도 추가하는 것이 좋겠습니다:

  • 네트워크 오류
  • 권한 부족
  • 잘못된 입력값
  "toastMessage": {
    "refresh": "Refresh completed.",
    "memoEdited": "Memo has been edited.",
    "categoryEdited": "Category has been changed.",
    "memoDeleted": "Memo has been deleted.",
    "memoWishListDeleted": "Memo has been removed from the wish list.",
-    "memoWishListAdded": "Memo has been added to the wish list."
+    "memoWishListAdded": "Memo has been added to the wish list.",
+    "error": {
+      "network": "Network error occurred. Please try again.",
+      "permission": "You don't have permission for this action.",
+      "invalidInput": "Please check your input and try again."
+    }
  },

45-45: 버전 설명 메시지 개선 제안

현재 버전 설명이 다소 기술적입니다. 일반 사용자를 위해 더 친근한 문구로 수정하는 것이 좋겠습니다.

-    "description": "Current Version: {{currentVersion}} | Latest Version: {{lastVersion}}",
+    "description": "You're using version {{currentVersion}}. Version {{lastVersion}} is now available!",
packages/web/src/modules/search-params/SearchParams.test.ts (2)

55-55: 테스트 설명에 오타가 있습니다

"않는다.."에서 마침표가 중복되어 있습니다.

-    test('key와 value에 해당하는 값이 없다면 제거하지 않는다..', () => {
+    test('key와 value에 해당하는 값이 없다면 제거하지 않는다.', () => {

3-75: 테스트 커버리지 개선을 위한 제안

다음과 같은 추가 테스트 케이스들을 고려해보시면 좋을 것 같습니다:

  1. 특수 문자가 포함된 파라미터 처리
  2. 빈 문자열 값 처리
  3. 메서드 호출 시 발생할 수 있는 에러 케이스
  4. URL 인코딩/디코딩이 필요한 케이스

추가 테스트 케이스 구현을 원하시면 도움을 드릴 수 있습니다.

packages/web/src/app/[lng]/memos/components/Header/index.tsx (2)

Line range hint 39-40: Supabase 클라이언트 사용 방식 개선이 필요합니다.

현재 사용 중인 getSupabaseClient 함수는 더 이상 권장되지 않습니다. 대신 useSupabaseClient 훅을 사용하는 것이 좋습니다.

다음과 같이 수정하는 것을 제안드립니다:

- const supabaseClient = getSupabaseClient();
+ const supabaseClient = useSupabaseClient();

관련하여 import 구문도 업데이트가 필요합니다:

- import { getSupabaseClient, signout } from '@src/utils/supabase.server';
+ import { useSupabaseClient } from '@supabase/auth-helpers-react';
+ import { signout } from '@src/utils/supabase.server';

Line range hint 46-47: 사용자 아바타 URL의 안전한 처리가 필요합니다.

옵셔널 체이닝을 사용한 fallback 처리는 잘 되어있으나, 이미지 URL의 유효성 검사가 추가되면 좋을 것 같습니다.

다음과 같은 유틸리티 함수 사용을 제안드립니다:

const validateImageUrl = (url: string, fallback: string): string => {
  if (!url || !url.match(/^https?:\/\/.+/)) return fallback;
  return url;
};

// 사용 예시
const userAvatarUrl = validateImageUrl(
  user?.data?.user?.identities?.[0]?.identity_data?.avatar_url,
  '/images/pngs/default_image_user.png'
);
chrome-extension/lib/background/index.ts (2)

Line range hint 71-71: OpenAI 모델명을 확인해주세요.

'gpt-4o-mini'라는 모델명이 올바른지 확인이 필요합니다. 일반적으로 알려진 OpenAI 모델명과 다릅니다.

다음과 같이 수정하는 것을 제안드립니다:

-      model: 'gpt-4o-mini',
+      model: 'gpt-4',  // 또는 다른 적절한 OpenAI 모델

Line range hint 64-83: 스트리밍 응답 처리 로직 검토가 필요합니다.

OpenAI API 호출 시 에러 처리가 누락되어 있습니다. 스트리밍 응답 처리 중 발생할 수 있는 예외 상황에 대한 처리가 필요합니다.

다음과 같은 에러 처리 로직 추가를 제안드립니다:

   try {
     const stream = await openai.chat.completions.create({
       model: 'gpt-4',
       messages: [
         { role: 'system', content: prompt },
         { role: 'user', content: pageContent },
       ],
       stream: true,
     });

     for await (const chunk of stream) {
       const message = chunk.choices[0]?.delta?.content;
       port.postMessage(message);
     }
+  } catch (error) {
+    console.error('OpenAI API 호출 중 오류 발생:', error);
+    port.postMessage({ error: '응답을 처리하는 중 오류가 발생했습니다.' });
+  }
pages/options/src/components/OptionForm.tsx (1)

Line range hint 23-39: 다운로드 핸들러의 에러 처리를 개선하면 좋을 것 같습니다.

handleCSVDownloadClickhandleJSONDownloadClick 함수에서 데이터가 없는 경우 사용자에게 아무런 피드백 없이 함수가 종료됩니다. 사용자 경험 향상을 위해 에러 메시지를 표시하는 것이 좋을 것 같습니다.

다음과 같이 개선하는 것을 제안드립니다:

  const handleCSVDownloadClick = async () => {
    const memos = await getMemos();
-   if (!memos?.data) return;
+   if (!memos?.data) {
+     overlay.open(({ unmount }) => (
+       <Toast message={I18n.get('error_no_data')} onClose={unmount} />
+     ));
+     return;
+   }
    const csvBlob = convertToCSVBlob(memos.data);
    downloadBlob(csvBlob, { fileExtension: 'csv' });
  };
packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx (1)

35-38: 폼 유효성 검사 강화 필요

MemoInput 타입을 사용하여 타입 안정성이 향상되었지만, 폼 유효성 검사가 부족합니다.

다음과 같은 개선을 제안합니다:

  const { register, watch, setValue } = useForm<MemoInput>({
    defaultValues: {
      memo: '',
    },
+   resolver: zodResolver(memoSchema),
  });
pages/side-panel/src/components/MemoForm.tsx (2)

56-64: 메모 저장 로직의 에러 처리를 개선하면 좋겠습니다.

현재 구현은 기능적으로는 문제가 없으나, 다음과 같은 개선사항을 제안드립니다:

  • 네트워크 오류나 저장 실패 시 사용자에게 더 자세한 피드백 제공
  • 재시도 메커니즘 추가
  const saveMemo = async (data?: MemoInput) => {
+   try {
      const memo = data?.memo ?? watch('memo');
      const isWish = data?.isWish ?? watch('isWish');

      const formattedMemo = await getFormattedMemo({ memo, isWish });

      if (memoData) mutateMemoPatch({ id: memoData.id, memoRequest: formattedMemo });
      else mutateMemoPost(formattedMemo);
+   } catch (error) {
+     setIsSaved(false);
+     toast({
+       title: I18n.get('toast_error_save'),
+       description: error instanceof Error ? error.message : '알 수 없는 오류가 발생했습니다.',
+       action: (
+         <ToastAction altText="다시 시도" onClick={() => saveMemo(data)}>
+           다시 시도
+         </ToastAction>
+       ),
+     });
+   }
  };

101-104: 위시리스트 처리 중 로딩 상태 표시가 필요해 보입니다.

사용자 경험 향상을 위해 위시리스트 처리 중임을 표시하는 로딩 상태를 추가하면 좋겠습니다.

+ const [isWishProcessing, setIsWishProcessing] = useState(false);

  const handleWishListClick = () => {
+   setIsWishProcessing(true);
    const memoWishListUrl = getMemoWishListUrl(memoData?.id);

    Tab.create({ url: memoWishListUrl });
+   setIsWishProcessing(false);
  };
packages/web/src/app/[lng]/memos/components/MemoView/MemoItem.tsx (1)

34-35: URL 파라미터 관리 방식이 개선되었습니다.

useSearchParams를 사용하여 URL 파라미터를 관리하는 방식이 더 체계적으로 변경되었습니다. 특히 scroll: false 옵션을 통해 사용자 경험이 개선되었습니다.

하지만 URL 파라미터 변경 시 사용자에게 피드백을 제공하는 것이 좋을 것 같습니다.

다음과 같이 토스트 메시지를 추가하는 것을 고려해보세요:

 const handleContentClick = (event: MouseEvent<HTMLDivElement> | KeyboardEvent<HTMLDivElement>) => {
   const id = event.currentTarget.id;
   if (!id) return;
   searchParams.set('id', id);
   router.replace(searchParams.getUrl(), { scroll: false });
+  toast({ title: t('toastMessage.memoSelected') });
 };

Also applies to: 59-60

packages/web/src/app/[lng]/memos/components/MemoView/MemoOption.tsx (1)

Line range hint 50-65: 에러 처리를 개선하면 좋을 것 같습니다.

삭제 작업 시 에러 처리가 미흡합니다. 다음과 같은 개선을 제안드립니다:

 mutateDeleteMemo(memoId, {
   onSuccess: ({ data }) => {
     if (!data) return;
     const saveMemo = () => mutatePostMemo(data[0]);
     toast({
       title: t('toastMessage.memoDeleted'),
       action: (
         <ToastAction altText={t('toastActionMessage.memoDeleteCancel')} onClick={saveMemo}>
           {t('toastActionMessage.memoDeleteCancel')}
         </ToastAction>
       ),
     });
   },
+  onError: (error) => {
+    toast({
+      title: t('toastMessage.error'),
+      description: error.message,
+      variant: 'destructive',
+    });
+  },
 });
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f32b597 and 1434bfd.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (115)
  • .coderabbit.yaml (1 hunks)
  • chrome-extension/lib/background/index.ts (3 hunks)
  • chrome-extension/utils/openai.ts (1 hunks)
  • package.json (4 hunks)
  • packages/shared/package.json (1 hunks)
  • packages/shared/src/constants/Config.ts (1 hunks)
  • packages/shared/src/constants/Cookie.ts (1 hunks)
  • packages/shared/src/constants/Extension.ts (1 hunks)
  • packages/shared/src/constants/Supabase.ts (1 hunks)
  • packages/shared/src/constants/Url.ts (1 hunks)
  • packages/shared/src/hooks/extension/index.ts (1 hunks)
  • packages/shared/src/hooks/extension/useSupabaseClientQuery.ts (1 hunks)
  • packages/shared/src/hooks/index.ts (0 hunks)
  • packages/shared/src/hooks/supabase/index.ts (0 hunks)
  • packages/shared/src/hooks/supabase/useCategoryPostMutation.ts (1 hunks)
  • packages/shared/src/hooks/supabase/useCategoryQuery.ts (2 hunks)
  • packages/shared/src/hooks/supabase/useMemoPatchMutation.ts (1 hunks)
  • packages/shared/src/hooks/supabase/useMemoPostMutation.ts (1 hunks)
  • packages/shared/src/hooks/supabase/useMemoQuery.ts (2 hunks)
  • packages/shared/src/hooks/supabase/useMemosQuery.ts (1 hunks)
  • packages/shared/src/hooks/supabase/useSupabaseClient.ts (0 hunks)
  • packages/shared/src/hooks/supabase/useSupabaseUser.ts (1 hunks)
  • packages/shared/src/hooks/useSearchParamsRouter.ts (0 hunks)
  • packages/shared/src/utils/Environment.ts (1 hunks)
  • packages/shared/src/utils/Notion.ts (2 hunks)
  • packages/shared/src/utils/Sentry.ts (2 hunks)
  • packages/shared/src/utils/String.ts (1 hunks)
  • packages/shared/src/utils/Supabase.ts (2 hunks)
  • packages/shared/src/utils/extension/Storage.ts (2 hunks)
  • packages/shared/src/utils/extension/Supabase.ts (2 hunks)
  • packages/shared/src/utils/extension/bridge/getExtensionManifest.ts (1 hunks)
  • packages/shared/src/utils/extension/bridge/getSidePanelOpen.ts (1 hunks)
  • packages/shared/src/utils/extension/bridge/refetchTheMemos.ts (1 hunks)
  • packages/shared/src/utils/index.ts (1 hunks)
  • packages/shared/tsconfig.json (1 hunks)
  • packages/web/next-i18next.config.js (0 hunks)
  • packages/web/package.json (1 hunks)
  • packages/web/src/app/[lng]/layout.tsx (2 hunks)
  • packages/web/src/app/[lng]/login/components/LoginSection/ExtensionVersion.tsx (1 hunks)
  • packages/web/src/app/[lng]/login/components/LoginSection/index.tsx (2 hunks)
  • packages/web/src/app/[lng]/login/components/PersonalInformationInfo/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/login/page.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/Header/RefreshButton.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/Header/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx (2 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoSidebar/SidebarGroupCategory.tsx (2 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoSidebar/SidebarMenuItemAddCategory.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoSidebar/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoSidebarTrigger/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoView/MemoGrid.tsx (2 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoView/MemoItem.tsx (3 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoView/MemoOption.tsx (4 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoView/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/legacy/MemoTable.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/constants/guide.ts (0 hunks)
  • packages/web/src/app/[lng]/memos/constants/index.ts (0 hunks)
  • packages/web/src/app/[lng]/memos/hooks/useGuide.ts (1 hunks)
  • packages/web/src/app/[lng]/memos/layout.tsx (2 hunks)
  • packages/web/src/app/[lng]/memos/page.tsx (2 hunks)
  • packages/web/src/app/[lng]/memos/setting/component/Setting/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/setting/component/SettingHeader/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/setting/page.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/types/Input.ts (1 hunks)
  • packages/web/src/app/[lng]/memos/types/index.ts (1 hunks)
  • packages/web/src/app/[lng]/memos/utils/guide.ts (2 hunks)
  • packages/web/src/app/auth/callback-email/route.ts (2 hunks)
  • packages/web/src/app/auth/callback/route.ts (2 hunks)
  • packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts (1 hunks)
  • packages/web/src/app/components/ExtensionDialog/index.tsx (1 hunks)
  • packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts (1 hunks)
  • packages/web/src/app/components/Introduction.tsx (1 hunks)
  • packages/web/src/app/components/index.ts (1 hunks)
  • packages/web/src/app/i18n/locales/en/translation.json (0 hunks)
  • packages/web/src/components/Footer.tsx (2 hunks)
  • packages/web/src/components/ui/sidebar.tsx (1 hunks)
  • packages/web/src/constants/Config.ts (1 hunks)
  • packages/web/src/hooks/index.ts (1 hunks)
  • packages/web/src/hooks/useGetExtensionManifest.ts (1 hunks)
  • packages/web/src/hooks/useLanguage.ts (1 hunks)
  • packages/web/src/hooks/useMemoDeleteMutation.ts (1 hunks)
  • packages/web/src/hooks/useSupabaseClient.ts (1 hunks)
  • packages/web/src/middleware.ts (1 hunks)
  • packages/web/src/modules/i18n/client.js (1 hunks)
  • packages/web/src/modules/i18n/constant.ts (1 hunks)
  • packages/web/src/modules/i18n/index.ts (1 hunks)
  • packages/web/src/modules/i18n/locales/en/translation.json (1 hunks)
  • packages/web/src/modules/i18n/locales/ko/translation.json (2 hunks)
  • packages/web/src/modules/i18n/server.js (1 hunks)
  • packages/web/src/modules/i18n/type.ts (1 hunks)
  • packages/web/src/modules/i18n/util.ts (1 hunks)
  • packages/web/src/modules/local-storage/LocalStorage.ts (1 hunks)
  • packages/web/src/modules/local-storage/constant.ts (1 hunks)
  • packages/web/src/modules/local-storage/index.ts (1 hunks)
  • packages/web/src/modules/local-storage/type.ts (1 hunks)
  • packages/web/src/modules/local-storage/util.ts (1 hunks)
  • packages/web/src/modules/search-params/SearchParams.test.ts (1 hunks)
  • packages/web/src/modules/search-params/SearchParams.ts (1 hunks)
  • packages/web/src/modules/search-params/constant.ts (1 hunks)
  • packages/web/src/modules/search-params/index.ts (1 hunks)
  • packages/web/src/modules/search-params/type.ts (1 hunks)
  • packages/web/src/modules/search-params/useSearchParams.ts (1 hunks)
  • packages/web/src/utils/index.ts (1 hunks)
  • packages/web/src/utils/middleware.ts (2 hunks)
  • packages/web/src/utils/supabase.client.ts (2 hunks)
  • packages/web/src/utils/supabase.server.ts (5 hunks)
  • packages/web/tsconfig.json (1 hunks)
  • pages/content-ui/src/index.tsx (1 hunks)
  • pages/options/src/components/OptionForm.tsx (2 hunks)
  • pages/side-panel/src/components/LoginSection.tsx (2 hunks)
  • pages/side-panel/src/components/MemoForm.tsx (4 hunks)
  • pages/side-panel/src/components/MemoHeader.tsx (1 hunks)
  • pages/side-panel/src/hoc/withAuthentication.tsx (1 hunks)
  • pages/side-panel/src/types/Input.ts (1 hunks)
  • pages/side-panel/src/utils/Url.ts (1 hunks)
  • vitest.config.ts (1 hunks)
💤 Files with no reviewable changes (8)
  • packages/shared/src/hooks/index.ts
  • packages/shared/src/hooks/supabase/index.ts
  • packages/shared/src/hooks/supabase/useSupabaseClient.ts
  • packages/shared/src/hooks/useSearchParamsRouter.ts
  • packages/web/next-i18next.config.js
  • packages/web/src/app/[lng]/memos/constants/guide.ts
  • packages/web/src/app/[lng]/memos/constants/index.ts
  • packages/web/src/app/i18n/locales/en/translation.json
🧰 Additional context used
🪛 Biome (1.9.4)
packages/web/src/modules/local-storage/LocalStorage.ts

[error] 3-11: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

🔇 Additional comments (159)
packages/web/src/app/[lng]/memos/types/index.ts (1)

1-1: 배럴(barrel) 내보내기 패턴이 올바르게 구현되었습니다.

타입 시스템의 구조화가 잘 되어있습니다. 이는 코드의 가독성과 유지보수성을 향상시킵니다.

Input 모듈의 존재 여부와 내용을 확인하기 위해 다음 스크립트를 실행합니다:

✅ Verification successful

타입 내보내기가 올바르게 구현되었음을 확인했습니다.

Input.ts 파일이 존재하며 CategoryInput 인터페이스와 MemoInput 타입을 올바르게 정의하고 있습니다. 배럴 패턴을 통한 타입 내보내기는 코드의 구조화와 재사용성을 향상시키는 좋은 방법입니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and content of Input module

# Check if Input.ts exists in the same directory
fd -t f "Input.ts" "packages/web/src/app/\[lng\]/memos/types"

# If exists, check its content for the mentioned types
rg -A 5 "interface CategoryInput|type MemoInput" "packages/web/src/app/\[lng\]/memos/types"

Length of output: 364


Script:

#!/bin/bash
# Let's try searching without escaping brackets and with proper path structure
fd -t f "Input.ts" "packages/web/src/app"

# Also search for any files containing Input in their name
fd "Input" "packages/web"

# Search for type definitions related to memos
rg -g "*.ts" "interface|type.*Input"

Length of output: 2391


Script:

#!/bin/bash
# Let's check the content of Input.ts file to verify the types
cat "packages/web/src/app/[lng]/memos/types/Input.ts"

Length of output: 156

packages/web/src/modules/search-params/constant.ts (1)

1-1: 타입 안전성이 잘 구현되었습니다!

as const 어서션을 사용하여 배열을 읽기 전용으로 만들고 리터럴 타입을 보존한 것이 좋습니다. 이는 타입 안전성을 보장하고 실수로 인한 수정을 방지합니다.

packages/web/src/modules/i18n/index.ts (1)

1-3: 모듈 구조가 잘 구성되어 있습니다!

배럴(barrel) 파일 패턴을 사용하여 관련 모듈들을 깔끔하게 구성하였습니다. 이는 다른 파일에서 import 할 때 편리성을 높여줄 것입니다.

참조된 모듈들의 존재 여부를 확인하기 위해 다음 스크립트를 실행합니다:

✅ Verification successful

모든 참조 모듈이 정상적으로 존재합니다!

검증 결과, 다음 모듈 파일들이 모두 올바르게 존재함을 확인했습니다:

  • packages/web/src/modules/i18n/constant.ts
  • packages/web/src/modules/i18n/util.ts
  • packages/web/src/modules/i18n/type.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 참조된 모듈 파일들의 존재 여부 확인

# 현재 디렉토리의 상대 경로 확인
current_dir=$(dirname "packages/web/src/modules/i18n/index.ts")

# 각 모듈 파일 존재 여부 확인
echo "모듈 파일 확인 결과:"
for module in constant util type; do
  fd -t f "^${module}\.(ts|js|tsx|jsx)$" "$current_dir"
done

Length of output: 553

packages/web/src/utils/index.ts (1)

3-3: 모듈 경로 구조 검토 필요

utils 디렉토리 외부의 모듈을 재내보내기하는 것은 아키텍처 관점에서 바람직하지 않을 수 있습니다. search-params 모듈을 utils 디렉토리 내부로 이동하거나, 별도의 독립적인 모듈로 분리하는 것을 고려해보세요.

packages/shared/src/constants/Extension.ts (1)

1-4: 상수 구조 변경에 따른 사용처 확인이 필요합니다.

EXTENSION_ID에서 EXTENSION.id로의 변경이 다른 파일들에 미치는 영향을 확인해야 합니다.

✅ Verification successful

Let me verify if there are any other potential usages or imports of the extension constant.


구조 변경이 올바르게 적용되어 있습니다

코드베이스 분석 결과, EXTENSION_ID에서 EXTENSION.id로의 변경이 모든 사용처에서 올바르게 반영되어 있습니다. 이전 EXTENSION_ID 상수의 사용이 발견되지 않았으며, 새로운 EXTENSION.id가 필요한 모든 곳에서 정상적으로 임포트되어 사용되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify all usages of the extension ID constant

# Check for old usage
echo "Checking for old EXTENSION_ID usage:"
rg "EXTENSION_ID"

# Check for new usage
echo -e "\nChecking for new EXTENSION.id usage:"
rg "EXTENSION\.id"

Length of output: 692


Script:

#!/bin/bash
# Check for imports of EXTENSION constant
echo "Checking for EXTENSION imports:"
rg "import.*EXTENSION.*from"

# Check for any other potential extension ID references
echo -e "\nChecking for direct extension ID references:"
rg "eaiojpmgklfngpjddhoalgcpkepgkclh"

Length of output: 1582

packages/shared/src/utils/Environment.ts (2)

3-3: 환경 설정 일관성 검증이 필요합니다.

CONFIG.nodeEnv를 사용하는 방식이 다른 파일들과 일관되게 적용되어 있는지 확인이 필요합니다.

다음 스크립트로 nodeEnv 사용 패턴을 검증하겠습니다:

✅ Verification successful

환경 설정 사용 방식이 일관되게 적용되어 있습니다.

코드베이스 분석 결과, 환경 설정 사용이 다음과 같이 일관되게 구현되어 있습니다:

  • CONFIG.nodeEnvshared/src/utils/Environment.ts에서 중앙 관리되며, 다른 모듈에서 import하여 사용
  • process.env.NODE_ENV는 주로 쿠키 설정과 빌드 설정에서만 직접 사용
  • Config.ts에서 nodeEnv 설정을 안전하게 추상화하여 제공
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# NODE_ENV와 CONFIG.nodeEnv 사용 패턴 검색

# 기존 NODE_ENV 직접 사용 여부 확인
rg "NODE_ENV.*===.*'production'" -g '!node_modules'

# CONFIG.nodeEnv 사용 패턴 확인
rg "CONFIG\.nodeEnv.*===.*'production'" -g '!node_modules'

Length of output: 523


Script:

#!/bin/bash
# CONFIG 관련 전체 사용 패턴 확인
rg "CONFIG\." -g '!node_modules' -A 2

# process.env.NODE_ENV 전체 사용 패턴 확인
rg "process\.env\.NODE_ENV" -g '!node_modules' -A 2

# Environment.ts 파일이 import되는 위치 확인
rg "from.*Environment" -g '!node_modules'

Length of output: 5690


1-1: CONFIG 객체의 타입 정의 확인이 필요합니다.

CONFIG 객체가 올바르게 타입 정의되어 있는지 확인하는 것이 중요합니다.

다음 스크립트를 실행하여 CONFIG 객체의 구조와 타입을 확인하겠습니다:

✅ Verification successful

Let me gather more information about the CONFIG usage and type definitions.


CONFIG 객체가 적절하게 구현되어 있으며 타입 안정성이 확보되었습니다.

CONFIG 객체는 다음과 같이 잘 구현되어 있습니다:

  • getSafeConfig 함수를 통해 환경 변수를 안전하게 관리
  • nodeEnv는 'development' | 'production' 타입으로 명시적 정의
  • 전체 코드베이스에서 일관되게 사용됨

따라서 Environment.ts에서 CONFIG 객체를 사용하는 것은 적절하며 타입 안정성도 보장됩니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CONFIG 객체의 타입 정의와 구조 확인

# CONFIG 타입 정의 검색
ast-grep --pattern 'type CONFIG = {
  $$$
}'

# CONFIG 객체 구현 검색
ast-grep --pattern 'export const CONFIG = {
  $$$
}'

Length of output: 1828


Script:

#!/bin/bash
# CONFIG 관련 추가 정보 수집

# getSafeConfig 함수 구현 확인
ast-grep --pattern 'function getSafeConfig($_' 

# CONFIG 타입 추론을 위해 타입스크립트 인터페이스나 타입 정의 검색
ast-grep --pattern 'interface $_Config {
  $$$
}'

# CONFIG 사용 패턴 확인
rg "CONFIG\." -A 2

Length of output: 4077

packages/web/src/app/components/index.ts (1)

2-2: 새로운 ExtensionDialog 컴포넌트 내보내기가 추가되었습니다.

컴포넌트 내보내기 패턴이 일관성 있게 적용되어 있습니다.

ExtensionDialog 컴포넌트의 존재 여부를 확인하기 위해 다음 스크립트를 실행하겠습니다:

✅ Verification successful

ExtensionDialog 컴포넌트가 정상적으로 구현되어 있습니다.

ExtensionDialog 컴포넌트가 packages/web/src/app/components/ExtensionDialog/index.tsx에 존재하며, 필요한 모든 관련 파일들이 함께 구현되어 있습니다:

  • useExtensionDialog.ts: 다이얼로그 상태 관리 로직
  • getExtensionDialogInfo.ts: 다이얼로그 표시 정보 관리
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# ExtensionDialog 컴포넌트 파일의 존재 여부 확인
fd --type f "ExtensionDialog" packages/web/src/app/components

# 컴포넌트의 default export 확인
ast-grep --pattern 'export default function ExtensionDialog' 

Length of output: 268


Script:

#!/bin/bash
# ExtensionDialog 컴포넌트 파일 추가 검색
fd --type f "ExtensionDialog.tsx?" packages/web/src/app/components

# ExtensionDialog 디렉토리의 모든 파일 내용 확인
fd --type f . packages/web/src/app/components/ExtensionDialog --exec cat {}

# default export 패턴 추가 검색
ast-grep --pattern 'export default $_'

Length of output: 162406

packages/shared/src/constants/Cookie.ts (1)

1-5: 구조 변경이 잘 이루어졌습니다만, 주의가 필요합니다.

상수들을 하나의 객체로 통합한 것은 좋은 접근이지만, 이는 breaking change입니다. 다른 파일들에서 이 상수들을 import하는 방식을 업데이트해야 합니다.

다음 스크립트를 실행하여 영향을 받는 파일들을 확인하세요:

✅ Verification successful

상수 구조 변경이 안전하게 적용되어 있습니다

검색 결과를 분석해보니, 모든 파일에서 이미 새로운 COOKIE_KEY 객체 구조를 올바르게 사용하고 있습니다. 이전 상수명(COOKIE_KEY_ACCESS_TOKEN 등)을 사용하는 코드가 없으며, 모든 참조가 COOKIE_KEY.accessToken과 같은 새로운 형식을 따르고 있습니다.

영향을 받는 파일들:

  • packages/web/src/utils/supabase.server.ts
  • packages/web/src/components/ui/sidebar.tsx
  • packages/web/src/app/auth/callback-email/route.ts
  • packages/web/src/app/auth/callback/route.ts
  • packages/web/src/app/[lng]/memos/layout.tsx
  • packages/shared/src/utils/extension/Supabase.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 이전 상수 사용 여부 확인

# 이전 상수명으로 사용되는 파일 검색
echo "이전 상수 사용 검색 중..."
rg "COOKIE_KEY_ACCESS_TOKEN|COOKIE_KEY_REFRESH_TOKEN|COOKIE_KEY_SIDEBAR_STATE" 

Length of output: 123


Script:

#!/bin/bash
# Search for files importing from Cookie.ts and using COOKIE_KEY
echo "Searching for COOKIE_KEY usage..."
rg -l "COOKIE_KEY" --type ts

# Search for actual usage patterns of COOKIE_KEY
echo -e "\nSearching for COOKIE_KEY usage patterns..."
rg "COOKIE_KEY\." --type ts -A 2

Length of output: 2863

packages/web/src/modules/local-storage/index.ts (2)

1-3: 모듈 내보내기가 잘 구성되어 있습니다!

모듈의 구조가 barrel 패턴을 따르고 있어 코드의 가독성과 유지보수성이 향상되었습니다.


5-5: LocalStorage 클래스 구현을 확인해주세요.

LocalStorage 클래스가 올바르게 구현되어 있는지 확인이 필요합니다.

다음 스크립트를 실행하여 LocalStorage 클래스의 구현을 확인하세요:

✅ Verification successful

Let me gather more information about the LocalStorage implementation.


Let me check one more detail about the LocalStorageKeyType.


LocalStorage 클래스가 안전하게 구현되어 있습니다.

LocalStorage 클래스는 다음과 같은 특징을 가지고 있습니다:

  • 타입 안전성이 보장된 get/set 메서드 구현
  • 올바른 키 타입 제한 (guide, updateVersion, install)
  • JSON 직렬화/역직렬화 처리
  • 적절한 정적 메서드 사용
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: LocalStorage 클래스의 구현 확인

# LocalStorage 클래스의 구현 확인
ast-grep --pattern $'class LocalStorage {
  $$$
  static get($_) {
    $$$
  }
  static set($_) {
    $$$
  }
  $$$
}'

# 클래스 사용 패턴 확인
rg -A 3 "LocalStorage\.(get|set)"

Length of output: 633


Script:

#!/bin/bash
# LocalStorage 클래스 파일의 전체 내용 확인
fd "LocalStorage.ts" --exec cat {}

# LOCAL_STORAGE_VALUE_MAP 상수 확인
rg "LOCAL_STORAGE_VALUE_MAP" -A 3

Length of output: 1789


Script:

#!/bin/bash
# LocalStorageKeyType 타입 정의 확인
rg "LocalStorageKeyType" -B 2 -A 2

# 타입 파일 찾기
fd "types?.ts" --exec cat {}

Length of output: 5130

chrome-extension/utils/openai.ts (1)

1-1: 설정 관리 방식이 개선되었습니다.

중앙 집중식 설정 관리로의 전환은 좋은 접근 방식입니다. 하지만 API 키와 같은 민감한 정보의 보안을 확인해주세요.

보안 설정을 확인하기 위해 다음 스크립트를 실행합니다:

Also applies to: 5-5

✅ Verification successful

API 키 관리가 적절하게 구현되어 있습니다.

환경 변수를 통한 API 키 관리와 .env 파일의 gitignore 설정이 확인되었습니다. 다음과 같은 보안 조치가 적절히 구현되어 있습니다:

  • .env 파일이 .gitignore에 포함되어 있어 민감한 정보가 저장소에 노출되지 않습니다
  • turbo.json에서 OPENAI_API_KEY가 환경 변수로 적절히 관리되고 있습니다
  • getSafeConfig를 통해 환경 변수 값을 안전하게 처리하고 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CONFIG 객체가 환경 변수나 안전한 방식으로 API 키를 관리하는지 확인

# shared constants 파일에서 API 키 관리 방식 확인
rg -A 5 "openApiKey" 

# gitignore 설정 확인
cat .gitignore | grep -i "env\|config"

Length of output: 348


Script:

#!/bin/bash
# getSafeConfig 함수의 구현을 확인
ast-grep --pattern 'function getSafeConfig($_,$_) { $$$ }'

# 환경 변수 관련 설정 파일 검색
rg -l "process\.env"

# Config 파일에서 API 키 관리 방식 전체 확인
rg -A 10 "OPENAI_API_KEY"

Length of output: 1476

packages/web/src/modules/i18n/constant.ts (2)

1-2: 타입 안정성이 보장된 언어 설정이 잘 구현되었습니다!

as const 타입 어서션을 사용하여 배열의 타입 안정성을 보장한 것이 좋습니다. 또한 fallbackLnglanguages 배열에서 재사용하여 일관성을 유지한 것도 훌륭합니다.


3-4: i18next 기본 설정이 적절하게 구성되었습니다.

defaultNScookieName의 값이 i18next의 일반적인 컨벤션을 따르고 있어 적절합니다.

다음 스크립트를 실행하여 i18next 설정의 일관성을 확인하겠습니다:

✅ Verification successful

i18next 설정이 일관되게 적용되어 있음을 확인했습니다

constant.ts에서 정의된 defaultNScookieName 값이 클라이언트(client.js)와 서버(server.js) 양쪽에서 일관되게 사용되고 있으며, 미들웨어에서도 올바르게 참조되고 있습니다. 특히:

  • util.ts에서 i18next 초기화 옵션에 정확하게 반영됨
  • middleware.ts에서 쿠키 처리에 올바르게 활용됨
  • client.js에서 쿠키 설정에 일관되게 사용됨
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# i18next 관련 설정 파일들을 검색하여 일관성 확인
rg -g '*.{ts,tsx,js,jsx}' -l 'i18next.init|createInstance' 

Length of output: 100


Script:

#!/bin/bash
# i18next 서버 설정 파일의 내용을 확인하여 defaultNS와 cookieName 사용을 검증
rg -A 5 -B 5 'i18next.init|createInstance' packages/web/src/modules/i18n/server.js

# i18next 관련 설정이 사용되는 다른 파일들도 확인
rg -g '*.{ts,tsx,js,jsx}' 'defaultNS|cookieName' 

Length of output: 1716

packages/web/src/modules/search-params/index.ts (2)

1-2: 타입과 상수 내보내기가 적절히 구성되어 있습니다.

타입을 먼저 선언하고 상수를 그 다음에 선언하는 구조가 명확하고 일관성 있습니다.


4-5: 모듈 간 의존성 확인이 필요합니다.

useSearchParams 훅이 SearchParams 클래스에 의존할 것으로 예상됩니다. 순환 참조가 없는지 확인해 주세요.

다음 스크립트로 의존성을 확인할 수 있습니다:

✅ Verification successful

Let me gather more information about the dependencies by checking the full content of both files.


의존성 구조가 올바르게 구현되어 있습니다.

useSearchParams 훅은 SearchParams 클래스를 적절하게 활용하고 있으며, 순환 참조 문제가 없습니다. useSearchParams는 Next.js의 기본 훅을 확장하여 SearchParams 클래스의 기능을 제공하는 래퍼 역할을 수행합니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 모듈 간 의존성 확인

# SearchParams.ts와 useSearchParams.ts 파일 내용 확인
echo "=== SearchParams.ts 파일 내용 ==="
rg -A 5 "import.*useSearchParams" "./packages/web/src/modules/search-params/SearchParams.ts" || true

echo -e "\n=== useSearchParams.ts 파일 내용 ==="
rg -A 5 "import.*SearchParams" "./packages/web/src/modules/search-params/useSearchParams.ts" || true

Length of output: 606


Script:

#!/bin/bash
# Description: 전체 파일 내용 확인

echo "=== SearchParams.ts 전체 내용 ==="
cat "./packages/web/src/modules/search-params/SearchParams.ts" || true

echo -e "\n=== useSearchParams.ts 전체 내용 ==="
cat "./packages/web/src/modules/search-params/useSearchParams.ts" || true

Length of output: 2469

packages/web/src/modules/i18n/type.ts (2)

Line range hint 3-11: 타입 정의가 명확하고 잘 구조화되어 있습니다.

Language, LanguageType, LanguageParams의 타입 정의가 TypeScript의 기능을 잘 활용하여 구현되어 있습니다. 특히 typeof와 array index type을 사용한 방식이 타입 안정성을 잘 보장합니다.


1-1: import 경로 변경에 대한 검증이 필요합니다.

languages 상수가 index 파일에서 올바르게 내보내지고 있는지 확인이 필요합니다.

다음 스크립트를 실행하여 import 경로 변경이 올바른지 확인하세요:

✅ Verification successful

import 경로 변경이 올바르게 이루어졌습니다.

languages 상수는 constant.ts에서 정의되어 있으며, index.ts에서 re-export되고 있습니다. settings.ts 파일은 더 이상 존재하지 않으며, 모든 import가 올바르게 '.' 경로를 통해 이루어지고 있습니다. 이는 코드베이스 전체에서 일관되게 적용되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the languages export in index.ts and its usage

# Check if languages is exported from index.ts
rg -l "export.*languages" "packages/web/src/modules/i18n/"

# Check for any potential broken imports
rg -l "import.*languages.*from.*['\"]\\./settings['\"]" "packages/web/src/"

Length of output: 217


Script:

#!/bin/bash
# Check the content of index.ts and settings.ts to verify the export
echo "=== Content of index.ts ==="
cat packages/web/src/modules/i18n/index.ts || true

echo -e "\n=== Content of settings.ts ==="
cat packages/web/src/modules/i18n/settings.ts || true

# Check if languages is imported from settings in other files
echo -e "\n=== Files importing languages from settings ==="
rg "import.*\{.*languages.*\}.*from.*['\"]./settings['\"]" packages/web/src/modules/i18n/

# Check if languages is imported from index in other files
echo -e "\n=== Files importing languages from index ==="
rg "import.*\{.*languages.*\}.*from.*['\"].['\"]" packages/web/src/modules/i18n/

Length of output: 952


Script:

#!/bin/bash
# Check the content of constant.ts as it might contain the languages export
echo "=== Content of constant.ts ==="
cat packages/web/src/modules/i18n/constant.ts

# Check if there are any other files importing languages
echo -e "\n=== All files importing languages ==="
rg "import.*languages" packages/web/src/

Length of output: 880

packages/shared/src/hooks/extension/index.ts (1)

3-3: 새로운 useSupabaseClientQuery 훅 내보내기가 추가되었습니다.

기존의 barrel 파일 패턴을 잘 따르고 있습니다. 다만, useSupabaseClientQuery의 구현을 확인해보시기 바랍니다.

다음 스크립트를 실행하여 useSupabaseClientQuery 구현을 확인하겠습니다:

✅ Verification successful

useSupabaseClientQuery 구현이 적절하게 되어 있습니다.

useSupabaseClientQuery는 useSuspenseQuery를 사용하여 Supabase 클라이언트를 관리하고 있으며, 기존의 useSupabaseClient 훅을 대체하는 새로운 구현입니다. 이는 다음과 같은 장점이 있습니다:

  • 캐싱과 재시도 로직이 내장되어 있습니다 (retry: 1)
  • Suspense를 지원하여 로딩 상태 처리가 더 간단해집니다
  • 일관된 queryKey를 사용하여 상태 관리가 용이합니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: useSupabaseClientQuery 구현 확인

# useSupabaseClientQuery 구현 확인
ast-grep --pattern 'export default function useSupabaseClientQuery() {
  $$$
}'

# 이전 useSupabaseClient 사용처 확인
rg "useSupabaseClient" -A 3

Length of output: 11189

vitest.config.ts (2)

1-2: 필요한 의존성이 올바르게 임포트되었습니다.

React 테스팅을 위한 플러그인과 Vitest 설정이 적절하게 임포트되었습니다.


8-8: 글로벌 설정에 대한 보안 고려사항을 검토하세요.

globals: true 설정은 테스트 환경에서 전역 변수를 사용할 수 있게 하지만, 이는 테스트 격리성에 영향을 줄 수 있습니다.

테스트 파일에서 전역 변수 사용 여부를 확인하기 위해 다음 스크립트를 실행하세요:

✅ Verification successful

Let me analyze the test files to verify the impact of globals: true setting.


globals: true 설정이 안전하게 사용되고 있습니다

테스트 파일들을 분석한 결과, 모든 테스트 전역 객체들(expect, test 등)이 명시적으로 import되어 사용되고 있으며, 테스트 격리성을 해칠 수 있는 전역 변수의 직접적인 사용은 발견되지 않았습니다. Playwright 테스트 프레임워크의 표준 사용 방식을 따르고 있어 안전합니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 테스트 파일에서 전역 변수 사용 패턴 검색
rg -t ts -t js "describe|it|test" -A 5

Length of output: 130484


Script:

#!/bin/bash
# Search for global variable usage in test files
rg -t ts -t js "global\." tests/

Length of output: 34


Script:

#!/bin/bash
# Check test files for common test globals like expect, describe, test, etc.
rg -t ts -t js "^(import|const) \{.*?(expect|describe|test|it|jest|beforeEach|afterEach)" tests/

Length of output: 419

packages/web/src/modules/i18n/util.ts (2)

Line range hint 1-11: 코드가 깔끔하게 정리되었습니다!

상수들을 로컬 모듈에서 가져오도록 변경하여 코드의 구조가 개선되었습니다. getOptions 함수의 구현이 명확하고 잘 구성되어 있습니다.


1-1: cookieName 상수 제거의 영향을 확인해주세요.

cookieName 상수가 제거되었는데, 이로 인해 쿠키 기반의 언어 설정 지속성에 영향이 없는지 확인이 필요합니다.

다음 스크립트를 실행하여 cookieName 상수의 사용 여부를 확인해보세요:

✅ Verification successful

Let me gather more information about cookie-related functionality in the i18n module.


cookieName 상수 제거는 안전합니다

cookieName 상수가 client.js에서 직접 사용되고 있었으나, 이는 i18next 라이브러리의 기본 쿠키 이름과 동일한 'i18next'를 사용하고 있었습니다. 상수를 제거하더라도 i18next-browser-languagedetector가 동일한 쿠키 이름을 기본값으로 사용하므로 기능상의 영향이 없습니다.

  • packages/web/src/modules/i18n/client.js에서 i18next-browser-languagedetector를 사용하고 있어 쿠키 기반 언어 설정이 자동으로 처리됩니다.
  • 현재 코드에서도 cookies.i18next로 직접 접근하고 있어, 상수 제거가 실제 동작에 영향을 주지 않습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: cookieName 상수의 사용처를 검색합니다.

# 'i18next' 쿠키 관련 코드 검색
echo "Searching for i18next cookie usage:"
rg -i "i18next.*cookie" 

# 쿠키 관련 설정 파일 검색
echo -e "\nSearching for cookie configuration files:"
fd -t f -e ts -e js "cookie|config"

Length of output: 827


Script:

#!/bin/bash
# Check i18n module implementation and cookie usage
echo "Checking i18n implementation files:"
rg -l "i18n" packages/web/src/

echo -e "\nChecking cookie usage in i18n related files:"
fd . packages/web/src/modules/i18n/ -t f -x rg -l "cookie"

echo -e "\nChecking content of Cookie.ts:"
cat packages/shared/src/constants/Cookie.ts

echo -e "\nChecking i18next configuration:"
rg "i18next" packages/web/src/ -A 5

Length of output: 5722

packages/web/src/modules/search-params/type.ts (1)

1-5: 타입 정의가 명확하고 잘 구조화되어 있습니다.

타입스크립트의 typeof와 인덱스 접근을 활용하여 상수로부터 타입을 생성하는 방식이 적절합니다.

packages/web/src/app/[lng]/memos/setting/page.tsx (2)

1-1: import 경로 변경이 올바르게 적용되었는지 확인이 필요합니다.

import 경로가 @src/app/i18n/type에서 @src/modules/i18n으로 변경되었습니다. 이는 코드베이스의 모듈 구조 개선을 위한 변경으로 보입니다.

다른 파일들에서도 동일한 변경이 일관되게 적용되었는지 확인하겠습니다:

✅ Verification successful

import 경로 변경이 성공적으로 완료되었습니다.

검증 결과, 모든 파일에서 @src/app/i18n/type의 이전 import 경로가 @src/modules/i18n으로 일관되게 변경되었음을 확인했습니다. 새로운 경로가 전체 코드베이스에서 올바르게 사용되고 있으며, 이전 경로를 사용하는 파일이 없습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: LanguageParams import 경로의 일관성 확인

# 이전 import 경로 사용 확인
echo "기존 import 경로 사용 확인:"
rg "from '@src/app/i18n/type'" -t tsx -t ts

# 새로운 import 경로 사용 확인
echo "\n새로운 import 경로 사용 확인:"
rg "from '@src/modules/i18n'" -t tsx -t ts

Length of output: 262


Script:

#!/bin/bash
# Description: LanguageParams import 경로의 일관성 확인 (수정된 버전)

# 이전 import 경로 사용 확인
echo "기존 import 경로 사용 확인:"
rg "@src/app/i18n/type"

# 새로운 import 경로 사용 확인
echo -e "\n새로운 import 경로 사용 확인:"
rg "@src/modules/i18n"

# i18n 관련 파일 구조 확인
echo -e "\n현재 i18n 관련 파일 구조:"
fd "i18n"

Length of output: 4746


Line range hint 1-11: 모듈 구조 변경이 적절한지 확인이 필요합니다.

i18n 관련 모듈이 @src/modules로 이동된 것은 더 나은 모듈화를 위한 것으로 보입니다. 전반적인 컴포넌트 구조는 Next.js의 국제화 라우팅 컨벤션을 잘 따르고 있습니다.

모듈 구조 변경의 영향을 확인하겠습니다:

✅ Verification successful

Let me gather more information about the i18n module structure and its usage.


모듈 구조 변경이 적절하게 이루어졌습니다.

i18n 모듈이 @src/modules/i18n으로 이동된 것이 확인되었으며, 다음과 같은 이유로 이 변경이 적절합니다:

  • 모든 i18n 관련 기능이 modules/i18n 디렉토리에 잘 구조화되어 있습니다
  • client와 server 측 번역 로직이 명확하게 분리되어 있습니다
  • 타입 정의(LanguageParams, LanguageType)가 일관되게 사용되고 있습니다
  • Next.js의 국제화 라우팅 패턴을 준수하며 모든 페이지에서 일관된 방식으로 사용되고 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: i18n 모듈 구조 변경 확인

# modules 디렉토리의 i18n 관련 파일 구조 확인
echo "새로운 i18n 모듈 구조:"
fd . -t f -p "**/modules/i18n/**"

# 다른 i18n 관련 파일들의 위치 확인
echo "\n기타 i18n 관련 파일:"
fd i18n -t f

Length of output: 291


Script:

#!/bin/bash
# Check for i18n related imports and module structure
echo "Checking i18n related imports:"
rg -l "@src/modules/i18n" --type ts --type tsx

echo "\nChecking previous i18n module location:"
rg -l "import.*i18n" --type ts --type tsx

echo "\nChecking i18n type definitions:"
rg "LanguageParams" --type ts --type tsx -A 2

Length of output: 461


Script:

#!/bin/bash
# i18n 모듈 구조와 사용 패턴 분석
echo "i18n 관련 임포트 확인:"
rg "@src/modules/i18n"

echo "\ni18n 모듈 위치 확인:"
rg "import.*i18n"

echo "\nLanguageParams 타입 정의 및 사용 확인:"
rg "LanguageParams"

echo "\n현재 디렉토리 구조 확인:"
fd . --type directory | grep -i "i18n\|modules"

Length of output: 11470

packages/web/src/hooks/index.ts (1)

3-4: 새로운 훅 내보내기가 일관된 패턴을 따르고 있습니다.

내보내기 패턴이 기존 훅들과 일치하여 코드 일관성이 잘 유지되고 있습니다.

새로운 훅의 구현을 확인하기 위해 다음 스크립트를 실행하겠습니다:

✅ Verification successful

Let me check the implementation of both hooks to ensure they are properly implemented.


새로운 훅들이 적절하게 구현되어 있으며, 일관된 패턴으로 내보내기가 이루어지고 있습니다.

  • useGetExtensionManifest: Chrome 확장 프로그램의 매니페스트를 가져오는 훅으로, 적절한 에러 처리와 상태 관리가 구현되어 있습니다.
  • useSupabaseClient: 메모이제이션된 Supabase 클라이언트를 제공하며, 싱글톤 패턴으로 구현되어 있어 성능 최적화가 잘 되어 있습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 새로운 훅 파일들의 존재 여부와 구현을 확인합니다.

echo "useGetExtensionManifest 훅 확인:"
fd "useGetExtensionManifest.ts" --type f

echo "\nuseSupabaseClient 훅 확인:"
fd "useSupabaseClient.ts" --type f

echo "\nuseSupabaseClient 사용 현황 확인:"
rg "useSupabaseClient" -A 3

Length of output: 10851


Script:

#!/bin/bash
# Check implementation of both hooks
echo "useGetExtensionManifest 구현 확인:"
cat packages/web/src/hooks/useGetExtensionManifest.ts

echo "\nuseSupabaseClient 구현 확인:"
cat packages/web/src/hooks/useSupabaseClient.ts

Length of output: 1162

packages/shared/src/utils/index.ts (1)

11-11: String 모듈 추가가 확인되었습니다.

새로운 String 모듈의 추가는 적절해 보입니다. 이는 문자열 관련 유틸리티 함수들을 더 체계적으로 관리할 수 있게 해줄 것입니다.

String 모듈의 존재와 내용을 확인하기 위해 다음 스크립트를 실행합니다:

✅ Verification successful

String 모듈이 성공적으로 검증되었습니다.

String.ts 파일이 packages/shared/src/utils/ 경로에 존재하며, checkStringArray 함수를 올바르게 내보내고 있음을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: String 모듈의 존재와 내용 확인

# String.ts 파일 찾기
fd -t f "String.ts" "packages/shared/src"

# 파일이 존재하면 내용 확인
if [ $? -eq 0 ]; then
  echo "String.ts 파일 내용:"
  rg -A 10 "export" $(fd -t f "String.ts" "packages/shared/src")
fi

Length of output: 413

packages/web/src/app/[lng]/memos/hooks/useGuide.ts (2)

2-2: 로컬 스토리지 접근 방식이 개선되었습니다!

중앙 집중화된 로컬 스토리지 접근 방식을 사용함으로써 코드의 일관성과 유지보수성이 향상되었습니다.


7-7: 가이드 체크 로직이 단순화되었습니다만, 일관성 검증이 필요합니다.

early return 패턴을 사용하여 코드가 더 깔끔해졌습니다. 다만, 'guide' 키가 다른 곳에서도 동일하게 사용되는지 확인이 필요합니다.

로컬 스토리지 키 사용의 일관성을 확인하기 위해 다음 스크립트를 실행하세요:

✅ Verification successful

'guide' 키의 사용이 일관되게 구현되어 있습니다.

코드베이스 검토 결과, 'guide' 키는 다음과 같이 일관되게 사용되고 있습니다:

  • guide.ts에서 튜토리얼 완료 시 setLocalStorageTrue('guide')를 호출
  • RefreshButton.tsx에서도 동일한 키로 setLocalStorageTrue('guide')를 호출
  • useGuide.ts에서 checkLocalStorageTrue('guide')로 일관되게 확인
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 로컬 스토리지의 'guide' 키 사용 검증

# 로컬 스토리지 관련 코드에서 'guide' 키워드 검색
echo "로컬 스토리지에서 'guide' 키 사용 확인:"
rg -l "localStorage.*['\"]guide['\"]" || rg -l "setLocalStorageTrue.*['\"]guide['\"]" || rg -l "checkLocalStorageTrue.*['\"]guide['\"]"

Length of output: 280


Script:

#!/bin/bash
# 'guide' 키워드가 사용된 파일들의 내용을 자세히 확인
echo "guide.ts 파일 내용:"
cat packages/web/src/app/[lng]/memos/utils/guide.ts

echo -e "\nRefreshButton.tsx 파일에서 guide 관련 코드:"
rg "guide" -A 3 -B 3 packages/web/src/app/[lng]/memos/components/Header/RefreshButton.tsx

Length of output: 1791

packages/web/tsconfig.json (1)

14-15: Next.js 구성과의 호환성 확인이 필요합니다

Next.js 프로젝트에서 TypeScript 설정이 올바르게 적용되는지 확인이 필요합니다.

✅ Verification successful

TypeScript 설정이 Next.js와 호환됩니다

현재 설정은 Next.js 14.2.10 버전과 완벽하게 호환됩니다:

  • next 플러그인이 올바르게 구성되어 있습니다
  • jsx: "preserve" 설정이 Next.js에 적합합니다
  • ES2015 타겟은 Next.js의 지원 범위 내에 있습니다
  • .next/types가 올바르게 포함되어 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Next.js 설정 파일들을 확인하여 TypeScript 관련 설정 검증
echo "Next.js 설정 파일 확인 중..."
fd -e js -e json -g "next.config.*"

# package.json에서 next 버전 확인
echo "Next.js 버전 확인 중..."
fd -g "package.json" --exec jq -r '.dependencies.next // .devDependencies.next'

Length of output: 326


Script:

#!/bin/bash
# Next.js 설정 파일의 내용 확인
echo "Next.js 설정 파일 내용:"
cat packages/web/next.config.js

# tsconfig.json 전체 내용 확인
echo -e "\nTypeScript 설정 파일 내용:"
cat packages/web/tsconfig.json

# Next.js 관련 의존성 확인
echo -e "\nNext.js 관련 의존성:"
cat packages/web/package.json | jq '.dependencies + .devDependencies'

Length of output: 2164

pages/side-panel/src/utils/Url.ts (1)

1-1: 설정 상수 가져오기가 적절히 구현되었습니다.

공유 상수를 사용하여 설정을 중앙 집중화한 것은 좋은 접근 방식입니다.

packages/shared/src/hooks/extension/useSupabaseClientQuery.ts (1)

1-3: 임포트 구성이 깔끔합니다!

모듈 임포트가 잘 구성되어 있으며, 일관된 경로 별칭(@src)을 사용하고 있습니다.

packages/web/src/modules/local-storage/util.ts (1)

1-1: 깔끔한 import 구문입니다!

필요한 타입과 모듈을 명확하게 가져오고 있습니다.

packages/web/src/modules/local-storage/LocalStorage.ts (1)

1-1: 타입 정의 확인이 필요합니다.

LOCAL_STORAGE_VALUE_MAPUpdateVersionType가 임포트되었지만 사용되지 않고 있습니다. 이러한 타입들이 어떻게 사용될 예정인지 확인이 필요합니다.

✅ Verification successful

임포트된 타입들이 모두 사용되고 있습니다.

검색 결과를 통해 확인한 바로는:

  • LOCAL_STORAGE_VALUE_MAPutil.ts에서 로컬 스토리지 값을 설정하고 확인하는데 사용되고 있습니다.
  • UpdateVersionTypeconstant.ts에서 버전 체크 함수의 타입으로 사용되고 있습니다.
  • LocalStorageKeyTypeLocalStorage 클래스의 메서드에서 키 타입으로 사용되고 있습니다.

따라서 해당 임포트들은 모두 필요한 것으로 확인됩니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how these types are used in other files
rg -t typescript "LOCAL_STORAGE_VALUE_MAP|UpdateVersionType" --no-filename

Length of output: 111


Script:

#!/bin/bash
# Search for type usage with ripgrep, without file type restriction
rg "LOCAL_STORAGE_VALUE_MAP|UpdateVersionType"

# Also check the index file that exports these types
fd "index.ts" --exec cat {} \;

Length of output: 31921

packages/web/src/constants/Config.ts (1)

3-7: 설정 값들을 하나의 객체로 통합한 것이 좋습니다!

설정 값들을 CONFIG 객체로 통합함으로써 코드의 일관성과 유지보수성이 향상되었습니다.

packages/web/src/components/Footer.tsx (2)

1-1: URL 상수 관리 방식의 개선이 확인되었습니다.

URL 상수들을 하나의 객체로 통합하여 관리하는 방식으로 변경된 것이 확인되었습니다. 이는 URL 관리의 일관성과 유지보수성을 향상시키는 좋은 변경사항입니다.


10-10: Chrome 스토어 URL 참조 방식이 개선되었습니다.

기존의 개별 상수 방식에서 구조화된 객체 접근 방식으로 변경되었습니다. 다만, 다른 컴포넌트들에서도 동일한 방식으로 URL을 참조하고 있는지 확인이 필요합니다.

✅ Verification successful

Let me check the actual implementation of these files to ensure consistency.


Let me check the URL constant definition to ensure it's properly structured.


URL 참조 방식이 일관되게 적용되었음을 확인했습니다.

모든 Chrome 스토어 URL 참조가 URL.chromeStore를 통해 일관되게 이루어지고 있으며, 이는 packages/shared/src/constants/Url.ts에 중앙 집중화되어 정의되어 있습니다. Footer, Introduction, ExtensionDialog 컴포넌트 모두 동일한 방식으로 URL을 참조하고 있어 일관성이 유지되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: URL 상수 사용 방식의 일관성 검증

# 이전 URL_CHROME_STORE 상수 사용 여부 확인
echo "기존 URL_CHROME_STORE 상수 사용 검색:"
rg "URL_CHROME_STORE" -l

# 새로운 URL.chromeStore 사용 패턴 확인
echo "\n새로운 URL.chromeStore 사용 검색:"
rg "URL\.chromeStore" -l

Length of output: 349


Script:

#!/bin/bash
# Check the actual implementation in files using URL.chromeStore
echo "Footer.tsx implementation:"
rg -A 2 "URL\.chromeStore" packages/web/src/components/Footer.tsx

echo "\nIntroduction.tsx implementation:"
rg -A 2 "URL\.chromeStore" packages/web/src/app/components/Introduction.tsx

echo "\ngetExtensionDialogInfo.ts implementation:"
rg -A 2 "URL\.chromeStore" packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts

# Also check if there are any other URL constant patterns
echo "\nChecking other URL patterns:"
rg "URL\." -l

Length of output: 1160


Script:

#!/bin/bash
# Find and check URL constant definition
echo "Finding URL constant definition:"
rg "const URL" -A 5

# Also check for any potential URL-related type definitions
echo "\nChecking URL-related types:"
rg "type.*URL" -A 3

Length of output: 737

packages/shared/src/utils/Notion.ts (2)

1-1: 설정 관리 개선이 잘 이루어졌습니다!

설정값을 CONFIG 객체로 중앙 집중화하는 리팩토링이 잘 진행되었습니다.


12-12: CONFIG 객체의 속성 존재 여부를 확인해주세요.

CONFIG.makeWebhookNotionApi 속성이 올바르게 설정되어 있는지 확인이 필요합니다.

✅ Verification successful

Let me verify the getSafeConfig function to ensure proper error handling and default values.


Let me check the implementation of getSafeConfig function one more time with a different pattern.


CONFIG.makeWebhookNotionApi 속성이 안전하게 구현되어 있습니다.

getSafeConfig 함수가 환경 변수가 없을 경우 명시적인 에러를 발생시키며, makeWebhookNotionApi 속성은 'development' 또는 'production' 값만 허용하도록 타입이 정의되어 있습니다. 설정이 올바르게 구현되어 있어 안전하게 사용할 수 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CONFIG 객체에서 makeWebhookNotionApi 속성의 정의를 확인

# CONFIG 정의 확인
ast-grep --pattern 'export const CONFIG = {
  $$$
  makeWebhookNotionApi: $_,
  $$$
}'

# 다른 파일에서의 사용 패턴 확인
rg "CONFIG.makeWebhookNotionApi"

Length of output: 1437


Script:

#!/bin/bash
# getSafeConfig 함수 구현 확인
ast-grep --pattern 'function getSafeConfig($_,$_) {
  $$$
}'

# 관련 타입 정의 확인
rg "type.*Config" -A 3

Length of output: 3609


Script:

#!/bin/bash
# getSafeConfig 함수의 정확한 구현 확인
rg "getSafeConfig" -A 5

# MAKE_WEBHOOK_NOTION_API 환경 변수 관련 타입 정의나 설정 확인
rg "MAKE_WEBHOOK_NOTION_API"

Length of output: 2490

packages/web/src/app/[lng]/memos/setting/component/SettingHeader/index.tsx (2)

Line range hint 1-12: 구현이 깔끔하고 잘 되어있습니다! 👍

  • 서버 사이드 렌더링 적용
  • TypeScript를 활용한 타입 정의
  • 컴포넌트 구조가 명확함
  • UI 컴포넌트와 다국어 처리가 적절히 구현됨

3-4: 모듈 경로 변경이 일관되게 적용되었는지 확인이 필요합니다.

import 경로가 @src/app/i18n에서 @src/modules/i18n으로 변경되었습니다. 이는 모듈 구조 개선을 위한 변경으로 보입니다.

다음 스크립트를 실행하여 프로젝트 전체에서 i18n 관련 import 경로가 일관되게 변경되었는지 확인하겠습니다:

✅ Verification successful

i18n 모듈 경로가 일관되게 적용되어 있습니다.

검색 결과를 분석한 결과, 모든 파일에서 새로운 경로인 @src/modules/i18n을 사용하고 있으며, 이전 경로인 @src/app/i18n을 사용하는 파일이 없음을 확인했습니다. 따라서 import 경로 변경이 프로젝트 전체에 걸쳐 일관되게 적용되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: i18n 모듈의 import 경로 일관성 검사

echo "기존 경로(@src/app/i18n) 사용 여부 확인:"
rg "@src/app/i18n" -t tsx -t ts

echo "\n새로운 경로(@src/modules/i18n) 사용 확인:"
rg "@src/modules/i18n" -t tsx -t ts

Length of output: 273


Script:

#!/bin/bash
# Description: i18n 모듈의 import 경로 일관성 검사 (수정된 버전)

echo "기존 경로(@src/app/i18n) 사용 여부 확인:"
rg --type-add 'ts:*.{ts,tsx}' --type ts "@src/app/i18n"

echo -e "\n새로운 경로(@src/modules/i18n) 사용 여부 확인:"
rg --type-add 'ts:*.{ts,tsx}' --type ts "@src/modules/i18n"

echo -e "\ni18n 모듈 파일 위치 확인:"
fd -e ts -e tsx "i18n" src/

Length of output: 4895

packages/shared/src/utils/extension/bridge/refetchTheMemos.ts (2)

1-1: 상수 가져오기 방식의 개선이 확인되었습니다.

상수 관리 구조가 개선되어 더 체계적으로 변경되었습니다. EXTENSION 객체를 통한 통합된 상수 관리는 좋은 접근 방식입니다.


6-6: 확장 프로그램 ID 참조 방식이 일관되게 수정되었습니다.

EXTENSION.id를 사용하는 방식으로 변경된 것이 확인되었습니다. 이는 확장 프로그램 관련 상수들의 일관된 관리를 위한 리팩토링과 잘 부합합니다.

다른 파일들에서도 동일한 방식으로 변경되었는지 확인하겠습니다:

✅ Verification successful

Let me generate additional verification scripts to check for any potential inconsistencies:


확장 프로그램 ID 참조가 일관되게 적용되었음을 확인했습니다

코드베이스 전체를 검사한 결과, 모든 chrome.runtime.sendMessage 호출에서 EXTENSION.id를 일관되게 사용하고 있으며, 이전 방식인 EXTENSION_ID는 더 이상 사용되지 않음을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of EXTENSION.id across the codebase
# Check for any remaining usage of EXTENSION_ID
rg "EXTENSION_ID" 

# Check the new pattern usage
rg "EXTENSION\.id"

Length of output: 520


Script:

#!/bin/bash
# Search for any chrome.runtime.sendMessage usage to ensure we haven't missed any cases
rg "chrome\.runtime\.sendMessage" -A 1

# Search for any extension ID related constants or configurations
ast-grep --pattern 'const EXTENSION = { $$$'

Length of output: 1082

packages/web/src/app/[lng]/login/components/PersonalInformationInfo/index.tsx (2)

Line range hint 4-13: 구현이 깔끔하고 타입 안전성이 잘 보장되어 있습니다.

컴포넌트가 다음과 같은 좋은 패턴을 따르고 있습니다:

  • TypeScript를 통한 명확한 타입 정의
  • i18n 훅의 올바른 사용
  • 단일 책임 원칙을 잘 지킨 간결한 구조

1-2: 모듈 구조 변경이 올바르게 적용되었는지 확인이 필요합니다.

import 경로가 @src/app/i18n에서 @src/modules/i18n으로 변경되었습니다. 이는 i18n 관련 모듈의 구조 개선을 위한 리팩토링의 일부로 보입니다.

다음 스크립트를 실행하여 i18n 모듈의 새로운 구조가 일관되게 적용되었는지 확인하겠습니다:

✅ Verification successful

i18n 모듈 경로 변경이 올바르게 적용되었음을 확인했습니다.

검색 결과를 통해 다음 사항들을 확인했습니다:

  • 모든 파일에서 @src/modules/i18n 경로를 일관되게 사용하고 있습니다.
  • 이전 경로인 @src/app/i18n을 사용하는 파일이 없습니다.
  • packages/web/src/modules/i18n/ 디렉토리가 존재합니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: i18n 모듈의 새 경로가 일관되게 사용되고 있는지 확인

# 이전 경로를 사용하는 파일이 있는지 확인
echo "이전 경로 사용 확인 중..."
rg "@src/app/i18n"

# 새 경로의 실제 존재 여부 확인
echo "새 모듈 구조 확인 중..."
fd -t f . "src/modules/i18n"

Length of output: 235


Script:

#!/bin/bash
# i18n 모듈 구조 확인을 위한 더 자세한 검색

# 1. 전체 저장소에서 i18n 관련 파일 검색
echo "=== i18n 관련 파일 검색 ==="
fd "i18n"

# 2. i18n import 사용 패턴 검색
echo -e "\n=== i18n import 패턴 검색 ==="
rg "from ['\"]@src.*i18n" -A 1

# 3. modules 디렉토리 구조 확인
echo -e "\n=== modules 디렉토리 구조 확인 ==="
fd . "modules" -t d

# 4. 현재 파일의 실제 위치 확인
echo -e "\n=== 대상 파일 위치 확인 ==="
fd "PersonalInformationInfo"

Length of output: 7650

packages/web/src/hooks/useSupabaseClient.ts (1)

1-5: 전역 변수 사용에 대한 주의 필요

전역 변수 client를 사용하는 것은 다음과 같은 잠재적인 문제를 일으킬 수 있습니다:

  • 테스트 환경에서 격리가 어려움
  • 여러 Supabase 프로젝트를 동시에 사용해야 하는 경우 문제 발생 가능

다음 스크립트를 실행하여 다중 Supabase 프로젝트 사용 여부를 확인하세요:

✅ Verification successful

전역 변수 client 사용은 안전합니다

코드베이스 분석 결과, 현재 구현은 다음과 같은 이유로 안전합니다:

  • 단일 Supabase 프로젝트만 사용 중이며, CONFIG.supabaseUrl로 중앙 관리됨
  • getSupabaseClient()는 브라우저 환경에 최적화된 클라이언트를 생성
  • 전역 변수는 클라이언트 인스턴스를 메모이제이션하는 용도로만 사용되어 적절함
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 여러 Supabase 프로젝트 설정이 있는지 확인

# env 파일에서 여러 Supabase URL 검색
rg "SUPABASE.*URL" -g "*.env*"

Length of output: 181


Script:

#!/bin/bash
# Check for Supabase configuration and usage patterns

# Search for Supabase URL configuration in any file
rg "SUPABASE.*URL"

# Search for Supabase client initialization patterns
ast-grep --pattern 'createClient($$$)'

# Search for multiple Supabase project usage
rg "supabase" -l

Length of output: 2412


Script:

#!/bin/bash
# Check Supabase client implementation details

# Check the client implementation in supabase.client.ts
cat packages/web/src/utils/supabase.client.ts

# Check if there are multiple client instances
rg "createClient\(" -A 5

# Check for any conditional client creation
rg "new.*Supabase" -A 5

Length of output: 905

packages/shared/src/utils/extension/Storage.ts (2)

1-1: 설정 관리 개선이 잘 이루어졌습니다!

상수들을 중앙 집중화된 객체로 관리하도록 변경한 것이 좋은 개선사항입니다. 이는 설정 값의 유지보수성과 일관성을 향상시킵니다.


6-7: 상수 정의 확인이 필요합니다.

SUPABASE.authTokenCONFIG.webUrl 상수가 올바르게 정의되어 있는지 확인이 필요합니다.

✅ Verification successful

상수가 올바르게 정의되어 있음을 확인했습니다

SUPABASE.authTokenCONFIG.webUrl 상수가 각각 다음 위치에서 적절하게 정의되어 있습니다:

  • packages/shared/src/constants/Supabase.ts에서 authToken: 'sb-czwtqukymcqoberdoltq-auth-token'
  • packages/shared/src/constants/Config.ts에서 webUrl: getSafeConfig('WEB_URL', process.env.WEB_URL)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the constant definitions

# Check for SUPABASE.authToken definition
rg -A 2 "SUPABASE\s*=\s*{[^}]*authToken" 

# Check for CONFIG.webUrl definition
rg -A 2 "CONFIG\s*=\s*{[^}]*webUrl"

Length of output: 331


Script:

#!/bin/bash
# Search for SUPABASE constant definition
rg "export const SUPABASE" -A 5

# Search for CONFIG constant definition
rg "export const CONFIG" -A 5

# Alternative search for these constants
rg "SUPABASE.*=.*{" -A 5
rg "CONFIG.*=.*{" -A 5

# Search for files that might contain these constants
fd -e ts -e js -x grep -l "SUPABASE\|CONFIG"

Length of output: 2522

pages/content-ui/src/index.tsx (1)

1-2: 임포트 간소화 검증 필요

여러 유틸리티 함수들의 임포트가 제거되었습니다. 특히 getMemo, insertMemo, getSupabaseClient 등의 제거는 기존 기능에 영향을 줄 수 있습니다.

다음 스크립트를 실행하여 제거된 기능들이 다른 곳으로 적절히 이전되었는지 확인하겠습니다:

✅ Verification successful

임포트 변경이 적절히 처리됨

코드베이스 분석 결과, 제거된 기능들이 다른 컴포넌트로 적절히 이전되었음을 확인했습니다:

  • getMemo, insertMemo 함수들은 packages/shared/src/utils/Supabase.ts에서 중앙 관리되고 있습니다.
  • Supabase 클라이언트 관련 기능은 packages/shared/src/hooks/supabase/ 디렉토리에서 체계적으로 관리되고 있습니다.
  • OPEN_SIDE_PANEL_IDresponsePageContent는 extension 관련 유틸리티로 적절히 유지되고 있습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 제거된 기능들이 다른 파일로 이전되었는지 확인

# getMemo, insertMemo 함수 사용처 확인
rg "getMemo|insertMemo" -t typescript -t javascript

# Supabase 클라이언트 관련 새로운 구현 확인
rg "useSupabaseClient" -t typescript -t javascript

Length of output: 174


Script:

#!/bin/bash
# Description: 제거된 기능들이 다른 파일로 이전되었는지 확인

# getMemo, insertMemo 함수 사용처 확인
rg "getMemo|insertMemo"

# Supabase 클라이언트 관련 새로운 구현 확인
rg "useSupabaseClient"

# 전체 코드베이스에서 메모 관련 기능 검색
rg "memo" -i

# extension 관련 기능 검색
rg "OPEN_SIDE_PANEL_ID|responsePageContent"

Length of output: 54245

packages/shared/src/utils/extension/bridge/getSidePanelOpen.ts (2)

1-1: 구조화된 상수 객체 사용으로의 개선을 승인합니다.

단일 상수 대신 구조화된 EXTENSION 객체를 사용하는 것은 확장 프로그램 관련 상수들을 더 체계적으로 관리할 수 있게 해주는 좋은 변경사항입니다.


6-6: 전체 코드베이스에서 EXTENSION 객체 사용 확인이 필요합니다.

EXTENSION.id를 사용하도록 변경된 부분이 정확합니다. 다만, 다른 파일들에서도 이러한 변경이 일관되게 적용되었는지 확인이 필요합니다.

다음 스크립트를 실행하여 검증하세요:

✅ Verification successful

Let me verify the usage of EXTENSION object in the codebase to ensure we have a complete understanding.


EXTENSION 객체의 사용이 일관되게 적용되었음을 확인했습니다

코드베이스 검사 결과, EXTENSION.id가 올바르게 사용되고 있으며 이전 EXTENSION_ID 상수의 사용이 완전히 제거되었음을 확인했습니다. EXTENSION 객체는 constants/Extension.ts에서 정의되어 있고, 필요한 모든 파일에서 적절하게 임포트되어 사용되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# EXTENSION_ID에서 EXTENSION.id로의 마이그레이션이 완전히 이루어졌는지 확인

# EXTENSION_ID 사용 여부 확인
echo "Checking for any remaining EXTENSION_ID usage:"
rg "EXTENSION_ID"

# EXTENSION.id 사용 확인
echo -e "\nVerifying EXTENSION.id usage:"
rg "EXTENSION\.id"

Length of output: 698


Script:

#!/bin/bash
# Check EXTENSION object definition and imports
echo "Checking EXTENSION object definition:"
rg "export const EXTENSION" -A 3

echo -e "\nChecking EXTENSION imports:"
rg "import.*EXTENSION.*from"

Length of output: 1339

packages/web/src/modules/search-params/useSearchParams.ts (1)

8-8: 타입 캐스팅 검증이 필요합니다

searchParams.entries()의 결과를 SearchParamType[]으로 타입 캐스팅하는 것이 안전한지 확인이 필요합니다. 런타임에서 예기치 않은 타입으로 인한 오류가 발생할 수 있습니다.

✅ Verification successful

타입 캐스팅이 안전합니다

searchParams.entries()의 결과를 SearchParamType[]으로 타입 캐스팅하는 것이 안전합니다. 그 이유는:

  • SearchParamKeyType이 'id', 'isWish', 'category'로 명확하게 제한되어 있습니다
  • SearchParamValueType이 string 타입으로 정의되어 있어 URLSearchParams의 값과 일치합니다
  • SearchParams 클래스가 내부적으로 Map과 Set을 사용하여 데이터를 안전하게 관리합니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# SearchParamType 정의를 확인
ast-grep --pattern 'type SearchParamType = $_'

# SearchParams 클래스에서 타입 검증 로직 확인
ast-grep --pattern 'class SearchParams {
  constructor($_) {
    $$$
  }
}'

Length of output: 249


Script:

#!/bin/bash
# SearchParamKeyType과 SearchParamValueType 정의 확인
ast-grep --pattern 'type SearchParamKeyType = $_'
ast-grep --pattern 'type SearchParamValueType = $_'

# SearchParams 클래스의 전체 구현 확인
rg -A 10 "class SearchParams" 

# 실제 사용 예시 확인
rg "new SearchParams" -A 2

Length of output: 1981


Script:

#!/bin/bash
# SEARCH_PARAMS_KEYS 상수 정의 확인
rg "SEARCH_PARAMS_KEYS.*=" -A 5

# searchParams.entries()의 실제 사용 확인
rg "searchParams\.entries\(\)" -A 2 -B 2

Length of output: 686

pages/side-panel/src/hoc/withAuthentication.tsx (2)

1-2: 훅 임포트 구조가 개선되었습니다.

공유 훅을 사용하는 방식이 더 명확하고 구조화되었습니다. useSupabaseClientQuery를 사용함으로써 React Query의 장점을 활용할 수 있게 되었습니다.


7-8: 데이터 추출 방식 검증이 필요합니다.

useSupabaseClientQueryuseSupabaseUser 훅의 반환 타입이 변경되었습니다. 이러한 변경이 다른 컴포넌트에 영향을 미치지 않는지 확인이 필요합니다.

다음 스크립트를 실행하여 영향을 받는 컴포넌트를 확인하세요:

React Query를 사용하는 것은 좋은 선택입니다. 다만, 에러 처리와 로딩 상태 처리를 추가하는 것을 고려해보세요:

-    const { data: supabaseClient } = useSupabaseClientQuery();
-    const { user } = useSupabaseUser({ supabaseClient });
+    const { data: supabaseClient, isLoading: isClientLoading } = useSupabaseClientQuery();
+    const { user, isLoading: isUserLoading } = useSupabaseUser({ supabaseClient });
+
+    if (isClientLoading || isUserLoading) return <LoadingSpinner />;
✅ Verification successful

데이터 추출 방식이 일관되게 적용되어 있습니다.

검토 결과, useSupabaseUseruseSupabaseClientQuery 훅의 반환 타입이 일관성 있게 구현되어 있습니다. 두 훅 모두 useSuspenseQuery를 사용하며, 반환되는 데이터 구조가 명확하게 정의되어 있습니다. 현재 구현된 데이터 추출 방식은 다음과 같이 안전합니다:

  • useSupabaseClientQuery: data 속성을 통해 클라이언트 인스턴스 반환
  • useSupabaseUser: user 속성을 통해 사용자 정보 반환

다른 컴포넌트들도 동일한 패턴으로 데이터를 추출하고 있어 호환성 문제가 없습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: useSupabaseUser 훅의 사용 패턴을 검색합니다.

echo "useSupabaseUser 훅 사용 검색:"
rg "useSupabaseUser.*data:\s*user" -t tsx -t ts

echo "\nuseSupabaseClientQuery 사용 검색:"
rg "useSupabaseClient(Query)?\s*\(\)" -t tsx -t ts

Length of output: 290


Script:

#!/bin/bash
# Let's try searching without file type restrictions
echo "useSupabaseUser 훅 사용 검색:"
rg "useSupabaseUser"

echo "\nuseSupabaseClientQuery 사용 검색:"
rg "useSupabaseClientQuery"

# Let's also check the file structure to understand the file extensions
echo "\n파일 구조 확인:"
fd . --extension tsx --extension ts

Length of output: 14534


Script:

#!/bin/bash
# useSupabaseUser 훅의 구현 확인
echo "useSupabaseUser 훅 구현 확인:"
cat packages/shared/src/hooks/supabase/useSupabaseUser.ts

echo "\nuseSupabaseClientQuery 훅 구현 확인:"
cat packages/shared/src/hooks/extension/useSupabaseClientQuery.ts

Length of output: 1167

packages/shared/src/hooks/supabase/useCategoryQuery.ts (2)

3-3: 임포트 변경이 적절히 이루어졌습니다.

getCategory에서 getCategories로의 함수명 변경이 일관성 있게 반영되었습니다.


12-12: 쿼리 함수 구현이 개선되었습니다.

화살표 함수를 사용한 더 간단한 구현으로 변경되었습니다. 다만, 이 변경이 다른 파일들에도 영향을 미칠 수 있으므로 전체적인 리팩토링이 제대로 이루어졌는지 확인이 필요합니다.

다음 스크립트를 실행하여 getCategory 함수의 사용처가 모두 업데이트되었는지 확인하세요:

✅ Verification successful

Let me analyze the results from the shell scripts. I can see that there are no remaining references to getCategory (singular), and all usages are consistently using getCategories (plural). The function is used in three files:

  1. Defined in packages/shared/src/utils/Supabase.ts
  2. Used in packages/shared/src/hooks/supabase/useCategoryQuery.ts
  3. Used in packages/web/src/app/[lng]/memos/layout.tsx

I can now generate the final response:

리팩토링이 일관되게 적용되었습니다

모든 코드베이스에서 getCategories 함수가 일관되게 사용되고 있으며, 이전 getCategory 함수에 대한 참조가 남아있지 않습니다. 리팩토링이 성공적으로 완료되었습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all usages of getCategory have been updated to getCategories

# Check for any remaining references to getCategory
echo "Checking for remaining 'getCategory' references:"
rg "getCategory" --type ts

# Check for new getCategories usage
echo -e "\nVerifying 'getCategories' implementation:"
rg "getCategories" --type ts

Length of output: 866

packages/shared/src/hooks/supabase/useSupabaseUser.ts (1)

11-14: 쿼리 구현이 깔끔하고 타입 안전성이 잘 보장되어 있습니다.

useSuspenseQuery의 구현이 간결하면서도 타입 안전성이 잘 보장되어 있습니다. Error 타입을 명시적으로 지정한 것이 좋은 실천 사례입니다.

packages/shared/src/utils/extension/bridge/getExtensionManifest.ts (2)

1-1: 상수 구조 개선이 잘 이루어졌습니다.

상수 관리 방식이 개선되어 더 체계적인 구조로 변경되었습니다.


6-6: EXTENSION 상수 변경에 따른 영향도 확인이 필요합니다.

EXTENSION_ID에서 EXTENSION.id로의 변경이 다른 파일들에도 일관되게 적용되었는지 확인이 필요합니다.

다음 스크립트를 실행하여 변경사항의 일관성을 검증하세요:

✅ Verification successful

Let me verify the usage of EXTENSION constant to ensure we have a complete picture.


EXTENSION 상수 변경이 일관되게 적용되었음을 확인했습니다.

코드베이스 검사 결과, 이전 EXTENSION_ID 사용이 완전히 제거되었으며, 모든 관련 파일에서 EXTENSION.id를 일관되게 사용하고 있습니다. EXTENSION 상수는 packages/shared/src/constants/Extension.ts에 올바르게 정의되어 있으며, 모든 참조가 이 새로운 형식을 따르고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# EXTENSION_ID 사용 여부 확인
echo "Checking for any remaining EXTENSION_ID usage:"
rg "EXTENSION_ID"

# EXTENSION.id 사용 패턴 확인
echo -e "\nChecking current EXTENSION.id usage:"
rg "EXTENSION\.id"

Length of output: 712


Script:

#!/bin/bash
# Check for EXTENSION constant definition and its usage
echo "Checking EXTENSION constant definition:"
rg "const EXTENSION" -A 3

# Check for any other potential EXTENSION usages
echo -e "\nChecking other EXTENSION usages:"
rg "EXTENSION\." --type ts

Length of output: 2013

packages/web/src/modules/local-storage/constant.ts (2)

5-6: 타입 가드 구현이 잘 되어있습니다

타입 안전성을 보장하는 타입 가드 패턴이 적절하게 구현되어 있습니다.


13-15: 값 매핑의 목적과 확장성 검토가 필요합니다

LOCAL_STORAGE_VALUE_MAP이 현재 단일 값만 매핑하고 있습니다. 이 상수의 목적과 향후 확장 계획을 명확히 하면 좋을 것 같습니다.

다음 스크립트로 이 매핑이 다른 곳에서 어떻게 사용되는지 확인해보겠습니다:

pages/side-panel/src/components/LoginSection.tsx (2)

1-1: 설정 관리 개선을 위한 좋은 변경사항입니다.

중앙 집중식 설정 관리를 위해 CONFIG 객체를 사용하는 것은 좋은 접근 방식입니다.


13-13: CONFIG 객체의 구조 확인이 필요합니다.

CONFIG.webUrl이 올바르게 설정되어 있는지 확인하겠습니다.

✅ Verification successful

Let me verify the getSafeConfig function implementation to ensure proper configuration handling.


CONFIG 객체가 올바르게 구성되어 있음을 확인했습니다.

검증 결과:

  • CONFIG.webUrl은 환경 변수에서 적절히 설정되고 있습니다
  • 여러 컴포넌트에서 일관되게 사용되고 있습니다
  • 로그인 페이지 URL 구성에 문제가 없습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CONFIG 객체의 구조와 webUrl 속성 확인

# constants 파일에서 CONFIG 정의 확인
rg -A 5 "export const CONFIG" 

# webUrl 사용 패턴 확인
rg "CONFIG\.webUrl"

Length of output: 2308


Script:

#!/bin/bash
# getSafeConfig 함수 구현 확인
ast-grep --pattern 'function getSafeConfig($_) {
  $$$
}'

# CONFIG import 확인
rg "import.*CONFIG" pages/side-panel/src/

Length of output: 294

packages/web/src/app/[lng]/memos/page.tsx (2)

4-5: getMemos 함수의 구현 확인이 필요합니다.

getMemo에서 getMemos로의 변경이 감지되었습니다. 이 변경이 올바르게 구현되었는지 확인이 필요합니다.

✅ Verification successful

getMemos 함수가 정상적으로 구현되어 있음을 확인했습니다.

getMemos 함수는 Supabase 클라이언트를 사용하여 메모 데이터를 조회하는 기능을 올바르게 구현하고 있습니다. 이전 getMemo 함수는 더 이상 존재하지 않으며, getMemos로의 변경이 적절하게 이루어졌습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# getMemos 함수의 구현을 확인합니다
ast-grep --pattern 'export const getMemos = $_' 

Length of output: 312


Script:

#!/bin/bash
# Check if getMemo (singular) exists in the codebase
ast-grep --pattern 'export const getMemo = $_'

# Check the implementation details of getMemos
rg -A 5 "export const getMemos" packages/shared/src/utils/Supabase.ts

Length of output: 489


14-14: 데이터 페칭 로직 검토가 필요합니다.

HydrationBoundaryWrapper의 queryFn이 getMemos로 변경되었습니다. 다음 사항들을 확인해 주세요:

  • QUERY_KEY.memos()가 새로운 getMemos 함수와 일관성이 있는지
  • 에러 처리가 적절히 구현되어 있는지
✅ Verification successful

Let me gather more information about the QUERY_KEY definition and getMemos implementation.


Let me check the getMemos implementation with a different pattern and look for error handling.


데이터 페칭 로직이 일관성 있게 구현되어 있습니다.

검증 결과:

  • QUERY_KEY.memos()는 ['memos']를 반환하며, 이는 getMemos 함수와 함께 일관되게 사용되고 있습니다.
  • getMemos 함수는 Supabase 클라이언트를 통해 데이터를 조회하며, 쿼리 키와 함께 적절히 캐시 관리가 이루어지고 있습니다.
  • 에러 처리는 React Query의 기본 에러 처리 메커니즘을 통해 자동으로 처리됩니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# QUERY_KEY 정의와 에러 처리 구현을 확인
rg -A 5 "QUERY_KEY.memos"
ast-grep --pattern 'try { $$ } catch (error) { $$ }'

Length of output: 5521


Script:

#!/bin/bash
# Check QUERY_KEY definition and getMemos implementation
rg -A 3 "export const QUERY_KEY"
ast-grep --pattern 'const getMemos = async ($_) => { $$ }'

Length of output: 366


Script:

#!/bin/bash
# Check getMemos implementation and error handling
rg -A 10 "getMemos.*=.*async"
ast-grep --pattern 'export async function getMemos($_) { $$ }'

Length of output: 1902

packages/web/src/app/[lng]/login/page.tsx (1)

5-5: i18n 모듈 경로 변경 검증 필요

모듈 구조 개선을 위한 import 경로 변경이 확인되었습니다. 다른 컴포넌트들에서도 동일한 방식으로 import가 이루어지고 있는지 확인이 필요합니다.

다음 스크립트를 실행하여 일관성을 검증하겠습니다:

✅ Verification successful

i18n 모듈 경로가 일관되게 적용되었음을 확인했습니다

모든 파일에서 새로운 import 경로 @src/modules/i18n를 사용하고 있으며, 이전 경로 @src/app/i18n/type를 사용하는 파일이 없음을 확인했습니다. 코드베이스 전반에 걸쳐 일관성이 유지되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistency of LanguageParams imports across the codebase

# Check for any remaining old imports
echo "Checking for old import path usage..."
rg "from '@src/app/i18n/type'" -l

# Check new import usage
echo "Checking new import path usage..."
rg "from '@src/modules/i18n'" -l

Length of output: 1675

packages/shared/tsconfig.json (3)

26-26: 프로젝트 구조 단순화

include 패턴을 "src"로 단순화한 것은 좋은 변경사항입니다. 하지만 모든 소스 파일이 src 디렉토리 내에 있는지 확인이 필요합니다.

✅ Verification successful

packages/shared 패키지의 TypeScript 파일이 모두 src 디렉토리 내에 있음을 확인했습니다

packages/shared 패키지의 모든 TypeScript 소스 파일이 src 디렉토리와 그 하위 디렉토리에 올바르게 위치해 있습니다. 따라서 tsconfig.json"include": ["src"] 설정이 적절합니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# src 디렉토리 외부의 TypeScript 파일 검사
fd -e ts -e tsx -E src -E node_modules -E dist

Length of output: 1355


Script:

#!/bin/bash
# packages/shared/src 디렉토리의 TypeScript 파일 확인
fd -e ts -e tsx . packages/shared/src

# packages/shared 디렉토리의 전체 구조 확인
tree packages/shared

Length of output: 5455


5-5: Jest 타입 정의 추가에 대한 검토

Jest 타입을 추가한 것은 테스트 인프라 통합을 위한 좋은 변경사항입니다. 단, 테스트 파일이 올바르게 구성되어 있는지 확인이 필요합니다.

✅ Verification successful

Jest 타입 정의 추가가 적절히 구성되었음을 확인했습니다

테스트 파일들이 packages/web/src/modules/tests/e2e/ 디렉토리에 적절히 존재하는 것을 확인했습니다. Jest 타입 정의를 shared 패키지의 tsconfig.json에 추가한 것은 타당한 변경사항입니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Jest 설정 및 테스트 파일 존재 여부 확인
fd -e test.ts -e test.tsx -e spec.ts -e spec.tsx

Length of output: 194


Script:

#!/bin/bash
# Jest 설정 파일 확인
fd jest.config

Length of output: 16


Script:

#!/bin/bash
# package.json에서 Jest 관련 설정 및 의존성 확인
fd package.json --exec cat {} | jq 'select(.jest != null or .dependencies.jest != null or .devDependencies.jest != null)'

Length of output: 125


Script:

#!/bin/bash
# shared 패키지의 테스트 관련 import 확인
rg "import.*jest" packages/shared/

Length of output: 36


9-9: ⚠️ Potential issue

모듈 해결 전략 변경에 대한 중요 검토

모듈 해결 방식의 주요 변경사항이 있습니다:

  1. 경로 매핑이 더 일반적인 @*로 변경됨
  2. 모듈 시스템이 "es2015"로 변경됨
  3. moduleResolution이 "bundler"로 변경됨

이러한 변경은 번들러 호환성을 개선하지만, 기존 임포트 구문의 호환성을 확인해야 합니다.

Also applies to: 16-16, 20-20

✅ Verification successful

모듈 해결 전략 변경이 안전함을 확인했습니다

코드베이스 분석 결과, 다음과 같은 이유로 변경이 안전합니다:

  1. 대부분의 임포트가 @extension, @src, @root 등 명확한 접두사를 사용하고 있어 와일드카드 패턴 @*이 기존 임포트를 모두 포함합니다.
  2. 모듈 시스템이 "es2015"로 변경되었지만, 대부분의 코드가 이미 ES 모듈 구문을 사용하고 있습니다.
  3. "bundler" moduleResolution은 Vite, Webpack과 같은 현대 번들러와의 호환성을 개선합니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 기존 임포트 패턴 검사
rg -t typescript -t javascript "from ['\"]@src/" 

Length of output: 87


Script:

#!/bin/bash
# TypeScript 파일에서 @ 접두사로 시작하는 모든 임포트 검색
rg "from ['\"]@" --type=ts --type=tsx

# 현재 tsconfig 파일들의 paths 설정 확인
fd tsconfig.json --exec cat {} 

Length of output: 3291


Script:

#!/bin/bash
# 모든 소스 파일에서 @ 접두사로 시작하는 임포트 패턴 검색
rg "from ['\"]@" 

# 파일 확장자 패턴 확인
fd -e ts -e tsx -e js -e jsx --exec echo {}

Length of output: 57228

packages/web/src/modules/i18n/server.js (1)

4-4: import 경로 변경에 대한 검증이 필요합니다.

getOptions 함수의 import 경로가 './settings'에서 './util'로 변경되었습니다. 이 변경이 올바르게 적용되었는지 확인이 필요합니다.

✅ Verification successful

import 경로 변경이 정상적으로 확인되었습니다.

getOptions 함수가 util.ts에 올바르게 구현되어 있으며, 다음과 같이 검증되었습니다:

  • util.ts에서 getOptions 함수가 정상적으로 export 되어 있음
  • client.jsserver.js 모두 새로운 경로인 './util'에서 import하여 사용 중
  • 함수의 사용 방식이 동일하게 유지됨 (getOptions(lng, ns) 형태로 호출)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify getOptions function exists in new location and check for any references to old location

# Check if getOptions exists in new location
echo "Checking for getOptions in util file..."
rg -l "export.*getOptions" "packages/web/src/modules/i18n"

# Check for any remaining references to old path
echo "Checking for remaining references to old path..."
rg -l "from.*['\"]./settings['\"]" "packages/web/src/modules/i18n"

Length of output: 363


Script:

#!/bin/bash
# Let's verify the actual implementation of getOptions in both files

# Check the implementation in util.ts
echo "=== Content of getOptions in util.ts ==="
ast-grep --pattern 'export $_ getOptions$_' -f packages/web/src/modules/i18n/util.ts -A 10

# Check if there are any remaining files that might contain the old implementation
echo -e "\n=== Files containing 'getOptions' ==="
rg "getOptions" packages/web/src/modules/i18n --type ts --type js -C 2

# Check for any potential usage differences
echo -e "\n=== Usage of getOptions in server.js ==="
rg "getOptions" packages/web/src/modules/i18n/server.js -C 2

Length of output: 3067

packages/shared/src/utils/Sentry.ts (2)

16-16: DSN 설정 변경이 적절합니다

중앙 집중식 설정 관리로의 전환이 잘 이루어졌습니다.


4-4: CONFIG 상수의 구조 확인이 필요합니다

CONFIG 객체에서 sentryDsn이 올바르게 정의되어 있는지 확인이 필요합니다.

✅ Verification successful

CONFIG 상수가 올바르게 구현되어 있습니다

CONFIG 객체에 sentryDsn이 적절하게 정의되어 있으며, getSafeConfig 함수를 통해 환경 변수가 없을 경우의 에러 처리도 잘 구현되어 있습니다. Sentry.ts 파일에서의 사용도 정확합니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# CONFIG 객체의 구조와 sentryDsn 속성 확인

# CONFIG 타입 정의 확인
ast-grep --pattern 'interface CONFIG {
  $$$
  sentryDsn: $_
  $$$
}'

# CONFIG 객체 정의 확인
ast-grep --pattern 'export const CONFIG = {
  $$$
  sentryDsn: $_
  $$$
}'

Length of output: 148


Script:

#!/bin/bash
# CONFIG 관련 파일 찾기
fd "config|constants" --type f

# CONFIG 정의 검색 (다른 패턴 시도)
rg -l "CONFIG.*=.*{" --type ts

# sentryDsn 문자열 검색
rg "sentryDsn" --type ts -A 2

Length of output: 1742


Script:

#!/bin/bash
# Config.ts 파일의 전체 내용 확인
cat packages/shared/src/constants/Config.ts

# Sentry.ts 파일의 전체 내용 확인
cat packages/shared/src/utils/Sentry.ts

Length of output: 1758

packages/web/src/utils/supabase.client.ts (3)

1-1: 설정 관리 개선을 위한 import 구조 변경이 확인되었습니다.

개별 상수들을 중앙 집중식 설정 객체로 통합한 것은 좋은 접근 방식입니다. 이는 설정 관리를 더욱 용이하게 만들어줍니다.

Also applies to: 3-3


21-21: 스키마 참조 방식이 개선되었습니다.

SUPABASE.schemaMemo를 통한 스키마 참조는 타입 안정성을 높여주는 좋은 접근입니다.

스키마 상수가 올바르게 정의되어 있는지 확인하겠습니다:

✅ Verification successful

SUPABASE.schemaMemo 사용이 일관되게 구현되어 있습니다

packages/shared/src/constants/Supabase.ts에서 schemaMemo가 'memo'로 올바르게 정의되어 있으며, 이 상수가 클라이언트, 서버 및 공유 유틸리티 전반에 걸쳐 일관되게 사용되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify schema constant definition

# Check SUPABASE schema definition
ast-grep --pattern 'export const SUPABASE = {
  $$$
  schemaMemo: $_
  $$$
}'

Length of output: 79


Script:

#!/bin/bash
# Let's try to find SUPABASE constant definition with ripgrep
rg "SUPABASE.*=.*{" -A 10

# Also search for schemaMemo usage
rg "schemaMemo" -A 2

Length of output: 2209


Line range hint 7-21: 인증 관련 설정의 보안성 검증이 필요합니다.

쿠키 기반의 인증 저장소 구현이 적절해 보이나, 보안 설정을 확인해야 합니다.

다음 스크립트를 실행하여 환경 설정 값들이 올바르게 참조되는지 확인하세요:

✅ Verification successful

Let me gather more information about the configuration values.


Let me check one more thing about the configuration and environment variables.


인증 관련 쿠키 설정이 적절하게 구현되어 있습니다.

현재 구현된 인증 저장소의 쿠키 설정이 다음과 같이 적절한 보안 설정을 포함하고 있습니다:

  • SameSite=Strict: CSRF 공격 방지
  • Secure: HTTPS 통신 강제
  • max-age=31536000: 1년의 적절한 만료 기간 설정
  • path=/: 올바른 경로 설정

또한 Supabase 클라이언트 구성이 환경 변수를 통해 안전하게 관리되고 있음을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the configuration values and their usage

# Check if CONFIG values are properly defined
rg -A 2 "CONFIG\." "packages/shared/src/constants/"

# Verify cookie security settings across the codebase
rg "SameSite|Secure|max-age" --type ts

Length of output: 527


Script:

#!/bin/bash
# Check for CONFIG definition and usage
rg -p "CONFIG\s*=\s*{" --type ts -A 10

# Check for any other cookie-related security configurations
rg -p "cookie.*=.*" --type ts

# Look for any environment variable definitions that might contain Supabase configuration
fd .env --exec cat {} \; || true

Length of output: 2338


Script:

#!/bin/bash
# Check for Supabase configuration and environment variables
rg -p "supabase.*Key|SUPABASE_" --type ts -A 2

# Check for any environment variable files
fd -e env -e env.example -e env.local --exec cat {} \; || true

# Look for schema definitions
rg "schemaMemo" --type ts -A 5

Length of output: 4631

packages/shared/src/hooks/supabase/useMemosQuery.ts (2)

2-7: 타입 정의가 잘 구현되었습니다!

타입 안전성을 높이기 위한 다음 변경사항들이 잘 구현되었습니다:

  • MemoSupabaseClient를 타입으로 임포트
  • QueryData 타입을 getMemos 함수의 반환 타입으로부터 자동 유추
  • QueryErrorError 타입으로 명시적 정의

9-11: 인터페이스 설계가 견고합니다!

UseMemosQueryProps 인터페이스가 다음과 같이 잘 설계되었습니다:

  • UseQueryOptions를 확장하여 React Query의 모든 옵션을 지원
  • queryKeyqueryFn을 올바르게 제외하여 내부 구현과의 충돌 방지
packages/web/src/app/[lng]/login/components/LoginSection/ExtensionVersion.tsx (1)

3-6: 깔끔한 의존성 관리와 타입 정의

모듈 임포트가 잘 구성되어 있으며, 공유 상수와 국제화 모듈을 적절히 활용하고 있습니다.

packages/web/src/app/[lng]/memos/components/MemoSidebarTrigger/index.tsx (2)

Line range hint 1-24: 컴포넌트 구조 검토 완료

서버 컴포넌트로 적절히 구현되어 있으며, 사이드바 트리거와 툴팁 기능이 잘 통합되어 있습니다. 타입 정의와 번역 처리도 올바르게 구현되어 있습니다.


6-7: i18n 모듈 경로 변경 검증 필요

i18n 관련 모듈의 import 경로가 변경되었습니다. 이는 전반적인 i18n 기능의 모듈화 작업의 일환으로 보입니다.

다음 스크립트를 실행하여 i18n 모듈의 일관된 사용을 확인하겠습니다:

✅ Verification successful

i18n 모듈 경로 변경이 일관되게 적용되었습니다

검증 결과, 모든 i18n 관련 import가 새로운 경로인 @src/modules/i18n을 사용하고 있으며, 이전 경로인 @src/app/i18n을 사용하는 파일이 없음을 확인했습니다. 경로 변경이 프로젝트 전반에 걸쳐 일관되게 적용되었습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# i18n 모듈 사용 패턴 검증

# 이전 경로 사용 여부 확인
echo "이전 경로 사용 검사 중..."
rg "@src/app/i18n/(type|server)"

# 새로운 경로 사용 패턴 확인
echo "새로운 경로 사용 패턴 검사 중..."
rg "@src/modules/i18n(/server)?"

Length of output: 4614

packages/web/src/hooks/useMemoDeleteMutation.ts (2)

2-2: 불필요한 import 제거 및 필요한 import 추가 완료

사용하지 않는 MemoTable 타입을 제거하고 useSupabaseClient 훅을 추가한 변경이 적절합니다.

Also applies to: 5-5


13-13: Supabase 클라이언트 관리 방식 개선

getSupabaseClient()에서 useSupabaseClient 훅으로 변경한 것은 다음과 같은 이점이 있습니다:

  • React 훅 패턴을 따르는 일관된 구현
  • 컴포넌트 수준에서 클라이언트 인스턴스 관리
  • 불필요한 클라이언트 재생성 방지
packages/shared/src/constants/Config.ts (1)

12-15: 타입 어서션 사용이 올바른지 확인이 필요합니다.

nodeEnvmakeWebhookNotionApi에 대한 타입 어서션이 적절히 구현되어 있습니다. 하지만 이러한 타입 제한이 애플리케이션의 다른 부분에서도 일관되게 적용되는지 확인이 필요합니다.

다음 스크립트로 타입 사용을 확인해보세요:

✅ Verification successful

Let me gather more information about the type usage and validation.


타입 어서션이 적절하게 사용되고 있음을 확인했습니다.

코드베이스 분석 결과:

  • nodeEnvisProduction 체크에서 올바르게 사용되고 있으며, 빌드 설정과 쿠키 보안 설정에서도 일관되게 'production'/'development' 값이 활용됩니다.
  • makeWebhookNotionApi는 Notion API 호출 시에만 사용되며, 타입 제한된 값이 적절히 전달됩니다.
  • getSafeConfig 함수가 환경 변수의 존재 여부를 확실히 검증하므로, 타입 어서션의 안전성이 보장됩니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: CONFIG 객체의 타입 어서션 사용 확인

# nodeEnv와 makeWebhookNotionApi 타입 사용 검색
echo "Checking nodeEnv usage:"
rg "CONFIG\.nodeEnv" -A 2

echo "Checking makeWebhookNotionApi usage:"
rg "CONFIG\.makeWebhookNotionApi" -A 2

Length of output: 536


Script:

#!/bin/bash
# Check type definitions and validations for these environment variables
echo "Checking getSafeConfig implementation:"
rg "getSafeConfig" -A 5

echo "Checking environment type definitions:"
ast-grep --pattern 'type $_ = $$$| "development" |$$$| "production" |$$$'

echo "Checking environment validation:"
rg "process\.env\.(NODE_ENV|MAKE_WEBHOOK_NOTION_API)" -A 2

Length of output: 4049

packages/shared/src/hooks/supabase/useMemoQuery.ts (1)

3-3: 함수 이름 변경이 일관성 있게 적용되었습니다!

getMemo에서 getMemos로의 변경이 다른 파일들의 변경사항과 잘 맞춰져 있습니다.

packages/web/src/app/auth/callback/route.ts (1)

4-4: 쿠키 키 상수 통합 변경 승인

쿠키 키 상수들을 하나의 객체로 통합한 변경이 전반적인 코드 구조를 개선했습니다.

packages/web/src/hooks/useLanguage.ts (1)

1-2: 모듈 구조 개선이 잘 이루어졌습니다.

i18n 관련 import를 @src/modules/i18n으로 중앙화하여 모듈 구조가 개선되었습니다. 이는 코드의 유지보수성과 가독성을 향상시킵니다.

새로운 import 경로가 올바르게 설정되어 있는지 확인하겠습니다:

✅ Verification successful

모듈 구조 변경이 정상적으로 구현되었습니다.

@src/modules/i18n 경로의 모듈이 올바르게 구성되어 있으며, fallbackLngLanguage 타입이 정확하게 export되어 있는 것을 확인했습니다. 모듈화가 잘 되어있어 코드의 구조와 유지보수성이 향상되었습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of the new i18n module structure

# Check if the new i18n module exists and contains the required exports
fd -e ts -e tsx "i18n.(ts|tsx)$" src/modules/ --exec grep -l "export.*{.*fallbackLng.*}"
fd -e ts -e tsx "i18n.(ts|tsx)$" src/modules/ --exec grep -l "export.*{.*Language.*}"

Length of output: 378


Script:

#!/bin/bash
# Let's try searching in the packages directory structure
fd -e ts -e tsx "i18n.(ts|tsx)$" packages/ --exec grep -l "export.*{.*fallbackLng.*}"
fd -e ts -e tsx "i18n.(ts|tsx)$" packages/ --exec grep -l "export.*{.*Language.*}"

# Also search for the actual module path
fd -e ts -e tsx "i18n.(ts|tsx)$" packages/web/src/modules/ --exec grep -l "export.*{.*fallbackLng.*}"
fd -e ts -e tsx "i18n.(ts|tsx)$" packages/web/src/modules/ --exec grep -l "export.*{.*Language.*}"

# Let's check if the file exists first
fd -e ts -e tsx "i18n.(ts|tsx)$" packages/

Length of output: 473


Script:

#!/bin/bash
# Let's check the content of the found i18n file and the import path structure
cat packages/shared/src/utils/extension/module/I18n.ts

# Let's also check if there are any other i18n-related files in the project
rg -l "fallbackLng|Language.*export" packages/

Length of output: 419


Script:

#!/bin/bash
# Let's check the content of the found i18n-related files in web package
cat packages/web/src/modules/i18n/util.ts
cat packages/web/src/modules/i18n/constant.ts

# Also check the actual import path mentioned in the review
ls -la packages/web/src/modules/i18n/

Length of output: 1059


Script:

#!/bin/bash
# Let's check the content of type.ts and index.ts to verify the Language export
cat packages/web/src/modules/i18n/type.ts
cat packages/web/src/modules/i18n/index.ts

Length of output: 358

packages/web/src/app/auth/callback-email/route.ts (2)

4-4: LGTM! 쿠키 상수 가져오기 개선

쿠키 키 상수들을 단일 객체로 통합한 것은 유지보수성 향상에 도움이 됩니다.


16-22: LGTM! 접근 토큰 쿠키 설정

접근 토큰에 대한 쿠키 설정이 적절하게 구현되었습니다. 보안 관련 설정(httpOnly, secure, sameSite)이 올바르게 유지되었습니다.

packages/web/src/app/[lng]/memos/components/MemoView/index.tsx (2)

3-3: 임포트 구조가 개선되었습니다!

Next.js의 기본 기능을 활용하는 방향으로 리팩토링이 잘 이루어졌습니다. 커스텀 라우터 대신 내장 기능을 사용함으로써 코드의 복잡성이 줄어들었습니다.

Also applies to: 5-5, 6-6, 9-9


14-17: 🛠️ Refactor suggestion

검색 파라미터 처리 시 null 안전성 개선이 필요합니다.

searchParams.get()이 null을 반환할 수 있으므로, 기본값 처리를 추가하는 것이 좋습니다.

다음과 같이 개선해보세요:

- const isWish = searchParams.get('isWish') === 'true';
- const category = searchParams.get('category');
+ const isWish = searchParams.get('isWish') === 'true' ?? false;
+ const category = searchParams.get('category') ?? undefined;

Likely invalid or redundant comment.

packages/web/src/app/[lng]/memos/components/Header/RefreshButton.tsx (2)

5-6: 모듈 구조 개선이 잘 이루어졌습니다!

i18n 관련 모듈들이 더 명확한 위치로 이동되었고, local storage 관련 기능이 모듈화되어 재사용성이 향상되었습니다.

Also applies to: 11-11


18-18: 성능 최적화가 잘 이루어졌습니다!

queryClient를 핸들러 함수 외부에서 초기화하여 불필요한 재생성을 방지했습니다.

packages/web/src/app/[lng]/memos/setting/component/Setting/index.tsx (1)

3-4: 모듈 경로 변경이 일관되게 적용되었는지 확인이 필요합니다.

import 경로가 @src/app/i18n에서 @src/modules/i18n으로 변경되었습니다. 변경 자체는 적절해 보이나, 다른 컴포넌트들에서도 동일한 방식으로 적용되었는지 확인이 필요합니다.

다음 스크립트를 실행하여 일관성을 확인하세요:

✅ Verification successful

모듈 경로 변경이 성공적으로 완료되었습니다.

검색 결과에 따르면 @src/app/i18n의 이전 경로를 사용하는 파일이 없으며, 모든 관련 파일들이 새로운 @src/modules/i18n 경로를 일관되게 사용하고 있습니다. 이는 리팩토링이 프로젝트 전체에 걸쳐 완전히 적용되었음을 보여줍니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: i18n 모듈의 import 경로 일관성 검사

# 이전 경로를 사용하는 파일 검색
echo "이전 경로(@src/app/i18n)를 사용 중인 파일 확인:"
rg "@src/app/i18n" --type ts --type tsx

# 새로운 경로를 사용하는 파일 검색
echo -e "\n새로운 경로(@src/modules/i18n)를 사용 중인 파일 확인:"
rg "@src/modules/i18n" --type ts --type tsx

Length of output: 313


Script:

#!/bin/bash
# Let's try a different approach using ripgrep without file type filters
echo "이전 경로(@src/app/i18n)를 사용 중인 파일 검색:"
rg -l "@src/app/i18n"

echo -e "\n새로운 경로(@src/modules/i18n)를 사용 중인 파일 검색:"
rg -l "@src/modules/i18n"

Length of output: 1652

packages/web/src/app/[lng]/memos/components/MemoSidebar/SidebarMenuItemAddCategory.tsx (3)

5-5: 임포트 구조가 개선되었습니다.

클라이언트 관리 방식이 유틸리티 함수에서 훅 기반으로 변경되었고, 타입 정의가 별도 파일로 분리되어 재사용성이 향상되었습니다.

Also applies to: 9-9


12-12: Supabase 클라이언트 초기화 방식이 개선되었습니다.

훅 기반 접근 방식으로 변경되어 컴포넌트의 생명주기와 더 잘 통합되었습니다. 또한 타입 안정성이 향상되었습니다.

다른 컴포넌트들도 동일한 패턴을 따르는지 확인이 필요합니다:

Also applies to: 14-14

✅ Verification successful

Supabase 클라이언트 초기화 패턴이 일관되게 적용되어 있습니다.

검증 결과, 웹 애플리케이션의 클라이언트 사이드 컴포넌트들은 모두 useSupabaseClient 훅을 사용하고 있으며, 서버 사이드 컴포넌트들은 getSupabaseClient를 사용하는 일관된 패턴을 보여주고 있습니다. 이는 의도된 설계대로 올바르게 구현되어 있습니다.

  • 클라이언트 컴포넌트들: MemoSidebar, MemoDialog, MemoView 등에서 useSupabaseClient 사용
  • 서버 컴포넌트들: layout.tsx, page.tsx, route.ts 등에서 getSupabaseClient 사용
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 기존 getSupabaseClient 사용 여부 확인
rg "getSupabaseClient" --type typescript

Length of output: 75


Script:

#!/bin/bash
# Search for getSupabaseClient usage with ripgrep
rg "getSupabaseClient"

# Search for useSupabaseClient usage to verify the new pattern
rg "useSupabaseClient"

# Search for supabase client initialization patterns in typescript files
fd -e ts -e tsx --exec rg -l "supabase.*client"

Length of output: 5784


20-20: 뮤테이션 훅 사용이 일관성 있게 수정되었습니다.

Supabase 클라이언트가 적절하게 뮤테이션 훅에 전달되도록 변경되었습니다.

다른 뮤테이션 훅들도 동일한 패턴을 따르는지 확인이 필요합니다:

✅ Verification successful

뮤테이션 훅의 일관성이 확인되었습니다.

검색 결과를 통해 다음과 같은 사항들이 확인되었습니다:

  • useMemoPostMutation, useMemoPatchMutation, useCategoryPostMutation 등 모든 Supabase 관련 뮤테이션 훅들이 supabaseClient를 일관되게 전달받고 있습니다.
  • 각 컴포넌트에서 이러한 뮤테이션 훅들을 사용할 때도 동일한 패턴으로 supabaseClient를 전달하고 있습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 뮤테이션 훅 패턴 확인
ast-grep --pattern 'use$_Mutation({ supabaseClient })'

Length of output: 56


Script:

#!/bin/bash
# Search for mutation hook usage patterns
rg "use.*Mutation.*supabaseClient" -A 2

Length of output: 1588


Script:

#!/bin/bash
# Search for mutation hook declarations
ast-grep --pattern 'export const use$_Mutation = ({ supabaseClient }: { supabaseClient: SupabaseClient }) => {'

Length of output: 113


Script:

#!/bin/bash
# Search for any mutation hook usage
rg "use.*Mutation" -A 2

Length of output: 10508

packages/web/src/app/[lng]/memos/utils/guide.ts (2)

2-5: 가져오기 구문이 잘 정리되었습니다! ✨

CSS, 내부 모듈, 외부 모듈 순서로 잘 정리되어 있으며, 로컬 스토리지 관리를 중앙화하는 방식으로 개선되었습니다.


40-43: 가이드 완료 처리가 개선되었습니다! 👍

로컬 스토리지 관리를 중앙화된 유틸리티 함수를 통해 처리하도록 개선된 점이 좋습니다.

가이드 완료 상태가 다른 컴포넌트에서도 올바르게 사용되는지 확인이 필요합니다:

✅ Verification successful

Let me analyze the usage of guide-related localStorage operations more broadly to verify the implementation.


가이드 상태 관리가 일관되게 구현되어 있습니다 ✅

가이드 완료 상태가 다음과 같이 일관된 방식으로 관리되고 있음을 확인했습니다:

  • LOCAL_STORAGE_KEY에 'guide' 키가 상수로 정의되어 있습니다
  • useGuide 훅에서 checkLocalStorageTrue('guide')를 통해 가이드 상태를 확인합니다
  • RefreshButton 컴포넌트와 가이드 유틸리티에서 setLocalStorageTrue('guide')를 사용하여 가이드 완료를 처리합니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 가이드 완료 상태 사용 확인
rg "getLocalStorage.*('guide')" --type ts

Length of output: 49


Script:

#!/bin/bash
# Search for any usage of 'guide' in localStorage related operations
rg "localStorage.*guide" --type ts -A 2

# Also search for guide-related state management
rg "('|\")guide('|\")" --type ts -A 2

Length of output: 1181

packages/web/src/app/components/Introduction.tsx (2)

1-1: URL 상수 관리 개선이 잘 이루어졌습니다.

개별 URL 상수를 하나의 객체로 통합하여 관리하는 방식으로 변경된 것이 좋습니다. 이는 URL 관리의 일관성과 유지보수성을 향상시킵니다.


7-8: 클래스명 구조가 개선되었습니다.

Tailwind 클래스명의 순서가 더 일관성 있게 정리되었습니다. 이는 코드의 가독성을 향상시킵니다.

Also applies to: 15-15

pages/side-panel/src/components/MemoHeader.tsx (3)

1-2: 훅 임포트 구조가 개선되었습니다.

공통 훅과 확장 프로그램 전용 훅이 명확하게 구분되어 있어 코드의 구조가 더 명확해졌습니다.


9-9: Supabase 클라이언트 사용 방식이 개선되었습니다.

useSupabaseClientQuery를 사용하여 클라이언트를 가져오는 방식이 더 일관성 있고 타입 안정성이 향상되었습니다.


11-14: 메모 데이터 구조 변경을 확인해주세요.

useMemoQuery 훅의 반환값 구조가 변경되었습니다 (data: currentMemomemo: memoData). 이 변경이 다른 컴포넌트에도 영향을 미칠 수 있습니다.

다른 컴포넌트에서의 사용을 확인하기 위해 다음 스크립트를 실행하세요:

✅ Verification successful

Let me analyze the usage of useMemoQuery across the codebase. I can see that all instances are using the new structure with memo: memoData. Let me verify the implementation of the hook itself to ensure completeness.


useMemoQuery 훅의 변경이 일관되게 적용되어 있습니다.

코드베이스 전체를 검토한 결과, useMemoQuery 훅의 반환값 구조 변경(data: currentMemomemo: memoData)이 모든 사용처에서 일관되게 적용되어 있음을 확인했습니다. 다음 파일들에서 모두 새로운 구조를 사용하고 있습니다:

  • pages/side-panel/src/components/MemoForm.tsx
  • pages/side-panel/src/components/MemoHeader.tsx
  • packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# useMemoQuery 훅의 사용 패턴을 검색
rg "useMemoQuery" -A 3

Length of output: 3103


Script:

#!/bin/bash
# Check the implementation of useMemoQuery hook
ast-grep --pattern 'export default function useMemoQuery($_) {
  $$$
}'

Length of output: 1657

packages/web/src/utils/middleware.ts (1)

2-2: 설정 관리 개선이 잘 이루어졌습니다!

개별 상수 import에서 통합된 CONFIG 객체를 사용하도록 변경한 것이 좋은 개선사항입니다. 이는 설정 관리를 중앙화하고 유지보수성을 향상시킵니다.

packages/web/src/middleware.ts (2)

2-5: 모듈 구조 변경 검증 필요

i18n 관련 상수들의 import 경로가 변경되었습니다. 이러한 구조 변경이 전체 코드베이스에서 일관되게 적용되었는지 확인이 필요합니다.

✅ Verification successful

Let me gather more information about the i18n related imports to verify the module structure changes.


모듈 구조 변경이 일관되게 적용되었음을 확인했습니다

i18n 관련 상수들과 타입들이 modules/i18n 디렉토리로 올바르게 이전되었으며, 모든 참조 파일들(middleware.ts, hooks/useLanguage.ts, app/[lng]/layout.tsx 등)에서 새로운 경로를 사용하고 있습니다. 이전 경로인 ./app/i18n/settings를 사용하는 파일이 없어 구조 변경이 완전히 이루어졌음을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of new import paths

# Check for any remaining old import paths
rg -l "from './app/i18n/settings'"

# Check adoption of new import path
rg -l "from './modules/i18n'"

Length of output: 111


Script:

#!/bin/bash
# Search for any i18n related imports and constants
rg -l "fallbackLng|languages|cookieName" --type ts

# Check content of files that might be using i18n constants
rg "fallbackLng|languages|cookieName" --type ts -C 2

Length of output: 4563


7-7: 새로운 유효성 검사 메서드의 동작 확인 필요

isStringArray에서 checkStringArray로의 변경이 있었습니다. 두 함수의 동작이 완전히 동일한지 확인이 필요합니다.

✅ Verification successful

유효성 검사 메서드 변경이 적절하게 이루어졌습니다

checkStringArray 함수의 구현을 확인한 결과, 이전 isStringArray 함수와 동일한 검증 로직을 수행합니다:

  • 입력값이 배열인지 확인
  • 배열의 모든 요소가 문자열인지 검증
  • 타입 가드로서 value is string[] 타입 보장

이는 안전한 변경이며 기존 기능이 그대로 유지됩니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Compare the implementation of both validation methods

# Search for the new validation method implementation
ast-grep --pattern 'export function checkStringArray($_) {
  $$$
}'

# Search for any remaining usage of old validation method
rg 'isStringArray'

Length of output: 88


Script:

#!/bin/bash
# Let's try a broader search for both functions and their usages

# Search for checkStringArray function or type definition
rg -A 5 "checkStringArray"

# Search for isStringArray function or type definition
rg -A 5 "isStringArray"

# Search for files containing either of these functions
fd -t f -e ts -e tsx -x grep -l "checkStringArray\|isStringArray" {}

Length of output: 1154

packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts (1)

30-33: 버전 비교 로직 검증 필요

manifest?.version이 없는 경우나 버전 형식이 일치하지 않는 경우에 대한 처리가 필요합니다.

버전 비교 로직을 검증하기 위해 다음 스크립트를 실행하세요:

✅ Verification successful

Let me gather more information about the version handling logic.


Let me try one more search to find the EXTENSION constant definition with a corrected regex:


버전 처리가 적절히 구현되어 있습니다

버전 비교 로직이 다음과 같이 안전하게 구현되어 있습니다:

  • manifest?.version으로 옵셔널 체이닝을 사용하여 manifest가 없는 경우를 처리
  • EXTENSION.lastVersion이 상수로 명확하게 정의되어 있음 ('1.6.4')
  • 버전 비교가 엄격한 동등 비교 연산자(!==)를 사용하여 정확하게 수행됨
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# manifest와 EXTENSION.lastVersion의 사용을 확인
rg -A 2 "manifest.*version|EXTENSION\.lastVersion" 

Length of output: 1681


Script:

#!/bin/bash
# Check how manifest and version are handled
ast-grep --pattern 'const manifest = $_'

# Check EXTENSION constant definition
rg "EXTENSION.*=.*{" -A 5

# Check version comparison implementation
ast-grep --pattern 'if ($_ !== EXTENSION.lastVersion) {
  $$$
}'

Length of output: 4389


Script:

#!/bin/bash
# Check EXTENSION constant definition with fixed regex
rg "EXTENSION\s*=\s*" -A 5

# Check how version is used in the extension dialog
ast-grep --pattern 'useExtensionDialog($$$)'

Length of output: 489

packages/web/src/app/[lng]/layout.tsx (2)

11-12: 모듈 임포트 구조가 개선되었습니다.

상대 경로에서 절대 경로로의 변경은 코드의 가독성과 유지보수성을 향상시킵니다. @src/modules/i18n에서 타입과 상수를 가져오는 방식이 더 명확합니다.


46-46: ExtensionDialog 배치 위치를 검토해주세요.

ExtensionDialog가 전역 레이아웃에 추가된 것은 적절해 보이나, 다음 사항들을 확인해주시기 바랍니다:

  1. 다이얼로그가 다른 UI 요소들(예: Toaster)과 겹치지 않는지
  2. z-index 관리가 적절한지
  3. 페이지 전환 시 다이얼로그 상태가 올바르게 유지되는지

다음 스크립트로 z-index 충돌 여부를 확인할 수 있습니다:

✅ Verification successful

ExtensionDialog의 배치가 적절합니다

레이아웃 파일을 검토한 결과, ExtensionDialog와 Toaster의 배치가 적절하게 되어 있습니다:

  • ExtensionDialog와 Toaster가 모두 body 태그의 마지막에 위치하여 다른 UI 요소들과의 겹침 문제를 방지합니다.
  • 두 컴포넌트가 ThemeProvider와 QueryProvider의 context 내부에 있어 전역 상태 관리가 가능합니다.
  • 페이지 전환과 무관하게 body 레벨에서 렌더링되어 상태가 안정적으로 유지됩니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential z-index conflicts in styles
rg -g '*.{css,scss,tsx}' 'z-index'

Length of output: 34


Script:

#!/bin/bash
# Check for dialog-related styles and z-index
rg -g '*.{css,scss,tsx}' -i '(dialog|modal|toast|notification).*style|style.*?(dialog|modal|toast|notification)|z-index'

# Find ExtensionDialog component definition
ast-grep --pattern 'const ExtensionDialog = $$$'

# Find other dialog/modal components in layout
ast-grep --pattern 'import.*Dialog' packages/web/src/app/[lng]/layout.tsx

Length of output: 251


Script:

#!/bin/bash
# Find ExtensionDialog component file
fd ExtensionDialog

# Find dialog/modal related components in the codebase
rg -l -g '*.tsx' '<dialog|<Modal|<Toaster'

# Check imports in layout file
cat packages/web/src/app/[lng]/layout.tsx

Length of output: 1901

packages/web/src/app/[lng]/memos/layout.tsx (2)

3-5: 상수 및 유틸리티 임포트 구조가 개선되었습니다.

상수와 유틸리티 함수의 임포트 구조가 더 명확하고 일관성 있게 변경되었습니다. COOKIE_KEY를 객체로 사용하는 방식은 키 관리 측면에서 더 안전하고 체계적입니다.


31-34: HydrationBoundary 컴포넌트의 데이터 흐름이 개선되었습니다.

getCategories 함수로의 변경은 적절해 보이나, 데이터 페칭 실패 시의 처리가 누락되어 있습니다.

카테고리 데이터 처리 방식을 확인하기 위해 다음 스크립트를 실행합니다:

✅ Verification successful

카테고리 데이터 처리가 적절히 구현되어 있습니다.

코드베이스 분석 결과, 카테고리 데이터 처리가 다음과 같이 안전하게 구현되어 있음을 확인했습니다:

  • useCategoryQuery 훅에서 enabled 옵션을 통해 supabaseClient 존재 여부를 확인
  • useCategoryPostMutation에서 에러 타입이 명시적으로 정의되어 있음
  • React Query의 HydrationBoundary를 통해 서버-클라이언트 간 데이터 동기화가 적절히 처리됨
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 카테고리 관련 에러 처리 로직 확인

# getCategories 함수의 구현 확인
ast-grep --pattern 'export const getCategories = async ($_) => { $$$ }'

# 에러 처리 패턴 검색
rg -A 5 "catch.*getCategories"

Length of output: 106


Script:

#!/bin/bash
# 카테고리 관련 함수 및 에러 처리 검색

# getCategories 함수 검색 (다른 패턴으로 시도)
ast-grep --pattern 'const getCategories = async'

# 카테고리 관련 파일 내용 확인
fd "categories?" -t f | xargs cat

# HydrationBoundaryWrapper 컴포넌트 구현 확인
ast-grep --pattern 'const HydrationBoundaryWrapper = ({ $_' -l

# 에러 처리 관련 코드 검색 (더 넓은 범위)
rg "error.*categor" -i

Length of output: 425


Script:

#!/bin/bash
# 카테고리 관련 코드 분석

# HydrationBoundaryWrapper 컴포넌트 검색 (언어 지정)
ast-grep --pattern 'const HydrationBoundaryWrapper = ({ $$ }) => { $$ }' --lang typescript

# getCategories 함수 검색 (수정된 패턴)
ast-grep --pattern 'export async function getCategories' --lang typescript

# 카테고리 관련 파일 찾기
fd -e ts -e tsx | grep -i "categor" | xargs cat

# HydrationBoundary 관련 에러 처리 검색
rg -A 5 "HydrationBoundary.*error"

Length of output: 4793

packages/web/src/modules/i18n/locales/ko/translation.json (2)

16-16: 카테고리 변경 메시지가 기존 토스트 메시지와 일관성이 있습니다.

기존의 다른 토스트 메시지들과 동일한 문체와 종결어미를 사용하여 일관성을 유지하고 있습니다.


21-24: 새로운 토스트 액션 메시지의 용어 선택이 적절합니다.

"바로가기"와 "제거 취소"는 사용자가 직관적으로 이해할 수 있는 간단명료한 용어를 사용했습니다.

packages/web/src/app/[lng]/login/components/LoginSection/index.tsx (2)

19-27: OAuth 버튼 핸들러 개선 👍

bind() 메서드 대신 화살표 함수를 사용하여 코드가 더 명확하고 이해하기 쉽게 개선되었습니다.


2-3: i18n 모듈 경로 변경 확인 필요

모듈 구조 개선을 위해 i18n 관련 import 경로가 변경되었습니다. 새로운 경로가 올바르게 설정되어 있는지 확인이 필요합니다.

✅ Verification successful

Let me analyze the repository structure first to locate the i18n module files correctly. The previous command assumed a specific directory structure that might not be accurate. This new command will help us find the correct location of the modules directory and i18n related files.


i18n 모듈 import 경로가 정상적으로 설정되었습니다

packages/web/src/modules/i18n 경로에서 필요한 모든 모듈이 확인되었습니다:

  • LanguageTypetype.ts에 정의되어 있습니다
  • useTranslationserver.jsclient.js에 모두 구현되어 있습니다

import 구문의 경로 변경이 올바르게 이루어졌습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# i18n 모듈의 새로운 경로 확인
fd -e ts -e tsx "i18n" src/modules

Length of output: 133


Script:

#!/bin/bash
# Check repository structure first
fd -t d "modules"

# Then search for i18n related files
fd -e ts -e tsx "i18n"

Length of output: 117


Script:

#!/bin/bash
# Check i18n module contents in packages/web/src/modules
fd -e ts -e tsx . packages/web/src/modules/i18n

# Check if LanguageType and useTranslation exist
rg "export.*LanguageType" -A 2 packages/web/src/modules/i18n
rg "export.*useTranslation" -A 2 packages/web/src/modules/i18n

Length of output: 1037

packages/shared/src/hooks/supabase/useMemoPostMutation.ts (1)

6-11: 타입 정의가 개선되었습니다!

MutationDataMutationError 타입 별칭을 도입하여 코드의 타입 안전성과 가독성이 향상되었습니다. ReturnTypeAwaited를 활용한 타입 추론도 잘 구현되었습니다.

packages/shared/src/utils/extension/Supabase.ts (1)

1-5: 깔끔한 import 구조입니다!

상수들을 CONFIG 객체로 통합한 것이 좋은 접근 방식입니다.

packages/web/package.json (1)

8-9: TypeScript 타입 체크 스크립트 추가에 대해 긍정적입니다.

타입 체크 스크립트를 추가한 것은 개발 프로세스 향상에 도움이 될 것 같습니다. 이는 빌드 전에 타입 오류를 미리 발견할 수 있게 해줍니다.

packages/web/src/modules/i18n/client.js (1)

9-9: import 경로 변경에 대한 검증이 필요합니다

import 경로가 './settings'에서 './util'로 변경되었습니다. 필요한 모든 엔티티들이 새로운 위치에서 올바르게 export되고 있는지 확인이 필요합니다.

✅ Verification successful

import 경로 변경이 올바르게 이루어졌습니다

필요한 모든 엔티티들이 새로운 구조에서 정상적으로 export되고 있음을 확인했습니다:

  • getOptionsutil.ts에서 직접 export됨
  • languagescookieNameconstant.ts에서 export되고 index.ts를 통해 재export됨
  • 모든 import가 정상적으로 작동할 것으로 예상됨
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence of required exports in the new util file

# Check if util file exists and contains the required exports
rg -U "export.*(?:getOptions|languages|cookieName)" "$(fd -t f util.ts util.js -d 1 packages/web/src/modules/i18n)"

Length of output: 271


Script:

#!/bin/bash
# Let's check the content of util.ts to verify all exports
cat "$(fd -t f util.ts -d 1 packages/web/src/modules/i18n)"

Length of output: 341


Script:

#!/bin/bash
# Let's check the index file for languages and cookieName exports
cat "$(fd -t f "index.ts|index.js" -d 1 packages/web/src/modules/i18n)"

Length of output: 186


Script:

#!/bin/bash
# Let's check the constant file for languages and cookieName exports
cat "$(fd -t f "constant.ts|constant.js" -d 1 packages/web/src/modules/i18n)"

Length of output: 284

packages/web/src/app/[lng]/memos/components/MemoSidebar/SidebarGroupCategory.tsx (2)

Line range hint 3-18: 임포트 구문이 잘 정리되었습니다!

훅과 타입 임포트가 논리적으로 잘 구성되어 있으며, 컴포넌트에서 모두 적절히 사용되고 있습니다.


22-24: Supabase 클라이언트 사용이 개선되었습니다.

useSupabaseClient 훅을 사용하는 방식으로 변경된 것이 React의 관례에 더 부합하며, 코드베이스 전반의 일관성을 향상시켰습니다.

다른 컴포넌트들에서도 동일한 패턴으로 마이그레이션이 이루어졌는지 확인이 필요합니다:

✅ Verification successful

Let me analyze the results and provide a final response in Korean.

Supabase 클라이언트 사용 패턴이 일관되게 적용되어 있습니다.

코드베이스 분석 결과:

  • 웹 애플리케이션의 클라이언트 컴포넌트들은 useSupabaseClient 훅을 일관되게 사용하고 있습니다.
  • getSupabaseClient는 서버 컴포넌트(*.server.ts)와 확장 프로그램에서만 사용되고 있어 적절한 구분이 이루어져 있습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of useSupabaseClient across components
# Check for any remaining instances of getSupabaseClient
rg "getSupabaseClient"

# Check for adoption of useSupabaseClient
rg "useSupabaseClient"

Length of output: 5688

packages/web/src/app/[lng]/memos/components/MemoView/MemoGrid.tsx (2)

Line range hint 27-56: 구현이 잘 되어있습니다! 👍

컴포넌트가 다음과 같은 우수한 구현 사항을 포함하고 있습니다:

  • 효율적인 페이지네이션 로직
  • 적절한 상태 관리
  • 부드러운 애니메이션 처리
  • 타입 안정성 확보

4-4: 타입 변경 사항 검증이 필요합니다.

타입 변경이 올바르게 이루어졌는지 확인이 필요합니다:

  • GetMemoType에서 GetMemoResponse로의 변경
  • LanguageType 임포트 경로 변경

Also applies to: 8-8, 23-23

✅ Verification successful

Based on the results, I can now generate the final response since we have clear evidence that:

  1. No references to GetMemoType exist in the codebase
  2. GetMemoResponse is consistently used in related files and properly defined in shared/src/utils/Supabase.ts
  3. All LanguageType imports consistently use the path @src/modules/i18n

타입 변경이 올바르게 적용되었습니다.

타입 변경이 전체 코드베이스에서 일관되게 이루어졌음을 확인했습니다:

  • GetMemoType은 완전히 제거되었으며 GetMemoResponse로 올바르게 대체되었습니다
  • GetMemoResponseshared/src/utils/Supabase.ts에서 정의되어 있으며 관련 컴포넌트에서 일관되게 사용됩니다
  • LanguageType 임포트 경로가 모든 파일에서 @src/modules/i18n으로 통일되어 있습니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify type changes across the codebase

# Check for any remaining references to GetMemoType
echo "Checking for remaining GetMemoType references..."
rg "GetMemoType"

# Check for consistent usage of GetMemoResponse
echo "Checking GetMemoResponse usage..."
rg "GetMemoResponse"

# Verify LanguageType import path consistency
echo "Checking LanguageType import paths..."
rg "import.*LanguageType.*from"

Length of output: 2805

packages/shared/package.json (1)

38-41: 웹 훅을 위한 새로운 내보내기 경로가 올바르게 추가되었습니다.

내보내기 구조가 기존 패턴을 잘 따르고 있으며, 웹과 확장 프로그램 코드의 분리를 적절히 지원합니다.

packages/shared/src/utils/Supabase.ts (1)

1-3: 타입 정의와 임포트가 깔끔하게 구성되어 있습니다.

상수와 타입 정의가 잘 분리되어 있으며, 필요한 타입들이 명확하게 임포트되어 있습니다.

packages/shared/src/hooks/supabase/useMemoPatchMutation.ts (1)

6-11: 타입 정의가 명확하고 잘 구조화되어 있습니다! 👍

MutationVariables, MutationData, MutationError와 같은 타입 별칭을 사용하여 코드의 가독성과 유지보수성이 향상되었습니다. 특히 Awaited 타입을 사용하여 비동기 응답 타입을 정의한 것이 인상적입니다.

packages/web/src/app/[lng]/memos/components/legacy/MemoTable.tsx (1)

4-4: Supabase 클라이언트 관리 방식이 개선되었습니다!

함수형 컴포넌트에서 훅을 사용하는 방식으로 변경한 것이 React의 패턴에 더 적합합니다.

Also applies to: 8-8

packages/web/src/app/components/ExtensionDialog/index.tsx (1)

1-16: 타입 정의와 임포트 구조가 깔끔합니다!

컴포넌트의 타입 정의가 간단하면서도 명확하며, 필요한 의존성들이 잘 구성되어 있습니다.

packages/web/src/modules/search-params/SearchParams.ts (1)

1-5: 타입 안정성과 캡슐화가 잘 구현되었습니다!

private 필드를 사용한 캡슐화와 타입 정의가 잘 되어있습니다.

packages/web/src/utils/supabase.server.ts (1)

1-10: 서버 사이드 상태 관리에 대한 고려사항

supabaseClient를 전역 변수로 관리하는 것은 서버 사이드 렌더링 환경에서 잠재적인 문제를 일으킬 수 있습니다. Next.js의 서버 컴포넌트는 여러 요청에서 공유될 수 있으므로, 전역 상태를 신중하게 관리해야 합니다.

다음 스크립트를 실행하여 다른 서버 컴포넌트에서 이 클라이언트를 어떻게 사용하는지 확인하겠습니다:

✅ Verification successful

서버 사이드 상태 관리는 안전하게 구현되어 있습니다

코드베이스 분석 결과, supabaseClient 싱글톤 패턴의 구현이 Next.js 서버 컴포넌트 환경에서 안전하게 사용되고 있음을 확인했습니다:

  • getSupabaseClient()는 각 요청마다 새로운 쿠키 컨텍스트를 사용하여 클라이언트를 초기화합니다
  • 서버 컴포넌트들(app/[lng] 경로)은 독립적으로 getSupabaseClient()를 호출하여 요청별 컨텍스트를 유지합니다
  • 클라이언트 사이드 컴포넌트들은 useSupabaseClient 훅을 통해 별도의 브라우저 클라이언트를 사용합니다
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage of supabase client in server components
rg -t typescript "getSupabaseClient" --glob "**/*.server.ts*"

Length of output: 96


Script:

#!/bin/bash
# Search for getSupabaseClient usage in all TypeScript files
rg "getSupabaseClient" --type-add 'ts:*.{ts,tsx}' -t ts

# Check how supabaseClient is used across the codebase
rg "supabaseClient" --type-add 'ts:*.{ts,tsx}' -t ts

# Look for server component files that might use Supabase
fd -e ts -e tsx "server" --full-path

Length of output: 13434

packages/web/src/modules/i18n/locales/en/translation.json (2)

1-59: JSON 구조가 잘 구성되어 있습니다.

전반적으로 구조가 깔끔하고 논리적으로 잘 구성되어 있습니다.


1-59: 번역키 사용 현황 확인 필요

정의된 번역키들이 실제 컴포넌트에서 올바르게 사용되고 있는지 확인이 필요합니다.

✅ Verification successful

번역키가 적절하게 사용되고 있음을 확인했습니다

코드베이스 분석 결과, translation.json에 정의된 모든 번역키들이 컴포넌트에서 올바르게 사용되고 있습니다:

  • common.*: Header 컴포넌트에서 사용
  • sideBar.*: MemoSidebar 컴포넌트에서 사용
  • header.*: Header 컴포넌트에서 사용
  • toastMessage.*: MemoItem, MemoOption, RefreshButton 등에서 사용
  • toastActionMessage.*: MemoOption에서 사용
  • option.*: MemoOption에서 사용
  • login.*: LoginSection에서 사용
  • dialogInstall.*, dialogVersion.*: ExtensionDialog에서 사용
  • tooltip.*: MemoSidebarTrigger에서 사용
  • setting.*: Setting 컴포넌트에서 사용
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify translation key usage in the codebase

# Search for translation key usage
rg -t tsx -t ts "useTranslation|t\(['\"]" ./packages/web/src/

Length of output: 93


Script:

#!/bin/bash
# Search for translation key usage without file type restrictions
rg "useTranslation|[\"']common\.|[\"']sideBar\.|[\"']header\.|[\"']toastMessage\.|[\"']toastActionMessage\.|[\"']option\.|[\"']login\.|[\"']dialogInstall\.|[\"']dialogVersion\.|[\"']tooltip\.|[\"']setting\." ./packages/web/src/

Length of output: 8648

packages/web/src/app/[lng]/memos/components/MemoSidebar/index.tsx (1)

21-22: i18n 모듈 경로 변경이 적절히 이루어졌습니다.

모듈 구조 개선을 위한 import 경로 변경이 잘 이루어졌습니다. 다만, 다른 컴포넌트들에서도 동일한 변경이 일관되게 적용되었는지 확인이 필요합니다.

다른 컴포넌트들의 import 경로 변경 여부를 확인하기 위해 다음 스크립트를 실행합니다:

✅ Verification successful

i18n 모듈 경로가 전체 코드베이스에서 일관되게 변경되었습니다.

검증 결과, 이전 경로(@src/app/i18n)를 사용하는 파일이 없으며, 새로운 경로(@src/modules/i18n)가 모든 관련 컴포넌트에서 일관되게 사용되고 있음을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: i18n 관련 모듈의 import 경로 일관성 검사

# 이전 경로를 사용하는 파일 검색
echo "이전 경로(@src/app/i18n)를 사용하는 파일 검색:"
rg -l "@src/app/i18n"

# 새로운 경로를 사용하는 파일 검색
echo -e "\n새로운 경로(@src/modules/i18n)를 사용하는 파일 검색:"
rg -l "@src/modules/i18n"

Length of output: 1648

.coderabbit.yaml (1)

35-35: base_branches 설정이 적절히 추가되었습니다.

'master'와 'develop' 브랜치를 base_branches로 설정한 것은 GitFlow 브랜칭 전략과 잘 부합합니다. 이는 주요 브랜치에 대한 코드 품질을 유지하는데 도움이 될 것입니다.

현재 저장소의 브랜치 전략을 확인하기 위해 다음 스크립트를 실행하세요:

packages/web/src/modules/search-params/SearchParams.test.ts (3)

1-12: 테스트 설정이 잘 구성되어 있습니다!

테스트 데이터가 다양한 시나리오를 커버할 수 있도록 적절히 구성되어 있습니다.


26-31: getAll 메서드 테스트가 잘 작성되었습니다!

단일 값과 다중 값 케이스를 모두 적절히 검증하고 있습니다.


62-74: removeAll과 getSearchParams 테스트가 잘 구현되었습니다!

각 메서드의 핵심 기능을 정확하게 검증하고 있습니다.

packages/web/src/app/[lng]/memos/components/Header/index.tsx (1)

15-16: i18n 모듈 경로 변경이 올바르게 적용되었습니다.

모듈 구조 개선을 위한 import 경로 변경이 일관성 있게 이루어졌습니다.

chrome-extension/lib/background/index.ts (4)

1-1: 상수 관리 방식이 개선되었습니다.

URL과 설정 관련 상수들이 CONFIG와 URL 객체로 통합되어 관리되는 것은 좋은 변경사항입니다.


27-27: 웹 URL 참조 방식이 개선되었습니다.

하드코딩된 URL 대신 CONFIG.webUrl을 사용하여 URL을 관리하는 것은 좋은 접근 방식입니다.


51-51: URL 참조의 일관성이 향상되었습니다.

메모 페이지와 가이드 페이지의 URL 참조가 CONFIG.webUrl과 URL 객체를 통해 일관되게 관리되고 있습니다.

Also applies to: 54-55


60-60: 제거 설문 URL 관리가 개선되었습니다.

확장 프로그램 제거 시 표시되는 설문 URL이 URL 객체를 통해 관리되도록 변경된 것은 좋은 개선사항입니다.

pages/options/src/components/OptionForm.tsx (2)

3-8: 가져오기 구문이 더 명확하게 정리되었습니다.

유틸리티 함수들의 이름이 더 명시적으로 변경되어 코드의 가독성이 향상되었습니다. 특히 getMemos as getMemosSupabase로의 변경은 함수의 출처와 목적을 더 잘 나타냅니다.


20-20: 함수 호출이 일관되게 업데이트되었습니다.

getMemo에서 getMemosSupabase로의 변경이 올바르게 적용되었습니다. 다만, 이 변경으로 인한 영향을 확인할 필요가 있습니다.

✅ Verification successful

getMemo 관련 함수들이 정상적으로 사용되고 있습니다.

검색 결과를 분석해보면, getMemo에서 getMemosSupabase로의 변경은 pages/options/src/components/OptionForm.tsx 파일에서만 필요했던 것으로 확인됩니다. 다른 파일들에서 발견된 getMemo 관련 함수들(getMemoUrl, getMemoWishListUrl, getMemoItems)은 완전히 다른 용도의 함수들이므로 변경이 필요하지 않습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistent usage of getMemosSupabase across the codebase

# Search for any remaining instances of getMemo
rg "getMemo[^s]" --type ts --type tsx

# Search for current usage of getMemosSupabase
rg "getMemosSupabase" --type ts --type tsx

Length of output: 138


Script:

#!/bin/bash
# Search for any remaining instances of getMemo
rg "getMemo[^s]"

# Search for current usage of getMemosSupabase
rg "getMemosSupabase"

Length of output: 1166

packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx (1)

4-5: 모듈 구조 개선 확인 필요

i18n과 타입 관련 임포트 경로가 변경되었습니다. 새로운 모듈 구조가 프로젝트 전반에 걸쳐 일관되게 적용되었는지 확인이 필요합니다.

Also applies to: 14-16

✅ Verification successful

i18n 모듈 경로 변경이 일관되게 적용되었습니다

코드베이스 전반에 걸쳐 @src/modules/i18n 경로가 일관되게 사용되고 있으며, 이전 경로인 @src/app/i18n은 더 이상 사용되지 않음을 확인했습니다. 모든 컴포넌트가 새로운 모듈 구조를 따르고 있어 문제가 없습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of new module paths across the codebase

# Check for any remaining old import paths
rg -l "@src/app/i18n"

# Verify new module structure adoption
rg -l "@src/modules/i18n"
rg -l "@src/modules/search-params"

Length of output: 1707


Script:

#!/bin/bash
# Let's check the actual import statements to understand the pattern
rg "@src/(app|modules)/i18n" -A 2

# Also check if there are any imports from the old path that need updating
rg "from ['\"]\@src/app/i18n" --type typescript

Length of output: 9583

package.json (3)

28-28: 테스트 스크립트 추가 검토

Vitest를 사용하여 Jest 테스트를 실행하는 새로운 스크립트가 추가되었습니다. 하지만 기존의 Playwright 테스트 스크립트와 함께 사용될 때 혼란을 줄 수 있습니다.

다음 스크립트를 실행하여 테스트 설정을 확인하겠습니다:

스크립트 이름을 더 명확하게 변경하는 것을 고려해보세요:

-    "test:jest": "vitest",
+    "test:unit": "vitest",
✅ Verification successful

테스트 스크립트 구성이 적절합니다

현재 테스트 환경이 명확하게 구분되어 있습니다:

  • Vitest로 단위 테스트 실행 (test:jest)
  • Playwright로 E2E 테스트 실행 (test)

각 테스트 유형이 다른 목적으로 사용되고 있어 스크립트 이름 변경이 불필요합니다:

  • 단위 테스트: SearchParams.test.ts와 같은 비즈니스 로직 테스트
  • E2E 테스트: LoginPage.spec.ts와 같은 통합 테스트
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# vitest.config.ts 파일의 존재 여부 확인
fd -t f "vitest.config.ts"

# Jest 테스트 파일 검색
rg -t ts -t tsx "describe|test|it\(" 

Length of output: 110


Script:

#!/bin/bash
# Check vitest.config.ts content
cat vitest.config.ts

# Search for test files with proper extension patterns
rg -t typescript -t js "describe|test|it\(" 

# Check if there are any existing test files
fd -e test.ts -e test.js -e spec.ts -e spec.js

Length of output: 506


Script:

#!/bin/bash
# Check package.json for all test-related scripts
cat package.json | grep -A 5 -B 5 "\"test"

# Check content of a unit test file
cat "packages/web/src/modules/search-params/SearchParams.test.ts"

# Check content of an e2e test file
cat "tests/e2e/LoginPage.spec.ts"

Length of output: 4176


43-43: 프로덕션 의존성 업데이트 검토

새로운 의존성들이 추가되었습니다:

  • @supabase/ssr: Supabase SSR 지원
  • lucide-react: 아이콘 라이브러리
  • vite-plugin-svgr: SVG 지원

의존성 버전의 호환성을 확인하겠습니다:

Supabase SSR 구현 시 다음 사항들을 고려해주세요:

  • 서버 사이드 환경에서의 인증 처리
  • 클라이언트/서버 상태 동기화
  • 캐싱 전략

Also applies to: 50-50, 59-59

✅ Verification successful

의존성 호환성 검증 완료

의존성 분석 결과 모든 패키지가 호환되며 안전하게 사용할 수 있습니다:

  • @supabase/[email protected]은 peer dependency로 @supabase/supabase-js@^2.43.4를 요구하며, 현재 프로젝트는 2.45.4 버전을 사용하고 있어 호환됩니다.
  • [email protected]은 React 16.5.1 이상을 요구하며, 프로젝트의 React 18.3.1 버전과 호환됩니다.
  • [email protected]은 별도의 peer dependency 요구사항이 없습니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# package-lock.json 또는 pnpm-lock.yaml 파일 검색
fd -t f "package-lock.json|pnpm-lock.yaml"

# peer dependencies 충돌 확인
npm ls @supabase/ssr lucide-react vite-plugin-svgr

Length of output: 293


Script:

#!/bin/bash
# pnpm-lock.yaml에서 의존성 정보 확인
cat pnpm-lock.yaml | grep -A 10 "@supabase/ssr"
cat pnpm-lock.yaml | grep -A 10 "lucide-react"

# package.json에서 관련 의존성들의 버전 범위 확인
cat package.json | grep -A 20 '"dependencies":'

Length of output: 2418


66-66: 🛠️ Refactor suggestion

개발 의존성 업데이트 검토

테스트 및 빌드 도구 관련 의존성이 추가되었습니다:

  • Jest 타입스크립트 지원
  • Vite React 플러그인
  • Vitest 테스트 프레임워크

Vite 버전 고정에 대한 이유를 확인하겠습니다:

Vite 버전을 고정하는 대신 유연한 버전 관리를 권장드립니다:

-    "vite": "5.3.3",
+    "vite": "^5.3.3",

Also applies to: 72-72, 96-97

✅ Verification successful

Let me gather more information about the Vite configuration and dependencies to understand if there's any specific reason for version pinning.


Let me check the dependencies and plugins that might require a specific Vite version.


Vite 버전 고정에 대한 검토 완료

현재 프로젝트에서는 Vite 관련 플러그인들(@vitejs/plugin-react, vite-plugin-svgr, @sentry/vite-plugin)이 모두 유연한 버전 관리(^)를 사용하고 있는 반면, Vite 자체는 5.3.3으로 고정되어 있습니다. 특별한 호환성 이슈나 마이그레이션 가이드가 발견되지 않았고, 다른 의존성들과의 충돌 문제도 확인되지 않았습니다. 따라서 Vite도 다른 패키지들과 동일하게 유연한 버전 관리를 사용하는 것이 좋겠습니다.

  • package.json에서 Vite 버전을 "^5.3.3"으로 변경하는 것을 권장합니다.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 프로젝트의 변경 이력에서 Vite 관련 이슈 검색
rg -g "!{node_modules,dist}/*" "vite.*5\.3\.3"

Length of output: 1109


Script:

#!/bin/bash
# Check for Vite configuration files and any comments about version requirements
fd -e js -e ts -e mjs "vite.config" --exec cat {}

# Check package.json for peer dependencies that might require specific Vite version
cat package.json | jq '.peerDependencies'

# Look for any documentation about Vite version requirements
fd "README" --exec cat {}

Length of output: 4101


Script:

#!/bin/bash
# Check all Vite-related dependencies and their versions
cat package.json | jq '.dependencies, .devDependencies' | grep -i "vite"

# Look for any migration guides or breaking changes in the repository
rg -g "!{node_modules,dist}/*" "migration|breaking.?changes|upgrade" -i

Length of output: 289

pages/side-panel/src/components/MemoForm.tsx (2)

10-14: 타입 시스템 개선 및 Supabase 클라이언트 관리 방식 변경이 적절해 보입니다.

useSupabaseClientQuery로의 전환과 MemoInput 타입의 도입으로 코드의 타입 안정성이 향상되었습니다.


24-28: Supabase 클라이언트 사용 방식 변경에 대한 검증이 필요합니다.

useSupabaseClientQuery로의 전환이 적절해 보이나, 다른 컴포넌트들과의 일관성 확인이 필요합니다.

✅ Verification successful

Supabase 클라이언트 사용이 일관되게 적용되어 있습니다.

검증 결과, 웹 확장 프로그램의 사이드 패널 컴포넌트들(pages/side-panel/)에서는 모두 useSupabaseClientQuery를 일관되게 사용하고 있으며, 웹 애플리케이션(packages/web/)에서는 useSupabaseClient를 사용하고 있습니다. 이는 각 환경에 맞는 적절한 구현 방식을 따르고 있는 것으로 확인됩니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of useSupabaseClientQuery across components

# Search for any remaining useSupabaseClient usage
rg "useSupabaseClient[^Q]" --type tsx

Length of output: 67


Script:

#!/bin/bash
# Search for any remaining useSupabaseClient usage (without extension filter)
rg "useSupabaseClient[^Q]"

# Search for useSupabaseClientQuery usage to verify consistency
rg "useSupabaseClientQuery"

# Find all TypeScript/React files that might use Supabase
fd "\.(tsx?|jsx?)$" | grep -i "supabase"

Length of output: 4029

packages/web/src/app/[lng]/memos/components/MemoView/MemoItem.tsx (4)

3-18: 임포트 구조가 개선되었습니다.

공유 훅과 타입을 사용하도록 변경되어 코드의 재사용성이 향상되었습니다. 특히 useSearchParams를 사용하여 URL 파라미터 관리가 체계화되었습니다.


21-21: 타입 정의가 더 명확해졌습니다.

GetMemoResponse 타입으로 변경되어 메모 데이터의 구조가 더 명확하게 정의되었습니다.


28-28: Supabase 클라이언트 사용이 개선되었습니다.

useSupabaseClient 훅을 직접 사용하도록 변경되어 클라이언트 관리가 더 모듈화되었습니다.

Also applies to: 32-32


126-126: prop 이름이 더 명확해졌습니다.

id 대신 memoId를 사용하여 prop의 목적이 더 명확해졌습니다.

packages/web/src/app/[lng]/memos/components/MemoView/MemoOption.tsx (3)

25-27: Props 인터페이스의 명확성이 개선되었습니다.

id에서 memoId로의 이름 변경은 props의 목적을 더 명확하게 표현합니다. 이는 코드의 가독성과 유지보수성을 향상시킵니다.


Line range hint 32-38: Supabase 클라이언트 관리가 개선되었습니다.

useSupabaseClient 훅을 사용하여 클라이언트를 관리하는 방식은 React의 훅 패턴을 잘 따르고 있습니다. 쿼리 캐시 무효화도 적절히 구현되어 있습니다.


60-61: 번역 키가 올바르게 정의되어 있는지 확인이 필요합니다.

사용된 번역 키들이 실제로 번역 파일에 정의되어 있는지 확인이 필요합니다.

Also applies to: 81-85

✅ Verification successful

번역 키가 모두 올바르게 정의되어 있습니다.

toastActionMessage.memoDeleteCanceltoastActionMessage.goTo 키가 영어와 한국어 번역 파일 모두에서 적절하게 정의되어 있는 것을 확인했습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 번역 키 존재 여부 확인
rg -l "toastActionMessage\.(memoDeleteCancel|goTo)" public/locales/

Length of output: 125


Script:

#!/bin/bash
# Find translation files in the repository
fd -t f "translation|locale|i18n|lang" -e json -e yaml -e yml

# After finding translation files, let's check their content

Length of output: 179


Script:

#!/bin/bash
# Check translation keys in both files
echo "=== English translations ==="
cat packages/web/src/modules/i18n/locales/en/translation.json | jq '.toastActionMessage'

echo -e "\n=== Korean translations ==="
cat packages/web/src/modules/i18n/locales/ko/translation.json | jq '.toastActionMessage'

Length of output: 430

packages/web/src/components/ui/sidebar.tsx (1)

16-16: 쿠키 키 관리 방식이 개선되었습니다.

쿠키 키를 중앙 집중식으로 관리하도록 변경한 것은 좋은 개선입니다. 이는 유지보수성을 향상시키고 일관성을 보장합니다.

다른 파일에서도 동일한 방식으로 쿠키 키를 사용하는지 확인하겠습니다:

Also applies to: 18-18

✅ Verification successful

Let me verify the cookie key usage by checking the shared constants file to ensure the structure is properly defined.


쿠키 키 관리가 일관되게 적용되어 있습니다.

@extension/shared/constantsCOOKIE_KEY 객체를 통해 모든 쿠키 키가 중앙 집중식으로 관리되고 있으며, 코드베이스 전반에 걸쳐 일관되게 사용되고 있습니다. 특히:

  • 인증 관련 쿠키 (accessToken, refreshToken)
  • 사이드바 상태 관리 쿠키 (sideBarState)

모두 동일한 패턴으로 구현되어 있어 유지보수성이 향상되었습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: 쿠키 키 사용 방식의 일관성 확인

# COOKIE_KEY 상수 사용 패턴 검색
rg "COOKIE_KEY\." -A 2

# 이전 쿠키 키 상수 사용 여부 확인
rg "COOKIE_KEY_SIDE_BAR_STATE"

Length of output: 2366


Script:

#!/bin/bash
# Check the shared constants file for COOKIE_KEY definition
fd "constants.ts" --exec cat {}

Length of output: 231


Script:

#!/bin/bash
# Let's search for COOKIE_KEY definition in the entire codebase
rg "export const COOKIE_KEY" -A 5

Length of output: 363

Comment on lines 1 to 4
export interface MemoInput {
memo: string;
isWish: boolean;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

인터페이스 불일치 문제 발견

MemoInput 인터페이스가 두 위치에서 서로 다르게 정의되어 있습니다:

  • pages/side-panel/src/types/Input.ts에서는 memo: stringisWish: boolean을 포함
  • packages/web/src/app/[lng]/memos/types/Input.ts에서는 memo: string만 포함

이는 다음과 같은 문제를 야기할 수 있습니다:

  • MemoDialog 컴포넌트에서는 isWish 속성을 사용하지 않지만, MemoForm 컴포넌트에서는 해당 속성을 필요로 함
  • 두 컴포넌트가 동일한 데이터를 다루고 있음에도 타입 정의가 불일치
🔗 Analysis chain

인터페이스 사용 현황 확인 필요

새로 추가된 MemoInput 인터페이스가 애플리케이션 전반에 걸쳐 일관되게 사용되고 있는지 확인이 필요합니다.

다음 스크립트를 실행하여 인터페이스 사용 현황을 확인하세요:


Let me verify the implementation details of MemoInput in both locations to ensure consistency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: MemoInput 인터페이스의 사용 현황 확인

# MemoInput 타입이 사용된 모든 파일 검색
echo "MemoInput 타입 사용 현황:"
rg -l "MemoInput"

# useForm 훅에서 MemoInput 사용 확인
echo -e "\nuseForm 훅에서 MemoInput 사용 현황:"
rg "useForm.*MemoInput"

Length of output: 591


Script:

#!/bin/bash
# Check the implementation of MemoInput interface in both locations
echo "=== MemoInput in pages/side-panel/src/types/Input.ts ==="
cat pages/side-panel/src/types/Input.ts

echo -e "\n=== MemoInput in packages/web/src/app/[lng]/memos/types/Input.ts ==="
cat packages/web/src/app/[lng]/memos/types/Input.ts

# Check how MemoInput is used in the components
echo -e "\n=== Usage in MemoForm.tsx ==="
cat pages/side-panel/src/components/MemoForm.tsx

echo -e "\n=== Usage in MemoDialog/index.tsx ==="
cat packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx

Length of output: 8464

packages/shared/src/constants/Extension.ts Outdated Show resolved Hide resolved
packages/shared/src/constants/Supabase.ts Outdated Show resolved Hide resolved
packages/web/src/modules/local-storage/type.ts Outdated Show resolved Hide resolved
Comment on lines 4 to 5
if (id) return `${CONFIG.webUrl}/memos?id=${id}`;
return `${CONFIG.webUrl}/memos`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

URL 생성 시 XSS 취약점 방지가 필요합니다.

id 파라미터가 직접 URL에 삽입되고 있습니다. 보안을 강화하기 위해 URL 인코딩을 추가하는 것이 좋겠습니다.

다음과 같이 수정을 제안드립니다:

-  if (id) return `${CONFIG.webUrl}/memos?id=${id}`;
+  if (id) return `${CONFIG.webUrl}/memos?id=${encodeURIComponent(id)}`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (id) return `${CONFIG.webUrl}/memos?id=${id}`;
return `${CONFIG.webUrl}/memos`;
if (id) return `${CONFIG.webUrl}/memos?id=${encodeURIComponent(id)}`;
return `${CONFIG.webUrl}/memos`;

Copy link

개발자 경험 개선

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🧹 Outside diff range and nitpick comments (15)
packages/shared/src/modules/local-storage/type.ts (2)

1-1: 명시적인 import 경로 사용 권장

현재 index 파일에서 간접적으로 LOCAL_STORAGE_KEY를 가져오고 있습니다. 유지보수성과 가독성을 위해 직접적인 파일 경로를 사용하는 것이 좋습니다.

-import { LOCAL_STORAGE_KEY } from '.';
+import { LOCAL_STORAGE_KEY } from './constant';

3-3: 버전 번호에 대한 제약 조건 추가 고려

현재 버전 번호에 대한 제약이 없어 음수나 매우 큰 숫자도 허용됩니다. 유효한 버전 범위를 제한하는 것이 좋을 것 같습니다.

type VersionNumber = `${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}${number}` | number;
export type UpdateVersionType = `updateVersion${VersionNumber}.${VersionNumber}.${VersionNumber}`;
packages/shared/src/modules/search-params/type.ts (1)

3-5: 타입 정의가 잘 구성되어 있습니다만, 문서화를 추가하면 좋겠습니다

타입 정의가 명확하고 타입 안전성이 잘 보장되어 있습니다. 다만, 각 타입의 용도와 제약사항을 설명하는 JSDoc 문서를 추가하면 더 좋을 것 같습니다.

다음과 같이 문서화를 추가해보세요:

+/** 검색 파라미터의 키 타입. SEARCH_PARAMS_KEYS에 정의된 값들만 허용됩니다. */
 export type SearchParamKeyType = (typeof SEARCH_PARAMS_KEYS)[number];
+/** 검색 파라미터의 값 타입 */
 export type SearchParamValueType = string;
+/** 검색 파라미터의 키-값 쌍을 나타내는 튜플 타입 */
 export type SearchParamType = [SearchParamKeyType, SearchParamValueType];
packages/shared/src/modules/local-storage/LocalStorage.ts (1)

8-10: 타입 안전성과 오류 처리를 강화하세요.

값을 저장할 때 타입 검증과 오류 처리가 필요합니다.

다음과 같이 개선하는 것을 제안합니다:

-  static set(key: LocalStorageKeyType, value: unknown) {
-    localStorage.setItem(key, JSON.stringify(value));
+  static set(key: LocalStorageKeyType, value: unknown): boolean {
+    try {
+      localStorage.setItem(key, JSON.stringify(value));
+      return true;
+    } catch (error) {
+      console.error(`LocalStorage save error for key ${key}:`, error);
+      return false;
+    }
   }
packages/shared/src/modules/local-storage/util.ts (1)

1-9: localStorage 추상화 계층 개선을 제안드립니다.

현재 구현은 기본적인 기능만을 제공하고 있습니다. 다음과 같은 개선사항을 고려해보시면 좋을 것 같습니다:

  1. localStorage 사용 가능 여부를 확인하는 초기화 로직
  2. 메모리 캐싱을 통한 성능 최적화
  3. 저장된 값의 유효성 검사
  4. 만료 시간 설정 기능

이러한 기능들을 추가하면 더욱 안정적이고 확장 가능한 모듈이 될 것 같습니다.

packages/shared/src/modules/search-params/useSearchParams.ts (1)

1-5: 클라이언트 컴포넌트 지시자와 임포트 구성이 적절합니다.

'use client' 지시자와 Next.js navigation 기능의 임포트가 올바르게 구성되어 있습니다. useSearchParams를 useSearchParamsNext로 별칭을 지정한 것은 이름 충돌을 방지하는 좋은 방법입니다.

상대 경로 대신 절대 경로를 사용하는 것을 고려해보세요:

-import { SearchParams, SearchParamType } from '.';
+import { SearchParams, SearchParamType } from '@shared/modules/search-params';
packages/shared/src/modules/local-storage/constant.ts (2)

5-6: 함수 문서화가 필요합니다.

타입 가드 함수의 목적과 사용법을 설명하는 JSDoc 문서를 추가하면 좋을 것 같습니다.

다음과 같이 문서를 추가해보세요:

+/**
+ * 주어진 문자열이 유효한 업데이트 버전 키인지 확인합니다.
+ * @param value - 검사할 문자열
+ * @returns 문자열이 'updateVersionX.Y.Z' 형식을 따르는지 여부
+ */
export const checkUpdateVersionKey = (value: string): value is UpdateVersionType =>
  REGEXR_UPDATE_VERSION_VERSION.test(value);

10-11: 타입 체크 로직 최적화를 제안합니다.

현재 구현은 올바르지만, 배열 검색을 최적화할 수 있습니다.

Set을 사용하여 검색 성능을 개선해보세요:

+const LOCAL_STORAGE_KEY_SET = new Set(LOCAL_STORAGE_KEY);
 export const checkLocalStorageKey = (value: string): value is LocalStorageKeyType =>
-  checkUpdateVersionKey(value) || (LOCAL_STORAGE_KEY as readonly string[]).includes(value);
+  checkUpdateVersionKey(value) || LOCAL_STORAGE_KEY_SET.has(value);
packages/shared/src/modules/search-params/SearchParams.ts (1)

16-23: get 메서드의 반환 값 처리를 개선할 수 있습니다.

get 메서드에서 빈 값 처리를 더 명시적으로 할 수 있습니다.

다음과 같이 개선해보세요:

  get = (key: SearchParamKeyType) => {
    const values = this.#searchParamsMap.get(key);
-   return values ? Array.from(values)[0] || '' : '';
+   if (!values || values.size === 0) return '';
+   return Array.from(values)[0];
  };
packages/shared/src/modules/search-params/SearchParams.test.ts (4)

1-12: 타입 안전성 및 테스트 데이터 구성 개선 제안

테스트 데이터 설정이 잘 되어 있지만, 다음과 같은 개선사항을 제안드립니다:

  1. 테스트 데이터를 상수로 분리하여 재사용성을 높이고 유지보수를 용이하게 할 수 있습니다.
  2. 테스트 데이터의 타입을 명시적으로 정의하면 타입 안전성을 향상시킬 수 있습니다.
const TEST_SEARCH_PARAMS: [string, string][] = [
  ['id', '5'],
  ['id', '10'],
  ['category', 'book'],
] as const;

26-31: 테스트 케이스 보완 제안

현재 테스트가 잘 작성되어 있지만, 다음과 같은 엣지 케이스 테스트를 추가하면 좋을 것 같습니다:

  1. 존재하지 않는 키에 대한 테스트
  2. 빈 값이 포함된 경우의 테스트
test('존재하지 않는 key값의 경우 빈 배열을 반환한다.', () => {
  expect(searchParams.getAll('nonexistent')).toStrictEqual([]);
});

test('빈 값이 포함된 경우를 처리한다.', () => {
  searchParams.add('empty', '');
  expect(searchParams.getAll('empty')).toStrictEqual(['']);
});

55-55: 테스트 설명 오타 수정 필요

테스트 설명에 마침표가 두 번 들어간 오타가 있습니다: "제거하지 않는다.."

-    test('key와 value에 해당하는 값이 없다면 제거하지 않는다..', () => {
+    test('key와 value에 해당하는 값이 없다면 제거하지 않는다.', () => {

62-68: removeAll 메서드 테스트 케이스 보완 필요

현재 기본적인 케이스만 테스트하고 있습니다. 다음과 같은 추가 테스트 케이스를 고려해보세요:

  1. 존재하지 않는 키에 대한 removeAll 호출
  2. 여러 키를 연속적으로 제거하는 경우
test('존재하지 않는 key에 대해 removeAll을 호출해도 에러가 발생하지 않는다.', () => {
  expect(() => searchParams.removeAll('nonexistent')).not.toThrow();
});

test('여러 key를 연속적으로 제거할 수 있다.', () => {
  searchParams.removeAll('id');
  searchParams.removeAll('category');
  expect(searchParams.getSearchParams()).toBe('');
});
packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx (1)

4-5: 모듈 구조 개선을 위한 제안

imports를 다음과 같이 그룹화하여 정리하면 코드 가독성이 향상될 것 같습니다:

  1. 외부 라이브러리
  2. 내부 모듈
  3. 컴포넌트
  4. 타입
'use client';

import { useCloseOnEscape, useMemoPatchMutation, useMemoQuery } from '@extension/shared/hooks';
+ import { useSearchParams } from '@extension/shared/modules/search-params';
import { Button } from '@extension/ui';
+ import { useRouter } from 'next/navigation';
+ import Image from 'next/image';
+ import Link from 'next/link';
+ import { useEffect, useState } from 'react';
+ import { useForm } from 'react-hook-form';

import useTranslation from '@src/modules/i18n/client';
import { LanguageType } from '@src/modules/i18n';
import { useSupabaseClient } from '@src/hooks';
import { useToast } from '@src/hooks/use-toast';

import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@src/components/ui/dialog';
import { Textarea } from '@src/components/ui/textarea';

- import Image from 'next/image';
- import Link from 'next/link';
- import { useEffect, useState } from 'react';
- import { useForm } from 'react-hook-form';
import { MemoInput } from '../../types';
- import { useRouter } from 'next/navigation';
- import { useSearchParams } from '@extension/shared/modules/search-params';

Also applies to: 14-16

packages/web/src/app/[lng]/memos/components/MemoView/MemoItem.tsx (1)

3-18: 의존성 관리 개선이 필요합니다.

불필요한 import를 제거하고 필요한 의존성을 추가한 것은 좋은 변경사항입니다. 하지만 몇 가지 개선할 점이 있습니다:

  1. 관련된 import들을 그룹화하여 정리하면 가독성이 향상될 것 같습니다.
  2. 외부/내부 의존성을 명확하게 구분하면 좋겠습니다.

다음과 같이 import문을 정리하는 것을 제안합니다:

// React & Next.js
import { HTMLAttributes, KeyboardEvent, memo, MouseEvent, MouseEventHandler, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { useRouter } from 'next/navigation';

// External dependencies
import { HeartIcon } from 'lucide-react';

// Internal shared modules
import { useMemoPatchMutation } from '@extension/shared/hooks';
import { GetMemoResponse } from '@extension/shared/utils';
import { useSearchParams } from '@extension/shared/modules/search-params';

// Internal UI components
import { Badge } from '@src/components/ui/badge';
import { Card, CardContent, CardFooter, CardHeader } from '@src/components/ui/card';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@src/components/ui/tooltip';

// Internal hooks & utils
import useTranslation from '@src/modules/i18n/client';
import { LanguageType } from '@src/modules/i18n';
import { useSupabaseClient } from '@src/hooks';
import { useToast } from '@src/hooks/use-toast';
import { cn } from '@src/utils';
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1434bfd and 6cd8b18.

📒 Files selected for processing (28)
  • packages/shared/package.json (1 hunks)
  • packages/shared/src/constants/Extension.ts (1 hunks)
  • packages/shared/src/constants/Supabase.ts (1 hunks)
  • packages/shared/src/modules/local-storage/LocalStorage.ts (1 hunks)
  • packages/shared/src/modules/local-storage/constant.ts (1 hunks)
  • packages/shared/src/modules/local-storage/index.ts (1 hunks)
  • packages/shared/src/modules/local-storage/type.ts (1 hunks)
  • packages/shared/src/modules/local-storage/util.ts (1 hunks)
  • packages/shared/src/modules/search-params/SearchParams.test.ts (1 hunks)
  • packages/shared/src/modules/search-params/SearchParams.ts (1 hunks)
  • packages/shared/src/modules/search-params/constant.ts (1 hunks)
  • packages/shared/src/modules/search-params/index.ts (1 hunks)
  • packages/shared/src/modules/search-params/type.ts (1 hunks)
  • packages/shared/src/modules/search-params/useSearchParams.ts (1 hunks)
  • packages/shared/src/utils/web/Environment.ts (0 hunks)
  • packages/shared/src/utils/web/index.ts (0 hunks)
  • packages/web/src/app/[lng]/layout.tsx (3 hunks)
  • packages/web/src/app/[lng]/memos/components/Header/RefreshButton.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx (2 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoView/MemoItem.tsx (4 hunks)
  • packages/web/src/app/[lng]/memos/components/MemoView/index.tsx (1 hunks)
  • packages/web/src/app/[lng]/memos/hooks/useGuide.ts (1 hunks)
  • packages/web/src/app/[lng]/memos/utils/guide.ts (2 hunks)
  • packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts (1 hunks)
  • packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts (1 hunks)
  • packages/web/src/modules/i18n/client.js (1 hunks)
  • packages/web/src/utils/index.ts (1 hunks)
  • pages/side-panel/src/utils/Url.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/shared/src/utils/web/Environment.ts
  • packages/shared/src/utils/web/index.ts
✅ Files skipped from review due to trivial changes (3)
  • packages/shared/src/modules/local-storage/index.ts
  • packages/shared/src/modules/search-params/constant.ts
  • packages/shared/src/modules/search-params/index.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • packages/shared/package.json
  • packages/shared/src/constants/Extension.ts
  • packages/shared/src/constants/Supabase.ts
  • packages/web/src/app/[lng]/layout.tsx
  • packages/web/src/app/[lng]/memos/components/Header/RefreshButton.tsx
  • packages/web/src/app/[lng]/memos/components/MemoView/index.tsx
  • packages/web/src/app/[lng]/memos/hooks/useGuide.ts
  • packages/web/src/app/[lng]/memos/utils/guide.ts
  • packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts
  • packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts
  • packages/web/src/modules/i18n/client.js
  • packages/web/src/utils/index.ts
  • pages/side-panel/src/utils/Url.ts
🧰 Additional context used
🪛 Biome (1.9.4)
packages/shared/src/modules/local-storage/LocalStorage.ts

[error] 3-11: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

🔇 Additional comments (14)
packages/shared/src/modules/local-storage/type.ts (1)

5-5: 타입 정의가 잘 되어있습니다!

typeof를 사용한 타입 추론과 유니온 타입의 조합이 잘 구현되어 있습니다. 타입 안전성을 보장하면서도 확장 가능한 구조입니다.

packages/shared/src/modules/search-params/type.ts (1)

1-1: 상수 파일의 존재 여부와 내용을 확인하세요

SEARCH_PARAMS_KEYS 상수가 올바르게 정의되어 있는지 확인이 필요합니다.

✅ Verification successful

SEARCH_PARAMS_KEYS 상수가 올바르게 정의되어 있음을 확인했습니다

constant.ts 파일에서 SEARCH_PARAMS_KEYS['id', 'isWish', 'category']로 정확하게 정의되어 있으며, 타입 정의에서도 적절하게 사용되고 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and content of SEARCH_PARAMS_KEYS constant

# Check if the constant file exists and show its content
fd -e ts -e tsx constant.ts --exec cat {}

# Find usages of SEARCH_PARAMS_KEYS
rg "SEARCH_PARAMS_KEYS"

Length of output: 1375

packages/shared/src/modules/local-storage/LocalStorage.ts (1)

1-1: 타입 정의를 검토하세요.

LocalStorageKeyType의 정의를 확인하고 필요한 모든 키가 포함되어 있는지 검증해야 합니다.

✅ Verification successful

LocalStorageKeyType 정의가 명확하게 확인되었습니다.

LocalStorageKeyType은 다음 키들을 포함하고 있습니다:

  • 'guide': 가이드 관련 상태
  • 'updateVersion': 업데이트 버전 관련 상태
  • 'install': 설치 관련 상태
  • updateVersion${number}.${number}.${number} 형식의 버전 문자열

모든 필수 키가 포함되어 있으며, 타입 정의가 적절하게 되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# LocalStorageKeyType 정의를 확인
rg -t typescript "type LocalStorageKeyType" -A 5

Length of output: 85


Script:

#!/bin/bash
# LocalStorageKeyType 정의를 찾기 위한 다양한 검색 시도
rg "LocalStorageKeyType" -A 5

# index.ts 파일에서 타입 정의 찾기
fd "index.ts" --exec cat {} \; --exec echo "---" \;

# 타입 정의가 있을 수 있는 모든 타입스크립트 파일 검색
fd -e ts --exec cat {} \; --exec echo "---" \;

Length of output: 100294


Script:

#!/bin/bash
# LOCAL_STORAGE_KEY 상수 정의 찾기
rg "LOCAL_STORAGE_KEY" -A 5

# constant.ts 파일에서 LocalStorageKeyType 관련 정의 찾기
fd "constant.ts" --exec cat {} \; --exec echo "---" \;

Length of output: 2470

packages/shared/src/modules/local-storage/util.ts (1)

1-1: 깔끔한 import 구문입니다!

필요한 타입과 상수들을 명확하게 import하고 있습니다.

packages/shared/src/modules/local-storage/constant.ts (2)

3-3: 정규식 패턴이 적절해 보입니다.

시맨틱 버저닝 형식을 정확하게 검증할 수 있는 패턴입니다.


1-1: 타입 임포트 검증이 필요합니다.

임포트된 타입들이 올바르게 정의되어 있는지 확인이 필요합니다.

✅ Verification successful

타입 임포트가 올바르게 정의되어 있음을 확인했습니다.

UpdateVersionTypeLocalStorageKeyType 타입이 packages/shared/src/modules/local-storage/type.ts 파일에서 적절하게 정의되어 있고, 올바르게 내보내기(export)되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the imported types are properly defined
ast-grep --pattern 'type UpdateVersionType = $_'
ast-grep --pattern 'type LocalStorageKeyType = $_'

Length of output: 375

packages/shared/src/modules/search-params/SearchParams.ts (1)

1-5: 코드가 깔끔하고 타입이 잘 정의되어 있습니다!

타입스크립트의 타입 시스템을 잘 활용하고 있으며, private 필드를 사용하여 캡슐화가 잘 되어있습니다.

packages/web/src/app/[lng]/memos/components/MemoDialog/index.tsx (2)

28-29: 이전 리뷰 코멘트가 여전히 유효함

데이터 페칭 에러 처리와 로딩 상태 처리가 아직 구현되지 않았습니다.


60-64: 이전 리뷰 코멘트가 여전히 유효함

저장되지 않은 변경사항이 있을 때의 사용자 경험 처리가 아직 구현되지 않았습니다.

packages/web/src/app/[lng]/memos/components/MemoView/MemoItem.tsx (5)

21-21: 타입 정의가 개선되었습니다.

GetMemoResponse 타입으로 변경한 것은 좋은 선택입니다. API 응답 타입과 일치하도록 개선되었습니다.


28-28: Supabase 클라이언트 사용 방식이 개선되었습니다.

useSupabaseClient 훅을 사용하는 방식으로 변경한 것은 다음과 같은 장점이 있습니다:

  • 컴포넌트 생명주기와 잘 통합됩니다
  • 다른 컴포넌트들과 일관된 방식을 유지합니다

Also applies to: 32-32


86-86: 이미지 스타일링이 개선되었습니다.

object-fit: 'contain'height: 'auto' 설정으로 이미지 비율이 깨지지 않도록 수정된 점이 좋습니다.


126-126: prop 이름이 더 명확해졌습니다.

id에서 memoId로 prop 이름을 변경한 것은 좋은 개선입니다. 이는 prop의 목적을 더 명확하게 전달합니다.


34-35: 검색 파라미터 처리 방식 검증이 필요합니다.

새로운 검색 파라미터 처리 방식이 도입되었습니다. 다음 사항들을 확인해주세요:

  1. URL 업데이트 시 스크롤 동작이 의도한대로 작동하는지
  2. 브라우저 뒤로가기 동작이 올바르게 처리되는지

Also applies to: 59-60

✅ Verification successful

Let me gather more information about the scroll behavior implementation.


Let me check the implementation of browser history handling.


URL 파라미터 처리가 적절하게 구현되어 있습니다.

코드 분석 결과, 다음과 같은 사항들이 확인되었습니다:

  1. 스크롤 동작:

    • MemoItem과 MemoDialog에서 URL 업데이트 시 { scroll: false } 옵션을 사용하여 불필요한 스크롤을 방지
    • 카테고리 이동 시에만 { scroll: true }를 사용하여 의도적인 스크롤 동작 구현
  2. 브라우저 히스토리:

    • router.replace()를 사용하여 불필요한 히스토리 스택 쌓임을 방지
    • 공통 useSearchParams 훅을 통해 일관된 URL 파라미터 처리
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# URL 파라미터 처리 관련 코드 검색
rg "useSearchParams|router\.replace" -A 3

Length of output: 4159


Script:

#!/bin/bash
# Search for scroll-related configurations and implementations
rg "scroll:|scrollTo|scrollIntoView" -A 3

Length of output: 2446


Script:

#!/bin/bash
# Search for router and navigation related implementations
rg "useRouter|router\.(back|forward|push|replace)" -A 3

Length of output: 5903

@guesung guesung changed the base branch from master to develop November 26, 2024 12:15
@guesung guesung merged commit c06e6c9 into develop Nov 26, 2024
7 of 8 checks passed
@guesung guesung deleted the feature/dx-search-params branch November 26, 2024 12:16
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (7)
packages/shared/src/modules/local-storage/type.ts (2)

3-3: 버전 형식에 대한 문서화가 필요합니다.

템플릿 리터럴 타입을 사용하여 버전 문자열 형식을 잘 정의했습니다. 하지만 이 형식이 어떤 상황에서 사용되는지 설명하는 JSDoc 주석을 추가하면 좋을 것 같습니다.

다음과 같이 문서화를 추가해보세요:

+/**
+ * 업데이트 버전을 나타내는 문자열 타입
+ * @example 'updateVersion1.0.0'
+ */
export type UpdateVersionType = `updateVersion${number}.${number}.${number}`;

6-6: 타입 설계가 잘 되었습니다!

BasicStorageKeyTypeUpdateVersionType을 유니온 타입으로 결합한 것은 좋은 설계입니다. 이는 기본 스토리지 키와 버전 관련 키를 명확하게 구분하면서도 함께 사용할 수 있게 해줍니다.

향후 새로운 종류의 키가 필요할 경우, 이 유니온 타입에 추가하면 됩니다. 단, 키의 종류가 많아진다면 카테고리별로 분리하는 것을 고려해보세요.

packages/shared/src/modules/local-storage/util.ts (1)

1-10: 단위 테스트 추가를 고려해주세요.

localStorage 관련 기능은 중요한 부분이므로, 다음과 같은 테스트 케이스 추가를 권장드립니다:

  • 정상적인 값 설정/조회
  • localStorage 접근 불가 상황
  • 잘못된 키 사용

단위 테스트 코드 작성을 도와드릴까요?

packages/shared/src/modules/local-storage/constant.ts (3)

3-3: 정규식 패턴을 더 엄격하게 개선해 보세요.

현재 정규식은 부분 일치를 허용할 수 있으며, 버전 번호의 범위가 제한되어 있지 않습니다.

다음과 같이 개선하는 것을 제안드립니다:

-const REGEXR_UPDATE_VERSION_VERSION = /^updateVersion\d+\.\d+\.\d+$/;
+const REGEXR_UPDATE_VERSION_VERSION = /^updateVersion(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;

이렇게 수정하면:

  • 각 버전 번호가 0이거나 1-9로 시작하는 숫자만 허용
  • 불필요한 선행 0을 방지

5-6: 입력값 검증을 추가하면 좋을 것 같습니다.

현재 구현은 undefined 또는 null 입력에 대한 처리가 없습니다.

다음과 같이 개선하는 것을 제안드립니다:

-export const checkUpdateVersionKey = (value: string): value is UpdateVersionType =>
-  REGEXR_UPDATE_VERSION_VERSION.test(value);
+export const checkUpdateVersionKey = (value: string): value is UpdateVersionType =>
+  typeof value === 'string' && REGEXR_UPDATE_VERSION_VERSION.test(value);

8-8: 각 스토리지 키의 용도를 문서화하면 좋을 것 같습니다.

현재 코드만으로는 각 키의 구체적인 용도를 파악하기 어렵습니다.

다음과 같이 JSDoc을 추가하는 것을 제안드립니다:

+/**
+ * 로컬 스토리지 키 목록
+ * - guide: 사용자 가이드 표시 여부
+ * - updateVersion: 앱 업데이트 버전 정보
+ * - install: 앱 설치 상태
+ */
export const LOCAL_STORAGE_KEYS = ['guide', 'updateVersion', 'install'] as const;
packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts (1)

18-34: useEffect 로직 개선이 필요합니다

현재 구현은 다음과 같은 개선이 필요합니다:

  1. 조건문이 중첩되어 있어 가독성이 떨어집니다
  2. 상태 업데이트 로직이 반복됩니다

다음과 같이 리팩토링하는 것을 제안드립니다:

 useEffect(() => {
   if (manifest === null) return;
 
   const isExtensionInstalled = manifest !== undefined;
   const isExtensionNotLastVersion = isExtensionInstalled && manifest.version !== EXTENSION.lastVersion;
 
-  if (!isExtensionInstalled && !checkLocalStorageTrue('install')) {
-    setDialogType('install');
-    setOpen(true);
-    return;
-  }
-  if (isExtensionNotLastVersion && !checkLocalStorageTrue('updateVersion')) {
-    setDialogType('update');
-    setOpen(true);
-    return;
-  }
+  const shouldShowInstall = !isExtensionInstalled && !checkLocalStorageTrue('install');
+  const shouldShowUpdate = isExtensionNotLastVersion && !checkLocalStorageTrue('updateVersion');
+
+  if (shouldShowInstall || shouldShowUpdate) {
+    setDialogType(shouldShowInstall ? 'install' : 'update');
+    setOpen(true);
+  }
 }, [manifest]);
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6cd8b18 and 733cb2a.

📒 Files selected for processing (11)
  • packages/shared/src/modules/local-storage/LocalStorage.ts (1 hunks)
  • packages/shared/src/modules/local-storage/constant.ts (1 hunks)
  • packages/shared/src/modules/local-storage/type.ts (1 hunks)
  • packages/shared/src/modules/local-storage/util.ts (1 hunks)
  • packages/shared/src/modules/search-params/SearchParams.test.ts (1 hunks)
  • packages/shared/src/modules/search-params/SearchParams.ts (1 hunks)
  • packages/web/src/app/auth/callback/route.ts (2 hunks)
  • packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts (1 hunks)
  • packages/web/src/app/components/ExtensionDialog/index.tsx (1 hunks)
  • packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts (1 hunks)
  • packages/web/tsconfig.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • packages/shared/src/modules/search-params/SearchParams.test.ts
  • packages/shared/src/modules/search-params/SearchParams.ts
  • packages/web/src/app/components/ExtensionDialog/getExtensionDialogInfo.ts
  • packages/web/src/app/components/ExtensionDialog/index.tsx
  • packages/web/tsconfig.json
🧰 Additional context used
🪛 Biome (1.9.4)
packages/shared/src/modules/local-storage/LocalStorage.ts

[error] 3-11: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

🔇 Additional comments (12)
packages/shared/src/modules/local-storage/type.ts (2)

1-1: 상수 가져오기가 올바르게 구현되었습니다!

로컬 스토리지 키 상수를 상대 경로로 올바르게 가져오고 있습니다.


4-4: LOCAL_STORAGE_KEYS 상수의 정의를 확인해주세요.

LOCAL_STORAGE_KEYS 상수로부터 타입을 추출하는 방식이 적절합니다. 하지만 상수의 정의가 올바른지 확인이 필요합니다.

다음 스크립트로 상수 정의를 확인할 수 있습니다:

✅ Verification successful

LOCAL_STORAGE_KEYS 상수가 올바르게 정의되어 있습니다.

LOCAL_STORAGE_KEYS 상수가 guide, updateVersion, install 세 가지 키를 포함하는 문자열 배열로 적절하게 정의되어 있으며, as const 단언을 통해 타입 안전성이 보장되어 있습니다.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# LOCAL_STORAGE_KEYS 상수의 정의 확인
ast-grep --pattern 'const LOCAL_STORAGE_KEYS = [$$$] as const'

Length of output: 202

packages/shared/src/modules/local-storage/util.ts (1)

1-2: LGTM!

타입과 의존성이 명확하게 정의되어 있습니다.

packages/shared/src/modules/local-storage/LocalStorage.ts (2)

4-6: JSON 파싱 및 오류 처리가 필요합니다

이전 리뷰에서 지적된 JSON 파싱 관련 문제가 아직 해결되지 않았습니다.


3-11: 정적 메서드만 포함된 클래스를 함수로 변경하세요

이전 리뷰에서 제안된 클래스 구조 개선이 아직 반영되지 않았습니다.

🧰 Tools
🪛 Biome (1.9.4)

[error] 3-11: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

packages/shared/src/modules/local-storage/constant.ts (2)

1-1: 타입 임포트가 깔끔하게 구성되어 있습니다!

타입 정의를 별도 파일로 분리하고, 명확한 네이밍을 사용한 점이 좋습니다.


10-14: 타입 안전성이 잘 구현되어 있습니다!

isBasicStorageKeycheckLocalStorageKey 함수가 타입 가드를 효과적으로 활용하고 있어 타입 안전성을 보장합니다.

packages/web/src/app/auth/callback/route.ts (1)

4-4: 상수 관리 개선이 잘 되었습니다!

개별 상수들을 COOKIE_KEY 객체로 통합하여 관리하는 방식으로 개선된 것이 좋습니다.

packages/web/src/app/components/ExtensionDialog/useExtensionDialog.ts (4)

1-11: 경로 별칭 설정 확인이 필요합니다

이전 리뷰에서 지적된 @extension 경로 별칭 문제가 여전히 존재합니다.


13-17: 상태 관리가 잘 구현되어 있습니다

opendialogType 상태가 명확하게 분리되어 있고, 타입 정의도 적절합니다.


21-23: 버전 비교 로직 개선이 필요합니다

이전 리뷰에서 지적된 버전 비교 문제가 해결되지 않았습니다. 시맨틱 버저닝을 올바르게 처리하기 위해 semver 라이브러리 사용을 권장드립니다.


36-39: handleClose 함수가 적절하게 구현되어 있습니다

로컬 스토리지 키 검증 후 상태를 업데이트하는 로직이 안전하게 구현되어 있습니다.

Comment on lines +4 to +6
export const setLocalStorageTrue = (key: LocalStorageKeyType) => {
LocalStorage.set(key, true);
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

localStorage 사용 시 안전성 개선이 필요합니다.

다음과 같은 개선사항을 제안드립니다:

  1. localStorage 접근 실패에 대한 예외 처리
  2. 반환 타입 명시
  3. 값 매핑 상수 사용
-export const setLocalStorageTrue = (key: LocalStorageKeyType) => {
+export const setLocalStorageTrue = (key: LocalStorageKeyType): void => {
+  try {
-    LocalStorage.set(key, true);
+    LocalStorage.set(key, LOCAL_STORAGE_VALUE_MAP.true);
+  } catch (error) {
+    console.error(`localStorage 설정 중 오류 발생: ${error}`);
+  }
 };

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +8 to +10
export const checkLocalStorageTrue = (key: LocalStorageKeyType) => {
return LocalStorage.get(key) === true;
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

타입 안전성과 예외 처리가 필요합니다.

boolean 값 비교 시 LOCAL_STORAGE_VALUE_MAP.true를 사용하고, localStorage 접근 실패에 대한 처리가 필요합니다.

-export const checkLocalStorageTrue = (key: LocalStorageKeyType) => {
+export const checkLocalStorageTrue = (key: LocalStorageKeyType): boolean => {
+  try {
-    return LocalStorage.get(key) === true;
+    return LocalStorage.get(key) === LOCAL_STORAGE_VALUE_MAP.true;
+  } catch (error) {
+    console.error(`localStorage 확인 중 오류 발생: ${error}`);
+    return false;
+  }
 };

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +4 to +6
static get<T>(key: LocalStorageKeyType): T | null {
return JSON.parse(localStorage.getItem(key) ?? '');
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

제네릭 타입 안전성을 개선하세요

현재 구현은 타입 안전성이 보장되지 않습니다. 저장된 데이터의 타입과 반환 타입이 일치하지 않을 수 있습니다.

다음과 같이 개선하는 것을 제안합니다:

-  static get<T>(key: LocalStorageKeyType): T | null {
-    return JSON.parse(localStorage.getItem(key) ?? '');
+  static get<T>(key: LocalStorageKeyType): T | null {
+    try {
+      const item = localStorage.getItem(key);
+      if (!item) return null;
+      
+      const parsed = JSON.parse(item);
+      // 런타임 타입 검사 추가
+      if (typeof parsed !== typeof {} as T) {
+        console.warn(`Type mismatch for key ${key}`);
+        return null;
+      }
+      return parsed as T;
+    } catch (error) {
+      console.error(`Failed to parse localStorage key ${key}:`, error);
+      return null;
+    }
   }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 18 to +28
cookieStore.set(COOKIE_KEY.accessToken, sessionData.session.access_token, {
maxAge: 3600 * 24 * 365, // 1년
secure: true,
httpOnly: true,
sameSite: 'strict',
});
cookieStore.set(COOKIE_KEY.refreshToken, sessionData.session.refresh_token, {
maxAge: 3600 * 24 * 365, // 1년
secure: true,
httpOnly: true,
sameSite: 'strict',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

보안 설정은 개선되었으나, 만료 기간 검토가 필요합니다.

쿠키 보안 설정(secure, httpOnly, sameSite)이 추가된 것은 매우 긍정적인 변화입니다. 하지만 여전히 다음 사항에 대한 검토가 필요합니다:

토큰의 만료 기간이 1년으로 설정되어 있는데, 이는 보안상 너무 긴 기간입니다. 다음과 같이 수정하는 것을 권장드립니다:

 cookieStore.set(COOKIE_KEY.accessToken, sessionData.session.access_token, {
-  maxAge: 3600 * 24 * 365, // 1년
+  maxAge: 3600 * 24 * 30, // 30일
   secure: true,
   httpOnly: true,
   sameSite: 'strict',
 });

 cookieStore.set(COOKIE_KEY.refreshToken, sessionData.session.refresh_token, {
-  maxAge: 3600 * 24 * 365, // 1년
+  maxAge: 3600 * 24 * 30, // 30일
   secure: true,
   httpOnly: true,
   sameSite: 'strict',
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cookieStore.set(COOKIE_KEY.accessToken, sessionData.session.access_token, {
maxAge: 3600 * 24 * 365, // 1년
secure: true,
httpOnly: true,
sameSite: 'strict',
});
cookieStore.set(COOKIE_KEY.refreshToken, sessionData.session.refresh_token, {
maxAge: 3600 * 24 * 365, // 1년
secure: true,
httpOnly: true,
sameSite: 'strict',
cookieStore.set(COOKIE_KEY.accessToken, sessionData.session.access_token, {
maxAge: 3600 * 24 * 30, // 30일
secure: true,
httpOnly: true,
sameSite: 'strict',
});
cookieStore.set(COOKIE_KEY.refreshToken, sessionData.session.refresh_token, {
maxAge: 3600 * 24 * 30, // 30일
secure: true,
httpOnly: true,
sameSite: 'strict',

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant