납기 20영업일·공휴일 · 차량 도착 예정일 · 특장 착수 · PDI 체크리스트 · 영문화 게이트 - #385
Merged
Conversation
added 6 commits
September 10, 2026 17:26
`t()` 는 사전에 없으면 한국어를 그대로 돌려준다. 화면이 깨지지 않으니
눈으로는 못 잡고, 영어로 보는 사람에게만 한국어가 나간다. 검사를 붙이니
이미 **19개**가 그렇게 배포돼 있었다 — MyPage 「계정」·「언어」,
Header 「일반」, SalesPage 「지연」, 어제 넣은 대화 탭 증빙 버튼까지.
지시(2026-09-10): 앞으로 모든 수정 배포는 영문화를 검사한 뒤 진행한다.
사람이 매번 보는 규칙은 이미 한 번 실패했으므로 검사로 못 박는다.
· t()·tc() 원문이 EN 에 있는가
· tf() 틀이 EN_FMT 에 있는가
뒤지다 나온 것 둘도 함께 고쳤다.
· 「숨긴 고객 {0}명」이 EN 쪽에 있었다. tf() 는 EN_FMT 만 보므로
번역이 사전에 있는데도 한국어가 나가고 있었다.
· 자리표시자가 `{-1}` 인 항목 88개. tf() 가 채우는 규칙은 `{0}`·`{1}` 이라
채워지지도 찾아지지도 않는 죽은 항목이다. 걷어내고, 다시 생기면
걸리도록 검사를 하나 더 뒀다.
「한국어」 라벨은 t() 를 벗겼다 — 언어 이름은 그 언어로 적는 자리라
옮길 대상이 아니다(옆의 English 와 같은 취급).
검사 3개. 넷을 되돌려 각각 걸리는 것을 확인했다 — 사전 없는 새 문구,
tf 틀을 EN 에 잘못 넣기, {-1} 항목 부활, 정규식이 눈머는 경우.
영어로 켠 화면을 DOM 으로 훑어 라벨에 남은 한국어가 없는 것도 확인했다
(남은 것은 고객명·특장사명 — 데이터라 한국어가 맞다).
주말만 빼고 세다 보니 연휴가 낀 달에 고를 수 있는 날짜가 실제보다 적었다.
추석(9/24~26)을 앞두고 납기를 찍지 못하는 일이 생겼다(제보).
**한도 15 → 20 영업일.** 기산점은 예전과 같은 **배정일**이다(수락일이 아니다) —
수락이 늦으면 남는 제작 기간이 그만큼 줄어든다.
· 이미 납기를 찍은 건(수락 완료) → 15일 그대로. 발주서에 「15일 이내」가
문서로 찍혀 나갔으므로 소급해 고치지 않는다.
· 아직 수락 안 된 배정 → 20일 창을 연다. 연휴에 막혀 있던 건들이 이 대상이다.
그래서 한도를 **주문에 얼려 둔다**(`order.due_limit_days`). 상수 하나로 두면
다음에 또 바꿀 때 이미 나간 서류가 같이 바뀐다.
## 공휴일
`holiday` 표를 새로 만들고 영업일 계산에 **주입**한다. 코드에 박으면 임시공휴일
하나에 배포를 해야 한다. 서버는 DB 에서, 화면은 `GET /holidays` 에서 같은 목록을
받아 같은 함수(shared/schedule)에 물린다 — 어긋나면 「고를 수 있는데 저장이
거부되는」 예전 사고가 다시 난다.
⚠️ 무료 공개 API 두 곳(nager.at · holidays.hyunbin.page)을 대조해 보니 **둘 다**
제헌절(7/17)을 공휴일로 넣고 있었다. 2008년에 빠진 날이다. 그래서 불러온 값을
그대로 쓰지 않고, 확인한 2026년 값을 migration 으로 넣었다. 자동 조회는
관리자 화면에서 **초안**으로만 쓸 것이다(다음 PR).
받아오지 못해도 멈추지 않는다 — 달력이 비면 주말만 빼는 예전 계산이 되고,
한도가 짧게 나온다. 한도는 넘기면 안 되는 쪽이라 안전한 방향이다.
## 달력 화면
연휴는 회색으로 가라앉히지 않고 **이름을 적는다.** 「왜 이 날은 못 고르지」가
남으면 전화가 온다 — 추석이라 못 고르는 것과 한도를 넘어 못 고르는 것은 다른
이야기다.
달력이 늦게 도착하면 격자를 **다시 센다.** 처음엔 한 번 그리고 말아서, 10/14
까지여야 할 달력이 10/10 에서 끊겨 있었다(브라우저에서 잡았다).
검사: shared 8개 · 실제 API 6개. 넷을 되돌려 각각 걸리는 것을 확인했다.
db:drift 일치(테이블 40 · 컬럼 317).
## 차량 도착 예정일 관리자가 특장사에게 **차가 언제 가는지** 알려 주는 날짜다. 특장사가 완료 처리하는 「차량 도착」 단계와 다르다 — 이건 예정이고, 아는 사람은 차를 보내는 쪽이다. 단계가 아니라 **주문에** 둔다(`order.car_arrival_planned_at`). 단계에 매달면 수락 전에는 쓸 자리가 없는데, 배정 직후에 정해질 수도 제작 중에 바뀔 수도 있어야 한다. 상태로 막지 않는다. 바뀌면 **다시 알린다.** 현장은 이 날짜에 맞춰 사람을 뺀다 — 조용히 바뀌면 그날 아무도 없는 공장에 차가 간다. 무엇에서 무엇으로 바뀌었는지는 그 단계 대화에 남긴다. 표를 새로 만들지 않은 이유는, 특장사가 이미 보고 있는 자리가 거기이기 때문이다. 알림은 배정된 특장사에게만 간다. 같은 날짜를 다시 보내면 알리지 않는다 — 안 바뀐 것은 소식이 아니다. ## 특장 제작 착수 완료 하나만 두면 「받아는 놨는데 손도 안 댔다」와 「만들고 있다」가 구분되지 않는다. 납기가 다가올 때 물어봐야 하는 것이 바로 그 차이다. 착수에는 **증빙을 두지 않는다.** 시작했다는 것을 사진으로 증명하라고 하면 누르는 것 자체가 미뤄지고, 그러면 이 단계를 만든 이유가 사라진다.⚠️ 진행 중인 주문이 모순 상태가 되지 않게 기존 행을 채웠다. 새 단계가 완료의 선행조건이라, 이미 제작 완료인 주문에 착수가 비어 있으면 「완료됐는데 착수는 안 함」이 된다. 이미 완료한 건은 실제로 착수도 했으므로 같은 시각·같은 사람으로 채우고, 아직 전인 건에는 빈 칸을 깔아 둔다. 반영 뒤 모순 0건 확인. 장착은 여전히 **완료**를 기다린다 — 착수만으로는 못 단다. 검사 7 + 3개. 다섯을 되돌려 각각 걸리는 것을 확인했다. 브라우저에서 관리자가 찍고 특장사가 보는 것까지 확인했다(특장사에게는 고치는 자리가 없다). db:drift 일치(테이블 40 · 컬럼 320).
차량 도착 · 특장 제작 완료 · 인도 세 단계에 체크리스트를 붙인다. 앞의 둘은 특장사가, 인도는 넘겨받는 관리자가 적는다. ## 규칙은 코드, 서식은 데이터 무엇을 확인하는지는 관리자가 화면에서 고친다(관리자 > 체크리스트 탭). 어느 단계에 붙는지·누가 적는지·「채워야 넘어간다」는 shared 카탈로그에 둔다 — 규칙까지 데이터로 내리면 검증할 곳이 흩어진다.⚠️ 서식을 고쳐도 **이미 작성한 체크리스트는 바뀌지 않는다.** 작성을 시작할 때 그 시점의 항목을 주문에 사본으로 얼린다. 발주서 단가와 같은 원칙 — 3개월 전에 합격 처리한 항목의 뜻이 소급해서 바뀌면 근거가 되지 못한다.⚠️ 서식이 **비어 있으면 막지 않는다.** 항목을 아직 안 정한 단계에서 완료가 막히면 진행 중인 주문이 통째로 선다. 체크리스트는 있을 때만 관문이다. ## 불합격은 끝이 아니다 합격이 아닌 항목이 하나라도 있으면 그 단계를 완료할 수 없다. 불합격을 놔두고 넘어갈 수 있으면 체크리스트는 형식이 된다. 대신 고쳐서 **재검으로 합격**을 주면 열리고, 그 과정이 항목별 이력으로 남는다. 결과 칸 하나만 두면 마지막 판정만 남아 「한 번에 통과」와 「고쳐서 통과」가 같아진다 — 무엇이 왜 걸렸었는지가 다음 차를 만들 때 쓰인다. 제출한 뒤에 불합격이 생기면 제출이 거둬진다. 「제출됨」인데 안에 불합격이 있는 상태가 남으면 관문이 무엇을 보는지 흐려진다. ## 그 밖에 · 제출하면 앱 알림을 켠 관리자에게 알린다. 알림은 켜고 끄는 것 하나만 본다 — 무슨 알림인지로 가르지 않는다(지시: 2026-09-10). · 서식에서 「지운」 항목은 **꺼질 뿐** 사라지지 않는다. 그 항목으로 합격 처리한 옛 체크리스트가 무엇을 봤는지 되짚을 수 있어야 한다. · 서식을 고치는 권한은 새 기능모듈 `checklist.manage` — 기본은 꺼 두고 계정별로 켠다. 검사 9개. 일곱을 되돌려 각각 걸리는 것을 확인했다 — 관문 제거, 빈 서식에도 체크리스트 생성, 이력 미기록, 지운 항목 실제 삭제, 적는 사람 미검증, 알림 미발송, 불합격에도 제출 유지. 브라우저에서 서식 작성 → 특장사 화면 관문 → 모두 합격 → 제출 열림까지 확인했다. db:drift 일치(테이블 44 · 컬럼 350).
`npx tsc --noEmit` 은 통과하는데 배포의 `npm run build`(clean tsc)가 `unknown` 을 supertest 의 `send()` 에 넘긴 것을 잡았다. 검사 파일도 빌드 대상이라, 여기서 나는 타입 오류는 배포를 멈춘다.
손으로 적은 제약 이름(`order_checklist_order_fkey`)이 Prisma 가 짓는 이름(`order_checklist_order_id_fkey`)과 달라 migration 검증이 어긋났다. maker_price 때와 같은 실수다 — 이름은 `<표>_<컬럼>_fkey` 다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #380
Closes #382
Closes #384
한 번에 배포하기로 해 네 건을 한 PR 로 모았습니다(#381 · #383 은 여기로 합치고 닫았습니다). 커밋은 주제별로 나뉘어 있습니다 — 커밋 단위로 보시는 편이 읽기 쉽습니다.
1. 영문화 — 사전에 없는 문구를 CI 가 막는다 (
57e0bd7)t()는 사전에 없으면 한국어를 그대로 돌려준다. 화면이 안 깨지니 눈으로는 못 잡고, 영어로 보는 사람에게만 한국어가 나간다. 검사를 붙이니 이미 19개가 새고 있었다.지시대로 「배포 전에 잘 보자」가 아니라 검사로 못 박았다. 이번 PR 에서 새로 쓴 문구들도 실제로 이 검사에 걸려 채웠다.
곁들여:
숨긴 고객 {0}명이EN쪽에 있어(tf 는EN_FMT만 본다) 번역이 있는데도 한국어가 나가고 있었고, 자리표시자가{-1}인 죽은 항목이 88개 있었다.2. 납기 20영업일 + 공휴일 (
885d5c8)기산점은 바뀌지 않는다. 예전부터
assigned_at(배정을 누른 순간)부터 셌다 — 수락하며 새 창이 열리는 것이 아니라, 수락이 늦으면 제작 기간이 줄어든다.한도를 주문에 얼린다(
order.due_limit_days). 공휴일은holiday표에서 읽어 shared 계산에 주입한다 — 서버와 화면이 같은 목록을 봐야 「고를 수 있는데 저장이 거부」가 안 난다.3. 차량 도착 예정일 (
a04e6c3)관리자가 찍고 특장사는 본다. 단계가 아니라 주문에 둔다 — 단계에 매달면 수락 전에 쓸 자리가 없다. 상태로 막지 않는다.
바뀌면 다시 알린다. 현장은 이 날짜에 맞춰 사람을 뺀다. 무엇에서 무엇으로 바뀌었는지는 그 단계 대화에 남긴다(특장사가 이미 보고 있는 자리다). 같은 날짜를 다시 보내면 알리지 않는다.
4. 특장 제작 착수 (
a04e6c3)「받아는 놨는데 손도 안 댔다」와 「만들고 있다」를 가른다. 착수에는 증빙을 두지 않는다 — 시작을 사진으로 증명하라고 하면 누르는 것 자체가 미뤄진다.
5. PDI 체크리스트 (
24060b4)차량 도착 · 특장 제작 완료(특장사) · 인도(관리자) 셋에 붙는다.
checklist.manage— 기본 꺼짐, 계정별로 켠다.검증
검사 702(백엔드) + 316(shared) 통과 · 프론트 클린 빌드 ·
db:drift일치(테이블 44 · 컬럼 350).되돌려 걸리는 것을 확인한 변이 20개:
{-1}부활 / 정규식 눈멀기브라우저로 확인한 것: 납기 달력에 추석·개천절·한글날이 이름과 함께 뜨고 고를 수 있는 날이 정확히 20칸 · 관리자가 도착 예정일을 찍고 특장사가 읽기 전용으로 보는 것 · 서식 작성 → 특장사 관문 → 모두 합격 → 제출 열림.
스키마
추가만 했다. 새 표
holiday·checklist_item·order_checklist·order_checklist_line·order_checklist_line_log, 새 컬럼order.due_limit_days·order.car_arrival_planned_at(+set_by/at). 기존 표·컬럼은 건드리지 않았다.데이터 채우기 셋(모두 migration 안에서, 전체 seed 를 돌리지 않는다):
due_limit_days— 수락 완료 15 / 미수락 20ON CONFLICT DO NOTHING)build_started행 — 이미 완료된 건은 done 으로