first commit
This commit is contained in:
@@ -0,0 +1,698 @@
|
||||
# 사내 지원 플랫폼 통합 아키텍처 설계서
|
||||
|
||||
## 1. 문서 목적
|
||||
|
||||
본 문서는 BARON-SSO 기반 공용 플랫폼으로 다음 두 서비스를 하나의 구조로 통합하는 방안을 설명함.
|
||||
|
||||
- 각 S/W 프로그램에서 진입하는 S/W별 Q&A 플랫폼
|
||||
- 회사 인트라넷에서 진입하는 사내 지원 플랫폼
|
||||
|
||||
이번 설계의 핵심은 기존 ABC User Feedback 솔루션을 그대로 폐기하지 않고, 원본 게시글 저장소와 채널 관리 도구로 활용하면서 우리 시스템이 권한 제어, 승인 워크플로우, 동적 폼, 운영 대시보드를 담당하는 구조로 고도화하는 데 있음.
|
||||
|
||||
## 2. 한눈에 보는 통합 방향
|
||||
|
||||
### 2.1 통합 대상 서비스
|
||||
|
||||
| 구분 | 설명 |
|
||||
| --- | --- |
|
||||
| S/W Q&A | 각 S/W 프로그램에서 로그인 후 해당 앱 전용 Q&A 채널로 연결되는 지원 서비스 |
|
||||
| 사내 지원 | 인트라넷에서 진입하여 물품신청, 도서 신청, 출장 차량 신청, 비품 대여, 사내 Q&A를 처리하는 지원 서비스 |
|
||||
|
||||
### 2.2 핵심 설계 판단
|
||||
|
||||
- 사용자 인증과 `tenant_id` 식별의 원본은 BARON-SSO가 담당함.
|
||||
- ABC User Feedback는 게시글 원본 저장소이자 관리자 기반 채널/필드 관리 도구로 사용함.
|
||||
- 우리 시스템은 FastAPI와 자체 DB를 통해 권한 분기, 상태 제어, 승인 이력, 운영 화면을 담당함.
|
||||
- 외부 진입 경로의 `app_id`, `service_type_id`는 내부 `workspace`로 매핑함.
|
||||
- 일반 사용자는 Next.js 동적 폼과 조회 화면을 사용하고, 담당자는 운영 페이지에서 승인/반려/후속 조치를 처리함.
|
||||
- Q&A와 신청은 공통 티켓 모델로 다루되, 실제 원본 본문은 ABC에 저장하고 우리 DB에는 제어용 메타데이터와 매핑 정보를 저장함.
|
||||
|
||||
### 2.3 역할 분리 요약
|
||||
|
||||
| 구성요소 | 주 역할 | 저장 데이터 |
|
||||
| --- | --- | --- |
|
||||
| BARON-SSO | 사용자 인증, `user_id`, `tenant_id` 발급 | 사용자/조직 원본 정보 |
|
||||
| ABC User Feedback | 게시글 저장, 댓글/첨부 관리, 채널/필드 구성, 기본 목록/상세 UI | 피드백 원본 데이터, 채널 설정, 필드 값 |
|
||||
| 우리 시스템 | 권한 필터링, 승인 워크플로우, 상태 제어, 운영 페이지, 동적 폼, 외부 연동 오케스트레이션 | 권한, 워크스페이스, 매핑, 승인, 자산, 차량, 알림, 운영 이력 |
|
||||
|
||||
## 3. High-Level Architecture
|
||||
|
||||
### 3.1 아키텍처 관점
|
||||
|
||||
| 관점 | 설명 |
|
||||
| --- | --- |
|
||||
| 사용자 접점 | 사용자가 어디서 진입하는지 |
|
||||
| 인증 계층 | BARON-SSO가 어디에서 인증을 담당하는지 |
|
||||
| 데이터 저장 계층 | ABC와 자체 DB가 어떤 데이터를 나눠 저장하는지 |
|
||||
| 제어 계층 | 권한, 승인, 운영 로직이 어디에서 처리되는지 |
|
||||
| 외부 연동 | 알림, 자산, 조직도, 기타 사내 API가 어디에서 연결되는지 |
|
||||
|
||||
### 3.2 High-Level Architecture 다이어그램
|
||||
|
||||
아래 다이어그램은 처리 행위를 화살표 라벨로 표시하고, 결과가 쌓이거나 보여지는 지점은 사각형 박스로 구분한 구조임.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
classDef result fill:#eef6ff,stroke:#1d4ed8,stroke-width:1.5px,color:#0f172a;
|
||||
classDef control fill:#f7f7f7,stroke:#334155,stroke-width:1.2px,color:#111827;
|
||||
classDef external fill:#fff7ed,stroke:#c2410c,stroke-width:1.2px,color:#111827;
|
||||
|
||||
subgraph U[사용자 영역]
|
||||
U1[인트라넷 사용자]
|
||||
U2[S/W 사용자]
|
||||
U3[운영 담당자]
|
||||
end
|
||||
|
||||
subgraph E[진입 채널]
|
||||
E1[인트라넷 포털]
|
||||
E2[각 S/W 프로그램]
|
||||
E3[운영 메뉴]
|
||||
end
|
||||
|
||||
SSO[BARON-SSO\nOAuth 2.0 / OIDC]:::external
|
||||
|
||||
subgraph UI[화면 계층]
|
||||
N1[Next.js 사용자 화면\n동적 폼 / 조회 / 상세]:::result
|
||||
N2[Next.js 운영 페이지\n승인 / 반려 / 후속 조치]:::result
|
||||
end
|
||||
|
||||
subgraph CTL[우리 시스템\nFastAPI + 자체 DB]
|
||||
F1[권한 분기 엔진\nuser_id + tenant_id + workspace]:::control
|
||||
F2[업무 프로세스 엔진\n상태 제어 / 승인 워크플로우 / 후속 조치]:::control
|
||||
F3[브릿지 API\nABC API 연동 / 매핑 기록]:::control
|
||||
D1[자체 제어 DB\n권한 / 매핑 / 승인 / 자산 / 차량 / 알림]:::result
|
||||
end
|
||||
|
||||
subgraph ABC[ABC User Feedback]
|
||||
A1[채널 / 필드 관리자 UI]:::result
|
||||
A2[Feedback API\nPOST /feedbacks 등]:::control
|
||||
A3[원본 데이터 저장소\n제목 / 본문 / 댓글 / 첨부 / 필드값]:::result
|
||||
A4[기본 목록 / 상세 UI]:::result
|
||||
end
|
||||
|
||||
subgraph X[외부 연동]
|
||||
X1[Naver Works API]:::external
|
||||
X2[SMS Gateway]:::external
|
||||
X3[자산 / 조직도 / 기타 사내 API]:::external
|
||||
end
|
||||
|
||||
U1 -->|인트라넷 서비스 진입| E1
|
||||
U2 -->|앱 내부 지원 메뉴 진입| E2
|
||||
U3 -->|운영 메뉴 진입| E3
|
||||
|
||||
E1 -->|사용자 화면 호출| N1
|
||||
E2 -->|사용자 화면 호출| N1
|
||||
E3 -->|운영 페이지 호출| N2
|
||||
|
||||
N1 -->|SSO 로그인 요청| SSO
|
||||
N2 -->|운영자 인증 요청| SSO
|
||||
SSO -->|user_id, tenant_id, 토큰 반환| N1
|
||||
SSO -->|운영 권한 토큰 반환| N2
|
||||
|
||||
N1 -->|폼/목록 조회 요청| F1
|
||||
N1 -->|신청/문의 등록 요청| F3
|
||||
N2 -->|승인 대기/처리 요청| F2
|
||||
|
||||
F1 -->|workspace 매핑 및 권한 판정| D1
|
||||
F2 -->|승인 이력 / 상태 저장| D1
|
||||
F3 -->|매핑 정보 조회 및 기록| D1
|
||||
|
||||
F3 -->|채널/필드 조회| A1
|
||||
F3 -->|원본 게시글 생성/조회| A2
|
||||
A2 -->|피드백 원본 저장| A3
|
||||
A2 -->|기본 목록/상세 제공| A4
|
||||
|
||||
F2 -->|알림 발송 요청| X1
|
||||
F2 -->|실패 시 대체 발송| X2
|
||||
F2 -->|자산/차량 후속 처리| X3
|
||||
```
|
||||
|
||||
### 3.3 전체 처리 흐름 요약
|
||||
|
||||
1. 사용자는 인트라넷 포털 또는 S/W 프로그램에서 Next.js 사용자 화면으로 진입함.
|
||||
2. 사용자 화면은 BARON-SSO를 통해 인증하고 `user_id`, `tenant_id`를 확보함.
|
||||
3. 우리 시스템의 권한 분기 엔진은 진입 경로를 `workspace`로 매핑하고 조회/등록 가능 범위를 판단함.
|
||||
4. 사용자가 문의 또는 신청서를 등록하면 브릿지 API가 ABC Feedback API로 원본 데이터를 저장함.
|
||||
5. 동시에 우리 DB에는 `workspace`, 상태, 요청 유형, ABC 피드백 ID, 기존 시스템 ID, 승인 필요 여부 등 제어 정보를 저장함.
|
||||
6. 담당자는 운영 페이지에서 승인 대기 건을 조회하고 `request_approvals` 기반으로 승인/반려/후속 조치를 처리함.
|
||||
7. 승인 결과와 상태 변경은 우리 DB에 기록되고, 필요 시 Naver Works 또는 SMS, 자산/차량 API 연동이 수행됨.
|
||||
|
||||
## 4. 서비스 책임 분리
|
||||
|
||||
### 4.1 ABC User Feedback의 역할
|
||||
|
||||
ABC User Feedback는 기능 저장소이자 데이터 저장소로 사용함. 즉, 사용자에게 보이는 게시글 원본과 채널 구조는 ABC가 책임지고, 우리 시스템은 이를 직접 대체하지 않음.
|
||||
|
||||
ABC가 담당하는 범위는 다음과 같음.
|
||||
|
||||
- 게시글 원본 데이터 저장
|
||||
- 제목, 본문, 댓글, 첨부파일 저장
|
||||
- 채널 생성 및 채널별 필드 구성
|
||||
- 신청서 항목을 표현하는 커스텀 필드 저장
|
||||
- 시스템 API를 통한 피드백 생성 및 조회
|
||||
- 기본 목록/상세 UI 제공
|
||||
|
||||
즉, ABC는 "무엇이 기록되었는가"를 보존하는 원본 시스템임.
|
||||
|
||||
### 4.2 우리 시스템의 역할
|
||||
|
||||
우리 시스템은 FastAPI, Next.js, 자체 DB를 사용하여 ABC 위에 제어 계층을 추가함.
|
||||
|
||||
우리 시스템이 담당하는 범위는 다음과 같음.
|
||||
|
||||
- `tenant_id`와 `workspace` 기준 권한 분기
|
||||
- 사용자별 조회 가능 데이터 필터링
|
||||
- 신청서 상태 제어: 대기, 승인, 반려, 처리 완료
|
||||
- `request_approvals` 기반 승인 워크플로우 처리
|
||||
- 자산 배정, 차량 배차, 원격지원 등 확장 프로세스 처리
|
||||
- 운영 대시보드 제공
|
||||
- Next.js 동적 폼 렌더링 및 유효성 검사
|
||||
- 기존 데이터 마이그레이션 시 ABC ID와 기존 글 ID 매핑 관리
|
||||
|
||||
즉, 우리 시스템은 "누가 무엇을 볼 수 있고, 어떤 절차로 처리되는가"를 책임지는 지능형 제어 엔진임.
|
||||
|
||||
### 4.3 화면 구성 원칙
|
||||
|
||||
| 화면 | 주 시스템 | 설명 |
|
||||
| --- | --- | --- |
|
||||
| 일반 사용자 입력 화면 | 우리 시스템 | 진입 경로별 동적 폼, 유효성 검사, 등록 프로세스 제어 |
|
||||
| 일반 사용자 목록/상세 | 혼합 | 우리 시스템의 권한 필터링 결과와 ABC 원본 데이터를 조합하여 노출 |
|
||||
| 운영 페이지 | 우리 시스템 | 승인/반려/후속 조치 전용 대시보드 |
|
||||
| 채널/필드 관리자 화면 | ABC User Feedback | 채널 생성, 필드 구성, 스키마 관리 |
|
||||
|
||||
## 5. DB 설계 방향
|
||||
|
||||
### 5.1 설계 원칙
|
||||
|
||||
- 사용자 마스터와 조직 정보는 BARON-SSO에서 관리함.
|
||||
- 게시글 원본, 댓글, 첨부, 채널 필드 값은 ABC에 저장함.
|
||||
- 우리 DB는 제어용 메타데이터와 운영용 확장 데이터만 저장함.
|
||||
- `support_tickets`는 내부 티켓 식별자이자 ABC 피드백과 연결되는 제어 엔트리 역할을 수행함.
|
||||
- 마이그레이션과 운영 연계에 필요한 식별자 매핑은 별도 매핑 테이블로 관리함.
|
||||
- 승인, 자산, 차량, 원격지원은 ABC 원본과 느슨하게 연결된 확장 테이블로 관리함.
|
||||
|
||||
### 5.2 데이터 저장 책임 분리
|
||||
|
||||
| 데이터 범주 | 저장 위치 | 설명 |
|
||||
| --- | --- | --- |
|
||||
| 사용자 인증 정보 | BARON-SSO | `user_id`, `tenant_id`, 토큰, 조직 기준 원본 |
|
||||
| 게시글 원본 | ABC User Feedback | 제목, 본문, 댓글, 첨부, 사용자 입력 필드 값 |
|
||||
| 권한/워크스페이스 | 우리 DB | `workspace`, 역할, 읽기/쓰기/승인/관리 권한 |
|
||||
| 제어용 티켓 메타데이터 | 우리 DB | 내부 티켓 ID, 상태, ABC 피드백 ID, 승인 필요 여부 |
|
||||
| 업무 확장 데이터 | 우리 DB | 승인, 자산, 차량, 원격지원, 알림 로그 |
|
||||
| 마이그레이션 매핑 | 우리 DB | 기존 시스템 ID와 ABC 피드백 ID, 내부 티켓 ID 연결 |
|
||||
|
||||
### 5.3 핵심 관계 구조
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
classDef result fill:#eef6ff,stroke:#1d4ed8,stroke-width:1.2px,color:#0f172a;
|
||||
classDef control fill:#f7f7f7,stroke:#334155,stroke-width:1.2px,color:#111827;
|
||||
|
||||
W[workspaces]:::result -->|1:N 서비스 범위 정의| UWA[user_workspace_access]:::result
|
||||
W -->|1:N 내부 티켓 소속| ST[support_tickets]:::result
|
||||
ST -->|1:1 또는 1:N ABC 원본 연결| AFM[abc_feedback_mappings]:::result
|
||||
AFM -->|ABC feedback_id 참조 기록| ABCREF[ABC feedback]:::control
|
||||
ST -->|1:N 승인 이력| RA[request_approvals]:::result
|
||||
ST -->|1:N 자산 배정| AA[asset_allocations]:::result
|
||||
ST -->|1:N 차량 일정| VS[vehicle_schedules]:::result
|
||||
ST -->|1:N 원격지원 이력| RS[remote_support]:::result
|
||||
ST -->|1:N 알림 이력| NL[notification_logs]:::result
|
||||
ST -->|1:N 마이그레이션 추적| MM[migration_mappings]:::result
|
||||
```
|
||||
|
||||
## 6. DB 스키마 상세화
|
||||
|
||||
### 6.1 자체 DB 데이터 영역
|
||||
|
||||
| 데이터 영역 | 주요 테이블 | 설명 |
|
||||
| --- | --- | --- |
|
||||
| 서비스 마스터 | `software_apps`, `service_types`, `workspaces` | 진입 채널을 내부 `workspace`로 매핑 |
|
||||
| 권한 관리 | `user_workspace_access` | 읽기, 쓰기, 운영, 승인 권한 제어 |
|
||||
| 폼/채널 연동 | `workspace_channel_mappings`, `workspace_field_mappings` | `workspace`와 ABC 채널/필드 연결 |
|
||||
| 공통 티켓 메타데이터 | `support_tickets` | 내부 상태, 요청자, 티켓 유형, 우선순위 관리 |
|
||||
| ABC 연동 매핑 | `abc_feedback_mappings` | 내부 티켓과 ABC `feedback_id` 연결 |
|
||||
| 마이그레이션 추적 | `migration_mappings`, `migration_batches` | 기존 글 ID, 기존 첨부 ID, ABC ID 적재 이력 관리 |
|
||||
| 승인/운영 | `request_approvals`, `notification_logs` | 승인 및 알림 처리 이력 |
|
||||
| 업무 확장 | `assets`, `asset_allocations`, `vehicle_schedules`, `remote_support` | 자산, 차량, 원격지원 업무 관리 |
|
||||
|
||||
### 6.2 핵심 상세 테이블 제안
|
||||
|
||||
아래 스키마는 ABC와 우리 DB의 역할 분리를 반영한 초안임.
|
||||
|
||||
```sql
|
||||
CREATE TABLE software_apps (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
app_code VARCHAR(50) NOT NULL,
|
||||
app_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_software_apps_app_code (app_code),
|
||||
UNIQUE KEY uq_software_apps_app_name (app_name)
|
||||
);
|
||||
|
||||
CREATE TABLE service_types (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
service_code VARCHAR(50) NOT NULL,
|
||||
service_name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_service_types_service_code (service_code),
|
||||
UNIQUE KEY uq_service_types_service_name (service_name)
|
||||
);
|
||||
|
||||
CREATE TABLE workspaces (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
workspace_type VARCHAR(20) NOT NULL,
|
||||
software_app_id BIGINT NULL,
|
||||
service_type_id BIGINT NULL,
|
||||
workspace_code VARCHAR(50) NOT NULL,
|
||||
workspace_name VARCHAR(100) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_workspaces_workspace_code (workspace_code),
|
||||
CONSTRAINT fk_workspaces_software_app
|
||||
FOREIGN KEY (software_app_id) REFERENCES software_apps(id),
|
||||
CONSTRAINT fk_workspaces_service_type
|
||||
FOREIGN KEY (service_type_id) REFERENCES service_types(id),
|
||||
CONSTRAINT chk_workspaces_scope
|
||||
CHECK (
|
||||
(workspace_type = 'SOFTWARE_APP' AND software_app_id IS NOT NULL AND service_type_id IS NULL)
|
||||
OR
|
||||
(workspace_type = 'INTRANET_SERVICE' AND service_type_id IS NOT NULL AND software_app_id IS NULL)
|
||||
)
|
||||
);
|
||||
|
||||
CREATE TABLE user_workspace_access (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
user_id VARCHAR(100) NOT NULL,
|
||||
tenant_id VARCHAR(100) NOT NULL,
|
||||
workspace_id BIGINT NOT NULL,
|
||||
workspace_role VARCHAR(30) NOT NULL DEFAULT 'USER',
|
||||
can_read BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
can_write BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_manage BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
can_approve BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
page_scope VARCHAR(50),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_user_workspace_access_user_tenant_workspace (user_id, tenant_id, workspace_id),
|
||||
CONSTRAINT fk_user_workspace_access_workspace
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id)
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_channel_mappings (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
workspace_id BIGINT NOT NULL,
|
||||
abc_channel_id VARCHAR(100) NOT NULL,
|
||||
abc_channel_key VARCHAR(100),
|
||||
form_template_version VARCHAR(30),
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_workspace_channel_mappings_workspace_channel (workspace_id, abc_channel_id),
|
||||
CONSTRAINT fk_workspace_channel_mappings_workspace
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id)
|
||||
);
|
||||
|
||||
CREATE TABLE workspace_field_mappings (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
workspace_id BIGINT NOT NULL,
|
||||
abc_channel_id VARCHAR(100) NOT NULL,
|
||||
abc_field_key VARCHAR(100) NOT NULL,
|
||||
local_field_code VARCHAR(100) NOT NULL,
|
||||
field_label VARCHAR(100) NOT NULL,
|
||||
field_type VARCHAR(30) NOT NULL,
|
||||
is_required BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
sort_order INT NOT NULL DEFAULT 0,
|
||||
validation_rule JSON,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_workspace_field_mappings_workspace_channel_field (workspace_id, abc_channel_id, abc_field_key),
|
||||
CONSTRAINT fk_workspace_field_mappings_workspace
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id)
|
||||
);
|
||||
|
||||
CREATE TABLE support_status_codes (
|
||||
code VARCHAR(20) NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
sort_order INT NOT NULL,
|
||||
PRIMARY KEY (code)
|
||||
);
|
||||
|
||||
CREATE TABLE support_category_codes (
|
||||
code VARCHAR(20) NOT NULL,
|
||||
name VARCHAR(50) NOT NULL,
|
||||
sort_order INT NOT NULL,
|
||||
PRIMARY KEY (code)
|
||||
);
|
||||
|
||||
CREATE TABLE support_tickets (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
workspace_id BIGINT NOT NULL,
|
||||
requester_id VARCHAR(100) NOT NULL,
|
||||
requester_tenant_id VARCHAR(100) NOT NULL,
|
||||
ticket_type VARCHAR(30) NOT NULL,
|
||||
source_system VARCHAR(30) NOT NULL DEFAULT 'ABC',
|
||||
title VARCHAR(255) NOT NULL,
|
||||
category_code VARCHAR(20),
|
||||
status_code VARCHAR(20) NOT NULL,
|
||||
is_secret BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
requires_approval BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
current_assignee_id VARCHAR(100),
|
||||
current_assignee_tenant_id VARCHAR(100),
|
||||
requested_start_at TIMESTAMP NULL,
|
||||
requested_end_at TIMESTAMP NULL,
|
||||
priority VARCHAR(20) NOT NULL DEFAULT 'NORMAL',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_support_tickets_workspace
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id),
|
||||
CONSTRAINT fk_support_tickets_category_code
|
||||
FOREIGN KEY (category_code) REFERENCES support_category_codes(code),
|
||||
CONSTRAINT fk_support_tickets_status_code
|
||||
FOREIGN KEY (status_code) REFERENCES support_status_codes(code)
|
||||
);
|
||||
|
||||
CREATE TABLE abc_feedback_mappings (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ticket_id BIGINT NOT NULL,
|
||||
workspace_id BIGINT NOT NULL,
|
||||
abc_channel_id VARCHAR(100) NOT NULL,
|
||||
abc_feedback_id VARCHAR(100) NOT NULL,
|
||||
abc_feedback_url TEXT,
|
||||
sync_status VARCHAR(20) NOT NULL DEFAULT 'SYNCED',
|
||||
last_synced_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_abc_feedback_mappings_ticket_id (ticket_id),
|
||||
UNIQUE KEY uq_abc_feedback_mappings_feedback_id (abc_feedback_id),
|
||||
CONSTRAINT fk_abc_feedback_mappings_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id),
|
||||
CONSTRAINT fk_abc_feedback_mappings_workspace
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id)
|
||||
);
|
||||
|
||||
CREATE TABLE migration_batches (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
batch_name VARCHAR(100) NOT NULL,
|
||||
source_system VARCHAR(50) NOT NULL,
|
||||
started_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
completed_at TIMESTAMP NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'RUNNING',
|
||||
executed_by VARCHAR(100),
|
||||
notes TEXT,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE migration_mappings (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
batch_id BIGINT NOT NULL,
|
||||
source_system VARCHAR(50) NOT NULL,
|
||||
source_entity_type VARCHAR(30) NOT NULL,
|
||||
source_entity_id VARCHAR(100) NOT NULL,
|
||||
source_parent_id VARCHAR(100),
|
||||
workspace_id BIGINT NOT NULL,
|
||||
ticket_id BIGINT NULL,
|
||||
abc_feedback_id VARCHAR(100),
|
||||
migration_status VARCHAR(20) NOT NULL,
|
||||
error_message TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_migration_mappings_source_entity (source_system, source_entity_type, source_entity_id),
|
||||
CONSTRAINT fk_migration_mappings_batch
|
||||
FOREIGN KEY (batch_id) REFERENCES migration_batches(id),
|
||||
CONSTRAINT fk_migration_mappings_workspace
|
||||
FOREIGN KEY (workspace_id) REFERENCES workspaces(id),
|
||||
CONSTRAINT fk_migration_mappings_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id)
|
||||
);
|
||||
|
||||
CREATE TABLE request_approvals (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ticket_id BIGINT NOT NULL,
|
||||
approver_id VARCHAR(100) NOT NULL,
|
||||
approver_tenant_id VARCHAR(100) NOT NULL,
|
||||
approval_status VARCHAR(20) NOT NULL,
|
||||
comment TEXT,
|
||||
approved_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_request_approvals_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id)
|
||||
);
|
||||
|
||||
CREATE TABLE assets (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
asset_code VARCHAR(50) NOT NULL,
|
||||
asset_name VARCHAR(100) NOT NULL,
|
||||
asset_type VARCHAR(30) NOT NULL,
|
||||
quantity INT NOT NULL DEFAULT 1,
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
location VARCHAR(100),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uq_assets_asset_code (asset_code)
|
||||
);
|
||||
|
||||
CREATE TABLE asset_allocations (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ticket_id BIGINT NOT NULL,
|
||||
asset_id BIGINT NOT NULL,
|
||||
assignee_id VARCHAR(100),
|
||||
assignee_tenant_id VARCHAR(100),
|
||||
allocation_status VARCHAR(20) NOT NULL,
|
||||
loaned_at TIMESTAMP NULL,
|
||||
due_at TIMESTAMP NULL,
|
||||
returned_at TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_asset_allocations_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id),
|
||||
CONSTRAINT fk_asset_allocations_asset
|
||||
FOREIGN KEY (asset_id) REFERENCES assets(id)
|
||||
);
|
||||
|
||||
CREATE TABLE vehicle_schedules (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ticket_id BIGINT NOT NULL,
|
||||
asset_id BIGINT NOT NULL,
|
||||
departure_at TIMESTAMP NOT NULL,
|
||||
arrival_at TIMESTAMP NULL,
|
||||
destination VARCHAR(255),
|
||||
driver_name VARCHAR(100),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_vehicle_schedules_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id),
|
||||
CONSTRAINT fk_vehicle_schedules_asset
|
||||
FOREIGN KEY (asset_id) REFERENCES assets(id)
|
||||
);
|
||||
|
||||
CREATE TABLE remote_support (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ticket_id BIGINT NOT NULL,
|
||||
status_code VARCHAR(20) NOT NULL,
|
||||
support_engineer_id VARCHAR(100),
|
||||
support_engineer_tenant_id VARCHAR(100),
|
||||
scheduled_time TIMESTAMP NULL,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_remote_support_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id)
|
||||
);
|
||||
|
||||
CREATE TABLE notification_logs (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ticket_id BIGINT NULL,
|
||||
recipient_id VARCHAR(100) NOT NULL,
|
||||
recipient_tenant_id VARCHAR(100) NOT NULL,
|
||||
channel VARCHAR(20) NOT NULL,
|
||||
target_address VARCHAR(100),
|
||||
delivery_status VARCHAR(20) NOT NULL,
|
||||
fallback_channel VARCHAR(20),
|
||||
error_message TEXT,
|
||||
sent_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_notification_logs_ticket
|
||||
FOREIGN KEY (ticket_id) REFERENCES support_tickets(id)
|
||||
);
|
||||
```
|
||||
|
||||
### 6.3 테이블 간 연동 해석
|
||||
|
||||
- `workspaces`는 외부 진입 채널과 내부 처리 단위를 연결하는 기준 테이블임.
|
||||
- `workspace_channel_mappings`는 하나의 `workspace`가 어떤 ABC 채널을 사용하는지 정의함.
|
||||
- `workspace_field_mappings`는 Next.js 동적 폼과 ABC 커스텀 필드를 동일한 규칙으로 묶어줌.
|
||||
- `support_tickets`는 우리 시스템이 상태와 권한을 제어하기 위한 내부 티켓 헤더임.
|
||||
- `abc_feedback_mappings`는 내부 티켓과 ABC 원본 피드백을 1:1로 연결하는 핵심 브릿지 테이블임.
|
||||
- `migration_mappings`는 기존 시스템 글, 댓글, 첨부가 어느 내부 티켓과 ABC 피드백으로 적재되었는지 추적함.
|
||||
|
||||
## 7. API 엔드포인트 설계
|
||||
|
||||
### 7.1 API 설계 원칙
|
||||
|
||||
- 외부 클라이언트는 직접 ABC API를 호출하지 않고 우리 FastAPI를 경유함.
|
||||
- FastAPI는 SSO 토큰을 검증하고 `tenant_id`, `workspace`, 권한 범위를 해석함.
|
||||
- 등록 시에는 ABC API와 자체 DB 쓰기가 하나의 업무 트랜잭션처럼 동작해야 함.
|
||||
- 조회 시에는 우리 DB에서 권한 필터링을 먼저 수행하고, 필요 시 ABC 원본 데이터를 조합하여 응답함.
|
||||
|
||||
### 7.2 브릿지 API 목록
|
||||
|
||||
| 메서드 | 경로 | 목적 |
|
||||
| --- | --- | --- |
|
||||
| `POST` | `/api/workspaces/{workspaceCode}/tickets` | 사용자 문의/신청 등록, ABC 피드백 생성, 내부 티켓 및 매핑 저장 |
|
||||
| `GET` | `/api/workspaces/{workspaceCode}/tickets` | 권한 필터링된 목록 조회 |
|
||||
| `GET` | `/api/workspaces/{workspaceCode}/tickets/{ticketId}` | 내부 상태 + ABC 원본 상세 조합 조회 |
|
||||
| `POST` | `/api/workspaces/{workspaceCode}/tickets/{ticketId}/comments` | 댓글 또는 처리 메모 등록 |
|
||||
| `POST` | `/api/workspaces/{workspaceCode}/tickets/{ticketId}/attachments` | 첨부 업로드 브릿지 처리 |
|
||||
| `GET` | `/api/workspaces/{workspaceCode}/form-template` | 동적 폼 렌더링용 필드 구성 조회 |
|
||||
| `GET` | `/api/admin/workspaces/{workspaceCode}/pending-approvals` | 운영 페이지 승인 대기 목록 조회 |
|
||||
| `POST` | `/api/admin/tickets/{ticketId}/approve` | 승인 처리 및 `request_approvals` 기록 |
|
||||
| `POST` | `/api/admin/tickets/{ticketId}/reject` | 반려 처리 및 반려 사유 기록 |
|
||||
| `POST` | `/api/admin/tickets/{ticketId}/follow-up/assets` | 자산 배정 후속 처리 |
|
||||
| `POST` | `/api/admin/tickets/{ticketId}/follow-up/vehicle` | 차량 배차 후속 처리 |
|
||||
|
||||
### 7.3 등록 브릿지 API 처리 순서
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
classDef result fill:#eef6ff,stroke:#1d4ed8,stroke-width:1.2px,color:#0f172a;
|
||||
classDef control fill:#f7f7f7,stroke:#334155,stroke-width:1.2px,color:#111827;
|
||||
|
||||
C1[클라이언트 요청]:::result -->|SSO 토큰 포함| C2[FastAPI 브릿지]:::control
|
||||
C2 -->|workspace 및 권한 확인| C3[user_workspace_access 조회]:::result
|
||||
C2 -->|필드 매핑 로드| C4[workspace_field_mappings 조회]:::result
|
||||
C2 -->|ABC payload 변환| C5[ABC POST /feedbacks 호출]:::control
|
||||
C5 -->|feedback_id 반환| C6[ABC 원본 저장 완료]:::result
|
||||
C2 -->|내부 티켓 생성| C7[support_tickets 저장]:::result
|
||||
C2 -->|ABC 연결 기록| C8[abc_feedback_mappings 저장]:::result
|
||||
C2 -->|승인 필요 여부 판정| C9[초기 상태 결정]:::result
|
||||
```
|
||||
|
||||
### 7.4 조회 API 권한 필터링 규칙
|
||||
|
||||
| 시나리오 | 필터 기준 |
|
||||
| --- | --- |
|
||||
| 일반 사용자 내 글 조회 | `requester_id = current_user_id` and `requester_tenant_id = current_tenant_id` |
|
||||
| 워크스페이스 담당자 조회 | `user_workspace_access.can_manage = true` |
|
||||
| 승인 담당자 조회 | `user_workspace_access.can_approve = true` and `page_scope` 일치 |
|
||||
| 외부 고객 조회 | 본인 글만 조회, 비밀글은 작성자/담당자만 허용 |
|
||||
|
||||
### 7.5 예시 응답 모델
|
||||
|
||||
```json
|
||||
{
|
||||
"ticketId": 1024,
|
||||
"workspaceCode": "INTRA_BOOK_REQUEST",
|
||||
"statusCode": "PENDING_APPROVAL",
|
||||
"approvalRequired": true,
|
||||
"abc": {
|
||||
"channelId": "book-request-channel",
|
||||
"feedbackId": "fb_938421",
|
||||
"detailUrl": "https://abc.example.com/feedbacks/fb_938421"
|
||||
},
|
||||
"requester": {
|
||||
"userId": "u1001",
|
||||
"tenantId": "baron"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 마이그레이션 매핑 로직 설계
|
||||
|
||||
### 8.1 마이그레이션 목표
|
||||
|
||||
기존 시스템의 게시글, 신청서, 댓글, 첨부를 ABC 원본 구조로 적재하면서, 동시에 우리 시스템의 내부 티켓과 매핑 정보를 남겨 이후 조회, 권한 제어, 운영 처리에 문제없이 연결되도록 해야 함.
|
||||
|
||||
### 8.2 배치 처리 단계
|
||||
|
||||
1. 기존 시스템에서 대상 데이터와 첨부 메타데이터를 추출함.
|
||||
2. 기존 글 유형을 `workspace`와 `ticket_type`으로 변환함.
|
||||
3. 필드 매핑 규칙에 따라 ABC 커스텀 필드 payload를 생성함.
|
||||
4. ABC API로 게시글 원본을 생성하고 `abc_feedback_id`를 수신함.
|
||||
5. 우리 DB의 `support_tickets`에 내부 제어용 티켓을 생성함.
|
||||
6. `abc_feedback_mappings`와 `migration_mappings`에 연결 정보를 저장함.
|
||||
7. 댓글과 첨부는 원본 글 적재 완료 후 후속 단계로 연결함.
|
||||
8. 실패 건은 `migration_status = 'FAILED'`와 `error_message`로 남기고 재처리 가능하게 함.
|
||||
|
||||
### 8.3 마이그레이션 흐름 다이어그램
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
classDef result fill:#eef6ff,stroke:#1d4ed8,stroke-width:1.2px,color:#0f172a;
|
||||
classDef control fill:#f7f7f7,stroke:#334155,stroke-width:1.2px,color:#111827;
|
||||
|
||||
M1[기존 시스템 데이터]:::result -->|배치가 원본 추출| M2[Migration Script]:::control
|
||||
M2 -->|workspace 규칙 적용| M3[workspace 결정 결과]:::result
|
||||
M2 -->|ABC payload 생성| M4[ABC POST /feedbacks]:::control
|
||||
M4 -->|abc_feedback_id 수신| M5[ABC 원본 생성 결과]:::result
|
||||
M2 -->|내부 티켓 생성| M6[support_tickets]:::result
|
||||
M2 -->|브릿지 연결 저장| M7[abc_feedback_mappings]:::result
|
||||
M2 -->|이관 추적 저장| M8[migration_mappings]:::result
|
||||
M2 -->|실패 사유 기록| M9[재처리 대상 목록]:::result
|
||||
```
|
||||
|
||||
### 8.4 마이그레이션 스크립트 의사코드
|
||||
|
||||
```python
|
||||
def migrate_record(source_record):
|
||||
workspace = resolve_workspace(source_record.app_id, source_record.service_type)
|
||||
template = load_workspace_template(workspace.id)
|
||||
abc_payload = build_abc_payload(source_record, template)
|
||||
|
||||
abc_feedback = abc_client.create_feedback(
|
||||
channel_id=template.abc_channel_id,
|
||||
payload=abc_payload,
|
||||
)
|
||||
|
||||
ticket = create_support_ticket(
|
||||
workspace_id=workspace.id,
|
||||
requester_id=source_record.user_id,
|
||||
requester_tenant_id=source_record.tenant_id,
|
||||
ticket_type=source_record.ticket_type,
|
||||
title=source_record.title,
|
||||
status_code=initial_status(source_record),
|
||||
)
|
||||
|
||||
create_abc_feedback_mapping(
|
||||
ticket_id=ticket.id,
|
||||
workspace_id=workspace.id,
|
||||
abc_channel_id=template.abc_channel_id,
|
||||
abc_feedback_id=abc_feedback.id,
|
||||
)
|
||||
|
||||
create_migration_mapping(
|
||||
source_system="legacy_support",
|
||||
source_entity_type="POST",
|
||||
source_entity_id=source_record.legacy_id,
|
||||
workspace_id=workspace.id,
|
||||
ticket_id=ticket.id,
|
||||
abc_feedback_id=abc_feedback.id,
|
||||
migration_status="SYNCED",
|
||||
)
|
||||
```
|
||||
|
||||
### 8.5 운영상 주의점
|
||||
|
||||
- 댓글과 첨부는 원본 글 생성 성공 이후 단계적으로 적재해야 함.
|
||||
- 기존 시스템 ID 중복을 막기 위해 `migration_mappings`에 유니크 제약이 필요함.
|
||||
- 재실행 가능성을 고려해 배치는 멱등적으로 설계해야 함.
|
||||
- ABC 적재 성공 후 내부 DB 저장 실패가 발생하면 보상 처리 또는 재동기화 큐가 필요함.
|
||||
|
||||
## 9. 정리
|
||||
|
||||
이 설계의 핵심은 S/W별 Q&A와 인트라넷 사내 지원을 하나의 `workspace` 기반 플랫폼으로 통합하되, 시스템 역할을 명확히 나누는 데 있음.
|
||||
|
||||
- ABC User Feedback는 게시글 원본 저장소이자 채널/필드 관리 도구임.
|
||||
- 우리 시스템은 FastAPI와 자체 DB를 통해 권한 분기, 승인 워크플로우, 운영 페이지, 동적 폼, 외부 연동을 담당함.
|
||||
- BARON-SSO는 사용자와 `tenant_id`의 원본 인증 계층으로 유지됨.
|
||||
- `abc_feedback_mappings`, `workspace_channel_mappings`, `migration_mappings`가 두 시스템을 연결하는 핵심 브릿지 역할을 수행함.
|
||||
|
||||
다음 단계에서는 상태 코드 표준값, `page_scope` 체계, 실제 ABC API 스펙, 운영 페이지 화면 와이어프레임을 추가하면 구현 준비 수준의 설계 문서로 확장 가능함.
|
||||
Reference in New Issue
Block a user