# 킨텍스 자동전시시스템 — 애플리케이션 아키텍처 표준 (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`/도메인)를 **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 — 스캐폴드 정본) 모든 REST 응답은 `common.ApiResponse`를 사용한다(예외 없음). ```json { "success": true, "data": { ... }, "error": null } { "success": false, "data": null, "error": { "code": "FORBIDDEN", "message": "요약 메시지" } } ``` - 성공은 컨트롤러가 `ApiResponse.ok(dto)`. 실패는 **던지고**(ApiException) `GlobalExceptionHandler`가 봉투로 변환(컨트롤러에서 실패 봉투 수동 조립 금지). - **목록**: `common.PageResponse` = `{ 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`. - 필터는 명시 쿼리 파라미터(자유 텍스트 SQL 금지). 통합검색(공통 search)은 별도 검색 서비스 경유. ### 5-5. 인증 헤더·공개 경로 - `Authorization: Bearer `(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`(record: success·data·error{code,message})·`common.PageResponse`. §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/<도메인>/` 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 정합. |