backend: M2 배치/규정검증(PostGIS)·M3 설계·M4 배선/견적·M5 RenderJob + 인증(login/workspaces/accept-invite) 매퍼 배선으로 501 해소. M2 자동배치 3안 생성→선택/병합→규정 재검증. 계약 확장(Violation 좌표·LayoutDto.hall·AutoLayoutOption.booths, additive NON_NULL). 신규 HallMapper·UtilityOrderMapper(기존 테이블). gradlew build 통과. frontend: SCR-02 대시보드·SCR-06 설계스튜디오(4샷+Before/After)·SCR-07 배선뷰(적/청/녹)·SCR-12 갤러리 + CompareSlider(reroomai)·WiringCanvas. tsc/vite build EXIT 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.7 KiB
6.7 KiB
킨텍스 백엔드 — M2~M5 매퍼 배선 + 계약 확장 (Phase C, D-4)
작성: kintex-backend-dev · 근거:
_workspace/01_backend_contracts.md·_workspace/02_db_schema.md·_workspace/02_frontend_progress.md(계약 공백 5건)·IMPLEMENTATION_BACKLOG C-M2~C-M5 대상: frontend·qa 대조. 이번 회차는 db-engineer가 완성한 MyBatis 매퍼에 ServiceImpl을 배선해 M2~M5·인증의 501(NOT_IMPLEMENTED)을 200으로 전환하고, 프론트가 지적한 계약 공백을 additive(하위호환)로 보강한다. 스키마 마이그레이션·2FA·프론트·build.gradle 미변경. 커밋 없음(파일만).
1. 501 → 200 전환된 엔드포인트
| 모듈 | 메서드 | 엔드포인트 | 배선 요지 |
|---|---|---|---|
| 인증 | login | POST /api/auth/login |
UserMapper.findAuthByEmail + BCrypt 대조 + findEventRoles→토큰·워크스페이스 |
| 인증 | listWorkspaces | GET /api/auth/workspaces |
findEventRoles(userId)→WorkspaceDto[] |
| 인증 | acceptInvite | POST /api/auth/accept-invite |
등록업체 검증(findCompanyRegistered)→토큰 재발급. ★초대코드 매핑은 후속(아래 TODO) |
| M2 | getLayout | GET …/halls/{hallId}/layout |
findLayout+findBooths(GeoJSON 파싱)+HallMapper+검증 요약 |
| M2 | saveLayout | PUT …/layout |
폴리곤→WKT upsertLayout+replaceBooths, 저장 후 규정 재검증 반영 |
| M2 | validate | POST …/layout/validate |
minAisleWidth·countExitsBlocked+부스 최댓값→룰엔진 M2 |
| M2 | autoGenerate | POST …/layout/auto-generate |
제약 기반 그리드 패킹으로 정확히 optionCount(기본 3)안 + S7 발행 |
| M2 | applyOption | POST …/layout/apply-option (신규) |
선택/병합 부스열→새 버전 저장+규정 재검증 |
| M3 | getDesign | GET …/booths/{boothId}/design |
findDesign+spec(jsonb) 역직렬화 |
| M3 | saveDesign | PUT …/design |
spec 직렬화 upsertDesign(버전 next), 최신본 반환 |
| M4 | computeWiring | POST …/utility/wiring |
isAssumedTrench+단말별 shortestPath(LineString 파싱)·색상 규약 |
| M4 | submitOrder | POST …/utility/order |
quote+UtilityOrderMapper.insertOrder(영속)+위치표시도 URL·마감/릴레이 고지 |
| M4 | getOrder | GET …/utility |
UtilityOrderMapper.findOrder(부스 최신) |
| M5 | listByBooth | GET …/render-jobs |
RenderJobMapper.findByBooth→갤러리 목록(워터마크 항상 포함) |
| M5 | publish(보강) | POST …/render |
쿼터 정본을 countSucceededByEvent(DB DONE)로 전환 + insertJob 내구 이력 |
| M5 | callback(보강) | POST /api/internal/render/callback |
updateStatus 내구 갱신(쿼터는 DONE 집계에서 자동) |
2. 계약 확장 (additive · 하위호환 · 프론트 gap 해소)
모두 @JsonInclude(NON_NULL)로 기존 필드 불변, 신규 nullable 필드만 추가.
2-1. gap #1 — 위반 오버레이 좌표 (rules.Violation)
- 추가 필드:
boothId(String, nullable) ·anchor([x,y] 미터, nullable). - 부스 단위 규칙(HEIGHT_MAX·FLOOR_LOAD) 위반에 한해 해당 부스 id + 폴리곤 중심 앵커를 부여. 레이아웃 단위(AISLE_WIDTH_MIN·EXIT_ACCESS)는 null(캔버스에서 목록 핀만).
- 프론트:
violations[].anchor존재 시 캔버스 핀 위치로 사용, 없으면 기존처럼 목록 핀만.
{ "pin":1, "code":"HEIGHT_MAX", "severity":"block", "measured":"측정 5.4m",
"boothId":"b-102", "anchor":[3.0,1.5] }
2-2. gap #2 — 홀 치수·트렌치 (m2.dto.LayoutDto.hall = HallInfo)
LayoutDto에hall필드 추가(신규HallInfo). 캔버스 하드코딩(126×90m·트렌치 그리드) 제거 근거.HallInfo:hallId·label·dimsM[w,d]·ceilingM·targetBoothCount·floorLoadTPerM2·assumedTrench·trenches[]·exits[].HallInfo.Trench:{trenchId,x,y,assumed,supplies[power|water|air|network|gas]}·HallInfo.Exit:{x,y,clearanceM}.- 원천: 신규
HallMapper(hall·trench·hall_exit read-only).assumedTrench=true면 SCR-07 "가정 트렌치" 배지(PLANNING R4).
"hall": { "hallId":"H7","label":"제2전시장 홀7","dimsM":[126,90],"ceilingM":12,
"targetBoothCount":510,"floorLoadTPerM2":5.0,"assumedTrench":true,
"trenches":[{"trenchId":"H7-T-3-3","x":3,"y":3,"assumed":true,"supplies":["power","water","air","network","gas"]}],
"exits":[{"x":63,"y":0,"clearanceM":3.0}] }
2-3. gap #3 — 자동배치 안의 부스 + 적용 경로 (AutoLayoutOption.booths + apply-option)
AutoLayoutOption에booths(BoothDto[]) 추가 — "이 안으로 편집 시작"/병합 소스.- 신규
POST …/layout/apply-option(ORGANIZER): bodyApplyOptionRequest {name, booths[]}→ 새 버전 저장 + 규정 재검증된LayoutDto. - 3안 흐름 마감: auto-generate(3안+각 booths) → 클라 선택/구역 병합(booths 합성) → apply-option(영속+재검증). 단일 안 적용도 동일 엔드포인트.
3. backend 추가 매퍼 (db-engineer 계약 §3 밖 — 기존 테이블 read/write, 마이그레이션 불변)
db-engineer 인수·정본화 요청. 모두 V2~V5 기존 테이블만 사용.
| 매퍼 | 메서드 | 테이블 |
|---|---|---|
m2.mapper.HallMapper |
findHall·findTrenches·findExits | hall·trench·hall_exit (read-only) |
m4.mapper.UtilityOrderMapper |
insertOrder·findOrder | utility_order (V3) |
auth.mapper.UserMapper(+1) |
findCompanyRegistered | company (read-only) |
4. 남은 TODO (경계·후속)
- 초대코드→행사/부스/역할 매핑: invite 테이블·매퍼 미제공 → acceptInvite는 등록업체 게이트 + 현재 역할 재발급까지만. 역할 upsert는 매핑 매퍼 인수 시 배선(db-engineer).
- 위치표시도 PDF(M4-3): submitOrder는 신청 영속 + 자산 URL(
…/utility/location-diagram)·고지 반환. 실제 PDF 렌더는 문서 큐(후속). 현재 해당 GET 자산은 미구현(URL만). - wiring 지오메트리 영속: computeWiring은 산출·반환만. utility_order.wiring(MultiLineString) 저장은 후속.
- 자동배치 최적화: 현재 결정적 그리드 패킹(3안=통로폭/규격 변주, 무위반 골격). 제약 솔버 고도화는 후속(흐름은 성립).
- 트렌치 실측(R4): 가정 그리드 유지(is_assumed=true). CAD 추출 교체 시 HallInfo.assumedTrench=false 자동 반영.
5. 검증
./gradlew compileJava·./gradlew build -x test통과. 매퍼 id/namespace 정합 확인. PostgreSQL 미기동으로 런타임 왕복은 dev 배포 후.- 보안 불변 유지: password_hash/otp 응답 제외, 스택트레이스 미노출(요약 메시지), AI 이미지 워터마크·고지 항상 포함, 워커 에러 요약화.