ITN Dev 07-23
feat: 프런트엔드에서 합성 기관코드를 반영하고 policy 특례를 제거
기관 코드가 6자(008_02 등)로 늘어난 데 맞춰 OrgList의 코드 칸 폭을 넓히고,
OrgOverview의 Mattermost 채널 링크 생성에 남아 있던 치안정책연구소 -policy-
특례를 제거했다(연번 자체가 하위기관까지 구분하므로 더 이상 필요 없음).
@5c7c71b0b916bfe1ba084257ba28f9102df14de2
frontend/src/components/OrgList.test.tsx
--- frontend/src/components/OrgList.test.tsx
+++ frontend/src/components/OrgList.test.tsx
@@ -5,12 +5,12 @@
 
 const orgs: Org[] = [
   {
-    id: 1, orgNo: '001', orgName: '국제방송교류재단', status: 'ACTIVE',
+    id: 1, orgNo: '001_00', orgName: '국제방송교류재단', status: 'ACTIVE',
     applicant: null, mj: null, lawyer: null, lawyerAssignedDate: null,
     channelIdMj: 'a', channelIdLaw: 'b',
   },
   {
-    id: 2, orgNo: '008', orgName: '경찰청_치안정책연구소', status: 'INFO_PENDING',
+    id: 2, orgNo: '008_01', orgName: '경찰청_치안정책연구소', status: 'INFO_PENDING',
     applicant: null, mj: null, lawyer: null, lawyerAssignedDate: null,
     channelIdMj: null, channelIdLaw: null,
   },
@@ -20,7 +20,7 @@
   it('연번과 기관명을 보여준다', () => {
     render(<OrgList orgs={orgs} selectedId={null} onSelect={() => {}} />)
 
-    expect(screen.getByText('001')).toBeTruthy()
+    expect(screen.getByText('001_00')).toBeTruthy()
     expect(screen.getByText('국제방송교류재단')).toBeTruthy()
     expect(screen.getByText('경찰청_치안정책연구소')).toBeTruthy()
   })
@@ -50,19 +50,19 @@
       <OrgList orgs={orgs} selectedId={null} onSelect={() => {}} collapsed onToggle={() => {}} />,
     )
 
-    expect(screen.getByText('001')).toBeTruthy()
+    expect(screen.getByText('001_00')).toBeTruthy()
     expect(screen.queryByText('국제방송교류재단')).toBeNull()
     expect(screen.queryByPlaceholderText('기관명 검색')).toBeNull()
 
-    const item = screen.getByRole('button', { name: '001 국제방송교류재단' })
-    expect(item).toHaveAttribute('title', '001 국제방송교류재단 (운영 중)')
+    const item = screen.getByRole('button', { name: '001_00 국제방송교류재단' })
+    expect(item).toHaveAttribute('title', '001_00 국제방송교류재단 (운영 중)')
   })
 
   it('접힌 상태에서도 기관을 선택할 수 있다', () => {
     const onSelect = vi.fn()
     render(<OrgList orgs={orgs} selectedId={null} onSelect={onSelect} collapsed />)
 
-    fireEvent.click(screen.getByRole('button', { name: '001 국제방송교류재단' }))
+    fireEvent.click(screen.getByRole('button', { name: '001_00 국제방송교류재단' }))
 
     expect(onSelect).toHaveBeenCalledWith(1)
   })
frontend/src/components/OrgList.tsx
--- frontend/src/components/OrgList.tsx
+++ frontend/src/components/OrgList.tsx
@@ -59,7 +59,9 @@
                   selectedId === org.id ? 'bg-blue-50' : ''
                 }`}
               >
-                <span className="text-[11px] font-medium text-gray-600">{org.orgNo}</span>
+                <span className="w-14 text-center text-[11px] font-medium text-gray-600">
+                  {org.orgNo}
+                </span>
                 <span className={`h-1.5 w-1.5 rounded-full ${STATUS_DOT[org.status]}`} />
               </button>
             </li>
@@ -102,7 +104,7 @@
                 selectedId === org.id ? 'bg-blue-50' : ''
               }`}
             >
-              <span className="w-9 shrink-0 text-xs text-gray-500">{org.orgNo}</span>
+              <span className="w-14 shrink-0 text-xs text-gray-500">{org.orgNo}</span>
               <span className="flex-1 truncate text-sm">{org.orgName}</span>
               <StatusBadge status={org.status} />
             </button>
frontend/src/components/OrgOverview.test.tsx
--- frontend/src/components/OrgOverview.test.tsx
+++ frontend/src/components/OrgOverview.test.tsx
@@ -33,7 +33,7 @@
 function org(overrides: Partial<Org> = {}): Org {
   return {
     id: 1,
-    orgNo: '001',
+    orgNo: '001_00',
     orgName: '국제방송교류재단',
     status: 'ACTIVE',
     applicant: contact({
@@ -65,7 +65,7 @@
   it('연번_기관명 헤더와 신청기관 담당자 정보를 보여준다', async () => {
     render(<OrgOverview org={org()} />)
 
-    expect(screen.getByText('001_국제방송교류재단')).toBeTruthy()
+    expect(screen.getByText('001_00_국제방송교류재단')).toBeTruthy()
     expect(screen.getByText('데이터정보화팀')).toBeTruthy()
     expect(screen.getByText('송민지 과장')).toBeTruthy()
     expect(screen.getByText('02-3475-5434')).toBeTruthy()
@@ -170,7 +170,7 @@
     const link = screen.getByRole('link', { name: 'Mattermost 열기' })
     expect(link).toHaveAttribute(
       'href',
-      'https://hub.iten.co.kr/itn-hub/channels/org-001-mj',
+      'https://hub.iten.co.kr/itn-hub/channels/org-001-00-mj',
     )
     await waitFor(() => expect(mocks.getPosts).toHaveBeenCalled())
   })
@@ -182,16 +182,16 @@
     expect(screen.getByRole('button', { name: 'Mattermost 열기' })).toBeDisabled()
   })
 
-  it('치안정책연구소는 policy 채널 링크를 쓴다', async () => {
+  it('치안정책연구소도 합성코드 슬러그로 채널 링크를 만든다', async () => {
     render(
       <OrgOverview
-        org={org({ orgNo: '008', orgName: '경찰청_치안정책연구소', channelIdMj: 'x' })}
+        org={org({ orgNo: '008_01', orgName: '경찰청_치안정책연구소', channelIdMj: 'x' })}
       />,
     )
 
     expect(screen.getByRole('link', { name: 'Mattermost 열기' })).toHaveAttribute(
       'href',
-      'https://hub.iten.co.kr/itn-hub/channels/org-008-policy-mj',
+      'https://hub.iten.co.kr/itn-hub/channels/org-008-01-mj',
     )
     await waitFor(() => expect(mocks.getPosts).toHaveBeenCalled())
   })
frontend/src/components/OrgOverview.tsx
--- frontend/src/components/OrgOverview.tsx
+++ frontend/src/components/OrgOverview.tsx
@@ -31,14 +31,12 @@
 
 // Mattermost 웹 주소. 채널 화면은 팀명 + 채널 내부명으로 열린다.
 // 내부명 규칙은 백엔드 ChannelNaming.java가 정본이며 여기서는 열람 링크용으로만 복제한다.
+// 기관 코드({연번1}_{연번2})가 하위기관까지 구분하므로 기관명에 따른 별도 특례는 없다.
 const MATTERMOST_BASE = 'https://hub.iten.co.kr/itn-hub/channels/'
-const SPECIAL_ORG_NAME = '경찰청_치안정책연구소'
 
 function mattermostChannelUrl(org: Org): string {
   const slug = org.orgNo.trim().toLowerCase().replace(/_/g, '-').replace(/ /g, '-')
-  const name =
-    org.orgName.trim() === SPECIAL_ORG_NAME ? `org-${slug}-policy-mj` : `org-${slug}-mj`
-  return MATTERMOST_BASE + name
+  return MATTERMOST_BASE + `org-${slug}-mj`
 }
 
 function Field({ label, value }: { label: string; value: string | null }) {
Add a comment
List