사용자 지시(2026-09-07 「묵은 것 청소」). 이름이 비슷한 표가 둘이라 **「감사 기록이 비었다」는
오진이 실제로 한 번 났던** 자리임.
지우기 전 확인(공용 DB) — `audit_logs` **0행** · 정본 `system_audit_logs` **81행** ·
이 표를 참조하는 **외래키 0건** · 코드는 쓰기(`common_util_audit.py:61`) · 읽기
(`B01_Dashboard_Repository.py:455·460`) · 정리(`purge_expired_audit_logs`) 전부 정본만 씀.
최초 스키마(`001_create_schema.sql`)는 **안 고침** — 지나간 이력은 다시 쓰지 않는 것이 규칙임.
새로 설치하면 001 이 만들고 이 파일이 지움.
공용 DB 라 **적용 전 두 창(보조 워크트리 · 데스크톱)에 알리고** 「막을 것 없음」을 받은 뒤 돌림.
서버 재시작 없음. 적용 후 확인 — 표 사라짐, 정본 81행 그대로.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 승인(2026-09-07). 앞서 취향을 localStorage 로 옮겨 **탭·재시작** 문제는 풀었고,
이 변경은 그 위에 **다른 PC 에서도 같은 배치**를 얹음. 사용자가 노트북·데스크톱 두 대를 오감.
- `db_management/018_user_ui_prefs.sql` — 사용자당 한 줄, `prefs` JSON 한 칸.
칸을 나누면 취향이 늘 때마다 마이그레이션이 또 필요해 한 칸에 담음.
- `GET/PUT /api/dashboard/me/ui-prefs` — 배치 값만. **설계값은 안 담음**(문자열만 받음).
- 로그인이 확인된 첫 순간에 한 번 받아 로컬 위에 얹고, 취향이 바뀌면 1.5초 모아 올림.
서버가 없거나 못 읽으면 **로컬 값으로 그대로 돔**(계획서 원문).
⚠ 같은 함정을 또 밟을 뻔했음 — 키만 아는 자리가 저장소를 직접 고르면 **올려보내기도 안 걸림**.
그래서 `storageOf` 를 없애고 **읽기·쓰기 창구 하나**(`readByKey`/`writeByKey`)로 모음.
저장소 선택과 서버 올려보내기가 그 한 곳에만 있음. 그물도 그 이름으로 갱신.
**DB 는 아직 적용하지 않았음** — 표가 없으면 API 가 실패하고 화면은 로컬 값으로 도는 것이
정상 동작임. 적용 시점은 다른 창들과 맞춘 뒤.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 기록을 `common_util_audit.record_audit()` 한 곳으로 모음 — 여섯 자리에 흩어져 있던
raw INSERT 제거
- 대상 식별자 칸 신설(`017_audit_log_detail.sql`, 적용 완료) — 기존 `resource_id` 는 INT 라
프로젝트 UUID 를 못 담아 늘 NULL 이었음. 프로젝트 생성·수정·삭제·회사 생성이 대상을 남김
- 접속 주소·브라우저 기록 — 라우터가 요청을 넘겨 주고, 프록시 뒤에서는 X-Forwarded-For 우선
- 보관 기간 `AUDIT_LOG_RETENTION_DAYS` 기본 365일, 임시 보관함 정리 루프에 얹어 함께 정리
- 화면: 시스템 로그 표에 대상·접속 주소 열 추가(대상은 UUID 앞 8자만)
자체검증 — 프로젝트 생성·하드삭제를 실화면에서 돌려 두 줄 모두
`프로젝트 e1040640… · 127.0.0.1 · 2026-09-06 09:54/09:55` 로 남는 것 확인.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- project_members 표 신설(016 마이그레이션, 기존 프로젝트는 생성자 자동 채움)
- 프로젝트 수정 모달에 참여자 선택 추가, 참여자로 지정된 일반사용자는 해당 프로젝트 수정 가능 (백엔드 _can_edit_project 동반 수정)
- B02 프로젝트 생성 시 생성자를 참여자로 자동 등록, 참여자도 같은 회사 구성원인지 검증
- 가입 요청 목록을 대기 상태만 표시 (처리 완료 건이 사용자 관리 목록과 중복 노출되던 문제)
- 팀원 등록 시 남아 있던 가입 신청 자동 정리
- 서명·로고 선택 문구를 뜻이 드러나게 수정
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- 계획노선 사용 범위: B02 등록에 시작·종료 누가거리 두 칸 추가, B01 수정 모달에서도
변경. projects.route_start_m·route_end_m 신설(015_route_range.sql).
load_design_route 가 범위 절단 → 서피스 트림 순서로 적용. 시작 >= 종료는 화면·서버
양쪽에서 차단. 비우면 전 구간으로 종전과 같음.
- 서피스 절단 여유 기본값 30m → 3m (SURFACE_ROUTE_EDGE_TRIM_M).
- B04 지도·B05 배수유역도 줌 상한을 「화면 폭 20m」 기준으로 계산(고정 8배·16배 폐지).
4배를 넘으면 배경 그림 흐림 보간 해제.
- 계획선 위 측점 눈금·번호 표기(측점번호+잔여거리). 관 마커와 겹치면 반대쪽으로 밀고,
되꺾임 구간에서 라벨이 겹치면 건너뜀. 그리기 코드는 두 화면 공용.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
사용자 확정(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): 설계일자는 확정일 자동이 아니라 **사용자가 넣는다**. 도면번호는
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>
표제란에 남아 있던 빈칸 중 연도·기번과 사업량은 프로그램이 지어낼 수 없는 값이라
입력 자리를 만든다. 값의 출처를 정하지 않고 받을 칸만 세운다.
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) — 로고·서명을 임의로 만들어 표제란에 넣고, 위치·크기는
도각을 고치면 따라오게 하며, 시행청·과업책임자 등은 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>
라이다 원본은 업로드에 오래 걸려 프로젝트 정보 확정 전에 미리 올릴 수 있어야 한다.
계정에 묶인 임시 보관함을 만들고, 나중에 만든 프로젝트로 자료를 옮겨 쓴다.
저장·DB
- storage/tmp/{user_id}/{batch_id}/ 아래에 프로젝트 저장소와 동일한 구조를 써서
청크 저장·병합 엔진(resolve_upload_destination/merge_upload_chunks)을 그대로 재사용
- 010_temp_upload.sql: temp_upload_batches / temp_upload_files 신설,
upload_sessions.project_id NULL 허용 + temp_batch_id 추가(FK명 조회 후 재생성)
- config: TEMP_UPLOAD_DIR_NAME / TEMP_UPLOAD_RETENTION_DAYS(30) /
TEMP_UPLOAD_CLEANUP_INTERVAL_HOURS(6)
백엔드
- B03_FileInput_Router_Temp.py: 묶음 생성·목록·삭제, 일반/청크 업로드, finalize,
이어올리기 상태 조회, 프로젝트 연결(attach)
- attach: 파일 이동 후 input_files 등록, stage 0 완료, WF1·자동 설계 체인 트리거
- common_util_temp_cleanup.py: 완료 시각 기준 만료분 주기 삭제(서버 시작 시 1회 포함)
프론트엔드
- B01 대시보드 임시 보관함 섹션: 프로젝트 등록과 같은 폼 + 보관 목록.
진행률은 모달이 아니라 리스트 행에 표시, 새로고침 후 이어올리기 지원
- B03 업로드 컨테이너 내부 불러오기 버튼과 선택 모달.
완료된 묶음만 노출하고, 선택 후 업로드를 누르면 이동과 분석으로 이어짐
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>