현황판 · 운영 원장
상대 한 곳을 고르면 카톡·메일·주문서가 한 달력에, 수백 곳의 거래 단계가 한 화면에 보입니다
거래 상대와 나눈 이야기는 카톡방, 주문 메일함, 슬랙에 나뉘어 있고 엑셀 주문서는 메일 첨부로 따로 옵니다. 현황판은 이 기록을 하루 단위로 요약해 상대별 달력에 날짜순으로 올립니다. 브랜드·벤더사·셀러 중 한 곳을 고르면 그 상대와 오간 기록이 한 화면에 모입니다. 소통현황 탭은 수백 곳이 첫 연락부터 정산까지 어느 단계에 있는지 보여 줍니다. 규칙으로 잇지 못한 기록과 애매한 단계는 직원이 정합니다.
- 같은 기록이 다시 와도 화면은 그대로입니다. 수집기는 같은 기록을 몇 번이고 다시 보냅니다. (출처, source_ref)가 같으면 갱신하는 upsert 한 문장으로 저장합니다. 직원이 고친 행과 내용이 같은 행은 건드리지 않습니다. 내용이 같으면 트리거도 순번과 시각을 올리지 않아서, 재전송 뒤에도 화면이 그대로입니다.
- 작성자 값은 호출자가 보낸 것을 쓰지 않습니다. 인입 함수는 호출자가 보낸 작성자 값을 버리고 'ingest:출처'로 다시 만듭니다. manual 출처는 직원 전용이라 거절합니다. '직원이 고침' 표시는 앱이 아니라 트리거가 찍고, 숨긴 기록은 UPDATE로 되살릴 수 없습니다. 앱 역할에는 함수 실행 권한만 줍니다.
- 키가 엇갈리면 잇지 않습니다. 연결 순서는 스레드, 사업자번호, 카톡방, 이메일, 전화, 도메인, 거래처 코드, 별칭으로 고정했습니다. 사업자번호나 전화가 다른 근거와 다른 상대를 가리키면 충돌로 표시하고 미분류에 둡니다. gmail·naver 같은 공용 도메인 13개는 근거로 쓰지 않습니다.
- 동시 수집이 상대를 두 번 만들지 않습니다. 새 상대를 만들 때만 근거 값마다 advisory lock(트랜잭션 간 이름표 잠금)을 정렬 순서로 잡고 다시 찾습니다. 그 사이 다른 트랜잭션이 만든 상대가 있으면 그것을 씁니다. 직원의 단계 반영도 수집과 같은 잠금 순서(상대 → 제안)를 따라서 교착이 생기지 않습니다.
- LLM 출력은 원문과 맞춰 봅니다. 단계 근거 문구는 마스킹된 본문의 부분 문자열일 때만 남깁니다. 거래 조건은 더 엄격합니다. 값에 든 숫자가 하나하나 인용문에 있어야 하고, 조건 종류별 키워드와 단위도 맞아야 합니다. 회사명은 근거 줄 안에 정규화한 이름이 있을 때만 씁니다.
- 주문서 표는 열 단위로 가립니다. 주문서는 대개 표로 옵니다. '수령인·주문자' 같은 머리 열을 찾고, 칸 수가 머리 줄과 같은 줄에서만 그 열의 값을 가립니다. 그래서 상품명과 수량은 요약에 남습니다. '㈜' 같은 법인 표기 옆 이름은 회사명으로 보고 가리지 않습니다.
- 비용은 부르기 전에 예약합니다. 잔액 검사와 예약이 SQL 한 문장이라 동시 호출 둘이 함께 한도를 넘지 못합니다. 예약액은 최대 입출력 기준 추정치와 바닥값(예약액 최소치) 중 큰 쪽입니다. 정산이 실패하면 그 뒤 호출을 멈춥니다. 늦게 온 재시도 요약은 날짜 비교에 걸려 새 요약을 덮지 못합니다.
- 메일 커서는 원장이 다 받은 뒤에 옮깁니다. 메일은 로컬 큐에 먼저 넣고 원장으로 보냅니다. Gmail history 커서는 그 회차 전달이 모두 성공해야 옮깁니다. 커서가 만료되면 마지막 성공 시각부터 목록으로 다시 채웁니다. 두 번 실패한 메일은 격리하고 경보를 냅니다.