네트워크 보안장비를 다루는 기업의 기술영업 직무는 공공기관 입찰 대응이 핵심 업무 중 하나다. 입찰공고에 딸린 제안요청서(RFP)에는 "처리성능 10Gbps 이상", "국제 보안인증 등급 EAL2 이상", "특정 기관 보안적합성 검증필" 같은 요구사항이 수십 줄로 박혀 있다.
담당자가 하는 일은 이 요구사항을 자사 제품 카탈로그와 한 줄씩 대조해서 충족 여부를 판단하는 것이다. 이 작업은 두 가지 특징을 가진다.
이 두 특징이 겹치는 지점이 자동화 후보다. 그래서 "입찰공고를 자동으로 모으고, 요구사항과 제품 스펙을 대조해서 갭분석표를 만들어주는 시스템"을 만들기로 했다.
기획 단계에서 가장 신경 쓴 부분은 "무엇을 자동화하고 무엇을 자동화하지 않을 것인가"를 명확히 가르는 것이었다. 처음부터 전부 자동화하려고 하면 프로젝트가 산으로 간다.
자동화 대상
자동화하지 않은 것
이 경계를 초반에 명확히 그은 게 이후 개발 전체의 방향을 잡아줬다. "완전 자동화"가 아니라 "반복 작업은 기계가, 판단이 필요한 부분은 사람이" 라는 원칙이다.
기능을 4개로 쪼갰다.
이 중 4번이 압도적으로 중요하다. 1~3번은 사실 CRUD와 배치 작업이라 기술적으로 특별할 게 없다. 반면 4번은 "처리성능 10Gbps"와 "네트워크 처리량 20Gbps"가 같은 항목을 가리킨다는 걸 코드가 판단해야 하고, "EAL2"와 "EAL4"의 대소를 비교해야 하고, "10Gbps"와 "8000Mbps"를 같은 단위로 환산해서 비교해야 한다. 이건 단순 API 연동이 아니라 직접 설계해야 하는 도메인 규칙이다.
| 구분 | 선택 | 이유 |
|---|---|---|
| Backend | Java 17, Spring Boot 3.4 | 도메인 규칙을 타입으로 명확히 표현하고 싶었다. record, sealed 등 최신 문법도 써보고 싶었고 |
| DB | H2(로컬) / MySQL 8(배포) | 인증키 없이도 바로 클론해서 띄워볼 수 있어야 한다는 게 우선순위였다 |
| Frontend | React 18 + TypeScript + Vite | 갭분석 결과를 표와 차트로 보여줘야 해서 타입 안전성이 중요했다 |
| 외부 연동 | 공공 데이터 포털 Open API | 실시간 조회 대신 스케줄러 폴링 + DB 캐싱 구조로 설계 |
DB를 로컬은 H2, 배포는 MySQL로 나눈 이유는 단순하다. "클론하고 바로 실행"이 안 되는 포트폴리오는 아무도 끝까지 안 본다. 인증키 발급 절차나 DB 설치를 먼저 요구하면 리뷰어가 중간에 이탈한다. 그래서 기본 프로필은 H2 인메모리 + 예시 데이터 자동 적재로 잡고, 운영에 가까운 검증이 필요할 때만 MySQL 프로필로 전환하도록 나눴다.
[React Client]
│ REST/JSON
▼
[Spring Boot API Server]
├─ BidController → 공고 목록/상세
├─ RequirementController → 공고별 요구사항 등록/조회
├─ ProductController → 제품 스펙 CRUD
├─ MatchController → 매칭 실행 + 갭분석 조회
├─ BidSyncScheduler → Open API 주기 폴링 → DB 저장
│
▼
[MySQL] BidAnnouncement / RequirementItem / ProductSpec / MatchResult
설계에서 가장 먼저 정한 원칙은 "공고는 실시간 조회하지 않는다" 였다. 사용자가 화면을 열 때마다 외부 API를 호출하면, 외부 API가 느리거나 죽어 있을 때 내 서비스까지 같이 죽는다. 대신 스케줄러가 하루 1~2회 수집해서 DB에 캐싱하고, 화면은 항상 DB만 본다. 이 결정 하나로 "외부 API 장애 = 서비스 장애"라는 등식을 끊을 수 있었다. (이 부분의 구체적인 장애 대응은 4편에서 다룬다.)
| Phase | 범위 |
|---|---|
| Phase 1 (MVP) | Open API 연동, 제품 스펙 CRUD, 요구사항 수동 등록, 수치/등급/Boolean 매칭 |
| Phase 2 | 갭분석 리포트 시각화, 매칭 결과 저장·재조회 |
| Phase 3 | 텍스트형 요구사항 규칙 확장, 제안서 초안 내보내기 |
| Phase 4 | 배포, API 문서 공개 |
다음 글에서는 이 프로젝트의 핵심인 매칭 엔진을 다룬다. "요구사항 문구와 제품 스펙 항목명이 다른데 어떻게 같은 항목이라고 판단하는가", "10Gbps와 EAL2를 어떻게 같은 파이프라인으로 비교하는가" 같은 실제 설계 문제를 풀어간 과정을 정리했다.
이 시리즈는 개인 학습 프로젝트 개발 기록입니다. 코드에 등장하는 기관명·제품명은 전부 가상이며, 실제 연동 대상 서비스의 명칭·엔드포인트는 기술적 세부사항 보호를 위해 일반화해서 서술합니다.