승인됨이라는 표시가 뜨면 업무가 끝났다고 생각하기 쉽다. 그러나 누군가 내용을 확인한 일과 실제로 발주·발송한 일은 서로 다른 사건이다.

나는 승인 상태 다음에 실행이라는 별도 단계를 둔 합성 SQLite 실험을 만들었다. 실제 외부 시스템에 연결하지 않고도 어떤 사실이 확인됐고 무엇이 아직 남았는지 설명하려는 선택이었다.

승인은 실행할 수 있는 조건이다

예제에서 승인된 문서는 approved로 남고 바로 executed가 되지 않는다. 승인자는 현재 내용 버전을 확인했다는 사실을 남긴 것이다. 다음 담당자가 실행 명령을 보낼 때 그 승인 대상과 현재 내용이 다시 맞아야 한다. 수량이 바뀌어 초안으로 돌아가면 이전 승인을 실행의 근거로 쓰지 않는다.

실행 권한도 읽기나 승인과 다른 선택이다. 이번 정책은 담당자에게 합성 실행을 허용하고 대표는 읽기만 한다. 승인자가 실행자와 같아도 되는지까지 회사마다 다르게 정할 수 있다. 이 코드는 그 전체 결재 정책을 대신하지 않는다. 먼저 어떤 확인 뒤 어떤 행동을 허용할지 나누는 방법을 보여 주는 예제다.

실행이라는 이름의 범위를 좁혀 적었다

패키지의 execute 행동은 DB 안의 상태를 executed로 바꾼다. 파일을 전송하거나 외부 문서를 발급하지 않는다. 따라서 이 값을 실제 거래처가 받았다는 증거로 설명하지 않는다. 화면이나 문서에서 같은 동사를 사용하더라도 어디까지 작동하는지 분명히 적어야 한다고 판단했다.

실제 시스템에서는 요청 생성, 발송 시도, 상대 시스템의 접수, 최종 완료가 여러 단계일 수 있다. 응답을 못 받았다고 무조건 실패로 단정해서도 안 된다. 이번 실험은 그 바깥 결과를 만들어내지 않고 승인 이후에도 독립적인 실행 기록이 필요하다는 경계를 구현했다. 좋은 시연이 아직 없는 기능을 대신 증명하게 두지 않았다.

문서 변경과 후속 작업의 예약을 함께 남긴다

성공한 전환마다 변경 사건과 알림 대기 행을 같은 트랜잭션에서 만든다. 이것은 알림을 실제로 보냈다는 뜻이 아니라 다음 작업이 필요하다는 기록이다. 문서만 바뀌고 후속 작업의 존재를 잃는 틈을 줄이기 위해서다. 실제 외부 통신을 긴 DB 트랜잭션 안에서 기다리는 구현은 넣지 않았다.

대기 기록의 유일한 사건과 대상 조합은 같은 성공 사건이 중복 대기 행을 만들지 않게 한다. 하지만 외부 전달자의 동작까지 한 번이라고 보장하지는 않는다. 전달 실패나 미확인은 별도의 결과로 남고 현재 문서와 독립적으로 읽힌다. 예약된 일과 끝난 일을 분리해야 대표도 미처리 업무를 이해할 수 있다.

중간 실패를 어느 완료로 읽을 것인가

승인 처리 중 DB 오류가 나면 승인됨과 사건·요청 결과가 함께 되돌아가야 한다. 반면 문서와 후속 대기 기록이 이미 확정된 뒤 알림이 실패한 경우에는 승인 자체를 다시 실행할 이유가 없다. 두 실패는 발생한 경계가 다르다. 모든 문제를 처음 버튼부터 다시 누르는 방식으로 처리하면 중복 업무가 생길 수 있다.

독립 테스트는 강제 오류의 전체 되돌림과 전달 실패 뒤 문서 사건이 추가되지 않는 상황을 따로 확인한다. 로컬 저장의 실패와 저장 후 후속 작업의 실패를 다른 결과로 다룬 것이다. 운영 시스템에서는 실제 제공자의 접수 기록과 조회 기능, 재시도 정책이 필요하다. 이번 패키지의 합성 전달 결과가 그 구현을 대신하지는 않는다.

대표 화면에는 다음 확인을 남긴다

실행 전의 승인 문서는 처리 가능하거나 실행 대기인 상태로 읽어야 한다. 승인 표시 하나로 납품이나 수금까지 끝났다고 해석하게 만들고 싶지 않았다. 기존 체험에서 준비·발송·납품·수금을 나눴던 원칙을 승인 뒤에도 이어 간 것이다. 업무마다 확인된 사건과 다음 사람의 행동을 연결하면 단순한 상태표보다 읽을 근거가 생긴다.

공유 기록에서 승인 직후 상태와 실행 표시가 생긴 뒤 상태를 비교할 수 있다. 테스트도 두 단계가 구별되는지 확인한다. 실제 업체 정보나 외부 메시지는 없으며 실브라우저 검수를 수행하지 않았다. 나는 새 프로그램을 도입하려는 사람이 완료라는 단어 뒤에 무엇이 남는지 질문할 수 있게 이 제작 판단과 적용 경계를 함께 공개한다.