From 4049b7c222da2e49033e1743fbf168da7edee1f2 Mon Sep 17 00:00:00 2001 From: zio Date: Sun, 12 Jul 2026 10:14:29 +0900 Subject: [PATCH] =?UTF-8?q?feat(backlog):=20wave=204=20=E2=80=94=20ops=20r?= =?UTF-8?q?eal-data,=20M9=20settlement=20(V24),=20M1=20hall=20assign+quote?= =?UTF-8?q?=20(V25),=20roleCode/nav;=20fix=20OTP=20retry=20lockout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - fix(security): verifyOtp/enrollVerify consumed the challenge BEFORE code verification — one mistyped TOTP burned the session and every retry hit "세션 만료" (live incident). Now consume only on success, keep challenge for up to 5 failures (OtpChallengeStoreTest) - SCR-14 ops: congestion from real check-in aggregates, power from utility orders; hardware widgets stay as honest "sensor not connected" empty states - M9 settlement: /api/settlement (dashboard/invoices/generate/issue/payments), V24 invoice tables, server-authoritative amounts (ST_Area x rate + VAT), PG-delegation notice, /settlement UI - M1 hall assign: /api/halls CRUD + period-overlap conflict (409 with details) + rates-v1.0 auto-quote, V25 idempotent period columns, /halls board UI - shared: AuthUser.roleCode (JWT rc claim, additive), AdminGuard precise check, AppShell placeholder nav wired via event-context builders, /_styleguide dev-only route Co-Authored-By: Claude Fable 5 --- docs/WORK_STATUS.md | 1 + .../zioinfo/kintex/auth/AuthServiceImpl.java | 12 +- .../com/zioinfo/kintex/auth/JwtService.java | 21 +- .../zioinfo/kintex/auth/KintexPrincipal.java | 10 +- .../kintex/auth/dto/LoginResponse.java | 10 +- .../HallAssignConflictException.java | 23 + .../hallassign/HallAssignController.java | 124 ++++ .../kintex/hallassign/HallAssignMapper.java | 147 +++++ .../kintex/hallassign/HallAssignService.java | 361 +++++++++++ .../hallassign/dto/AssignmentRequest.java | 17 + .../kintex/hallassign/dto/ConflictDto.java | 15 + .../hallassign/dto/HallAssignmentDto.java | 18 + .../kintex/hallassign/dto/HallDto.java | 16 + .../kintex/hallassign/dto/QuoteLine.java | 12 + .../kintex/hallassign/dto/QuoteRequest.java | 17 + .../kintex/hallassign/dto/QuoteResult.java | 20 + .../com/zioinfo/kintex/ops/OpsMapper.java | 56 +- .../com/zioinfo/kintex/ops/OpsService.java | 107 ++- .../com/zioinfo/kintex/ops/dto/OpsDto.java | 30 +- .../kintex/security/OtpChallengeStore.java | 28 +- .../kintex/security/TwoFactorService.java | 46 +- .../settlement/SettlementController.java | 83 +++ .../kintex/settlement/SettlementMapper.java | 183 ++++++ .../kintex/settlement/SettlementService.java | 348 ++++++++++ .../kintex/settlement/dto/SettlementDtos.java | 114 ++++ .../db/migration/V24__m9_settlement.sql | 76 +++ .../db/migration/V25__m1_hall_assign.sql | 25 + .../security/OtpChallengeStoreTest.java | 49 ++ src/frontend/src/App.tsx | 7 +- src/frontend/src/api/types.ts | 4 + .../src/components/layout/AppShell.tsx | 58 +- .../src/components/layout/app-shell.css | 9 + src/frontend/src/screens/admin/AdminGuard.tsx | 15 +- .../screens/hallassign/HallAssignmentPage.tsx | 400 ++++++++++++ .../src/screens/hallassign/hallAssignApi.ts | 115 ++++ .../src/screens/hallassign/hallassign.css | 261 ++++++++ .../src/screens/ops/HallOperationsPage.tsx | 196 +++--- src/frontend/src/screens/ops/ops.css | 9 + src/frontend/src/screens/ops/opsApi.ts | 39 ++ .../settlement/SettlementDashboardPage.tsx | 608 ++++++++++++++++++ .../src/screens/settlement/settlement.css | 337 ++++++++++ .../src/screens/settlement/settlementApi.ts | 122 ++++ src/frontend/src/store/authStore.ts | 4 + 43 files changed, 4009 insertions(+), 144 deletions(-) create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/HallAssignConflictException.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/HallAssignController.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/HallAssignMapper.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/HallAssignService.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/AssignmentRequest.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/ConflictDto.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/HallAssignmentDto.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/HallDto.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/QuoteLine.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/QuoteRequest.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/hallassign/dto/QuoteResult.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/settlement/SettlementController.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/settlement/SettlementMapper.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/settlement/SettlementService.java create mode 100644 src/backend/src/main/java/com/zioinfo/kintex/settlement/dto/SettlementDtos.java create mode 100644 src/backend/src/main/resources/db/migration/V24__m9_settlement.sql create mode 100644 src/backend/src/main/resources/db/migration/V25__m1_hall_assign.sql create mode 100644 src/backend/src/test/java/com/zioinfo/kintex/security/OtpChallengeStoreTest.java create mode 100644 src/frontend/src/screens/hallassign/HallAssignmentPage.tsx create mode 100644 src/frontend/src/screens/hallassign/hallAssignApi.ts create mode 100644 src/frontend/src/screens/hallassign/hallassign.css create mode 100644 src/frontend/src/screens/ops/opsApi.ts create mode 100644 src/frontend/src/screens/settlement/SettlementDashboardPage.tsx create mode 100644 src/frontend/src/screens/settlement/settlement.css create mode 100644 src/frontend/src/screens/settlement/settlementApi.ts diff --git a/docs/WORK_STATUS.md b/docs/WORK_STATUS.md index 08b3bbe..0fa53c5 100644 --- a/docs/WORK_STATUS.md +++ b/docs/WORK_STATUS.md @@ -98,6 +98,7 @@ | 2026-07-12 | **Stitch 전 화면 확보 완료(64/64)** — 서비스 회복 후 수확 패스 재실행: 잔여 39화면 전부 서버측 지연 생성 완료 상태(프로젝트 27→155 화면)로 재생성 0회·다운로드 43파일(보조 변형 5 포함: P4 3단계·P7 예매확인·M15 권종선택) 실패 0. `_workspace/stitch_gen/{harvest2.py,screen_titles.txt,harvest_report.md}`. 다음: frontend/mobile dev 이식 + design.md 🔲미생성 마커 갱신(designer 경유) | | 2026-07-12 | **실데이터·2FA 트랙 마감** — ①실데이터 집계 API 5패키지(analytics·dashboard·ops·admin·catalog + V13 인덱스) ②TOTP 2FA 완결(SecretCipher AES-256-GCM·V12·OtpChallengePanel/OtpSetupPage·OTP_ENFORCE env) ③공통 업무기능 SCR-39~48 화면(`screens/work/`) 배선 ④M2 부스 겹침 검사(BOOTH_OVERLAP·compliance-v1.1) + 단위테스트 3종. 검증: backend compileJava+test·frontend tsc 통과, QA PASS(blocker/major 0, minor 2=RIGGING_RANGE semantics 소유자 결정 대기·운영 KINTEX_OTP_ENC_KEY 주입 게이트 — `_workspace/09_qa_track_close.md`). 계약 갭 기록: `_workspace/{07_work_api_gaps,08_m2m5_contract_changes}.md` | | 2026-07-12 | **Stitch 확보 화면 이식 완료(웹 24 + 공개 7단계플로우 + 모바일 1)** — 에이전트 7팀 병렬(폴더 소유권 분리·공유파일 통합자 단일 배선). ①도메인: SCR-22/23/25(서류·신고서류·도크, M6/M8 샘플)·SCR-26/27/29/38(옥션 3종+수주 대시보드, M15 샘플, 봉인입찰 마스킹·등록업체만 응찰 UI)·SCR-30/32/33/34(관람객·리드·EDM·스폰서십, M10/M12 샘플, PII 마스킹)·SCR-35/36/37(CMS 3종, M17 샘플) ②관리자: **A5 감사로그·A6 시스템설정 = 라이브 백엔드 실배선**(PageResponse·시크릿 마스킹), A8 룰셋(정적 v1.1 스냅샷)·A9 테넌트(샘플) ③공개: P1~P7 자체 PublicShell(비인증 /public/*·/tickets/*, PG위임 고지) ④모바일: M15 티켓지갑(mobile/app/tickets, QR placeholder) ⑤통합: App 라우트 18종+AppShell "도메인 모듈" 네비. tsc -b EXIT 0·QA PASS(minor 2 코스메틱: kx-field 접두, ★/✓ 글리프). 각 팀 API 계약 초안 = `_workspace/port_*.md`. 커밋 becbc55 | +| 2026-07-12 | **4차 웨이브(백로그 4트랙) + ★OTP 로그인 루프 라이브 장애 수정** — ①**OTP 장애**(사용자 보고 "로그인 후 메인화면 안 나옴"): `verifyOtp`/`enrollVerify`가 코드 검증 **전에** 챌린지를 소비 → 오입력 1회면 이후 정답도 "세션 만료" 루프. 수정=성공 시에만 소비+실패 5회 한도(`OtpChallengeStore.recordFailure`)+`OtpChallengeStoreTest` ②SCR-14 현장운영 실전환(혼잡=체크인 파생·전력=utility 부하, IoT는 "센서 미연동" 정직 표기) ③M9 정산 신설(`/api/settlement`·V24 invoice/invoice_payment·`/settlement` 화면, ST_Area×요율+VAT 서버 권위·PG위임) ④M1 홀배정+자동견적(`/api/halls`·V25 기간 컬럼 순증·충돌 409+상세·rates-v1.0 견적·`/halls` 화면) ⑤공유 레이어: AuthUser.roleCode 순증 노출(JWT `rc` 클레임)+AdminGuard 정밀화+AppShell 플레이스홀더 네비 전량 배선(행사 컨텍스트 계산 경로)+`/_styleguide` prod 제외. 검증: compileJava·test·tsc -b --force·vite build 전부 EXIT 0 | | 2026-07-12 | **3차 웨이브(백로그 3트랙) + 배포 크래시 근본수정** — ①크래시 규명: c6f3a8d jar가 MyBatis `") + List> listInvoices(@Param("eventId") String eventId, + @Param("status") String status, + @Param("limit") int limit, + @Param("offset") int offset); + + @Select("") + long countInvoices(@Param("eventId") String eventId, @Param("status") String status); + + @Select("") + Map findInvoice(@Param("id") String id); + + @Select(""" + SELECT id, + amount, + method, + memo, + to_char(recorded_at AT TIME ZONE 'UTC','YYYY-MM-DD"T"HH24:MI:SS"Z"') AS "recordedAt" + FROM invoice_payment WHERE invoice_id = #{invoiceId} + ORDER BY recorded_at ASC + """) + List> listPayments(@Param("invoiceId") String invoiceId); + + // ── 상태 전이/수납 ──────────────────────────────────────────────────────── + /** 발행: pending → invoiced (issued_at·due_date 확정). 이미 발행된 건은 미영향(WHERE 조건). */ + @Update(""" + UPDATE invoice + SET status = 'invoiced', issued_at = now(), + due_date = COALESCE(due_date, (now() + interval '30 day')::date), + updated_at = now() + WHERE id = #{id} AND status = 'pending' + """) + int issueInvoice(@Param("id") String id); + + @Insert(""" + INSERT INTO invoice_payment (id, invoice_id, amount, method, memo, recorded_by) + VALUES (#{id}, #{invoiceId}, #{amount}, #{method}, #{memo}, #{recordedBy}) + """) + int insertPayment(Map p); + + /** + * 수납 반영 — paid_amount 를 결제 이력 합계로 재계산하고 상태를 파생. + * 완납(paid_amount >= total)이면 paid, 부분 수납이면 invoiced, 그 외 유지. + * (비교 연산은 SQL 본문 — {@code