harness/plugins/zio-harness/knowledge/kintex/docs/architecture/app.md
DESKTOP-TKLFCPR\ython 1ef2235939 feat(zio-harness): v1.1.0 — auto source analysis + GUARDiA/KINTEX knowledge base
- SessionStart hook (scripts/graphify_setup.py): auto-install graphifyy[sql],
  build knowledge graph on first run (graphify extract --code-only, local AST),
  incremental graphify update thereafter — install-only smartness
- knowledge/kintex/: all 183 KINTEX md docs bundled (planning/design/analysis)
- knowledge/guardia/: distilled GUARDiA-wide knowledge from 2,483 md files
  (solutions-catalog, standard-framework, operations-cicd, lessons-learned;
  credentials/IP-free curated)
- SKILL.md: graph-first codebase query rules + knowledge base loading guide

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 23:15:35 +09:00

402 lines
28 KiB
Markdown

# 킨텍스 자동전시시스템 — 애플리케이션 아키텍처 표준 (app.md)
> 작성: 애플리케이션 아키텍트(AA) · 작성일: 2026-07-11 · 버전: **v1.0** · BACKLOG **A-1**
> 근거: `docs/PLANNING.md` v2.0(§2 6역할 포털·§4 모듈맵·§5 M1~M9·§5A M10~M18·§5B 공통레이어·§8 아키텍처)·`docs/IMPLEMENTATION_BACKLOG.md`(Phase A~E)·`_workspace/01_backend_contracts.md`(P0 계약)·`src/backend` 스캐폴드 실측.
> 스택(확정·불변): React 18/19(Vite·TypeScript) + Spring Boot 3.x(Java 17) + MyBatis + PostgreSQL(PostGIS) + Redis + 나노바나나 Python 워커 사이드카.
>
> **문서 소유권**: 본 문서는 AA만 수정한다. 구현 에이전트(BE/FE/DB/COM/도메인 devs)는 이 표준을 **준수**하며, 위반 발견 시 kintex-qa와 함께 시정한다. 교차 문서(system.md·tech.md·data.md·network.md)와의 정합은 링크로 참조하고 직접 수정하지 않는다.
---
## 0. 목적과 적용 범위
본 문서는 킨텍스 자동전시시스템의 **애플리케이션 구조 일관성**을 규정하는 단일 표준이다. 개별 기능 구현 방식이 아니라 **모듈 경계·레이어링·패키지·API 규격·공통 컴포넌트·의존성 규칙**을 정의한다.
- **적용 대상**: `src/backend`(Spring Boot) 전 모듈, `src/frontend`(React) 전 포털, 나노바나나 워커와의 큐 계약, kintex-common(WISE/UIWS 이식) 공통 레이어.
- **정합 기준**: PLANNING §8/§8-1 아키텍처 개요와 **정합하며 이를 구체화**한다. 상충 시 PLANNING이 상위, 본 문서가 구현 표준.
- **현행 스캐폴드 정합**: 본 표준은 이미 스캐폴드된 실제 구조(§1.2)를 성문화한 것이며, 신규 모듈은 이 패턴을 복제한다. 기존 코드 변경을 요구하지 않는다(성문화·확장).
---
## 1. 패키지 구조 표준
### 1-1. 루트 패키지
전 백엔드 코드는 `com.zioinfo.kintex` 하위에 둔다(GUARDiA 표준 프레임워크 정렬, WISE=`com.zioinfo.*` 관례). 최상위는 **횡단 관심사(cross-cutting)****도메인 모듈(module)** 로 나뉜다.
```
com.zioinfo.kintex
├── KintexApplication # 부트 진입점
├── common # 횡단: 응답봉투·페이징·에러·감사·유틸 (모듈 무의존)
│ ├── ApiResponse / PageResponse
│ ├── error/ (ErrorCode·ApiException·GlobalExceptionHandler)
│ ├── audit/ (감사 AOP·@Audited — Phase B B-2/B-4)
│ └── code/ (공통코드 조회 캐시 — Phase B)
├── config # 부트 설정: SecurityConfig·WebSocketConfig·RedisConfig·MyBatisConfig
├── auth # 인증/인가: JWT·RBAC·2FA(OTP)·principal·guard (도메인 무관 공용)
│ ├── dto/ · mapper/
├── rules # 룰 엔진: 규정(compliance)·요율(rate) 룰셋 로딩·평가 (서비스 계층)
├── health # 헬스체크
└── module # ★도메인 모듈 루트 — 모듈별 서브패키지
├── m1 … m9 # 판매·운영(배정·서류·매칭·정산·물류)
├── m2 · m3 · m4 · m5 # ★P0 부스 시공 코어
├── m10 · m11 · m12 · m13 · m14 # 관람·참가·마케팅·wayfinding·현장운영
└── m15 · m16 · m17 · m18 # 옥션·BI·CMS·관리자
```
### 1-2. 모듈 내부 구조 (표준 레이아웃 — 스캐폴드 실측)
각 도메인 모듈 `module.mN`은 아래 4계층을 **고정 서브패키지**로 둔다. M2가 정본 참조 패턴이다.
```
module.mN
├── MNController # REST 진입 — 얇게 유지(가드·바인딩·위임만)
├── MNService # 서비스 인터페이스(계약)
├── MNServiceImpl # 서비스 구현(비즈니스 로직·트랜잭션 경계)
├── dto/ # 요청/응답 DTO — record 우선(불변)
│ └── *Dto / *Request / *Response
├── mapper/ # MyBatis 매퍼 인터페이스(@Mapper)
│ └── MNMapper (XML은 resources/mybatis/mapper/)
├── MNProperties (선택) # @ConfigurationProperties 모듈 설정
└── domain/ (선택) # 순수 도메인 모델·값객체(엔티티 매핑 시)
```
> **명명 규칙**: 서비스는 인터페이스(`FloorplanService`) + 구현(`FloorplanServiceImpl`) 분리(스캐폴드 실측). 컨트롤러는 `<도메인명>Controller`. DTO는 `record` 우선(불변·직렬화 안정). 모듈 접두어 `mN`은 패키지에만 쓰고 클래스명은 도메인 어휘(Floorplan·Design·Utility·RenderJob·Auction·Visitor…)를 쓴다.
### 1-3. 리소스 레이아웃
```
src/backend/src/main/resources
├── application.yml # 시크릿·엔드포인트는 env 플레이스홀더만(하드코딩 금지)
├── mybatis/mapper/**/*.xml # 공간 SQL(ST_*) 포함 매퍼 XML — mapper-locations로 로드
└── rulesets/ # 버전 관리 룰셋 데이터(코드 아님)
├── compliance-v1.json (compliance-v1.0)
└── rates-v1.json (rates-v1.0)
```
---
## 2. 레이어링 표준 (controller / service / mapper / domain / dto)
### 2-1. 레이어 책임 경계
| 레이어 | 책임 | 금지 |
|---|---|---|
| **Controller** | HTTP 바인딩, 입력 검증(`@Valid`), RBAC 가드 호출, 서비스 위임, `ApiResponse` 래핑 | 비즈니스 로직·SQL·트랜잭션·매퍼 직접 호출 |
| **Service (interface+Impl)** | 비즈니스 규칙, 트랜잭션 경계(`@Transactional`), 룰 엔진 호출, 매퍼 오케스트레이션, 도메인 예외 발생 | HTTP 타입(HttpServletRequest 등) 참조, 매퍼 XML 로직 침범 |
| **Mapper (MyBatis)** | DB 접근, 공간 SQL(`ST_*`) 바인딩. 인터페이스+XML 쌍 | 비즈니스 분기, DTO 조립(원시 `Map`/도메인 반환까지) |
| **DTO** | 계층·경계 데이터 전달(record 불변) | 로직·영속 어노테이션 |
| **domain / 값객체(선택)** | 순수 도메인 모델·계산(엔티티 매핑 시) | 프레임워크 의존 |
### 2-2. 계층 관통 흐름 (표준)
```
Controller ──(가드: EventAccessGuard)──► Service(interface)
└► ServiceImpl ──► Mapper(@Mapper) ──► PostgreSQL/PostGIS
└──► RuleEngine(rules) (공간 SQL은 XML)
└──► RedisTemplate(비동기 큐/실시간)
결과 DTO ◄── ServiceImpl ◄── Mapper(Map/도메인)
Controller ──► ApiResponse.ok(dto) | 예외 ──► GlobalExceptionHandler ──► ApiResponse.fail
```
- 컨트롤러는 **가드 호출 → 서비스 위임 → 봉투 래핑**만 한다(FloorplanController가 정본). 로직이 컨트롤러에 새면 위반.
- 서비스는 매퍼가 반환한 원시(`Map<String,Object>`/도메인)를 **DTO로 조립**한다. 매퍼는 DTO 조립을 하지 않는다.
- 공간 연산(부스 폴리곤·트렌치 KNN·배선 LineString·면적)은 **서비스가 아니라 매퍼 XML의 PostGIS SQL**로 수행하고 서비스는 스칼라/GeoJSON 결과만 사용한다(스캐폴드 `BoothMapper`·`WiringMapper` 계약).
### 2-3. 트랜잭션·읽기 정책
- 쓰기 서비스 메서드는 `@Transactional`, 조회는 `@Transactional(readOnly=true)`.
- **낙관적 잠금**: 배치·설계 등 버전 있는 리소스는 `version` 불일치 시 `CONFLICT`(409). (LayoutSaveRequest·DesignSaveRequest에 `version` 존재.)
- **BI(M16)**: 운영 DB 직조회 금지 — KpiSnapshot/데이터마트(스타 스키마) 또는 읽기 전용 경로로 격리(PLANNING §8-1·M16-1, 상세는 data.md DA 트랙).
---
## 3. 모듈 경계와 분류
### 3-1. 모듈 3계열 + 공통 레이어
| 계열 | 모듈 | 패키지 | 우선순위 | 비고 |
|---|---|---|---|---|
| **공통 레이어(선행 기반)** | 인증·시스템관리·공통업무기능 | `auth`·`common`·`module.m18`(system)·공통 모듈 | P1(전 모듈 선행) | §5B WISE/UIWS 이식 |
| **P0 부스 시공 코어(불변·심장)** | M2 플로어플랜·M3 부스설계·M4 유틸리티·M5 나노바나나 | `module.m2~m5` | **P0** | 스캐폴드 완비 |
| 판매·운영 | M1 배정견적·M6 서류·M7 매칭·M9 정산·M8 물류 | `module.m1·m6·m7·m9·m8` | P1/P2 | |
| 발주·계약 | **M15 공사/장치 옥션** | `module.m15` | **P1(핵심 플로우)** | 폐루프 연결고리 |
| 관람·참가·마케팅 | M10 관람객·M11 매칭·M12 마케팅/공개사이트·M13 wayfinding·M14 현장운영 | `module.m10~m14` | P1/P2 | |
| 경영·콘텐츠·관리 | M16 BI·M17 CMS·M18 관리자 | `module.m16·m17·m18` | P1 | |
### 3-2. 공간 데이터 공유 원칙 (불변)
M2(부스 폴리곤)→M3(부스 내부)→M4(배선)→M5(시각화)는 **하나의 PostGIS 공간 데이터 모델을 공유**한다. M13 wayfinding·M14 부하집계·M16 ㎡당 수익은 **동일 원천(Booth 폴리곤·Wiring LineString)을 재사용**한다. → 공간 지오메트리 소유는 **M2/M4 매퍼가 권위**이며, 소비 모듈은 조회만 한다(중복 저장 금지).
### 3-3. 권위(ownership) 경계 — 중복 제거 (PLANNING §5B-2 규칙)
| 관심사 | 권위 모듈 | 소비 모듈(읽기/이벤트) |
|---|---|---|
| 경영·수익 지표 | **M16 BI** | 대시보드·포털 |
| 일상 업무보고·통계 | 공통 `report/stats` | — |
| 콘텐츠·공지 발행 | **M17 CMS** | 공개사이트·사이니지 |
| 사내 알림성 공지 | 공통 `notice` | — |
| 알림 발송 채널 | 공통 `notification`(단일화) | M10·M12·M15(이벤트 발행) |
| 사용자·역할·공통코드·감사·마스터데이터 | **M18(=system)** | 전 모듈(RBAC·룰셋 공급) |
| 규정·요율 룰셋 | `rules` + M18(버전 관리) | M1·M2·M3·M4 |
---
## 4. 의존성 규칙 (참조 방향·순환 금지)
### 4-1. 허용 참조 방향 (단방향)
```
module.mN ──► rules · auth · common (횡단 계층 참조 허용)
module.mN ──► module.mK (오직 §4-2 표에 명시된 방향만, 하위→상위 데이터 소비)
common ──► (무의존) ★common은 어떤 module·auth·rules도 참조하지 않는다
auth ──► common (에러·봉투만)
rules ──► common
config ──► auth · common (보안/웹소켓/레디스 배선)
```
**철칙**: `common`은 순수 횡단 유틸(봉투·에러·감사·페이징)로 **어떤 도메인/인증/룰도 모른다**. 도메인 모듈이 common을 참조하지, 그 역은 없다.
### 4-2. 모듈 간 참조(도메인) — 명시 방향만 허용
PLANNING §4 모듈맵의 데이터 흐름을 코드 의존으로 옮긴다. **화살표 방향으로만 참조**(소비자→생산자 조회, 순환 금지).
| 소비 모듈 | 참조(생산) 모듈 | 목적 |
|---|---|---|
| M3 → M2 | 부스 좌표·행사 역참조 |
| M4 → M2 | 트렌치·부스 지오메트리 |
| M5 → M2·M3·M4 | 씬 컴파일 입력(scene) |
| M15 → M2·M3·M4·M5·M7 | 옥션 자료 패키지·등록업체 검증 |
| M9 → M1·M4·M15 | 정산 대상(배정·유틸·낙찰) |
| M13 → M2 | wayfinding 지오메트리 |
| M14 → M4·M10 | 부하·체크인 파생 |
| M16 → 전 모듈 | 지표 소비(읽기 전용/스냅샷) |
| M12 → M10·M17 | 세그먼트·콘텐츠 |
- **순환 금지**: 위 표에 역방향이 필요하면 **직접 참조 대신 이벤트(알림 큐)·공유 식별자**로 디커플. 예: M15 낙찰→M9는 M15가 M9를 호출하는 것이 아니라 **도메인 이벤트/발주 링크**로 전달(순환 회피).
- **모듈 간 결합은 서비스 인터페이스로만**: `mK.MKService`를 주입해 쓰고, 상대 모듈의 `mapper`·`ServiceImpl`·`dto` 내부를 직접 참조하지 않는다(계약 경유).
- **공간 원천**은 M2/M4 매퍼가 권위(§3-2) — 타 모듈은 그 서비스로 조회.
- 검증: 빌드 타임 아키텍처 테스트(ArchUnit 권장, tech.md TA 트랙)로 `common→module` 역참조·모듈 순환을 CI에서 차단.
---
## 5. REST API 설계 표준
### 5-1. 경로·버전
- **베이스**: `/api`. 공개(비인증) 홍보/워커 경로는 `/api/public/**`·`/api/internal/**` 접두어로 분리.
- **행사 스코프 리소스**: `/api/events/{eventId}/…` 하위에 배치(모든 도메인 리소스는 `{eventId}` 스코프). 중첩 예:
- M2 `…/events/{eventId}/halls/{hallId}/layout`
- M3 `…/events/{eventId}/booths/{boothId}/design`
- M4 `…/events/{eventId}/booths/{boothId}/utility`
- M5 `…/events/{eventId}/booths/{boothId}/render` · `…/events/{eventId}/render-jobs/{jobId}`
- **플랫폼(비행사) 리소스**: `/api/admin/**`(M18·백오피스, `hasRole(ADMIN)` 게이트), `/api/auth/**`(인증), `/api/me/**`(개인).
- **버전 정책**: P0/P1은 무접두 `/api`(단일 버전). **파괴적 변경 시에만** `/api/v2/…` 도입. 계약 진화는 **후방호환 우선**(필드 추가는 non-breaking, 제거·의미변경만 버전 상향). 룰셋·계약 semver는 페이로드의 `rulesetVersion`으로 별도 표기(코드 API 버전과 분리).
- **동사 규약**: 자원 CRUD는 표준 HTTP 메서드. 비 CRUD 액션은 하위 동사 세그먼트(`/validate`·`/auto-generate`·`/precheck`·`/quote`·`/wiring`·`/order`·`/render`)로 표현(스캐폴드 실측 패턴). 액션은 POST.
### 5-2. 응답 봉투 (ApiResponse<T> — 스캐폴드 정본)
모든 REST 응답은 `common.ApiResponse<T>`를 사용한다(예외 없음).
```json
{ "success": true, "data": { ... }, "error": null }
{ "success": false, "data": null, "error": { "code": "FORBIDDEN", "message": "요약 메시지" } }
```
- 성공은 컨트롤러가 `ApiResponse.ok(dto)`. 실패는 **던지고**(ApiException) `GlobalExceptionHandler`가 봉투로 변환(컨트롤러에서 실패 봉투 수동 조립 금지).
- **목록**: `common.PageResponse<T>` = `{ items, page, size, total }`. (P0 갤러리/워크스페이스처럼 소량 고정 목록은 배열 직접 반환 허용 — 계약 §0-1.)
### 5-3. 오류 코드 → HTTP (ErrorCode enum — 안정 계약)
`common.error.ErrorCode`가 코드↔HTTP 단일 매핑. 신규 코드는 여기에만 추가한다.
| code | HTTP | 의미 |
|---|---|---|
| `VALIDATION` | 400 | 요청 값 오류(필드 메시지) |
| `UNAUTHORIZED` | 401 | 미인증/토큰 만료 |
| `FORBIDDEN` | 403 | 행사/부스/역할 권한 없음 |
| `NOT_FOUND` | 404 | 대상 없음 |
| `CONFLICT` | 409 | 상태/버전 충돌(낙관적 잠금) |
| `COMPLIANCE_BLOCKED` | 422 | 규정 위반(차단) |
| `RENDER_QUOTA_EXCEEDED` | 429 | 이미지 생성 쿼터 소진 |
| `NOT_REGISTERED_COMPANY` | 403 | 미등록 장치업체 차단 |
| `NOT_IMPLEMENTED` | 501 | 매퍼/엔진 구현 대기(스켈레톤) |
| `INTERNAL` | 500 | 서버 오류(요약만) |
- **미구현 지점**은 `ApiException.notImplemented(...)`(501) 표준 사용 — 계약은 확정하되 매퍼/워커 대기 구간 표시(스캐폴드 관례).
- 도메인 확장 코드(옥션 마감·배지 만료 등)는 계열 접두 없이 `ErrorCode`에 추가하고 본 표에 반영(AA 승인).
### 5-4. 페이징·정렬·필터
- 쿼리 파라미터: `page`(0-base)·`size`(기본 20, 상한 100)·`sort=field,asc|desc`. 응답은 `PageResponse<T>`.
- 필터는 명시 쿼리 파라미터(자유 텍스트 SQL 금지). 통합검색(공통 search)은 별도 검색 서비스 경유.
### 5-5. 인증 헤더·공개 경로
- `Authorization: Bearer <JWT>`(HS256). 클레임: `sub`(userId)·`name`·`roles`(eventId→역할)·`hm`(홀매니저)·(Phase B 확장) `plat`(플랫폼 역할 ADMIN 등)·`otp`(2FA 통과 플래그).
- **무상태**(SessionCreationPolicy.STATELESS). CSRF disable, CORS는 config에서 관리.
- **공개(permitAll)**: `GET /health`, `POST /api/auth/login`, `/ws/**`, `POST /api/internal/render/callback`(워커 토큰), (Phase D) `/api/public/**`(공개 홍보사이트 조회). 그 외 전부 인증.
- 내부 워커 콜백은 `X-Worker-Token`(env) 검증. 공개사이트는 읽기 전용(행사 데이터 쓰기 불가).
### 5-6. 보안 불변 (API 계약 강제 — 위반 시 QA 반려)
1. **스택트레이스·내부 세부 미노출**`error.message`는 사람이 읽을 요약만, 상세는 서버 로그. (`server.error.include-*: never` + GlobalExceptionHandler.)
2. **민감정보 응답 완전 제외** — IP·SSH·비밀번호·`os_pw_enc`·해시·내부 식별자. 사용자/업체는 이름·역할·번호 등 비민감 필드만.
3. **`GEMINI_API_KEY`는 백엔드가 다루지 않는다** — 나노바나나 Python 워커 전용. M5는 큐 발행까지만.
4. **AI 생성 이미지 응답은 항상** `watermarkRequired:true`+`watermarkText`+`notice`(계약·심사 서류 사용 금지) 포함(제거 불가, PLANNING §6-5).
5. **admin 비번**은 env `ADMIN_PASSWORD_ENC`(AES-256-GCM)+별도 키파일 주입, `admin123` 하드코딩 금지(§5B-3).
---
## 6. 인증·인가 아키텍처 (이중 RBAC)
PLANNING §2 6역할·§8-1 SSO 이중 권한을 코드 모델로 표준화한다. 인증 스택은 **WISE/UIWS 표준 이식**(JWT+2FA/OTP), 그 위에 킨텍스 행사 RBAC를 얹는다(재설계 금지).
### 6-1. 이중 권한 평가
| 계층 | 대상 | 저장/평가 | 게이트 |
|---|---|---|---|
| **플랫폼 역할(platform)** | ADMIN(백오피스), 셀프서비스(VISITOR/PUBLIC) | JWT `plat` 클레임 + Spring `hasRole` | `/api/admin/**`=`hasRole(ADMIN)`(§5B-1) |
| **행사 역할(event)** | ORGANIZER·EXHIBITOR·CONTRACTOR·HALL_MANAGER | JWT `roles`(eventId→역할)·`hm`, `KintexPrincipal.roleFor(eventId)` | `EventAccessGuard.requireRole(...)` |
- **현행 스캐폴드**(P0): `EventRole`(4역할) + `KintexPrincipal.hallManager` 플래그 + `EventAccessGuard`(require/requireEventAccess/requireRole). 이 4역할 게이트가 정본.
- **Phase B 확장**: 플랫폼 역할(ADMIN)·관람객 셀프서비스 계정·2FA(OTP)·로그인 실패 잠금을 `auth`에 추가(WISE `TotpService` 이식). `EventRole`은 유지, 플랫폼 역할은 별도 축으로 평가(직교).
### 6-2. 가드 사용 규약 (컨트롤러 표준)
```
guard.requireEventAccess(principal, eventId); // 열람: 멤버 or 홀매니저
guard.requireRole(principal, eventId, EventRole.ORGANIZER); // 편집/액션: 역할 한정
guard.requireRole(principal, eventId, EventRole.ORGANIZER, HALL_MANAGER); // 복수 허용
```
- **열람=행사 멤버 or 홀매니저 / 편집·액션=역할별**(계약 §0-5). 홀매니저는 전 행사 열람+승인(`hasAccess`가 항상 true).
- **등록업체 게이트(불변)**: CONTRACTOR 초대 수락·M15 응찰은 `companyRegistrationNo` 킨텍스 등록업체 검증 필수 → 미등록 `NOT_REGISTERED_COMPANY`(403). M7이 검증 권위.
- 가드는 **컨트롤러에서** 호출한다(서비스 진입 전). 서비스는 이미 인가된 것으로 가정하되, 크로스-모듈 호출 시 재검증이 필요하면 호출 측이 책임.
### 6-3. 개인정보·감사
- 리드캡처(M10)·관람객 데이터는 개인정보 — 동의·보존정책 필수(PLANNING R10). 접근은 소유 참가업체+주최자+홀매니저로 한정.
- **감사 대상**(§5B-1): 승인·**낙찰(M15)**·설계 변경·룰셋 개정·리드 접근을 `common.audit` AOP로 전수 기록(§7-3).
---
## 7. 공통 컴포넌트 표준 (kintex-common / WISE 정합)
공통 레이어는 `workspace/uiws`(WISE=GUARDiA 표준 프레임워크) 이식을 원칙으로 하되, 아래 컴포넌트는 **kintex 스캐폴드가 이미 정의한 계약을 정본**으로 삼는다(재설계 금지, 이식 시 정합).
### 7-1. 응답 봉투·페이징
- `common.ApiResponse<T>`(record: success·data·error{code,message})·`common.PageResponse<T>`. §5-2 정본. 모든 응답 필수.
### 7-2. 예외 체계
- `common.error.ErrorCode`(enum, HTTP 매핑) → `ApiException`(코드+요약 메시지) → `@RestControllerAdvice GlobalExceptionHandler`(봉투 변환·로그 격리). 3자 세트가 표준(§5-3). 신규 예외는 `ApiException`+`ErrorCode`만 사용(RuntimeException 남발 금지 — 최종 방어선만 `INTERNAL`).
### 7-3. 감사 AOP (Phase B B-2/B-4)
- `common.audit.@Audited` 어노테이션 + AOP 어드바이스로 상태 변경 API를 `TB_AUDIT_LOG`에 기록(액터·행사·대상·before/after 요약·룰셋 버전). **민감정보·비번·스택트레이스 미기록**(§5-6 정합). WISE `TB_AUDIT_LOG` 스키마 이식.
### 7-4. 공통코드 (Phase B)
- `common.code`가 코드 그룹/상세를 캐시 제공(홀·부스유형·공종 14분류·유틸리티 요금코드 등 도메인 코드 포함). 권위는 M18(system). 도메인 모듈은 하드코딩 대신 공통코드 조회.
### 7-5. 룰셋(버전 관리 데이터)
- `rules``rulesets/*.json`(compliance·rate)을 로드·평가. **코드가 아닌 데이터** — 개정 시 파일 교체·`rulesetVersion` 리포트 기록(감사·면책, PLANNING R2). 연산자: `lte·gte·between·isTrue·eq·lteHall·excludesAll`.
### 7-6. 알림 단일화 (§5B-2)
- 발송 채널은 공통 `notification` 단일. 도메인 모듈(M10·M12·M15)은 직접 발송하지 않고 **이벤트를 발행**한다(마감 리마인더·낙찰·승인·결제 알림). WebSocket 실시간 경로는 §8.
### 7-7. 프론트 공통(FE, Phase B B-4)
- 2FA 화면·공통코드·검색바·그리드·달력·모달·파일업로드는 **공유 컴포넌트 라이브러리**로(WISE 이식, design.md 토큰 정합). 역할별 포털이 상속(중복 구현 금지).
---
## 8. WebSocket 이벤트 규격 (STOMP)
`config.WebSocketConfig` 정본. 실시간 진행/이벤트 푸시는 STOMP over WebSocket으로만 한다(REST 폴링 지양).
- **핸드셰이크**: `GET /ws`(SockJS). 공개 경로(핸드셰이크 후 STOMP CONNECT 헤더에 JWT 전달 — 인가는 구독 시점 평가).
- **prefix**: 서버→클라 브로드캐스트 `/topic`, 클라→서버 `/app`.
- **토픽 네이밍 표준**: `/topic/<도메인>/<식별자>`.
| 토픽 | 이벤트 | 발행 시점 | 대상 |
|---|---|---|---|
| `/topic/render/{jobId}` | `RenderJobDto`(DONE/FAILED) | 워커 콜백 relay(M5) | 발행 멤버 |
| `/topic/auction/{auctionId}` | 순위/라운드 마감(M15) | 응찰·타이머 | 옥션 참여 업체 |
| `/topic/events/{eventId}/notifications` | 알림(승인·마감·결제) | 공통 notification | 행사 멤버 |
| `/topic/events/{eventId}/checkin` | 입장/혼잡(M10·M14) | 체크인 | 홀매니저/주최자 |
- **페이로드는 REST DTO 재사용**(RenderJobDto 등) — 별도 WS 전용 스키마 금지(계약 일원화).
- **인가**: 구독 대상이 행사/부스 스코프면 CONNECT 시 신원 + 구독 시 접근 검증(민감 토픽 무단 구독 차단). 브로드캐스트에도 §5-6 민감정보 제외 동일 적용.
- 나노바나나·서류·알림은 **동일 비동기 패턴**: REST가 Redis 큐 발행 → 워커/서비스 처리 → WS 완료 푸시.
---
## 9. 비동기·큐 계약 (Redis · Python 워커)
- **RenderJob 큐**: `kintex:renderjob:queue`(env `RENDER_QUEUE_KEY`). 백엔드가 scene 페이로드(§6-2 PLANNING) leftPush → Python 워커 소비. 상태 `kintex:renderjob:job:{jobId}`, 쿼터 `kintex:renderjob:quota:{eventId}`(스캐폴드 실측 키).
- **성공 시에만 쿼터 차감**(PLANNING §6-5). 실패 에러는 `safeError`로 요약만 통과(스택트레이스 유입 차단).
- **워커 결합은 얇은 큐 계약으로만** — 백엔드는 큐잉·상태·콜백·WS relay만, 나노바나나 실호출·방어 로직은 워커(§6-4 PLANNING). `GEMINI_API_KEY` 백엔드 미접촉.
- 옥션 실시간 순위·라운드 마감 타이머, 서류/알림 생성도 Redis 재사용(동일 패턴). BI 집계는 배치/스냅샷(§2-3).
- **G1 게이트**: Gemini 외부 호출 미승인 시에도 큐잉/상태는 동작(목/degraded). 실호출·배포는 소유자 승인 후.
---
## 10. 역할별 프론트/백엔드 모듈화 원칙
### 10-1. 프론트 — 역할별 번들 분리 (PLANNING §2-1·§8-1)
6개 프론트를 **역할별 번들·도메인/서브패스 분리**로 배포해 최소권한·공격면 축소. **공유 디자인 시스템·공유 컴포넌트·공유 API 계약을 상속**(중복 구현 금지).
| 프론트 | 도메인(예) | 주 사용 모듈 | 채널 |
|---|---|---|---|
| 주최자 콘솔 | `organizer.` | M1·M2·M6·M15·M16·M12 | 데스크톱 주력 |
| 참가업체 포털 | `exhibitor.` | M3·M4·M5·M10·M11·M15·M9 | 데스크톱+모바일(리드캡처) |
| 업체 포털 | `contractor.` | M3·M4·M15·M8·M7 | 데스크톱+모바일(현장) |
| 운영 대시보드 | `ops.` | M2·M6·M8·M14·M16 | 데스크톱+모바일(검수) |
| 관리자 백오피스 | `admin.` | M18 | 웹 전용 |
| 공개/관람객 | `www`·`expo.` | M12·M10·M11·M13·M17 | 공개 SEO/SSR + 관람객 모바일 |
- **공유 계층**(모노레포 워크스페이스 권장): `packages/api-client`(계약 타입·fetch 래퍼·ApiResponse 언랩), `packages/ui`(공유 컴포넌트·디자인 토큰 `tokens.css`), `packages/auth`(JWT·2FA·라우팅 가드). 각 포털 앱은 이를 의존(역참조 금지).
- **기술 표준(스캐폴드)**: React 18 + Vite + TS, `react-router-dom`·`@tanstack/react-query`(서버 상태)·`zustand`(클라 상태)·`@stomp/stompjs`+`sockjs-client`(WS). 상세 빌드·라우팅은 tech.md(TA).
- **공개 홍보사이트(M12/M17)**: SEO/SSR·다국어(한/영/중/일)·CDN — 인증 앱과 **별도 렌더 경로**(공개 성능·검색 노출). 쓰기 불가.
### 10-2. 백엔드 — 단일 공유 모놀리식(모듈러) (PLANNING §8-1)
- **공유 Spring Boot 백엔드 1개**(모든 포털이 SSO+RBAC로 접근). 역할별로 백엔드를 쪼개지 않는다 — **모듈러 모놀리스**(`module.mN` 경계 + §4 의존 규칙)로 경계를 코드 레벨에서 강제.
- API 노출은 경로 접두(`/api/events/**`·`/api/admin/**`·`/api/public/**`)와 RBAC로 역할별 표면을 나눈다(별도 서비스 아님).
- 장래 서비스 분리가 필요하면 §4 모듈 경계가 분할선(느슨한 결합·이벤트 디커플이 선행 조건).
---
## 11. 신규 모듈 추가 체크리스트 (구현 에이전트용)
새 도메인 모듈(mN) 추가 시 본 표준 준수 확인:
1. 패키지 `com.zioinfo.kintex.module.mN` + 4계층(Controller·Service/Impl·dto·mapper) 생성(§1-2).
2. 컨트롤러는 가드→위임→`ApiResponse` 래핑만(§2-2, FloorplanController 패턴 복제).
3. 경로 `/api/events/{eventId}/…`(행사 스코프) 또는 `/api/admin/**`(플랫폼)(§5-1).
4. DTO는 record, 목록은 `PageResponse`, 오류는 `ApiException`+`ErrorCode`(§5-2/5-3).
5. 공간 데이터는 M2/M4 매퍼 권위 재사용(§3-2), 신규 지오메트리만 자기 매퍼 XML(PostGIS).
6. 크로스 모듈은 상대 `Service` 인터페이스로만, §4-2 방향 준수·순환 금지(이벤트 디커플).
7. 실시간은 `/topic/<도메인>/<id>` STOMP, 비동기는 Redis 큐(§8/§9).
8. 감사 대상 액션에 `@Audited`(§7-3), 알림은 `notification` 이벤트 발행(§7-6).
9. 보안 불변 5종(§5-6) 자체 점검 → QA 반려 방지.
10. 미완 구간은 `ApiException.notImplemented(...)`(501)로 계약만 확정(스캐폴드 관례).
---
## 12. 교차 아키텍처 참조 (링크)
- 시스템·NFR·배포 토폴로지 → `docs/architecture/system.md`(SA)
- 기술 표준·빌드/관측성·AiTextRouter → `docs/architecture/tech.md`(TA)
- 전사 ERD·공간데이터·마스터·BI 데이터마트 → `docs/architecture/data.md`(DA)
- DMZ/내부망·방화벽·외부 아웃바운드(Gemini) → `docs/architecture/network.md`(NA)
- P0 백엔드 API 계약(정본 예시) → `_workspace/01_backend_contracts.md`
- 기획·모듈 정의 → `docs/PLANNING.md` v2.0 · 실행 → `docs/IMPLEMENTATION_BACKLOG.md`
---
## 13. 변경 이력
| 버전 | 일자 | 작성자 | 내용 |
|---|---|---|---|
| v1.0 | 2026-07-11 | AA | 최초 — A-1. 패키지 구조(`com.zioinfo.kintex`)·4계층 레이어링·모듈 경계(P0 코어 M2~M5·도메인 M10~M18·공통 레이어 §5B)·의존성 규칙(common 무의존·모듈 단방향·순환 금지)·REST 표준(경로/버전/봉투/에러/페이징/인증)·이중 RBAC(플랫폼+행사)·WebSocket STOMP 규격·공통 컴포넌트(WISE 정합)·Redis 큐 계약·역할별 프론트 번들 분리 + 모듈러 모놀리스 백엔드. 스캐폴드(`src/backend`) 실측 정합, PLANNING v2.0 §8 정합. |