한컴인스페이스

국가보안기관 위성영상 AI 처리 플랫폼 - 개발·운영·신규 구축

2022.07 ~ 진행중
풀스택 개발 → 시스템 운영·인프라 구축
Kubernetes 1.19Docker 19.03Rocky Linux 8.11Go 1.24PostgreSQL 15GDAL 3.4Zabbix 6.4ShellSpring Boot 3.1Java 17MyBatisPostGISCesiumJSJSPjQueryTomcatJenkinsSpring Session

아키텍처 - 멀티모듈 다중 WAR (Tomcat)

콘텐츠 관리 웹
자료·표적 등록 화면
판독·분석 웹
CesiumJS 3D 판독 화면
API 서버
REST API · MyBatis · PostGIS
↓   ↓
인증 서버
세션 인증 · Spring Session + Redis
파일 서버
대용량 다운로드 · 이어받기
Spring Boot + jQuery/JSP · 공통 base 모듈 · Jenkins 멀티모듈 빌드 → WAR 배포

국가보안기관 위성영상 시스템을 4년째 책임지고 있습니다. Spring Boot·MyBatis·PostGIS·CesiumJS 기반 시스템에서 판독보고서 생성·어드민·위성 ETL(수집·전처리·적재)·AI 분석 연동 등 핵심 도메인 서비스를 개발·운영했고, 이후 에어갭 환경 운영과 신규 플랫폼 구축까지 이어서 맡았습니다.

초기 2년(2022.07~2024.07)은 콘텐츠 관리·판독 분석 웹 프론트엔드부터 REST API·인증 서버·대용량 다운로드 서버까지 처음부터 끝까지 개발하며 레거시 모듈을 점진적으로 전환했고, 이후 위성영상 AI 처리 플랫폼을 인터넷이 완전히 차단된 에어갭 환경에서 수십 대 서버 규모로 롤링 방식 서비스 중단 없이 운영(2024.07~), 별도의 다종위성 수집·처리 플랫폼을 베어메탈부터 전 과정 신규 구축하고 있습니다 (2025.06~진행 중).

인프라·운영

에어갭 인프라 운영 - 장애 사전 감지 · 재현 가능한 구축 · 인증서 자동화

Zabbix 커스텀 대시보드 · 프로비저닝 쉘 스크립트화(구축 1~2일 → 2~3시간) · K8s 인증서 만료 대응 자동화

에어갭 운영

1. 장애 사전 감지 - Zabbix 커스텀 대시보드

외부 검색이나 라이브러리 반입이 불가능한 에어갭 환경이라, 장애가 발생해도 사용자 신고 전까지는 인지가 늦는 구조였습니다. Zabbix로 호스트·서비스 상태를 실시간 모니터링하는 커스텀 대시보드를 직접 구축해 장애를 사전에 감지할 수 있는 체계를 확보하고, 외부 반입이 막힌 환경에서의 장애 대응 판단을 절차로 정리했습니다.

2. 클러스터 프로비저닝 쉘 스크립트화

반입 가능한 도구가 제한된 환경이라 Terraform·Ansible 같은 범용 IaC 도구를 그대로 들여올 수 없었습니다. 클러스터 구축 절차를 쉘 스크립트로 코드화해, 같은 환경 제약 안에서도 사람이 매번 손으로 따라 하지 않고 재현 가능한 구축 절차를 확보했습니다. 수동으로 진행하던 1~2일짜리 구축 작업을 2~3시간으로 단축했습니다.

3. K8s 인증서 만료 대응 자동화

kubeadm 클러스터의 인증서는 주기적으로 만료되는데, 이전에는 만료 시점마다 현장을 직접 방문해 수동으로 갱신해야 했습니다. 갱신 절차를 자동화해 연 1회 현장 방문 작업을 제거했습니다.

가시화 전면 실패 장애 - 표면 에러를 따라가 만난 진짜 원인

No space left on device였지만 실제 여유 용량은 있었던 상황 - 컨테이너→마운트→디바이스→펌웨어까지 추적

에어갭 운영

어느 날 가시화 작업이 전부 실패 처리되기 시작했습니다. 로그에는 No space left on device가 찍혀 단순 디스크 부족처럼 보였지만, 마운트된 스토리지 용량을 확인하니 여유가 충분히 남아 있었습니다 - 명령어로 본 용량과 실제 동작이 어긋나 있었던 겁니다.

마운트 경로에 빈 파일을 만들어보니 단순 쓰기조차 실패했습니다 - 컨테이너가 아니라 마운트된 스토리지 자체의 문제로 범위를 좁혔습니다. 팀원과 함께 스토리지 장비에 직접 원격 접속해 NVMe 상태를 확인한 결과 실제 여유 용량이 0이었고, 업체 운영 코드를 검토한 결과 펌웨어 업그레이드 과정에서 NVMe→system pool 데이터 이동 로직이 누락된 것이 근본 원인이었습니다.

임시 패치로 서비스를 즉시 복구한 뒤 업체 정식 패치까지 연동해 마무리했습니다. 컨테이너 → 마운트 → 디바이스 → 펌웨어로 경계를 넘어 근본 원인을 추적한 사례로, 외부 레퍼런스 없이 하루 이상 걸리던 원인 파악·수정을 수 시간 이내로 단축했습니다.

백엔드

인증·인가 체계 - Spring Session + Redis 세션 인증 · 선언적 인가

Spring Session + Redis 세션 쿠키로 다중 WAR 공유(JWT 미사용) · 인가는 어노테이션+AOP · session:user 인덱스로 동시 로그인 통제

API 서버 · 프론트 공통

1. 인증 - Spring Session + Redis 세션 (토큰·JWT 아님)

시스템이 멀티모듈로 나뉘면서 하나의 Tomcat에 여러 WAR가 함께 올라가는 구조가 됐고, WAR마다 세션이 분리돼 로그인 상태가 공유되지 않는 문제가 있었습니다. 이를 토큰이 아니라 Spring Session + Redis로 풀었습니다 - @EnableRedisHttpSession으로 세션을 Redis(DB 0)에 영속화하고 인증 상태(SPRING_SECURITY_CONTEXT)를 세션에 저장하며, JSESSIONID SESSION으로 rename한 공유 쿠키(HttpOnly·Secure·SameSite=Lax)로 클라이언트를 식별합니다. 로그인 응답은 쿠키만 발급하고 토큰은 내려주지 않으며, JWT 라이브러리 의존성 자체가 없습니다.

즉 완전 stateless(JWT)도, 별도 토큰 레이어도 아닌 서버 세션을 Redis로 외부화한 순수 세션 쿠키 방식입니다. 다중 WAR 공유는 쿠키명을 SESSION으로 통일하고 저장소를 Redis로 공유하는 것으로 해결됐고, 세션 무효화·동시 로그인 통제도 서버가 세션을 쥐고 있어 그대로 가능하며, SameSite=Lax로 기본 CSRF 노출도 완화되므로 굳이 토큰 레이어를 얹을 필요가 없었습니다.

항목완전 stateless JWT채택 - Spring Session + Redis 세션
클라이언트 식별Authorization 헤더 토큰SESSION 쿠키(JSESSIONID rename, HttpOnly·Secure·SameSite=Lax)
다중 WAR 공유토큰 검증(세션 없음)쿠키명 통일 + Redis 공유 저장소(DB 0)
세션 무효화·동시 로그인만료 전 무효화 어려움서버 세션 보유 → 즉시 무효화 · session:user 인덱스로 통제

※ 리포에 남은 TokenInfo DTO·Authorization: Bearer 옵션·jwtLogin 호출 등 토큰 흔적은 jwtLogin 컨트롤러가 없어 실제로 동작하지 않는 레거시 잔재이고, Swagger의 bearerAuth도 문서 표기용입니다.

2. 프론트 서버의 인증 재구성 - /auth/session-check 위임

프론트 서버는 자체적으로 Spring Security 컨텍스트를 들고 있지 않습니다. SessionAuthenticationFilter가 요청의 SESSION 쿠키로 API 서버의 /auth/session-check를 호출해 인증을 재구성하는 방식으로, 세션 검증 책임을 API 서버 한 곳으로 위임했습니다.

3. 인가 - 커스텀 어노테이션 + AOP로 선언적 분리

엔드포인트가 늘어날수록 컨트롤러마다 권한 체크 코드를 개별적으로 넣다 보니, 신규 API를 추가할 때 권한 검증을 깜빡 빠뜨리거나 서로 다른 방식으로 중복 구현하는 위험이 커졌습니다. 인증은 Spring Security 필터 체인에서 일괄 처리하고, 인가는 컨트롤러·서비스 코드와 분리해 커스텀 어노테이션 + AOP로 선언적으로 처리해, 신규 API는 어노테이션 하나만 붙이면 권한 검증이 자동 적용되도록 만들었습니다.

방식권한 체크 위치신규 API 추가 시
기존 (컨트롤러 개별 구현)각 컨트롤러 메서드 내부매번 권한 체크 코드 직접 작성 - 누락 위험
어노테이션 + AOPAOP 어드바이스 한 곳어노테이션만 부착 - 로직 재작성 불필요

4. 동시 로그인 통제 - session:user 인덱스

로그인 시 session:user:{userId} 키로 세션을 인덱싱해(AuthController), 세션 식별자만으로는 답하기 어려운 "이 사용자가 지금 몇 세션에 접속 중인가"를 사용자 기준으로 즉시 조회·통제할 수 있게 했습니다.

파일 다운로드 안정화 - 엔드포인트 통합·이어받기 → 대용량 전송 안정화

일반/INNORIX 엔드포인트 통합 · DRM 재암호화 동시성 버그 · 청크 스트리밍 이어받기

파일 서버

1. 다운로드 엔드포인트 통합 - 일반 다운로드와 INNORIX 대용량 전송을 하나로

일반 다운로드와 위성영상처럼 큰 파일의 INNORIX 대용량 전송을 엔드포인트를 따로 두지 않고 /download.do 하나로 처리했습니다. 분기 기준은 파일 크기가 아니라 요청에 _StartOffset·_EndOffset 파라미터가 있는지입니다 - INNORIX 클라이언트가 downloadType: "stream" 설정일 때만 이 파라미터를 붙여 보냅니다.

요청판단 기준동작
일반 다운로드_StartOffset·_EndOffset 없음file.length() 전체를 한 번에 응답
INNORIX 대용량 전송_StartOffset·_EndOffset 있음input.skip()으로 해당 구간만 건너뛰어 그 바이트만 응답

2. DRM 재암호화 동시성 버그

Fasoo DRM 암호화 대상 파일이 동시 다운로드 시 조각마다 재암호화되면서 조각별로 바이트 구조가 달라져 파일이 깨지는 버그를 발견했습니다. 다운로드 요청을 synchronized로 직렬화하고 암호화된 파일이 이미 있으면 재사용하도록 고쳐 최초 요청에만 암호화가 일어나도록 만들었습니다.

3. 대용량 스트리밍 다운로드 UX 재설계 - 서버 구현 갭까지 직접 발견

전체 파일을 한 번에 받는 구조라 네트워크가 끊기면 처음부터 다시 받아야 했고 진행률 표시도 없었습니다. File System Access API로 서버 응답을 64KB 청크 단위로 읽어 디스크에 직접 기록하고, Range 지원 여부를 사전 탐지해 이어받기, 실패 시 최대 3회 재시도를 구현했습니다. 업로드 확장자 검증은 @FileUploadValidation 커스텀 애노테이션 + AOP로 횡단 관심사를 분리했습니다.

다운로드 UX를 다 만든 뒤 서버 코드를 다시 들여다보니, folderDownload() Accept-Ranges: bytes를 선언하면서도 실제 Range 헤더 파싱 코드가 없어 클라이언트가 이어받기를 시도해도 서버는 매번 파일 전체를 재전송한다는 구현 갭을 코드 리뷰로 직접 발견했습니다. 같은 시기에 공통 Ajax 모듈이 바이너리 응답까지 JSON.parse하려던 버그도 함께 고쳤습니다.

보안 취약점 진단·대응 - 외부 보안 진단 지적사항 전량 해소

Burp 브루트포스 → 5회 초과 차단 · 위험도별 Rate Limiting · 동적 CSP·47개 매퍼 SQLi 해소

인증 서버 · API 서버

1. 무차별 대입(브루트포스) 방어 - 발견부터 실증까지

Burp Suite로 로그인 무차별 대입을 시뮬레이션해 무제한 시도가 가능한 취약점을 확인했습니다. IP·계정 단위로 로그인 실패를 카운트해 5회 초과 시 차단하도록 구현하고, 다시 Burp Suite로 재검증해 차단이 실제로 동작함을 실증했습니다. 실패 카운트는 Redis INCR(원자적 증가)로 경쟁조건을 원천 차단하고 차단 해제는 TTL 만료로 자동 처리했습니다.

2. 계층형 Rate Limiting

업로드·삭제 같은 고위험 엔드포인트와 단순 조회 API가 동일하게 무제한 호출 가능했습니다. 필터(ConcurrentHashMap + incrementAndGet()으로 락 없이 스레드 안전하게 카운팅)와 AOP(@RateLimit 어노테이션)를 2계층으로 분리하고, 엔드포인트 위험도를 HIGH/MEDIUM/LOW로 나눠 차등 제한했습니다. Redis 장애 시에는 로그인을 막지 않는 fail-open을 명시적으로 선택했습니다.

위험도제한예시
HIGH5회/분업로드·삭제 등 고위험 엔드포인트
MEDIUM20회/분일반 쓰기 API
로그인 실패5회 초과 시 차단Redis INCR + TTL 자동 해제

3. 외부 보안 진단 대응 - 동적 CSP 생성 · SQL Injection 제거

외부 보안 진단에서 서버 정보 노출, CSP 미비(인라인/eval 허용), MyBatis ${} 방식 SQL Injection 등 10건 이상을 지적받았습니다. 문제는 지도 라이브러리(CesiumJS)가 eval과 인라인 스타일에 의존해, CSP를 강하게 걸면 지도 화면 자체가 깨지는 제약이 있었다는 점이었습니다.

CSP를 API origin 기반으로 런타임 동적 생성하도록 바꾸고, CesiumJS 라이브러리의 eval 패턴을 소스 레벨에서 직접 패치해 CSP 위반 없이 동작하도록 만들었습니다. Nginx proxy_hide_header로 보안 헤더 관리를 한 곳으로 모으고, 47개 매퍼의 SQL Injection을 해소했습니다 - 정적 쿼리 13개는 ${} → #{} 파라미터 바인딩으로, 동적 정렬(ORDER BY ${sidx})에 쓰이는 나머지 34개는 컬럼명을 허용된 목록과 대조하는 화이트리스트 검증으로 각각 전환했습니다.

항목이전이후
CSP인라인/eval 허용 - 사실상 무방비API origin 기반 런타임 동적 생성
CesiumJS eval 의존CSP 강화 시 화면 깨짐라이브러리 eval 패턴 직접 패치
정적 쿼리 매퍼13개 매퍼 ${} 파라미터 삽입#{} 바인딩으로 전환
동적 정렬 컬럼 매퍼34개 매퍼 ${} 컬럼명 치환, 검증 없음화이트리스트 검증으로 전환
공통 base 모듈·자동화 도구 개발 - 반복 개발 제거 → 신규 테이블 온보딩 효율화

information_schema 기반 Entity·mapper 자동 생성 · 제네릭 CRUD base 모듈 · AOP 공통 로깅

API 서버

DB 엔지니어가 설계해둔 스키마를 그대로 Entity·MyBatis XML mapper로 옮겨 적어야 했는데, 테이블 수가 많아(40여 개) 신규 테이블마다 이 손 작업을 반복하는 게 번거로웠습니다. 특히 MyBatis mapper는 컬럼 목록·CRUD·검색 쿼리 조각이 테이블마다 거의 똑같이 반복되는 보일러플레이트가 많아 자동화 효과가 컸습니다.

DB information_schema를 조회해 컬럼명·PK·주석·numeric precision을 읽고, 컬럼명 명명 규칙에 따라 타입·검증 애노테이션을 자동 매핑해 Entity와 CRUD/검색 XML mapper를 생성했습니다. 테이블 전반에 컬럼 네이밍 규칙이 이미 표준화돼 있었기 때문에 가능했던 방식이며, 스키마가 바뀌면서 생성기도 두 세대(Es→Tobe)로 갈아탔습니다.

컬럼명 규칙매핑 결과
Code로 끝남공통코드 참조 (CmmCd.Entity)
Yn으로 끝남Y/N 패턴 검증 (@Pattern)
numeric precision·scaleInteger / Long / Float 타입 추론

공통 base 모듈 - Controller·Service·Mapper·Entity 제네릭 추상화

코드 생성기가 초기 코드를 빠르게 찍어내는 접근이라면, 반복 코드 자체를 줄이는 접근도 병행했습니다. 네 계층을 제네릭 기반으로 추상화한 base 모듈을 구현해 신규 테이블은 상속만으로 기본 CRUD 계층을 갖추도록 만들었고, 에러 로깅도 서비스마다 개별로 넣는 대신 AOP로 base 모듈에 공통 적용해 로깅 누락을 구조적으로 방지했습니다.

테이블당 30분~1시간 걸리던 보일러플레이트 작성을 수 분 내로 단축했습니다.

표적 데이터 관리 · 집계 쿼리 최적화 - SQL 레벨 정합성·성능 개선

윈도우 함수 순번 재정렬 · CUD 감사로그·계단식 무결성 · 집계 UNION ALL → CTE(스캔 5→1)

API 서버

1. 즐겨찾기·관심표적 우선순위 재정렬

사용자별 드래그앤드롭 정렬에 정수 순번 컬럼을 쓰다 보니, 전체 재정렬 UPDATE 비용과 삭제 시 순번 gap이 쌓이는 문제가 있었습니다. 이동 구간만 범위 UPDATE하는 부분 시프트 로직과 ROW_NUMBER() OVER() 윈도우 함수 기반 순번 재계산(defragmentation)을 그룹·아이템 2단 계층에 재사용해, reorder 연산이 전체 행이 아니라 이동 구간만 UPDATE하도록 만들었습니다.

2. 표적 생명주기 감사로그 + 삭제 시 계단식 무결성 처리

표적 데이터는 여러 사용자가 생성·수정·삭제·이관할 수 있는데 변경 이력이 없어 원인 추적이 불가능했습니다. 보고서가 참조 중인 표적을 삭제하면 참조 무결성이 깨지고, 삭제된 표적을 가리키는 즐겨찾기가 고아 레코드로 남는 문제도 있었습니다.

insert/update/delete마다 트랜잭션유형코드(C/U/D)를 포함한 이력 레코드를 같은 서비스 메서드 안에서 기록하는 수동 감사로그 패턴을 도입했습니다. 삭제 시 보고서 참조 카운트를 사전 검증해 참조 중인 표적의 삭제를 애플리케이션 레벨에서 차단하고, 표적 삭제·이관 시 연관 즐겨찾기·관심표적을 함께 정리하고 순번을 재정렬하도록(위 1번과 연동) 만들었습니다.

여기에 더해, 첨부파일 일련번호를 SELECT MAX(sno)+1로 채번하다 동시 업로드 시 경쟁조건이 발생하던 버그도 발견해 @Synchronized로 해당 인스턴스 내 요청을 직렬화해 제거했습니다.

3. 집계 API 쿼리 최적화 - UNION ALL 반복 → WITH CTE

한 통계 API가 5개 집계 기준마다 동일한 조인·필터 조건을 UNION ALL로 반복 실행하는 구조라, 같은 원본 테이블을 5회 스캔하고 있었습니다. 집계 기준만 다를 뿐 선행 조인·필터는 완전히 동일했습니다. 공통 조인·필터 결과를 WITH CTE로 한 번만 계산해두고 5개 집계가 그 CTE를 참조하도록 재작성해, 원본 테이블 스캔을 5회에서 1회로 줄였습니다.

항목이전이후
집계 방식5개 기준마다 동일 조인·필터 반복 (UNION ALL)공통 결과를 CTE로 1회 계산 후 참조
원본 테이블 스캔5회1회
배포 환경별 Spring Profile 분리 - 개발·에어갭 실배포·로컬 설정 분리 관리

로컬·개발·에어갭 실배포를 Spring Profile로 분리 · 환경 혼선·재빌드 제거

인증 서버

환경마다 context-path·외부 API host·로그 경로·내부 호출 방식 등이 달랐는데, 이 설정들이 한 파일에 섞여 있어 배포 대상이 바뀔 때마다 값을 손으로 고쳐야 했고 환경 혼선으로 내부 API 연동이 끊기는 장애가 반복됐습니다.

이를 로컬 · 개발서버 · 에어갭 실배포 서버 세 환경을 각각의 Spring Profile로 분리해 관리하도록 정리했습니다. 환경별로 갈리는 설정을 프로파일 파일로 떼어내고, 특히 에어갭 실배포 환경에서는 내부 API 호출을 localhost + 서비스별 path prefix로 우회하도록 고정했습니다.

프로파일용도핵심 설정 차이
local로컬 개발로컬 host·포트, 개발 편의 설정
dev개발서버개발 도메인·외부 API host
prod (에어갭 실배포)실 운영 배포context-path·내부 호출 localhost + path prefix로 고정

환경 설정을 프로파일로 떼어내면서 재빌드 없이 배포 대상만 바꿔 실행할 수 있게 됐고, 환경 혼선으로 인한 연동 장애도 재발하지 않게 됐습니다.

다종위성 플랫폼 신규 구축 - DB 접근 중앙화 · 베어메탈 인프라

베어메탈·K8s 직접 구축 · 흩어진 DB 접근을 Go API 한 곳으로 중앙화

신규 구축

기존 프로젝트들은 서비스 7개(Cataloger, Job Manager, 가시화 등)가 ORM으로 DB에 직접 접근하는 구조였습니다. DB 접근 로직과 자격증명이 모든 서비스에 흩어져 있어 스키마가 바뀌면 여러 서비스를 동시에 수정해야 했고, Python ORM과 Go가 같은 DB를 다룰 때 패턴이 어긋나는 문제도 있었습니다.

독립 스키마를 새로 짜야 하는 신규 구축 프로젝트의 기회를 활용해, DB 접근을 Go 기반 API 한 곳으로 중앙화했습니다. 모든 서비스가 HTTP로만 DB에 접근하도록 바꾸자 스키마 변경의 영향 범위가 API 레이어 한 곳으로 좁혀졌고, 서비스는 사용 언어와 무관하게 동일한 방식으로 DB를 다룰 수 있게 됐습니다. 관리형 인프라가 없는 상태에서 물리 서버 설치, K8s 클러스터 구성부터 다종 수집기 통합, DB 기반 중복 체크, zst/tar.gz 포맷 변환 자동화까지 베어메탈에서 운영 가능한 시스템까지의 인프라 전 과정에 핵심적으로 참여했습니다.

프론트엔드

판독보고서 - CesiumJS 3D globe 기반 보고서 저작 도구

별도 도구 없이 분석·주석·보고서 작성을 한 화면에서 원스톱 처리 - 분석관 호평

판독·분석 웹

판독보고서는 분석관이 CesiumJS 3D globe 위에서 위성영상을 직접 보며 표적에 화살표·도형·텍스트·이미지로 주석을 다는 기능입니다. 여러 페이지에 걸쳐 의견을 작성해, 최종적으로 HWP(정부 표준 문서 포맷) 파일로 내려받습니다. 영상 판독과 보고서 작성을 한 화면에서 이어서 끝낼 수 있게 만든 것 자체가 이 기능의 핵심 가치였고, 도구를 옮겨다니지 않아도 된다는 점에서 분석관들의 호평이 많았습니다.

이전 - PPT 등 별도 도구를 오가며 작성

화면 캡처
판독 화면에서
도구 전환
PPT로 이동
붙여넣기·정리
문서 편집
표적마다 반복
①~③ 되풀이

판독보고서 - 한 화면에서 이어서

표적 확인
3D globe에서
주석 작성
화살표·도형·텍스트·이미지
페이지 캡처
화면·뷰 상태 저장
다음 표적
표적마다 반복
HWP 내보내기
정부 표준 문서

각 페이지는 3D globe 화면을 그대로 캡처해 HWP 배경으로 삽입하는 구조라, 카메라가 지구본 바깥을 보거나 날짜변경선을 넘는 경우까지 감안해 뷰 상태를 저장·복원했습니다. 화살표·도형·텍스트는 Cesium 엔티티(Polyline·Label 등)로, 이미지는 ImageryLayer로 영역에 지오레퍼런싱해 얹는 방식으로 렌더링했습니다.

공통 컴포넌트 매니저 - 팝업·iframe·인페이지 통신 통합

팝업·iframe·인페이지 함수를 execute() 하나로 통일 · 창 경계 넘는 호출 추상화

판독·분석 웹

분석 화면은 같은 페이지 안의 패널, 별도 팝업 윈도우, iframe 등 컴포넌트가 실행되는 위치가 제각각이었습니다. 화면을 만들 때마다 "이 컴포넌트가 팝업인지 iframe인지"를 매번 구분해서 호출 방식을 다르게 짜야 한다면 화면이 늘어날수록 관리가 어려워집니다.

ins-comp-mng는 컴포넌트가 어디서 실행되든 ins.comp.execute(compId, fnName, args) 하나로 호출할 수 있게 추상화한 공통 매니저입니다. 내부적으로 대상이 같은 페이지 객체면 함수를 직접 호출하고, 팝업이나 iframe이면 postMessage로 명령을 전달해 그쪽에서 같은 이름의 함수를 실행시킵니다.

대상매니저 없이execute(compId, fnName, args)로
같은 페이지 객체직접 호출동일하게 직접 호출
팝업 (window.open, 독립 생명주기)핸들을 계속 들고 있다가 직접 호출 - 로딩 전이면 에러위치 신경 안 쓰고 동일하게 호출, 응답은 콜백 함수명(fnName)으로 회신
iframe (contentWindow, 부모 DOM 종속)contentWindow 직접 접근 또는 postMessage·리스너를 매번 직접 구현위치 신경 안 쓰고 동일하게 호출, 응답은 팝업과 동일한 fnName 콜백
아직 등록 안 됨호출부가 대상 존재 여부까지 알아야 함부모창으로 재위임, 무한 재요청 방지

postMessage 기반 전송 자체는 Penpal·Comlink 같은 라이브러리로도 가능했지만, 팝업·iframe·같은 페이지 객체를 한 레지스트리로 묶어 대상을 자동 판단하는 디스패치 구조는 앱 구조에 종속적이라 직접 구현했습니다. 유지보수 중에는 미등록 컴포넌트 재요청 가드가 카메라 이동처럼 정상적인 반복 호출까지 막던 부작용을 컴포넌트+함수명 단위로 세분화해 고쳤고, 창 참조를 점 표기법으로 동적 조회해 항상 undefined를 반환하던 버그와 닫힌 팝업을 살아있는 것으로 오인하던 null 체크 누락도 함께 고쳤습니다.