Files
sam-react-prod/claudedocs/[REF-2026-01-09] server-to-client-component-migration-checklist.md
byeongcheolryu 284c19f036 refactor(WEB): Server Component → Client Component 전면 마이그레이션
- 53개 페이지를 Server Component에서 Client Component로 변환
- Next.js 15에서 Server Component 렌더링 중 쿠키 수정 불가 이슈 해결
- 폐쇄형 ERP 시스템 특성상 SEO 불필요, Client Component 사용이 적합

주요 변경사항:
- 모든 페이지에 'use client' 지시어 추가
- use(params) 훅으로 async params 처리
- useState + useEffect로 데이터 페칭 패턴 적용
- skipTokenRefresh 옵션 및 관련 코드 제거 (더 이상 필요 없음)

변환된 페이지:
- Settings: 4개 (account-info, notification-settings, permissions, popup-management)
- Accounting: 9개 (vendors, sales, deposits, bills, withdrawals, expected-expenses, bad-debt-collection)
- Sales: 4개 (quote-management, pricing-management)
- Production/Quality/Master-data: 6개
- Material/Outbound: 4개
- Construction: 22개
- Other: 4개 (payment-history, subscription, dev/test-urls)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 19:19:37 +09:00

4.6 KiB

Server Component → Client Component 마이그레이션 계획서

배경

  • 문제: Server Component에서 API 호출 시 토큰 갱신(쿠키 수정)이 불가능
  • 원인: Next.js 15에서 Server Component 렌더링 중 쿠키 수정 금지
  • 영향: 토큰 만료 시 기본값 표시 → 데이터 덮어쓰기 위험
  • 결정: 폐쇄형 사이트로 SEO 불필요, Client Component로 전환

변경 대상 (53개 페이지)

Settings (4개)

  • settings/notification-settings/page.tsx
  • settings/popup-management/page.tsx
  • settings/permissions/[id]/page.tsx
  • settings/account-info/page.tsx

Accounting (9개)

  • accounting/vendors/page.tsx
  • accounting/sales/page.tsx
  • accounting/deposits/page.tsx
  • accounting/bills/page.tsx
  • accounting/withdrawals/page.tsx
  • accounting/expected-expenses/page.tsx
  • accounting/bad-debt-collection/page.tsx
  • accounting/bad-debt-collection/[id]/page.tsx
  • accounting/bad-debt-collection/[id]/edit/page.tsx

Sales (4개)

  • sales/quote-management/page.tsx
  • sales/pricing-management/page.tsx
  • sales/pricing-management/[id]/edit/page.tsx
  • sales/pricing-management/create/page.tsx

Production (3개)

  • production/work-orders/[id]/page.tsx
  • production/screen-production/page.tsx
  • production/screen-production/[id]/page.tsx

Quality (1개)

  • quality/inspections/[id]/page.tsx

Master Data (2개)

  • master-data/process-management/[id]/page.tsx
  • master-data/process-management/[id]/edit/page.tsx

Material (2개)

  • material/stock-status/[id]/page.tsx
  • material/receiving-management/[id]/page.tsx

Outbound (2개)

  • outbound/shipments/[id]/page.tsx
  • outbound/shipments/[id]/edit/page.tsx

Construction - Order (8개)

  • construction/order/order-management/[id]/page.tsx
  • construction/order/order-management/[id]/edit/page.tsx
  • construction/order/site-management/[id]/page.tsx
  • construction/order/site-management/[id]/edit/page.tsx
  • construction/order/structure-review/[id]/page.tsx
  • construction/order/structure-review/[id]/edit/page.tsx
  • construction/order/base-info/items/[id]/page.tsx
  • construction/order/base-info/pricing/[id]/page.tsx
  • construction/order/base-info/pricing/[id]/edit/page.tsx
  • construction/order/base-info/labor/[id]/page.tsx

Construction - Project/Bidding (8개)

  • construction/project/bidding/[id]/page.tsx
  • construction/project/bidding/[id]/edit/page.tsx
  • construction/project/bidding/site-briefings/[id]/page.tsx
  • construction/project/bidding/site-briefings/[id]/edit/page.tsx
  • construction/project/bidding/estimates/[id]/page.tsx
  • construction/project/bidding/estimates/[id]/edit/page.tsx
  • construction/project/bidding/partners/[id]/page.tsx
  • construction/project/bidding/partners/[id]/edit/page.tsx

Construction - Project/Contract (4개)

  • construction/project/contract/[id]/page.tsx
  • construction/project/contract/[id]/edit/page.tsx
  • construction/project/contract/handover-report/[id]/page.tsx
  • construction/project/contract/handover-report/[id]/edit/page.tsx

Others (4개)

  • payment-history/page.tsx
  • subscription/page.tsx
  • dev/test-urls/page.tsx
  • dev/construction-test-urls/page.tsx

변환 패턴

Before (Server Component)

import { Component } from '@/components/...';
import { getData } from '@/components/.../actions';

export default async function Page() {
  const result = await getData();
  return <Component initialData={result.data} />;
}

After (Client Component)

'use client';

import { useEffect, useState } from 'react';
import { Component } from '@/components/...';
import { getData } from '@/components/.../actions';
import { DEFAULT_DATA } from '@/components/.../types';

export default function Page() {
  const [data, setData] = useState(DEFAULT_DATA);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    getData()
      .then(result => {
        if (result.success) {
          setData(result.data);
        }
      })
      .finally(() => setIsLoading(false));
  }, []);

  if (isLoading) {
    return <div>로딩 ...</div>;
  }

  return <Component initialData={data} />;
}

추가 작업

1. RULES.md 업데이트

  • Client Component 사용 원칙 추가
  • SEO 불필요 폐쇄형 사이트 명시

2. fetch-wrapper.ts 정리

  • skipTokenRefresh 옵션 제거 (불필요해짐)

3. actions.ts 정리

  • skipTokenRefresh 관련 코드 제거

진행 상태

  • 시작일: 2026-01-09
  • 현재 상태: 진행 중