Files
PM_test/PM관리자화면개발산출물_20260611/통합관리자대시보드_구현가이드.html
2026-06-19 17:58:47 +09:00

794 lines
34 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>통합 관리자 대시보드 구현 계획 및 테이블 명세 가이드</title>
<!-- Google Fonts - Inter & Noto Sans KR -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet">
<!-- Mermaid JS for Dynamic Diagrams -->
<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'forest',
themeVariables: {
primaryColor: '#1e5149',
primaryTextColor: '#fff',
lineColor: '#1e5149',
secondaryColor: '#142e29'
}
});
</script>
<style>
:root {
--primary: #1e5149;
--primary-dark: #142e29;
--primary-light: #e9eeed;
--primary-border: #d2dcdb;
--accent: #4db251;
--bg: #f4f7f6;
--card-bg: #ffffff;
--text-main: #1f2937;
--text-muted: #4b5563;
--code-bg: #1e293b;
--code-text: #f8fafc;
--shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05), 0 2px 4px -2px rgba(0, 0, 0, 0.05);
--sidebar-width: 280px;
}
* {
box-sizing: border-box;
}
body {
font-family: 'Inter', 'Noto Sans KR', sans-serif;
background-color: var(--bg);
color: var(--text-main);
line-height: 1.7;
margin: 0;
padding: 0;
display: flex;
}
/* Sidebar Navigation */
aside {
width: var(--sidebar-width);
background: linear-gradient(180deg, var(--primary-dark) 0%, #0c1a18 100%);
color: #ffffff;
height: 100vh;
position: fixed;
top: 0;
left: 0;
overflow-y: auto;
border-right: 1px solid rgba(255, 255, 255, 0.1);
padding: 24px;
z-index: 100;
}
aside h2 {
font-size: 1.15rem;
font-weight: 700;
margin-bottom: 24px;
color: var(--accent);
display: flex;
align-items: center;
gap: 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.15);
padding-bottom: 12px;
}
aside ul {
list-style: none;
padding: 0;
margin: 0;
}
aside li {
margin-bottom: 8px;
}
aside a {
color: #b3c5c2;
text-decoration: none;
font-size: 0.9rem;
display: block;
padding: 8px 12px;
border-radius: 6px;
transition: all 0.2s ease;
}
aside a:hover, aside li.active a {
color: #ffffff;
background-color: rgba(255, 255, 255, 0.08);
padding-left: 16px;
}
aside .category-title {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #628781;
margin: 16px 0 8px 12px;
font-weight: 700;
}
/* Main Content */
main {
margin-left: var(--sidebar-width);
flex-grow: 1;
padding: 40px 50px;
max-width: 1000px;
}
header {
border-bottom: 2px solid var(--primary-border);
padding-bottom: 24px;
margin-bottom: 40px;
}
header h1 {
font-size: 2.2rem;
font-weight: 700;
margin: 0 0 10px 0;
color: var(--primary);
}
header .subtitle {
font-size: 1.1rem;
color: var(--text-muted);
margin: 0;
}
/* Content Sections */
section {
background-color: var(--card-bg);
border-radius: 12px;
padding: 30px;
margin-bottom: 30px;
box-shadow: var(--shadow);
border: 1px solid var(--primary-border);
}
h2.section-title {
font-size: 1.4rem;
font-weight: 700;
color: var(--primary);
margin-top: 0;
margin-bottom: 20px;
border-left: 4px solid var(--accent);
padding-left: 12px;
}
h3 {
font-size: 1.15rem;
font-weight: 600;
color: var(--primary-dark);
margin-top: 24px;
margin-bottom: 12px;
}
p {
margin: 0 0 16px 0;
color: var(--text-main);
}
/* Callouts (GitHub alerts) */
.callout {
border-left: 4px solid;
padding: 16px;
margin-bottom: 20px;
border-radius: 0 8px 8px 0;
}
.callout-note {
background-color: #f0f7ff;
border-color: #0066cc;
color: #004080;
}
.callout-important {
background-color: #fff8f8;
border-color: #ef4444;
color: #991b1b;
}
.callout-title {
font-weight: 700;
margin-bottom: 6px;
display: flex;
align-items: center;
gap: 6px;
}
/* Tables */
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 0.9rem;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--primary-border);
}
th {
background-color: var(--primary);
color: #ffffff;
font-weight: 600;
text-align: left;
padding: 12px 16px;
}
td {
padding: 12px 16px;
border-bottom: 1px solid var(--primary-border);
color: var(--text-main);
vertical-align: top;
}
tr:last-child td {
border-bottom: none;
}
tr:nth-child(even) td {
background-color: #f9fafb;
}
/* Code Blocks */
pre {
background-color: var(--code-bg);
color: var(--code-text);
padding: 18px;
border-radius: 8px;
font-family: 'Consolas', 'Courier New', Courier, monospace;
font-size: 0.85rem;
overflow-x: auto;
margin: 16px 0;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
}
code {
font-family: 'Consolas', 'Courier New', Courier, monospace;
background-color: #f1f5f9;
color: #0f172a;
padding: 2px 6px;
border-radius: 4px;
font-size: 0.85rem;
}
pre code {
background-color: transparent;
color: inherit;
padding: 0;
border-radius: 0;
font-size: inherit;
}
.method-badge {
display: inline-block;
padding: 3px 8px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 700;
color: #ffffff;
margin-right: 6px;
}
.method-get { background-color: #0ea5e9; }
.method-post { background-color: #22c55e; }
.method-put { background-color: #f59e0b; }
.method-delete { background-color: #ef4444; }
.api-url {
font-weight: 600;
font-family: monospace;
}
/* List Styling */
ul {
padding-left: 20px;
margin-bottom: 16px;
}
li {
margin-bottom: 6px;
}
/* Diagram Container */
.diagram-container {
display: flex;
justify-content: center;
margin: 24px 0;
background-color: #ffffff;
padding: 20px;
border-radius: 8px;
border: 1px solid var(--primary-border);
}
</style>
</head>
<body>
<!-- Sidebar Navigation -->
<aside>
<h2>📁 PM_ver4 Admin Guide</h2>
<ul>
<li><a href="#overview">가이드 소개</a></li>
</ul>
<div class="category-title">01. 시스템 아키텍처</div>
<ul>
<li><a href="#architecture">전체 구조 & 로직</a></li>
<li><a href="#migration">단계별 구현 계획</a></li>
</ul>
<div class="category-title">02. 데이터 모델 (ERD)</div>
<ul>
<li><a href="#schema-design">스키마 구조 & 관계</a></li>
</ul>
<div class="category-title">03. 화면별 데이터 매핑</div>
<ul>
<li><a href="#screen-dashboard">1. 종합 용량 및 접속자</a></li>
<li><a href="#screen-project">2. 프로젝트 관리</a></li>
<li><a href="#screen-banner">3. 실시간 배너 공지</a></li>
<li><a href="#screen-user">4. 사용자 관리</a></li>
<li><a href="#screen-audit">5. 감사 로그 조회</a></li>
<li><a href="#screen-policy">6. 자동 삭제 정책 설정</a></li>
<li><a href="#screen-codes">7. 공통 코드 관리</a></li>
</ul>
<div class="category-title">04. 백엔드 API 설계</div>
<ul>
<li><a href="#api-endpoints">핵심 CRUD API 목록</a></li>
</ul>
</aside>
<!-- Main Content -->
<main>
<header id="overview">
<h1>통합 관리자 대시보드 구현 계획 및 테이블 명세 가이드</h1>
<p class="subtitle">관리자 화면(Admin Panel) 마이그레이션 및 데이터베이스 연동 설계서</p>
</header>
<!-- Section 1 -->
<section id="architecture">
<h2 class="section-title">1. 전체 시스템 아키텍처 및 구현 계획</h2>
<p>본 설계서는 <code>관리자화면_통합대시보드_UI제안.html</code> 정적 파일의 사용자 동작 시뮬레이션을 프로덕션 급 서버 인프라에 안착하기 위한 설계 명세입니다. 시스템 환경은 Node.js / PostgreSQL / MinIO S3 및 Redis Queue 아키텍처를 준수합니다.</p>
<div class="diagram-container">
<div class="mermaid">
graph TD
Client[Browser Admin Page] -->|REST API Requests| Backend[Express.js Web Server]
Client -->|WebSocket Event Channel| SocketServer[Socket.io Server]
Backend -->|SQL Query / PG client| DB[(PostgreSQL Database)]
Backend -->|Enqueue / Monitor| Redis[(Redis / BullMQ Queue)]
SocketServer -->|Active Session Cache| Memory[Node.js Process Memory]
</div>
</div>
<div class="callout callout-note">
<div class="callout-title"> 백엔드 연동 방식</div>
<div class="callout-content">
본 시스템은 관리 업무의 연속성 확보 및 동시성 처리를 위해 REST API 채널 외에도 Socket.io 서버 채널을 동시에 가용하여 실시간 웹소켓 통신을 처리하도록 구성됩니다.
</div>
</div>
</section>
<!-- Section 2 -->
<section id="migration">
<h2 class="section-title">구현 단계별 개발 로드맵</h2>
<h3>[1단계] 데이터베이스 스키마 확장 및 마이그레이션</h3>
<ul>
<li>공통 코드 분류 및 세부 값 제어를 위한 <code>code_master</code><code>code_detail</code> 테이블 신설.</li>
<li><strong>기존 테이블 활용 (컬럼 추가 없음)</strong>: 기존에 존재하는 프로젝트 테이블(<code>tb_project</code>)의 <code>category</code> 컬럼과 사용자 테이블(<code>tb_user</code>)의 <code>"group"</code> 컬럼을 <code>code_detail.base_code</code> 외래키 참조 구조로 그대로 연동하여 불필요한 테이블 팽창 및 컬럼 추가를 차단합니다.</li>
<li>시스템 공통 자동 보존 및 삭제 임계치를 독립적으로 제어하기 위한 <strong><code>tb_system_policy</code> (시스템 공통 정책 테이블)</strong> 신설.</li>
<li>실시간 배너 공지 이력 보관을 위한 <code>tb_banner_notice</code> 및 정기 자동삭제 실행 결과를 기록하기 위한 <code>tb_auto_clean_log</code> 신설.</li>
</ul>
<h3>[2단계] 백엔드 RESTful API 및 WebSocket 핸들러 개발</h3>
<ul>
<li><strong>REST API</strong>: 각 기능 및 공통 코드 데이터의 CRUD API Endpoint 구축 (Express Controller 연동).</li>
<li><strong>WebSocket</strong>: <code>socket.js</code>에 접속한 클라이언트 세션을 <code>users</code> 메모리 맵에 보관 및 관리자가 강제퇴장(<code>forcedLogout</code>) 이벤트를 호출하면 해당 클라이언트 소켓의 접속을 끊고 세션을 제거하도록 구현.</li>
</ul>
<h3>[3단계] 프론트엔드 어드민 대시보드 UI 연동</h3>
<ul>
<li>프로토타입 디자인 컨셉(Pretendard 서체, Forest Green 테마 색상)을 CSS 변수로 그대로 반영.</li>
<li>모달 다이얼로그와 탭 렌더링에 실시간 API 데이터 통신 로직 바인딩.</li>
</ul>
</section>
<!-- Section 3 -->
<section id="schema-design">
<h2 class="section-title">2. 데이터베이스 스키마 설계 (ERD)</h2>
<p>기존에 이미 보유한 <code>tb_project.category</code><code>tb_user."group"</code> 구조를 활용한 관계 정의는 다음과 같습니다.</p>
<div class="diagram-container">
<div class="mermaid">
classDiagram
class code_master {
+main_code : VARCHAR(30) PK
+main_code_nm : VARCHAR(100)
+use_yn : CHAR(1)
+rmk : VARCHAR(255)
}
class code_detail {
+main_code : VARCHAR(30) PK/FK
+sub_code : VARCHAR(30) PK
+base_code : VARCHAR(61) UNIQUE
+code_nm : VARCHAR(100)
+sort_ord : INT
+use_yn : CHAR(1)
+rmk : VARCHAR(255)
}
class tb_project {
+project_id : VARCHAR(50) PK
+project_nm : VARCHAR(100)
+category : VARCHAR(50) FK
+limit_storage : INT
+is_active : BOOLEAN
}
class tb_system_policy {
+policy_id : INT PK
+policy_key : VARCHAR(50) UNIQUE
+limit_file_count : INT
+limit_days : INT
+is_active : BOOLEAN
+upd_date : TIMESTAMP
}
class tb_user {
+user_id : VARCHAR(50) PK
+user_nm : VARCHAR(50)
+user_pw : VARCHAR(255)
+company : VARCHAR(50)
+dept : VARCHAR(50)
+position : VARCHAR(50)
+group : VARCHAR(50) FK
+is_resigned : BOOLEAN
}
class tb_permission {
+project_id : VARCHAR(50) PK/FK
+user_id : VARCHAR(50) PK/FK
+lev : INT
}
class tb_banner_notice {
+banner_id : SERIAL PK
+project_id : VARCHAR(50) FK
+reg_date : DATE
+start_date : DATE
+end_date : DATE
+notice_text : TEXT
+status_code : VARCHAR(61) FK
}
class tb_log {
+log_id : SERIAL PK
+project_id : VARCHAR(50)
+activity : VARCHAR(100)
+user_id : VARCHAR(50)
+user_ip : VARCHAR(50)
+log_date : TIMESTAMP
+path_arr : TEXT[]
}
code_master "1" --> "0..*" code_detail
code_detail "1" --> "0..*" tb_project : "category 참조"
code_detail "1" --> "0..*" tb_user : "group 참조"
code_detail "1" --> "0..*" tb_banner_notice : "status_code 참조"
tb_project "1" --> "0..*" tb_permission
tb_user "1" --> "0..*" tb_permission
tb_project "1" --> "0..*" tb_banner_notice
</div>
</div>
</section>
<!-- Section 4 -->
<section id="screen-dashboard">
<h2 class="section-title">3. 화면별 연동 테이블 및 데이터베이스 상세 매핑</h2>
<h3>📊 화면 1: 종합 용량 및 접속자 현황 (Dashboard)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>전체 사용 용량 KPI & 현장별 게이지바</strong>:
<code>tb_project</code> 테이블의 한도 용량(<code>storage_byte</code>)과 <code>tb_data</code> 테이블의 실 누적 용량(<code>data_size</code>) 합산 결과 및 파일 건수를 <code>COUNT()</code>하여 렌더링.
</li>
<li><strong>실시간 접속자 세션 목록</strong>:
데이터베이스를 경유하지 않고 Node.js 메인 프로세스(<code>socket.js</code>)의 메모리 세션 해시맵에서 직접 연결 상태(ID, IP, 위치 경로)를 추출.
</li>
<li><strong>대기 중인 압축작업</strong>:
Redis(BullMQ Queue) 대기열 API를 조회하여 보류 중인 백그라운드 압축 다운로드 개수 파악.
</li>
</ul>
</section>
<section id="screen-project">
<h3>🏗️ 화면 2: 프로젝트 관리 (Project Management)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>좌측 프로젝트 그리드</strong>: <code>tb_project</code> 테이블 전체 데이터와 <code>code_detail</code>의 카테고리 코드 한글 명칭(TDC, GPD 등)을 <code>tb_project.category</code> 외래키 관계를 조인하여 렌더링.</li>
<li><strong>우측 참여 권한 사용자 목록</strong>: <code>tb_permission</code> $\bowtie$ <code>tb_user</code> 조인을 통해 해당 현장에 기속된 사용자 리스트업 및 등급 인라인 셀렉트 업데이트.</li>
<li><strong>사용자 배정 추가 모달</strong>: <code>tb_user</code>의 전체 사용자 데이터와 현재 프로젝트에 속해 있지 않은 유저 차집합 연산으로 가용 유저 목록 구성.</li>
</ul>
</section>
<section id="screen-banner">
<h3>📢 화면 3: 실시간 배너 공지 (Banner Notice)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>공지사항 이력 및 등록 폼</strong>: <code>tb_banner_notice</code> 테이블 CRUD 매핑.</li>
<li><strong>송출 상태 계산</strong>:
오늘 날짜 기준 <code>start_date</code><code>end_date</code> 조건을 체크하여 공통코드 매핑 상태(<code>NOTICE_STATUS_active</code>, <code>NOTICE_STATUS_scheduled</code>, <code>NOTICE_STATUS_expired</code>)를 동적 할당.
</li>
<li><strong>검색 필터</strong>: 송출상태 및 등록일 범위(From ~ To) 기준 <code>WHERE status_code = ? AND reg_date BETWEEN ? AND ?</code> 쿼리 연동.</li>
</ul>
</section>
<section id="screen-user">
<h3>👥 화면 4: 사용자 관리 (User Management)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>좌측 계정 목록</strong>: <code>tb_user</code> 테이블 및 <code>code_detail</code> 권한그룹(기존 <code>"group"</code> 컬럼 재사용) 매핑 렌더링.</li>
<li><strong>우측 참여 프로젝트 목록</strong>: <code>tb_permission</code> $\bowtie$ <code>tb_project</code> 조인을 활용하여 선택 유저가 소속된 모든 프로젝트 ID 및 현장명 출력.</li>
</ul>
</section>
<section id="screen-audit">
<h3>🔎 화면 5: 감사 로그 조회 (Audit Logs)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>시스템 감사 이력 목록</strong>:
파일 삭제/이동/다운로드 이벤트를 적재하는 <code>tb_log</code> 테이블을 필터 검색 쿼리(사용자 ID, 액션타입)와 연동하여 리스트 렌더링.
</li>
</ul>
</section>
<section id="screen-policy">
<h3>⚙️ 화면 6: 자동 보존 및 파일 삭제 정책 설정 (Delete Policy)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>시스템 공통 자동 삭제 정책 설정 폼</strong>:
프로젝트 단위 설정을 탈피하고, 신설된 <code>tb_system_policy</code>의 단일 글로벌 레코드를 제어.
</li>
<li><strong>자동 삭제 정기 실행 이력</strong>:
정기 스케줄러 배치 구동 시의 로그 기록을 <code>tb_auto_clean_log</code>에서 리스트업. 설정값 저장 및 기록 적재 시 프로젝트 ID 대신 <code>'SYSTEM'</code> 기록 식별자를 사용.
</li>
</ul>
</section>
<section id="screen-codes">
<h3>🔑 화면 7: 공통 코드 관리 (Common Code Management)</h3>
<p><strong>주요 데이터 흐름 및 활용 테이블:</strong></p>
<ul>
<li><strong>상단 마스터 대분류</strong>: <code>code_master</code> 테이블 CRUD.</li>
<li><strong>하단 상세 소분류</strong>: <code>code_detail</code> 테이블 CRUD.
<ul>
<li>대분류 선택이 없을 시 소분류 등록 폼 진입 차단 유효성 제어.</li>
<li>소분류의 <code>base_code</code> 컬럼은 <code>main_code || '_' || sub_code</code> 조합으로 자동 동기화.</li>
<li>대분류 삭제 시 외래키 <code>ON DELETE CASCADE</code> 명세를 통하여 소분류 레코드가 데이터베이스에서 연쇄적으로 자동 청소되도록 설정.</li>
</ul>
</li>
</ul>
</section>
<!-- Section 5 -->
<section id="api-endpoints">
<h2 class="section-title">4. 핵심 백엔드 CRUD API Endpoint 설계안</h2>
<p>프론트엔드-백엔드 간 통신을 위해 구성되어야 할 RESTful API 리스트입니다.</p>
<h3>1. 프로젝트 관리 API (<code>/api/admin/projects</code>)</h3>
<table>
<thead>
<tr>
<th style="width: 15%;">메소드</th>
<th style="width: 35%;">엔드포인트</th>
<th style="width: 50%;">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/</td>
<td>전체 프로젝트 및 카테고리 정보 조회</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/</td>
<td>신규 프로젝트 등록</td>
</tr>
<tr>
<td><span class="method-badge method-put">PUT</span></td>
<td class="api-url">/:id</td>
<td>특정 프로젝트 내용(카테고리 category 값, 용량제한, 활성화) 갱신</td>
</tr>
<tr>
<td><span class="method-badge method-delete">DELETE</span></td>
<td class="api-url">/:id</td>
<td>프로젝트 영구 삭제 (참여 권한 및 메타데이터 자동 CASCADE)</td>
</tr>
</tbody>
</table>
<h3>2. 프로젝트 권한 배정 API (<code>/api/admin/permissions</code>)</h3>
<table>
<thead>
<tr>
<th style="width: 15%;">메소드</th>
<th style="width: 35%;">엔드포인트</th>
<th style="width: 50%;">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/project/:projectId</td>
<td>특정 현장에 참여 중인 유저 목록 조회</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/assign</td>
<td>현장에 특정 사용자 권한 신규 부여 (다중 배정)</td>
</tr>
<tr>
<td><span class="method-badge method-put">PUT</span></td>
<td class="api-url">/update</td>
<td>배정 유저의 권한 등급(lev) 수정</td>
</tr>
<tr>
<td><span class="method-badge method-delete">DELETE</span></td>
<td class="api-url">/remove</td>
<td>현장 참여 권한 배정 제외 (매핑 행 삭제)</td>
</tr>
</tbody>
</table>
<h3>3. 실시간 배너 공지 API (<code>/api/admin/banners</code>)</h3>
<table>
<thead>
<tr>
<th style="width: 15%;">메소드</th>
<th style="width: 35%;">엔드포인트</th>
<th style="width: 50%;">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/</td>
<td>배너 송출 이력 조회 (상태, 날짜검색 필터 지원)</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/</td>
<td>신규 배너 공지 작성 및 등록</td>
</tr>
<tr>
<td><span class="method-badge method-put">PUT</span></td>
<td class="api-url">/stop/:id</td>
<td>공지 수동 송출 중지 (상태를 expired로 강제 업데이트)</td>
</tr>
</tbody>
</table>
<h3>4. 사용자 관리 API (<code>/api/admin/users</code>)</h3>
<table>
<thead>
<tr>
<th style="width: 15%;">메소드</th>
<th style="width: 35%;">엔드포인트</th>
<th style="width: 50%;">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/</td>
<td>전체 계정 정보 및 권한그룹 조회</td>
</tr>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/:id/permissions</td>
<td>해당 유저가 참여 권한을 지닌 프로젝트 목록 조회</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/</td>
<td>신규 사용자 계정 등록 (패스워드 bcrypt 암호화)</td>
</tr>
<tr>
<td><span class="method-badge method-put">PUT</span></td>
<td class="api-url">/:id</td>
<td>사용자 정보(권한 그룹 group 포함) 및 재직 상태 갱신</td>
</tr>
<tr>
<td><span class="method-badge method-delete">DELETE</span></td>
<td class="api-url">/:id</td>
<td>사용자 계정 삭제 (권한 정보 및 설정 연쇄 삭제)</td>
</tr>
</tbody>
</table>
<h3>5. 공통 코드 관리 API (<code>/api/admin/common-codes</code>)</h3>
<table>
<thead>
<tr>
<th style="width: 15%;">메소드</th>
<th style="width: 35%;">엔드포인트</th>
<th style="width: 50%;">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/masters</td>
<td>대분류 마스터 코드 목록 조회</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/masters</td>
<td>신규 대분류 등록</td>
</tr>
<tr>
<td><span class="method-badge method-put">PUT</span></td>
<td class="api-url">/masters/:code</td>
<td>대분류 수정</td>
</tr>
<tr>
<td><span class="method-badge method-delete">DELETE</span></td>
<td class="api-url">/masters/:code</td>
<td>대분류 삭제 (하위 소분류 자동 연쇄 삭제)</td>
</tr>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/details/:mainCode</td>
<td>선택된 대분류에 해당하는 소분류 정렬 조회</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/details</td>
<td>신규 소분류 등록 (base_code 자동 연산 생성)</td>
</tr>
<tr>
<td><span class="method-badge method-put">PUT</span></td>
<td class="api-url">/details/:mainCode/:subCode</td>
<td>소분류 수정 (명칭, 정렬순서, 사용여부)</td>
</tr>
<tr>
<td><span class="method-badge method-delete">DELETE</span></td>
<td class="api-url">/details/:mainCode/:subCode</td>
<td>소분류 삭제</td>
</tr>
</tbody>
</table>
<h3>6. 시스템 공통 보존 정책 API (<code>/api/admin/system-policy</code>)</h3>
<table>
<thead>
<tr>
<th style="width: 15%;">메소드</th>
<th style="width: 35%;">엔드포인트</th>
<th style="width: 50%;">설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="method-badge method-get">GET</span></td>
<td class="api-url">/</td>
<td>시스템 글로벌 보존 정책 조회</td>
</tr>
<tr>
<td><span class="method-badge method-post">POST</span></td>
<td class="api-url">/update</td>
<td>글로벌 보존 정책 값 갱신 및 저장</td>
</tr>
</tbody>
</table>
</section>
</main>
</body>
</html>