feat(approvals): 결재 접근 차단 대응과 전표 전이 메모 전달 강화

- approvals 모듈에서 APPROVAL_ACCESS_DENIED 응답을 포착하여 ApprovalAccessDeniedException으로 변환하고 접근 거부 시 토스트·대시보드 리다이렉트를 처리

- approval history 조회가 서버 action id에 맞춰 필터링되도록 repository·controller·테스트를 보강

- 재고 트랜잭션 상태 전이 API 호출에 note를 전달하도록 repository·컨트롤러·통합/단위 테스트를 업데이트

- 승인 플로우 QA 체크리스트 및 연동 문서를 최신 계약과 테스트 흐름으로 업데이트
This commit is contained in:
JiWoong Sul
2025-10-31 16:43:14 +09:00
parent d76f765814
commit 3e83408aa7
35 changed files with 1056 additions and 470 deletions

View File

@@ -1,82 +1,65 @@
# 프런트엔드/백엔드 정합성 점검 리포트 (2025-10-21)
# 프런트엔드/백엔드 정합성 점검 리포트 (2025-10-23)
## 개요
- 기준 문서: `doc/backup/backend_change_requests.md`와 최신 계약 문서(`doc/stock_approval_system_api_v4.md`)를 토대로 Flutter 프런트(`superport_v2`)와 Rust 백엔드(`superport_api_v2`) 구현을 재검증했다.
- 백엔드 팀이 전달한 최신 패치(로그인/트랜잭션, 결재 단계, 대시보드·보고서, 권한)와 `cargo test` 통과 결과를 반영해 실제 로그인 → 대시보드 → 재고/결재 → 보고서/권한 흐름을 다시 점검했다.
- Approval Flow 전면 개편 합의를 위해 백엔드 작업 계획(`../superport_api_v2/doc/approval_flow_backend_task_plan.md`)과 프런트 작업 계획(`doc/approval_flow_frontend_task_plan.md`)을 신규 작성했다.
- 기준 문서: 갱신된 `backend_change_requests.md`(B8-2 완료)와 `stock_approval_system_api_v4.md`(Approval Flow v2 전면 개편 반영)를 토대로 Flutter 프런트(`superport_v2`)와 Rust 백엔드(`superport_api_v2`)의 계약을 재검증했다.
- 로그인 → 대시보드 → 재고/결재 → 보고서/권한까지 전 흐름을 재검증하고, 기본 목록 비노출 정책(B5-5) 적용 여부를 코드·테스트로 확인했다.
## 주요 정합성 결과
| 구분 | 내용 | 결과 | 후속 조치 |
| 구분 | 내용 | 상태 | 후속 조치 |
| --- | --- | --- | --- |
| 1 | 대여/출고 `expected_return_date` 저장·조회 | ✅ 해결 (`backend/src/domain/stock_transactions.rs:274`, `backend/src/adapters/repositories/stock_transactions.rs:808`) | 프런트 DTO·폼이 필드를 유지하는지 위젯 테스트로 확인 |
| 2 | 결재 단계 `q`·`status_id` 필터 및 `status` 응답 | ✅ 해결 (`backend/src/domain/approval_steps.rs:31`, `backend/src/adapters/repositories/approval_steps.rs:162`) | 검색/필터 UI와 리스트 표시가 새 계약(`status`)을 반영하는지 시나리오 테스트 필요 |
| 3 | 결재 단계 요청/응답 내 상태 필드 정규화 | ✅ 해결 (요청 `status_id`, 응답 `status`) | 프런트 DTO(`lib/features/approvals/step/domain/entities/approval_step_input.dart:30`)에서 레거시 `step_status_id` 제거 여부 확인 |
| 4 | 보고서 PDF 스트리밍·메타데이터 생성 | ✅ 해결 (`backend/src/api/v1/reports.rs:94`) | `ReportingRepositoryRemote`가 스트림·파일명 메타 처리하는지 합동 점검 |
| 5 | 그룹-메뉴 권한 `path`·`is_deleted`·`include_deleted` | ✅ 해결 (`backend/src/domain/group_menu_permissions.rs:149`, `backend/src/adapters/repositories/group_menu_permissions.rs:227`) | DTO/필터·권한 편집 UI가 추가 필드로 회귀 없는지 테스트 |
| 6 | 대시보드 KPI `delta` 전일 대비 비율 계산 | ✅ 해결 (`backend/src/adapters/repositories/dashboard.rs:61`) | KPI 카드/차트가 백분율·부호 표시를 지원하는지 확인 |
| 7 | 사용자 요약(`created_by`, `requester`) 기본 노출 및 회귀 테스트 | ✅ 해결 (`backend/src/domain/approval_templates.rs:34`, `backend/src/adapters/repositories/approval_templates.rs:100`, `backend/src/adapters/repositories/approvals.rs:878`, `backend/src/adapters/repositories/stock_transactions.rs:1173`, `backend/src/adapters/repositories/reports.rs:256`) | 프런트 DTO가 사번(`employee_id`)·이름을 모두 반영하는지, 리스트/리포트 표시가 정상인지 검증 |
| 8 | Approval Flow v2: 트랜잭션 결재 구성 필수화 + `/approval/*` 엔드포인트 확장 | 🚧 진행중 (`backend/src/domain/stock_transactions.rs:365`, `backend/src/domain/approvals/models.rs:583`, `backend/src/api/v1/approval_flow.rs:13`) | 프런트 DTO/리포지토리 확장(`lib/features/inventory/transactions/data/dtos/`, `lib/features/approvals/data/`) 및 기능 토글 기반 UI 연동 필요 |
| 1 | Approval Flow v2 API 문서 (`expected_updated_at`, drafts, 이력·지표) | ✅ 해결 | `tool/sync_stock_docs.sh`로 프런트 문서/DTO 재생성 |
| 2 | 결재/재고 응답 스키마(상태·메타데이터·중첩 객체) | ✅ 해결 | 프런트 DTO/위젯에 새 필드 반영 및 테스트 추가 |
| 3 | 전표 기본 목록 비노출 정책(B5-5) | ✅ 해결 | 기본 목록=승인·완료, 대기 영역은 `status=draft,submitted` 또는 `include_pending`으로 조회 |
| 4 | 보고서 Export(PDF/XLSX) 스트리밍·메타데이터 | ✅ 해결 | 감사 로그 확인 및 다운로드 UI 메타 필드 적용 |
| 5 | 그룹-메뉴 권한 `route_path`·`is_deleted`·`include_deleted` | ✅ 해결 | 편집 화면에 삭제 항목/경로 노출 및 회귀 테스트 |
| 6 | Prometheus 지표(`approval_flow_action_*`) 및 감사 로그 | ✅ 해결 | Ops 대시보드/알림 구성안 수립 |
아래 섹션에서 영역별 관찰 내용과 프런트엔드 후속 작업을 정리했다.
## 로그인 & 세션
- 변경 없음: 로그인/세션 API는 기존 계약과 동일하며(`backend/src/api/v1/login.rs`), 프런트 `AuthSessionDto` 매핑도 변동이 없다(`lib/features/auth/data/dtos/auth_session_dto.dart:17`).
- 체크포인트: 세션 만료 401 처리 시 백엔드 토큰 갱신 로직은 유지되므로, 프런트 재시도/로그아웃 UX를 QA 체크리스트에 유지한다.
- 추가 확인: `POST /api/v1/auth/refresh` 오류 메시지가 문서 규격(`token expired`, `token revoked`, `invalid token`)으로 일치하는지 스테이징 로그로 검증한다. 메시지 표준화가 미완료인 경우 `Failure` 매퍼에서 임시 매핑을 추가해야 한다.
- `backend/src/api/v1/auth.rs``data.access_token`, `data.refresh_token`, `data.expires_at`, `data.user`, `data.permissions`를 반환하며 오류 메시지는 문서 규격과 일치한다.
- 프런트 `AuthSessionDto` 매핑은 유지되지만, 알림 메시지가 영어 키(`invalid credentials`, `token expired` 등)에 맞춰 노출되는지 QA에서 다시 확인한다.
- 세션 만료 재로그인 UX는 기존대로 유지하되, 만료/재사용 토큰 구분 안내를 사용자에게 명확히 보여주는지 체크한다.
## 대시보드
- KPI `delta`가 전일 대비 증감률(예: `0.125` → 12.5%)로 채워지며(`backend/src/adapters/repositories/dashboard.rs:61`), 프런트는 % 포맷과 부호를 고려해 렌더링해야 한다(`lib/features/dashboard/presentation/widgets/dashboard_kpi_card.dart`).
- `step_summary` 포맷이 `"2단계 / 승인자"`에서 `"2단계 · 승인자"`로 정규화됐다. 문자열을 그대로 노출하는 UI라면 디자인팀과 표시 규칙을 다시 합의한다.
- 추가 활동: 대시보드 테스트에서 `delta != null` 기준으로 동작하는 메트릭 뱃지/차트 회귀 여부를 확인한다.
- `GET /api/v1/dashboard/summary``kpis[]`, `recent_transactions[]`, `pending_approvals[]`를 제공하고 `delta`·`trend_label`이 문서와 코드에 맞춰 채워진다(`backend/src/api/v1/dashboard.rs`).
- 프런트 KPI 카드에서 `delta`가 소수(0.125) → 백분율(12.5%)로 변환되는 로직과 `step_summary` 포맷(`"2단계 · 승인자"`)이 정상 노출되는지 UI 스냅샷 테스트를 업데이트한다.
## 재고·대여 트랜잭션
- `expected_return_date`가 생성/수정/조회 전 흐름에 포함된다(`backend/src/domain/stock_transactions.rs:274`, `backend/src/adapters/repositories/stock_transactions.rs:808`). 프런트 `StockTransactionInput``RentalPage`는 이미 필드를 전송하므로, 저장 후 상세/목록에서 값이 노출되는지 UI 테스트를 추가하면 된다(`lib/features/inventory/rental/presentation/pages/rental_page.dart:1651`).
- 마이그레이션 `migration/006_add_expected_return_date_to_stock_transactions.sql`을 반드시 적용해야 하며, 로컬/스테이징 DB에 컬럼이 없으면 500 에러가 발생한다. DevOps와 일정 합의 후 `diesel migration run`을 실행하고 `.env` DB URL을 재확인한다.
- 추가 확인: 고객 정보(`customers[].customer`), 거래 라인 메모, 템플릿명 등 선택 필드가 null일 때 키가 빠지지 않는지 샘플 데이터를 확보해 양쪽 DTO 직렬화/역직렬화 테스트를 보강한다.
- 최종 승인 완료 전에는 기본 입고/출고/대여 목록에서 전표가 숨겨져야 하므로, 프런트 목록/완료 카드에 `status=draft|submitted` 필터를 추가하고 대기 전용 섹션을 제공한다.
- 응답 본문이 거래/창고/라인/고객/결재 요약을 중첩 객체로 반환하고 `quantity`·`unit_price`의 null도 유지한다(`backend/src/api/v1/stock_transactions.rs`).
- 결재 전이 API가 `expected_updated_at`, `transaction_expected_updated_at`을 요구하며 최신 `data.transaction`/`data.approval`을 반환한다. 프런트는 낙관적 잠금 실패 시 메시지를 문서에 맞춰 노출해야 한다.
- 기본 목록은 승인·완료 상태만 반환하고, 초안·상신 전표는 `status=draft,submitted` 또는 `include_pending=true`로 별도 조회한다. (`backend/src/domain/stock_transactions.rs:74`, `backend/src/adapters/repositories/stock_transactions.rs:45`)
## 결재 단계
- 목록 API가 `q`·`status_id` 필터를 처리하고 응답에 `transaction_no`를 포함한다(`backend/src/adapters/repositories/approval_steps.rs:176`). 프런트 검색 바(`lib/features/approvals/step/presentation/controllers/approval_step_controller.dart`) 파라미터를 전달하는지, 리스트에서 거래번호를 표시하는지 확인한다.
- 도메인이 `status` 구조체(`{ id, name, code }`)를 반환한다(`backend/src/domain/approval_steps.rs:84`). 프런트 DTO는 `status_id` 입력과 `status` 응답을 모두 지원해야 하므로, 레거시 필드 제거와 단위 테스트(`test/features/approvals/step/domain/`) 성공 여부를 점검한다.
- 컨트롤러/위젯 테스트: 필터링, 상태 변경, 거래번호 표시 흐름을 추가해 회귀를 방지한다.
- 추가 확인: `histories[].action`에 레거시 데이터가 들어오는 경우(`id`, `name` 누락) 프런트가 안전하게 폴백 문자열을 표시하는지, 백엔드는 해당 케이스를 데이터 정제 로직으로 보완할지 정한다.
- 열람 권한은 상신자와 이미 결재한 승인자에게만 부여된다. 단계 미도달 승인자는 목록/상세 접근 시 403 처리되므로, 프런트 `ApprovalDetailPage`·`MyApprovals`에서 숨김/권한 안내 토스트를 구현하고 최종 승인 대기 상태에서도 상신자·중간 승인자만 접근 가능하도록 필터링한다.
## 결재 단계 & 행위
- `GET /api/v1/approval-steps``approver_id`, `approval_id`, `status_id`, `q` 필터와 `include=approval,approver,status` 확장을 지원한다. 프런트 컨트롤러 파라미터를 모두 전달하는지 점검한다.
- `/approval/**` 행위가 `expected_updated_at`을 요구하고 `data.approval`을 반환하며, Prometheus 지표(`approval_flow_action_total`, `approval_flow_action_duration_seconds`)가 발행된다.
- 열람 권한 정책이 상신자·기결재자에게만 상세 접근을 허용하므로, 프런트 `MyApprovals`·`ApprovalDetailPage`에서 403 시나리오 UX를 재확인한다.
## Approval Flow v2
- 입·출·대여 생성 요청에 `approval` 블록이 필수(`backend/src/domain/stock_transactions.rs:365`)이며, `approval.config`는 템플릿(`template_id`) 또는 직접 지정 단계(`steps[]`) 중 하나가 존재해야 한다(`backend/src/domain/stock_transactions.rs:384`). 프런트 입력모델(`lib/features/inventory/transactions/domain/entities/stock_transaction_input.dart:1`)은 `approval`을 선택이 아닌 필수 값으로 승격하고, 최소 1단계 + 최종 승인자 검증을 위젯 레벨에서 선반영해야 한다.
- 트랜잭션 목록 기본 필터는 승인 완료 건만 노출하고 `include_pending` 파라미터를 명시해야 대기/초안이 반환된다(`backend/src/domain/stock_transactions.rs:29`, `backend/src/domain/stock_transactions.rs:178`). 프런트 리스트 필터(`lib/features/inventory/transactions/domain/entities/stock_transaction_input.dart:158`)와 대시보드 카드가 새 파라미터를 전달하도록 조정하고, 결재 대기 전표 전용 섹션을 기능 토글(`feature.approval_flow_v2`)로 가드한다.
- 결재 제출·재상신 엔드포인트는 `ApprovalSubmitRequest`/`ApprovalResubmitRequest`를 사용하며 전 단계 배열을 전송해야 한다(`backend/src/domain/approvals/models.rs:583`, `backend/src/api/v1/approval_flow.rs:13`). 프런트는 `ApprovalRequestDto`·`ApprovalStepDto`·`ApprovalAuditDto` 신설 후 `ApprovalRepositoryRemote`를 통해 `/approval/submit|resubmit` 호출 시 단계 순번·승인자 ID를 직렬화한다.
- 승인/반려/회수 액션은 `actor_id`가 세션 사용자와 일치해야 하고 옵티미스틱 잠금(`expected_updated_at`, `transaction_expected_updated_at`)을 요구한다(`backend/src/domain/approvals/models.rs:624`, `backend/src/domain/approvals/models.rs:634`). 프런트 컨트롤러(`lib/features/approvals/presentation/controllers/approval_history_controller.dart`)는 서버 응답의 `approval.updated_at`을 저장해 재전송 시 파라미터로 포함해야 충돌 409를 피할 수 있다.
- 결재 상세 응답은 `current_step`, `steps[].status.is_blocking_next`, `histories[].action_code`를 포함하며 비허용 사용자에게는 `APPROVAL_ACCESS_DENIED`가 반환된다(`doc/stock_approval_system_api_v4.md:1011`, `backend/src/api/v1/approval_flow.rs:42`). DTO 파서(`lib/features/approvals/data/dtos/approval_dto.dart`)에서 새 서브 객체를 맵핑하고, 403 수신 시 접근 제한 안내를 표준 토스트로 노출한다.
- 프런트 데이터 계층에 `ApprovalSubmissionInput`/`ApprovalDecisionInput`/`ApprovalRecallInput`/`ApprovalResubmissionInput`을 추가하고, `ApprovalRepositoryRemote.submit|approve|reject|recall|resubmit|listHistory` 메서드를 신규 엔드포인트(`/approval/submit`, `/approval/approve`, `/approval/reject`, `/approval/recall`, `/approval/resubmit`, `/approval/history`)에 맞춰 구현했다. (`lib/features/approvals/domain/entities/approval.dart`, `lib/features/approvals/data/repositories/approval_repository_remote.dart`, 2025-10-29) — 기존 `create/update/assignSteps` 경로는 레거시 호환을 위해 유지하되, F2 단계에서 컨트롤러/유즈케이스를 새 흐름으로 전환할 예정이다.
## 결재 플로우 문서 & 모니터링
- `stock_approval_system_api_v4.md` `/approval`, `/approval-drafts`, 회수/재상신, 이력, 권한 정책, 예상 업데이트 시각(`expected_updated_at`)을 모두 포함한다.
- Prometheus 지표/Slack 알림 정책은 `doc/approval_flow_alert_policy.md`에 정리돼 있으니 Ops와 함께 대시보드 구성을 착수한다.
- 프런트 문서 동기화(`tool/sync_stock_docs.sh`)와 DTO 리프레시 후 회귀 테스트(`flutter analyze`, `flutter test`) 일정을 맞춘다.
## 보고서 (PDF)
- 백엔드가 PDF를 스트리밍으로 내려주고 파일명·Content-Length·ETag를 헤더에 포함한다(`backend/src/api/v1/reports.rs:94`). 프런트 `ReportingRepositoryRemote``StreamedResponse` 처리를 유지하되, 새 메타데이터(`report_name`, `generated_at`)로 다운로드 UI를 업데이트한다(`lib/features/reporting/presentation/controllers/reporting_controller.dart`).
- 단위 테스트(`backend/tests/api_reports_pdf.rs`)가 계약을 고정하고 있으므로, 프런트에서도 PDF 다운로드 및 실패 경로(404/500 등)를 위젯 테스트에 반영한다.
- 추가 확인: PDF 다운로드 요청이 감사 로그에 기록되는지 스테이징에서 확인하고, 정책상 필요 시 프런트 다운로드 성공/실패 토스트에 감사 로그 연동 여부를 표시한다.
## 보고서 (PDF/XLSX)
- `GET /api/v1/reports/transactions|approvals/export`가 스트리밍과 메타데이터 모드를 모두 지원하고, `download_url`, `filename`, `mime_type`, `expires_at`을 반환한다.
- 프런트 다운로드 UI는 새 메타 필드를 표시하고, 감사 로그(Download 요청 시 이벤트 남는지) 결과를 스테이징에서 확인한 뒤 UX 안내문구를 보강한다.
- 대용량 PDF/XLSX에 대한 합동 테스트를 QA 시나리오에 추가한다.
## 권한/문서
- 그룹-메뉴 권한 API가 `include_deleted=true` 시 삭제 항목을 함께 반환하고 각 항목에 `path`, `is_deleted`가 포함된다(`backend/src/domain/group_menu_permissions.rs:149`). 프런트 DTO(`lib/features/masters/group_permission/data/dtos/group_permission_dto.dart:49`)와 편집 UI가 새 필드를 사용하는지 확인한다.
- `doc/stock_approval_system_api_v4.md`가 갱신됐으므로, 프런트 문서는 `tool/sync_stock_docs.sh`로 재동기화한다.
- 추가 확인: 그룹-메뉴 배치 업데이트 API가 변경 이력을 남기는지 백엔드 로그로 점검하고, 프런트 편집 시 이력 누락에 대비한 사용자 안내를 준비한다.
- `GET /api/v1/group-menu-permissions``include_deleted`를 허용하고 `route_path`, `path`, `is_deleted`를 응답에 포함한다. 프런트 DTO와 편집 화면이 삭제 항목을 구분 표시하는지 확인한다.
- 백엔드/프런트 문서가 모두 최신 스펙을 참조하도록, `backend_change_requests.md`와 프런트 대응 문서를 동시에 업데이트한 후 공유한다.
## 공동 액션 아이템
| 구분 | 작업 내용 | 담당 | 상태 | 비고 |
| --- | --- | --- | --- | --- |
| DB | `006_add_expected_return_date_to_stock_transactions.sql` 적용 확인 | 백엔드 | 진행 예정 | 스테이징 DB 스키마 점검 후 공유 |
| 결재 | 단계 검색(`q`, `status_id`)·거래번호 노출 통합 테스트 | 프런트/백엔드 | 준비 | 계약 데이터 샘플 확보 필요 |
| 결재 | `histories.action` 레거시 데이터 폴백 처리 협의 | 프런트/백엔드 | 준비 | 데이터 정제 vs UI 폴백 선택 |
| 결재 | 열람 권한/대기 전표 노출 제한 구현 (`draft`,`submitted` 접근 제어) | 프런트/백엔드 | 준비 | API 403/필터 명세 동기화 |
| 보고서 | Approvals/Transactions PDF 스트리밍 합동 점검 | 프런트/백엔드 | 준비 | 대용량 파일·감사 로그 확인 |
| 보고서 | 감사 로그 정책 준수 여부 재확인 | 백엔드 | 준비 | 정책 준수 결과 문서화 |
| 결재 | Approval Flow 작업 계획 상호 공유(`doc/approval_flow_frontend_task_plan.md`) | 프런트/백엔드 | 완료 | 백엔드 문서(`../superport_api_v2/doc/approval_flow_backend_task_plan.md`)와 동기화 |
| QA | `flutter analyze`, `flutter test --coverage` 회귀 실행 후 공유 | 프런트 | 준비 | DTO/테스트 수정 후 `notify.py` 발송 |
| QA | `cargo test` + 통합 시나리오 스크립트 재실행 | 백엔드 | 준비 | 보고서/결재 단계 회귀 포함 |
## 일정 & 의존성
| 구분 | 작업 내용 | 담당 | 상태 | 목표일(제안) | 비고 |
| --- | --- | --- | --- | --- | --- |
| 결재 | 전표 기본 목록 비노출 정책 구현(B5-5) | 백엔드 | ✅ 완료 | 2025-10-24 | 기본 필터/테스트 반영 완료, 대기 목록은 상태 필터로 조회 |
| 결재 | 목록 비노출 UI/필터 적용 및 QA 시나리오 | 프런트 | 🗓️ 예정 | 2025-10-25 | 백엔드 배포 직후 테스트 연동 |
| 문서 | `tool/sync_stock_docs.sh` 실행 및 DTO 재생성 | 프런트 | 🗓️ 예정 | 2025-10-23 | 문서/코드 차이 검출 후 PR 공유 |
| QA | Approval Flow 통합 테스트 재실행 (`cargo test`) | 백엔드 | 🗓️ 예정 | 2025-10-24 | 보고서/결재 전이 회귀 포함 |
| QA | `flutter analyze`, `flutter test --coverage` | 프런트 | 🗓️ 예정 | 2025-10-26 | 새 DTO·UI 반영 후 보고 |
| Ops | Prometheus 지표 대시보드 구성 | 백엔드/Ops | 🗓️ 예정 | 2025-10-28 | `approval_flow_action_*` 메트릭 시각화 |
## 테스트 & 다음 단계
- Approval Flow 개선 과제는 `doc/approval_flow_frontend_task_plan.md`를 기준으로 우선순위를 재정정하고 백엔드 진행 상황과 주별 체크인을 맞춘다.
- 백엔드 `cargo test` 통과 보고가 공유됐지만, 프런트 QA 관점에서는 다음을 진행한다.
- 새 마이그레이션(`006_add_expected_return_date_to_stock_transactions.sql`) 적용 → 스테이징 DB 반영 상태 확인.
- 결재 단계 검색(`q`, `status_id`), 거래번호 노출, 결재 열람 권한 제한, 보고서 PDF 다운로드를 프런트/백엔드 합동 점검.
- `flutter analyze`, `flutter test --coverage`로 DTO·테스트 변경 이후 회귀 여부 확인.
- 모든 작업을 마치면 `notify.py` 워크플로를 통해 완료 알림을 발송한다.
- 백엔드는 기본 필터 동작 검증 후 `cargo fmt`, `cargo check`, `cargo test` 결과를 공유한다.
- 프런트는 문서/DTO 동기화 이후 Approval Flow UI·보고서 다운로드·권한 편집 시나리오를 회귀 테스트로 보강한다.
- 양측 모두 QA 완료 시 `notify.py` 워크플로로 완료 알림을 발송하고, 남은 일정(B8-4, B8-5, B9-x)을 공유 캘린더에 업데이트한다.