13 KiB
13 KiB
ACS 개발 이슈 정리 및 유의사항(규칙)
문서 작성일: 2026-07-03 대상: IT센터 출입자관리시스템 (
C:\ai-dev\workspace\acs) 목적: 기획·개발·테스트·수정 단계에서 실제로 겪은 이슈를 정리하고, 재발 방지를 위한 규칙으로 제안한다. 표기: 각 항목은 [이슈] → [규칙] 형태. 규칙 요약은 문서 끝 §6 체크리스트 참조.
1. 기획 단계
1-1. 출입 하드웨어 미확정
- [이슈] 실제 출입통제 게이트 장비가 확정되지 않은 상태에서 개발을 시작해야 했다.
- [규칙] 외부 의존(장비·SMS·인증서 등)은 인터페이스로 추상화하고 Mock 구현을 기본 제공한다. ACS는
AccessControlGateway+MockAccessControlGateway로 이 원칙을 지켰다. 실장비는 구현체 교체만으로 붙일 수 있어야 한다.
1-2. 상태(라이프사이클) 정의를 코드보다 먼저
- [이슈] 방문 신청의 상태(승인 대기/승인/반려/취소/만료)가 모호하면 서비스 곳곳의 분기가 흐트러진다.
- [규칙] 도메인 상태 머신을 먼저 확정하고 enum(
VisitStatus)으로 고정한다. 상태 전이 규칙(예:PENDING만 승인 가능, 방문일 경과 시EXPIRED)을 문서/주석에 남긴다.
1-3. 역할·권한 경계
- [이슈] ADMIN/SECURITY/HOST의 화면·API 접근 범위가 불명확하면 권한 누수가 생긴다.
- [규칙] 역할별 접근 표를 기획 단계에서 확정하고, 프론트 라우팅 가드(
Protected roles=[...])와 백엔드 인가(SecurityConfig)에서 이중으로 강제한다. 프론트 가드만 믿지 않는다.
1-4. 방문자 개인정보·공개 링크
- [이슈] 방문자에게 보내는 출입증 링크(
/pass/:token)는 비로그인 공개 페이지다. - [규칙] 공개 식별자는 추측 불가능한 토큰(UUID
qrToken)만 사용하고, 순번 ID를 공개 URL에 노출하지 않는다.
2. 개발 단계 — 빌드/환경
이 프로젝트는 JDK 26 + Maven + 사내 보안환경(EDR·선택적 SSL 인스펙션)이라는 특수 조합에서 개발되었다. 아래는 재현성이 확인된 함정들이다.
2-1. JDK 26에서 Lombok이 조용히 동작 안 함
- [이슈]
cannot find symbol: method getX/setX수백 개. Lombok 애너테이션 프로세서가 침묵 실패. - [규칙] 두 가지를 모두 적용한다 (하나만으론 부족):
pom.xml <properties>에<lombok.version>1.18.46</lombok.version>(Spring Boot가 핀한 1.18.38은 JDK 26 미지원).maven-compiler-plugin에 명시적annotationProcessorPaths로 lombok 등록 (JDK 23+는 classpath 자동 발견을 하지 않음).
- 참고:
backend/pom.xml이 정상 레퍼런스.
2-2. 콜드 Maven 빌드가 .lastUpdated 파일잠금으로 죽음
- [이슈] 처음 빌드 시
FileSystemException: ....lastUpdated: 다른 프로세스가 파일 사용 중→ reactor 전체 중단. 원인은 사내 EDR의 실시간 파일 잠금. - [규칙]
MAVEN_OPTS에-Dmaven.legacyLocalRepo=true(env.cmd에 반영됨). 직접 mvn 실행 시에도 포함.- 콜드 빌드는 실패하면
find .m2 -name '*.lastUpdated' -delete후 재시도 루프로 repo를 데운다. 한번 캐시가 따뜻해지면 이후엔 깨끗하게 빌드된다. - 검증 실행은
mvn package로 fat jar를 만들어java -jar로 구동하는 것이 가장 안전(런타임에 Maven 불필요 → 잠금 회피).
2-3. 편집 중 잔여 .tmp.* 파일
- [이슈] 소스 곳곳에
*.java.tmp.PID.hash,*.tsx.tmp...같은 잔여 파일이 남아 있다(현재도 7개 존재). 에디터/툴이 원자적 교체를 하는 중 EDR 잠금으로 임시본이 정리되지 못한 흔적. - [규칙]
- 커밋/빌드 전
find . -name "*.tmp.*" -not -path '*/target/*' -delete로 정리. .gitignore에*.tmp.*패턴을 추가해 저장소 오염을 막는다.
- 커밋/빌드 전
2-4. 사내 SSL 인스펙션 (선택적)
- [이슈] 명시적 프록시는 없지만 일부 도메인은 사내 장비가 인증서를 재서명(Bank of Korea CA). curl/git은 폐기검사 hard-fail(
CRYPT_E_NO_REVOCATION_CHECK)로 끊김. - [규칙]
- 검증을 끄지 않는다.
verify=False, 사내 CA 단독 번들 교체(REQUESTS_CA_BUNDLE=사내단독) 금지 — 공인 CA 호스트(npm/pypi/github)가 깨진다. - 추가형/저장소형 신뢰만 사용: Windows 저장소(공인+사내 CA)를 쓰고, 폐기검사만 건너뛴다(curl
ssl-no-revoke, gitschannelCheckRevoke=false). - TLS/인증서 오류가 나면 임의 대응 대신
corporate-cert-fix스킬을 사용한다.
- 검증을 끄지 않는다.
2-5. .cmd 스크립트 인코딩
- [이슈]
.cmd편집 시 LF 혼입 → cmd.exe 파싱 깨짐. 한글 주석이 든 .cmd는 CP949 콘솔에서 바이트 desync로 줄이 깨져 엉뚱한 명령 실행. - [규칙]
scripts\*.cmd는 ASCII 전용 + CRLF 줄바꿈. 한글 설명은.cmd가 아니라 별도readme\·data\md에 둔다.
3. 개발 단계 — 도메인 로직
3-1. 승인 시점에 qrToken 발급
- [이슈] 출입증 QR·공개 링크·문자 발송이 모두 하나의 토큰에 의존한다.
- [규칙]
qrToken(UUID)은 승인(APPROVED) 시점에만 발급한다(ApprovalService). 신청/반려 단계에서는 발급하지 않는다.
3-2. 알림 발송 실패가 승인을 롤백하면 안 됨
- [이슈] 문자 발송(외부 API)이 실패하면 승인 트랜잭션까지 롤백될 위험.
- [규칙] 부수효과(알림)의 실패는 catch & log로 흡수하고 주 트랜잭션(승인)은 커밋한다(
ApprovalService.notifyVisitor). 외부 I/O 실패로 핵심 업무가 무효화되지 않게 한다.
3-3. 체크인 검증 순서 고정
- [이슈] 검증 순서가 흐트러지면 만료·차단·중복입장이 잘못된 우선순위로 처리될 수 있다.
- [규칙]
AccessService.checkIn의 검증 순서를 유지한다:- 상태
APPROVED확인 - 방문 종료일 경과 →
EXPIRED전이 + 거부 - 방문 시작일 이전 → 거부
- 블랙리스트 매칭 → 403 차단
- 이미 재실 중 → 409 중복입장
- 금일 퇴장 완료 → 재입장 불가
- 상태
- 상태 값·거부 사유 메시지를 응답에 명확히 담는다.
3-4. "일자" 기준 판정 (늦은 도착 허용)
- [이슈] 시각까지 엄격히 보면 몇 분 늦은 방문자가 입장 거부된다.
- [규칙] 입장 허용은 날짜(LocalDate) 기준으로 판정하고, 실제 입출입 시각은 신청 시각과 분리하여
access_events.event_at에 기록한다.
3-5. 재실 판정은 마지막 이벤트로
- [이슈] 입장/퇴장을 별도 플래그로 관리하면 정합성이 깨진다.
- [규칙] "현재 재실 중"은 별도 상태 컬럼이 아니라 해당 방문의 마지막
AccessEvent방향이IN인가로 판정한다(isInside). 단일 진실원본(이벤트 로그)을 유지한다.
3-6. 웹캠 QR 스캔은 secure context 필수
- [이슈] 출입콘솔/키오스크의 웹캠 QR 스캔이
http://내부IP접속 시 카메라 차단으로 동작 안 함. - [규칙] 카메라 기능은 HTTPS 또는 localhost에서만 동작함을 전제로 배포한다. QR 스캔이 필요한 단말은 HTTPS 도메인 또는 localhost로 접속시킨다(대안: 이름 검색 체크인).
3-7. 문자 링크 주소(ACS_PUBLIC_BASE_URL)
- [이슈] 문자에 담긴 출입증 링크가
localhost면 방문자 휴대폰에서 열리지 않는다. - [규칙]
ACS_PUBLIC_BASE_URL은 방문자 휴대폰에서 실제 접속 가능한 외부 URL로 설정한다. localhost 금지. 실발송(hanbank) 전 메시지 API 도달성(nc -vz)을 확인한다.
4. 테스트 단계
4-1. 런타임 end-to-end 검증
- [이슈] 컴파일 성공 ≠ 동작. 특히 QR 이미지·엑셀·권한 가드는 실제 응답을 봐야 안다.
- [규칙] 핵심 플로우는 curl 실서버 검증으로 확인한다(로그인→신청→승인→체크인→재실→체크아웃, 역할 가드 403 포함). ACS는 1~7단계 전부 런타임 검증됨: QR PNG 240x240 유효/없으면 404, 블랙리스트 add→체크인 403→해제→200, stats 정확, 리포트 xlsx 셀 내용·역할 가드·잘못된 기간 400 확인.
- API 스모크 테스트는
backend/test-api.http에 유지한다.
4-2. Flyway 마이그레이션 검증 자동화
- [이슈] prod 스키마(Flyway
V1__init.sql)와 JPA 엔티티가 어긋나면 운영 기동 시 터진다. - [규칙] Flyway 스크립트를 JUnit 회귀 테스트로 검증한다. ACS는
FlywayValidationTest(@ActiveProfiles("fwtest"), H2 PostgreSQL-mode +ddl-auto=validate)로 V1을 검증한다. 스키마를 바꿀 때 이 테스트를 반드시 통과시킨다.
4-3. 경계·예외 케이스
- [이슈] 정상 경로만 보면 중복입장/만료/차단/권한 없음이 방치된다.
- [규칙] 각 API의 거부·오류 경로(403/404/409/400)를 정상 경로와 함께 테스트한다. 상태 코드와 사유 메시지를 검증한다.
4-4. Docker 실기동은 별도 확인 필요
- [이슈] 검증 시 Docker 데몬이 꺼져 있어
docker compose up실기동은 미검증으로 남았다. - [규칙] 컨테이너 빌드/기동은 환경 가용 시 별도 검증 항목으로 명시하고, 미검증이면 "미검증"으로 솔직히 남긴다. 특히 사내망
docker build는 SSL 인스펙션에 걸리면 사내 CA 주입/내부 미러가 필요할 수 있다.
5. 수정/유지보수 단계
5-1. 버전 관리 시작
- [이슈] 현재 저장소에 git 커밋 이력이 없다(작업이 커밋되지 않음). 잔여
.tmp파일도 함께 방치. - [규칙] 의미 있는 단위로 즉시 커밋한다. 커밋 전
.tmp.*정리 + 빌드/핵심 테스트 통과 확인..gitignore에target/,node_modules/,*.tmp.*,.env,sms-outbox/등을 등록해 산출물·비밀·임시파일이 커밋되지 않게 한다.
5-2. dev 시드/비밀번호가 prod로 새면 안 됨
- [이슈]
DataSeeder의 admin/security/host +ChangeMe123!는 개발 편의용이다. - [규칙] 시드 계정은
@Profile("!prod")로 prod에서 비활성한다(적용됨). prod 사용자는 별도 스크립트(scripts/seed-load.py)로 적재하고, 최초 로그인 시 비밀번호 변경(mustChangePassword)을 강제한다. 기본 비밀번호를 문서/코드에 그대로 두지 않는다.
5-3. 상태 전이 로직 수정 시 파급 확인
- [이슈]
VisitStatus전이나 체크인 검증을 고치면 승인·재실·리포트·통계가 연쇄 영향을 받는다. - [규칙] 상태/검증 로직을 수정하면 §3-3 검증 순서와 §4의 end-to-end·Flyway 테스트를 재실행한다. 상태 값을 추가/변경하면 프론트 표시 문자열과 통계 집계도 함께 갱신한다.
5-4. 비밀·설정은 .env로 분리
- [이슈] DB 비밀번호, SMS provider, 공개 URL 등이 코드에 박히면 환경 이전이 위험해진다.
- [규칙] 환경 의존 값은 전부
.env(예:POSTGRES_PASSWORD,WEB_PORT,ACS_SMS_PROVIDER,ACS_PUBLIC_BASE_URL,ACS_SMS_API_URL)로 분리하고.env.example만 커밋한다. 실제.env는 커밋 금지.
5-5. HTTPS/장비 연동 등 미완 항목 추적
- [이슈] HTTPS(카메라), 실 출입장비, 사내망 Docker 빌드는 도메인/인증서/장비 확정 후 진행할 항목으로 남아 있다.
- [규칙] 미완/보류 항목은 README·이 문서에 명시적으로 남기고, 전제 조건(도메인·인증서·장비 스펙)이 갖춰지면 반영한다.
6. 규칙 요약 체크리스트
환경/빌드
- Lombok 1.18.46 +
annotationProcessorPaths유지 (JDK 26) MAVEN_OPTS에-Dmaven.legacyLocalRepo=true, 콜드빌드는 retry, 검증은java -jar- 커밋 전
*.tmp.*정리,.gitignore등록 - TLS 오류 시 검증 끄지 말 것 →
corporate-cert-fix스킬 (추가형 신뢰) scripts\*.cmd는 ASCII + CRLF, 한글 설명은 md로 분리
도메인 로직
qrToken은 승인 시점에만 발급- 알림 실패는 catch & log (승인 롤백 금지)
- 체크인 검증 순서 6단계 고정, 날짜 기준 판정
- 재실 판정은 마지막 이벤트 방향으로
- 카메라 QR = secure context, 문자 URL은 외부 접속 가능 주소
테스트
- 정상+거부(403/404/409/400) 경로 모두 curl 검증
- Flyway
FlywayValidationTest통과 - Docker 실기동은 가용 시 별도 검증, 미검증이면 명시
보안/운영
- 시드 계정
@Profile("!prod"), 기본 비밀번호 강제 변경 - 비밀/설정은
.env분리,.env.example만 커밋 - 의미 단위 즉시 커밋, 미완 항목은 문서에 추적