ITN Dev 07-22
docs: 운영 인수인계용 README와 .env.example 추가
- 시스템 개요, 필수 환경변수 8개 표, 실운영 Mattermost 경고 박스(system-admin PAT
  필요, 테스트 기관으로 스모크 권장), 빌드/실행/최초 사용 순서, hikari.schema
  설정이 왜 필요한지, 프론트엔드 개발 워크플로를 정리.
- .env.example에 8개 변수를 플레이스홀더 값으로 정리하고 실값 커밋 금지 주석 추가.
- .gitignore에 .env 추가.

Co-Authored-By: Claude Opus 4.8 (1M context) 
@42b991f59ac66207cf0f9cc9d4442fe796b75796
 
.env.example (added)
+++ .env.example
@@ -0,0 +1,18 @@
+# 이 파일은 예시 템플릿이다. 실제 값을 채운 .env(또는 배포 환경변수)는 절대 커밋하지 말 것.
+# 8개 변수 모두 필수 - 하나라도 없으면 애플리케이션이 기동하지 않는다.
+
+# PostgreSQL 16 접속 정보
+DB_URL=jdbc:postgresql://localhost:5432/itnhub
+DB_USERNAME=itnhub_app
+DB_PASSWORD=change-me-to-a-real-password
+
+# Mattermost 연동 (운영 서버: https://hub.iten.co.kr)
+# MATTERMOST_TOKEN은 반드시 system-admin 권한 Personal Access Token이어야 한다 -
+# 비공개 채널 팀 전체 조회/생성에 필요하다. README의 경고 박스를 먼저 읽을 것.
+MATTERMOST_URL=https://hub.iten.co.kr
+MATTERMOST_TOKEN=replace-with-a-real-system-admin-personal-access-token
+MATTERMOST_TEAM_ID=replace-with-real-team-id
+
+# 앱 로그인 관리자 계정 (단일 관리자 계정)
+APP_ADMIN_USERNAME=admin
+APP_ADMIN_PASSWORD=replace-with-a-long-random-value
.gitignore
--- .gitignore
+++ .gitignore
@@ -1,4 +1,5 @@
 target/
+.env
 frontend/node_modules/
 frontend/node/
 frontend/.vite/
 
README.md (added)
+++ README.md
@@ -0,0 +1,97 @@
+# ITN-HUB
+
+47개 신유형 사업 신청기관의 명부·담당자 정보를 관리하고, 기관별 Mattermost 채널(문정원/법률검토)
+생성을 자동화하는 웹 애플리케이션이다. 기존 Excel VBA 매크로(`M06_Mattermost_기관목록`,
+`M07_Mattermost_채널일괄생성`) 워크플로를 웹으로 옮긴 후속 단계로, 신청목록 시트 업로드로
+기관 정보를 시드하고, 부서/담당자 정보를 입력한 뒤, 기관당 Mattermost 비공개 채널 2개
+(`문정원`, `법률검토`)를 생성·복구한다.
+
+## ⚠️ 실행 전 반드시 읽을 것
+
+- **이 애플리케이션은 실제 운영 Mattermost 서버(`https://hub.iten.co.kr`)에 실제 채널을 생성한다.**
+  테스트 목적으로 함부로 실행하면 운영 팀에 실제 채널이 생긴다.
+- Mattermost `MATTERMOST_TOKEN`(Personal Access Token)은 **시스템 관리자(system-admin) 권한**을
+  가진 계정의 토큰이어야 한다. 비공개(private) 채널을 팀 전체 범위에서 조회(레거시 채널
+  복구용 표시명 검색, `GET /api/v4/teams/{teamId}/channels`)하려면 이 권한이 필요하다.
+  일반 권한 토큰을 쓰면 레거시 채널을 못 찾아 매번 중복 채널이 생성될 수 있다.
+- **최초 사용 전에는 실제 신청기관이 아니라 테스트용 기관(예: 연번 `999`, 임시 기관명)으로
+  먼저 스모크 테스트를 해볼 것을 권장한다.** 시드 업로드 → 담당자 입력 → 채널 생성까지
+  한 번 돌려보고, Mattermost 서버에서 실제로 의도한 이름의 비공개 채널 2개가 만들어지는지
+  확인한 뒤 실제 기관 데이터를 올린다.
+
+## 환경변수
+
+`.env.example`을 참고해 실제 값을 채운 `.env`(또는 배포 환경의 환경변수)를 준비한다.
+**`.env`나 실제 값이 든 파일은 절대 커밋하지 않는다.**
+
+| 변수 | 설명 | 예시 값 |
+|---|---|---|
+| `DB_URL` | PostgreSQL 16 JDBC URL | `jdbc:postgresql://localhost:5432/itnhub` |
+| `DB_USERNAME` | DB 접속 계정 | `itnhub_app` |
+| `DB_PASSWORD` | DB 접속 비밀번호 | `changeme-please` |
+| `MATTERMOST_URL` | Mattermost 서버 베이스 URL | `https://hub.iten.co.kr` |
+| `MATTERMOST_TOKEN` | system-admin 권한 Personal Access Token | `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` |
+| `MATTERMOST_TEAM_ID` | 채널을 생성할 Mattermost 팀 ID | `abcdefghijklmnopqrstuvwxyz` |
+| `APP_ADMIN_USERNAME` | 앱 로그인 관리자 계정 | `admin` |
+| `APP_ADMIN_PASSWORD` | 앱 로그인 관리자 비밀번호(충분히 긴 무작위 문자열 권장) | `use-a-long-random-value` |
+
+이 8개는 전부 `${...}` 플레이스홀더로 `application.yml`에 선언되어 있어 값이 없으면
+애플리케이션이 기동하지 않는다.
+
+### 왜 `spring.datasource.hikari.schema: itnhub`가 있는가
+
+`application.yml`의 `spring.datasource.hikari.schema: itnhub` 설정은 지우면 안 된다.
+`spring.flyway.schemas`는 Flyway 전용 커넥션에만 적용되는 설정이라, 애플리케이션이 실제
+쿼리를 실행하는 HikariCP 커넥션 풀은 이 설정이 없으면 기본 `search_path`(보통 `public`)를
+써서 `relation "organization" does not exist` 오류가 난다. Flyway가 만드는 스키마와
+런타임 커넥션이 바라보는 스키마를 반드시 일치시켜야 한다.
+
+## 빌드
+
+```bash
+mvn -DskipTests package
+```
+
+`pom.xml`의 `frontend-maven-plugin`이 `mvn package` 과정에서 `frontend/`의 React 앱을
+함께 빌드해 `src/main/resources/static/`에 넣고, 그 결과를 Spring Boot의 단일 jar에
+패키징한다. 별도로 프론트엔드를 먼저 빌드할 필요는 없다.
+
+## 실행
+
+```bash
+export DB_URL=jdbc:postgresql://localhost:5432/itnhub
+export DB_USERNAME=itnhub_app
+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
+```
+
+## 최초 사용 순서
+
+1. PostgreSQL 16 인스턴스를 준비하고 위 환경변수로 접속 정보를 지정한다. 기동 시 Flyway가
+   `itnhub` 스키마와 테이블을 자동으로 만든다(수동 DDL 불필요).
+2. 브라우저로 접속해 `APP_ADMIN_USERNAME` / `APP_ADMIN_PASSWORD`로 로그인한다.
+3. 좌측 하단 "신청목록 시트 올리기"로 기관 신청목록 엑셀(`.xlsx`/`.xlsm`)을 업로드해
+   기관 명부를 시드한다.
+4. 기관을 선택해 부서명/담당자명/연락처/이메일(직급/직함은 선택)을 입력하고 저장한다.
+5. "채널 생성"을 눌러 Mattermost에 문정원/법률검토 채널 2개를 생성한다. 이미 생성된
+   채널은 재실행해도 다시 만들지 않는다(idempotent) - 실패한 채널만 다시 시도된다.
+
+## 개발 워크플로
+
+```bash
+cd frontend
+npm install
+npm run dev
+```
+
+Vite 개발 서버가 `/api` 요청을 `:8080`(백엔드)으로 프록시한다. 백엔드는 별도로
+`mvn spring-boot:run` 등으로 띄워둔 상태에서 프론트엔드만 `npm run dev`로 반복 개발하면 된다.
+
+프론트엔드 테스트: `cd frontend && npm test`
+백엔드 테스트(Testcontainers로 PostgreSQL을 띄우므로 Docker 필요): `mvn test`
Add a comment
List