Files
egbim_qa_platform/FEEDBACK_DATA_FLOW.md

18 KiB

피드백 작성 페이지와 관리페이지 데이터 흐름

1. 전체 구조

현재 구조는 피드백 작성 웹과 관리 콘솔이 분리되어 있습니다. 작성 웹은 직접 ABC API나 DB에 접근하지 않고, Next.js 서버 Proxy를 통해 외부 관리 콘솔 API에 요청합니다.

피드백 작성 페이지
/support/{workspaceCode}/new
        │
        │ POST /api/support/workspaces/{workspaceCode}/submit
        ▼
apps/web의 Next.js API Proxy
        │
        │ POST /api/support/workspaces/{workspaceCode}/tickets
        ▼
외부 관리 콘솔 API
https://feedback.hmac.kr/api/support
        │
        ├─ Secretary DB: support_tickets 저장
        ├─ ABC API: feedbacks 저장
        ├─ abc_feedback_mappings: 두 ID 연결
        └─ 첨부파일: Secretary Local/R2 저장
        ▼
관리 콘솔에서 조회·처리

피드백 전용 배포에서는 브라우저 요청을 same-origin으로 유지하고, 외부 관리 콘솔 주소는 서버 환경변수로만 사용합니다.

관련 설정:

  • NEXT_PUBLIC_FEEDBACK_ONLY=true
  • SUPPORT_CONSOLE_API_BASE_URL=https://feedback.hmac.kr/api/support
  • NEXT_PUBLIC_API_BASE_URL은 빈 값으로 설정

1.1 전체 데이터 흐름도

flowchart LR
    U[사용자] --> W[피드백 작성 페이지<br/>/support/{workspaceCode}/new]
    W -->|FormData<br/>제목·내용·필드·첨부파일| P[Next.js 서버 Proxy]
    P -->|POST /api/support/workspaces/{workspaceCode}/tickets| S[외부 관리 콘솔 API<br/>Secretary]

    S -->|1. 내부 티켓 저장| T[(Secretary DB<br/>baron_support)]
    S -->|2. ABC 피드백 생성| A[ABC API]
    A --> F[(ABC MySQL<br/>feedbacks)]
    S --> M[(abc_feedback_mappings)]
    M -. ticket_id ↔ feedback_id .-> T
    M -. ticket_id ↔ feedback_id .-> F
    S -->|첨부파일 저장| X[(Secretary Local/R2<br/>+ attachments 메타데이터)]

    T --> C[관리 콘솔 목록·상세 화면]
    F --> C
    X --> C

핵심 저장 위치

flowchart TD
    D[피드백 등록 데이터]
    D --> D1[ABC MySQL<br/>feedbacks.data JSON<br/>원본 피드백 본문]
    D --> D2[Secretary DB<br/>support_tickets<br/>관리용 티켓·상태·권한]
    D --> D3[Secretary DB<br/>abc_feedback_mappings<br/>두 시스템 ID 연결]
    D --> D4[Secretary Local/R2<br/>첨부파일 바이너리]
    D --> D5[Secretary DB<br/>attachments<br/>첨부파일 메타데이터]
    D1 -. 검색 활성화 시 .-> D6[OpenSearch<br/>검색용 색인]

ID 연결 구조

flowchart LR
    W[workspace_code<br/>예: EGBIM_DEMO]
    W --> ST[Secretary ticket_id]
    ST --> MAP[abc_feedback_mappings]
    MAP --> AF[ABC feedback_id]
    AF --> CH[ABC project_id / channel_id]

ticket_idfeedback_id는 서로 다른 시스템에서 생성되는 별도 ID입니다. 관리 콘솔은 abc_feedback_mappings 또는 응답의 extra_fields.abc_feedback_id를 이용해 두 데이터를 결합합니다.

1.2 네이버웍스 알림 흐름도

피드백 등록 자체는 먼저 ABC와 Secretary에 저장되고, 저장 완료 후 ABC 백엔드 이벤트를 통해 네이버웍스 알림이 발송됩니다.

sequenceDiagram
    participant User as 사용자
    participant Web as 작성 웹
    participant Secretary as Secretary API
    participant ABC as ABC API
    participant ABCDB as ABC MySQL
    participant Notify as 알림 서비스
    participant NW as 네이버웍스 API
    participant Log as notification_deliveries

    User->>Web: 피드백 등록
    Web->>Secretary: POST /workspaces/{code}/tickets
    Secretary->>Secretary: support_tickets 저장
    Secretary->>ABC: feedback 생성 요청
    ABC->>ABCDB: feedbacks 저장
    ABC-->>Notify: FEEDBACK_CREATION 이벤트
    Notify->>Notify: 담당자·프로젝트 관리자·작성자 계산
    Notify->>NW: 이메일로 사용자 ID 조회
    NW-->>Notify: 네이버웍스 userId
    Notify->>NW: Bot 개인 메시지 발송
    Notify->>Log: SENT / FAILED / SKIPPED 기록
    ABC-->>Secretary: abc_feedback_id 반환
    Secretary-->>Web: ticket_id·동기화 상태 반환

2. 피드백 작성 페이지

작성 페이지는 다음 파일입니다.

apps/web/src/pages/support/[workspaceCode]/new.tsx

양식 조회

페이지 진입 시 workspace별 양식을 조회합니다.

GET /api/support/workspaces/{workspaceCode}/form-template

Next.js API Proxy는 이를 외부 관리 콘솔 API로 전달합니다.

GET {SUPPORT_CONSOLE_API_BASE_URL}/workspaces/{workspaceCode}/form-template

양식의 workspace code는 프로젝트와 ABC 프로젝트·채널을 연결하는 식별자입니다.

등록 요청

사용자가 등록하면 브라우저는 FormData를 생성합니다.

주요 필드는 다음과 같습니다.

  • title
  • description
  • category_code
  • is_secret
  • ticket_type
  • requires_approval
  • extra_fields
  • attachments

작성 페이지는 다음 내부 API를 호출합니다.

POST /api/support/workspaces/{workspaceCode}/submit

관련 파일:

apps/web/src/pages/api/support/workspaces/[workspaceCode]/submit.ts

이 API는 multipart 요청을 파싱한 후 외부 관리 콘솔로 다시 전달합니다.

POST {SUPPORT_CONSOLE_API_BASE_URL}/workspaces/{workspaceCode}/tickets

인증 정보는 브라우저에서 별도 입력받지 않고, 현재 로그인된 BARON-SSO 세션의 Authorization 헤더를 Proxy가 전달합니다.

3. Secretary API에서의 저장

Secretary API의 티켓 생성 로직은 다음 파일에 있습니다.

apps/secretary-api/app/services/ticket_service.py

티켓 등록 시 다음 순서로 처리됩니다.

  1. support_tickets에 내부 관리 티켓을 생성합니다.
  2. workspace에 매핑된 ABC 프로젝트와 채널을 확인합니다.
  3. ABC API에 피드백을 생성합니다.
  4. abc_feedback_mappings에 Secretary 티켓과 ABC 피드백의 연결 정보를 저장합니다.
  5. 첨부파일을 Secretary 저장소에 저장합니다.
  6. 동기화 상태를 SYNCED로 변경합니다.
  7. 티켓 ID와 동기화 상태를 작성 웹에 반환합니다.

API 라우트:

POST /api/workspaces/{workspaceCode}/tickets

구현 파일:

apps/secretary-api/app/api/routes/tickets.py

4. 데이터베이스 구조

Secretary DB

Secretary 쪽에는 관리 업무용 데이터가 저장됩니다.

테이블 역할
support_tickets 내부 관리 티켓 본체
abc_feedback_mappings Secretary 티켓 ID와 ABC 피드백 ID 연결
ticket_comments 사용자 댓글 및 내부 메모
attachments 첨부파일 메타데이터
user_workspace_access 사용자별 workspace 권한

주요 모델은 다음 파일에 정의되어 있습니다.

apps/secretary-api/app/db/models.py

ABC DB

ABC 쪽에는 기존 피드백 데이터가 저장됩니다.

테이블 역할
feedbacks 피드백 본문과 동적 필드를 data JSON으로 저장
channels 피드백이 소속된 채널
feedbacks_issues_issues 피드백과 이슈의 다대다 연결

ABC 피드백 엔티티:

apps/api/src/domains/admin/feedback/feedback.entity.ts

5. 티켓 ID와 피드백 ID

Secretary 티켓 ID와 ABC 피드백 ID는 서로 다른 식별자입니다.

Secretary ticket_id     = 관리 티켓 식별자
ABC feedback_id         = ABC 피드백 식별자
abc_feedback_mappings   = 두 식별자를 연결하는 매핑

관리 API 응답에서는 보통 다음과 같이 ABC ID가 함께 노출됩니다.

{
  "ticket_id": 101,
  "extra_fields": {
    "abc_feedback_id": "345"
  }
}

이 매핑을 이용해 관리 콘솔은 티켓 정보와 ABC 피드백 정보, 이슈 연결 정보를 함께 처리합니다.

6. 관리페이지 조회 흐름

실제 운영 관리 콘솔은 Secretary API를 기준으로 티켓 목록을 조회합니다.

GET /api/support/workspaces/{workspaceCode}/tickets
        │
        ├─ support_tickets 조회
        ├─ abc_feedback_mappings 확인
        ├─ 담당자·권한 정보 결합
        ├─ 댓글·첨부파일 정보 결합
        └─ ABC 피드백과 상태 동기화

피드백 전용 모드에서 이 저장소의 목록 Proxy는 외부 관리 콘솔 API를 그대로 호출합니다.

관련 파일:

apps/web/src/pages/api/support/workspaces/[workspaceCode]/tickets.ts

관리 콘솔에서 처리하는 주요 데이터는 다음과 같습니다.

  • 피드백 목록과 상세 내용
  • 피드백 처리 상태
  • 담당자 지정
  • 사용자 댓글
  • 내부 메모
  • 첨부파일
  • ABC 이슈 연결 상태

7. 이 저장소에 있는 기존 ABC 관리자 화면

이 저장소에는 기존 ABC 관리자 화면도 남아 있습니다.

/main/project/{projectId}/feedback

페이지:

apps/web/src/pages/main/project/[projectId]/feedback.tsx

이 화면은 Secretary 티켓 목록이 아니라 ABC 관리자 API를 직접 조회합니다.

POST /api/admin/projects/{projectId}/channels/{channelId}/feedbacks/search

ABC API의 검색 요청은 다음 서버 로직으로 처리됩니다.

apps/api/src/domains/admin/feedback/feedback.service.ts

검색 데이터는 설정에 따라 다음 중 하나에서 조회됩니다.

  • ABC MySQL의 feedbacks 테이블
  • OpenSearch의 피드백 인덱스

따라서 이 화면은 실제 외부 관리 콘솔의 Secretary 기반 관리 화면과 데이터 조회 기준이 다를 수 있습니다.

8. 화면별 역할 비교

화면 주요 데이터 원천 역할
/support/{workspaceCode}/new 외부 관리 콘솔 등록 API 피드백 작성
외부 관리 콘솔 feedback.hmac.kr Secretary + ABC 실제 운영 관리
/main/project/{projectId}/feedback ABC API 직접 조회 기존 ABC 관리자 화면
/admin/issues Secretary 티켓 API 또는 스텁 데모·보조 관리 화면
/ops Secretary 티켓 API 또는 스텁 승인 큐 데모 화면

피드백 전용 전환 문서의 목표는 이 저장소에서 작성 화면만 제공하고, 목록·상세·관리 기능은 외부 관리 콘솔에서 유지하는 것입니다.

9. 첨부파일 흐름

작성 페이지에서 첨부파일을 선택하면 브라우저의 FormData에 포함됩니다.

브라우저
→ Next.js Proxy
→ 외부 관리 콘솔/Secretary API
→ Secretary Local 또는 R2 저장소
→ attachments 테이블에 메타데이터 저장

현재 작성 화면의 제한은 다음과 같습니다.

  • 파일당 최대 30MB
  • 전체 최대 30MB
  • 최대 10개
  • 이미지 외 일반 파일도 업로드 가능

첨부파일은 피드백 본문 JSON에 직접 저장되지 않고 별도 저장소와 attachments 메타데이터로 관리됩니다.

10. 네이버웍스 알림 흐름

피드백 작성 웹은 네이버웍스 API를 직접 호출하지 않습니다. 피드백 등록 후 ABC API와 기존 관리 콘솔의 백엔드 알림 파이프라인에서 네이버웍스 알림을 처리합니다.

피드백 작성
→ Secretary가 내부 티켓 저장
→ ABC API가 feedbacks 저장
→ FEEDBACK_CREATION 이벤트 발생
→ 알림 수신자 계산
→ 네이버웍스 사용자 ID 조회
→ 네이버웍스 Bot 메시지 발송
→ notification_deliveries에 결과 저장

10.1 알림 이벤트 발생

ABC의 FeedbackService.create는 피드백 저장 후 FEEDBACK_CREATION 이벤트를 발생시킵니다.

apps/api/src/domains/admin/feedback/feedback.service.ts
        │
        │ EventTypeEnum.FEEDBACK_CREATION
        ▼
apps/api/src/domains/admin/project/webhook/notification-internal.listener.ts

트랜잭션 커밋 전에 알림이 조회되지 않도록, 생성 이벤트 처리 시 저장 완료 후 피드백을 다시 조회합니다.

알림 이벤트에는 다음 정보가 포함됩니다.

  • projectId
  • channelId
  • feedbackId
  • 피드백 제목
  • 작성자 이메일
  • 담당자 이메일
  • 현재 피드백 상태
  • 비밀글 여부

10.2 알림 대상

수신자 계산은 notification-recipient.router.ts에서 수행합니다.

신규 피드백과 상태 변경 시 대상은 다음과 같습니다.

  • 해당 피드백의 담당자
  • 해당 프로젝트의 PROJECT_MANAGER 또는 Admin 역할 사용자
  • 피드백 작성자

관리자 댓글 등록 시에는 해당 피드백 작성자에게만 보냅니다.

같은 사용자가 여러 역할에 해당하면 이메일 기준으로 중복 제거하여 한 번만 발송합니다. 프로젝트 관리자는 ABC의 프로젝트 멤버와 Secretary의 관리자 조회 결과를 함께 사용합니다.

ABC project/channel
        │
        ├─ ABC DB의 프로젝트 관리자 조회
        ├─ Secretary API의 프로젝트 관리자 조회
        ├─ 피드백 담당자 추가
        └─ 피드백 작성자 추가
                │
                ▼
        이메일 기준 중복 제거

수신자 이메일은 네이버웍스 API에서 실제 사용자 ID로 변환됩니다. 이메일 또는 사용자 매핑이 확인되지 않으면 임의 사용자나 전체 방으로 대체 발송하지 않습니다.

10.3 네이버웍스 발송

실제 발송은 NaverWorksClient에서 수행합니다.

  1. 네이버웍스 Access Token을 확인합니다.
  2. 설정된 이메일로 네이버웍스 사용자 ID를 조회합니다.
  3. Bot ID와 사용자 ID를 사용해 개인 메시지를 발송합니다.
  4. 발송 성공·실패 결과를 저장합니다.

인증 방식은 두 가지를 지원합니다.

  • NAVER_WORKS_ACCESS_TOKEN 직접 사용
  • Client ID, Client Secret, Service Account, Private Key를 이용한 JWT Bearer 인증

관련 환경변수는 API 서버에만 설정해야 합니다.

NAVER_WORKS_ENABLED
NAVER_WORKS_API_BASE_URL
NAVER_WORKS_AUTH_URL
NAVER_WORKS_ACCESS_TOKEN
NAVER_WORKS_BOT_ID
NAVER_WORKS_DEFAULT_ROOM_ID
NAVER_WORKS_CLIENT_ID
NAVER_WORKS_CLIENT_SECRET
NAVER_WORKS_SERVICE_ACCOUNT
NAVER_WORKS_PRIVATE_KEY

피드백 전용 작성 웹에는 이 값들을 넣지 않습니다.

10.4 메시지 구성

메시지는 notification-message.builder.ts에서 생성합니다.

기본 메시지에는 다음 정보가 포함됩니다.

  • 이벤트 종류
  • 피드백 ID
  • 피드백 제목
  • 상태 변경 전·후 상태
  • 관리자 공개 댓글 내용
  • 기존 관리자 상세 페이지 링크

비밀글 작성자에게 보내는 메시지는 제목·본문·댓글 원문을 노출하지 않고 피드백 ID 중심으로 최소화합니다. 전화번호, IP 주소, MAC 주소는 기본 알림에 포함하지 않습니다.

10.5 알림 대상 이벤트

이벤트 기본 수신자 조건
FEEDBACK_CREATION 담당자, 프로젝트 관리자, 작성자 신규 피드백 등록
FEEDBACK_STATUS_CHANGE 담당자, 프로젝트 관리자, 작성자 이전 상태와 현재 상태가 다름
FEEDBACK_COMMENT_CREATION 작성자 관리자의 공개 댓글 등록

다음 이벤트는 현재 네이버웍스 피드백 알림 대상이 아닙니다.

  • 내부 메모 등록·수정·삭제
  • 관리자 공개 댓글 수정·삭제
  • 이슈 상태 변경
  • Gitea 상태 변경
  • 같은 상태로 다시 저장한 상태 변경

10.6 중복 및 실패 처리

알림 서비스는 notification_deliveries 테이블에 이벤트별 발송 결과를 기록합니다.

주요 상태:

  • RECEIVED: 발송 처리 대상 등록
  • SENT: 발송 성공
  • SKIPPED: 대상 없음 또는 알림 제외
  • FAILED: 발송 실패

이벤트와 수신자 조합으로 Idempotency Key를 생성하므로 동일 이벤트가 반복 수신되어도 같은 사용자에게 중복 발송하지 않습니다.

네이버웍스 발송은 네트워크 오류, 408, 429, 5xx 응답에 대해 제한적으로 재시도합니다. 400, 403, 사용자 매핑 실패와 같은 영구 오류는 반복하지 않고 실패 이력으로 남깁니다.

발송 실패는 피드백 등록 실패와 분리됩니다. 즉, 피드백이 ABC와 Secretary에 정상 저장된 뒤 네이버웍스 알림만 실패할 수 있습니다.

11. 현재 운영 기준 요약

사용자 입력
→ /support/{workspaceCode}/new
→ /api/support/workspaces/{workspaceCode}/submit
→ 외부 관리 콘솔 API
→ Secretary support_tickets 저장
→ ABC feedbacks 저장
→ abc_feedback_mappings로 연결
→ 외부 관리 콘솔에서 조회·상태변경·댓글·이슈처리

정리하면 작성 페이지와 관리페이지는 프론트엔드 상태를 직접 공유하지 않습니다. 두 시스템은 다음 정보를 기준으로 서버 데이터에서 연결됩니다.

workspace_code
→ Secretary ticket_id
→ abc_feedback_id
→ ABC project/channel

참고 파일

  • FEEDBACK_ONLY_TASKS.md
  • apps/web/src/pages/support/[workspaceCode]/new.tsx
  • apps/web/src/pages/api/support/workspaces/[workspaceCode]/submit.ts
  • apps/web/src/pages/api/support/workspaces/[workspaceCode]/tickets.ts
  • apps/web/src/server/support-external.ts
  • apps/web/src/server/support-auth.ts
  • apps/secretary-api/app/api/routes/tickets.py
  • apps/secretary-api/app/services/ticket_service.py
  • apps/secretary-api/app/db/models.py
  • apps/api/src/domains/admin/feedback/feedback.entity.ts
  • apps/api/src/domains/admin/feedback/feedback.service.ts
  • apps/api/src/domains/admin/project/webhook/notification-internal.listener.ts
  • apps/api/src/domains/admin/project/webhook/notification-recipient.router.ts
  • apps/api/src/domains/admin/project/webhook/webhook-notification.service.ts
  • apps/api/src/domains/admin/project/webhook/notification-message.builder.ts
  • apps/api/src/domains/admin/project/webhook/naver-works.client.ts
  • apps/api/src/domains/admin/project/webhook/notification-delivery.entity.ts