325 lines
27 KiB
Markdown
325 lines
27 KiB
Markdown
# 킨텍스 자동전시시스템 — 기술 표준 (Technical Architecture)
|
|
|
|
> 작성: 기술 아키텍트(TA) · 작성일: 2026-07-11 · 버전: v1.0
|
|
> 근거: `docs/PLANNING.md` v2.0(§8 확정 스택·§8-1 아키텍처 보강·§10 리스크)·`docs/IMPLEMENTATION_BACKLOG.md`(A-3)·실측 스캐폴드(`src/backend/build.gradle`·`src/backend/src/main/resources/application.yml`·`src/frontend/package.json`·`tools/nanobanana/`)·`.claude/agents/kintex-ai-dev.md`
|
|
> 교차참조: 앱 아키텍처 `docs/architecture/app.md`(A-1) · 시스템/NFR `docs/architecture/system.md`(A-2) · 데이터 `docs/architecture/data.md`(A-4) · 네트워크 `docs/architecture/network.md`(A-5)
|
|
> **문서 소유권**: 본 tech.md는 TA만 수정한다. 확정 스택·버전·빌드/배포·개발표준·관측성·AI 프로바이더 표준의 단일 출처(SSOT)다. 스택 변경은 본 문서 개정을 선행한다.
|
|
|
|
---
|
|
|
|
## 0. 이 문서의 위치
|
|
|
|
Phase A(아키텍처·거버넌스) 4개 표준 문서 중 **기술 표준(A-3)** 이다. 애플리케이션 경계·레이어(app.md), NFR·토폴로지(system.md), 데이터 모델(data.md), 네트워크(network.md)와 정합한다. 본 문서는 "무엇을 어떤 버전으로, 어떻게 빌드·배포·개발·관측하는가"의 기술 규범을 확정한다. 기능 범위·모듈 우선순위는 PLANNING이 권위이며 본 문서는 그 위 기술 계층만 다룬다.
|
|
|
|
핵심 원칙 4가지:
|
|
1. **실측 스캐폴드 정합** — 이미 스캐폴드된 실제 스택(Spring Boot 3.2.5·React 18.3.1·google-genai 워커)에 표기를 맞춘다. "3.x" 같은 느슨한 표기 대신 핀 버전을 SSOT로 둔다.
|
|
2. **GUARDiA/UIWS 표준 정렬** — kintex는 `zio/kintex` 독립 저장소이나 GUARDiA 표준 프레임워크(UIWS)와 스택·인증·AI 프로바이더 패턴을 공유한다.
|
|
3. **보안 불변 우선** — 시크릿 env-only, 스택트레이스·자격증명·PII 미노출, AES-256-GCM은 코드보다 상위 제약(§10, PLANNING §10·보안 불변).
|
|
4. **결정론과 폐쇄망 우선** — 규정/요율은 버전 관리 데이터, AI는 온프레미스 폴백 필수, 외부 아웃바운드는 승인된 도메인만.
|
|
|
|
---
|
|
|
|
## 1. 확정 기술 스택 (버전 표준·SSOT)
|
|
|
|
> 아래 버전은 **실측 스캐폴드에서 채택된 값**이다. 임의 상향/하향 금지 — 변경은 TA 승인 + 본 표 개정 후.
|
|
|
|
### 1-1. 백엔드 (Spring Boot · Java 17 · MyBatis)
|
|
|
|
`src/backend/build.gradle` 기준.
|
|
|
|
| 항목 | 표준 값 | 근거/비고 |
|
|
|---|---|---|
|
|
| 언어/런타임 | **Java 17** (`sourceCompatibility`/`targetCompatibility` = 17) | GUARDiA 표준(전 솔루션 Java 17 정렬). Java 21 금지 |
|
|
| 프레임워크 | **Spring Boot 3.2.5** | 핀 버전. `org.springframework.boot` 플러그인 |
|
|
| 의존성 관리 | `io.spring.dependency-management` **1.1.4** | Spring Boot BOM 정렬 |
|
|
| 빌드 도구 | **Gradle** (wrapper 동봉 `gradlew`/`gradlew.bat`) | 시스템 Gradle 미의존, wrapper 고정 |
|
|
| 그룹/패키지 | `com.zioinfo.kintex` / rootProject `kintex-backend` | GUARDiA 네이밍 규약 |
|
|
| 버전 | `0.1.0-SNAPSHOT` | SemVer, 릴리스 시 `-SNAPSHOT` 제거 |
|
|
| ORM | **MyBatis** `mybatis-spring-boot-starter` **3.0.3** | Spring Boot 3.2.x 호환 핀. JPA 금지(공간 SQL은 매퍼 XML) |
|
|
| DB 드라이버 | `org.postgresql:postgresql` (runtimeOnly, BOM 관리) | PostGIS 함수는 `ST_*` 매퍼 XML |
|
|
| 캐시/큐 | `spring-boot-starter-data-redis` | RenderJob·서류·알림 큐 + 옥션 실시간 순위 |
|
|
| 실시간 | `spring-boot-starter-websocket` (STOMP) | RenderJob 완료·옥션 순위 푸시 |
|
|
| 인증 | `spring-boot-starter-security` + **jjwt 0.12.5** (api/impl/jackson) | JWT HS256 + RBAC + TOTP 2FA |
|
|
| 검증 | `spring-boot-starter-validation` | DTO Bean Validation |
|
|
| 보일러플레이트 | Lombok (compileOnly + annotationProcessor) | |
|
|
| 테스트 | `spring-boot-starter-test` + `spring-security-test`, JUnit Platform | |
|
|
| 인코딩 | **UTF-8 강제** (`JavaCompile.options.encoding = 'UTF-8'`) | Windows javac CP949 한글 리터럴 손상 방지 — **불변, 전 모듈 유지** |
|
|
|
|
**MyBatis 규약**(application.yml 기준):
|
|
- `mapper-locations: classpath*:mybatis/mapper/**/*.xml`
|
|
- `map-underscore-to-camel-case: true`, `jdbc-type-for-null: NULL`
|
|
- `@MapperScan`은 GUARDiA 표준(`annotationClass = Mapper.class`) — 빈 누락 크래시 방지(다른 솔루션 회귀 이력). db-engineer가 공간 SQL 매퍼 XML 소유.
|
|
|
|
**Hikari 풀 표준**: `maximum-pool-size = ${DB_POOL_MAX:3}`. 공유 PostgreSQL 보호(GUARDiA 표준). kintex 전용 DB `kintex_db`라도 서버 공용 PG면 캡 유지. 상향 필요 시 SA(system.md)·DA와 합의.
|
|
|
|
### 1-2. 프론트엔드 (React · Vite · TypeScript)
|
|
|
|
`src/frontend/package.json`·`vite.config.ts`·`tsconfig.json` 기준.
|
|
|
|
| 항목 | 표준 값 | 비고 |
|
|
|---|---|---|
|
|
| UI 라이브러리 | **React 18.3.1** (`react`/`react-dom`) | PLANNING "18/19" 중 **18.3.1 확정 채택** |
|
|
| 빌드/번들러 | **Vite 5.4.8** + `@vitejs/plugin-react` 4.3.2 | dev 서버 :5173, `/api`·`/ws` 프록시 |
|
|
| 언어 | **TypeScript 5.6.2** (`strict: true`) | `noUnusedLocals`/`noUnusedParameters`/`noFallthroughCasesInSwitch` 켬 |
|
|
| 라우팅 | `react-router-dom` **6.26.2** | 역할별 포털 라우팅 |
|
|
| 서버 상태 | `@tanstack/react-query` **5.59.0** | API 캐싱·재검증 표준. 수동 fetch 지양 |
|
|
| 클라이언트 상태 | `zustand` **4.5.5** | 전역 상태(경량). Redux 금지 |
|
|
| 실시간 | `@stomp/stompjs` **7.0.0** + `sockjs-client` **1.6.1** | 백엔드 STOMP 정합 |
|
|
| 경로 별칭 | `@/*` → `src/*` (vite alias + tsconfig paths) | 상대경로 지옥 회피 |
|
|
| 모듈 타입 | `"type": "module"` (ESM), `target ES2020` | |
|
|
|
|
**빌드 스크립트**(package.json): `build = "tsc -b && vite build"`, `typecheck/lint = "tsc --noEmit"`. **타입 에러는 빌드 실패** — CI 게이트.
|
|
|
|
**역할별 프론트 분리**(PLANNING §2-1·§8-1): organizer·exhibitor·contractor·ops·admin(인증) + public/visitor(공개). **번들 분리** 방식은 designer/FE 트랙 결정(모노레포 다중 진입점 vs 서브패스). 공유 디자인 시스템(design.md)·공유 컴포넌트·공유 API 계약은 **상속**(중복 구현 금지). 현재 스캐폴드는 단일 Vite 앱(`src/frontend`) — 분리 실행 시 본 표준의 라이브러리 버전을 전 번들이 공유한다.
|
|
|
|
### 1-3. 나노바나나 Python 워커 (사이드카)
|
|
|
|
`tools/nanobanana/` 기준. PLANNING §8 "Python 워커 유지 근거"(google-genai는 Python SDK, ReRoomAI 검증 client.py 재사용 — Java 재구현 회피).
|
|
|
|
| 항목 | 표준 값 | 비고 |
|
|
|---|---|---|
|
|
| 런타임 | **Python 3.11+** (개발 실측 3.14 `__pycache__`) | 배포는 3.11/3.12 LTS 권장(3.14는 개발 로컬) |
|
|
| 이미지 SDK | **google-genai** (`pip install google-genai`) | Gemini image-to-image. 지연 임포트(무네트워크 import 성립) |
|
|
| 모델 | `gemini-3.1-flash-image-preview` (나노바나나 2, env `NANOBANANA_MODEL`) | 하드코딩 아님, env 오버라이드 |
|
|
| 이미지 처리 | **Pillow(PIL)** | S6 배선 오버레이 결정적 래스터 합성·목 플레이스홀더 |
|
|
| 큐/이벤트 | **redis** (`redis.from_url`, BLPOP 소비 + pub/sub 발행) | 지연 연결 |
|
|
| 실행 | `python -m tools.nanobanana.worker` (루프) / `--smoke` (무네트워크) | |
|
|
|
|
**워커 불변식**(worker.py 헤더): ①G1 게이트 — 실 Gemini 호출은 `NANOBANANA_LIVE=1` + `GEMINI_API_KEY` 동시 충족 시만, 기본 목/degraded. ②지연 연결 — Redis 미기동이어도 `process_job()` 직접 호출 성립. ③S6은 생성형 아님(항상 로컬 PIL). ④비밀 미노출(키/IP/스택트레이스 미기록).
|
|
|
|
**의존성 관리 표준**: 현재 워커에 `requirements.txt` **부재** — 배포 전 `tools/nanobanana/requirements.txt`(google-genai·Pillow·redis 핀 버전) 추가 필요(§9 백로그). devops-dev(DEV) 담당.
|
|
|
|
### 1-4. 데이터·인프라
|
|
|
|
| 항목 | 표준 값 | 비고 |
|
|
|---|---|---|
|
|
| DB | **PostgreSQL + PostGIS** (`kintex_db`) | 공간 데이터 일원화(부스 폴리곤·트렌치 포인트·배선 LineString). 상세 DA/data.md |
|
|
| 캐시/큐/실시간 | **Redis** | 작업 큐 + 옥션 라운드 타이머 + 순위 |
|
|
| 오브젝트 스토리지 | 로컬 FS(기본 degraded 어댑터) → S3/GCS(운영) | `ObjectStore.save_image()` 반환 계약 유지하며 어댑터 교체 |
|
|
| 마이그레이션 | **미확정** — B-0 백로그는 Flyway 명시(현 build.gradle 미포함) | §3-1 참조. TA 결정: Flyway 채택 권고 |
|
|
|
|
---
|
|
|
|
## 2. 통합 계약 (백엔드 ↔ 워커 ↔ 프론트)
|
|
|
|
### 2-1. RenderJob 큐 계약 (Spring → Redis → Python 워커)
|
|
|
|
Spring 백엔드가 RenderJob을 Redis 리스트에 push → 워커가 BLPOP 소비 → 오브젝트 스토리지 적재 → pub/sub 이벤트 발행 → 백엔드 구독 → WebSocket(STOMP) 프론트 푸시. 계약 단일 출처: `tools/nanobanana/_workspace/01_worker_contract.md`.
|
|
|
|
> **★ 실측 불일치(리스크 R-T1, §10)**: 큐/채널 키 기본값이 백엔드와 워커에서 다르다.
|
|
> - `application.yml`: `kintex.render.queue-key = kintex:renderjob:queue`
|
|
> - `worker.py`: `NANOBANANA_QUEUE 기본 = kintex:renderjobs`, `EVENT_CHANNEL 기본 = kintex:renderjob:events`
|
|
>
|
|
> 양측 모두 env 오버라이드 가능하나 **기본값 불일치는 배포 시 조용한 무처리(silent no-op)** 위험. **표준 확정**: 큐 키 `kintex:renderjob:queue`, 이벤트 채널 `kintex:renderjob:events`로 통일하고 배포 env(`RENDER_QUEUE_KEY`/`NANOBANANA_QUEUE`/`NANOBANANA_EVENT_CHANNEL`)를 동일 값으로 명시 주입. BE·VIZ·DEV가 `01_worker_contract.md`에 최종 키를 고정한다.
|
|
|
|
### 2-2. WebSocket(STOMP) 계약
|
|
|
|
- 백엔드 `WebSocketConfig`(STOMP) — 프론트 `@stomp/stompjs` + `sockjs-client`. dev는 Vite 프록시 `/ws`(ws:true).
|
|
- 이벤트: `renderjob.completed`/`renderjob.failed`(워커→백엔드→구독 클라), 옥션 순위 푸시(M15). 페이로드에 `image_ref`·`meta`(live/degraded 플래그) 포함, 비밀·스택트레이스 미포함.
|
|
|
|
### 2-3. API 응답 봉투
|
|
|
|
실측: `common/ApiResponse.java`·`common/PageResponse.java`·`common/error/GlobalExceptionHandler.java` 존재. 표준 응답 봉투 + 페이지 봉투 + 전역 예외 핸들러로 **에러 응답 표준화**(스택트레이스 미노출, `ErrorCode` 코드+요약 메시지만). 상세 계약은 app.md(A-1) 소유 — 본 문서는 정합만 명시.
|
|
|
|
---
|
|
|
|
## 3. 빌드·배포 표준
|
|
|
|
### 3-1. 백엔드 빌드 (Gradle · 단일 jar)
|
|
|
|
- 빌드: `./gradlew clean bootJar` → 단일 실행 jar(`build/libs/kintex-backend-<ver>.jar`). GUARDiA 단일 jar 표준.
|
|
- **프론트→백엔드 static 번들**(GUARDiA 표준 옵션): 운영 배포는 역할별 프론트 번들을 백엔드 static 리소스 또는 nginx 정적 서빙 중 택1. 역할별 프론트 분리(§1-2)이므로 **백오피스/포털별 별도 정적 서빙 + 공유 백엔드 jar** 토폴로지가 기본(system.md 확정). 공개사이트(M12/M17)는 SEO·다국어로 별도 렌더 경로(SSR/정적 생성).
|
|
- 테스트: `./gradlew test`(JUnit Platform). compileJava·test 통과가 배포 게이트.
|
|
- **마이그레이션(TA 결정)**: B-0가 Flyway를 명시하나 현 build.gradle 미포함. **Flyway 채택 권고** — `org.flywaydb:flyway-core` + `flyway-database-postgresql`(PostGIS 정합) 추가, `db/migration/V__*.sql`(PostGIS 확장·공간 인덱스 포함). 시드/후행 테이블은 GUARDiA 교훈(멱등화 + 누출 차단) 준수 — sql.init `mode=never` 후행 추가 테이블 미적용 회귀(schema-integrity 하네스 교훈) 방지. DB 스키마 상세는 DA/data.md.
|
|
|
|
### 3-2. 프론트 빌드 (Vite)
|
|
|
|
- `npm ci && npm run build`(= `tsc -b && vite build`) → `dist/`. 타입 에러 시 실패.
|
|
- 역할별 번들 분리 시 각 진입점 빌드 산출물을 도메인/서브패스별 배포.
|
|
- **★로컬 rollup win32 크래시 함정(리스크 R-T2, §10)**: GUARDiA 전 프로젝트에서 로컬 Windows rollup 네이티브 렌더 크래시가 반복 관측됨(homepage-renewal·CMS 등). **표준 대응**: (1) CI/서버 빌드(Linux) 신뢰 — 서버 `npm run build`가 권위. (2) 로컬 검증은 `tsc --noEmit`(typecheck)로 대체하거나 esbuild 경로. (3) `package-lock.json` 커밋으로 `npm ci` 재현성 확보. (4) 로컬 크래시가 서버 빌드 성공을 막지 않음 — 서버 번들 검증(최신 청크 diff)로 마무리.
|
|
|
|
### 3-3. 워커 배포 (systemd 서비스)
|
|
|
|
- 별도 프로세스(사이드카). systemd 유닛으로 상주(`ExecStart=python -m tools.nanobanana.worker`), `Restart=on-failure`.
|
|
- env(`EnvironmentFile` 또는 drop-in): `REDIS_URL`·`NANOBANANA_QUEUE`·`NANOBANANA_EVENT_CHANNEL`·`NANOBANANA_OUTPUT_DIR`·(G1 승인 후)`NANOBANANA_LIVE=1`·`GEMINI_API_KEY`. **GEMINI_API_KEY는 워커 env에만**(백엔드 미보유 — application.yml 주석 명시). GUARDiA 서버는 명령줄 인자 기동 서비스가 많아 **systemd drop-in EnvironmentFile 방식** 채택(기존 ExecStart 불변, guardia-claude-ai 트랙 패턴).
|
|
- 미승인(G2/G1 전) 기본 목/degraded 모드로 상주 가능(무네트워크).
|
|
|
|
### 3-4. CI/CD 파이프라인
|
|
|
|
GUARDiA 표준 흐름 정렬(솔루션 푸시 구조 메모리):
|
|
```
|
|
workspace/kintex (개발·SSOT)
|
|
→ repos/kintex (fresh git init — 모노레포 히스토리 상속 금지, bundle 비대화 방지)
|
|
→ Gitea zio/kintex (push)
|
|
→ webhook :9999 (deploy_server.py)
|
|
→ 서버 빌드(gradlew bootJar + npm build + 워커 배포) → systemd 재시작 → health 게이트
|
|
```
|
|
- **선행 게이트 G2**(BACKLOG): 배포 대상 서버·포트(GUARDiA 인프라와 별개 도메인) 확정 전 Phase E 착수 금지.
|
|
- **함정(GUARDiA 교훈, 배포블록 반영 필수)**: ①`repos/kintex`는 반드시 fresh `git init`(모노레포 `.git` 상속 시 bundle 1.5GB 회귀). ②`deploy_server.py`에 kintex 블록 추가 시 **서버 `/opt/zioinfo/deploy_server.py` 사본 반영 + `zioinfo-deploy` 재시작 필수**(로컬만 고치면 웹훅 1ms no-op). ③백엔드 jar만이 아니라 **워커 서비스도 배포 대상**(별도 systemd). ④health 200 확인이 완료 게이트.
|
|
|
|
### 3-5. 환경변수 표준 (시크릿 env-only)
|
|
|
|
application.yml은 **모든 시크릿을 플레이스홀더로만** 주입(하드코딩 금지, 주석 명시).
|
|
|
|
| env | 용도 | 소비자 |
|
|
|---|---|---|
|
|
| `DB_URL`/`DB_USER`/`DB_PASSWORD` | PostgreSQL(PostGIS) | 백엔드 |
|
|
| `DB_POOL_MAX` (기본 3) | Hikari 캡 | 백엔드 |
|
|
| `REDIS_HOST`/`REDIS_PORT`/`REDIS_PASSWORD` | Redis | 백엔드 |
|
|
| `REDIS_URL` | Redis(워커) | 워커 |
|
|
| `JWT_SECRET`(≥32B)/`JWT_ACCESS_TTL` | JWT HS256 | 백엔드 |
|
|
| `RENDER_QUEUE_KEY`/`NANOBANANA_QUEUE` | 큐 키(통일) | 백엔드/워커 |
|
|
| `NANOBANANA_EVENT_CHANNEL` | 이벤트 채널 | 워커/백엔드 |
|
|
| `RENDER_EVENT_QUOTA`(기본 500) | 행사별 생성 쿼터 | 백엔드 |
|
|
| `NANOBANANA_LIVE`/`GEMINI_API_KEY` | G1 승인 후 실 Gemini | **워커 전용** |
|
|
| `ANTHROPIC_API_KEY` | Claude AI(§6) | 백엔드 |
|
|
| `ADMIN_PASSWORD_ENC` + 키파일 | admin 비번(AES-256-GCM) | 백엔드 |
|
|
| `VITE_BACKEND_ORIGIN`/`VITE_API_BASE` | 프론트 오리진/프록시 | 프론트 |
|
|
|
|
**admin 비번**(B-1·GUARDiA 표준): `admin123` 등 평문 시드 **금지**. `ADMIN_PASSWORD_ENC`(AES-256-GCM) + 별도 키파일 주입, 최초 기동 재시드(guardia-claude-ai `guardia_master.key` 패턴).
|
|
|
|
---
|
|
|
|
## 4. 개발 표준
|
|
|
|
### 4-1. 코드 스타일
|
|
|
|
- **Java**: Google Java Style 기준(4-space, 100~120 col). Lombok 활용(`@Getter`/`@RequiredArgsConstructor`/`@Slf4j`), 필드 주입 금지(생성자 주입). 패키지 = 모듈별(`module.m2`·`module.m5`·`auth`·`common`·`config`) — app.md 경계 준수. **UTF-8 소스 필수**(build.gradle 강제).
|
|
- **TypeScript**: `strict` 전면. `any` 지양(불가피 시 주석). 컴포넌트 함수형, hooks 규약. 서버 상태는 react-query, 전역은 zustand. `@/*` 별칭 사용.
|
|
- **Python(워커)**: PEP 8 + type hints(`from __future__ import annotations`). 방어적 임포트(SDK/redis 지연). 비밀 미노출 규약(에러 메시지 300자 절단·키 미기록) 유지.
|
|
|
|
### 4-2. 테스트 표준
|
|
|
|
- **백엔드**: JUnit 5 + spring-security-test. 단위(서비스·룰엔진·요율 계산) + 슬라이스(`@WebMvcTest`/`@MyBatisTest`) + 통합(핵심 왕복). **필수 테스트**(GUARDiA feedback_test_required): 임포트/컴파일 검증 + 라우트 확인 + curl 응답. 룰엔진(규정·요율)·PostGIS 공간 SQL은 결정적 테스트 필수.
|
|
- **프론트**: `tsc --noEmit` 게이트(현 최소선). 확장 시 Vitest + Testing Library 권고(현 미도입).
|
|
- **워커**: `python -m tools.nanobanana.worker --smoke`(무네트워크 스모크) — 목 잡 S2 + S6 래스터 처리·사이드카 확인. CI 필수 게이트.
|
|
- **AI/외부 호출**: 목/degraded 경로가 무네트워크로 통과해야 함(폐쇄망·미승인 대비).
|
|
|
|
### 4-3. 브랜치·커밋 규약
|
|
|
|
- **브랜치**: `main`(보호) + 작업 브랜치(`feat/`·`fix/`·`chore/`). main 직접 커밋 금지(작업 브랜치 → PR). 기본 브랜치 push는 `origin HEAD:main`(BI repo master 함정 교훈 — repo별 기본 브랜치 확인).
|
|
- **커밋(Conventional Commits)**: `type(scope): summary`. type = `feat`/`fix`/`docs`/`refactor`/`test`/`chore`/`build`/`perf`. scope = 모듈(`m2`·`m5`·`auth`·`worker`·`bidding`). **커밋 메시지 영어**(kintex-ai-dev·visualizer 산출 규약). 예: `feat(m5): add renderjob quota guard`.
|
|
- **커밋 금지 대상**: 시크릿·`.env`·CAD zip(gitignore)·build 산출물. `.gitignore` 준수(`.gradle/`·`build/`·`*.log`·`.env`).
|
|
- **커밋/푸시 타이밍**: 사용자·오케스트레이터 명시 요청 시에만.
|
|
|
|
### 4-4. 저장소·문서 규약
|
|
|
|
- kintex는 **독립 저장소**(`zio/kintex`) — GUARDiA ITSM(관공서 관제)과 별개 도메인. R12 게이트상 Gemini 외부호출은 kintex 독립성과 무관하게 소유자 승인 선행.
|
|
- 아키텍처 문서는 `docs/architecture/`. PLANNING(planner)·design(designer) 소유권 존중 — 본 문서는 직접 수정하지 않고 교차참조.
|
|
|
|
---
|
|
|
|
## 5. 성능·관측성 표준
|
|
|
|
### 5-1. 로깅
|
|
|
|
- 백엔드: SLF4J/Logback(Spring Boot 기본). `logging.level.root: INFO`, `com.zioinfo.kintex: DEBUG`(개발). **운영은 INFO**로 하향(env `LOGGING_LEVEL_*` 오버라이드). 구조화(JSON) 로깅은 관측성 승격 시 권고.
|
|
- **로그 보안 불변**: 자격증명·IP·SSH·PII·스택트레이스 로그 금지. 워커는 예외 요약만(`type(e).__name__`), 키 미기록. `include-stacktrace: never` 유지.
|
|
- 상관관계: 요청별 traceId(MDC) 표준화 권고 — 옥션·RenderJob 비동기 흐름 추적.
|
|
|
|
### 5-2. 메트릭·트레이싱 (Observability)
|
|
|
|
- **표준(Micrometer + Actuator 권고)**: `spring-boot-starter-actuator` 추가(현 미포함) → `/actuator/health`(배포 게이트), `/actuator/metrics`, Prometheus `/actuator/prometheus`(GUARDiA guardia-rag `/metrics` 패턴 정렬).
|
|
- **핵심 지표**: RenderJob 처리량·지연·실패율(목/live 구분), 큐 적체(Redis 리스트 길이), 옥션 순위 계산 지연, PostGIS 공간 쿼리 지연, Hikari 풀 사용률, AI 프로바이더 폴백 발생률(Claude→Ollama).
|
|
- **트레이싱**: OpenTelemetry(OTel)는 관측성 트랙 승격 시(GreenOps/observability-platform 패턴). 초기는 로그 상관관계 + Actuator 메트릭.
|
|
- health 계약: 배포 후 `/actuator/health` 200이 완료 게이트(§3-4). 워커는 하트비트/최근 처리 시각을 이벤트/로그로 관측(전용 health 엔드포인트 부재 — 큐 소비 로그로 감시).
|
|
|
|
### 5-3. 성능 표준·부하 목표
|
|
|
|
PLANNING §10 리스크(R6 이미지 비용·지연) 정렬:
|
|
- **이미지 생성**(R6): 홀당 200~600부스 동시 생성 시 비용/지연 급증. **표준**: 자동 생성은 S1·S7 한정 + **온디맨드 + 스키마 해시 캐시**(client.py 캐시) + **행사별 쿼터**(`RENDER_EVENT_QUOTA` 기본 500). 워커는 성공 시에만 쿼터 차감(worker 방어 로직).
|
|
- **PostGIS 대량 배치**: 부스 폴리곤·배선 LineString 대량 연산은 공간 인덱스(GiST) 전제. 배치 배치도 생성·정산 집계는 트랜잭션 분할.
|
|
- **BI 집계**(M16, PLANNING §8-1): 운영 DB 부하 회피 — 배치/스냅샷(KpiSnapshot) 또는 읽기 전용 복제. 실시간 대시보드 직접 집계 지양.
|
|
- **비동기 우선**: 이미지·서류·알림·PDF(옥션 견적서)는 전면 Redis 큐 경유(동기 블로킹 금지).
|
|
|
|
---
|
|
|
|
## 6. AI 프로바이더 기술 표준 (Claude 기본 + 설정형 전환)
|
|
|
|
> 근거: `.claude/agents/kintex-ai-dev.md`·GUARDiA guardia-claude-ai 트랙·UIWS 패턴. 나노바나나(Gemini 이미지)는 **별개**(visualizer·§1-3·G1 게이트) — 본 절은 **텍스트/지능 AI**(부스배치 조건해석·규정검증 보조·예측·매칭·서류검수·챗봇).
|
|
|
|
### 6-1. 프로바이더 라우팅 아키텍처
|
|
|
|
UIWS 표준 3-컴포넌트(현 스캐폴드 **미구현** — AI 모듈 착수 시 신설):
|
|
- **`ClaudeTextClient`**: Anthropic Claude API(`api.anthropic.com` — 소유자 승인 예외 2026-07-03) 호출. 키는 env `ANTHROPIC_API_KEY`에서만 로드(코드·DB·로그·커밋·응답 기록 금지).
|
|
- **`AiTextRouter`**: 프로바이더 선택·폴백 오케스트레이션. **기본 Claude → 실패 시 Ollama 자동 폴백**(온프레미스 소형: `qwen3:1.7b`·`llama3.2:1b` 등). 하드코딩 금지.
|
|
- **`AiConfig`/`AiConfigService` + 설정 화면**: 런타임 프로바이더/모델 전환(화이트리스트 `claude-*` 기본 + 승인된 Ollama). generation_model·temperature·top_k·enabled 설정.
|
|
|
|
### 6-2. 폴백·폐쇄망·결정론
|
|
|
|
- **Ollama 폴백 필수**(폐쇄망·Claude 장애 대비). RAM 제약 준수 — 서버 가용 ~2GB, 대형 모델 금지(소형만, [[project_ollama_ram_constraint]]).
|
|
- **결정론 기능**(분류·추출·서류검수): 구조화 출력(`format:json`). 환각 방지 — 근거 없는 답변 보류·인용(guardia-ai-trust 정렬).
|
|
- **부스 배치(M2)**: 생성형 LLM이 배치를 만드는 것이 아니라 **제약 솔버/휴리스틱**이 3안 생성, LLM은 조건 해석·설명에만(kintex-ai-dev 규약).
|
|
|
|
### 6-3. 외부 아웃바운드 게이트 (불변)
|
|
|
|
| 도메인 | 상태 | 조건 |
|
|
|---|---|---|
|
|
| `api.anthropic.com` | **승인**(2026-07-03 소유자 예외) | Claude 텍스트 AI. 키 env-only, 실패 시 Ollama 폴백 |
|
|
| `generativelanguage.googleapis.com` | **미승인 게이트 G1**(PLANNING R12) | 나노바나나. M5 실호출 착수 전 소유자 승인 선행. 미승인 시 목/degraded |
|
|
| 그 외 외부 API | **금지** | GUARDiA 보안 불변 |
|
|
|
|
네트워크 아웃바운드 화이트리스트·프록시는 network.md(A-5) 소유. 본 문서는 AI 게이트만 확정.
|
|
|
|
---
|
|
|
|
## 7. 보안 기술 표준 (불변 요약)
|
|
|
|
PLANNING §10·GUARDiA 보안 불변 정렬(상세는 app.md/network.md):
|
|
- **시크릿 env-only** — 코드·DB·커밋·로그·응답 기록 금지. application.yml 플레이스홀더만.
|
|
- **자격증명·PII·스택트레이스 미노출** — API 응답/에러/로그/이벤트. `include-stacktrace: never`, 워커 에러 요약만.
|
|
- **AES-256-GCM** — admin 비번(`ADMIN_PASSWORD_ENC`)·민감 자격증명. 별도 키파일.
|
|
- **인증**(B-1): JWT(HS256, jjwt 0.12.5) + RBAC(6역할·행사 단위) + **TOTP 2FA(RFC6238)** + 로그인 실패 잠금. UIWS 이식.
|
|
- **AI 워터마크**(R1): 나노바나나 전 이미지 "AI 생성 예상 — 실제 시공과 다를 수 있음" 고지 강제(worker 목/live 공통). 계약·심사 서류 자동 배제.
|
|
- **등록업체 게이트**(M15): 미등록 업체 옥션 응찰 원천 차단(M7 검증).
|
|
|
|
---
|
|
|
|
## 8. 기술 리스크 · PoC
|
|
|
|
PLANNING §10(R1~R12)의 **기술 실행 리스크**를 TA 관점으로 구체화. 도메인/법적 리스크(R1·R2·R8·R9·R10)는 PLANNING 소유.
|
|
|
|
### 8-1. TA 신규/구체화 리스크
|
|
|
|
| # | 리스크 | 영향 | 완화·PoC |
|
|
|---|---|---|---|
|
|
| **R-T1** | **큐/이벤트 키 기본값 불일치**(§2-1) — application.yml `kintex:renderjob:queue` vs worker.py `kintex:renderjobs` | 높음(배포 시 조용한 무처리) | 키 통일(`kintex:renderjob:queue`/`kintex:renderjob:events`) + `01_worker_contract.md` 고정 + 배포 env 명시. **PoC: 백엔드 push → 워커 소비 → WebSocket 완료 왕복 스모크** |
|
|
| **R-T2** | **로컬 rollup win32 크래시**(§3-2) — Windows Vite 빌드 네이티브 렌더 크래시(GUARDiA 반복 관측) | 중간(로컬 개발 저해) | 서버 빌드 신뢰 + `tsc --noEmit` 로컬 게이트 + `package-lock.json` 커밋(`npm ci` 재현) |
|
|
| **R-T3** | **PostGIS 대량 배치 성능** — 홀당 200~600부스 폴리곤·배선 최단경로·통로버퍼 검증 대량 연산 | 중간 | GiST 공간 인덱스 + 매퍼 XML `ST_*` 튜닝 + 배치 분할. **PoC: 600부스 배치도 생성·규정검증 SQL 부하 측정**(DA 협업) |
|
|
| **R-T4** | **이미지 큐 부하**(PLANNING R6) — 대량 동시 RenderJob 비용·지연 | 중간 | S1/S7 한정 자동생성 + 스키마 해시 캐시 + 행사 쿼터(500) + 워커 동시성 제한. **PoC: 목 모드 N=500 잡 큐 처리량·적체 측정**(무비용) |
|
|
| **R-T5** | **Flyway 부재**(§3-1·B-0 명시) — 마이그레이션 도구 미결정, 후행 테이블 미적용 회귀(GUARDiA schema-integrity 교훈) | 중간 | Flyway 채택 + 멱등 스키마 + 누출 차단. DA와 확정 |
|
|
| **R-T6** | **워커 requirements.txt 부재**(§1-3) — 의존성 핀 미고정 | 낮음 | `tools/nanobanana/requirements.txt` 추가(google-genai·Pillow·redis 핀). DEV 담당 |
|
|
| **R-T7** | **AiTextRouter/AiConfig 미구현**(§6-1) — AI 프로바이더 표준 코드 부재 | 낮음(설계 확정, 착수 대기) | AI 모듈 착수 시 UIWS 패턴 이식. Ollama 폴백 무네트워크 검증 |
|
|
|
|
### 8-2. 권장 PoC 순서 (TA 실행 가능·Bash)
|
|
|
|
1. **워커 스모크**(무네트워크·무비용) — `python -m tools.nanobanana.worker --smoke`. S2 목 + S6 래스터 사이드카 확인. **즉시 실행 가능**.
|
|
2. **큐 왕복 PoC**(R-T1) — 로컬 Redis + 백엔드 push + 워커 소비 스모크(키 통일 검증).
|
|
3. **PostGIS 배치 PoC**(R-T3) — 600부스 합성 데이터로 배치·검증 공간 SQL EXPLAIN ANALYZE.
|
|
4. **이미지 큐 부하 PoC**(R-T4) — 목 모드 500잡 처리량·적체.
|
|
|
|
> 본 구현은 구현 에이전트(BE·VIZ·DB·AI)가 표준대로 수행. TA는 PoC 스크립트 실행·표준 개선만.
|
|
|
|
---
|
|
|
|
## 9. 미결 사항 (구현 착수 전 확정 필요)
|
|
|
|
| # | 항목 | 담당 | Phase |
|
|
|---|---|---|---|
|
|
| 1 | 큐/이벤트 키 통일(R-T1) → `01_worker_contract.md` 고정 | BE·VIZ·DEV | B/C |
|
|
| 2 | Flyway 채택·마이그레이션 구조(R-T5) | DA·DB·TA | B-0 |
|
|
| 3 | Actuator/Micrometer 관측성 의존성 추가(§5-2) | DEV·TA | B |
|
|
| 4 | 워커 `requirements.txt` 핀(R-T6) | DEV | C-M5 |
|
|
| 5 | 역할별 프론트 번들 분리 방식(§1-2) 확정 | DES·FE | C/D |
|
|
| 6 | `AiTextRouter`/`AiConfig` 이식(§6-1) | AI·BE | D |
|
|
| 7 | 배포 서버·포트·도메인(G2) | DEV·SA | E |
|
|
| 8 | Gemini 외부호출 승인(G1) | 소유자 | C-M5 |
|
|
|
|
---
|
|
|
|
## 10. 변경 이력
|
|
|
|
| 버전 | 일자 | 작성자 | 내용 |
|
|
|---|---|---|---|
|
|
| v1.0 | 2026-07-11 | TA | 최초 작성(A-3). 실측 스캐폴드 정합 — 확정 스택 핀 버전(Spring Boot 3.2.5·MyBatis 3.0.3·jjwt 0.12.5·React 18.3.1·Vite 5.4.8·TS 5.6.2·google-genai 워커) SSOT화, 빌드·배포(Gradle 단일 jar·Vite·워커 systemd·CI/CD)·개발표준(코드스타일·테스트·Conventional Commits·브랜치)·관측성(로깅·Actuator/Micrometer·성능목표)·AI 프로바이더(Claude 기본+AiTextRouter/AiConfig+Ollama 폴백·외부 아웃바운드 게이트)·기술 리스크7종(R-T1~R-T7)+PoC 확정. ★실측 불일치 발견: 큐 키 기본값 백엔드/워커 상이(R-T1) — 통일 표준 제시. app.md/system.md/data.md/network.md 교차참조 |
|