Files
acs/docs/ACS작업일지.md
2026-07-16 11:15:36 +09:00

754 lines
40 KiB
Markdown

# ACS 작업일지
## 2026-07-10
### 작업 범위 합의
- Codex는 `C:\ai-dev\workspace\acs`의 ACS 개선 및 배포 준비를 담당하기로 함.
- RTGS 프로젝트는 별도 담당자가 작업하므로, 사용자가 명시적으로 요청하지 않는 한 `C:\ai-dev\workspace\rtgs`는 읽기/수정/빌드/배포하지 않기로 함.
- ACS 관련 설치, 구성, 변경, 배포, 검증 내용은 이 파일에 계속 갱신하기로 함.
- 서버/저장소 계정 정보와 비밀번호는 일지에 기록하지 않기로 함.
### 로컬 프로젝트 확인
- ACS 구조 확인:
- 백엔드: Spring Boot 3.4.5, Java 21, Maven, JPA, Flyway, PostgreSQL 운영 구성
- 프론트엔드: React 19, Vite 6, TypeScript
- 배포 구성: `infra/docker-compose.yml`, `infra/docker-compose.tls.yml`, nginx reverse proxy
- Git 원격 저장소는 아직 등록되어 있지 않음을 확인함.
- `.git/index.lock` 파일이 남아 있어, 추후 `git add/commit/push` 전 정리가 필요함.
### 배포 전 빌드/테스트 검증
- 프론트엔드 `npm run build` 성공.
- 백엔드 최초 테스트에서 운영 Flyway 스키마와 엔티티 불일치 발견:
- `visit_requests` 테이블에 `work_name`, `control_*`, `watcher*_ *` 계열 컬럼 누락.
- 신규 Flyway 마이그레이션 추가:
- `backend/src/main/resources/db/migration/V4__visit_request_contact_fields.sql`
- 기존 DB에도 적용 가능하도록 `ALTER TABLE ... ADD COLUMN` 방식 사용.
- 테스트용 H2 호환성을 위해 컬럼 추가 구문을 개별 `ALTER TABLE` 문으로 분리함.
- `DataSeeder`의 로컬 계정과 테스트 코드 기대 계정 불일치 수정:
- 기존 단축 계정 `a/s/h` 유지
- 테스트 및 CSV seed와 맞는 `admin/security/host`도 함께 생성하도록 보정
- 백엔드 `mvn -B -ntp test` 성공:
- 9 tests, 0 failures, 0 errors
- 백엔드 `mvn -B -ntp -DskipTests package` 성공:
- `backend/target/acs-0.0.1-SNAPSHOT.jar` 생성 확인
### Docker/Compose 확인
- 로컬 Docker 설치 확인:
- `docker --version` 성공
- `docker compose` 플러그인은 없음
- `docker-compose --version`은 사용 가능
- Compose 설정 문법 확인:
- `docker-compose --env-file infra/.env.example -f infra/docker-compose.yml config` 성공
- `docker-compose --env-file infra/.env.example -f infra/docker-compose.yml -f infra/docker-compose.tls.yml config` 성공
- 운영 배포 URL을 환경변수로 넣은 HTTPS 구성 확인:
- `ACS_PUBLIC_BASE_URL=https://acs.apps.bokdev.in`
- `ACS_COOKIE_SECURE=true`
- Compose config 정상
- Docker 이미지 빌드는 로컬 Docker 빌더 문제로 실패:
- buildx 플러그인 없음
- Docker legacy builder가 Docker API v1.54 build 요청에서 `500 Internal Server Error` 반환
- 코드/Compose 문법 문제보다는 로컬 Docker Desktop/빌더 환경 문제로 판단
### 서버/URL 접근성 확인
- `https://portal.bokdev.in/`:
- HTTPS 접근 가능
- HTTP 200 OK 확인
- `https://acs.apps.bokdev.in`:
- DNS 해석 가능
- 현재 HTTP 503 Service Unavailable 확인
- 아직 앱이 정상 배포/기동되지 않은 상태로 판단
- `https://acs.bokdev.in/0420301/repo`:
- 현재 PC 네트워크에서 `acs.bokdev.in` DNS 해석 실패
- 저장소 원격 등록/푸시 전 네트워크 또는 도메인 확인 필요
### 저장소 URL/DNS 추가 확인
- 저장소 후보 URL `https://acs.bokdev.in/0420301/repo` 확인.
- 로컬 ACS Git remote 확인 결과, 등록된 원격 저장소 없음.
- `git ls-remote https://acs.bokdev.in/0420301/repo` 실행 결과:
- `Could not resolve host: acs.bokdev.in`
- 현재 PC DNS 서버:
- `210.104.132.1`, `210.104.132.2`
- `10.168.198.34`, `10.168.198.35`
- 기본 DNS 및 공개 DNS 확인 결과:
- `portal.bokdev.in``27.96.158.129`로 해석됨.
- `acs.apps.bokdev.in``27.96.158.129`로 해석됨.
- `acs.bokdev.in`은 해석 실패.
- `bokdev.in` 권한 DNS 서버 확인:
- `salvador.ns.porkbun.com`
- `fortaleza.ns.porkbun.com`
- `curitiba.ns.porkbun.com`
- `maceio.ns.porkbun.com`
- 권한 DNS 서버 `curitiba.ns.porkbun.com`에 직접 질의한 결과:
- `portal.bokdev.in` A 레코드 존재: `27.96.158.129`
- `acs.apps.bokdev.in` A 레코드 존재: `27.96.158.129`
- `acs.bokdev.in` A/CNAME 레코드 없음
- `nslookup acs.bokdev.in curitiba.ns.porkbun.com` 결과: `Non-existent domain`
- 결론:
- 현재 저장소 URL의 호스트명 `acs.bokdev.in`은 DNS에 등록되어 있지 않은 것으로 판단.
- 저장소 URL이 잘못 전달되었거나, DNS 레코드 생성이 아직 완료되지 않았을 가능성이 큼.
- 원격 저장소 등록/푸시 전에 정확한 저장소 URL 재확인이 필요.
### AI DEV 매뉴얼 확인
- 참조 파일: `docs/AIdev.md`
- 매뉴얼 기준 주요 서비스:
- 포털: `https://portal.bokdev.in`
- Coder: `https://coder.bokdev.in`
- Gitea: `https://gitea.bokdev.in`
- Kubero: `https://kubero.bokdev.in`
- Coolify: `https://coolify.bokdev.in`
- Gitea 저장소 생성/Push 기준:
- Gitea의 `playground` 조직에 저장소를 생성.
- 저장소 URL 형식은 `https://gitea.bokdev.in/playground/<repo>.git`.
- 예: ACS 저장소명이 `acs`라면 `https://gitea.bokdev.in/playground/acs.git`.
- 배포 기준:
- Gitea 저장소 1개가 배포 앱 1개에 대응.
- Kubero 또는 Coolify 중 하나를 사용.
- Coolify는 Public Repository 방식으로 Gitea 저장소 URL 전체를 입력하고 Dockerfile 빌드를 사용.
- Coolify에서 도메인 생성 시 `https://<repo>.apps.bokdev.in` 형식으로 지정되는 것으로 매뉴얼에 기재되어 있음.
- ACS에 대한 적용 판단:
- 기존 후보 `https://acs.bokdev.in/0420301/repo`는 매뉴얼 기준 저장소 URL 형식이 아님.
- ACS 저장소 URL은 우선 `https://gitea.bokdev.in/playground/acs.git`로 보는 것이 타당.
- 저장소가 아직 없다면 Gitea `playground` 조직에 `acs` repository를 생성해야 함.
- 배포 URL `https://acs.apps.bokdev.in`은 Coolify 도메인 형식과 일치.
### 프로젝트 설정 URL 오류 확인
- 사용자가 포털 프로젝트 수정 화면에서 저장소 URL을 `https://acs.bokdev.in/0420301/repo`로 임의 입력한 사실 확인.
- 해당 값은 Gitea 저장소 URL이 아니므로 수정 필요.
- 후보 저장소 페이지 확인:
- `https://gitea.bokdev.in/playground/acs`: Not found
- `https://gitea.bokdev.in/playground/ACS`: Not found
- `https://gitea.bokdev.in/0420301/acs`: Not found
- `https://gitea.bokdev.in/0420301/ACS`: Not found
- 결론:
- 현재 ACS Gitea 저장소는 아직 생성되지 않았거나, 비공개/다른 이름으로 생성된 상태일 수 있음.
- 매뉴얼 기준으로는 `playground` 조직에 `acs` 저장소를 새로 만들고, 프로젝트 저장소 URL을 `https://gitea.bokdev.in/playground/acs.git`로 설정하는 것이 우선 추천.
- 배포 URL `https://acs.apps.bokdev.in`은 유지 가능.
### Gitea Credential Helper 및 저장소 재확인
- Git 접근 중 Windows `CredentialHelperSelector` 팝업 발생.
- 권장값인 `manager` 선택 완료.
- 이후 `git ls-remote https://gitea.bokdev.in/playground/acs.git` 재시도 시 인증 대기 상태로 타임아웃됨.
- 비대화식 확인:
- `GIT_TERMINAL_PROMPT=0`
- `git -c credential.helper= ls-remote https://gitea.bokdev.in/playground/acs.git`
- 결과: `could not read Username for 'https://gitea.bokdev.in': terminal prompts disabled`
- Gitea API 비교 확인:
- `https://gitea.bokdev.in/api/v1/repos/playground/MANUAL`: 200 OK
- `https://gitea.bokdev.in/api/v1/repos/playground/acs`: `The target couldn't be found`
- 판단:
- Gitea 서버와 API는 정상 접근 가능.
- `playground/acs` 저장소는 비로그인/API 기준으로 존재하지 않거나 private/권한 미승인 상태.
- 포털 프로젝트의 저장소 URL 수정만으로 Gitea 저장소가 자동 생성되는 것은 아니므로, Gitea에서 `playground/acs` repository 생성 여부를 별도로 확인해야 함.
### Gitea ACS 저장소 생성 및 원격 등록
- 사용자가 Gitea에서 ACS 저장소 생성 완료.
- 생성된 저장소 확인:
- 웹 URL: `https://gitea.bokdev.in/0420301/acs`
- Git URL: `https://gitea.bokdev.in/0420301/acs.git`
- `playground/acs`가 아니라 개인 네임스페이스 `0420301/acs`로 생성됨.
- 빈 저장소 상태 확인:
- `git ls-remote https://gitea.bokdev.in/0420301/acs.git` 결과가 비어 있으나 exit code 0으로 정상.
- 이전 타임아웃된 Gitea 확인용 Git 프로세스와 stale lock 파일 정리:
- `.git/config.lock`
- `.git/index.lock`
- 로컬 ACS Git remote 등록 완료:
- `origin https://gitea.bokdev.in/0420301/acs.git`
- 남은 사항:
- push 전 커밋 대상 정리 필요.
- 로그 파일(`backend/backend-run.log`, `frontend/frontend-dev.log`)과 백업 파일(`docs/ACS작업일지.md.bak`)은 커밋 제외 권장.
- 작업트리 변경분 검토 후 최초 commit/push 진행 필요.
### 최초 커밋 및 Gitea Push
- 커밋 대상 정리:
- `.gitignore``*.log`, `*.bak` 제외 규칙 추가.
- `backend/backend-run.log`, `frontend/frontend-dev.log`, `docs/ACS작업일지.md.bak`는 커밋 제외.
- 최초 Gitea push용 커밋 생성:
- 커밋: `01d48fe`
- 메시지: `feat: prepare ACS deployment`
- 포함: ACS 코드 변경, Flyway V4, 문서, 작업일지, AI DEV 매뉴얼 참조 파일.
- 원격 push 완료:
- remote: `origin`
- URL: `https://gitea.bokdev.in/0420301/acs.git`
- branch: `main`
- `origin/main` 추적 설정 완료.
- 원격 검증:
- `git ls-remote origin main` 결과 `01d48fe... refs/heads/main` 확인.
- `https://gitea.bokdev.in/0420301/acs` 웹 페이지 접근 200 OK 확인.
### Gitea 저장소 위치 수정
- 서버담당자/매뉴얼 기준 배포용 저장소는 개인 네임스페이스가 아니라 `playground` 조직 아래여야 함을 확인.
- 기존 개인 저장소:
- `https://gitea.bokdev.in/0420301/acs.git`
- 새 배포용 저장소:
- `https://gitea.bokdev.in/playground/acs.git`
- 사용자가 Gitea `playground` 조직 아래 `acs` 저장소 생성 완료.
- 로컬 ACS Git remote 변경:
- `origin``https://gitea.bokdev.in/playground/acs.git`로 변경.
- `main` 브랜치 push 완료:
- `git push -u origin main`
- 원격 `origin/main` 확인: `4fe4c37... refs/heads/main`
- 포털 프로젝트의 저장소 URL도 `https://gitea.bokdev.in/playground/acs.git`로 맞춰야 함.
### 테스트용 화면 URL 확인
- 프론트 라우트 정의 파일: `frontend/src/App.tsx`
- 관리자/담당자 로그인 화면:
- 운영 배포 기준: `https://acs.apps.bokdev.in/login`
- 로컬 개발 기준: `http://localhost:5173/login`
- 로그인 후 주요 내부 화면:
- 대시보드: `/dashboard`
- 방문 신청 목록: `/visit-requests`
- 방문 신청 등록: `/visit-requests/new`
- 승인 대기: `/approvals`
- 출입 콘솔: `/access`
- 관리자 감사 로그: `/audit`
- 발송 내역: `/deliveries`
- 방문자/출입 QR 관련 공개 화면:
- 방문자 휴대폰 출입증 화면: `/pass/{qrToken}`
- 출입구 키오스크 QR 태깅/스캔 화면: `/kiosk`
- 운영 배포 기준 키오스크 URL: `https://acs.apps.bokdev.in/kiosk`
- QR/출입증 API:
- 공개 출입증 조회: `/api/public/passes/{qrToken}`
- 공개 QR 이미지: `/api/public/passes/{qrToken}/qr.png`
- 키오스크 체크인: `/api/public/passes/{qrToken}/check-in`
- 키오스크 체크아웃: `/api/public/passes/{qrToken}/check-out`
- QR 토큰은 방문 신청 승인 후 `qrToken`으로 발급됨.
- 문자/이메일 발송 링크는 `ACS_PUBLIC_BASE_URL + "/pass/" + qrToken` 형식으로 생성됨.
### 배포 URL 접속 상태 확인
- 운영 배포 후보 URL 확인:
- `https://acs.apps.bokdev.in`
- `https://acs.apps.bokdev.in/login`
- 확인 결과:
- 두 URL 모두 `no available server` 응답.
- 판단:
- Gitea push는 완료되었으나, Coolify 등 배포 플랫폼에서 해당 도메인에 연결된 앱 서버가 아직 생성/기동되지 않았거나 배포가 실패한 상태로 판단.
- 포털의 프로젝트 등록/저장소 URL 설정과 실제 앱 배포는 별도 단계임.
- 다음 확인 필요:
- Coolify에 ACS resource/app 생성 여부.
- Repository URL이 `https://gitea.bokdev.in/0420301/acs.git`로 설정되었는지.
- Branch가 `main`인지.
- 빌드 방식이 Docker Compose 또는 Dockerfile 중 무엇인지.
- 배포 도메인이 `https://acs.apps.bokdev.in`로 연결되었는지.
- Deployments 로그에서 빌드/기동 실패 원인 확인.
### Coolify Docker Compose 리소스 설정 진행
- 사용자가 Coolify `aidev` 프로젝트에서 `+ Add Resource`를 통해 Docker Compose Empty 리소스 생성 화면 진입.
- Docker Compose file 입력 화면에 최초로 `https://acs.apps.bokdev.in`만 입력했으나, 해당 칸은 도메인 입력칸이 아니라 compose YAML 전체를 입력하는 영역임을 안내.
- Coolify용 compose는 repository root 기준으로 `./backend`, `./frontend` build context를 사용하는 형태가 필요하다고 안내.
- 도메인 `https://acs.apps.bokdev.in`은 compose file 영역이 아니라 resource의 Domains 설정에서 별도 입력해야 함.
- 환경변수는 리소스 저장 후 resource 상세 화면의 `Environment Variables`, `Variables`, 또는 `Developer view`에서 입력해야 함.
- Coolify 배포에 필요한 최소 환경변수:
- `POSTGRES_PASSWORD`
- `POSTGRES_USER=acs`
- `POSTGRES_DB=acs`
- `ACS_PUBLIC_BASE_URL=https://acs.apps.bokdev.in`
- `ACS_COOKIE_SECURE=true`
- `ACS_SMS_PROVIDER=dev`
- Docker Compose 입력 화면에서 저장 시 권한 없음 메시지 발생.
- `Teams > aidev > General` 화면 확인:
- 팀 설정 입력칸이 비활성화된 상태로 보임.
- 현재 계정은 `aidev` 팀/프로젝트 조회는 가능하지만 resource 생성/수정 권한이 부족할 가능성이 큼.
- 다음 확인 필요:
- `Teams > aidev > Members`에서 사용자 `0420301`의 역할 확인.
- `aidev` 팀 또는 프로젝트에서 resource create/update/deploy 권한 부여 요청.
- 권한이 없는 경우 권한 있는 관리자가 ACS resource를 생성하거나, 사용자에게 프로젝트 관리자 권한을 부여해야 함.
### 인프라 담당자 피드백 반영 필요
- 인프라 담당자 피드백 요지:
- AI DEV 표준 환경에는 `.project-env`가 미리 정의되어 있음.
- DB를 로컬/compose 내부에 직접 만들고 전체 기술구조를 통째로 배포하는 방식은 표준 흐름과 맞지 않을 수 있음.
- 개발은 PC 로컬보다 포털의 Coder 환경에서 진행하는 것을 권장.
- 배포 앱은 Node.js 기반으로 맞추는 것이 좋다는 의견.
- `CLAUDE.md` 등 프로젝트 작업 규칙 파일이 표준 템플릿에 이미 준비되어 있음.
- 현재 ACS와의 차이:
- 현재 ACS는 Spring Boot 백엔드 + React 프론트 + PostgreSQL + nginx의 다중 컨테이너 구조.
- 기존 compose는 자체 PostgreSQL 컨테이너를 포함함.
- AI DEV 표준은 Coder에서 제공하는 `.project-env``DATABASE_URL` 등 환경값을 사용하고, 앱 소스 중심으로 배포하는 방식으로 보임.
- 대응 방향:
- Coolify Docker Compose 직접 배포 시도를 잠시 중단.
- Coder 환경에서 `playground/acs`를 clone한 뒤, 실제 제공되는 `.project-env`와 sample/템플릿 구조를 먼저 확인.
- 인프라 담당자에게 Java/Spring Boot Dockerfile 배포 허용 여부를 확인.
- Node.js가 필수라면 ACS 백엔드 구조를 Node 기반으로 전환하거나, 최소 배포 가능 범위를 재설계해야 함.
- 자체 DB 컨테이너 대신 플랫폼 제공 PostgreSQL 접속정보(`DATABASE_URL`)를 쓰는 구조로 변경 검토.
- ACS용 `CLAUDE.md` 또는 동등한 작업 규칙 문서를 추가해 Claude/Codex 협업 기준을 명시하는 방안 검토.
### AI DEV 배포 제약 확정
- 인프라 담당자 확인 결과:
- 배포 앱은 Node.js 앱만 허용.
- DB는 반드시 Coder/AI DEV 환경의 `.project-env`에 제공되는 `DATABASE_URL`을 사용해야 함.
- 영향:
- 현재 Spring Boot 백엔드(`backend/`)는 AI DEV 표준 배포 대상이 아님.
- 현재 `infra/docker-compose.yml`의 자체 PostgreSQL 컨테이너 방식은 표준 배포 방식과 맞지 않음.
- ACS를 배포하려면 Node.js 기반 서버/API로 전환하거나, Node.js 배포 앱이 기존 기능을 대체하도록 재구성해야 함.
- 권장 전환 방향:
- React 프론트엔드는 유지 가능.
- 백엔드는 Node.js(Express/Fastify 등)로 재작성 검토.
- DB 접속은 `process.env.DATABASE_URL` 사용.
- 기존 Flyway SQL은 Node 앱 시작/배포 시 적용 가능한 SQL migration 방식으로 재활용 검토.
- 배포 산출물은 단일 Node.js 앱 또는 Node.js + 정적 프론트 서빙 구조로 단순화하는 방향을 우선 검토.
### 인증서 확인
- `infra/certs/fullchain.pem`, `infra/certs/privkey.pem` 존재 확인.
- 현재 인증서는 `CN=localhost`, SAN도 `localhost`, `127.0.0.1`용임.
- 운영 도메인 `acs.apps.bokdev.in`용 인증서가 아니므로 실제 HTTPS 운영 배포에는 부적합.
- 운영 배포 전 포털/플랫폼 인증서 자동 제공 여부 또는 도메인 인증서 교체 필요.
### 배포 정책 추천
- 권장 흐름:
- 로컬 개발
- Git commit/push
- 서버 개발환경 배포
- 서버 개발환경 검증
- 운영 배포 승인
- 서버 운영환경 배포
- 서버에서 직접 코드를 수정하며 개발하는 방식은 비추천.
- 서버 개발환경도 Git으로 받은 검증 대상 환경으로 운영하고, 운영환경에는 검증된 커밋/태그만 배포하는 정책을 권장.
- 권장 브랜치/환경:
- `dev` 또는 `develop`: 서버 개발환경 배포
- `main`: 운영 배포 가능 브랜치
- 운영 배포 시 태그 사용 예: `acs-v0.1.0`
- DB 변경은 Flyway migration으로만 반영하는 정책 유지.
### 남은 작업
- `.git/index.lock` 정리 후 Git 작업 가능 상태 확인.
- ACS 원격 저장소 URL/DNS 문제 확인.
- 원격 저장소 등록 및 최초 push 여부 결정.
- 서버 개발환경과 운영환경을 포털에서 분리 구성할 수 있는지 확인.
- 운영 도메인 인증서 처리 방식 확인.
- 로컬 Docker buildx 또는 Docker Desktop 빌더 문제 해결.
- 실제 배포 전 운영 `.env` 값 확정:
- `POSTGRES_PASSWORD`
- `ACS_PUBLIC_BASE_URL`
- `ACS_COOKIE_SECURE`
- `ACS_SMS_PROVIDER`
- SMTP 또는 사내 메시지 API 설정
## 2026-07-13
### Node.js 전환 착수
- 사용자가 `C:\ai-dev\workspace\acs - 복사본`에 기존 소스 백업이 있으므로, 원본 `C:\ai-dev\workspace\acs`를 AI DEV 표준 배포 구조로 전환하기로 결정.
- 목표:
- Spring Boot 백엔드 배포 방식에서 Node.js 앱 배포 방식으로 전환.
- DB는 자체 PostgreSQL 컨테이너가 아니라 AI DEV `.project-env``DATABASE_URL` 사용.
- 기존 React 프론트와 `/api` 계약은 최대한 유지.
- 추가 문서:
- `docs/node-migration-plan.md`
- 추가된 Node 골격:
- 루트 `package.json`, `tsconfig.json`
- `server/index.ts`
- `server/config/env.ts`
- `server/db/pool.ts`
- `server/db/migrate.ts`
- `server/http/apiResponse.ts`
- `server/http/errors.ts`
- `server/routes/health.ts`
- `server/routes/index.ts`
- Flyway SQL을 Node migration 구조로 1차 이관:
- `migrations/001_init.sql`
- `migrations/002_audit_log.sql`
- `migrations/003_pass_delivery.sql`
- `migrations/004_visit_request_contact_fields.sql`
- 검증:
- `npm install` 완료.
- `npm run typecheck` 성공.
- `npm audit --omit=dev` 결과 운영 의존성 취약점 0건.
- `npm run build` 성공. 단, 로컬 PC 권한 정책상 프론트 `esbuild`는 승인 권한으로 실행 필요.
- `node dist/server/index.js` 기동 후 `GET /api/health` 응답 확인.
- 정적 React build(`/`) 응답 200 확인.
- 다음 작업:
- Auth/session/role middleware 구현.
- PostgreSQL session store 연결.
- 사용자 seed 전략 확정.
- `/api/auth/login`, `/api/auth/logout`, `/api/auth/me`, `/api/auth/change-password`부터 Spring 기능 parity 구현.
### AIdev.md 배포 가이드 준수 보완
- `docs/AIdev.md` 기준 ACS 배포 필수 항목을 재점검.
- 보완 사항:
- 루트 `Dockerfile` 추가. AI DEV Coolify/Kubero Dockerfile build pack 기준으로 빌드.
- 루트 `.dockerignore` 추가.
- Node engine 기준을 `>=22`로 조정.
- `/healthz` 추가: `{"ok": true}` 응답.
- `/db` 추가: `DATABASE_URL`로 PostgreSQL `SELECT now()` 점검.
- `/s3` 추가: ACS는 S3/MinIO 미사용이므로 skip 응답.
- `npm run db:check` 추가: `.project-env`/`.env` 로드 후 DB 점검.
- `npm run minio:check` 추가: ACS S3 미사용 skip 출력.
- `npm run start:deploy` 추가: migration 적용 후 Node 서버 기동.
- `CLAUDE.md` 추가: AI DEV 배포 제약과 ACS 전환 규칙 명시.
- 검증:
- `npm run typecheck` 성공.
- `npm audit --omit=dev` 운영 의존성 취약점 0건.
- `npm run build` 성공. 이 PC에서는 esbuild 실행 정책 때문에 승인 권한 필요.
- `GET /healthz` 정상.
- `GET /api/health` 정상.
- `GET /s3` skip 응답 정상.
- `GET /db`는 현재 Windows 로컬에 `DATABASE_URL`이 없어 500과 명확한 오류 메시지를 반환. AI DEV/Coder에서 `.project-env` 로드 후 재검증 필요.
- `docker build -t acs-node-guide-check .`는 Docker daemon 미기동(`dockerDesktopLinuxEngine` pipe 없음)으로 실행 전 실패. Docker Desktop 또는 AI DEV/Coder 배포 환경에서 재검증 필요.
### Coder / Gitea / Coolify 배포 검증
- Coder 접속:
- `https://coder.bokdev.in/workspaces`에서 `ws-aidev-0420301` 워크스페이스 확인.
- 최초 VS Code Web 접속 시 `Agent state is "disconnected"` 404가 발생했으나, 잠시 대기 후 VS Code Web 아이콘이 활성화되어 접속 성공.
- VS Code Web 작업 위치: `/home/coder/projects`.
- Gitea 장애:
- 초기에는 Gitea 루트는 200이었으나 저장소 URL은 500 오류:
- `https://gitea.bokdev.in/playground/MANUAL`
- `https://gitea.bokdev.in/playground/acs`
- `https://gitea.bokdev.in/0420301/acs`
- `git ls-remote https://gitea.bokdev.in/playground/acs.git`
- 인프라 확인 후 Gitea가 정상화되어 clone 가능해짐.
- AI DEV 표준 프로젝트 생성:
- 단순 `git clone https://gitea.bokdev.in/playground/acs.git`만 수행하면 `.project-env`가 생성되지 않아 `DATABASE_URL`이 없음.
- `docs/AIdev.md`의 6번 절차에 따라 아래 순서로 표준 프로젝트 재생성:
- `mv acs acs-from-git`
- `new-project acs`
- `cd ~/projects/acs`
- `.project-env` 생성 확인.
- 이후 원격 소스 반영:
- `git init -b main`
- `git remote add origin https://gitea.bokdev.in/playground/acs.git`
- `git fetch origin`
- `git reset --hard origin/main`
- `.project-env`가 유지되었고 `DATABASE_URL` 환경변수 로드 확인.
- Coder 로컬 검증:
- `npm install` 성공.
- `npm --prefix frontend install` 성공.
- `npm run typecheck` 성공.
- `npm run db:check` 성공:
- `DB OK: Mon Jul 13 2026 10:53:51 GMT+0900 (한국 표준시)`
- `npm run minio:check`는 ACS S3 미사용으로 정상 skip:
- `S3 SKIPPED: ACS does not currently use S3/MinIO storage.`
- `npm run build` 성공.
- `npm run migrate` 성공:
- `Applied migration 001_init.sql`
- `Applied migration 002_audit_log.sql`
- `Applied migration 003_pass_delivery.sql`
- `Applied migration 004_visit_request_contact_fields.sql`
- `npm start` 성공:
- `ACS Node app listening on port 3000`
- Coder 로컬 endpoint 확인:
- `curl 127.0.0.1:3000/healthz` -> `{"ok":true}`
- `curl 127.0.0.1:3000/db` -> `{"ok":true,"now":"..."}`
- `curl 127.0.0.1:3000/s3` -> ACS S3 미사용 skip 응답.
- Coder 내 Docker/Podman build 성공:
- `docker build -t acs-node-local .`
- `Successfully tagged localhost/acs-node-local:latest`
- Coolify 리소스 생성:
- Coolify 팀/프로젝트: `aidev / production`.
- Resource type: `Public Repository`.
- Repository URL: `https://gitea.bokdev.in/playground/acs.git`.
- Branch: `main`.
- Build Pack: `Dockerfile`.
- Base Directory: `/`.
- Port: `3000`.
- Static site: 비활성.
- 최초 자동 생성 resource 이름:
- `obedient-ocelot-w6wzpkzzv8qua4uzejznirp`
- 최초 자동 생성 domain:
- `https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in`
- Coolify 환경변수 등록:
- `.project-env`에서 제공된 값 중 아래 DB 관련 변수를 등록:
- `DATABASE_URL`
- `PGHOST`
- `PGPORT`
- `PGDATABASE`
- `PGUSER`
- `PGPASSWORD`
- `PGOPTIONS`
- `PORT`
- 추가 ACS 변수:
- `SESSION_SECRET`
- `ACS_PUBLIC_BASE_URL=https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in`
- `ACS_SMS_PROVIDER=dev`
- S3 관련 변수는 ACS 현재 범위에서는 사용하지 않으므로 필수 등록 대상에서 제외.
- Coolify healthcheck 설정:
- Type: `HTTP`
- Method: `GET`
- Scheme: `http`
- Host: `localhost`
- Port: `3000`
- Path: `/healthz`
- Return Code: `200`
- Healthcheck enabled.
- 1차 Coolify 배포 결과:
- Docker image build와 container start는 성공.
- 컨테이너 로그에 `ACS Node app listening on port 3000` 확인.
- 그러나 Coolify healthcheck 실패:
- `/bin/sh: 1: curl: not found`
- `/bin/sh: 1: wget: not found`
- 원인:
- `node:22-bookworm-slim` runtime image에 Coolify가 healthcheck에 사용하는 `curl`/`wget`이 없음.
- healthcheck 실패 조치:
- `Dockerfile` runtime stage에 `curl``ca-certificates` 설치 추가:
- `apt-get update`
- `apt-get install -y --no-install-recommends curl ca-certificates`
- `rm -rf /var/lib/apt/lists/*`
- Coder에서 커밋:
- `Install curl for Coolify healthcheck`
- Coder에서 최초 `git push`는 upstream 미설정으로 실패.
- `git push --set-upstream origin main`은 인증 실패.
- Gitea `Settings > Applications`에서 repository read/write 권한 토큰 생성 후 토큰 URL 방식으로 push 성공.
- 2차 Coolify 배포 결과:
- commit `44a4bc1086ab9d57dd9815e519c2d2c3c2d0d9c4` 기준 배포.
- Docker image build 성공.
- New container started.
- Healthcheck URL:
- `GET http://localhost:3000/healthz`
- Healthcheck passed:
- `Healthcheck status: "healthy"`
- `Return code: 0`
- Rolling update completed.
- Coolify 상태:
- `Running (healthy)`
- 외부 배포 URL 검증:
- `https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in/healthz`
- `{"ok":true}`
- `https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in/db`
- `{"ok":true,"now":"2026-07-13T05:12:54.842Z"}` 등 정상 응답.
- `https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in/login`
- React 로그인 화면 표시 정상.
- 현재 배포 상태:
- AI DEV 표준 Node.js + Dockerfile + `.project-env`/`DATABASE_URL` 기반 배포 파이프라인 성공.
- 현재 Node 서버는 health/db/static frontend 기반까지만 구현됨.
- 기존 ACS 업무 기능은 아직 Spring Boot 백엔드에서 Node API로 이관 전.
- 로그인 화면은 표시되지만 `/api/auth/login` 등 Node Auth API 구현 전이므로 실제 로그인은 다음 단계에서 구현 필요.
- 도메인 정리 및 고정 도메인 전환:
- 최초 Coolify 자동 생성 임시 도메인:
- `https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in`
- 인프라팀에 고정 도메인 사용 가능 여부 확인 요청:
- 희망: `https://acs.apps.bokdev.in`
- 또는 AI DEV 표준: `https://acs.playground.bokdev.in`
- 팀장 확인 결과, Coolify에서 사용자가 직접 고정 도메인으로 변경하면 되는 것으로 판단.
- Coolify `Configuration > General`에서 `Domains` 값을 아래로 변경:
- `https://acs.apps.bokdev.in`
- `Set Direction`은 기존 direction 확인/적용용이며, domain 자체 저장은 `General` 제목 옆 `Save` 버튼으로 처리.
- 도메인 저장 직후 `/healthz`에서 일시적으로 `no available server`가 표시되었으나, 재배포/라우팅 반영 후 정상화.
- Coolify `Configuration > Environment Variables`에서 `ACS_PUBLIC_BASE_URL` 값 변경:
- 변경 전: `https://hridawfl9pktjtzq1vj92zbb.apps.bokdev.in`
- 변경 후: `https://acs.apps.bokdev.in`
- 변경 후 재배포 및 최종 확인 완료:
- `https://acs.apps.bokdev.in/healthz` -> `{"ok":true}`
- `https://acs.apps.bokdev.in/db` -> `{"ok":true,"now":"..."}`
- `https://acs.apps.bokdev.in/login` -> React 로그인 화면 표시 정상.
- AI DEV 포털 프로젝트의 배포 URL도 `https://acs.apps.bokdev.in`로 맞추는 방향으로 정리.
- 다음 작업:
- Node Auth/session/role middleware 구현.
- PostgreSQL session store 구성.
- 사용자 seed 또는 기존 사용자 적재 방식 확정.
- `/api/auth/login`, `/api/auth/logout`, `/api/auth/me`, `/api/auth/change-password` 구현.
- 이후 방문신청/승인/출입/리포트 API를 순차 이관.
## 2026-07-14
### ACS 테스트 준비 및 문서 산출물
- ACS 수동 테스트 시나리오 문서 작성:
- `docs/ACS-test-scenarios.md`
- 운영 기준 URL을 `https://acs.apps.bokdev.in`로 정리.
- Smoke, 권한, 방문신청, 승인/반려, 출입증/QR, 출입콘솔, 키오스크, 블랙리스트, 리포트, 발송함, 엑셀 업로드, 보안/세션, UI 테스트 항목 작성.
- 로그인 404 분석 문서 작성:
- `docs/ACS-login-404-analysis.md`
- 증상, 원인, 조치, 재테스트 기록, 운영 반영 확인 기준 정리.
- 출입신청 화면 UI 수정 문서 작성:
- `docs/ACS-visit-form-ui-update.md`
- 1차/2차 UI 변경 내용, 빌드 검증, 최신 asset 기준 기록.
### 로그인 404/500 조치
- 운영 `https://acs.apps.bokdev.in/login`에서 로그인 시도 시 `POST /api/auth/login` 404 발생.
- 원인:
- Node 서버의 `/api` 라우터에 health 라우터만 연결되어 있었고 Auth API가 미구현 상태.
- Node Auth API 추가:
- `server/routes/auth.ts`
- `POST /api/auth/login`
- `POST /api/auth/logout`
- `GET /api/auth/me`
- `POST /api/auth/change-password`
- 세션 처리 추가:
- `express-session`
- `connect-pg-simple`
- PostgreSQL 기반 `user_sessions` 세션 스토어 사용.
- 사용자 seed 보장:
- `scripts/seeds/users.csv`에 테스트 단축 계정 추가.
- `migrations/005_seed_test_users.sql` 추가.
- 테스트 계정:
- `a / 1` = ADMIN
- `s / 1` = SECURITY
- `h / 1` = HOST
- 운영 재배포 후 404는 해소되었으나 500 발생.
- `/api/auth/diagnostics` 추가 후 확인 결과, 운영 DB에 `users`, `user_roles` 테이블이 없는 상태 확인.
- Coolify 실행 명령이 Dockerfile `CMD ["npm", "run", "start:deploy"]`를 타지 않을 수 있다고 판단.
- 서버 시작 시 migration을 직접 보장하도록 `server/index.ts``runMigrations()` 추가.
- Coolify Redeploy 후 로그인 성공 확인:
- `a / 1` 로그인 성공.
### 운영 배포 및 커밋
- 원격 `origin/main`에 반영한 주요 커밋:
- `7c8bd37 Add Node auth routes for ACS login`
- `9562766 Seed ACS test login accounts`
- `e02afcd Add auth deployment diagnostics`
- `0ae4b73 Run migrations on server startup`
- `7a404cd Update visit request form layout`
- `2653ed6 Compact visit request form`
- Coolify Redeploy 후 `/api/health`에서 최신 build marker 확인:
- `build: auth-seed-20260714`
- `authApi: true`
### 출입신청 화면 UI 1차 개선
- 요청사항 반영:
- 화면 콘텐츠 폭을 브라우저 창 기준으로 넓게 사용하도록 조정.
- 입력 항목과 레이블을 한 줄 배치로 변경.
- 필수 입력 `*` 표시를 red로 변경.
- 방문자 연락처, 현장감시자2 연락처 11자리 숫자 입력 시 `000-0000-0000` 자동 변환.
- `방문자`, `출입통제담당자`, `현장감시자1과2` 테두리 그룹 박스 적용.
- 범례/레이블/개인정보 수집·이용 동의 문구 수정.
- 검증:
- `npm run typecheck` 성공.
- `npm --prefix frontend run build` 성공.
### 출입신청 화면 UI 2차 압축 개선
- 목표:
- 출입신청 화면의 모든 내용을 수직 스크롤 없이 한 화면에 최대한 보이도록 조정.
- 반영 내용:
- 전체 콘텐츠 padding 축소.
- 폼 그룹/필드/동의 영역 여백 축소.
- 그룹 내부를 3열 기반으로 조정.
- `출입 전산실``추가 구역`을 같은 라인에 배치.
- `출입 목적``작업명`을 같은 라인에 배치.
- 불필요한 레이블 설명을 제거하고 필요한 안내는 placeholder로 이동.
- `퇴실예정일시``퇴실 예정일시`로 수정.
- `직원명``이름`으로 수정.
- `현장감시자1과2``현장감시자`로 수정.
- `현장감시자1 : IT센터 사무보조원 (자동 지정)` 문구 반영.
- 출입통제담당자 연락처 표시를 `내선번호/휴대폰번호` placeholder 기준으로 정리.
- 최신 프론트 빌드 asset:
- JS: `/assets/index-Cc3Y9nv_.js`
- CSS: `/assets/index-V1wV5EGT.css`
- 검증:
- `npm run typecheck` 성공.
- `npm --prefix frontend run build` 성공.
### 현재 상태
- 로그인:
- `a / 1` 로그인 성공.
- 운영 URL:
- `https://acs.apps.bokdev.in`
- 출입신청 UI:
- 최신 UI 커밋은 원격 `main` 반영 완료.
- 운영 반영은 Coolify Redeploy 후 HTML asset 해시 확인 필요.
- 로컬 작업트리:
- 이전 작업 중 생성/수정된 미정리 파일이 일부 남아 있음.
- 배포용 커밋은 임시 worktree를 사용해 원격 최신 `main` 기준으로 선별 push 완료.
### 다음 작업
- Coolify Redeploy 후 운영 HTML이 최신 asset을 참조하는지 확인:
- 기대 JS: `/assets/index-Cc3Y9nv_.js`
- 기대 CSS: `/assets/index-V1wV5EGT.css`
- `/visit-requests/new` 화면 실브라우저 확인:
- 한 화면 표시 여부.
- 레이블/placeholder/그룹 박스/연락처 자동 포맷 확인.
- 방문 신청 저장 API가 아직 Node로 이관되지 않은 경우, 다음 테스트 단계에서 `/api/visit-requests` 구현 필요.
## 2026-07-16
### 출입신청 날짜 검증 및 QR 유효기간 정책
- 출입신청 화면에서 퇴장일이 출입일 다음날 이후인 경우 2건 분리 신청 안내 후 제출 차단.
- 출입일시가 현재 시스템 일시 이전이어도 입력 가능하도록 과거일자 차단 제거.
- 출입일시가 퇴장일시보다 늦은 경우 안내 메시지 후 제출 차단.
- 백엔드 신청 생성 API에도 동일한 역전/익일 퇴장 검증 추가.
- 방문자 QR은 `visitFrom`의 일자 동안만 유효하도록 입장 판정 기준을 `visitTo`가 아닌 `visitFrom.toLocalDate()`로 변경.
- 지난 출입일 QR을 스캔하면 입장을 차단하고 해당 신청을 `EXPIRED`로 전이하도록 조정.
- 매일 00:10 만료 배치도 `visitFrom` 기준으로 지난 승인 건을 만료 처리하도록 변경.
- 검증:
- `npm.cmd run build` 성공.
- `mvn.cmd test` 성공.
### 개인정보 동의 문구 조정
- `[개인정보 수집·이용 동의 확인]``[방문자에 대한 개인정보 수집·이용 동의 확인]`으로 변경.
- 보유·이용 기간 문구를 `전산실 퇴장 등록시 입력된 방문자 이름, 연락처, 이메일, 차량번호는 바로 삭제`로 변경.
- 해당 보유·이용 기간 한 줄만 red 색상으로 표시.
- 검증:
- `npm.cmd run build` 성공.
### 시스템 관리 및 출입목적 코드화
- 관리자 전용 `시스템관리` 메뉴 추가.
- 관리 탭:
- 현장감시자1 정보 수정.
- 출입목적 코드/표시명/사용 여부/기타 입력 허용 관리.
- 사용자별 ADMIN/SECURITY/HOST 권한 관리.
- 출입신청 화면의 출입목적 목록을 고정 상수에서 서버 코드 목록 기반으로 변경.
- 방문신청 저장 시 `purposeCode`, `purposeDetail`을 함께 저장하도록 확장.
- 기타 목적 입력값이 기존 출입목적 코드/표시명과 일치하면 해당 코드로 자동 정규화.
- Flyway `V5__admin_config.sql` 추가:
- `purpose_codes`
- `system_settings`
- `visit_requests.purpose_code`
- `visit_requests.purpose_detail`
- 검증:
- `mvn.cmd test` 성공.
- `npm.cmd run build` 성공.
- 로컬 새 API 확인: `/api/purpose-codes`, `/api/admin/purpose-codes`, `/api/settings/watcher1`, `/api/admin/users` 모두 200.
### 팀 기반 권한관리 개선
- 개발1팀 등 조직 변경이 잦은 운영을 고려해 사용자별 권한 직접 수정만 두지 않고, 팀 기준 권한 템플릿을 추가.
- `시스템관리 > 팀 관리` 탭 추가:
- 팀 코드, 팀명, 사용 여부, 기본권한 관리.
- 기본권한은 ADMIN/SECURITY/HOST 다중 선택 가능.
- 팀별 기본권한을 해당 팀 소속 전체 사용자에게 일괄 적용 가능.
- `시스템관리 > 권한관리` 탭 개선:
- 사용자 검색, 팀 필터 추가.
- 사용자별 소속 팀 변경 가능.
- 팀 변경 시 팀 기본권한을 즉시 적용할지 선택 가능.
- 특정 사용자에게 팀 기본권한만 별도 재적용 가능.
- 기존 `users.department`는 호환성을 위해 유지하되, 신규 `teams` 마스터와 `users.team_id`를 기준으로 운영하도록 확장.
- Flyway `V6__teams.sql` 추가:
- `teams`
- `team_default_roles`
- `users.team_id`
- 기존 IT운영팀/개발1팀/보안팀 및 기본권한 seed.
- 검증:
- `mvn.cmd test` 성공.
- `npm.cmd run build` 성공.
- 로컬 서버 재기동 후 `/api/admin/teams`, `/api/admin/users` 모두 200.
### 팀/권한 엑셀 업로드
- `시스템관리 > 팀 관리`에 엑셀 업로드 기능 추가.
- 컬럼: `팀 코드`, `팀명`, `기본권한`.
- 팀 코드를 기준으로 신규/수정 구분.
- 기본권한은 업로드 값으로 교체.
- 양식 다운로드 제공.
- `시스템관리 > 권한관리`에 엑셀 업로드 기능 추가.
- 컬럼: `아이디`, `이름`, `팀명`, `권한`.
- 기존 사용자만 수정하며 신규 사용자 생성은 제외.
- 아이디 기준으로 사용자 확인, 이름 불일치/없는 팀/잘못된 권한/중복 행은 오류 처리.
- 양식 다운로드 제공.
- 업로드는 즉시 반영하지 않고 `검증`으로 미리보기 결과를 확인한 뒤, 오류가 0건일 때만 `적용` 가능하도록 구성.
- 백엔드에서 Apache POI로 `.xlsx`를 파싱하고 적용 시 `ADMIN_CONFIG_UPDATE` 감사로그 기록.
- 검증:
- `mvn.cmd test` 성공.
- `npm.cmd run build` 성공.
- 로컬 서버 재기동 후 팀 양식 다운로드 및 `/api/admin/teams/upload?dryRun=true` 200 확인.
- 권한 양식 다운로드 및 `/api/admin/users/roles/upload?dryRun=true` 200 확인.
### 권한관리 운영 방식 일원화
- `시스템관리 > 권한관리` 하단 목록의 사용자별 `기본권한 적용` 버튼 제거.
- 사용자별 권한 변경은 팀 선택/권한 체크박스 수정 후 `저장` 버튼으로 반영하도록 변경.
- 팀 변경 시에도 팀 기본권한을 자동 적용하지 않고, 관리자가 화면에서 확인한 권한 체크 상태 그대로 저장.
- 팀 기본권한 적용 기능은 `팀 관리`의 팀원 일괄 적용 또는 권한 엑셀 업로드 방식으로만 유지.
- `/api/admin/**`는 기존 보안 설정상 ADMIN 권한자만 접근 가능함을 확인.
- 검증:
- `npm.cmd run build` 성공.
- `mvn.cmd test` 성공.
- 2026-07-16 배포 준비:
- 서버 배포 구조가 루트 Node Dockerfile 기준임을 확인하고, Spring Boot 변경사항 중 서버에서 필요한 기능을 Node API로 이관.
- 원격 최신 `playground/acs` 기준의 클린 클론(`acs-deploy`)에 Node/프론트/마이그레이션 변경만 적용.
- 클린 클론 검증:
- `npm.cmd run typecheck` 성공.
- `npm.cmd run build` 성공.
- `npm.cmd test` 성공.
- 로컬 DB 접속 정보(`DATABASE_URL`)가 없어 신규 마이그레이션은 서버 기동 시 적용되는 방식으로 확인 예정.
- 원격 `playground/acs` `main`에 배포 커밋 `c6f342a` push 완료.
- 운영 URL 확인:
- `/healthz` 200, `/db` 200, `/login` 200.
- `/api/health`의 build marker가 여전히 `auth-seed-20260714`이고 `/api/purpose-codes`가 JSON이 아니라 SPA HTML을 반환.
- 판단:
- Gitea push는 성공했지만 Coolify가 아직 새 커밋을 재배포하지 않음.
- Public Repository 방식은 webhook 미설정 시 push만으로 자동 배포되지 않으므로 Coolify에서 수동 Redeploy 또는 Gitea webhook 설정 필요.