Commit Graph
821 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 23b1e7e5b0 feat(B05/B06): 옛 계획고 유토곡선 노출 차단 + 사면 미교차 측점 경고
① 저장된 횡단이 지금 계획선과 어긋나면(재계산 예약 상태) 유토곡선을 그리지 않고
「횡단을 지금 계획선에 맞춰 다시 계산하는 중입니다」만 띄움. 옛 계획고로 만든 면적이
2초간 보였다가 정본으로 갈아 끼워지던 것을 없앰(2026-09-03 사용자 확정 「새 값만
보여주기」). 용화 실측 — 65측점 중 56개가 낡음, 계획고 차 −9.36~+5.83m,
저장분 성토 42,050㎥ ↔ 정본 14,881㎥.

② 사면이 계산 반폭 끝까지 원지반과 만나지 않아 면적이 잘린 측점에 카드 경고 표기.
판정은 면적을 내는 엔진 한 곳(B06_Section_Engine_Design)에서 `slope_unclosed` 로
내려 화면·수량·도면이 같은 기준을 봄. 계산은 손대지 않음(2026-09-03 사용자 확정
「영원히 못 만나는 지형이 있을 수 있으니 경고로 대체」).

검증 — 공용 브라우저 B06 실측: 2.6초 재계산 안내만 표시(옛 값 미노출), 4.4초 정본
표시, 사면 미교차 경고 13/65측점. pytest 366 passed·17 skipped, typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 09:10:46 +09:00
eomsangdonandClaude Opus 5 698f8f0505 knowledge(임도): 유토곡선 토량배분 기술문서 신설 + 미결 20·21 등재
실무 유토곡선 원본 6건(.MASS · EARTH.DAT) 파싱 관측 수록 — 최종 누가토량 +49~+324㎥,
0선 교차 3~17회, 장비 한계거리 전 건 무대 20.0 / 도자 60.0 m. 평형선 자동 선정·극값
무시 임계·balloon 표기 관행은 현행 근거 공백임을 명시하고 미결 20 으로 등재. 도자
한계거리 60m(실무) vs 70m(현행 구현) 채택은 미결 21.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 07:53:32 +09:00
eomsangdonandClaude Opus 5 0e0dd74e92 feat(B05/B06): 유토곡선 요약줄에 최종 누가토량 칩 신설
평형선·장비 띠·물량 balloon 이 안 생기는 노선에서 그 이유를 화면에서 읽을 수 있게,
곡선 끝의 누가토량을 요약 칩으로 드러냄. 0에 가까울수록 절·성토 균형이며 곡선이
0선을 넘지 않으면 평형선이 서지 않는다는 설명을 툴팁에 담음. 판정·조정은 사용자
몫이라 자동 보정 로직은 두지 않음(2026-09-03 사용자 확정).

B05 종단 패널과 B06 횡단 화면이 같은 함수를 쓰므로 양쪽에 함께 반영됨.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 07:53:32 +09:00
eomsangdonandClaude Opus 5 8daadf2d4f fix(B06): I형 집수정 배관 끝단이 마감면에 접혀 삼각형이 되던 결함 수정
관 끝단 두 꼭짓점을 마감면(I형 벽 안쪽 변) 선분 안으로 자를 때, 원지반이 벽 상단
위라 관 시작점이 벽 상단에 붙으면 위·아래 교점이 같은 끝점으로 접혀 관 단면이
삼각형으로 그려짐. 비스듬히 자른 끝단 길이는 항상 관경 이상이므로, 그보다 짧으면
접힌 것으로 보고 축 직각 마감으로 되돌림.

검증 — 공용 브라우저 B06 단면 8개 실측: 유입측 끝단 길이 0.0px → 18.7~58.4px.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 07:19:32 +09:00
eomsangdonandClaude Opus 5 e065e5701e fix(B05): 최소고 가드를 편집 단일 창구로 이관 + 되돌리기가 구조물 위치까지 복원
2026-09-02 화면 검증에서 나온 미해결 2건 처리.

- 최소고 가드: `blocksMinCover` 가 `_Profile_Render` 측점 끌기 한 곳에만 있어
  [직선화]·[쉬프트]·틸팅·방향키가 그냥 지나감. 판정 로직을
  `_Profile_MinCover.blocksMinCover()` 로 옮기고 모든 편집이 지나는
  `_Profile_Panel.applyEdits` 한 곳에서만 호출. 화면 모듈의 사본·죽은 배선
  (`enforceMinCover` ctx 필드, 미사용 import)은 제거.
- 되돌리기 범위: 이력이 `b05:`·`b05-`·`b06:`·`b06-` 세션 키만 스냅샷하는데
  구조물(관) 위치는 세션 밖이라 undo 가 계획선만 되돌림. `_Profile_Panel_Tools`
  가 기록 직전에 관 목록을 `b05:pipes` 로 흘리고 복원 뒤 되읽어 반영.
  사용자 확정 ⑥ 「범위는 B05 페이지 조작 전부」 충족.

검증(공용 브라우저, 용화 검증 프로젝트 route_id 126):
- 최소고 강제 켠 상태로 관 측점 264.060 방향키 ↓ → 편집 미적용 + 경고
  "배수관 Ø800 — 최소 계획고(지반 +1.3m) 아래로 내려갈 수 없습니다."
- 구조물 측점 264.060 → 263.960 이동 후 ↶ 1회 → 264.060 복귀,
  `b05:pipes` 목록도 264.06 으로 복귀.
- `tsc --noEmit` 0, prettier 통과, pytest 366 passed / 17 skipped / 0 failed.
- 파일 줄수: Panel 699 · Panel_Tools 197 · Render 350 · MinCover 188 (700줄 제한 준수).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 20:34:18 +09:00
eomsangdon 73a77a1376 Merge remote-tracking branch 'origin/sub_desktop_1' into main_desktop_1 2026-09-02 19:32:16 +09:00
eomsangdonandClaude Opus 5 3651ad9875 feat(B05): 종단 계획선 전체 측점 폴리라인 전환 + 직선화·쉬프트·undo/redo 신설
2026-09-02 사용자 지시 9건 반영. 화면 실조작 검증은 다음 세션 몫 (사용자 지시로
코딩까지만 진행).

1. 초기 계획선 = 전체 측점 폴리라인 — `design_ground_following_profile()` 신설.
   모든 측점을 변화점으로 잡고 계획고 = 원지반고, 라운드는 R을 지정한 자리에만
   (`build_curves(only_explicit=)`·`build_alignment(only_explicit_curves=)`).
   basis `ground_polyline`. 관 정착 선형은 폴백으로 내림.
2. 구간 쉬프트(⬆⬇) 삭제.
3. [직선화] 신설 — `B05_Profile_UI_Profile_Straighten.ts`. 두 측점의 라운드에 탄젠트한
   직선으로 대체하고 사이 라운드 삭제. 직선 틸팅 시 가운데 라운드 + 양측 탄젠트 재구성.
4. [쉬프트] 신설 — 직선 구간을 기하에서 되읽어(`detectStraightRun`) 복수 선택,
   최외곽 라운드 중심 기준 상·하 평행이동.
5. 방향키 조작 — 상하 0.1m 계획고, 좌우 0.1m 누가거리(구조물·비정규 측점 한정).
6. undo/redo 신설 — B05·B06 조작 세션 키 묶음 스냅샷(`_Profile_History.ts`).
   버튼은 요약줄 맨 앞(최대 기울기 좌측), 21x17px. Ctrl+Z / Ctrl+Shift+Z.
7. 종단 요약줄의 횡단배수 최소고 표시 삭제(산식·편집 차단은 유지).
8. [편집 되돌리기] 버튼 삭제 — undo/redo로 대체.
9. 지형 구분 기본값 특수지형 — 패널 셀렉트와 백엔드 기본값(스키마·체인 폴백) 일치.

700줄 제한 — 패널을 `_Profile_Panel_Tools` · `_Profile_Preview` 로 분리하고 측점↔구조물
짝짓기를 `_Profile_Structures` 로 이관(842줄 → 696줄).

검증: tsc --noEmit 오류 0, ruff format/check 통과,
pytest tmp/tests/ -q → 366 passed / 14 skipped / 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:30:16 +09:00
eomsangdon 5e51343f16 Merge remote-tracking branch 'origin/sub_laptop_1' into sub_desktop_1 2026-09-02 19:25:15 +09:00
eomsangdonandClaude Opus 5 ac983cf0e1 feat(B02): 등록 폼에 표제란 8칸 반영
사용자 지시(2026-09-02) — 프로젝트 등록에서도 수정 모달과 같은 항목 수신.

- 시행청·연도기번·사업량·설계일자·과업책임자·분야별책임자·설계자·회사 로고 8칸 추가.
  담당자는 select + 「신규 등록…」(관리자만), 로고는 회사 대표 로고가 기본값
- 담당자·자산 회사 경계 검사를 check_project_refs(company_id, data) 로 옮겨 B01 수정과 공용
- GET /admin/members 문턱을 require_company 로 — 일반 사용자도 담당자 선택 필요.
  _scope_company 가 남의 회사를 막고 쓰기는 관리자 그대로
- fix: road_type 스키마가 옛 값(branch·stream)을 받고 화면 선택지 work 를 막아
  「작업임도」 등록이 422 로 떨어지던 것 수정 — ^(main|fire|work)$
- 검증(5174 실조작): 등록 칸 14개로 수정 모달과 동일, 등록된 행에 8칸 그대로 저장
  (road_type=work, logo_asset_id=1, designer=3), 해당 프로젝트 표제란 12칸 전부 채워짐.
  pytest 151 passed (신규 test_b02_register_schema.py 8건)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:21:27 +09:00
eomsangdonandClaude Opus 5 3d0215f8d8 feat(B07): 표지에 회사 로고 자리 신설
- `00_template_cover.json` 에 Image 자리 추가 — `{{회사로고}}`,
  x 57.40~137.40 · y 64.06~104.06 (폭 80 · 높이 40)
- 자리는 오른쪽 아래 `{{시행청}}`(기준점 784.35, 84.06)과 좌우로 마주 보게 잡음.
  왼쪽 여백은 `{{연도기번}}`(x 57.4)과 맞추고 세로는 시행청 글자줄에 맞춤
- 값 공급은 도각과 같은 통로 — `build_cover_drawing` 이 이미 `_fill_placeholders` 를
  태우므로 로고를 못 구하면 종전대로 엔티티째 빠짐

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:19:57 +09:00
eomsangdonandClaude Opus 5 6e0c77d811 docs(B07): 94883733 내용 설명 — 도각 표제란 서명 자리 2개 신설
`94883733` 이 자동 폴백 커밋(`auto: …`)으로 묶여 나가 내용 설명이 빠짐. 이력 재작성
금지(CLAUDE.md 6장)라 amend 대신 이 빈 커밋으로 남김. 그 커밋의 실제 변경:

- `resources/template_2dDrawing/00_template_A1.json` — Image 자리 2개 추가.
  `{{과업책임자서명}}`(x 536.89~578.89) · `{{분야별책임자서명}}`(x 587.91~629.91),
  둘 다 y 17.5~25.5. 설계자 서명과 같은 폭 42·높이 8이고, 표제란 세로선
  (531.87 / 583.91 / 633.91) 이 만드는 칸 안에서 좌우 여백 4로 가운데 배치.
- `B07_DesignDetail_Router.py` `_title_block_fields` — 두 자리 값을
  `pm_user_id`·`field_lead_user_id` 계정의 `company_assets` SIGNATURE 자산에서 읽음
  (설계자와 같은 최신 1건 서브쿼리). 서명을 안 올린 사람 자리는 종전대로 엔티티째 빠짐.

자체검증: `frame-template` 응답이 Image 4건(회사로고+서명 3)으로 자리·좌표 확인,
`tmp/tests/test_b07_title_block_signatures.py` 3건 신설, `pytest tmp/tests/ -q` 15 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:09:43 +09:00
eomsangdon 94883733d5 auto: 2026-09-02 19:08 (EOMSANGDON-HOME) 2026-09-02 19:08:55 +09:00
eomsangdon f0dd4b08ef Merge remote-tracking branch 'origin/sub_desktop_1' into sub_laptop_1 2026-09-02 19:02:52 +09:00
eomsangdon aff882c2a0 Merge remote-tracking branch 'origin/main_desktop_1' into sub_laptop_1 2026-09-02 19:02:51 +09:00
eomsangdonandClaude Opus 5 dde40101bb fix(B07): 표제란 로고·서명 원천을 계정·회사 자산으로 이관
- 서명: `projects.signature_asset_id` 대신 설계자(`designer_user_id`, 없으면 소유자)
  계정의 `company_assets` SIGNATURE 자산을 따라감 (여러 벌이면 최신 1건)
- 로고: 프로젝트가 고른 것 우선, 없으면 `companies.logo_asset_id` (014) 로 폴백
- `projects.signature_asset_id` 는 컬럼만 남기고 더 읽지 않음 — B01 이 항상 null 저장

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:01:56 +09:00
eomsangdon a91262f110 Merge remote-tracking branch 'origin/sub_laptop_1' into sub_desktop_1 2026-09-02 18:57:57 +09:00
eomsangdon 85a478dd8a Merge remote-tracking branch 'origin/main_desktop_1' into sub_desktop_1 2026-09-02 18:57:56 +09:00
eomsangdonandClaude Opus 5 3a36af9a2c feat(B01): 서명은 사람 계정에, 회사 로고는 회사 등록 단계로 재배치
사용자 확정(2026-09-02) — 이름이 들어가는 자리는 서명도 받고, 담당자 선택에 신규 등록
항목을 두며, 회사 로고는 회사 등록 단계에서 받아 이후 변경.

- 014_company_logo.sql: companies.logo_asset_id 추가 (서명은 company_assets.user_id 로
  이미 표현되어 컬럼 없음). 공유 DB 적용 완료
- 사용자 수정 모달에 「서명 (도면 표제란)」 칸 — createAssetField 에 owner(주인 못박기)·
  onChange(즉시 반영) 추가로 재사용, 주인 고정 시 물리기 체크 잠금
- 담당자 select 3개에 「+ 신규 등록…」 — 계정 생성 모달 뒤 세 select 에 항목 삽입·자동 선택
- POST /admin/members 가 이름·직위·부서 수신, 계정 없으면 status=PENDING 으로 생성
  (로그인 불가 비밀번호). 700줄 제한으로 B01_Dashboard_Repository_Members.py 분리
- 회사 등록 모달에 로고 파일 칸, PUT /company/logo 신설, 회사 패널·회사 목록에서 변경
- 프로젝트 수정 모달의 「설계자 서명」 칸 제거 — signature_asset_id 는 null 로 고정 저장
- 검증(5174 실조작): 신규 등록 구성원 2→3(id 6 PENDING)·select 자동 선택, 서명 자산
  [4,'검증신규 서명',user_id 6] 생성, 회사 logo_asset_id None→1, 검증 자산·계정 정리.
  pytest 143 passed, tsc·ruff·prettier 통과

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:57:16 +09:00
eomsangdonandClaude Opus 5 65d6fd261f fix(B07): 도각 편집 띠 사이드바 이관·깨진 그림에 렌더 루프 정지 해소
- 편집 띠를 CAD 위 절대배치에서 도면 목록 하단 액션 칸으로 옮김 —
  1행 편집 띠, 2행 [도각 편집]·[현재 도면 확정] (리본과 겹쳐 문구·버튼이 찌그러지던 문제)
- `drawImage` 가 'broken' 상태 그림에서 던지던 예외로 렌더 루프가 끊겨
  이후 모든 도면이 백지로 남던 결함 해소 — 못 읽은 그림은 건너뜀
- `ImageEntity` 가 자리표시자(`{{회사로고}}`)를 절대 URL 로 굳히던 저장 경로 수정 —
  원본 주소를 보관해 그대로 돌려주고, 자리표시자는 요청조차 하지 않음
- 버튼 줌(ZOOMIN·ZOOMOUT)이 배율만 바꿔 도면이 화면 밖으로 밀리던 것을
  화면 중심 고정으로 수정

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:12:28 +09:00
eomsangdonandClaude Opus 5 5fc8009925 feat(B01): 서명 그리기 캔버스 추가
- 자산 모달 서명 칸에 마우스 그리기 판 신설 — pointer 이벤트 + setPointerCapture,
  getBoundingClientRect 로 CSS 크기 → 캔버스 픽셀 환산, [지우기] 1개
- 올릴 때 canvas.toBlob('image/png') → signature.png 로 기존 업로드 통로
  (POST /company/assets) 재사용 — 백엔드·DB 변경 없음
- 파일을 안 고르면 그린 서명을 대신 실어 보냄, 로고 칸에는 캔버스 없음
- 검증(5174 공용 브라우저): 좌표 환산 실측 x 98–381 · y 38–111(요청 100–380 · 40–110),
  [지우기] 후 잉크 0, 저장 PNG 480×160 RGBA 5,250 bytes,
  프로젝트 signature_asset_id 2→3 반영 확인 후 원복. pytest 143 passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:04:44 +09:00
eomsangdonandClaude Opus 5 2e57d29156 fix(B05,B03): 초기 설계 실패 시 초기값 부재 처리 — 실패 마커·안내 메일·[초기화] 거부
증상: 파일 입력 직후 초기 계산값과 B05 [초기화] 결과가 다름.

원인
- 자동설계 체인이 5단계까지 전부 성공해야만 `save_initial_snapshot()` 호출.
  중간에 깨지면 `initial_snapshot/` 미생성 → [초기화]가 복원 대신 재계산 폴백.
- 재계산 폴백의 지표면 기준이 체인과 다름 — 체인은 stage 1 확정값
  (`get_surface_confirmation_params`), [초기화]는 config 기본값
  (`surface_confirmation_defaults`). 실측: 프로젝트 stage1 `classification`/5m 대
  config `csf`/1m.
- 체인이 깨져도 WF1 은 초기 분석 완료 메일을 그대로 발송.

수정 (2026-09-02 사용자 확정 — 부분 결과는 분석 안 됨과 다르지 않으므로 부분
스냅샷은 만들지 않음)
- `initial_design.failed` 마커 신설 — 프로젝트 루트(스냅샷 4트리 밖), 실패 사유 기록.
  체인 진입 시 옛 마커 제거, 실패 5지점 + 스냅샷 저장 실패에서 기록.
- WF1 이 마커를 읽어 완료 메일 대신 `send_initial_design_failed_email()` 발송
  (관리자 주소 `ADMIN_EMAIL`, 없으면 주소 없이 안내).
- B05 [초기화]: 스냅샷 있으면 복원, 실패 마커 있으면 409 `initial_design_failed`
  로 거부(DELETE 앞에서 반환 — 데이터 무변경), 옛 프로젝트만 종전 재계산 폴백.
- 재계산 폴백의 지표면 기준을 `get_surface_confirmation_params()` 로 통일.

자체검증: `pytest tmp/tests/ -q` 366 passed / 14 skipped / 0 failed (+4).
공용 브라우저 실측 — 실패 프로젝트 [초기화] 409 응답·`routes` 행 무변경 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 18:03:18 +09:00
eomsangdonandClaude Opus 5 2bdad0947b fix(B07): 명령행 토글 기본값 숨김으로 변경
- 상태막대 `명령행` 토글의 초기 상태를 `useState(true)` → `useState(false)` 로 변경
- 진입 시 `--cad-command-height` 가 `0px` 로 잡혀 캔버스 세로 공간 확보
- 토글 동작·명령행 구현 자체는 불변

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 17:48:10 +09:00
eomsangdon 1a9947426a sync: 4환경 수렴본 main 반영 (PR #10)
4환경 브랜치 전부 fa0624a7 / tree 95d6e89b 동일. 커밋 34건. 테스트 359 passed, 17 skipped, 0 failed.
2026-09-02 17:24:18 +09:00
eomsangdon fa0624a7df Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-02 16:52:45 +09:00
eomsangdon e7b0d62060 Merge remote-tracking branch 'origin/main_desktop_1' into main_laptop_1 2026-09-02 16:52:43 +09:00
eomsangdon 9b1c816992 auto: 2026-09-02 16:52 (ESD_LAPTOP) 2026-09-02 16:52:38 +09:00
eomsangdon 397a135073 auto: 2026-09-02 16:48 (EOMSANGDON-HOME) 2026-09-02 16:48:22 +09:00
eomsangdon d93bd1cba8 refactor(B05): 페이지 버튼 동작 3종 분리 (819→679줄)
- `B05_Profile_UI_Page_Actions.ts`(216줄) 신설 — [경로 계산]·[임시저장]·[초기화].
  페이지는 상태 창구(`PageActionContext`)만 넘기고 화면 조립·로딩 순서만 맡음.
- 화면 검증: B05 [저장] 실제 클릭 — `PUT /drainage/pipe-points` 200 →
  `POST /route/confirm?mark_stage_complete=false` 200 → `GET /route/latest` 200 →
  `PUT /routes/111/corridor` 200 순서 그대로, 콘솔 오류 0.
  (앞서 분리한 Lifecycle 라우터의 `/route/confirm` 도 이 경로로 함께 확인됨.)
- `tsc --noEmit` 0, prettier 적용, pytest 359 passed.
2026-09-02 16:48:01 +09:00
eomsangdon 6809f8a148 refactor(B06): 측점 제어기 세션 맵 통합·구간값 제어 분리 (843→643줄)
- `createSessionMap` 을 `_Page_Link_Session.ts` 에 추가 — 반폭·기슭막이 4축·유입
  형식·집수정·추가 벽 수·단별 구간값 6쌍이 같은 모양(읽기 → 항목 검증 → 담기 /
  통째 직렬화)이라 제어기마다 두던 load/persist 짝을 하나로 모음. 항목 검증과
  구형식 호환(숫자 x·d=0)은 `accept` 로 넘어감.
- `B06_Section_UI_Page_Span_Control.ts`(130줄) 신설 — 다단 단별 구간값과 유입·유출·
  집수정 구간값 제어를 세션·캐시·정본 큐와 함께 한 덩어리로 이동.
- 화면 검증: B06 카드 렌더 후 콘솔 오류 0, 조정창 DOM(구간 69·단 23) 그대로.
  표시 반폭 − 조작으로 세션 `b06:crossw` 에 13 기록, ⤢ 로 12 복귀 후 키 제거.
- `tsc --noEmit` 0, prettier 적용, pytest 359 passed.
2026-09-02 16:43:57 +09:00
eomsangdon cc2c788122 refactor(B06): 횡단 페이지 저장 흐름·관 옵션 반영 분리 (926→680줄)
- `B06_Section_UI_Page_Persist.ts`(231줄) 신설 — 암 경계선 세션 저장소
  (`createRockBoundaryStore`), 편집분 수집, [저장]·[확정].
- `B06_Section_UI_Page_Pipe_Options.ts`(130줄) 신설 — 폼에서 바꾼 관 옵션을
  횡단 캐시·조정창 제어기에 얹는 경로.
- 페이지는 상태 창구(`SectionPersistContext`·`PipeOptionsContext`)만 넘김.
- 화면 검증: B06 진입 카드 280장·암 버튼 69개·콘솔 오류 0. 암 경계선 ▲ 조작으로
  표시 -0.5m → -0.4m + 세션키 기록, ↺ 로 -0.5m 복귀. [저장] 클릭 시
  `POST /sections/111/save` 200.
- `tsc --noEmit` 0, prettier 적용, pytest 359 passed.
2026-09-02 16:37:48 +09:00
eomsangdon b4c7a7eedb auto: 2026-09-02 16:31 (EOMSANGDON-HOME) 2026-09-02 16:31:23 +09:00
eomsangdon 4e074dcfbe refactor(B05): 3D 뷰어 포인터 입력 분리 (803→678줄)
- `B05_Profile_UI_Viewer_Marker_Input.ts`(196줄) 신설 — 지형 지점 픽킹, 마커 끌기·
  고르기, 끌어놓기(drop), 리스너 등록·해제를 `bindMarkerPointerControls` 로 묶음.
- 뷰어는 `markerInput.blocked()`(회전 중심 양보 판정)·`terrainPointAt`(공개 API
  `modelPointAt`)·`beginMoveSelected` 만 받아 쓰고, dispose 에서 함께 해제.
- 화면 검증: 공용 브라우저에서 BP 마커를 실제 클릭 — 선택 배율 1 → 1.35,
  빈 지형 클릭으로 해제 1.0 복귀. 마커군 명중 시 이벤트 전파 차단도 유지됨.
- `tsc --noEmit` 0, prettier 통과, pytest 359 passed.
2026-09-02 16:30:59 +09:00
eomsangdon 3a161aa18d refactor(B05): 경로 확정·초기화 엔드포인트 분리 (722→491줄)
- `B05_Profile_Router_Lifecycle.py`(256줄) 신설 — `/route/confirm` · `/route/reset`
  두 엔드포인트를 자체 APIRouter 로 옮김. URL·응답 스키마 불변.
- `main.py` 가 새 라우터를 함께 등록 (`b05_route_lifecycle_router`).
- 자동설계 체인이 쓰던 `B05_Profile_Router.confirm_latest_route` 경로는 재수출로 유지.
- 검증: 라우트 8개 그대로(openapi.json 실측), 백엔드 재기동 후 200, pytest 359 passed.
2026-09-02 16:20:17 +09:00
eomsangdon acdd2cef4e refactor(B05): 능선-계곡 길찾기 그래프 뼈대 분리 (787→552줄)
- `B05_Profile_Engine_RidgeValley_Graph.py`(257줄) 신설 — 격자 조회(`_Grid`),
  노드 수집, 구획 마스크, 정속경사 세그먼트 판정, 엣지·연결 후보, 교각 계산.
- 원본에는 탐색(`_search_segment`)·fillet 선형·진입점 계산만 남김.
- 엣지 후보 상수(MAX_EDGE_LEN_M 등)도 함께 이동 — 쓰는 쪽이 전부 새 모듈.
- 외부 호출부 불변(`solve_ridge_valley_route` 경로 동일), pytest 359 passed.
2026-09-02 16:15:25 +09:00
eomsangdon fc59cef976 feat(B05): 3D 화면 검증용 카메라 이동 창구 추가
- `__corridorScene.lookAt(x, y, z, distance, view)` — 모델 좌표 한 점으로 카메라를
  바로 보냄. 측점 확인을 마우스 휠·드래그로 하면 한 번에 20~30초가 걸리고
  우클릭이 구조물 메뉴를 여는 문제 해소.
- `fit()` 의 카메라 배치를 `placeCamera()` 로 공용화 — 뷰 4종(iso/top/front/side)
  위치·근평면·직교 반높이 계산이 한 곳.
2026-09-02 16:10:29 +09:00
eomsangdon 1250cabe71 fix(B07): CAD 그림 그리기의 y 뒤집기 누락 수정 — 도각 로고·서명이 화면에 안 보이던 원인
- screenCanvas.drawController.drawImage 가 worldToTarget 결과를 그대로 써서 그림이
  거울상 자리(캔버스 밖)에 놓였음. 선·글자처럼 canvasSize.y - y 로 뒤집고 회전 부호도 반대로
- vitest 추가: 그림 중심의 뒤집힌 y 자리, 회전 부호·원상 복구
- 검증(공용 브라우저, 종단면도): 로고 상자 비배경 픽셀 0 → 14708(파랑 11661),
  서명 상자 498 → 2810(빨강 852). 뷰는 187% 로 정확히 복귀
2026-09-02 12:24:26 +09:00
eomsangdonandClaude Opus 5 cb06e40f9c fix(B05): 잘린 자리 윤곽의 시작 모서리 유실 수정 — dropCollinear 닫힘점 처리
- `_Corridor_Cut.ts` `dropCollinear`: 추적 고리의 닫힘 중복점(머리=꼬리)을 떼고 순환
  다듬기 뒤 다시 붙임. 그대로 두면 머리 점의 이웃이 자기 자신이 되어 `away=0` 으로
  지워지고 양옆 일직선 점까지 빠져 8고리 전부 시작 모서리가 대각선으로 잘림(63셀 구멍).
- 공선 판정의 앞점을 마지막으로 남긴 점 기준으로 변경 — 완만한 곡선에서 누적 편차로
  현이 곡선 안쪽으로 파고들던 2셀 제거(`_Region.ts` `simplifyLoop` 과 같은 규칙).
- `BUILD_VERSION` 89→90 으로 저장본 만료.
- 실측: 되살릴 영역 미포함 셀 63→0(우 7886/7886·좌 7023/7023), 8고리 닫힘,
  `tmp/tests/test_b05_cut_merged_loop.py` 3건 포함 359 passed.
- PLAN.md 해당 항목 완료 표시 + 자체검증 기록(검증 대기).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 12:06:54 +09:00
eomsangdonandClaude Opus 5 00d30587b3 feat(B01,B07): 담당자 회사 구성원 지정 + 로고·서명 회사 공유 자산 모달
- B01 프로젝트 수정: 과업책임자·분야별책임자·설계자를 회사 구성원 목록(select)에서
  지정. 회사 로고·설계자 서명 칸은 누르면 등록 목록 모달(선택·삭제·신규 추가 업로드).
- 백엔드: `company_assets`(013) CRUD 라우트 신설 — 목록·업로드(Form+File, 2MB·확장자
  검사)·수정·소프트 삭제·파일 서빙. `_scope_company` 로 SYSTEM_ADMIN 만 타 회사 지정,
  `_check_project_refs` 로 담당자·자산이 같은 회사·같은 종류인지 검사(400).
- projects 조회·수정에 pm/field_lead/designer/logo_asset/signature_asset 5칸 합류.
  중복 3곳을 `_project_rows` 로 묶어 700줄 제한 유지.
- B07 표제란: 로고·서명 출처를 `companies.logo_path`/`users.signature_path` 에서
  프로젝트가 고른 `company_assets` 로 전환(삭제된 자산은 그림째 제외).
- 검증: pytest 143 통과(신규 4), tsc·ruff·prettier 통과. 공용 브라우저 사용자 경로
  (업로드→선택→저장→재열기) 및 종단도 API 표제란 글자 4건·그림 2건 수치 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 12:02:49 +09:00
eomsangdon 0ea0fe2ba8 Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-02 11:42:11 +09:00
eomsangdonandClaude Opus 5 2d07b990a4 feat(B05): 3D 평면 스케치를 최종 결과물에서 숨긴다 (디버깅용으로 되켤 수 있게)
투영 커브(구조물 노랑·날개 주황·투영선 빨강·잘린 자리 라임 등)는 구조물이 어디를
지우고 어디를 다시 채우는지 눈으로 좇으려고 만든 표기라 설계 산출물이 아니다.
사용자 지시로 **기본은 숨김**. 다만 절취·패치 기하를 다시 볼 때 쓰므로 지우지 않고
묶음째 감춘다(2026-09-02 사용자: "나중에 디버깅을 위해 재사용 가능성 있음").

- `_Corridor_Mesh.ts` — 커브를 `corridor-plan-sketch` 묶음에 담고 `visible` 을
  브라우저 스위치(`frd_debug_plan_curves`, 기본 꺼짐)로 정한다.
- `_Profile_UI_Viewer.ts` — `__corridorPlanCurves(true|false)` 로 켜고 끈다. 선택은
  브라우저에 남아 다음에 열 때도 유지된다. 인자 없이 부르면 지금 상태를 돌려준다.

검증(wdw · 3D 실측, 같은 화면에서 켜고 끄며 스케치 색 픽셀을 셈):
  숨김(기본) — 주황 1 · 노랑 0 · 빨강 0 · 라임 0
  켬        — 주황 89 · 노랑 260 · 빨강 6 · 라임 195
`__corridorPlanCurves()` 기본 false → true → false 왕복 확인.
`tsc --noEmit` 통과, `pytest tmp/tests/ -q` 356 passed / 0 failed, prettier 정합.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 11:41:41 +09:00
eomsangdonandClaude Opus 5 313a7dde43 feat(B01,B07): 설계일자 사용자 지정 입력 + 도면번호 자동 부여
사용자 확정(2026-09-02): 설계일자는 확정일 자동이 아니라 **사용자가 넣는다**. 도면번호는
Claude 판단으로 목록 순번을 쓴다.

설계일자
- `013_company_assets.sql` 로 `projects.design_date DATE` 추가(같은 마이그레이션에
  로고·서명 공유 테이블 자리도 함께 만들었음 — 배선은 다음 커밋).
- B01 프로젝트 수정 모달에 날짜 칸. 공용 `createInputField` 가 `type="date"` 를 받게 넓힘.
- 표제란에는 도면 표기 관행대로 `2026. 09. 02.` 꼴로 적는다.

도면번호
- 단건 조회는 목록 순서를 모른다 — 알려면 횡단 장 계획을 다시 계산해야 하고 도면을 열
  때마다 그러면 비싸다. **목록이 매긴 번호를 manifest 에 적어 두고** 단건 조회가 읽는다.
  목록은 화면 진입 때 늘 먼저 뜨므로 성립하고, 목록이 바뀌면 다음 조회에서 다시 적힌다.
- `add_title_fields()` 신설 — 도면을 읽는 도중에 아는 값을 문맥에 얹는 창구.

검증: `pytest tmp/tests/ -q` 139 passed / 0 failed, 루트 `tsc --noEmit` 통과.
실사용자 경로(5174, wdw) — 대시보드 [수정] 모달 라벨 10개(설계일자 칸 추가 확인) →
`2026-09-02` 입력 → [확인] → 종단면도 표제란에 `2026. 09. 02.`.
도면번호는 목록 13건 기준 종단 1 · 유역도 6 · 용지도 13 이 도각에 그대로 실림
(표지는 도각을 두르지 않아 번호 칸이 없다).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 11:38:50 +09:00
eomsangdonandClaude Opus 5 7498d6a2ec refactor(B06): API 타입 선언을 별도 파일로 분리 (700줄 제한)
`B06_Section_Api_Fetch.ts` 704줄 중 486줄이 타입 선언이었다. 타입을
`B06_Section_Api_Types.ts` 로 옮기고 `_Api_Fetch` 는 요청 함수만 남긴다.

호출 코드는 손대지 않았다 — `_Api_Fetch` 가 `export type *` 로 그대로 다시 내보내므로
기존 import 경로가 전부 유효하다. 계약이 아니라 파일만 나눈 것이다.

결과: 704줄 → 236줄(요청 함수) + 492줄(타입). 둘 다 700줄 이내.
검증: `tsc --noEmit` 통과, `pytest tmp/tests/ -q` 356 passed / 0 failed, prettier 정합.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 11:32:51 +09:00
eomsangdonandClaude Opus 5 dc91a5e831 fix(B05): BOX암거 패치도 절취 영역 안쪽으로 자른다
패치 리본을 절취 영역 안쪽만 남기는 규칙(`patchClip`)이 세월교에만 걸려 있었다.
`_Corridor_Cut.ts` 가 표식 없는 패치는 손대지 않고 그대로 돌려주므로 BOX암거 패치는
한 번도 안 잘려 절취 영역 밖으로 넘쳤다. BOX도 `wing-box` 커브로 절취 영역을 내므로
같은 반대 규칙이 성립한다. 기슭막이(배수관 세트)는 날개 사다리꼴이 없어 제외.

기하가 바뀌므로 `BUILD_VERSION` 88 → 89 (형식은 안 바뀌어 `ENVELOPE_VERSION` 은 그대로).

검증(wdw · 저장본 실측):
- 수정 전 — BOX 패치 리본 두 벌(198.4~203.5m)에 셀 마스크 없음. `patchClip` 3개.
- 수정 후 — 두 벌 모두 마스크 생김(남은 셀 46/282 · 43/282). `patchClip` 5개.
- 3D 화면(TOP, 지형 끔) — BOX 자리 성토면이 구조물에 맞물려 끊기고, 넘침도 구멍도 없음.
- `tsc --noEmit` 통과, `pytest tmp/tests/ -q` 356 passed / 0 failed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 11:27:25 +09:00
eomsangdon a218d08589 Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1 2026-09-02 10:51:04 +09:00
eomsangdonandClaude Opus 5 475fb73505 fix(B05): 코리도 저장본이 패치 리본 표식을 잃던 것 + 원복된 트림 도구 제거
- 저장본 왕복에서 `patch`·`patchClip` 두 표식이 사라졌음. 직렬화 대상에 없어
  저장본으로 다시 연 코리도는 패치인 줄 몰랐고, 뷰어의 지형 스냅 제외 가드
  (`B05_Profile_UI_Viewer.ts` `if (ribbon.patch) return;`)가 풀려 패치 리본
  바깥 끝이 원지반까지 끌려 내려갔음(2026-08-27 실측 세로 지느러미 4.1m).
  두 표식을 `serialize`·`deserialize` 에 싣고 `ENVELOPE_VERSION` 을 6으로 올림 —
  `fetchStored` 가 버전이 다른 저장본을 버리므로 기존 v5 저장본은 다시 만들어짐.
- `_Corridor_Carve_Wing.ts` 의 「주황 바깥선 트림」 도구 4개(`WingTrimLine`·
  `wingOuterLines`·`wingTrimAt`·`clipRunToRange`)를 제거. 버전 76~78용인데 그 판이
  사용자 지시로 원복된 뒤 `BUILD_VERSION 88` 까지 다시 배선되지 않아 파일 밖 참조가
  0이었음. 이력은 `_Corridor.ts` 버전 주석에 남김.

검증: 저장본 3건 실측 — 전부 `version=5`, `patch`·`patchClip` 0건으로 결함 확인.
회귀 방지 `tmp/tests/test_b05_corridor_envelope_flags.py` 7건 신규(표식 왕복·버전 상향·
뷰어 가드 존속·선택 필드 대칭·죽은 심볼 부재·살아 있는 도구 존속).
`pytest tmp/tests/ -q` 356 passed / 17 skipped / 0 failed, `tsc --noEmit` 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 10:50:10 +09:00
eomsangdonandClaude Opus 5 56aed2f2aa feat(B01,B07): 표지 연도·기번·사업량을 사람이 넣는 자리 신설
표제란에 남아 있던 빈칸 중 연도·기번과 사업량은 프로그램이 지어낼 수 없는 값이라
입력 자리를 만든다. 값의 출처를 정하지 않고 받을 칸만 세운다.

DB (`012_title_block_inputs.sql`, ADD COLUMN·NULL 허용)
- `projects.project_number` — 표지 연도·기번(실무문서 폴더명 관행:
  `2024년 간선임도(기번3-울진.대흥)`)
- `projects.work_amount` — 표지 사업량. 단위·표기가 사업 종류마다 달라 자유 문자열.

B01 프로젝트 수정
- 수정 모달에 시행청·연도기번·사업량 3칸 추가. 011 로 만든 시행청도 여기서 처음 입력
  가능해짐(그전에는 스크립트로만 넣었음).
- 목록·단건 조회 4곳과 UPDATE 에 세 칸을 함께 실음. USER 권한은 다른 칸과 같이 잠금.

B07
- `_title_block_fields` 가 연도기번·사업량도 실어 보냄. 비어 있으면 종전대로 빈칸.

검증: `pytest tmp/tests/ -q` 139 passed / 0 failed(표지 값 1건 신규), 루트 `tsc --noEmit`
통과. 실사용자 경로 실측(5174) — 대시보드 wdw 행 [수정] 클릭 → 모달 라벨 9개에 새 3칸
확인 → 연도기번·사업량 입력 → [확인] 저장 → 표지 도면 Text 7개 **빈칸 0 · `{{` 잔존 0**,
화면에도 연도기번·`wdw 설계도`·위치·사업량·시행청이 모두 그려짐.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 10:28:25 +09:00
eomsangdonandClaude Opus 5 07926e3867 fix(B07): 빈 도면의 "작도 영역을 넘습니다" 경고 제거
빈 도면 7종이 도각만 두르는데도 경고를 냈음 — `build_blank_drawing()` 이 콘텐츠
bbox 로 작도 영역(`_A1_INNER`, 770×520mm)을 그대로 넘겼고, 검사 기준은 여백을 뺀
수용 한도(739×499mm)라 담을 내용이 없는데도 넘친 것으로 잡혔음.

- `usable_bbox()` 신설 — 작도 영역 한가운데의 수용 한도 크기 bbox. 중심이 같아
  도각 배치(이동량 0)는 그대로.
- 한도와 **같은** 크기는 넘친 것이 아니므로 비교에 부동소수 여유(1e-6)를 둠.
  한도를 그대로 넘기면 마지막 자리 오차로 경고가 났음.

검증: `pytest tmp/tests/ -q` 138 passed / 0 failed(경고 없음을 잠그는 1건 신규).
백엔드 재시작 뒤 화면 실측(5174, wdw): 빈 도면 7종 전부 200, 새 서버 로그의
"작도 영역을 넘습니다" **0건**.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 10:02:35 +09:00
eomsangdonandClaude Opus 5 63428f2516 feat(B07): 표제란 축척 칸을 도면 축척 상수에서 채움
축척은 지어내는 값이 아니라 이미 정해져 있던 것 — `config_system` 의 도면별 축척
상수를 그대로 표제란에 싣는다. 도각이 `A1 = 1 :` 를 이미 찍으므로 **분모만** 낸다.

- `scale_fields()` 신설 — A3 는 A1 도면을 절반으로 뽑는 종이라 분모가 2배. 가로·세로가
  다른 도면(종단·토적)은 이름표를 붙여 함께 적는다.
- 종단면도 `1000(H) · 200(V)` / 횡단면도 `100` / 유역도 `6000` / 토적도 `2000(H)`.
  A3 는 각각 2배. 담을 내용이 없는 빈 도면·표지는 축척이 없어 빈칸 그대로.

검증: `pytest tmp/tests/ -q` 135 passed / 0 failed(축척 2건 신규 — 상수 유래·A3 2배,
호출부가 넘긴 값이 도각에 실림). 백엔드 재시작 뒤 화면 실측(5174, wdw): 종단
`1000(H) · 200(V)`/`2000(H) · 400(V)`, 횡단 `100`/`200`, 유역도 `6000`/`12000`,
토적도 `2000(H)`/`4000(H)`, 표준도 빈칸.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 09:54:16 +09:00
eomsangdonandClaude Opus 5 a5fba04778 fix(B07): 그림 테두리는 집었을 때만 그림
도각의 로고·서명 자리에 흰 사각형이 남던 것 — `ImageEntity.draw()` 가 폴리곤 네 변을
선택·강조 여부와 무관하게 늘 그렸음. 출력·내보내기가 같은 `draw()` 를 다른
DrawController 로 타므로 화면만의 문제가 아니라 산출물에도 실렸음.

- 도각층만 특례로 두지 않고 `ImageEntity` 전체에서 뺌. 일반 CAD 관행대로 **집었을
  때만**(강조·선택) 테두리를 보임 — 앞으로 붙일 그림(현황사진 등)에도 같은 규칙.
- 자리 표시가 필요하면 도각 편집 화면에서 집으면 보임.

검증: `ImageEntity.test.ts` 신규 2건 — 안 집은 그림은 `drawLine` 0회·`drawImage` 1회,
집은 그림은 4회·1회. `npx vitest run` 89 passed / 0 failed, check-types·build 통과.
화면 실측(5174, wdw 표준도): 두 슬롯 사각형 안 흰 픽셀(RGB>200) **0**,
그림 픽셀은 그대로(로고 56 · 서명 106).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 08:50:02 +09:00
eomsangdonandClaude Opus 5 b1593bce83 feat(B07): 표제란에 로고·서명 자리 신설 + 시행청·담당자 DB 확장
사용자 지시(2026-09-02) — 로고·서명을 임의로 만들어 표제란에 넣고, 위치·크기는
도각을 고치면 따라오게 하며, 시행청·과업책임자 등은 DB를 넓혀 채울 것.

도각(표제란)
- `00_template_A1.json` 에 그림 자리 2개 추가 — 회사 로고는 용역회사 칸 왼쪽
  (316~348 × 20~36mm), 설계자 서명은 설계 칸 아래(638~680 × 17.5~25.5mm).
  자리·크기가 **템플릿 좌표로만** 정해지므로 도각을 고치면 그대로 따라옴.
- `_fill_placeholders` 가 그림 자리(`imageData`)의 `{{키}}` 도 채움. 값을 못 구하면
  빈 문자열을 남기지 않고 **엔티티째 제거** — 빈 값은 CAD 가 깨진 그림으로 그림.
- `_transform_entity` 가 `points` 배열도 옮김. 그림(로고·서명)과 띠(Hatch)가 이 키를
  쓰는데 여태 변환 대상이 아니라 도각을 옮기면 제자리에 남았음.

DB (`011_title_block.sql`, 전부 ADD COLUMN·NULL 허용)
- `projects` — `client_org`(시행청), `pm_user_id`·`field_lead_user_id`·`designer_user_id`
- `companies.logo_path` · `users.signature_path` — 그림은 파일로 두고 경로만 담음
  (기존 `storage_path`·`input_files` 와 같은 방식)
- FK 는 걸지 않음 — 사유를 파일 머리말에 적음(소프트 삭제·LEFT JOIN·4환경 공유).

배선
- `_title_block_fields` 가 시행청·과업책임자·분야별책임자·설계자(배정 없으면 소유자)와
  로고·서명 data URL 까지 실어 보냄.
- `read_stored_asset()` 신설 — `storage/` 기준 상대 경로의 **파일**을 읽음.
  `resolve_stored_project_path()` 는 폴더를 만드는 프로젝트 루트용이라 파일에 못 씀.

CAD 결함 1건 (이번 작업에서 드러남)
- `screenCanvas.drawController.drawImage` 가 `(width, height)` 를 좌표처럼 변환해
  화면 오프셋과 y 뒤집기가 섞여 들어갔음 — 그림이 제 자리를 벗어나고 비율이 무너짐.
  크기는 배율만 곱하고 자리는 세계 중심으로 잡도록 고침(SVG 컨트롤러와 같은 방식).
- 검증 창구 `__aisloCad.screen(x, y)` 추가 — 세계→화면 좌표. 그림·글자가 제 자리에
  그려졌는지 픽셀로 판정할 때 씀.

검증: `pytest tmp/tests/ -q` 135 passed / 0 failed(그림 자리 3건 신규),
`npx vitest run` 87 passed / 0 failed, `check-types`·`build` 통과.
화면 실측(5174, wdw): 표준도 API Text 24개 `{{` 잔존 0, Image 2개가 도각 좌표
(316,20)-(348,36)·(638,18)-(680,26)에 실림. 캔버스 픽셀 판정 — 두 자리 모두 배경색
외 픽셀이 그려짐(로고 88px·서명 64px), 로고 파랑(20,70,140)이 슬롯 안에서만 검출.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 08:35:25 +09:00