Files
Q-A_test/docs/architecture_secretary_sso_components_v2.md
T
SDI 12e4f17b62
CI / typecheck (push) Successful in 1m8s
CI / format (push) Failing after 1m6s
CI / lint (push) Failing after 49s
CI / test (push) Failing after 1m8s
first commit
2026-07-15 18:05:12 +09:00

31 KiB

사내 지원 플랫폼 통합 아키텍처 설계서

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 다이어그램

아래 다이어그램은 처리 행위를 화살표 라벨로 표시하고, 결과가 쌓이거나 보여지는 지점은 사각형 박스로 구분한 구조임.

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_idworkspace 기준 권한 분기
  • 사용자별 조회 가능 데이터 필터링
  • 신청서 상태 제어: 대기, 승인, 반려, 처리 완료
  • 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 핵심 관계 구조

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의 역할 분리를 반영한 초안임.

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 처리 순서

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 예시 응답 모델

{
  "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. 기존 글 유형을 workspaceticket_type으로 변환함.
  3. 필드 매핑 규칙에 따라 ABC 커스텀 필드 payload를 생성함.
  4. ABC API로 게시글 원본을 생성하고 abc_feedback_id를 수신함.
  5. 우리 DB의 support_tickets에 내부 제어용 티켓을 생성함.
  6. abc_feedback_mappingsmigration_mappings에 연결 정보를 저장함.
  7. 댓글과 첨부는 원본 글 적재 완료 후 후속 단계로 연결함.
  8. 실패 건은 migration_status = 'FAILED'error_message로 남기고 재처리 가능하게 함.

8.3 마이그레이션 흐름 다이어그램

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 마이그레이션 스크립트 의사코드

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 스펙, 운영 페이지 화면 와이어프레임을 추가하면 구현 준비 수준의 설계 문서로 확장 가능함.