๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Project ESG+AI/[์‚ผ์ •KPMG]ESG ๋ฐ์ดํ„ฐ ํ™œ์šฉ ํ’€์Šคํ… ๊ฐœ๋ฐœ

30์ผ์ฐจ.

by GreenJin_S2 2025. 11. 19.

 


 

@frontend ์—ฌ๊ธฐ;์— ์ปจํ…์ŠคํŠธ๋กœ store๋ฅผ ๋ฐ˜๋“œ์‹œ 1๊ฐœ๋งŒ ๋งŒ๋“ค๊ณ , ์ด๊ฒƒ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ zustand๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ด. ํ•ด๋‹น๊ณผ์ •์— ๋Œ€ํ•ด ์ง์ ‘ ์‹คํ–‰ํ•˜์ง€๋Š” ๋ง๊ณ  ์ „๋žต์„ ์ž‘์„ฑํ•ด์ค˜

 

Zustand ๋‹จ์ผ Store ์ „๋žต

1. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์„ค๊ณ„

 

2. ์˜์กด์„ฑ ์„ค์น˜

  • zustand ์„ค์น˜ (ํ˜„์žฌ ๋ฏธ์„ค์น˜)
  • TypeScript ํƒ€์ž…์€ ๋‚ด์žฅ

3. Store ๊ตฌ์กฐ ์„ค๊ณ„ ์›์น™

3.1 ๋‹จ์ผ Store ํŒจํ„ด

  • ํ•˜๋‚˜์˜ zustand store๋งŒ ์ƒ์„ฑ (useStore)
  • ์—ฌ๋Ÿฌ ๋„๋ฉ”์ธ ์ƒํƒœ๋Š” store ๋‚ด๋ถ€์—์„œ ์Šฌ๋ผ์ด์Šค๋กœ ๋ถ„๋ฆฌ
  • ์˜ˆ: chat, ui, user ๋“ฑ

3.2 Store ์Šฌ๋ผ์ด์Šค ๊ตฌ์กฐ ์˜ˆ์‹œ

 

4. ๊ตฌํ˜„ ๋‹จ๊ณ„

Step 1: ํƒ€์ž… ์ •์˜

  • types/store.ts์— ์ „์ฒด store ํƒ€์ž… ์ •์˜
  • ํ˜„์žฌ page.tsx์˜ Message ์ธํ„ฐํŽ˜์ด์Šค ํฌํ•จ

Step 2: Store ์ƒ์„ฑ

  • store/useStore.ts์—์„œ create๋กœ ๋‹จ์ผ store ์ƒ์„ฑ
  • ์ดˆ๊ธฐ ์ƒํƒœ์™€ actions ์ •์˜
  • ํ˜„์žฌ page.tsx์˜ ๋กœ์ง์„ store actions๋กœ ์ด๋™

Step 3: Store Export

  • store/index.ts์—์„œ useStore๋งŒ export
  • ๋‹ค๋ฅธ store ํŒŒ์ผ ์ƒ์„ฑ ๊ธˆ์ง€

Step 4: ์ปดํฌ๋„ŒํŠธ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜

  • page.tsx์˜ useState๋ฅผ useStore๋กœ ๊ต์ฒด
  • selector ํŒจํ„ด์œผ๋กœ ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ๊ตฌ๋…

5. Store ์‚ฌ์šฉ ํŒจํ„ด

5.1 Selector ํŒจํ„ด

 

5.2 Actions ์‚ฌ์šฉ

  • ๋ชจ๋“  ์ƒํƒœ ๋ณ€๊ฒฝ์€ actions๋กœ๋งŒ ์ˆ˜ํ–‰
  • ์ง์ ‘ ์ƒํƒœ ์ˆ˜์ • ๊ธˆ์ง€

6. Next.js App Router ๊ณ ๋ ค์‚ฌํ•ญ

6.1 Server/Client ์ปดํฌ๋„ŒํŠธ

  • Store๋Š” Client Component์—์„œ๋งŒ ์‚ฌ์šฉ
  • 'use client' ๋””๋ ‰ํ‹ฐ๋ธŒ ํ•„์š”

6.2 SSR ํ˜ธํ™˜์„ฑ

  • zustand๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ SSR ํ˜ธํ™˜
  • ์ดˆ๊ธฐ ์ƒํƒœ๋Š” ํ•˜์ด๋“œ๋ ˆ์ด์…˜ ์‹œ ๋™๊ธฐํ™”

7. ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ „๋žต

7.1 ํ˜„์žฌ ์ƒํƒœ ๋ถ„์„

  • page.tsx์˜ ์ƒํƒœ:
  • messages: Message[]
  • input: string

7.2 ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ˆœ์„œ

  1. Store ํƒ€์ž… ์ •์˜
  1. Store ์ƒ์„ฑ ๋ฐ actions ๊ตฌํ˜„
  1. page.tsx์—์„œ store ์‚ฌ์šฉ์œผ๋กœ ๋ณ€๊ฒฝ
  1. ํ…Œ์ŠคํŠธ ๋ฐ ๊ฒ€์ฆ

8. ํŒŒ์ผ ์ƒ์„ฑ ๊ณ„ํš

  1. src/types/store.ts - ํƒ€์ž… ์ •์˜
  1. src/store/useStore.ts - ๋‹จ์ผ zustand store
  1. src/store/index.ts - export ์ง„์ž…์ 

9. ์ฃผ์˜์‚ฌํ•ญ

  • ๋‹จ์ผ store ์›์น™: useStore.ts ์™ธ ๋‹ค๋ฅธ store ํŒŒ์ผ ์ƒ์„ฑ ๊ธˆ์ง€
  • ํƒ€์ž… ์•ˆ์ •์„ฑ: TypeScript๋กœ ํƒ€์ž… ์ •์˜
  • ์„ฑ๋Šฅ: selector๋กœ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง ๋ฐฉ์ง€
  • ํ™•์žฅ์„ฑ: ์Šฌ๋ผ์ด์Šค ํŒจํ„ด์œผ๋กœ ๋„๋ฉ”์ธ๋ณ„ ๊ด€๋ฆฌ

10. ๊ฒ€์ฆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

  • [ ] zustand ํŒจํ‚ค์ง€ ์„ค์น˜ ํ™•์ธ
  • [ ] store/useStore.ts ๋‹จ์ผ ํŒŒ์ผ ์กด์žฌ ํ™•์ธ
  • [ ] store/index.ts์—์„œ ๋‹จ์ผ export ํ™•์ธ
  • [ ] ๋‹ค๋ฅธ store ํŒŒ์ผ ์—†์Œ ํ™•์ธ
  • [ ] ์ปดํฌ๋„ŒํŠธ์—์„œ useStore ์‚ฌ์šฉ ํ™•์ธ
  • [ ] ํƒ€์ž… ์—๋Ÿฌ ์—†์Œ ํ™•์ธ

 


<!-- 79f2f66b-147a-4a97-81fb-958c5d709f55 692e06e3-c0d1-4ed0-9fb1-c8d97512fe1c -->
# esgseed → frontend ํ†ตํ•ฉ ๋ฐ ๋‹จ์ผ React Context/Zustand ์ „๋žต

## 1. ๋ชฉํ‘œ ์ƒํƒœ ์ •์˜

- **์•ฑ์€ ํ•˜๋‚˜๋งŒ ์œ ์ง€**: `frontend`(Next.js App Router)๊ฐ€ ์ตœ์ข… SPA์˜ ์ง„์ž…์ ์ด ๋จ
- **esgseed** ๋””๋ ‰ํ† ๋ฆฌ๋Š” **ํŽ˜์ด์ง€/์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—ญํ• **๋งŒ ํ•˜๊ณ , ๋ณ„๋„ Vite ์•ฑ์œผ๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ์ •๋ฆฌ
- **์ „์—ญ ์ƒํƒœ ๋ ˆ์ด์–ด๋Š” ํ•˜๋‚˜**:
  - `frontend/src/store/useStore.ts` (์ด๋ฏธ ๊ตฌ์ถ•๋œ Zustand ์Šคํ† ์–ด)
  - ๋˜๋Š” ํ•„์š” ์‹œ ์ด ์œ„์— React Context Provider๋ฅผ ์–‡๊ฒŒ ์”Œ์›Œ์„œ ์‚ฌ์šฉ

## 2. esgseed ๊ตฌ์กฐ ๋ถ„์„ ๋ฐ ๋ถ„๋ฅ˜

1. `esgseed/src` ์•„๋ž˜ ํŒŒ์ผ๋“ค์„ ์—ญํ• ๋ณ„๋กœ ๋ถ„๋ฅ˜

   - `pages` ์„ฑ๊ฒฉ ์ปดํฌ๋„ŒํŠธ (์ „์ฒด ํ™”๋ฉด ๊ตฌ์„ฑ)
   - `components` ์„ฑ๊ฒฉ UI ์กฐ๊ฐ (๋ฒ„ํŠผ, ์นด๋“œ, ๋ฆฌ์ŠคํŠธ ๋“ฑ)

2. ๋ผ์šฐํŒ… ์˜์กด์„ฑ ํ™•์ธ

   - `react-router`, `vite` ์ „์šฉ ํ›…/์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ ์—ฌ๋ถ€ ์ฒดํฌ
   - ์ „์—ญ ์ƒํƒœ/Context ์‚ฌ์šฉ ์—ฌ๋ถ€ ์ฒดํฌ (์˜ˆ: `useContext`, `Redux`, `Recoil` ๋“ฑ)

๊ฒฐ๊ณผ์— ๋”ฐ๋ผ **ํŽ˜์ด์ง€์™€ ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ**๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ์˜ฎ๊ธฐ๋Š” ์ „๋žต์„ ์„ธ์›€.

## 3. ํ†ตํ•ฉ ๋Œ€์ƒ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ์„ค๊ณ„

`frontend` ํ”„๋กœ์ ํŠธ ๋‚ด๋ถ€์—์„œ esgseed ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ˆ˜์šฉํ•  ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ์ •์˜:

```bash
frontend/
  src/
    store/
      useStore.ts        # ๋‹จ์ผ Zustand ์Šคํ† ์–ด (์ด๋ฏธ ์กด์žฌ)
    lib/
      api.ts             # ๋ฐฑ์—”๋“œ ํ˜ธ์ถœ ์œ ํ‹ธ๋ฆฌํ‹ฐ
    features/
      esgseed/
        components/      # esgseed์—์„œ ์˜จ ์ˆœ์ˆ˜ UI ์ปดํฌ๋„ŒํŠธ๋“ค
        pages/           # esgseed ํŽ˜์ด์ง€ ๋ ˆ์ด์•„์›ƒ/์ปจํ…Œ์ด๋„ˆ
```

- `features/esgseed/components`: Next, Vite์— ์˜์กดํ•˜์ง€ ์•Š๋Š” ์ˆœ์ˆ˜ React ์ปดํฌ๋„ŒํŠธ๋กœ ์ •๋ฆฌ
- `features/esgseed/pages`: ์‹ค์ œ Next `app` ๋ผ์šฐํŠธ์—์„œ importํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ์ปดํฌ๋„ŒํŠธ

## 4. esgseed ์ปดํฌ๋„ŒํŠธ ์ด๊ด€ ์ „๋žต

### 4.1 ์ˆœ์ˆ˜ UI ์ปดํฌ๋„ŒํŠธ ์ด๋™

1. Vite ์ „์šฉ ์ฝ”๋“œ(์˜ˆ: `import.meta.env`, `react-router-dom` ๋“ฑ)๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ Next์— ๋งž๊ฒŒ ์น˜ํ™˜
2. ๊ฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ `frontend/src/features/esgseed/components`๋กœ ๋ณต์‚ฌ/์ด๋™
3. ๊ฒฝ๋กœ/๋ณ„์นญ ์ •๋ฆฌ

   - `import X from '../../components/X'` → `import X from '@/features/esgseed/components/X'`

### 4.2 ํŽ˜์ด์ง€ ๋ ˆ๋ฒจ ์ปดํฌ๋„ŒํŠธ ํฌํŒ…

1. `esgseed`์˜ ํŽ˜์ด์ง€ ๋‹จ ์ปดํฌ๋„ŒํŠธ๋ฅผ `frontend/src/features/esgseed/pages`๋กœ ์ด๋™
2. Next ๋ผ์šฐํŠธ ์ƒ์„ฑ:

   - ์˜ˆ: esgseed์˜ `/dashboard` ํŽ˜์ด์ง€ → `frontend/src/app/dashboard/page.tsx`
   - ํŒŒ์ผ ๋‚ด์šฉ:
     ```tsx
     'use client';
     
     import DashboardPage from '@/features/esgseed/pages/DashboardPage';
     
     export default function Page() {
       return <DashboardPage />;
     }
     ```


3. ํŽ˜์ด์ง€ ํŒŒ์ผ(`app/.../page.tsx`)์€ Next ๊ทœ์น™์— ๋”ฐ๋ผ `'use client'` ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •

   - Zustand/๋ธŒ๋ผ์šฐ์ € API ์‚ฌ์šฉ ์‹œ `'use client'` ์œ ์ง€

## 5. ๋‹จ์ผ ์ „์—ญ ์ƒํƒœ(React Context + Zustand) ์„ค๊ณ„

### 5.1 Zustand๋ฅผ ๋‹จ์ผ ์†Œ์Šค ์˜ค๋ธŒ ํŠธ๋ฃจ์Šค๋กœ ์‚ฌ์šฉ

- ์ด๋ฏธ ์กด์žฌํ•˜๋Š” `src/store/useStore.ts`๋ฅผ ํ™•์žฅํ•˜์—ฌ esgseed์—์„œ๋„ ํ•„์š”ํ•œ ์ƒํƒœ/์•ก์…˜์„ ์ถ”๊ฐ€
- esgseed ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” ๋ชจ๋‘ `useStore`๋งŒ ์‚ฌ์šฉํ•˜๋„๋ก ํ†ต์ผ

์˜ˆ์‹œ:

```ts
// esgseed์—์„œ ํ•„์š”๋กœ ํ•˜๋Š” state
interface AppState {
  // ๊ธฐ์กด soccer ๊ด€๋ จ ์ƒํƒœ...
  // esgseed ๊ณตํ†ต UI ์ƒํƒœ
  theme: 'light' | 'dark';
  sidebarOpen: boolean;
  setTheme: (theme: 'light' | 'dark') => void;
  toggleSidebar: () => void;
}
```

### 5.2 ์„ ํƒ์  React Context ๋ž˜ํผ (์›ํ•˜๋ฉด)

- ๋งŒ์•ฝ esgseed ์ชฝ์ด `useContext` ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„๋˜์–ด ์žˆ๋‹ค๋ฉด:

  1. ์ƒˆ๋กœ์šด `AppContext`๋ฅผ ๋งŒ๋“ค๊ณ  ๋‚ด๋ถ€ ๊ตฌํ˜„์—์„œ **Zustand๋ฅผ ์œ„์ž„**
  2. ๊ธฐ์กด esgseed ์ปดํฌ๋„ŒํŠธ๋Š” `useContext(AppContext)`๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ
  3. Context Provider ๊ตฌํ˜„ ์˜ˆ:
  ```tsx
  'use client';
  import { createContext, useContext } from 'react';
  import { useStore } from '@/store/useStore';
  
  const AppContext = createContext<ReturnType<typeof useStore> | null>(null);
  
  export function AppProvider({ children }: { children: React.ReactNode }) {
    const store = useStore();
    return <AppContext.Provider value={store}>{children}</AppContext.Provider>;
  }
  
  export function useAppContext() {
    const ctx = useContext(AppContext);
    if (!ctx) throw new Error('useAppContext must be used within AppProvider');
    return ctx;
  }
  ```


- `src/app/layout.tsx` ํ˜น์€ ์ƒ์œ„ client ์ปดํฌ๋„ŒํŠธ์—์„œ `AppProvider`๋กœ ์ „์ฒด ๊ฐ์‹ธ๊ธฐ

## 6. Next ์•ฑ์— Provider ์—ฐ๊ฒฐ

1. `src/app/layout.tsx`๊ฐ€ **์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ**์ผ ๊ฒฝ์šฐ:

   - ๋ณ„๋„ `AppProviders` client ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ:
   ```tsx
   // src/app/AppProviders.tsx
   'use client';
   import { AppProvider } from '@/store/AppContext';
   
   export default function AppProviders({ children }: { children: React.ReactNode }) {
     return <AppProvider>{children}</AppProvider>;
   }
   ```

   - `layout.tsx`์—์„œ:
   ```tsx
   import AppProviders from './AppProviders';
   
   export default function RootLayout({ children }: { children: React.ReactNode }) {
     return (
       <html lang="ko">
         <body>
           <AppProviders>{children}</AppProviders>
         </body>
       </html>
     );
   }
   ```


2. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด `frontend`์™€ esgseed์—์„œ ์˜จ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ **๋™์ผํ•œ Zustand/Context ์ƒํƒœ**๋ฅผ ๊ณต์œ 

## 7. esgseed ๋นŒ๋“œ/์„ค์ • ์ •๋ฆฌ

1. esgseed์˜ **Vite ๊ด€๋ จ ํŒŒ์ผ** ์ œ๊ฑฐ/๋ฌดํšจํ™”:

   - `esgseed/vite.config.ts`, `esgseed/index.html`, `esgseed/src/main.tsx` ๋“ฑ
   - `esgseed/package.json`์—์„œ ์Šคํฌ๋ฆฝํŠธ๋Š” ์ ์ง„์ ์œผ๋กœ ์‚ฌ์šฉ ์ค‘๋‹จ

2. ํ•„์š”ํ•˜๋‹ค๋ฉด esgseed๋ฅผ **ํŒจํ‚ค์ง€ํ™”** (์˜ˆ: `packages/esgseed-ui`)ํ•ด์„œ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ,

ํ˜„์žฌ๋Š” ๋‹จ์ˆœํžˆ `frontend/src/features/esgseed`๋กœ ํ•ฉ์น˜๋Š” ์ชฝ์ด ๊ฐ„๋‹จ

## 8. ํ…Œ์ŠคํŠธ ํ”Œ๋กœ์šฐ

1. `pnpm build` (frontend ๋ฃจํŠธ)๋กœ ํƒ€์ž…/๋นŒ๋“œ ์˜ค๋ฅ˜ ํ™•์ธ
2. `pnpm dev` ์‹คํ–‰ ํ›„:

   - esgseed์—์„œ ์˜จ ํŽ˜์ด์ง€ ๋ผ์šฐํŠธ๋“ค ์ •์ƒ ๋™์ž‘ ์—ฌ๋ถ€ ํ™•์ธ
   - Zustand/Context ์ƒํƒœ๊ฐ€ ํ™ˆ ํŽ˜์ด์ง€์™€ esgseed ํŽ˜์ด์ง€ ๊ฐ„์— ๊ณต์œ ๋˜๋Š”์ง€ ํ™•์ธ

3. ๋ธŒ๋ผ์šฐ์ € DevTools๋กœ ๋ฆฌ๋ Œ๋”๋ง/์ƒํƒœ ๋ณ€ํ™” ํ™•์ธ

## 9. ๋‹จ๊ณ„๋ณ„ ์š”์•ฝ

1. esgseed ์ปดํฌ๋„ŒํŠธ๋ฅผ `frontend/src/features/esgseed`๋กœ ์ด๋™
2. Zustand Store(`src/store/useStore.ts`)์— esgseed ๊ด€๋ จ ์ƒํƒœ/์•ก์…˜ ์ถ”๊ฐ€
3. ํ•„์š”ํ•œ ๊ฒฝ์šฐ React Context ๋ž˜ํผ(AppContext) ์ถ”๊ฐ€
4. `app/layout.tsx`์—์„œ Provider ์—ฐ๊ฒฐ
5. esgseed ํŽ˜์ด์ง€๋ฅผ Next `app` ๋ผ์šฐํŠธ์— ๋งคํ•‘
6. Vite/Vite ์ „์šฉ ์„ค์ • ์ œ๊ฑฐ ๋ฐ esgseed๋ฅผ ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ ๋ชจ์Œ์œผ๋กœ ์ •๋ฆฌ

### To-dos

- [ ] pnpm์œผ๋กœ zustand ์˜์กด์„ฑ ์„ค์น˜
- [ ] src/store/index.ts ์ƒ์„ฑ - ํƒ€์ž…, ์ƒํƒœ, actions ์ •์˜
- [ ] page.tsx์˜ useState๋ฅผ useStore๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
- [ ] soccer/page.tsx์˜ ๋กœ์ปฌ ์ƒํƒœ๋ฅผ Store๋กœ ์ด์ „
- [ ] pnpm dev๋กœ ๋™์ž‘ ํ™•์ธ ๋ฐ DevTools ์ ๊ฒ€

 

 

**์ด๋Œ€๋กœ ์ปค์„œ์—๊ฒŒ ๋งํ•˜๊ณ  ์ •๋ฆฌํ•˜๋ฉด์„œ ์ง„ํ–‰ํ•˜๊ธฐ 

 

 


 

 

 

๊ฐœ์ธ ํ”„๋กœ์ ํŠธ๋„ ํ‹ˆํ‹ˆํžˆ ํ•˜๊ธฐ!