website: 로그 조회 전용 계정 logviewer + 스킬 추가
X-Request-Id로 요청별 로그를 추적하는 기능(#404)은 만들어 놨는데, 정작 그 로그를 볼 수 있는 사람이 없는 상태였다. 팀원용 SSH 계정은 dbclient 하나뿐이었고 이건 DB 조회 전용이라, 백엔드 개발자인 신선우·안시현이 자기가 만든 버그의 로그를 확인하려면 매번 나한테 물어봐야 했다.
이 문제를 풀 때 처음부터 새로운 방식을 고민하지는 않았다. dbclient-sqlite-guard.sh가 이미 forced command 패턴으로 잘 돌아가고 있었고, db-access.md라는 문서 구조도 있었으니 그걸 그대로 가져다 로그 버전으로 만들면 됐다. 다만 dbclient와 위험의 성격이 다르다는 점은 짚고 넘어가야 했다. dbclient는 SQL을 직접 실행하는 CLI라 셸 탈출이 핵심 관심사였는데, logviewer는 애초에 grep 결과만 돌려주는 도구라 그런 경로 자체가 없다. 대신 다른 문제가 있었다 — 검색어를 자유롭게 열어두면 "로그 전체를 뒤지는 범용 grep 도구"가 돼버린다는 것. 그래서 requestId를 UUID 정규식으로 강제하고, stage/prod 두 값 외에는 사용법 안내만 하고 끝나게 좁혔다.
if [[ ! " ]]; then
echo "requestId 형식이 올바르지 않습니다 (UUID만 허용, 예: 3f9a1c2e-...)" >&2
exit 1
fi
/home/ubuntu 통과 권한도 dbclient 때 이미 한 번 겪은 문제라 같은 답을 그대로 썼다. chmod o+x /home/ubuntu로 열면 서버의 다른 로컬 계정까지 뚫리는 사고가 났던 이력이 있어서, setfacl -m u:logviewer:x /home/ubuntu로 계정 단위만 열기로 했다. 이건 이번에 새로 판단한 게 아니라 db-access.md에 이미 기록돼 있던 교훈을 그대로 재사용한 거다.
문제는 정작 실행권한을 커밋하는 순간에 터졌다. dbclient-sqlite-guard.sh가 2026-07-24에 실행권한 없이 커밋돼서 재배포마다 forced command가 조용히 죽었던 사고를 db-access.md에서 이미 읽었던 터라, 이번엔 안 그러려고 신경 쓰고 있었다. 그런데 로컬에서 chmod +x를 해놓고 git ls-files -s로 확인해보니 여전히 100644였다. 지금 작업 환경이 Windows라 core.filemode=false로 설정돼 있어서, 로컬 chmod가 git에 아예 반영이 안 되고 있었던 거다. 알고 있던 함정을 다른 경로로 또 밟을 뻔한 셈이다. git update-index --chmod=+x로 강제로 100755를 박고, 같은 PR 안에서 git ls-files -s로 재확인까지 했다.
이 PR에는 코드와 문서만 담았다. logviewer 계정을 실제로 만들고(useradd), ACL을 걸고, 신선우·안시현의 기존 dbclient 공개키를 재활용해 등록하는 작업은 서버 상태를 바꾸는 일이라 머지 후 별도로 진행하기로 했다. 테스트도 로컬에 실제 서버 환경(로그 파일, SSH 계정)이 없어서 bash -n 문법 검증까지만 하고, 실제 동작 확인은 계정 등록 후 수동 실행으로 남겨뒀다 — dbclient-sqlite-guard.sh 때와 동일한 방식이다.
문서 쪽은 팀원이 SSH 명령을 직접 치는 게 아니라 Claude Code한테 "이 요청 로그 좀 봐줘"라고 물으면 스킬이 log-access.md를 읽어서 바로 처리하도록 만들었다. 스킬 안에 내용을 복붙하지 않고 항상 문서를 다시 읽게 한 이유는, 문서가 바뀌었는데 스킬이 낡은 답을 주는 걸 막기 위해서다. PR은 생성 1분 만에 병합됐는데, 코드·문서만 다루는 인프라 변경이라 별도 리뷰 없이 바로 합쳤다.