초기 PM 소스 전체 업로드
This commit is contained in:
424
워크플로우_데이터흐름도.html
Normal file
424
워크플로우_데이터흐름도.html
Normal file
@@ -0,0 +1,424 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PM 프로젝트 워크플로우 및 데이터 흐름도</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;600;700&family=Noto+Sans+KR:wght@300;400;500;700&display=swap"
|
||||
rel="stylesheet">
|
||||
|
||||
<!-- Mermaid.js 라이브러리 (CDN) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: 'default',
|
||||
securityLevel: 'loose',
|
||||
themeVariables: {
|
||||
fontFamily: 'Inter, Noto Sans KR, sans-serif',
|
||||
primaryColor: '#f43f5e',
|
||||
primaryTextColor: '#fff',
|
||||
lineColor: '#cbd5e1'
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary: #f43f5e;
|
||||
--primary-dark: #be123c;
|
||||
--primary-light: #fff1f2;
|
||||
--bg: #f8fafc;
|
||||
--card-bg: #ffffff;
|
||||
--text-main: #0f172a;
|
||||
--text-muted: #475569;
|
||||
--border: #e2e8f0;
|
||||
--shadow: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.05);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.05), 0 4px 6px -4px rgb(0 0 0 / 0.05);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 40px auto;
|
||||
padding: 40px;
|
||||
background-color: var(--card-bg);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--shadow-lg);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
/* Header Styling */
|
||||
header {
|
||||
border-bottom: 2px solid var(--border);
|
||||
padding-bottom: 24px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2.2rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 8px 0;
|
||||
background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 1.1rem;
|
||||
color: var(--text-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
color: #1e293b;
|
||||
border-left: 5px solid var(--primary);
|
||||
padding-left: 12px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.2rem;
|
||||
color: #334155;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p,
|
||||
li {
|
||||
color: var(--text-muted);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Card / Diagram Area Style */
|
||||
.diagram-card {
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin: 20px 0 35px 0;
|
||||
box-shadow: var(--shadow);
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.mermaid {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* Highlight text */
|
||||
code {
|
||||
font-family: monospace;
|
||||
background-color: #f1f5f9;
|
||||
color: #e11d48;
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
background-color: var(--primary-light);
|
||||
color: var(--primary-dark);
|
||||
padding: 4px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1>PM 프로젝트 워크플로우 및 데이터 흐름도</h1>
|
||||
<p class="subtitle">로컬 개발 인프라 및 핵심 기능(업로드/압축)에 대한 시각화 명세서</p>
|
||||
</header>
|
||||
|
||||
<p>본 문서는 <code>PM_ver4</code> 프로젝트의 시스템 아키텍처, 기능별 워크플로우 및 엔티티 간 데이터 흐름을 시각적으로 구현하여 이해를 돕기 위한 HTML 문서입니다.</p>
|
||||
|
||||
<!-- 1. 전체 아키텍처 -->
|
||||
<h2>1. 전체 시스템 아키텍처 및 데이터 흐름도</h2>
|
||||
<p>사용자 브라우저에서 출발하여 웹 서버(Express), PostgreSQL, Redis 및 로컬 MinIO(S3) 스토리지까지 연결되는 데이터 흐름도입니다.</p>
|
||||
|
||||
<div class="diagram-card">
|
||||
<div class="mermaid">
|
||||
graph LR
|
||||
%% 1. 사용자 영역 (가장 좌측 배치)
|
||||
subgraph Client [사용자 브라우저]
|
||||
UI["HTML CSS JS views"]
|
||||
SocketClient["Socket.io Client"]
|
||||
end
|
||||
|
||||
%% 2. 백엔드 웹서버 영역 (중앙 배치)
|
||||
subgraph WebServer [백엔드 서버 Port 6565]
|
||||
Express["Express App"]
|
||||
Router["Router / Controller"]
|
||||
AuthMid["SSO / Login Bypass"]
|
||||
SocketServer["Socket.io Server"]
|
||||
BullQueue["BullMQ Producer"]
|
||||
S3SDK["aws-sdk s3 - MinIO 연동"]
|
||||
PGDriver["pg - PostgreSQL 연동"]
|
||||
end
|
||||
|
||||
%% 3. 백그라운드 워커 영역 (중앙 하단 배치)
|
||||
subgraph BackgroundWorker [비동기 워커 프로세스]
|
||||
Worker["BullMQ Worker - 압축 수행"]
|
||||
ExternalCLI["programs - pdf_thumb / encryp"]
|
||||
end
|
||||
|
||||
%% 4. 인프라 영역 (가장 우측 배치)
|
||||
subgraph Infrastructure [Docker 가상 환경]
|
||||
PostgresDB["PostgreSQL DB"]
|
||||
RedisDB["Redis Broker"]
|
||||
MinIOStorage["MinIO S3"]
|
||||
end
|
||||
|
||||
%% 좌측 (Client) -> 중앙 (WebServer) 흐름
|
||||
UI -->|HTTP Request| Express
|
||||
Express --> UI
|
||||
SocketClient ---|Socket Event| SocketServer
|
||||
|
||||
%% 웹서버 내부 로직 흐름
|
||||
Express --> AuthMid
|
||||
AuthMid --> Router
|
||||
|
||||
%% 중앙 (WebServer) -> 우측 (Infrastructure) 데이터 흐름
|
||||
Router -->|Query| PGDriver
|
||||
PGDriver --> PostgresDB
|
||||
|
||||
Router -->|Push Job| BullQueue
|
||||
BullQueue --> RedisDB
|
||||
|
||||
Router -->|Generate URL| S3SDK
|
||||
S3SDK --> MinIOStorage
|
||||
|
||||
%% 좌측 (Client) -> 우측 (Infrastructure) 다이렉트 업로드 흐름
|
||||
UI -->|Direct Upload| MinIOStorage
|
||||
|
||||
%% 워커 동작 흐름 (중앙 하단 -> 우측 및 외부)
|
||||
Worker -->|Pop Job| RedisDB
|
||||
Worker -->|Execute CLI| ExternalCLI
|
||||
Worker -->|Read Write Files| MinIOStorage
|
||||
Worker -->|Update Status| PGDriver
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 2. 주요 기능별 핵심 워크플로우 -->
|
||||
<h2>2. 주요 기능별 핵심 워크플로우</h2>
|
||||
|
||||
<h3>2.1 파일 업로드 워크플로우 <span class="badge">Presigned URL 방식</span></h3>
|
||||
<p>서버 리소스를 보존하기 위해 브라우저에서 스토리지(MinIO)로 파일을 직접 올릴 수 있게 구현된 프로세스입니다.</p>
|
||||
|
||||
<div class="diagram-card">
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User as 사용자 (브라우저)
|
||||
participant Server as 백엔드 서버 (Node.js)
|
||||
participant MinIO as 로컬 MinIO 스토리지
|
||||
participant DB as 데이터베이스 (PostgreSQL)
|
||||
|
||||
User->>Server: 1. 업로드 링크 요청 (POST /:projectId/archive/generateUploadUrl)
|
||||
Note over Server: Bucket명 변환 미들웨어 작동<br>(PM_TEST_01 -> pm-test-01)
|
||||
Server->>MinIO: 2. S3 SDK를 통한 Presigned PUT URL 요청
|
||||
MinIO-->>Server: 3. 제한 시간 설정된 Presigned URL 반환
|
||||
Server-->>User: 4. Presigned URL 전달
|
||||
|
||||
User->>MinIO: 5. 해당 Presigned URL로 직접 파일 업로드 (HTTP PUT)
|
||||
Note over User,MinIO: 브라우저에서 스토리지로 다이렉트 전송
|
||||
MinIO-->>User: 6. 업로드 완료 응답 (HTTP 200 OK)
|
||||
|
||||
User->>Server: 7. 업로드 정보 DB 반영 요청
|
||||
Server->>DB: 8. tb_data / _test_tb_data 테이블에 파일 정보 INSERT
|
||||
DB-->>Server: 9. 삽입 성공
|
||||
Server-->>User: 10. 업로드 최종 완료 처리
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>2.2 폴더 비동기 압축 및 다운로드 워크플로우 <span class="badge">BullMQ + Redis 방식</span></h3>
|
||||
<p>오래 걸리는 압축 다운로드 작업을 백그라운드에서 비동기로 수행하고, 소켓으로 클라이언트에 완료 알림을 제공하는 워크플로우입니다.</p>
|
||||
|
||||
<div class="diagram-card">
|
||||
<div class="mermaid">
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor User as 사용자 (브라우저)
|
||||
participant Server as 백엔드 서버 (Node.js)
|
||||
participant Redis as Redis (6379)
|
||||
participant Worker as 백그라운드 Worker
|
||||
participant MinIO as 로컬 MinIO 스토리지
|
||||
participant DB as 데이터베이스 (PostgreSQL)
|
||||
|
||||
User->>Server: 1. 폴더 압축 다운로드 요청
|
||||
Server->>DB: 2. tb_download_folder에 'PENDING' 상태로 이력 기록
|
||||
Server->>Redis: 3. BullMQ를 통해 압축 Job 발행 (Push)
|
||||
Server-->>User: 4. 압축 작업 시작 안내 응답 (즉시 반환, 화면 안멈춤)
|
||||
|
||||
loop Worker 감시
|
||||
Worker->>Redis: 5. 대기 중인 Job 가져오기 (Pop)
|
||||
end
|
||||
|
||||
Note over Worker: 6. 폴더 내 모든 파일 탐색 및<br>zip 압축 파일 로컬 생성
|
||||
Worker->>MinIO: 7. 생성된 zip 파일을 S3 스토리지에 업로드
|
||||
Worker->>DB: 8. tb_download_folder 상태를 'COMPLETED'로 갱신,<br>zip_key 및 만료일(expire_date) 기록
|
||||
|
||||
Note over Server,User: 소켓(Socket.io) 또는 폴링 감시
|
||||
Server->>User: 9. 압축 완료 알림 전송 (Socket.io)
|
||||
User->>Server: 10. 내 다운로드 리스트 요청 (GET /getMyDownloadList)
|
||||
Server->>DB: 11. 완료된 zip 다운로드 정보 조회
|
||||
DB-->>Server: 12. zip 키값 반환
|
||||
Server-->>User: 13. MinIO zip 다운로드 다운로드 링크 반환
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 3. ERD 맵핑 관계 -->
|
||||
<h2>3. 주요 데이터 스키마 간 맵핑 관계 (Core ERD)</h2>
|
||||
<p>시스템 비즈니스 로직의 핵심이 되는 6개 주요 테이블 간의 참조 관계와 주요 필드 중심의 ERD 다이어그램입니다.</p>
|
||||
|
||||
<div class="diagram-card">
|
||||
<div class="mermaid">
|
||||
erDiagram
|
||||
tb_user {
|
||||
varchar user_id PK
|
||||
varchar user_nm
|
||||
varchar company
|
||||
varchar dept
|
||||
varchar group
|
||||
}
|
||||
|
||||
tb_project {
|
||||
varchar project_id PK
|
||||
varchar user_id FK
|
||||
varchar project_nm
|
||||
varchar short_nm
|
||||
boolean overview
|
||||
boolean official_doc
|
||||
boolean gsim
|
||||
}
|
||||
|
||||
tb_data {
|
||||
integer data_id PK
|
||||
varchar project_id FK
|
||||
varchar user_id FK
|
||||
boolean is_folder
|
||||
bigint data_size
|
||||
text object_key
|
||||
bigint popup_size
|
||||
bigint preview_size
|
||||
text ai_summary
|
||||
timestamp create_date
|
||||
}
|
||||
|
||||
tb_download_folder {
|
||||
integer download_id PK
|
||||
varchar project_id FK
|
||||
varchar user_id FK
|
||||
varchar status
|
||||
text zip_key
|
||||
timestamp expire_date
|
||||
boolean made
|
||||
}
|
||||
|
||||
tb_official_doc_file {
|
||||
integer doc_id PK
|
||||
varchar project_id FK
|
||||
varchar uploader FK
|
||||
varchar doc_number
|
||||
varchar doc_date
|
||||
text doc_title
|
||||
text doc_title_summary
|
||||
text doc_content_summary
|
||||
bigint popup_size
|
||||
bigint preview_size
|
||||
}
|
||||
|
||||
tb_click_log {
|
||||
integer click_log_id PK
|
||||
varchar project_id FK
|
||||
varchar user_id FK
|
||||
varchar activity
|
||||
varchar user_ip
|
||||
text_array path_arr
|
||||
int_array data_id_arr
|
||||
}
|
||||
|
||||
%% Relationships
|
||||
tb_user ||--o{ tb_project : "manages"
|
||||
tb_project ||--o{ tb_data : "contains"
|
||||
tb_user ||--o{ tb_data : "creates"
|
||||
tb_project ||--o{ tb_download_folder : "contains"
|
||||
tb_user ||--o{ tb_download_folder : "requests"
|
||||
tb_project ||--o{ tb_official_doc_file : "contains"
|
||||
tb_user ||--o{ tb_official_doc_file : "uploads"
|
||||
tb_project ||--o{ tb_click_log : "records"
|
||||
tb_user ||--o{ tb_click_log : "performs"
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 4. 사용자 관리 업무 흐름 -->
|
||||
<h2>4. 사용자 관리 업무 흐름</h2>
|
||||
<p>신규 사용자 계정을 생성한 뒤, 프로젝트 현장을 등록하고, 해당 현장에 사용자를 배정하여 시스템 기능을 가동하는 일련의 흐름입니다.</p>
|
||||
|
||||
<div class="diagram-card">
|
||||
<div class="mermaid">
|
||||
graph TD
|
||||
A["👤 1. 사용자 등록 (tb_user)<br>사용자 아이디, 패스워드, 이름, 회사/소속부서 등록"] --> B["🏗️ 2. 프로젝트 등록 (tb_project)<br>현장 고유
|
||||
ID, 공식 명칭, 카테고리 구분, 용량제한 설정"]
|
||||
B --> C["🔗 3. 프로젝트 사용자 등록 (tb_permission)<br>등록된 사용자를 특정 현장에 권한 등급(lev)과 함께 배정 및 연결"]
|
||||
C --> D["💻 4. 시스템 사용 (tb_data / tb_official_doc_file)<br>배정받은 권한 레벨(Owner, Sub-Master, Worker, Viewer)에
|
||||
맞춰 시스템 기능 활용"]
|
||||
|
||||
%% Styling
|
||||
style A fill:#fff1f2,stroke:#f43f5e,stroke-width:2px;
|
||||
style B fill:#fff1f2,stroke:#f43f5e,stroke-width:2px;
|
||||
style C fill:#fff1f2,stroke:#f43f5e,stroke-width:2px;
|
||||
style D fill:#be123c,stroke:#be123c,stroke-width:2px,color:#fff;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user