승인 버튼을 만드는 것보다 먼저 정할 것이 있었다. 누가 어느 내용을 확인한 것인지다. 같은 주문 번호를 쓰더라도 수량이 바뀌었다면 확인의 대상은 달라진다.
나는 기존 수정본 확인 예제에서 더 들어가 승인 사건을 로컬 데이터베이스에 남기는 독립 합성 실험을 만들었다. 실제 회사의 결재 기록이나 계정은 사용하지 않았다.
문서 번호만으로는 승인 대상을 설명할 수 없었다
주문 S01을 승인했다고만 남기면 그 뒤 수량이 바뀌었을 때 처음 무엇을 확인했는지 알기 어렵다. 현재 화면의 값을 다시 읽어서 과거 승인 내용을 설명하면 승인 당시의 판단이 바뀐 문서를 따라가 버린다. 그래서 이번 실험에서는 문서 식별자와 별도로 내용 버전을 두었다. 승인 대상에는 그 내용 버전을 명시한다.
한편 상태를 승인 대기로 바꾸거나 승인 결과를 저장하는 작업도 동시 수정 검사가 필요하다. 나는 모든 저장 변화에 올라가는 version과 내용이 바뀔 때 올라가는 content_revision을 나눴다. 두 번호는 목적이 다르다. 승인 버튼을 눌렀다는 이유로 승인 대상인 수량의 버전까지 바뀌게 만들면 어떤 내용을 승인했는지 다시 해석해야 하기 때문이다.
신청과 승인 사이에 들어오는 수정
처음 수량은 합성 값 6개, 내용 버전은 0이다. 제출하면 승인 회차가 생기고 그 회차의 target_revision은 0을 가리킨다. 다른 담당자가 승인하면 승인한 사람과 사유가 같은 회차에 남는다. 이 과정에서 저장 버전은 올라가지만 수량을 고치지 않았으므로 내용 버전은 그대로다. 현재 문서와 승인 대상의 관계를 숫자로 대조할 수 있다.
승인 뒤 수량을 7개로 고치면 내용 버전은 1로 올라가고 문서는 초안으로 돌아간다. 과거 승인 기록을 지우지는 않는다. 실행을 시도할 때는 현재 상태와 최신 승인, 승인 대상 버전이 함께 맞아야 한다. 이전 버전의 승인이 있다는 이유로 새 수량을 실행하지 않는 경계다. 공개 실험의 실행은 로컬 상태 표시일 뿐 실제 발주나 전송은 없다.
사람을 고르는 UI와 신뢰할 승인자는 다르다
예제의 직원과 담당자는 고정 합성 주체다. 서버가 인증한 문맥을 받는다는 전제만 있고 로그인 서비스는 만들지 않았다. 사용자가 브라우저에서 대표나 담당자라고 고른 값을 실제 승인자로 받아들이면 이 규칙은 보호 장치가 되지 않는다. 승인자를 확인하는 일은 실제 서비스의 서버 경계에 있어야 한다.
이번 정책은 신청자와 승인자가 같으면 거절한다. 대표는 현황을 읽는 역할이며 승인 권한을 자동으로 갖지 않는다. 다른 회사의 문서도 보거나 고칠 수 없다. 이 선택을 모든 조직의 정답으로 주장하지 않는다. 자기 승인 허용 여부, 금액에 따른 단계, 대리 승인과 부재중 처리는 회사 업무를 듣고 별도로 정해야 할 정책이다.
문서와 승인 기록이 함께 확정되는지 확인했다
문서만 승인됨으로 바뀌고 승인 기록이 저장되지 않으면 누가 확인했는지 사라진다. 이번 코드는 로컬 SQLite 쓰기 트랜잭션 안에서 문서, 승인 회차, 변경 사건, 요청 결과와 후속 알림 대기 기록을 처리한다. 중간에 합성 오류를 넣으면 어느 일부만 남지 않고 함께 되돌아가는지 검사했다. 상태 이름만 바꾸는 화면 예제에서 한 단계 들어간 부분이다.
이 실험의 쓰기 잠금은 로컬 SQLite의 조건이다. 여러 지역의 서버와 외부 발송 시스템까지 한 번에 확정한다는 뜻은 아니다. 외부 작업은 트랜잭션 밖에서 별도의 결과 확인이 필요하다. 기록을 같은 곳에 남겼다는 사실과 외부 실행이 끝났다는 사실을 나눠야 승인 완료라는 말을 정확하게 쓸 수 있다.
회사에 적용할 때 문장으로 먼저 확인할 것
어떤 필드가 바뀌면 재승인이 필요한지, 누가 신청하고 승인하는지, 승인 뒤 어느 행동을 허용할지부터 적어 보는 편이 좋다. 모든 수정을 동일하게 취급할 필요는 없지만 예외를 프로그램이 추측하게 둘 수는 없다. 수량·금액·납기 변경의 영향이 다르다면 그 차이를 버전과 승인 정책에 드러내야 한다.
공유 패키지는 승인 대상 일치, 자기 승인 거절, 수정 뒤 실행 차단, 반려와 재제출을 독립 테스트로 확인한다. 기록 뷰어는 실제 로컬 실행에서 나온 결과를 보여 주며 브라우저에서 SQLite를 실행하지 않는다. 운영 회사의 결재나 실브라우저 검수를 마쳤다는 결과도 아니다. 나는 적용 조건과 검증 범위를 함께 공개하는 방식으로 이 제작기를 남긴다.