From 34f0015cff6c11f05823d7ce42b1d398a354278e Mon Sep 17 00:00:00 2001 From: HYOJIN Date: Fri, 10 Apr 2026 11:03:55 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat(ui):=20=EC=84=9C=EB=B9=84=EC=8A=A4=20A?= =?UTF-8?q?PI=20=EB=B6=84=EB=A5=98=20+=20API=20Key=20=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?UI=20=EC=A0=84=EB=A9=B4=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 서비스 API: - snp_service_api에 apiDomain/apiSection 컬럼 추가 - API 신청 시 서비스 > 도메인 계층형 아코디언+테이블 선택 - 검토 모달 API 권한 편집 가능 (체크박스 토글, API 추가 모달) API Key 관리: - KPI 카드 4개 (대기/활성/만료임박/폐기) - 필터 칩 (상태별) + 검색 + 15건 페이징 - 신청 관리: 사용자 아이콘, 필드 라벨 한글화, 목적 제거 - 키 관리: 소유자(userName) 필드 추가, 필드 순서 변경, maskedKey/생성일 제거 - 검토 모달: 탭(신청정보/API권한), EditableDateCard, 승인확인 변경테이블 - 상세 모달: 검토 모달 readOnly 재사용, 상태별 아이콘 헤더 - 키 상세: 상태별 색상, InfoRow, API Key 보기/숨기기+복사 Closes #31 Co-Authored-By: Claude Opus 4.6 (1M context) --- docs/schema/create_tables.sql | 2 + frontend/src/pages/admin/ServicesPage.tsx | 28 + frontend/src/pages/apikeys/KeyAdminPage.tsx | 1681 +++++++++++++---- frontend/src/pages/apikeys/KeyRequestPage.tsx | 354 +++- frontend/src/types/apikey.ts | 1 + frontend/src/types/service.ts | 4 + .../connection/apikey/dto/ApiKeyResponse.java | 3 + .../monitoring/entity/SnpApiRequestLog.java | 10 +- .../service/dto/CreateServiceApiRequest.java | 2 + .../service/dto/ServiceApiResponse.java | 4 + .../service/entity/SnpServiceApi.java | 15 +- .../service/ServiceManagementService.java | 2 + 12 files changed, 1672 insertions(+), 434 deletions(-) diff --git a/docs/schema/create_tables.sql b/docs/schema/create_tables.sql index df0af70..ae5d74a 100644 --- a/docs/schema/create_tables.sql +++ b/docs/schema/create_tables.sql @@ -91,6 +91,8 @@ CREATE TABLE IF NOT EXISTS snp_service_api ( api_path VARCHAR(500) NOT NULL, api_method VARCHAR(10) NOT NULL, api_name VARCHAR(200) NOT NULL, + api_domain VARCHAR(100), + api_section VARCHAR(100), description TEXT, is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP NOT NULL DEFAULT NOW(), diff --git a/frontend/src/pages/admin/ServicesPage.tsx b/frontend/src/pages/admin/ServicesPage.tsx index 2f2f1bd..d1a21bc 100644 --- a/frontend/src/pages/admin/ServicesPage.tsx +++ b/frontend/src/pages/admin/ServicesPage.tsx @@ -61,6 +61,8 @@ const ServicesPage = () => { const [apiMethod, setApiMethod] = useState('GET'); const [apiPath, setApiPath] = useState(''); const [apiName, setApiName] = useState(''); + const [apiDomain, setApiDomain] = useState(''); + const [apiSection, setApiSection] = useState(''); const [apiDescription, setApiDescription] = useState(''); const fetchServices = async () => { @@ -174,6 +176,8 @@ const ServicesPage = () => { setApiMethod('GET'); setApiPath(''); setApiName(''); + setApiDomain(''); + setApiSection(''); setApiDescription(''); setIsApiModalOpen(true); }; @@ -193,6 +197,8 @@ const ServicesPage = () => { apiMethod, apiPath, apiName, + apiDomain: apiDomain || undefined, + apiSection: apiSection || undefined, description: apiDescription || undefined, }; const res = await createServiceApi(selectedService.serviceId, req); @@ -537,6 +543,28 @@ const ServicesPage = () => { className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none" /> +
+
+ + setApiDomain(e.target.value)} + placeholder="예: Compliance" + className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none" + /> +
+
+ + setApiSection(e.target.value)} + placeholder="예: 선박 규정" + className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 focus:ring-2 focus:ring-blue-500 focus:outline-none" + /> +
+