- 거버넌스: kintex-pm·dev-pm·pmo 에이전트
- Phase A 아키텍처 5종: docs/architecture/{app,system,tech,data,network}.md (성문화·NFR·SRID0 공간표준·M16 스타스키마·보안영역)
- WISE(UIWS) 참조 개발문서 6종: README·DEVELOPMENT_GUIDE·ENV_SETUP·COMMON_CODES·API_GUIDE·BUILD_DEPLOY
- DB 계층: PostGIS 스키마 V1~V6(홀·트렌치 가정그리드·GiST) + MyBatis 매퍼 5종(ST_* 공간쿼리) + Flyway. gradlew build SUCCESS
- 프론트 착수: React/Vite 스캐폴드 + design.md 토큰 + SCR-01 로그인·SCR-03 부스 에디터. tsc/vite build EXIT 0
- R-T1 수정: 나노바나나 워커 큐키 kintex:renderjob:queue 통일(백엔드 정합, silent no-op 방지)
- 도메인/게이트: G2 해소(dev kintex.zioinfo.kr·prod kintex.wise.ai.kr), CLAUDE.md 로스터 20종
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
59 lines
5.0 KiB
Markdown
59 lines
5.0 KiB
Markdown
# 킨텍스 — DB 스키마·매퍼 계약 (Phase C / B-0 DB)
|
|
|
|
> 작성: kintex-db-engineer · 근거: PLANNING §7(ERD·마스터)·§8(공간 일원화), `_workspace/01_backend_contracts.md` §8 매퍼 인수 목록
|
|
> 스택: PostgreSQL + PostGIS · Flyway 순번 마이그레이션 · MyBatis 매퍼 XML
|
|
> **대조 대상**: kintex-backend-dev(서비스 조립)·kintex-qa. 본 문서가 컬럼·타입·파라미터 계약의 단일 출처.
|
|
|
|
## 1. 마이그레이션 (권위 = Flyway, `src/backend/src/main/resources/db/migration/`)
|
|
|
|
| 순번 | 파일 | 내용 |
|
|
|---|---|---|
|
|
| V1 | `V1__enable_extensions.sql` | postgis · pgcrypto extension |
|
|
| V2 | `V2__identity_and_master.sql` | app_user · company · event · hall · hall_assignment · event_member · booth_standard · master_data |
|
|
| V3 | `V3__spatial_core.sql` | trench(POINT) · hall_exit(POINT) · layout · booth(POLYGON) · design_plan(jsonb) · utility_order(MULTILINESTRING) · render_job + GiST 인덱스 |
|
|
| V4 | `V4__seed_hall_master.sql` | 홀 11행(H1~H10·OUTDOOR) 멱등 + 비상구 가정 4개소/홀 |
|
|
| V5 | `V5__seed_trench_grid.sql` | 트렌치 **가정 그리드**(6m 격자, is_assumed=true) |
|
|
| V6 | `V6__seed_master_and_demo.sql` | 부스 표준·요율/요금/규정 참조·등록업체 샘플·데모 행사(e-2026-smf→H7) |
|
|
|
|
- SRID **0** = 홀 로컬 평면 좌표계(미터). `ST_Area`→㎡, `ST_Distance`/`ST_Length`→m.
|
|
- 시드는 전부 멱등(ON CONFLICT). 재호출 시 **V7+ 순번으로 이어 추가**(기존 파괴 금지).
|
|
- `spring.flyway.baseline-on-migrate=true`. `FLYWAY_ENABLED=false`로 비활성 가능.
|
|
|
|
## 2. 보안 (계약 §0-3 유지)
|
|
- `app_user.password_hash`(BCrypt)·`otp_secret`(암호화)는 **API 응답 절대 제외**. `findAuthByEmail`만 인증 검증용으로 반환, 그 외 조회는 select 금지.
|
|
- 시크릿 하드코딩 없음. 데모 시드에 로그인 사용자 미포함(사용자·비번은 B-1 인증 트랙 admin env 재시드).
|
|
|
|
## 3. 매퍼 파라미터·반환 계약 (백엔드 조립 시 준수)
|
|
|
|
### UserMapper
|
|
- `findAuthByEmail(email)` → `{userId, displayName, passwordHash, hallManager}` | null
|
|
- `findEventRoles(userId)` → `[{eventId, roleCode, eventName, startDate, endDate, hallLabel, dday}]` (워크스페이스 카드 + eventRoles 동시 조립 가능)
|
|
|
|
### BoothMapper (M2 · PostGIS)
|
|
- `findLayout(eventId,hallId,version?)` → `{layoutId, version, name, status, updatedAt}` (version=null→최신)
|
|
- `findBooths(layoutId)` → `[{boothId, boothNo, type, polygonJson(GeoJSON), sizeW, sizeD, heightM, floorLoadTPerM2, assignedCompanyName, premium}]`
|
|
- `upsertLayout(params)` → layoutId. **params**: `{layoutId?, eventId, hallId, version, name, status}`
|
|
- `replaceBooths(layoutId, booths)`. **booths[i]**: `{boothId?, boothNo, type, wkt('POLYGON((x y,...))'), sizeW, sizeD, heightM, floorLoad, assignedCompanyName, premium}` (단일 CTE로 삭제→일괄 삽입, booths 비어있지 않아야 함)
|
|
- `sumSalesArea(layoutId)`→Double㎡ · `minAisleWidth(layoutId)`→Double m(10m내 인접쌍 최소이격) · `countExitsBlocked(layoutId,hallId)`→int
|
|
- 규정검증 metrics 키(01 계약 §3): `layout.min_aisle_width_m`, `layout.exits_blocked_count`, 부스별 `booth.height_m`/`booth.floor_load` 집계.
|
|
|
|
### DesignMapper (M3)
|
|
- `findDesign(boothId,version?)` → `{designId, boothId, version, status, specJson(문자열), updatedAt}` — 백엔드가 specJson→DesignSpec 역직렬화
|
|
- `upsertDesign(params)` → designId. **params**: `{designId?, boothId, version, status, specJson(JSON 문자열)}`
|
|
- `findEventIdByBooth(boothId)` → eventId (RBAC)
|
|
|
|
### WiringMapper (M4 · PostGIS)
|
|
- `findNearestTrenches(hallId,boothId,kind)` → `[{trenchId, x, y, distanceM, assumed}]` (KNN `<->` 상위 5)
|
|
- `shortestPath(hallId,fromX,fromY,kind)` → `{lineJson(GeoJSON LineString), lengthM, assumed}` — 백엔드가 lineJson→coords 파싱
|
|
- `isAssumedTrench(hallId)` → Boolean (WiringResult.assumedTrench 원천)
|
|
- kind: `power|network|plumbing|water|air|gas` → 트렌치 supply_* 컬럼 매핑.
|
|
|
|
### RenderJobMapper (M5)
|
|
- `insertJob(params)`. **params**: `{jobId, eventId, boothId, shotPreset, status, imageUrl?, schemaHash?, modelVersion?, errorMessage?}` (ON CONFLICT DO NOTHING)
|
|
- `updateStatus(jobId,status,imageUrl,errorMessage)` · `findByBooth(boothId,shotPreset?)`→갤러리 목록 · `countSucceededByEvent(eventId)`→int(status='DONE', 쿼터 정본)
|
|
|
|
## 4. 남은 TODO (경계·후속)
|
|
- **서비스 조립(backend-dev)**: 5개 ServiceImpl이 아직 `notImplemented` 반환. 위 계약대로 매퍼 호출 배선 시 M2~M5·인증 501 해소.
|
|
- **CAD 트렌치 실측 추출**: 현재 트렌치·비상구는 **가정 그리드**(is_assumed=true). `docs/assets/floorplans/cad/kintex1_cad_all_halls.zip`의 "평면,트렌치.dwg" 좌표 추출 → V7+ 마이그레이션으로 교체, hall.is_assumed_trench=false 갱신.
|
|
- booth 교체(replaceBooths)가 design_plan을 CASCADE 삭제 — 부스 ID 안정화(버전 간 유지)는 backend 배치 저장 로직에서 관리 필요.
|