# INVION — Low-Code ERP/PLM Platform ## 프로젝트 개요 **INVION**은 제조업 특화 Low-Code ERP/PLM(Product Lifecycle Management) 플랫폼입니다. 사용자가 런타임에 화면·테이블·워크플로우를 정의할 수 있는 **메타데이터 기반 설계**로, 코드 수정 없이 업무 화면을 구성합니다. Spring Boot + Next.js 풀스택 구조이며, 멀티테넌시(company_code 기반)로 복수 기업을 단일 인스턴스에서 운영합니다. ## 주요 특징 - **Low-Code 화면 디자이너**: 드래그앤드롭으로 업무 화면 구성, V2 컴포넌트 시스템 - **Spring Boot 백엔드**: Java 21 + MyBatis (SqlSessionTemplate) + PostgreSQL - **v5 Cosmic Glassmorphism UI**: 코스믹 배경 + 글래스 블러 기반 모던 디자인 시스템 - **멀티테넌시**: company_code 기반 데이터 격리, Super Admin 전사 접근 - **반응형 디자인**: 데스크톱 / 태블릿 / 모바일 완전 대응 - **3D / 차트 / 지도**: React Three Fiber, Recharts, Leaflet 통합 - **GitOps 배포**: Jenkins + Kaniko + Helm + Traefik (Kubernetes) ## 기술 스택 ### Frontend | 영역 | 기술 | 비고 | |------|------|------| | 프레임워크 | **Next.js 15** (App Router, Turbopack) | React 19 | | 언어 | **TypeScript 5** | strict mode | | 스타일링 | **Tailwind CSS v4** + v5 커스텀 CSS (`--v5-` prefix) | 글래스모피즘 테마 | | UI 라이브러리 | **shadcn/ui** + Radix UI (15개 컴포넌트) | 커스텀 오버라이드 | | 상태 관리 | **Zustand 5** (글로벌) + **TanStack Query 5** (서버) | | | 테이블 | **TanStack Table** + **TanStack Virtual** | 가상 스크롤 | | HTTP 클라이언트 | **Axios** | 70개 API 모듈 (`lib/api/`) | | 플로우 디자이너 | **XY Flow** (@xyflow/react) | 데이터플로우 | | 3D | **React Three Fiber** + Drei | Digital Twin | | 차트 | **Recharts** + **D3** | 대시보드 / 분석 | | 지도 | **Leaflet** + React Leaflet | 위치 기반 시각화 | | 리치 텍스트 | **Tiptap** | 에디터 | | 드래그앤드롭 | **DnD Kit** | 화면 디자이너 / 탭 정렬 | | 폼 | **React Hook Form** + **Zod** | 유효성 검증 | | 문서 생성 | **jsPDF** + **exceljs** + mammoth | PDF / Excel / Word | | 바코드 / QR | **jsbarcode** + **qrcode** + @zxing | 스캔 / 생성 | | 아이콘 | **Lucide React** | | ### Backend — Spring Boot | 영역 | 기술 | 비고 | |------|------|------| | 언어 | **Java 21** | LTS | | 프레임워크 | **Spring Boot 3.3.5** | | | 빌드 | **Gradle** (Groovy DSL) | | | SQL Mapper | **MyBatis 3** (SqlSessionTemplate 직접 사용) | Mapper Interface 미사용 | | 데이터베이스 | **PostgreSQL** + HikariCP | | | 보안 | **Spring Security** + JWT (jjwt 0.12.3) | | | JSON | **Jackson** (숫자→문자열 직렬화, null 키 포함) | | | 메일 | **Spring Boot Starter Mail** | IMAP 수신 + SMTP 발신 | | 로깅 | **SLF4J + Logback** | Spring Boot 기본 | > **아키텍처 핵심**: `Map` 기반 — Low-Code 플랫폼 특성상 테이블/컬럼이 런타임에 결정되므로 DTO 클래스를 사용하지 않습니다. Service에서 `sqlSession`으로 XML을 직접 호출하는 3레이어 구조입니다. > > ``` > Controller → Service (extends BaseService) → XML Mapper > ``` ### 개발 도구 | 영역 | 기술 | |------|------| | 컨테이너화 | Docker + Docker Compose | | 백엔드 핫리로드 | **Spring Boot DevTools** | | 코드 품질 | ESLint + Prettier | | CI/CD | **Jenkins** + **Kaniko** (이미지 빌드) | | 오케스트레이션 | **Kubernetes** + **Helm** (GitOps) | | 리버스 프록시 | **Traefik** (HTTPS, Let's Encrypt) | | 컨테이너 레지스트리 | `registry.kpslp.kr` (프라이빗) | ## 프로젝트 구조 ``` INVION/ ├── frontend/ # Next.js 15 프론트엔드 │ ├── app/ # App Router 페이지 │ │ ├── (main)/ # 메인 레이아웃 (인증 후) │ │ ├── (auth)/ # 로그인/인증 │ │ ├── (admin)/ # 관리자 페이지 │ │ └── (pop)/ # 팝업 페이지 │ ├── components/ # React 컴포넌트 (~27개 도메인) │ │ ├── ui/ # shadcn/ui 기본 컴포넌트 │ │ ├── layout/ # AppLayout, TabBar, Sidebar, Header │ │ ├── screen/ # 화면 디자이너 (~57개 파일) │ │ ├── dataflow/ # 데이터플로우 디자이너 │ │ ├── v2/ # V2 동적 컴포넌트 시스템 │ │ ├── admin/ # 관리자 컴포넌트 │ │ ├── approval/ # 전자결재 │ │ ├── flow/ # 워크플로우 │ │ ├── barcode/ # 바코드/라벨 │ │ ├── report/ # 리포트 │ │ ├── mail/ # 메일 │ │ ├── multilang/ # 다국어 │ │ ├── animations/ # 애니메이션 컴포넌트 │ │ └── ... # dashboard, vehicle, tax-invoice 등 │ ├── lib/ # 유틸리티, API 클라이언트, 서비스 │ │ ├── api/ # Axios 기반 API 클라이언트 (70개 모듈) │ │ ├── stores/ # Zustand 스토어 │ │ ├── schemas/ # Zod 스키마 │ │ ├── services/ # 프론트 비즈니스 로직 │ │ └── types/ # TypeScript 타입 정의 │ ├── stores/ # 글로벌 Zustand 스토어 │ ├── hooks/ # Custom React Hooks │ └── styles/ # v5-layout.css (글래스모피즘) │ ├── backend-spring/ # Spring Boot 백엔드 (95 컨트롤러, 97 서비스, 96 XML) │ └── src/main/ │ ├── java/com/erp/ │ │ ├── common/ # BaseService (sqlSession 주입) │ │ ├── config/ # Security, MyBatis, Jackson, Exception │ │ ├── controller/ # @RestController │ │ ├── service/ # @Service extends BaseService │ │ ├── security/ # JWT 인증 │ │ └── util/ # 유틸리티 │ └── resources/ │ ├── application.yml │ └── mapper/ # MyBatis XML (소문자 camelCase) │ ├── db/ # 데이터베이스 │ └── migrations/ # 순차 마이그레이션 SQL ├── docker/ # Docker 설정 (dev/prod/deploy) ├── scripts/ # 개발/배포 스크립트 (dev/prod) ├── Dockerfile # 프로덕션 멀티스테이지 빌드 (Spring + Next.js) └── Jenkinsfile # CI/CD 파이프라인 (Kaniko + Helm) ``` ## 빠른 시작 ### 1. 필수 요구사항 - **Java**: 21 - **Node.js**: **22 LTS+** (`frontend/package.json` 의 `engines.node` 에 `>=22.0.0` 강제. 프로젝트 루트에 `.nvmrc` 박혀있어 `nvm use` 로 자동 전환됨) - **PostgreSQL**: 데이터베이스 서버 - **npm**: 10.0+ ### 2. 개발 환경 실행 ```bash # 프론트엔드 (Turbopack, port 9771) cd frontend && npm install && npm run dev # 백엔드 — Spring Boot (port 8081) cd backend-spring && ./gradlew bootRun ``` ### 3. Docker 환경 실행 (dev) frontend + backend 한 컴포즈 파일로 띄움. 코드 변경은 volume mount 로 컨테이너 안에 즉시 반영됨 (turbopack 자동 리로드). ```bash # 개발 환경 한 번에 띄우기 docker compose -f docker/dev/docker-compose.invyone.yml up -d # 내리기 / 재시작 / 로그 docker compose -f docker/dev/docker-compose.invyone.yml down docker compose -f docker/dev/docker-compose.invyone.yml restart docker compose -f docker/dev/docker-compose.invyone.yml logs -f # 프로덕션 배포 (별도) docker compose -f docker/deploy/docker-compose.yml up -d ``` ### 4. 서비스 접속 | 환경 | 서비스 | URL | 설명 | |------|--------|-----|------| | **로컬 dev** (`npm run dev` / `gradlew bootRun`) | 프론트엔드 | http://localhost:9771 | Next.js (turbopack) | | | 백엔드 API | http://localhost:8081 | Spring Boot | | **도커 dev** (위 컴포즈) | 프론트엔드 | http://localhost:9772 | 컨테이너 내부 3000 → 호스트 9772 | | | 백엔드 API | http://localhost:8083 | 컨테이너 내부 8081 → 호스트 8083 | > 프론트엔드는 `next.config.mjs` 의 rewrites 설정으로 `/api/*` 요청을 백엔드로 프록시합니다 (도커 컴포즈에서는 컨테이너 네트워크 내부 이름 `invyone-backend-spring:8081` 로 프록시). ## 주요 기능 ### 1. 화면 디자이너 (Screen Designer) - 드래그앤드롭 기반 업무 화면 구성 - 그리드 레이아웃 빌더 + 레이어 관리 - V2 동적 컴포넌트 시스템 (Input, Select, Date, List, Hierarchy, Media 등) - 화면 복사 / 메뉴 할당 / 임베딩 ### 2. 데이터플로우 디자이너 (Data Flow) - XY Flow 기반 비주얼 데이터 흐름 설계 - 테이블 노드 + 관계 에지 + 외부 호출 노드 - 조건부 로직 / 연결 설정 ### 3. 사용자 및 권한 관리 - 역할 기반 접근 제어 (RBAC) - 부서/조직 계층 관리 - 멀티테넌시 (company_code 기반 데이터 격리) ### 4. 전자결재 (Approval) - 결재 요청/승인/반려 워크플로우 - 글로벌 리스너 기반 실시간 알림 ### 5. 제품/BOM 관리 - BOM 구성 및 버전 관리 - 제품 카테고리 트리 ### 6. Digital Twin / 3D 시각화 - React Three Fiber 기반 3D 뷰 - Yard Layout 시각화 - Digital Twin 템플릿 관리 ### 7. 기타 기능 - 메일 연동 (IMAP 수신 + SMTP 발신) - 바코드/QR 생성 및 스캔 (jsbarcode + qrcode + @zxing) - 대시보드 차트 (Recharts + D3) - 지도 시각화 (Leaflet) - 리포트 / 세금계산서 - 문서 생성 (PDF, Excel, Word) - 다국어 지원 - 번호 채번 규칙 - 배치 스케줄링 - 파일/문서 관리 ## 디자인 시스템 — v5 Cosmic Glassmorphism INVION v5는 **코스믹 글래스모피즘** 디자인 언어를 사용합니다. - **코스믹 배경**: 별/파티클/성운 애니메이션 (`CosmicBackground.tsx`) - **글래스 UI**: `backdrop-filter: blur()` 기반 반투명 패널 - **CSS 변수**: `--v5-` prefix로 shadcn/Tailwind 변수와 충돌 방지 - **다크/라이트 테마**: 크로스페이드 전환 애니메이션 - **모션 디테일**: 모든 전환/호버/진입에 애니메이션 적용 (CSS 기반, framer-motion 미사용) 주요 스타일 파일: - `frontend/styles/v5-layout.css` — v5 전체 CSS - `frontend/app/(auth)/login/login.css` — 로그인 전용 ## 환경 변수 ```yaml # backend-spring/src/main/resources/application.yml server: port: 8081 spring: datasource: url: jdbc:postgresql://host:port/dbname username: postgres password: **** jwt: secret: your-jwt-secret expiration: 86400000 file: upload-dir: ./uploads ``` ```bash # frontend/.env.local — 클라이언트(브라우저) 가 사용할 API base URL # 반드시 상대경로 "/api" 로 둘 것. 절대 URL (예: http://localhost:8083/api) 을 박으면 # 다른 머신/도메인에서 접속할 때 클라이언트가 자기 자신을 찌르며 connection refused 발생함. # next dev server 의 rewrites 가 "/api/*" 를 컨테이너 내부 backend 로 프록시한다. NEXT_PUBLIC_API_URL=/api ``` ## 배포 ### 프로덕션 빌드 ```bash # 멀티스테이지 Docker 빌드 (Spring Boot + Next.js → 단일 컨테이너) docker build -t invion . ``` 멀티스테이지 빌드 과정: 1. **Stage 1** — Spring Boot 빌드 (`eclipse-temurin:21-jdk-alpine`, Gradle → bootJar) 2. **Stage 2** — Next.js 빌드 (`node:22-alpine`, npm → standalone) 3. **Stage 3** — 런타임 (`eclipse-temurin:21-jre-alpine` + Node.js, 두 서비스 병렬 실행) ### CI/CD 파이프라인 ``` Git Push → Jenkins → Kaniko 이미지 빌드 → 프라이빗 레지스트리 푸시 → Helm 차트 태그 업데이트 → Kubernetes 자동 배포 (GitOps) ``` - **이미지 빌드**: Kaniko (Docker-in-Docker 불필요) - **레지스트리**: `registry.kpslp.kr` (프라이빗) - **배포**: Helm 차트 + GitOps (이미지 태그 자동 업데이트) - **프로덕션 도메인**: Traefik 리버스 프록시 + Let's Encrypt HTTPS ## 알려진 설정 정책 후임자/협업자가 "이거 왜 이렇게 짜놨지?" 헷갈리지 않도록 의도가 있는 비명시적 결정만 정리. ### `frontend/next.config.mjs` — `isDev` 분기 `output: "standalone"` 과 `experimental.webpackMemoryOptimizations` 는 **prod build 에서만 켜진다** (`NODE_ENV !== "production"` 이면 비활성화). dev 모드에서 같이 켜면 다음 두 가지 부작용이 동시에 발생함: - `output: standalone` 이 dev 청크 manifest 경로 처리를 깨트림 → 라우트 그룹 `(main)/(auth)` 의 layout/page 청크가 `_next/static/chunks/...` 에 못 만들어짐 - `webpackMemoryOptimizations` 가 컴파일된 SSR 청크를 GC 해버려서 첫 visit 후 ENOENT 발생 → ChunkLoadError 영구화 → 두 옵션은 절대 dev 에서 켜지 말 것. prod build 에서만 의미 있음. ### `docker/dev/frontend.Dockerfile` — turbopack 강제 `dev:docker` 스크립트에 `--turbopack` 플래그가 박혀있다. 도커에서 webpack 으로 돌리면 next 15 + app router + 라우트 그룹 `(main)/(auth)` 조합에서 layout/page 청크가 disk 에 flush 되지 않는 케이스가 발생함. 로컬 dev (`npm run dev`) 도 동일하게 turbopack 사용. 베이스 이미지는 `node:22-alpine`. ### Frontend → Backend API 호출 — 반드시 상대경로 위 "환경 변수" 섹션 참고. `NEXT_PUBLIC_API_URL` 에 절대 URL 을 박으면 안 된다. `/api` 로 두고 `next.config.mjs` 의 rewrites 가 처리하도록 위임. ## 코드 컨벤션 ### 네이밍 규칙 | 레이어 | 케이스 | 예시 | |--------|--------|------| | DB 컬럼/테이블 | UPPER_SNAKE_CASE | `SCREEN_ID`, `COMPANY_CODE` | | MyBatis XML SQL | UPPER_SNAKE_CASE | `SELECT SCREEN_ID FROM SCREEN_DEFINITIONS` | | MyBatis #{파라미터} | camelCase | `#{screenId}`, `#{companyCode}` | | API 응답 키 (Map) | lower_snake_case | `screen_id`, `company_code` | | 프론트 타입 필드 | lower_snake_case | `screen_id`, `menu_name_kor` | | JS 변수/함수/props | camelCase | `screenId`, `handleClick` | ### 공통 규칙 - **TypeScript**: strict mode 활성화 - **ESLint + Prettier**: 일관된 코드 스타일 - **shadcn/ui**: UI 컴포넌트 표준 - **API 클라이언트**: `frontend/lib/api/` Axios 기반 전용 클라이언트 사용 (fetch 직접 사용 금지) - **멀티테넌시**: 모든 쿼리에 company_code 필터링 필수 - **Map 기반**: Spring Boot 백엔드는 DTO 대신 `Map` 사용 - **snake→camel 변환 금지**: `toCamelCaseKeys()` 등 변환 함수 사용 불가 - **MyBatis 설정**: `map-underscore-to-camel-case: false` 유지