Files
baron_qa_write/docs/관리페이지 md 파일/# EG-BIM Q&A 로그인부터 글 저장까지 전이맵.md
T
root 9bbd9ed8ce
Deploy EG-BIM QA Gateway / deploy (push) Successful in 40s
디렉토리 구조 개선(egbim 분리)
2026-09-21 16:48:42 +09:00

25 KiB

EG-BIM Q&A 로그인부터 글 저장까지 전이맵

기준일: 2026-09-21
대상: qa-test.baroncs.co.kr / EG-BIM Q&A
구성: 목록(index.html) · 작성(write.html) · 상세(detail.html) · 관리페이지 · WORKS 알림

1. 전체 흐름

홈페이지 로그인 정보를 Q&A 사이트로 직접 전달하지 않는다. 홈페이지의 Q&A 링크는 별도 호스트로 이동하고, Q&A는 같은 BRSW OIDC SSO에 직접 인증을 요청한다. 이미 중앙 SSO 세션이 있으면 사용자는 로그인 화면을 보지 않고 Q&A 세션을 발급받는다.

flowchart TD
    A[바론 홈페이지<br/>EG-BIM Q&A 링크] --> B[Q&A 목록 진입<br/>https://qa-test.baroncs.co.kr/egbim/]
    B --> C{Q&A 세션 쿠키<br/>baron_qa_session 유효?}

    C -- 예 --> G[정적 목록 페이지 표시]
    C -- 아니오 --> D[302 /auth/login<br/>return_url 보관]
    D --> E[Worker가 PKCE 생성<br/>state · verifier · nonce]
    E --> F[BRSW OIDC SSO<br/>app.brsw.kr/oidc]
    F --> F1{중앙 SSO 세션 존재?}
    F1 -- 아니오 --> F2[SSO 로그인 화면]
    F2 --> F3[최초 동의 화면<br/>필요 시 1회]
    F1 -- 예 --> H[승인 코드 발급]
    F3 --> H
    H --> I[/auth/callback?code&state]
    I --> J[Worker가 state 검증<br/>PKCE code_verifier 검증]
    J --> K[Token Endpoint 호출<br/>Public Client · client_secret 없음]
    K --> L[UserInfo 조회 및 claim 정규화]
    L --> M[baron_qa_session 발급<br/>HttpOnly · Secure · SameSite=Lax]
    M --> G

    G --> N[문의 등록 버튼]
    N --> O[작성 페이지<br/>write.html]
    O --> P[GET /auth/session<br/>작성자·tenant 표시]
    P --> Q{userUuid와 tenantId 존재?}
    Q -- 아니오 --> R[제출 차단<br/>다시 로그인 안내]
    Q -- 예 --> S[카테고리·제목·내용·비밀글 입력]
    S --> T[등록 버튼 클릭]
    T --> U[브라우저 UUID 생성<br/>feedbackId]
    U --> V{첨부파일 존재?}
    V -- 아니오 --> Y[첨부 메타데이터 빈 배열]
    V -- 예 --> W[POST presign 요청]
    W --> X[qa_cdn presigned URL로<br/>파일 PUT 업로드]
    X --> Y[첨부파일 메타데이터 확정]
    Y --> Z[feedback envelope 생성]
    Z --> AA{apiBaseUrl 설정 여부}
    AA -- 비어 있음<br/>현재 테스트 모드 --> AB[localStorage에 임시 저장]
    AA -- 설정됨<br/>실서비스 모드 --> AC[POST /v1/qa/feedbacks<br/>feedback.hmac.kr API]
    AB --> AD[등록 완료 toast<br/>상세 페이지 이동]
    AC --> AE{API 성공?}
    AE -- 예 --> AD
    AE -- 아니오 --> AF[오류 표시<br/>재시도 가능]

2. 상태 전이표

상태 화면/주소 진입 조건 주요 처리 다음 상태
S0 홈페이지 Q&A 메뉴 클릭 외부 Q&A URL로 이동 S1
S1 /egbim/ Q&A 세션 유효 R2의 목록 HTML 제공 S5
S2 /auth/login 세션 없음 PKCE 상태 생성, SSO로 redirect S3
S3 app.brsw.kr/oidc SSO 세션 없음 최초 로그인 및 동의 S4
S4 /auth/callback code, state 수신 state/PKCE 검증, token/userinfo 조회 S5
S5 목록 또는 작성 페이지 baron_qa_session 유효 /auth/session에서 사용자 확인 S6
S6 write.html userUuid, tenantId 확인 작성 폼 입력 대기 S7
S7 작성 페이지 등록 클릭 feedbackId UUID 생성 및 입력 검증 S8
S8 작성 페이지 첨부 있음 presign → qa_cdn 업로드 S9
S9 작성 페이지 payload 준비 feedback/support ticket envelope 생성 S10
S10 API 또는 localStorage apiBaseUrl 상태에 따라 분기 실제 DB 저장 또는 테스트 저장 S11
S11 detail.html?id=... 저장 성공 등록 완료 및 상세 이동 종료

3. 화면별 사용자 경험

A. 홈페이지

  • EG-BIM 메뉴의 Q&A 링크만 제공한다.
  • 로그인 정보, 쿠키, token, SESSION_SECRET을 Q&A로 전달하지 않는다.
  • 링크 대상:
https://qa-test.baroncs.co.kr/egbim/

B. 중앙 SSO

  • Q&A RP는 https://app.brsw.kr/oidc를 사용한다.
  • 최초 사용자는 SSO 로그인 및 동의 화면을 볼 수 있다.
  • 같은 중앙 SSO 세션이 있으면 다음 접근부터 로그인 화면 없이 authorization code가 발급된다.
  • Q&A RP는 PKCE Public Client이므로 client secret을 보내지 않는다.

C. Q&A 목록

  • Worker가 baron_qa_session을 검사한다.
  • 세션이 없으면 /auth/login?return_url=...로 이동한다.
  • 세션이 있으면 R2의 egbim/index.html을 제공한다.

D. Q&A 작성

  • 브라우저가 GET /auth/session을 호출한다.
  • 다음 작성자 정보를 화면과 payload에 사용한다.
userUuid
ssoSubject / requesterId
tenantId / requesterTenantId
tenantIds
scope
roles
email
name
department
phone
  • requesterId 또는 requesterTenantId가 없으면 제출을 차단한다.

E. 글 저장

  • 브라우저에서 feedbackId UUID를 1회 생성한다.
  • 같은 UUID를 다음 식별자로 재사용한다.
feedback.id
feedback.source_record_id
support_tickets.idempotency_key
  • 첨부파일은 qa_cdn에 저장하고, DB에는 bucket/key 및 파일 메타데이터를 기록한다.
  • 실제 운영에서는 feedback API가 서버 측에서 Q&A 세션 또는 SSO token을 검증해야 한다.

4. 현재 테스트 모드와 운영 모드

현재 egbim/config.js는 다음과 같이 apiBaseUrl이 비어 있다.

apiBaseUrl: ''

따라서 현재 등록 결과는 다음과 같이 동작한다.

글 작성 → UUID 생성 → localStorage 저장 → 상세 페이지 이동

이 테스트 모드에서는 ABC DB에 저장되지 않으므로 관리페이지 목록에 나타나지 않고, FEEDBACK_CREATION 이벤트와 네이버웍스·SMS·카카오톡 알림도 발생하지 않는다. 관리페이지·알림까지 검증하려면 apiBaseUrl을 실제 API로 설정하고, 내부 수신자는 NAVER_WORKS_ENABLED=true와 WORKS 계정 매핑을, 외부 수신자는 외부 알림 게이트웨이·전화번호·카카오 템플릿을 준비해야 한다.

운영 API 주소를 설정하면 다음 흐름으로 변경된다.

첨부 presign 요청
→ qa_cdn 직접 업로드
→ feedback.hmac.kr/v1/qa/feedbacks 호출
→ feedbacks/support_tickets 트랜잭션 저장
→ 상세 페이지 이동

5. 주요 실패 전이

실패 지점 사용자 화면 원인/확인 항목
SSO 로그인 전 로그인 화면 중앙 SSO 세션 없음 또는 다른 SSO 환경
callback invalid_oauth_state OAuth cookie 만료, 호스트 변경, state 불일치
token 교환 oauth_token_exchange_failed issuer/endpoint/client ID/PKCE 설정 불일치
세션 확인 authenticated:false baron_qa_session 없음·만료·SESSION_SECRET 불일치
작성자 확인 UUID/tenant 오류 SSO scope 또는 claim mapping 누락
첨부 업로드 업로드 실패 presign API 또는 qa_cdn 권한 오류
DB 저장 API 요청 오류 apiBaseUrl, CORS, API 인증, DB envelope 규격 오류

6. 관리페이지와 ABC API 사이의 주고받기

Q&A 작성 페이지와 관리페이지는 서로의 화면을 직접 호출하지 않는다. 두 화면 모두 같은 ABC UserFeedback API를 사용하고, feedbackId를 공통 식별자로 사용한다.

sequenceDiagram
    participant Q as EG-BIM Q&A
    participant A as ABC API<br/>feedback.hmac.kr
    participant DB as ABC DB
    participant M as 통합 관리페이지<br/>Next.js 서버 프록시
    participant S as Secretary API

    Q->>A: POST feedbacks<br/>x-api-key + feedback envelope
    A->>DB: feedback 저장<br/>feedbackId 생성·중복 확인
    A-->>Q: { id: feedbackId }

    M->>A: workspaceCode로 project/channel 매핑 조회
    A-->>M: projectId, channelId
    M->>A: POST /api/v2/.../feedbacks/search
    A-->>M: feedback 목록(items)
    M->>A: GET .../feedbacks/{feedbackId}/comments
    A-->>M: 공개 댓글 목록

    M->>A: PATCH .../feedbacks/{feedbackId}<br/>상태·필드 변경
    A-->>M: 성공 응답
    M->>A: POST .../feedbacks/{feedbackId}/comments<br/>관리자 공개 댓글
    A-->>M: 저장된 comment
    M->>S: 담당자 지정·조회
    S-->>M: 담당자·처리 메타데이터

6.1 관리페이지 진입 시 식별자 매핑

관리페이지는 화면의 workspaceCode를 ABC의 실제 프로젝트·채널 UUID로 변환한 뒤 요청한다.

단계 요청/응답 목적
1 GET /api/internal/support/workspace-mappings?workspaceCodes={workspaceCode} workspace와 projectId·channelId 매핑 조회
2 x-api-key: MASTER_API_KEY 내부 매핑 API 인증
3 SECRETARY_ABC_API_KEY 관리페이지 서버가 ABC API를 호출할 때 사용하는 서비스 키
4 매핑 결과 캐시(현재 30초) 같은 화면에서 반복 매핑 요청 감소

이 매핑이 실패하면 관리페이지는 ABC 피드백을 조회하거나 저장할 수 없다. workspaceCode와 ABC의 프로젝트·채널 이름/UUID 매핑을 먼저 확인한다.

6.2 목록·상세 조회

현재 관리페이지의 ABC 연동은 Next.js 서버 라우트가 API 키를 보관하고 브라우저 요청을 ABC API로 중계하는 방식이다.

관리 동작 관리페이지 서버의 처리 ABC API 요청 응답/화면 반영
피드백 목록 workspace 매핑 후 목록 조회 POST /api/v2/projects/{projectId}/channels/{channelId}/feedbacks/search items를 목록·대시보드에 표시
피드백 상세 동일한 feedbackId로 대상 피드백 조회 GET /api/projects/{projectId}/channels/{channelId}/feedbacks/{feedbackId} 또는 매핑된 목록 조회 제목·내용·작성자·상태·이슈 표시
공개 댓글 조회 includeInternal=false로 조회 GET /api/projects/{projectId}/channels/{channelId}/feedbacks/{feedbackId}/comments Q&A 작성자에게 공개되는 댓글만 표시
담당자 조회/지정 Secretary API로 전달 /api/tickets/{ticketId}/assignee assignee_id, assignee_tenant_id, 이름·이메일 표시

관리페이지 목록의 ticketId 또는 화면 표시 번호는 화면용 값일 수 있다. ABC DB와 API에서의 정식 식별자는 항상 원래의 feedbackId UUID다.

6.3 관리페이지에서 변경하는 데이터

상태 변경

  1. 관리자가 상태를 선택한다.
  2. Next.js 서버 라우트가 관리자 세션과 권한을 확인한다.
  3. feedback_status 필드의 허용 옵션을 확인한다.
  4. ABC의 PATCH /api/projects/{projectId}/channels/{channelId}/feedbacks/{feedbackId}로 상태를 저장한다.
  5. 실제 상태가 변경된 경우 ABC가 FEEDBACK_STATUS_CHANGE 이벤트를 발생시킨다.
  6. 관리페이지는 저장된 상태로 화면을 갱신하고, WORKS 알림은 별도 비동기 흐름으로 처리한다.

관리페이지 프록시 경로는 다음과 같다.

PATCH /api/support/tickets/{ticketId}/feedback-status
  → updateAbcSupportFeedbackStatus()
  → PATCH /api/projects/{projectId}/channels/{channelId}/feedbacks/{feedbackId}

담당자 지정

담당자 정보는 assignee_id, assignee_tenant_id, assignee_name, assignee_email을 사용한다. 관리페이지는 담당자 지정 요청을 Secretary API로 보내고, 이후 목록·상세 조회에서 해당 값을 다시 읽는다.

담당자 이메일은 WORKS 알림 수신자 결정에도 사용되므로, 담당자 변경 후에는 이메일과 WORKS 계정 매핑이 함께 유효한지 확인한다.

공개 댓글·완료 안내

관리자 댓글은 다음 데이터로 ABC에 저장한다.

{
  "author_id": "관리자 SSO user id",
  "author_tenant_id": "관리자 tenant id",
  "author_name": "관리자 표시명",
  "content": "작성자에게 보여줄 답변",
  "is_internal": false,
  "actor_type": "ADMIN",
  "comment_type": "COMMENT"
}

관리자 공개 댓글은 POST /api/projects/{projectId}/channels/{channelId}/feedbacks/{feedbackId}/comments로 저장된다. comment_typeCOMPLETION_NOTICE로 저장하면 완료 안내로 취급하고, 연결된 이슈가 모두 완료된 경우 작성자의 완료 확인 단계로 넘어간다.

내부 메모는 공개 댓글과 다른 데이터다. Q&A 작성자에게 보여서는 안 되며, 현재 WORKS 일반 사용자 알림 대상에서도 제외한다.

6.4 작성자와 관리페이지의 왕복

처리 결과가 작성자에게 돌아가는 경로는 다음과 같다.

관리자 공개 댓글 저장
→ Q&A 상세 페이지에서 댓글 재조회
→ 관리자가 COMPLETION_NOTICE를 남긴 경우 완료 확인 버튼 노출
→ 작성자 POST /feedbacks/{feedbackId}/completion-confirmation
→ requester_id·requester_tenant_id 검증
→ 연결 이슈 완료 여부 확인
→ feedback_status를 완료로 변경
→ 상태 변경 이벤트 및 WORKS 알림

작성자의 추가 댓글은 같은 댓글 API로 저장된다. 작성자 댓글 이벤트가 발생하면 담당자와 프로젝트 관리자에게 WORKS 알림을 보내고, 완료 안내 대기 중이었다면 재문의 상태를 기록한다. 완료된 피드백을 작성자 댓글만으로 자동 재오픈하지는 않는다.

7. 이벤트와 사용자 유형별 알림 전이

피드백 저장 응답과 알림 발송 성공은 같은 단계가 아니다. ABC는 먼저 DB 저장 결과를 Q&A/관리페이지에 반환하고, 이벤트 리스너가 수신자의 사용자 유형을 판정한 뒤 알림 채널을 나누어 발송한다.

flowchart TD
    A[ABC feedback 저장 또는 관리자 변경] --> B[MySQL 저장]
    B --> C[EventEmitter 이벤트 발생]
    C --> D{이벤트 종류}

    D -->|FEEDBACK_CREATION| E[신규 피드백 수신자 결정]
    D -->|FEEDBACK_STATUS_CHANGE| F[상태 변경 전·후 확인]
    D -->|FEEDBACK_COMMENT_CREATION| G[댓글 작성자 유형 확인]

    E --> H[담당자·작성자·프로젝트 관리자 중복 제거]
    F --> H
    G -->|관리자 공개 댓글| I[작성자 1명]
    G -->|작성자 댓글| J[담당자·프로젝트 관리자]
    G -->|내부 메모| K[알림 제외]

    H --> L{수신자 사용자 유형 판정}
    I --> L
    J --> L
    L -->|사내 사용자·관리자·담당자| M[이메일로 WORKS userId 조회]
    M --> N[NAVER WORKS Bot API<br/>사용자별 메시지]
    L -->|외부 Q&A 작성자| O[카카오 알림톡 또는 SMS 발송]
    N --> P[알림 발송 이력 저장]
    O --> P
    P --> Q{SENT / FAILED / SKIPPED}

7.1 이벤트별 수신자

ABC 이벤트 발생 시점 사내 수신자: 네이버웍스 외부 작성자: SMS·카카오톡
FEEDBACK_CREATION Q&A 글 DB 저장 완료 담당자, 프로젝트 관리자, 작성자가 사내 사용자인 경우 외부 작성자에게 접수 완료 알림
FEEDBACK_STATUS_CHANGE 상태가 실제로 달라짐 담당자, 프로젝트 관리자, 작성자가 사내 사용자인 경우 외부 작성자에게 이전 상태 → 현재 상태 알림
FEEDBACK_COMMENT_CREATION + 관리자 관리자가 공개 댓글 저장 수신 대상이 사내 작성자이면 WORKS 외부 작성자에게 답변 등록 알림
FEEDBACK_COMMENT_CREATION + 작성자 작성자가 추가 댓글 저장 담당자, 프로젝트 관리자 외부 작성자에게는 별도 알림 없음
내부 메모 내부 협업 메모 저장 발송하지 않음 외부 작성자에게 절대 노출하지 않음

같은 사람이 여러 역할을 가지고 있어도 채널별 한 번만 발송한다. 수신자는 이벤트 payload의 임의 이메일이나 전화번호를 그대로 신뢰하지 않고, 피드백의 담당자·작성자·프로젝트 권한과 사용자 유형을 서버에서 다시 조회해 결정한다.

7.2 알림 채널 분류

알림 채널은 역할명이 아니라 수신자의 사용자 유형으로 결정한다.

수신자 유형 대상 기본 채널 식별·연락처 기준
사내 사용자 Q&A 작성자 중 회사 내부 사용자 네이버웍스 SSO subject·tenant·회사 소속 정보, WORKS 계정 이메일
관리자 시스템 관리자·프로젝트 관리자 네이버웍스 내부 권한과 활성 계정, WORKS 계정 이메일
담당자 피드백 담당자 네이버웍스 assignee_id·assignee_tenant_id, assignee_email
외부 사용자 회사 외부 Q&A 작성자 카카오 알림톡 또는 SMS 인증된 작성자 프로필의 requester_phone_number

외부 사용자는 네이버웍스 계정이 없다는 이유만으로 분류하지 않는다. SSO의 테넌트·회사 소속 정보와 서비스의 사용자 분류를 기준으로 외부 여부를 판정한다. 외부 작성자에게는 네이버웍스 메시지를 보내지 않는다.

7.3 사내 사용자·관리자·담당자: WORKS 발송

이벤트 수신
→ idempotency key 중복 확인
→ 사내 수신자만 WORKS 대상자로 분류
→ SSO 이메일을 NAVER WORKS userId로 조회
→ Bot API 사용자 메시지 발송
→ WORKS 발송 결과 기록
  • 사용자별 메시지 경로를 사용하며, 수신자 매핑 실패를 전체 방 발송으로 대체하지 않는다.
  • NAVER_WORKS_ENABLED=false이면 발송하지 않는다.
  • access token은 직접 설정된 값 또는 JWT bearer 방식으로 발급받는다.
  • 네트워크 오류, 408, 429, 5xx는 설정된 횟수까지 재시도한다.
  • 중복 이벤트는 eventId 또는 이벤트·피드백·댓글 조합의 idempotency key로 차단한다.
  • WORKS 발송 상태는 RECEIVED, SENT, FAILED, SKIPPED로 기록한다.

7.4 외부 사용자: 카카오톡·SMS 발송

외부 작성자 알림은 외부 알림 게이트웨이를 통해 처리한다. 카카오톡은 거래성 안내에 적합한 승인 템플릿이 준비된 경우 알림톡을 우선 사용하고, 카카오톡 발송 불가·수신자 미매핑·실패 시 SMS로 대체하는 방식을 기본안으로 둔다.

flowchart LR
    A[외부 작성자 대상 이벤트] --> B[requester_phone_number 확인]
    B --> C{카카오 알림톡 사용 가능?}
    C -->|예| D[카카오 알림톡 발송]
    C -->|아니오| E[SMS 발송]
    D --> F{성공?}
    F -->|예| G[발송 완료 기록]
    F -->|아니오| E
    E --> H{성공?}
    H -->|예| G
    H -->|아니오| I[실패·재처리 대상 기록]

외부 알림 발송 순서는 다음과 같다.

이벤트 수신
→ requester가 외부 사용자임을 서버에서 판정
→ 인증된 requester_phone_number 조회
→ 카카오 알림톡 템플릿·발송 가능 여부 확인
→ 카카오 알림톡 발송
→ 실패 또는 미사용 시 SMS fallback
→ 채널별 발송 결과와 실패 사유 기록
  • 전화번호가 없거나 검증되지 않은 경우 임의 번호로 보내지 않고 SKIPPED 또는 FAILED로 남긴다.
  • 외부 알림에는 내부 메모, SSO token, 관리자 URL, WORKS 인증정보를 포함하지 않는다.
  • 비밀글은 제목·본문·댓글 원문을 넣지 않고, Q&A 상세 페이지에서 권한을 확인할 수 있는 최소 안내만 보낸다.
  • 외부 사용자에게 보내는 링크는 관리페이지가 아니라 Q&A 상세 페이지 링크를 사용한다.
  • 카카오 알림톡 템플릿 ID, SMS 발신번호, 통신사/메시지 공급자 설정은 운영 환경별 비밀 설정으로 관리한다.
  • 외부 알림도 이벤트별·수신자별 idempotency key를 사용해 카카오톡과 SMS가 중복 발송되지 않도록 한다.

현재 저장소에는 WORKS 발송 어댑터가 구현되어 있지만, 외부 사용자용 카카오톡·SMS 발송 어댑터와 수신자 유형별 분기 로직은 별도 구현 범위로 관리해야 한다. 특히 현재 NotificationRecipientRouter가 생성·상태 변경 이벤트에서 requester_email을 WORKS 대상에 포함하므로, 외부 작성자를 WORKS에서 제외하고 외부 알림 라우터로 보내는 변경이 필요하다.

7.5 WORKS 메시지와 외부 알림의 개인정보 보호

  • 일반 관리자 수신자에게는 피드백 ID·제목·상태·댓글 일부·관리페이지 상세 링크를 보낸다.
  • 외부 작성자에게는 피드백 ID·상태·답변 등록 여부 등 최소 정보와 Q&A 상세 링크만 보낸다.
  • 비밀글 작성자에게는 본문·제목·댓글 원문을 보내지 않고, 권한 검증이 필요한 Q&A 상세 링크만 보낸다.
  • SSO token, Webhook token, WORKS access token·client secret·private key는 메시지나 로그에 기록하지 않는다.
  • 메시지 최대 길이는 현재 NAVER_WORKS_MAX_MESSAGE_LENGTH 설정값(기본 1,000자)을 따른다.

외부 알림에는 별도의 채널별 최대 길이와 템플릿 버전을 둔다. notification_deliveries를 확장하거나 별도 외부 알림 이력 테이블을 두어 다음 정보를 남기는 것을 권장한다.

recipient_type: INTERNAL | EXTERNAL
channel: NAVER_WORKS | KAKAO_ALIMTALK | SMS
recipient_id: 내부 userId 또는 마스킹된 전화번호 식별자
template_id / template_version
status: RECEIVED | SENT | FAILED | SKIPPED
attempts / last_error / sent_at

7.6 프로젝트 Webhook과 알림 채널의 구분

아래 세 경로는 이름이 비슷하지만 역할이 다르다.

경로 방향 용도 WORKS 발송과의 관계
프로젝트 Webhook 설정 관리페이지 → ABC 프로젝트별 외부 Webhook URL·이벤트·채널 범위 관리 외부 시스템 연동용. WORKS 직접 발송과 별도
POST /integrations/abc/webhooks 외부 시스템 → API 인증된 ABC Webhook 이벤트를 수신해 알림 채널 라우터로 전달 ABC_WEBHOOK_ENABLED가 켜진 외부 수신 경로
NotificationInternalListener ABC API 내부 이벤트 → 알림 라우터 Q&A/관리자 변경 직후 수신자 유형에 따라 WORKS·외부 채널로 라우팅 현재 Q&A 저장·관리 변경의 기본 경로

따라서 같은 API 프로세스 안에서 발생한 피드백 생성·상태 변경·댓글 이벤트의 알림은 외부 Webhook 왕복을 전제로 하지 않는다. ABC_WEBHOOK_ENABLED는 외부 Webhook 수신을 사용할 때 필요한 설정이고, 내부 수신자는 NAVER_WORKS_ENABLED와 WORKS 인증·수신자 매핑을, 외부 수신자는 외부 알림 게이트웨이와 전화번호·템플릿 설정을 확인한다.

8. 전이 상태 요약

상태 화면/시스템 진입 이벤트 주고받는 데이터 다음 상태
S12 관리페이지 목록 workspace 진입 workspaceCode ↔ projectId/channelId, feedback search S13
S13 관리페이지 상세 목록에서 feedbackId 선택 피드백 본문·작성자·상태·이슈·공개 댓글 S14
S14 ABC 피드백 저장 Q&A 등록 또는 관리 변경 feedbackId, dynamic fields, source/idempotency key S15
S15 이벤트 처리 생성·상태·댓글 이벤트 이벤트 타입, projectId, channelId, feedbackId S16
S16 수신자 유형 판정 사내 사용자·관리자·담당자 또는 외부 작성자 식별 user type, assignee/requester/project admin S17 또는 S18
S17 WORKS 발송 기록 사내 userId 조회 및 Bot API 호출 channel, target userId, status, attempts, error 종료 또는 재시도
S18 SMS·카카오톡 발송 기록 외부 전화번호·템플릿 조회 및 발송 channel, masked phone, template, status, attempts 종료 또는 재시도
S19 작성자 완료 확인 공개 완료 안내 후 작성자 확인 requesterId, requesterTenantId, feedbackId 완료 상태 및 S15

9. 운영 전 검증 체크리스트

  • workspaceCode가 정확한 ABC projectId·channelId로 매핑된다.
  • Q&A 저장 결과의 feedbackId가 관리페이지 상세의 feedbackId와 같다.
  • 관리페이지 목록·상세에서 제목·내용·작성자·비밀글 여부·상태·첨부가 일치한다.
  • 관리자가 상태를 바꾸면 ABC 상태가 바뀌고, 같은 상태 재저장에는 중복 알림이 없다.
  • 관리자 공개 댓글이 Q&A 상세에서 보이고, 내부 메모는 보이지 않는다.
  • COMPLETION_NOTICE 저장 후 작성자만 완료 확인을 할 수 있다.
  • 신규 피드백 알림이 사내 담당자·프로젝트 관리자에게 WORKS로 중복 없이 도착한다.
  • 사내 작성자에게는 WORKS로, 외부 작성자에게는 SMS·카카오톡으로 알림이 간다.
  • 관리자 공개 댓글 알림은 외부 작성자에게 SMS·카카오톡으로 도착한다.
  • 작성자 추가 댓글 알림은 사내 담당자·프로젝트 관리자에게 WORKS로 도착한다.
  • 비밀글의 본문·제목·댓글 원문이 WORKS 메시지에 노출되지 않는다.
  • WORKS 계정 매핑 실패 시 전체 방으로 오발송되지 않고 FAILED 또는 SKIPPED로 남는다.
  • 외부 전화번호 매핑 실패 시 임의 번호로 보내지 않고 FAILED 또는 SKIPPED로 남는다.
  • 카카오 알림톡 실패 시 SMS fallback이 한 번만 수행된다.
  • WORKS·카카오톡·SMS의 발송 성공·실패·재시도 횟수를 채널별로 확인할 수 있다.