hub.iten.co.kr을 관리하는 사이트
ITN-HUB#
2026 신유형 공공저작물 개방사업 · 3단계 법률검토 관리 시스템
신청기관 명부·담당자 관리부터 Mattermost 채널 자동 생성, 권리확인·권리처리 판정,
사업 현황 대시보드까지 한 곳에서 처리한다.
Spring Boot 3.3.5 Java 21 React 18 PostgreSQL 16 MyBatis Flyway Mattermost
목차#
무엇을 하는 시스템인가#
기존 Excel VBA 매크로(M06_Mattermost_기관목록, M07_Mattermost_채널일괄생성)로 하던 작업을
웹으로 옮긴 것이다. 47개 신청기관을 대상으로 다음 흐름을 처리한다.
신청목록 엑셀 담당자 채널 2종 권리확인 / 권리처리 보고서
업로드 → 배정 → 자동 생성 → 변호사 판정 → 제출
기관 명부 신청기관·문정원 문정원·법률검토 엑셀 업로드 후 사업관리
아이티앤·변호사 + 안내글 핀 고정 건별 판정
⚠ 주의
이 애플리케이션은 실제 운영 Mattermost 서버(
https://hub.iten.co.kr)에 실제 채널을 만든다.
처음 쓸 때는 실제 기관이 아니라 테스트 기관(예: 연번999)으로 한 바퀴 돌려보고 시작할 것.
MATTERMOST_TOKEN은 시스템 관리자(system-admin) 권한 계정의 Personal Access Token이어야 한다.
팀 전체 범위에서 비공개 채널을 조회해야(레거시 채널 복구) 중복 생성을 막을 수 있기 때문이다.
화면 구성#
| 메뉴 | 하는 일 |
|---|---|
| Dashboard | KPI 7타일 · 단계별 칸반(카드 드래그로 단계 이동) · 최근 진행 기관 |
| 채널관리 | 신청목록 시트 업로드 · 담당자 4역할 배정 · Mattermost 채널 2종 생성 |
| 기관관리 | 기관 상세. 업무단계 스트립 + 7개 탭(채팅·자료·권리확인·권리처리·RE·타임라인·업무메모) |
| 담당자관리 | 담당자 등록·수정·삭제, 회원명단 엑셀 일괄 업로드 |
| 사업관리 | 3단계 대상 기관 현황 · 신청 확인 연락 이력 · 기관별 최종 보고서 |
| 시스템관리 | 채널 초기화(미리보기 → 확인문구 → 실행) |
화면 곳곳의 버튼 옆 ? 아이콘을 누르면 실제 화면 캡처가 담긴 설명서가 열린다(19개 항목).
시작하기#
요구사항#
| 항목 | 버전 / 비고 |
|---|---|
| JDK | 21 |
| PostgreSQL | 16 |
| Node.js | 불필요 — mvn package가 v20.17.0을 내려받아 프런트를 함께 빌드한다 |
| Docker | 백엔드 테스트에만 필요(Testcontainers) |
빌드#
mvn -DskipTests package
frontend-maven-plugin이 React 앱을 빌드해 src/main/resources/static/에 넣고,
그 결과가 단일 jar 하나로 패키징된다. 프런트를 따로 빌드할 필요가 없다.
실행#
export DB_URL=jdbc:postgresql://localhost:5432/itnhub
export DB_USERNAME=itnhub
export DB_PASSWORD=...
export MATTERMOST_URL=https://hub.iten.co.kr
export MATTERMOST_TOKEN=...
export MATTERMOST_TEAM_ID=...
export APP_ADMIN_USERNAME=admin
export APP_ADMIN_PASSWORD=...
java -jar target/itnhub-0.1.0.jar
기동하면 Flyway가 itnhub 스키마와 테이블(V1~V12)을 자동으로 만든다. 수동 DDL은 없다.
프런트만 반복 개발할 때#
cd frontend && npm install && npm run dev # Vite가 /api 를 :8877 로 프록시
mvn spring-boot:run # 백엔드는 따로 띄워 둔다
환경변수#
.env.example을 복사해 값을 채운다. 실제 값이 든 파일은 커밋하지 않는다.
필수 — 하나라도 비면 기동하지 않는다#
| 변수 | 설명 | 예시 |
|---|---|---|
DB_URL | PostgreSQL JDBC URL | jdbc:postgresql://192.168.0.60:5432/itnhub |
DB_USERNAME | DB 계정 | itnhub |
DB_PASSWORD | DB 비밀번호 | |
MATTERMOST_URL | Mattermost 베이스 URL | https://hub.iten.co.kr |
MATTERMOST_TOKEN | system-admin 권한 Personal Access Token | |
MATTERMOST_TEAM_ID | 채널을 만들 팀 ID | |
APP_ADMIN_USERNAME | 앱 로그인 계정 | admin |
APP_ADMIN_PASSWORD | 앱 로그인 비밀번호(충분히 긴 무작위 값) |
선택 — 기본값 있음#
| 변수 | 기본값 | 설명 |
|---|---|---|
MATTERMOST_TEAM_NAME | itn-hub | 채널 URL을 만들 때 쓰는 팀 이름 |
MATTERMOST_DEFAULT_USER_PASSWORD | test1234! | 자동 생성되는 담당자 계정의 초기 비밀번호 |
참고 —
application.yml의spring.datasource.hikari.schema: itnhub는 지우면 안 된다.spring.flyway.schemas는 Flyway 전용 커넥션에만 적용돼서, 이 설정이 없으면 런타임 커넥션이public스키마를 보고relation "organization" does not exist로 죽는다.
업무 흐름#
진행단계 12단계#
① 신청 → ② 목록접수 → ③ 예비검토 → ④ 변호사 배당
→ ⑤ 법률검토(권리확인) → ⑥ RE:확인 → ⑦ 법률검토(권리확인) 완료
→ ⑧ 법률검토(권리처리) → ⑨ RE:처리 → ⑩ 법률검토(권리처리) 완료
→ ⑪ 법률검토 최종완료 → ⑫ 보고서 작성
- 채널을 만들면 ①신청이 자동으로 시작된다. 그 뒤로는 전부 수동이다 — 자료를 올리거나
게시글을 써도 단계가 저절로 넘어가지 않는다(요청자 확정 사항). - 단계 변경 이력은 전부 타임라인 탭에 남는다.
최초 사용 순서#
- PostgreSQL을 준비하고 환경변수를 채운다 → 기동하면 스키마가 만들어진다
- 브라우저로 접속해 관리자 계정으로 로그인
- 담당자관리 에서 담당자를 등록한다(회원명단 엑셀 일괄 업로드 가능)
- 채널관리 에서 신청목록 시트를 올려 기관 명부를 만들고, 기관마다 담당자 4역할을 배정한다
- 채널 생성 — 채널 2종 + 담당자 계정 + 안내글이 한 번에 준비된다
- 기관관리 › 권리확인/권리처리 탭에서 조사 엑셀을 올리고 건별로 판정한다
- 사업관리 에서 연락 이력을 남기고 최종 보고서를 올린다
핵심 규칙#
수정할 때 깨뜨리면 안 되는 약속들이다.
| 규칙 | 내용 |
|---|---|
| 채널은 항상 2개 | 기관마다 NNN_기관명 (문정원) · NNN_기관명 (법률검토) 가 쌍으로 만들어진다. 게시글·자료도 늘 양쪽에 함께 반영된다. 한쪽만 처리하는 코드는 버그다. |
| 재실행 안전 | 채널 생성·시드 업로드·채널 초기화 모두 여러 번 실행해도 안전하다. 이미 처리된 것은 건너뛰고 없는 것만 만든다. 새 로직에서도 이 원칙을 지킨다. |
| 채널 ⇔ 단계 | 채널이 있으면 진행단계가 반드시 있고, 단계가 없으면 채널도 없다(V11이 이 불변식을 맞춘다). 대시보드 칸반의 단계 미지정 컬럼은 채널 미생성 기관만 담는다. |
| 엑셀 재업로드 | 같은 파일을 다시 올려도 웹에서 고친 값(web_edited_at)은 보존되고 조사원 영역만 덮어쓴다. 병합 기준은 순번이 아니라 파일의 행 순서다(원본에 순번 중복이 있다). |
| 제3자 권리처리 | 권리 일부 보유·권리 미보유는 권리처리 추진 / 권리처리 추진 미희망 택일, 초상권 포함은 개방불가까지 3택. 추진이면 공공누리 유형이 보류로, 미희망이면 기존 유형이 자동 선택되고 비고에 사유가 적힌다. |
| 작성자 자동 기록 | 업무메모·연락 이력의 작성자는 화면에서 고르지 않는다. 로그인 사용자를 서버가 기록하고, 수정해도 최초 작성자·작성시각은 유지된다. |
| 연번은 문자열 | 기관 코드는 연번1_연번2(001_00) 형식이다. 숫자로 바꾸면 앞자리 0이 사라져 매칭이 전부 깨진다. |
프로젝트 구조#
itnhub/
├─ src/main/java/kr/itn/itnhub/
│ ├─ org/ 기관 명부·배정 ├─ review/ 권리확인
│ ├─ contact/ 담당자 ├─ process/ 권리처리
│ ├─ provision/ 채널 생성(멱등) ├─ stage/ 진행단계·이력
│ ├─ mattermost/ Mattermost API 클라이언트 ├─ timeline/ 타임라인 집계
│ ├─ feed/ 채널 게시글·파일 ├─ memo/ 업무메모
│ ├─ dashboard/ 대시보드 집계 ├─ project/ 사업관리
│ ├─ seed/ 신청목록 시트 시드 └─ system/ 채널 초기화
│ └─ config/ 보안·설정
│
├─ src/main/resources/
│ ├─ db/migration/ Flyway V1~V12
│ ├─ mapper/ MyBatis XML
│ └─ application.yml
│
├─ frontend/src/
│ ├─ components/ 화면 19개 (Dashboard, OrgOverview, ReviewBoard …)
│ ├─ help/ 버튼 옆 「?」 도움말 — 본문과 캡처가 여기 한 곳에 있다
│ ├─ api/client.ts 모든 서버 호출이 지나는 단일 창구
│ └─ stages.ts 12단계 라벨 정본
│
├─ deploy/ 176 서버 배포 정의 (compose · env 템플릿 · 절차서)
└─ Dockerfile 프런트까지 함께 빌드하는 멀티스테이지
API#
| 영역 | 엔드포인트 |
|---|---|
| 기관 | GET /api/orgs · PUT /api/orgs/{id}/assignments · POST /api/orgs/{id}/channels |
| 진행단계 | PUT /api/orgs/{id}/stage · GET /api/orgs/{id}/stage-history |
| 채팅·자료 | /api/orgs/{id}/posts messages notice files · GET /api/files/{fileId} |
| 권리확인 | /api/orgs/{id}/review import download · PUT …/review/bulk |
| 권리처리 | /api/orgs/{id}/process import download · PUT …/process/bulk |
| 대시보드 | GET /api/dashboard — KPI·칸반·최근 진행 기관을 한 번에 |
| 사업관리 | GET /api/projects · /api/orgs/{id}/contact-logs · /api/orgs/{id}/reports |
| 업무메모 | GET POST PUT DELETE /api/orgs/{id}/memos |
| 타임라인 | GET /api/orgs/{id}/timeline |
| 시스템 | GET /api/system/reset/preview · POST /api/system/reset/channels |
전 구간 로그인이 필요하고(/api/auth/login 제외), 변경 요청은 CSRF 토큰을 함께 보낸다.
테스트#
mvn test # 백엔드 221건 — Testcontainers로 PostgreSQL을 띄우므로 Docker 필요
cd frontend && npm test # 프런트 191건
배포#
Docker 기준 상세 절차는 deploy/README.md 에 있다.
docker build -t itnhub:latest .
sudo cp deploy/itnhub.env.example /etc/itnhub/itnhub.env # 값 채우기
cd /opt/itnhub && sudo docker compose up -d
| 산출물 | 단일 jar — React가 그 안에 있어 서버에 Node도 웹서버도 필요 없다 |
| 영속 볼륨 | 불필요 — 업로드 파일은 DB(org_report)와 Mattermost에 저장된다 |
| DB | 컨테이너로 띄우지 않고 기존 PostgreSQL을 그대로 쓴다 |
| 시간대 | 컨테이너를 Asia/Seoul로 고정 — UTC면 도달 일시·D+n이 9시간 어긋난다 |
| 헬스체크 | GET /login 200 (actuator 미포함) |
⚠ 빌드 머신에는 인터넷이 필요하다(Node·npm·Maven을 내려받는다). 실행 서버는 필요 없다.
사내망이 막혀 있으면 Maven 미러와nodeDownloadRoot를 사내 저장소로 돌려야 한다.