방문자 사전신청·승인, 입·출입 체크인/아웃, QR 배지, 재실현황, 블랙리스트, 대시보드 통계, 방문 리포트(엑셀)까지 7단계 전 기능 구현. - backend: Spring Boot 3.4.5 / Java 21 (JDK 26 빌드), 세션 인증, JPA, H2/PostgreSQL, POI, ZXing, Flyway - frontend: React 19 / Vite 6 / TypeScript - infra: Docker Compose (db·app·web nginx), Flyway V1__init, Python 사용자 시드 - docs: 워크플로우 / 시퀀스 다이어그램(Mermaid) / 이슈·유의사항 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
111 lines
6.0 KiB
Markdown
111 lines
6.0 KiB
Markdown
# IT센터 출입자관리시스템 (Access Control System)
|
|
|
|
IT센터 방문자/출입자 관리 웹 시스템. 방문 사전신청·승인, 입·출입 체크인, QR/배지 발급,
|
|
통계·리포트·블랙리스트를 목표로 하며, 출입통제 하드웨어는 추후 연동 가능하도록 추상화한다.
|
|
|
|
## 기술 스택
|
|
- **백엔드**: Spring Boot 3.4.5 / Java 21 (JDK 26 빌드) · Spring Security(세션) · JPA · H2(dev)·PostgreSQL(prod) · POI · ZXing · Flyway
|
|
- **프론트엔드**: React 19 · Vite 6 · TypeScript · react-router 7
|
|
- **포트**: API `8080`, 웹 `5173`
|
|
|
|
## 역할
|
|
| 역할 | 권한 |
|
|
|------|------|
|
|
| `ADMIN` | 전체 관리, 사용자/블랙리스트/리포트, 모든 승인 |
|
|
| `SECURITY` | 입·출입 콘솔(체크인/아웃), 재실현황, 배지 발급 |
|
|
| `HOST` | 방문 사전신청 등록, 담당 방문 승인 |
|
|
|
|
## 실행 (로컬 개발, H2)
|
|
```cmd
|
|
:: 백엔드 (http://localhost:8080)
|
|
run-backend.cmd
|
|
|
|
:: 프론트엔드 (http://localhost:5173)
|
|
run-frontend.cmd
|
|
```
|
|
> 두 스크립트는 `C:\ai-dev\scripts\env.cmd`(포터블 JDK/Maven/Node)를 먼저 로드한다.
|
|
|
|
### 초기 계정 (DataSeeder, dev 전용)
|
|
| 아이디 | 비밀번호 | 역할 |
|
|
|--------|----------|------|
|
|
| admin | ChangeMe123! | ADMIN |
|
|
| security | ChangeMe123! | SECURITY |
|
|
| host | ChangeMe123! | HOST |
|
|
|
|
최초 로그인 시 비밀번호 변경이 요구된다.
|
|
|
|
## 주요 API
|
|
- `POST /api/auth/login` · `POST /api/auth/logout` · `GET /api/auth/me` · `POST /api/auth/change-password`
|
|
- `GET /api/zones`
|
|
- `GET/POST /api/visit-requests` · `GET /api/visit-requests/pending` · `POST /api/visit-requests/{id}/cancel` · `POST /api/visit-requests/upload`(엑셀)
|
|
- `POST /api/approvals/{id}/approve` · `POST /api/approvals/{id}/reject`
|
|
- `POST /api/access/check-in` · `POST /api/access/check-out` · `GET /api/access/inside` · `GET /api/access/search?q=`
|
|
- `GET /api/passes/{id}` · `GET /api/passes/{id}/qr.png`(배지 QR)
|
|
- `GET /api/stats/summary` · `GET /api/reports/visits.xlsx?from=&to=`
|
|
- `GET/POST /api/blacklist` · `DELETE /api/blacklist/{id}` (ADMIN)
|
|
|
|
API 스모크 테스트는 [backend/test-api.http](backend/test-api.http) 참고.
|
|
|
|
## 구현 현황
|
|
- [x] **1단계** 스캐폴딩 (pom, 설정, 공통 클래스, 전역 예외/응답 래퍼, JPA auditing)
|
|
- [x] **2단계** 인증·인가 (세션 로그인, 역할 기반 권한, 시드)
|
|
- [x] **3단계** 방문 사전신청 + 승인 (신청/취소/엑셀 업로드, 승인/반려 시 qrToken 발급) + 프론트 화면
|
|
- [x] **4단계** 입·출입 체크인/체크아웃 + 재실현황 (`AccessEvent`, `AccessControlGateway`+Mock, QR/이름 체크인, 재실 목록, 중복입장·만료 검증) + 출입콘솔 화면
|
|
- [x] **5단계** QR/배지 발급 (ZXing PNG `/api/passes/{id}/qr.png`, 배지 인쇄 화면)
|
|
- [x] **6단계** 블랙리스트(체크인 시 차단) + 대시보드 통계 집계 + 방문 리포트 엑셀(POI) 다운로드
|
|
- [x] **7단계** Flyway `V1__init.sql`(prod) + Docker Compose(db·app·web nginx) + Python 사용자 시드
|
|
|
|
## Docker 실행 (prod, PostgreSQL)
|
|
```bash
|
|
cd infra
|
|
cp .env.example .env # 값 수정 (아래 참고)
|
|
docker compose up -d --build # db + app(:8080) + web(nginx :80)
|
|
docker compose run --rm seed # 사용자 시드 적재 (admin/security/host)
|
|
docker compose logs -f app # 기동/마이그레이션 로그
|
|
```
|
|
- 백엔드는 `prod` 프로파일로 기동, Flyway가 스키마를 생성/검증한다.
|
|
- 웹(nginx)이 정적 파일 + `/api` 리버스 프록시를 담당한다.
|
|
- DB는 named volume(`db_data`)에 영속 — 재기동해도 데이터 유지(dev H2와 다름).
|
|
|
|
### .env 주요 값
|
|
| 변수 | 설명 |
|
|
|------|------|
|
|
| `POSTGRES_PASSWORD` | DB 비밀번호 (실제값으로 변경) |
|
|
| `WEB_PORT` | 웹 공개 포트 (기본 80) |
|
|
| `ACS_SMS_PROVIDER` | `dev`(로그만) / `hanbank`(사내 API로 LMS 실발송) |
|
|
| `ACS_PUBLIC_BASE_URL` | 문자 링크가 가리키는 주소 — **방문자 휴대폰에서 접속 가능한 실제 URL** (localhost 금지) |
|
|
| `ACS_SMS_API_URL` | 사내 메시지 API 주소 (기본 `http://210.104.132.59:8000`) |
|
|
|
|
### 문자 실발송(hanbank) 전제
|
|
1. 서버에서 메시지 API 도달 확인: `nc -vz 210.104.132.59 8000`
|
|
2. `ACS_SMS_PROVIDER=hanbank`, `ACS_PUBLIC_BASE_URL`=외부 접속 URL 로 설정 후 재기동
|
|
|
|
### HTTPS / 카메라 스캔 (선택, 접속 방식에 따라 필요)
|
|
- 출입콘솔의 **웹캠 QR 스캔**은 secure context(HTTPS 또는 localhost)에서만 동작한다.
|
|
서버를 `http://내부IP`로 접속하면 카메라가 차단된다.
|
|
- 방문자 공개 링크(`/pass/{token}`)도 HTTPS 도메인이면 휴대폰에서 안전하게 열린다.
|
|
- 적용하려면: 사내 도메인/인증서 확보 → `frontend/nginx.conf`에 443 TLS server 블록 추가,
|
|
`docker-compose.yml` web 서비스에 `"443:443"` 매핑 + 인증서 볼륨 마운트,
|
|
`ACS_PUBLIC_BASE_URL`을 `https://...`로 설정. (도메인/인증서 확정 후 진행)
|
|
|
|
### 사내망 빌드 참고
|
|
`docker compose build`는 컨테이너 안에서 npm/maven 의존성을 받는다. dev 서버는 공개망 직접
|
|
접근이 되어 대개 그대로 성공하지만, 사내 SSL 인스펙션에 걸려 인증서 오류가 나면 Dockerfile에
|
|
사내 CA 주입 또는 내부 미러 설정이 필요하다(그때 별도 반영).
|
|
|
|
## 디렉터리
|
|
```
|
|
backend/ Spring Boot (com.itcenter.acs)
|
|
frontend/ React + Vite
|
|
docs/ 워크플로우·시퀀스 다이어그램·이슈/유의사항 문서
|
|
```
|
|
|
|
## 문서
|
|
- [docs/workflow.md](docs/workflow.md) — 전체 업무 워크플로우(서술형)
|
|
- [docs/workflow-sequence.md](docs/workflow-sequence.md) — 시퀀스/상태 다이어그램(Mermaid)
|
|
- [docs/issues-and-guidelines.md](docs/issues-and-guidelines.md) — 이슈 정리 및 유의사항(규칙)
|
|
|
|
## 빌드 노트
|
|
- JDK 26 환경에서 Lombok은 **1.18.46** + maven-compiler-plugin `annotationProcessorPaths` 설정이 필요하다
|
|
(Spring Boot가 핀한 1.18.38은 JDK 26에서 애너테이션 처리가 동작하지 않음). `backend/pom.xml`에 반영됨.
|