
외부 고객용 문의 창구를 사내 시스템에 붙일 때, 직원 명부와 떼어 놓은 이유
사내 그룹웨어에 외부 문의 창구를 붙여 첫 배포본을 낸 직후였습니다. 업데이트 안내 화면에 새 기능 네 줄이 같이 실려 나갔습니다.
업데이트 안내는 전 직원이 보는 화면입니다. 그런데 이 기능은 몇 사람만 보게 잠가 둔 비공개 시범이었습니다.
메뉴와 주소와 데이터 요청은 전부 막아 둔 상태였습니다. 쓸 수 있는 사람은 그대로였지만 기능이 생겼다는 사실은 전 직원에게 공개됐습니다.
지적을 받고 그 네 줄을 지워 다시 배포했습니다. 다시 나간 배포본에서 기능 이름을 검색해 0건인 것까지 확인했습니다.
이 일을 겪고 외부인을 사내 시스템에 들일 때 막아야 할 자리를 다시 셌습니다. 화면 하나로 끝나는 일이 아니었습니다.
기본값이 켜짐인 스위치
그 시스템은 모듈마다 켜고 끄는 스위치가 있습니다. 설정값이 아직 없는 모듈은 켜진 것으로 보는 규칙이었습니다.
이 규칙은 원래 안전장치였습니다. 스위치를 처음 들일 때 쓰던 화면이 하나도 바뀌지 않게 하려고 만든 것입니다.
새 비공개 모듈에서는 이 규칙이 거꾸로 작동합니다. 설정값을 넣지 않고 배포하면 그 순간 전 직원 메뉴에 새 기능이 뜹니다.
그래서 테이블을 만드는 단계에서 '꺼짐' 값을 명시해 넣었습니다. 배포 뒤 운영 DB를 열어 꺼짐으로 들어간 것을 확인했습니다.
스위치가 있는 시스템이라면 새 모듈의 첫 값을 누가 정하는지 먼저 보세요.
막을 자리는 화면 밖에도
비공개 기간에 막아야 하는 자리를 표로 적으면 이렇습니다.
| 자리 | 막지 않으면 생기는 일 |
|---|---|
| 메뉴 | 왼쪽 메뉴에 기능 이름이 뜬다 |
| 주소 | 주소를 아는 사람이 화면을 연다 |
| API | 화면 없이 데이터만 받아 간다 |
| 알림 | 담당 밖 직원에게 새 문의 소식이 간다 |
| 패치노트 | 기능이 생긴 사실이 전 직원에게 알려진다 |
앞의 네 자리는 코드 안에 있습니다. 메뉴와 주소와 API 셋은 함수 하나가 판정하게 했고, 알림은 배정자가 있으면 배정자에게만, 없으면 채널 담당자에게만 가게 했습니다.
볼 수 있는 사람은 개발자와 지정 명단과 채널 담당자를 합친 집합입니다. 관리자라도 명단 밖이면 메뉴가 보이지 않습니다.
채널 담당자를 자동으로 넣은 데도 이유가 있습니다. 담당으로 배치했는데 메뉴가 안 보이면 그건 그것대로 고장입니다.
API는 막힐 때 없는 주소라고 답하게 했습니다(404). 권한이 없다고 답하면 거기 무언가 있다는 걸 알려 주게 됩니다.
패치노트는 코드 게이트 밖에 있습니다. 제가 놓친 곳도 이 문서였습니다.
여기서 하나가 더 걸렸습니다. 이 시스템에는 소스가 바뀌었는데 패치노트가 그대로면 배포를 막는 검사가 있습니다.
비공개 기능을 적지 말라는 지시와 이 검사가 정면으로 부딪혔습니다. 패치노트 파일에 화면이 읽지 않는 내부 기록 칸을 따로 두는 것으로 풀었습니다.
기록은 남고 검사도 통과하고 직원 화면에는 나오지 않습니다. 공개하는 날 붙일 안내 문구는 변경 기록에 미리 써 두었습니다.
외부인을 직원 명부에 넣지 않은 이유
문의하는 사람을 직원 계정 테이블에 같이 넣으면 구현은 쉽습니다. 로그인도 세션도 있는 것을 그대로 쓰면 되기 때문입니다.
저는 그 길을 택하지 않았습니다. 이 그룹웨어의 권한은 '계정이 있으면 직원'이라는 전제 위에 서 있습니다.
프로젝트 참여자 확인 같은 권한 검사가 전부 이 전제를 깔고 짜여 있습니다. 외부인이 한 명이라도 섞이면 그 검사들을 하나하나 다시 의심해야 합니다.
그래서 문의자 신원은 직원 명부 밖 별도 테이블에 두었습니다. 로그인도 따로 만들었고 브라우저에는 서버가 서명한 쿠키를 줍니다.
쿠키는 30일 동안 유지됩니다. 다시 들어올 때는 메일로 받은 1회용 링크를 쓰고, 링크는 30분이 지나면 쓸 수 없습니다.
서명 키는 기존 인증 비밀값에서 파생했습니다. 새 비밀값을 하나 늘리면 서버 설정에 빠뜨리는 사고가 따라오기 때문입니다.
외부 전용 주소로 들어오면 모든 경로가 문의 창구 화면으로 고정됩니다. 그 주소로는 그룹웨어 화면이 하나도 열리지 않습니다.
명부 대조와 초대장
처음 기획에서는 인사 명부 파일과 대조한 뒤 일회용 인증번호(OTP)를 보내려 했습니다.
이 방식은 누군가 명부를 계속 최신으로 맞춰야 굴러갑니다. 담당 부서가 파일을 올려 주지 않으면 새로 온 사람은 문의를 못 합니다.
그래서 관리자가 메일로 초대장을 보내는 방식으로 바꿨습니다. 초대 링크를 열었다는 건 그 메일함의 주인이라는 뜻이라 인증번호와 같은 확인이 됩니다.
| 항목 | 명부 대조 + 인증번호 | 관리자 초대장 |
|---|---|---|
| 명부 관리 | 담당 부서가 주기적으로 갱신 | 초대한 목록이 곧 명부 |
| 본인 확인 | 인증번호 입력 | 메일함 소유 |
| 새 사람 | 명부 갱신을 기다림 | 관리자가 바로 초대 |
| 내보내기 | 명부에서 삭제 | 차단, 익명화, 완전 삭제 |
그룹웨어에 이미 직원 초대 기능이 있어서 그 흐름을 다시 쓸 수 있었습니다. 명부 동기화라는 일거리가 통째로 사라진 것이 가장 컸습니다.
대가도 있습니다. 초대를 받아야만 들어올 수 있으니 불특정 다수가 찾아오는 창구에는 맞지 않습니다.
이 창구는 거래하는 바깥 사람들이 쓰는 곳이라 초대가 맞았습니다. 가입할 때 이름과 소속과 직급을 받고, 약관에 동의하지 않으면 넘어가지 못하게 했습니다.
내부 메모는 어디서 거르나
담당자끼리는 문의자에게 보이지 않는 메모를 남깁니다. 이 메모를 거르는 조건을 문의자용 데이터 조회 함수 안에 넣었습니다.
문의자 화면을 그리는 코드는 이미 걸러진 결과만 받습니다. 화면 쪽에서 실수해도 내부 메모가 올라올 길이 없습니다.
첨부파일 내려받기에도 같은 조건이 붙어 있습니다. 내부 메모에 붙인 파일은 문의자가 주소를 알아도 받지 못합니다.
첨부는 올리는 순간에는 어느 글에도 묶지 않습니다. 글을 쓸 때 본인이 올린 파일만 연결되니 남의 파일 번호를 알아내 붙이는 수가 통하지 않습니다.
확장자는 허용 목록으로 거르고 크기는 25MB까지 받습니다. 나중에는 파일 머리의 서명 바이트까지 대조해 실행 파일을 PDF로 위장한 경우를 막았습니다.
한 번 나간 메일은 회수할 수 없어서 메일 알림에는 본문을 싣지 않고 링크만 보냅니다.
주민번호와 카드번호는 저장 직전에
외부인이 쓰는 창에는 주민번호나 카드번호가 들어올 수 있습니다. 첫 방어 작업에서는 이 가림을 일부러 미뤘습니다.
사용자가 쓴 글을 서버가 고쳐서 저장하는 기능이라 잘못 잡으면 정상 문의가 망가집니다. 한 번 바꿔 저장하면 되돌릴 수도 없습니다.
그래서 대상을 검증식이 있는 번호로만 좁혔습니다. 주민번호는 체크섬을, 카드번호는 Luhn 검사를 통과해야 가립니다.
계좌번호는 은행마다 형식이 다르고 검증식이 없어 대상에서 뺐습니다. 넣었다면 주문번호 같은 숫자까지 별표가 됐을 겁니다.
가리는 자리는 저장 직전 한 곳입니다. 문의자 글과 담당자 답변이 모두 DB에 들어가기 직전 같은 함수를 지납니다.
그러면 담당자 화면, 메일과 메신저 알림, 답변 추천용 지식 자료 어디에도 원본이 남지 않습니다. 화면마다 따로 가렸다면 한 곳은 빠뜨렸을 겁니다.
문의자에게는 보내기 전에 경고 줄을 띄웁니다. 빼고 보낼지 그대로 보낼지 본인이 고르고, 그대로 보내면 저장할 때 일부가 가려집니다.
경고를 띄우는 판단과 실제로 가리는 판단은 같은 함수를 씁니다. 화면은 경고했는데 서버는 안 가리는 어긋남을 막으려는 것입니다.
순서에도 함정이 있었습니다. 13자리 주민번호는 카드번호 패턴(13~19자리)에도 걸리기 때문에 주민번호를 먼저 별표로 바꿔야 카드 패턴이 다시 잡지 않습니다.
체크섬 계산이 틀려도 타입 검사는 통과합니다. 그래서 배포 전에 실제 값 6건을 넣어 돌렸습니다.
| 넣은 값 | 기대한 결과 |
|---|---|
| 유효한 주민번호 (하이픈 있음·없음) | 뒤 6자리 별표 |
| 유효한 카드번호 | 앞 4자리·뒤 4자리만 남김 |
| 전화번호, 사업자번호, 무효 13자리 | 그대로 |
사진으로 찍어 올린 서류 속 번호는 가리지 못합니다. 글자를 읽어 내는 장치가 없어서 지금도 남아 있는 빈자리입니다.
배포가 됐다는 근거
배포는 새 버전을 옆에 띄워 두고 넘기는 무중단 방식입니다. 전환 전 점검 7개가 7개 모두 통과한 뒤에 넘어갔습니다.
그다음 운영 DB를 열어 문의 창구 테이블 8개가 생겼는지, 스위치 값이 꺼짐인지 직접 봤습니다.
패치노트를 지운 두 번째 배포본은 기능 이름으로 검색해 0건을 확인했습니다. 첫 배포본에서 새 기능 네 줄이 나간 것도 이렇게 열어 봐서 알 수 있는 일이었습니다.
외부 전용 주소를 여는 일은 따로 승인을 받고 진행했습니다. 앱 배포와 공용 인프라 변경은 같은 날이어도 다른 결재로 다뤘습니다.
기존 시스템 옆에 붙일 때
전화와 메신저로 흩어진 바깥 문의를 모으고 싶은데 이미 쓰는 사내 시스템이 있다면, 그 옆에 이런 창구를 붙일 수 있습니다. 바탕이 되는 직원 쪽 화면은 그룹웨어 데모에 있습니다. 직원 명부의 모양을 보고 나면 외부인을 왜 따로 두는지가 더 잘 보입니다.
새로 만들지 기존 시스템에 붙일지는 지금 쓰는 계정 구조를 보면 대개 판단이 섭니다. 로그인 방식과 직원 명부를 관리하는 곳만 웹 시스템 상담에 알려 주셔도 판단할 수 있습니다.
창구를 붙이기 전 점검표
- 외부인 계정이 직원 계정 테이블 밖에 있는가. 같은 테이블이라면 직원 전용으로 짠 권한 검사를 하나씩 다시 봐야 합니다.
- 자격을 초대로 주는가, 명부 대조로 주는가. 명부라면 그 파일을 누가 언제 맞추는지 담당자 이름까지 정해 두세요.
- 비공개 기간에 메뉴, 주소, API, 알림, 패치노트 다섯 곳을 모두 막았는가. 새 모듈 스위치의 첫 값이 꺼짐인지도 운영 DB에서 확인하세요.
- 내부 메모 차단이 데이터 조회 함수에 들어 있는가. 첨부파일 내려받기 경로도 같은 조건을 쓰는지 함께 보세요.
- 개인정보 가림이 저장 직전 한 곳에서 일어나는가. 검증식 없는 번호를 대상에 넣지 않았는지, 실제 값으로 시험했는지 확인하세요.
앞의 넷은 대개 설계 회의에서 정해집니다. 패치노트는 배포하는 날 사람이 손으로 쓰는 문서라서 저는 거기서 한 번 놓쳤습니다.
이어서 읽기

자동 분류 테스트는 다 통과했는데 실제 파일에서 틀리는 이유
직접 만든 테스트 15건이 전부 통과한 판별기가 실제 엑셀 다섯 장 중 네 장을 사람 확인으로 돌렸습니다. 본사 마감 파일 투입구를 만들며 합성 시험이 놓친 결함들과, 실제 파일에서 시험 데이터를 떠 오는 점검 절차를 기록합니다.

작은 회사 개인정보 보안, 업무 시스템에 최소한 넣어야 할 것
병가 신청서가 진단서 첨부를 강제하던 사내 그룹웨어의 방침을 다시 쓰며 정한 최소 기준입니다. 민감정보를 받을지 말지, 기록 보관 기간, 위탁 문서, 안내문과 퇴사 계정, 저장소 히스토리까지 실제 판단을 적었습니다.

매출 리포트 날짜가 하루씩 어긋날 때, 시간대 9시간 점검법
급식 납품업체 리포트의 '어제 업로드'가 90일 중 19일 틀려 있었습니다. 저장과 조회의 시간대가 9시간 어긋난 원인을 짝 대조로 판정하고, 한 달 전 규칙 문서 대신 미래 시각 감시를 붙인 과정과 점검표를 적었습니다.