chore(docs): docs 폴더 git 추적 전환 · PLAN·OWNERS 최상위 이관

- `docs/` 를 .gitignore 에서 빼 git 추적 대상으로 전환 (위키·완료 이력·검증 기록)
- `docs/raw/PLAN.md` · `docs/raw/OWNERS.md` 를 저장소 최상위로 이동 후 .gitignore 에 등록
  — 창끼리 공유하되 저장소에는 안 올리는 장부
- 살아 있는 경로 참조 7개 파일 정정 (아카이브 107건은 그때 사실이라 그대로 둠)
- graphify 날짜별 산출물(`docs/wiki/graphify-out/20*/`) 제외 — `graphify update` 가 다시 만듦

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-09 18:19:07 +09:00
co-authored by Claude Opus 5
parent d7cb14f416
commit eb30b774f8
527 changed files with 43083 additions and 2 deletions
+5
View File
@@ -0,0 +1,5 @@
graphify-out/
log.md
AGENTS.md
CLAUDE.md
ingest/
+28
View File
@@ -0,0 +1,28 @@
---
type: wiki-governance
status: stable
related_pages: ["[[index]]", "[[ingest/index]]"]
last_updated: 2026-08-16
source: docs/AGENTS.md
---
# wiki/ 폴더 규칙
AI가 raw/의 원본을 읽고 편집·유지하는 산출물 계층. 자세한 운영 규칙(Ingest/Query/Lint, 위키 규칙 14가지)은 `docs/CLAUDE.md`의 Wiki Schema 섹션을 따른다.
## 구조
- `index.md` — 전체 카탈로그. 모든 질의는 여기서 시작한다.
- `log.md` — 연대기 로그. append-only.
- `pages/B0x_이름/` — 프로젝트의 실제 B01~B09 폴더와 1:1 대응하는 페이지 단위 폴더. 하위에 `frontend.md`, `backend.md`, `db.md`, `api.md`, `dependencies.md`를 필요한 것만 생성한다.
- `concepts/` — 여러 페이지가 함께 쓰는 공유 자원의 1차 정의처. DB 스키마, 인증/RBAC, 저장 경로 규칙, 공통 유틸(`common_util_*`), API 공통 엔드포인트, 공통 Pydantic 스키마, 외부 라이브러리 의존성, workflow 상태 관리 등.
## 작성 규칙
- 모든 페이지에 YAML frontmatter 포함. `status`는 `draft`/`stable`/`stale` 셋 중 하나만 사용 (draft=계획서만 반영, stable=검증보고서로 확인, stale=raw 갱신됐는데 미반영).
- **`pages/` 하위 파일에는 반드시 `page_id: B0x_이름`(또는 `A0x_이름`)을 frontmatter에 추가한다.** 파일명(`frontend.md` 등)만으로는 소속 페이지를 알 수 없으므로, 폴더 밖에서 봐도 식별 가능해야 한다. concepts 파일에는 해당 없음.
- 내부 참조는 `[[페이지명]]` 위키링크 형식.
- 새 페이지를 만들기 전에 기존 페이지를 업데이트할 수 있는지 먼저 확인한다.
- 소스 요약은 사실만, 해석·종합은 concepts 페이지에서 다룬다.
- 계획서와 검증보고서가 충돌하면 **검증보고서를 채택**한다 (실제 코드 상태에 더 가까운 소스). 계획서 내용은 지우지 않고 "계획 당시 의도"로 남긴다.
- **공유 자원(두 페이지 이상이 쓰는 테이블·함수·API·의존성 등)은 concepts에만 정의한다.** 페이지 쪽 파일(`db.md` 등)에는 용도 설명 + 위키링크만 남긴다. concepts 쪽에는 사용처(역참조) 목록을 직접 적어 유지한다.
- **함수·API·테이블 등 개별 항목은 `항목 | 위치(파일:줄번호) | 역할` 표 형식으로만 기록한다.** 서술문 금지 — grep 없이 바로 코드 위치를 찾을 수 있어야 한다.
- **페이지(파일) 하나는 100줄을 넘지 않는다.** 넘으면 하위 주제별로 즉시 분할하고 index.md를 갱신한다.
+28
View File
@@ -0,0 +1,28 @@
---
type: wiki-governance
status: stable
related_pages: ["[[index]]", "[[ingest/index]]"]
last_updated: 2026-08-16
source: docs/AGENTS.md
---
# wiki/ 폴더 규칙
AI가 raw/의 원본을 읽고 편집·유지하는 산출물 계층. 자세한 운영 규칙(Ingest/Query/Lint, 위키 규칙 14가지)은 `docs/CLAUDE.md`의 Wiki Schema 섹션을 따른다.
## 구조
- `index.md` — 전체 카탈로그. 모든 질의는 여기서 시작한다.
- `log.md` — 연대기 로그. append-only.
- `pages/B0x_이름/` — 프로젝트의 실제 B01~B09 폴더와 1:1 대응하는 페이지 단위 폴더. 하위에 `frontend.md`, `backend.md`, `db.md`, `api.md`, `dependencies.md`를 필요한 것만 생성한다.
- `concepts/` — 여러 페이지가 함께 쓰는 공유 자원의 1차 정의처. DB 스키마, 인증/RBAC, 저장 경로 규칙, 공통 유틸(`common_util_*`), API 공통 엔드포인트, 공통 Pydantic 스키마, 외부 라이브러리 의존성, workflow 상태 관리 등.
## 작성 규칙
- 모든 페이지에 YAML frontmatter 포함. `status`는 `draft`/`stable`/`stale` 셋 중 하나만 사용 (draft=계획서만 반영, stable=검증보고서로 확인, stale=raw 갱신됐는데 미반영).
- **`pages/` 하위 파일에는 반드시 `page_id: B0x_이름`(또는 `A0x_이름`)을 frontmatter에 추가한다.** 파일명(`frontend.md` 등)만으로는 소속 페이지를 알 수 없으므로, 폴더 밖에서 봐도 식별 가능해야 한다. concepts 파일에는 해당 없음.
- 내부 참조는 `[[페이지명]]` 위키링크 형식.
- 새 페이지를 만들기 전에 기존 페이지를 업데이트할 수 있는지 먼저 확인한다.
- 소스 요약은 사실만, 해석·종합은 concepts 페이지에서 다룬다.
- 계획서와 검증보고서가 충돌하면 **검증보고서를 채택**한다 (실제 코드 상태에 더 가까운 소스). 계획서 내용은 지우지 않고 "계획 당시 의도"로 남긴다.
- **공유 자원(두 페이지 이상이 쓰는 테이블·함수·API·의존성 등)은 concepts에만 정의한다.** 페이지 쪽 파일(`db.md` 등)에는 용도 설명 + 위키링크만 남긴다. concepts 쪽에는 사용처(역참조) 목록을 직접 적어 유지한다.
- **함수·API·테이블 등 개별 항목은 `항목 | 위치(파일:줄번호) | 역할` 표 형식으로만 기록한다.** 서술문 금지 — grep 없이 바로 코드 위치를 찾을 수 있어야 한다.
- **페이지(파일) 하나는 100줄을 넘지 않는다.** 넘으면 하위 주제별로 즉시 분할하고 index.md를 갱신한다.
@@ -0,0 +1,65 @@
---
type: architecture-status
status: draft
related_pages: ["[[architecture/workflow_data_flow]]", "[[workflow_state]]", "[[storage_paths]]", "[[architecture/project_map]]"]
last_updated: 2026-08-16
source: ["code-audit:2026-08-16"]
---
# 현재 구현 현황 — 소스 읽기 감사
> 이 문서는 2026-08-16 소스 읽기 감사 결과다. 코드를 수정하거나 실행 검증하지 않았으므로 `draft`이며, raw 검증보고서와 충돌하면 최신 코드의 현재 구조를 우선 참고하되 동작 성공까지 보장하지 않는다.
## 단계별 판정
| 단계 | 구현 판정 | 코드 근거 | 현재 책임 |
|---|---|---|---|
| B03 FileInput | 구현 | `B03_FileInput_Router.py`, `B03_FileInput_Service_WF1.py` | 입력 저장, stage 0 완료, B04 이후 초기화 |
| B04 PreProcess | 구현 | `B04_PreProcess_Router.py`, `B04_PreProcess_Service.py` | 지표면 분석·확정, stage 1 상태 관리 |
| B05 Profile | 구현 | `B05_Profile_Router.py`, `B05_Profile_Structures_Router.py` | 경로·종단 생성/편집, B~G 일반 구조물 수동 배치·정본, stage 2와 후속 STALE 관리 |
| B06 Section | 구현·결합 | `B06_Section_Router*.py` | 횡단 설계; 전체 확정 시 stage 2·3 동시 완료 |
| B07 Quantity | 임시 우회 | `B07_Quantity_Router.py`, `B07_Quantity_UI_Page.ts` | 계산 없이 stage 4를 COMPLETE로 바꾸고 B08 이동 |
| B08 DesignDetail | 부분 구현 | `B08_DesignDetail_Router.py` | CAD 도면, 횡단 확정, 단면 재계산, `quantity_table` 저장 |
| B09 Estimation | 셸 | `B09_Estimation_UI_Page.ts` | 준비 중 화면; stage 6 완료 backend 미확인 |
## 비워크플로 영역 판정
| 영역 | 구현 형태 | 판정 |
|---|---|---|
| A00 Common | SPA router·App Shell·workflow navigation | 공통 기반 구현 |
| A01~A05 | 각 1개 Frontend 페이지 | 공개 정보 화면; backend 없음 |
| A06 Login | Frontend + 5 API route | 인증 기능 구현 |
| A07 Register | Frontend + 3 API route | 가입 기능 구현 |
| A08 Support | Frontend + 1 API route | 지원 문의 기능 구현 |
| A09 Security | Frontend + 9 API route | 보안·계정 기능 구현 |
| B01 Dashboard | Frontend/Backend + 26 API route | 관리 기능 구현 |
| B02 Project Register | Frontend/Backend + 1 API route | 프로젝트 생성 구현 |
| B10 Payment | Frontend 1개 | workflow 외 화면; backend 미확인 |
| B11 Status | Frontend 2개 | 상태·로딩 화면; 독립 backend 없음 |
## 구현 상태 용어
| 용어 | 의미 |
|---|---|
| 구현 | 주요 API와 상태 전이가 소스에 존재 |
| 부분 구현 | 핵심 일부가 있으나 전체 업무 완료 기능은 아님 |
| 임시 우회 | 본문 기능 없이 다음 단계 진입만 허용 |
| 셸 | 레이아웃·준비 중 화면만 존재 |
| 미확인 | 소스 읽기만으로 동작 성공을 확정할 수 없음 |
## 반드시 유지할 구분
| 구분 | SSOT·처리 |
|---|---|
| workflow 상태 | DB `project_workflow_stages` |
| 프로젝트 요약 상태 | DB `projects.status` 캐시 |
| 레거시 보조 상태 | 프로젝트 루트 `workflow.json`; 현재 핵심 전이에서 사용 제한적 |
| 단계 산출물 | 프로젝트 저장소의 B03~B08 단계별 파일 + 일부 DB 레코드 |
| 후속 상태 무효화 | `start_stage()`가 뒤쪽 COMPLETE 단계만 STALE 처리 |
| 산출물 무효화 | 공통 자동 삭제가 아니라 각 단계의 개별 로직에 의존 |
## 미결 설계
- B07 최종 수량 계산과 B08 CAD 수량표의 책임 경계는 확정되지 않았다.
- B08 도면 수정이 향후 B07 수량을 역으로 무효화해야 하는지는 사용자 결정이 필요하다.
- B09 견적·설계도서 산출 및 stage 6 완료 API는 후속 구현 대상이다.
+44
View File
@@ -0,0 +1,44 @@
---
type: architecture-map
status: stable
related_pages: ["[[index]]", "[[architecture/implementation_status]]", "[[architecture/workflow_data_flow]]", "[[architecture/shared_resources]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-09-09
source: ["docs/raw/verification/2026-08-08_verify_R1_R2_features.md", "docs/raw/verification/2026-08-08_verify_server_and_e2e_fixes.md"]
---
# Aislo 프로젝트 지도
## 현재 명칭과 책임
| 영역 | 현재 책임 | 상세 진입점 | 레거시 위키명 |
|---|---|---|---|
| A00 | 공통 App Shell·라우터·UI | [[A00_Common/A00_Common]] | 동일 |
| A01~A05 | 공개 소개·소식·교육 | [[architecture/public_admin_map]] | 동일 |
| A06~A09 | 로그인·가입·지원·보안관리 | [[architecture/public_admin_map]] | 동일 |
| B01 | 프로젝트·조직·임시보관 관리 | [[B01_Dashboard/B01_frontend]] | 동일 |
| B02 | 프로젝트 생성·workflow 시드 | [[B02_ProjRegister/B02_backend]] | 동일 |
| B03 | 파일 입력·검증·WF1 실행 | [[B03_FileInput/B03_backend]] | 동일 |
| B04 | 전처리·지표면·GIS·배수유역 | [[B04_PreProcess/B04_backend]] | B04_wf1_Surface |
| B05 | 경로·종단·구조물·배수 편집 | [[B05_Profile/B05_backend]] | B05_wf2_Route |
| B06 | 횡단·유토곡선·단면 확정 | [[B06_Section/B06_backend]] | B06_wf3_ProfileCross |
| B07 | 상세설계·CAD·설계도면 | [[B07_DesignDetail/B07_frontend]] | B08_DesignDetail(구 위키 경로) |
| B08 | 수량산출·자재총괄·B09 인계 | [[B08_Quantity/B08_overview_2026_09]] | B07_Quantity(구 위키 경로) |
| B09 | 단가산출·예산내역·공사원가계산 | [[B09_Estimation/B09_overview_2026_09]] | B09_wf6_Estimation |
| B10~B11 | 결제·진행상태 목업 | [[B10_Payment/B10_frontend]], [[B11_Status/B11_frontend]] | workflow 외 후속 화면 |
## 탐색 순서
| 질문 | 먼저 읽을 문서 | 다음 문서 |
|---|---|---|
| 기능의 전체 위치 | 이 페이지 | 해당 B/A canonical 페이지 |
| B03~B09 데이터 흐름 | [[architecture/workflow_data_flow]] | backend/api/db 세부 페이지 |
| DB·인증·저장소·공통 유틸 영향 | [[architecture/shared_resources]] | 해당 concepts 페이지 |
| 공개·인증·관리자 흐름 | [[architecture/public_admin_map]] | A/B01 세부 페이지 |
| raw 반영 여부 | [[ingest/index]] | 월·유형별 원장 |
## 명칭 판정
- 2026-09-07 사용자 확정과 2026-09-08 완료·검증 문서를 현재 workflow 명칭·책임의 기준으로 채택한다.
- 레거시 명칭은 검색 호환을 위해 이 표의 alias로만 보존하며 현재 페이지 ID로 사용하지 않는다.
- B07은 상세설계/CAD, B08은 수량산출, B09는 원가계산이다. 2026-08 문서의 B07/B08 표기는 레거시 alias다.
- 현재 구현 완성도와 실제 책임은 [[architecture/implementation_status]]를 기준으로 판정한다.
@@ -0,0 +1,43 @@
---
type: architecture-map
status: stable
related_pages: ["[[architecture/project_map]]", "[[architecture/implementation_status]]", "[[auth_rbac]]", "[[a00_app_shell_framework]]", "[[ui_templates]]"]
last_updated: 2026-08-16
source: ["docs/raw/verification/2026-07-12_verify_add_phase4_role.md", "docs/raw/verification/2026-07-16_verify_인증주기개선.md", "docs/raw/verification/2026-07-17_verify_auth_reverify.md"]
---
# 공개·인증·관리 영역 지도
이 지도는 [[architecture/project_map]]의 공개·인증 영역을 상세화한다. 모든 공개 화면은 [[A00_Common/A00_Common]]의 SPA router와 App Shell을 사용하며, 인증·관리 API는 [[auth_rbac]]의 세션과 권한 규칙을 따른다.
| 사용자 흐름 | 관계 | 대상 페이지 | 핵심 상태·데이터 |
|---|---|---|---|
| 방문자 진입 | `ROUTES_TO` | [[A01_Home/A01_frontend]] | 공개 홈·소개 진입 |
| 기능 탐색 | `ROUTES_TO` | [[A02_ProgDetail/A02_frontend]], [[A03_CompDetail/A03_frontend]], [[A04_NewsHistory/A04_frontend]], [[A05_EduDetail/A05_frontend]] | 정적·목업 콘텐츠 |
| 로그인 | `AUTHENTICATES` | [[A06_Login/A06_backend]] | 세션쿠키·신뢰기기·재인증 |
| 회원가입 | `CREATES_IDENTITY` | [[A07_Register/A07_backend]] | OTP·회사검색·가입승인 |
| 기술지원 | `CREATES_REQUEST` | [[A08_Support/A08_backend]] | 비로그인 문의·DB 저장·메일 |
| 보안관리 | `GOVERNS` | [[A09_Security/A09_backend]] | 조직·회원·승인·감사 로그 |
| 로그인 후 진입 | `ROUTES_TO` | [[B01_Dashboard/B01_frontend]] | 프로젝트·회사·사용자·임시보관 |
## 공통 의존
| 자원 | 사용 이유 |
|---|---|
| [[a00_app_shell_framework]] | 헤더·라우터·인증 상태·공통 레이아웃 |
| [[auth_rbac]] | 역할별 접근과 API 권한 |
| [[ui_templates]] | 다국어·컴포넌트·워크플로우 레이아웃 |
| [[design]] | 테마·타이포그래피·간격 토큰 |
| [[db_schema/users_auth]] | 사용자·회사·세션·OTP·동의 |
| [[db_schema/logs_monitoring]] | 로그인·활동·감사·지원 로그 |
## 직접 구현 관계
| 상위 페이지 | 구현 파일 문서 | 관계 |
|---|---|---|
| [[A01_Home/A01_frontend]] | [[A01_Home/frontend/A01_Home_UI_Page]] | `IMPLEMENTS` |
| [[A02_ProgDetail/A02_frontend]] | [[A02_ProgDetail/frontend/A02_ProgDetail_UI_Page]] | `IMPLEMENTS` |
| [[A06_Login/A06_backend]] | [[A06_Login/backend/A06_Login_Router]] | `IMPLEMENTS` |
| [[A07_Register/A07_backend]] | [[A07_Register/backend/A07_Register_Router]] | `IMPLEMENTS` |
| [[A08_Support/A08_backend]] | [[A08_Support/backend/A08_Support_Router]] | `IMPLEMENTS` |
| [[A09_Security/A09_backend]] | [[A09_Security/backend/A09_Security_Router]] | `IMPLEMENTS` |
@@ -0,0 +1,46 @@
---
type: architecture-map
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/implementation_status]]", "[[architecture/workflow_data_flow]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-08-16
---
# 공유 자원 영향 지도
> 각 정의의 검증 상태는 링크된 concept 문서를 따른다. 이 페이지는 영향 탐색용 종합 지도다.
| 공유 자원 | 관계 | 주요 사용처 |
|---|---|---|
| [[auth_rbac]] | `GOVERNS` | A06, A07, A09, B01 및 보호 API 전체 |
| [[workflow_state]] | `GOVERNS` | B01, B02, B03~B09 |
| [[db_schema/overview]] | `DEFINES` | 모든 backend/db 페이지 |
| [[storage_paths]] | `DEFINES` | B03 입력, B04~B09 산출물 |
| [[crs_metadata]] | `NORMALIZES` | B03, B04, B05 |
| [[api_common]] | `STANDARDIZES` | 공통 오류 응답과 workflow API |
| [[schema_common]] | `STANDARDIZES` | 공유 Pydantic 요청·응답 모델 |
| [[common_util]] | `SUPPORTS` | 인증·저장소·메일·workflow·삭제 |
| [[dependencies]] | `SUPPORTS` | GIS·수치연산·DB·프론트 렌더링 |
| [[ui_templates]] | `RENDERS` | A00~A09, B01~B11 |
| [[design]] | `STYLES` | 전체 프론트엔드 |
| [[drainage_watershed]] | `CONNECTS` | B04 전처리, B05 구조물·배수, B06 횡단 |
| [[mass_haul_diagram]] | `CONNECTS` | B05 종단, B06 횡단·유토, B07 수량 |
| [[temp_upload]] | `CONNECTS` | B01 임시보관, B03 attach·자동 체인 |
## 단계별 직접 연결
| 단계 | API·Backend 관계 | 공유 자원 |
|---|---|---|
| B01 | [[B01_Dashboard/B01_api]] → [[B01_Dashboard/B01_backend]] | workflow·인증·DB |
| B03 | [[B03_FileInput/B03_api]] → [[B03_FileInput/B03_backend]] | 저장소·CRS·workflow |
| B04 | [[B04_PreProcess/B04_api]] → [[B04_PreProcess/B04_backend]] | 저장소·GIS·workflow |
| B05 | [[B05_Profile/B05_api]] → [[B05_Profile/B05_backend]] | 저장소·배수·workflow |
| B06 | [[B06_Section/B06_api]] → [[B06_Section/B06_backend]] | B05 산출물·workflow |
| B07 | [[B07_Quantity/B07_backend]] → [[workflow_state]] | stage 4 임시 완료만 사용 |
| B08 | [[B08_DesignDetail/B08_api]] → [[B08_DesignDetail/B08_backend]] | B06 산출물·CAD·workflow |
## 영향 분석 규칙
1. 공유 자원을 변경할 때 이 표에서 소비 페이지를 먼저 찾는다.
2. concept의 사용처 목록과 각 페이지의 `related_pages`를 양방향 대조한다.
3. DB·API·workflow 변경은 [[architecture/workflow_data_flow]]의 생산자와 소비자를 함께 검토한다.
4. 상세 함수·테이블은 해당 canonical concept 또는 페이지의 표에서 찾는다.
@@ -0,0 +1,52 @@
---
type: architecture-flow
status: stable
related_pages: ["[[architecture/project_map]]", "[[architecture/implementation_status]]", "[[workflow_state]]", "[[storage_paths]]", "[[db_schema/overview]]"]
last_updated: 2026-09-09
source: ["docs/raw/verification/2026-08-08_verify_R1_R2_features.md", "docs/raw/verification/2026-08-04_verify_b05_b06_profile_ui_chain.md", "docs/raw/verification/2026-07-17_verify_workflow_stepbar.md"]
---
# B01~B09 Workflow 데이터 흐름
## 단계 관계
| 생산 단계 | 관계 | 소비 단계 | 전달·상태 |
|---|---|---|---|
| [[B01_Dashboard/B01_backend]] | `SELECTS` | [[B02_ProjRegister/B02_backend]] | 사용자·회사·프로젝트 컨텍스트 |
| [[B02_ProjRegister/B02_backend]] | `INITIALIZES` | [[workflow_state]] | 프로젝트와 stage 0~6 `NOT_STARTED` 시드 |
| [[B03_FileInput/B03_backend]] | `PRODUCES` | [[B04_PreProcess/B04_backend]] | 업로드 파일, CRS 메타데이터, WF1 실행 |
| [[B04_PreProcess/B04_backend]] | `PRODUCES` | [[B05_Profile/B05_backend]] | 확정 지표면, GIS, 배수유역, stage 1 params |
| [[B05_Profile/B05_backend]] | `PRODUCES` | [[B06_Section/B06_backend]] | 경로·종단·측점과 [[B05_Profile/B05_structures|일반 구조물 정본]]; 설계 영향 변경 시 후속 STALE |
| [[B06_Section/B06_backend]] | `PRODUCES` | [[B07_DesignDetail/B07_frontend]] | 횡단 정본을 상세설계·도면 단계가 소비 |
| [[B07_DesignDetail/B07_frontend]] | `PRODUCES` | [[B08_Quantity/B08_overview_2026_09]] | 설계도면·구조물 정본에서 물량 산출 |
| [[B08_Quantity/B08_overview_2026_09]] | `HANDOFF` | [[B09_Estimation/B09_overview_2026_09]] | 공종코드·수량·갈래·근거를 인계 |
| [[B09_Estimation/B09_overview_2026_09]] | `PRICES` | [[workflow_state]] | 단가산출·예산내역·공사원가계산 |
## B04→B06 자동 계산과 재설계
| 트리거 | 호출·처리 | 저장·소비 | 상태 |
|---|---|---|---|
| B03 업로드 완료 | WF1 지표면 분석 | B04 모델·확정 스냅샷 | stage 1 진행/완료 |
| B04 확정 | 자동 설계 체인 | B05 기본 경로·B06 기본 횡단 | stage 2·3 `IN_PROGRESS` |
| B04 재확정 | `run_redesign_chain` | B05 제어점·경사와 B06 단면 설정 이월 | 하위 결과 재계산 |
| B05 경로·종단·일반 구조물 수정 | B05 save/confirm 또는 구조물 PUT | 종단 정본·비정규 측점·`structures.json` | 설계 영향 변경이면 B06 이후 STALE; 처리 실패 시 B06 재실행 안내 |
| B06 확정 | section confirm | 횡단 설계 정본 | stage 2·3 `COMPLETE`, B07 임시 셸 이동 |
## 상태와 산출물 무효화
| 변경 | DB 상태 | 실제 산출물 |
|---|---|---|
| B03 입력 교체 | stage 1~6을 `NOT_STARTED`로 초기화 | 단계별 정리 로직에 의존 |
| B04~B08 단계 재시작 | 뒤쪽 `COMPLETE` 단계만 `STALE` | 공통 함수는 파일을 삭제하지 않음 |
| B08 도면 무효화 | stage 5 `IN_PROGRESS`, 뒤쪽 완료 단계 `STALE` | manifest의 해당 도면 `confirmed=false` |
## 정본 위치
| 데이터 | canonical 문서 | 주요 소비자 |
|---|---|---|
| workflow 상태 | [[workflow_state]] | B01, B03~B09 스텝바·게이팅 |
| DB 스키마 | [[db_schema/overview]] | 모든 backend/db 페이지 |
| 저장 경로 | [[storage_paths]] | B03~B09 파일 산출물 |
| CRS 메타데이터 | [[crs_metadata]] | B03 분석, B04/B05 좌표 처리 |
| 배수유역·관 | [[drainage_watershed]] | B04·B05·B06 |
| 유토곡선 | [[mass_haul_diagram]] | B05·B06·B07 후보 데이터 |
@@ -0,0 +1,41 @@
---
status: stable
related_pages: ["[[A01_Home/A01_frontend]]", "[[A02_ProgDetail/A02_frontend]]", "[[B01_Dashboard/B01_frontend]]", "[[B03_FileInput/B03_frontend]]", "[[B04_PreProcess/B04_frontend]]", "[[B05_Profile/B05_frontend]]", "[[B06_Section/B06_frontend]]", "[[B07_Quantity/B07_frontend]]", "[[B08_DesignDetail/B08_frontend]]", "[[B09_Estimation/B09_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-18
source: docs/raw/verification/2026-07-18_verify_layout_improvement.md
---
# A00_Common — App Shell Framework
모든 페이지의 공통 스켈레톤. 헤더(로고/네비/언어·테마/인증버튼) + 콘텐츠 아울렛 + 푸터를 통합 관리. B그룹 작업 화면(B01~B11)의 경우 화면 전체 높이 사용을 위해 푸터를 동적 제외(FOOTERLESS_ROUTES) 처리.
## 파일 구성
| 파일 | 역할 |
|---|---|
| `app_shell.ts` (284줄) | 헤더·푸터 렌더링, 테마·언어 토글, `showFooter` 옵션 분기 및 `.app-outlet--without-footer` 뷰포트 확장 |
| `b_page_scaffold.ts` (163줄) | B 그룹(B03~B09) 페이지용 스캐폴드—"준비 중" 임시 페이지 래퍼, 워크플로우 셸 헬퍼 |
| `router.ts` (158줄) / `main.ts` | SPA 라우터(해시 기반), 인증 가드, `FOOTERLESS_ROUTES` 상수(B01~B11) 기준 푸터 비활성화 주입 |
| `b_workflow_nav.ts` (신설) | 7단계 라우트 배열(`WORKFLOW_STEP_ROUTES`), 공통 `fetchWorkflowState`, 네비게이션 `goToWorkflowStage` |
## app_shell 구성요소
### 테마 & 언어 관리
- `initThemeAndLang()` — localStorage 복원 (THEME_STORAGE_KEY, LANG_STORAGE_KEY)
- `onApp_Theme_Toggle_Click()` — light ↔ dark 전환
- `onApp_Lang_Toggle_Click()` — 한국어 ↔ 영문 전환 + 현재 페이지 재렌더
### 헤더 구성 (64px 높이, sticky)
- **로고**: `BRAND_ICON_URL`(prog_icon.jpg) + 브랜드명("Aislo")
- **네비게이션**: 5개 링크 (A02_PROG_DETAIL, A03_COMP_DETAIL, A04_NEWS_HISTORY, A05_EDU_DETAIL, A08_SUPPORT)
- **우측 액션**: 언어 버튼 ("EN" / "한"), 테마 버튼 ("☀" / "☾"), 인증 버튼 (로그인/로그아웃)
## router 라우팅 테이블
- **A그룹 (A01~A09)**: 로그인 전/보안/지원 화면 라우팅
- **B그룹 (B01~B11)**: 대시보드 및 7단계 워크플로우(`B03_FILE_INPUT` ~ `B09_WF6_ESTIMATION`), 결제(`B10`), 상태조회(`B11`) 라우팅
## 인증 가드
- **PROTECTED_ROUTES**: 로그인 토큰 없으면 A06_LOGIN으로 리다이렉트
- **워크플로우 라우트 (B02~B11)**: 추가 검증 (로그인 여부 + `company_id` 미보유 시 B01_ACCOUNT로 강제 이동하여 회사 가입 유도)
## 세부 스캐폴드·CSS·종속성
`b_page_scaffold`, CSS 주입, 공통 종속성은 [[a00_app_shell_framework_scaffold]]에 분리했다.
@@ -0,0 +1,38 @@
---
type: concept
status: draft
page_id: A00_Common
related_pages: ["[[a00_app_shell_framework]]", "[[B07_Quantity/B07_frontend]]", "[[B09_Estimation/B09_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-12
source: 상위 프로젝트 A00_Common 코드 및 페이지 인제스트 대조 (2026-07-12)
---
# A00_Common — 스캐폴드·CSS·종속성
## b_page_scaffold
| 항목 | 역할 |
|---|---|
| `renderPendingContent` | 비 workflow 페이지용 준비 중 블록 |
| `renderPendingWorkflow` | workflow 셸과 좌·우 준비 중 영역 |
| `workflowSteps()` | 7단계 workflow 라벨 배열 |
## CSS 인젝션
| 항목 | 역할 |
|---|---|
| `injectShellStyles` | 셸 스타일을 `<head>`에 1회 주입 |
| `app-shell-style` | 헤더·아울렛·푸터 스타일 ID |
| theme 변수 | 헤더 64px·푸터 56px·아울렛 최소높이 |
## 종속성
| 항목 | 역할 |
|---|---|
| `ui_template_locale.ts` | 언어 상태·문자열 |
| `ui_template_elements.ts` | 버튼·workflow 셸 |
| `config_frontend.ts` | routes·theme·protected routes |
| `A06_Login_Api_Fetch.ts` | 세션 조회·로그아웃 |
## 사용처
| 페이지 | 역할 |
|---|---|
| A01~A09 | 공통 헤더·푸터·아울렛 |
| B01~B09 | 페이지별 workflow 셸·단계 내비게이션 |
+27
View File
@@ -0,0 +1,27 @@
---
type: concept
status: draft
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-12
source: raw/plans/plan_workflow_state_management.md, raw/guidelines/backend.md + 실 코드 확인 2026-07-12
---
# API 공통 (여러 페이지가 공유하는 엔드포인트)
## 공통 오류 응답 포맷 (전 라우터)
```json
{"status": "error", "message": "원인"}
```
→ [[schema_common]]
## 워크플로우 상태 조회
| 항목 | 위치 | 역할 |
|---|---|---|
| `GET /api/projects/{project_id}/workflow-state` | `B03_FileInput_Router.py:667` | 단일 프로젝트의 `current_stage`와 `stages[]` 조회 |
| `get_workflow_states_for_projects()` | `B01_Dashboard_Repository.py:83` | [[B01_Dashboard/B01_backend|B01_Dashboard]] 목록용 다중 프로젝트 상태 배치 조회 |
상태 모델과 사용처: [[workflow_state]].
## 폴링 패턴 (legacy workflow.json 설계; 현재 구현은 workflow-state API 사용)
- 클라이언트가 3초마다 `GET /api/projects/{project_id}/workflow` 호출
- 과거 설계의 stale 감지 UX 참고용이며, 실제 상태 조회는 [[workflow_state]] API를 사용한다.
+68
View File
@@ -0,0 +1,68 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[A06_Login/A06_backend]]", "[[A07_Register/A07_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-17
source: docs/raw/verification/2026-07-17_verify_auth_reverify.md
---
# 인증 / RBAC
## 세션 인증 (backend.md 6.3)
- 방식: Secure HttpOnly 세션 쿠키 (`session_id`, JWT 아님), `SameSite=Lax`
- 저장소: `sessions` 테이블 → [[db_schema/users_auth]]
- 유효시간: 활동 기준 4시간 또는 절대 12시간 중 먼저 도달하는 쪽
- DB 풀: `autocommit=True` (세션 즉시 조회 가능하도록)
- 프론트: 모든 API 요청에 `credentials: "include"` (frontend.md 5.1)
## OTP / 비밀번호 및 디바이스 신뢰
- OTP 6자리, 5분 유효, 해시 저장(bcrypt/PBKDF2), 재시도 최대 3회(2s/4s/8s 백오프)
- 비밀번호 최소 8자, bcrypt(라운드≥12) 또는 PBKDF2, 평문 저장 절대 금지
- 5회 연속 실패 시 계정 임시 잠금 및 ADMIN_EMAIL로 보안 경고 메일 발송
- **디바이스 신뢰 (2026-07-17 도입)**:
- 기기 신뢰를 기존 User-Agent 해시에서 **HttpOnly 디바이스 토큰 쿠키 (`device_token`)**로 전환하여 브라우저 업데이트 시 반복적인 OTP 요구를 해결.
- 로그인 또는 가입 인증 성공 시 무작위 32바이트 토큰을 발급하여 브라우저 쿠키에 저장(만료 90일)하고, SHA256 해시값은 DB `trusted_devices` 테이블에 저장.
- 기기 신뢰 만료 정책: `last_used_at`이 `EMAIL_REVERIFY_DAYS`(90일) 이내인 기기 토큰만 유효 처리하며, 로그인 시 `last_used_at`을 자동으로 갱신.
## 사용자 상태 생명주기
```
PENDING_EMAIL → NO_COMPANY → (PENDING | ACTIVE) → (INACTIVE | REJECTED)
```
| 상태 | 접근 가능 범위 |
|---|---|
| NO_COMPANY | 로그인 가능, B01만 (B02~B11 차단) |
| PENDING | 로그인 가능, B01만 (승인 대기) |
| ACTIVE | 전체 (B01 + B02~B11) |
## 역할 (users.role)
| 역할 | 전체회사조회 | 역할변경 | 팀원관리 | 가입승인 | 프로젝트조회 범위 |
|---|---|---|---|---|---|
| SYSTEM_ADMIN | ✅ | ✅ | ✅ | ✅ | 전체 |
| ADMIN | ✗ | ✗ | ✅(자기회사) | ✅(자기회사) | 회사별 |
| USER | ✗ | ✗ | ✗ | ✗ | 회사별 |
`is_master` 플래그: TRUE=회사 생성자/ADMIN(팀원 승인권), FALSE=일반 팀원
## 권한 검증 헬퍼 (B01_Dashboard)
| 항목 | 위치 | 역할 |
|---|---|---|
| `_can_edit_project()` | `B01_Dashboard_Router.py:79` | 역할·회사 기준 프로젝트 수정 권한 |
| `_can_manage_automation()` | `B01_Dashboard_Router.py:87` | USER 차단과 프로젝트 범위 검사 |
| `_can_edit_user()` | `B01_Dashboard_Router.py:93` | 사용자 수정 범위 검사 |
| `count_company_admins()` | `B01_Dashboard_Repository.py:584` | 마지막 ADMIN 삭제·강등 방지 |
| `canEditProject()` 외 5개 | `B01_Dashboard_UI_Helper.ts:3` | 프론트 표시 제어; 백엔드 권한을 대체하지 않음 |
**원칙:** 백엔드가 모든 수정/삭제/역할변경 API에서 반드시 재검증 (프론트 UI는 표시 제어만, 신뢰 금지). 위반 시 403 `{"status":"error","message":"Access denied"}`.
## 인증 갱신 및 만료 일원화
- 기존의 중복된 `auth_expires_at` 컬럼 및 로직을 제거하고, 만료 개념을 **`EMAIL_REVERIFY_DAYS`(90일)로 일원화**하였습니다.
- 로그인/가입 인증 이후 90일이 지나면 OTP 재인증을 요구하며, 대시보드 표시 시에도 `last_email_verified_at + 90일`을 계산하여 적용합니다.
## 라우팅 가드 (frontend.md 5.2)
B02~B11 진입 시 `fetchDashboardMe()` → `company_id`+`status` 확인 → NO_COMPANY/PENDING이면 B01로 강제 리다이렉트.
## 사용처 (역참조)
- [[B01_Dashboard/B01_frontend]] — 권한 헬퍼 5종, RBAC 접근제어 및 만료일 동적 계산 표시
- [[A06_Login/A06_backend]] — 세션 발급/OTP 재인증, 디바이스 토큰 쿠키 신뢰 판정 및 발급
- [[A07_Register/A07_backend]] — 가입 OTP 인증 성공 시 기기 신뢰 연계 등록
- [[A09_Security/A09_backend]] — require_master/require_system_admin 권한 데코레이터
@@ -0,0 +1,35 @@
---
status: stable
related_pages: ["[[B08_DesignDetail/B08_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-19
source: docs/raw/verification/2026-07-19_verify_b07_external_webcad_demos.md
---
# B07 외부 WebCAD 비교 실행환경
B07 2D Drawing 후보를 통합 전에 직접 비교한 독립 실행환경이다. [[B08_DesignDetail/B08_dependencies]]의 현행 의존성이 아니라 과거 선택 근거인 `HISTORICAL_REFERENCE`로만 유지한다.
| 후보 | 위치 | URL | 역할 |
|---|---|---|---|
| OpenWebCAD | `external_program/openwebcad` | `http://127.0.0.1:5175/` | 기본 Drawing, 스냅, 선택 및 변형 UX 비교 |
| elhakimz/WebCAD | `external_program/elhakimz-webcad` | `http://127.0.0.1:5174/` | AutoCAD형 명령, 치수, 레이어 및 DXF 입출력 비교 |
| Maker.js | `external_program/makerjs` | `http://127.0.0.1:8020/docs/playground/` | 코드 기반 파라메트릭 기하 생성 비교 |
## 실행과 종료
- 일괄 실행: `external_program/start-cad-demos.ps1`
- 일괄 종료: `external_program/stop-cad-demos.ps1`
- 상세 사용법: `external_program/README_CAD_DEMOS.md`
## 검증 상태
- 세 프로젝트의 프로덕션 build 성공
- 세 URL의 HTTP 200 응답 확인
- 실행 스크립트가 기록한 프로세스 트리만 종료하는 동작 확인
- OpenWebCAD Vitest worker 종료 지연, elhakimz/WebCAD 테스트 픽스처 1개 누락, 각 프로젝트 npm audit 경고는 원본 프로젝트 이슈로 기록
## 라이선스 주의
- OpenWebCAD: MIT
- Maker.js: Apache-2.0
- elhakimz/WebCAD: README에는 MIT가 명시되어 있으나 정식 LICENSE 파일이 없어 통합 전 확인 필요. `opencascade.js`는 LGPL-2.1.
+47
View File
@@ -0,0 +1,47 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[B05_Profile/B05_backend]]", "[[B06_Section/B06_backend]]", "[[auth_rbac]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-13
source: ["docs/raw/verification/2026-07-19_verify_half_width_persistence.md", "docs/raw/verification/2026-07-19_verify_B05_B06_차트_레이아웃_후속보정.md", "docs/raw/verification/2026-07-20_verify_B07_상세설계개선.md", "docs/raw/verification/2026-08-01_verify_B04_detailed_basins.md", "docs/raw/verification/2026-08-08_verify_project_delete_hard.md", "docs/raw/verification/2026-08-13_verify_rainfall_wamis_station.md"]
---
# 공통 유틸 (common_util/)
> 둘 이상의 페이지가 실제로 공유하는 경로·원자적 파일쓰기·기하 유틸만 이 폴더에 배치 (migration_plan.md 2.2)
| 파일 | 역할 | 사용처 |
|---|---|---|
| `common_util_validate.ts` | 프론트 1차 유효성 검사 (이메일/빈값/최소길이) | 전 페이지 |
| `common_util_auth.py` | 비밀번호·OTP·세션 쿠키·권한 검증, 디바이스 토큰(32B) 발급 및 SHA256 해시, HttpOnly 쿠키 헬퍼 | 전 페이지 → [[auth_rbac]] |
| `common_util_auth_repository.py` | 인증·조직·관리 Raw SQL 저장소 (신뢰 기기 토큰 검증 포함) | 인증 관련 |
| `common_util_email.py` | 비동기 SMTP 발송+재시도(최대3회) | OTP/승인 알림 |
| `common_util_email_templates.py` | 인증·조직 알림 이메일 템플릿 | common_util_email.py |
| `common_util_string.ts` | 문자열 유틸 | 미상세 |
| `common_util_storage.py` | 프로젝트·워크플로우 단계별 저장 경로 | → [[storage_paths]] |
| `common_util_project_delete.py` | 프로젝트 DB/디스크 하드 삭제 유틸 | → [[concepts/common_util/common_util_project_delete]] |
| `common_util_json.py` | JSON 원자적 저장 | workflow.json 등 |
| `common_util_atomic.py` | 임시 파일을 활용한 바이트 및 npz 데이터 원자적 저장 오퍼레이션 | [[B04_PreProcess/B04_backend]] |
| `common_util_workflow.py` | 공유 workflow.json 상태 처리 | ⚠️ [[workflow_state]] 재설계로 대체/정리 예정 |
| `common_util_resource_monitor.py` | 시스템 리소스 계측(2분 주기) + log + DB 기록 | `sample_resources_loop()` → [[B01_Dashboard/B01_backend|B01_Dashboard]] |
| `common_util_surface_confirmation.py` | 지표면 확정 params 스냅샷 저장, B05 등고선 간격 영속화(`update_contour_interval_param`), config 폴백 조회 헬퍼 | [[B03_FileInput/B03_backend]], [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `common_util_wamis_station.py` | WAMIS 621개 관측소 xlsx 기반 확률강우량 수급, 반경 10km 최대 지점 선정, Mononobe/General IDF 산출 | [[B04_PreProcess/B04_backend]], [[concepts/drainage_watershed]] |
| `common_util_wamis_rainfall.py` | WAMIS 제주 등우선 내삽(96조합) 및 +10km 범위 밖 예외 전파 커버리지 가드 (`value_at`) | [[B04_PreProcess/B04_backend]], [[concepts/drainage_watershed]] |
| `common_util_drainage_detail.py` | B04/B05 공용 배수유역/세부유역 분할 및 도로 흐름 수신사 할당 코어 알고리즘 엔진 | [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `common_util_route_profile.py` | 종단 Z 해석기 및 노선 동일성 판정 API (`resolve_route_profile`, `routes_match`) | [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `common_util_drainage_context.py` | B04/B05 배수 엔진 연동을 위한 공용 입력 콘텍스트 구조 정의 | [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `common_util_surface_sampler.py` | 종단/횡단 생성에 필요한 포인트 클라우드 지표면 고도 샘플러 | [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `common_util_drainage_pipes.py` | 관 매설 지점 정보(`pipe_points.json`) 저장 및 원청 CSV 해시 검증 | [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `common_util_http_cache.py` | HTTP cache-control, ETag 헤더 기반 304 Not Modified 캐시 유틸 | [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_backend]] |
| `B05_Profile_Engine_Sections.py:prune_stale_cross_files` | 유효 측점 목록(`stations`) 기반 구버전 잔재 `cross_*.json` 자동 삭제 및 오삭제 방지 가드 | [[B05_Profile/B05_backend]], [[B06_Section/B06_backend]], [[B08_DesignDetail/B08_backend]] |
| `common_util_format.py` | 포맷 유틸 | 미상세 |
## 이메일 발송 (common_util_email.py)
- 개발: Google Gmail SMTP / 상용: Google Workspace 또는 AWS SES
- 발송 유형: OTP, 가입확인, 팀원승인요청(ADMIN), 승인/거부결과, 회사참여신청(SYSTEM_ADMIN), 인증갱신알림
## 리소스 모니터링 (common_util_resource_monitor.py)
- `main.py` lifespan에서 `asyncio.create_task` 등록/취소
- 계측: `psutil.cpu_percent`, `psutil.virtual_memory().percent`, `shutil.disk_usage`
- 이중 기록: `system_resources` 테이블 (DB) + `log/system_resources.log` (탭 구분 1줄, `.gitignore`)
- 30일 롤링 삭제 (DB `DELETE`, 로그파일 오래된 줄 제거)
@@ -0,0 +1,20 @@
---
type: concept
status: draft
related_pages: ["[[architecture/shared_resources]]"]
source_file: "common_util/common_util_project_delete.py"
last_updated: 2026-08-08
---
# common_util_project_delete.py
프로젝트 삭제 시 DB 행(ON DELETE CASCADE 연쇄 소멸) 및 물리 영구저장소 디스크 폴더(`storage/{회사}/{사용자}/{프로젝트ID}/`)를 통째로 지우는 하드 삭제 비즈니스 로직을 담당하는 공통 유틸리티 모듈입니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `hard_delete_project()` | `common_util/common_util_project_delete.py` | 트랜잭션 내에서 `storage_path` 조회 및 검증 후 `projects` 행 DELETE, `PROJECT_HARD_DELETE` 감사 로그 추가를 처리하고 커밋 성공 시 rmtree 물리 삭제를 실행 |
## 🔗 역참조 (사용처)
- [[B01_Dashboard/backend/B01_Dashboard_Router]] (스위치에 따른 프로젝트 하드 삭제 API 호출)
@@ -0,0 +1,25 @@
---
type: concept
status: draft
related_pages: ["[[architecture/shared_resources]]"]
source_file: "common_util/common_util_storage.py"
last_updated: 2026-08-08
---
# common_util_storage.py
프로젝트 파일 저장소의 상대 경로 및 루트 절대 경로 안전 변환/검증을 담당하는 공통 물리 파일 시스템 유틸리티 모듈입니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `resolve_stored_project_path()` | `common_util/common_util_storage.py` | DB에 저장된 프로젝트 저장소 상대 경로를 물리 시스템 절대 경로로 해석 반환 (필요 시 디렉터리 생성) |
| `resolve_project_root_for_delete()` | `common_util/common_util_storage.py` | 삭제용 경로를 검증 해석하여 물리 절대 경로 반환 (디렉터리를 생성하지 않고 4단계 보안 가드 적용) |
| `ensure_project_directory()` | `common_util/common_util_storage.py` | 프로젝트 저장소 디렉토리 존재 보장 및 생성 |
## 🔗 역참조 (사용처)
- [[B01_Dashboard/backend/B01_Dashboard_Router]] (하드 삭제 스위치 시 rmtree 경로 획득 목적)
- [[B03_FileInput/backend/B03_FileInput_Router]]
- [[B04_PreProcess/backend/B04_PreProcess_Router]]
- [[B05_Profile/backend/B05_Profile_Router]]
@@ -0,0 +1,26 @@
---
type: concept
status: draft
related_pages: ["[[architecture/shared_resources]]"]
source_file: "common_util/common_util_workflow_state.py"
last_updated: 2026-07-24
---
# common_util_workflow_state.py
`project_workflow_stages` DB 테이블과 직접 연동하여 7단계(Stage 1~7) 워크플로우 진행 상태(`IN_PROGRESS`, `COMPLETE`, `STALE`, `FAILED`)를 원자적 트랜잭션으로 전이 및 관리하는 백엔드 공통 유틸리티 모듈입니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `get_workflow_state()` | `common_util/common_util_workflow_state.py` | 프로젝트의 7개 스테이지 전이 상태 및 파라미터 맵 조회 |
| `start_stage()` | `common_util/common_util_workflow_state.py` | 지정 스테이지를 `IN_PROGRESS`로 바꾸고 파라미터를 JSON 저장 |
| `complete_stage()` | `common_util/common_util_workflow_state.py` | 지정 스테이지를 `COMPLETE`로 변경 |
| `fail_stage()` | `common_util/common_util_workflow_state.py` | 지정 스테이지를 `FAILED`로 기록 |
| `invalidate_subsequent_stages()` | `common_util/common_util_workflow_state.py` | 상위 스테이지 파라미터 변경 시 하위 스테이지들을 `STALE`로 전이 |
## 🔗 역참조 (사용처)
- `[[B04_PreProcess/backend/B04_PreProcess_Router]]`
- `[[B05_Profile/backend/B05_Profile_Router]]`
- `[[B06_Section/backend/B06_Section_Router]]`
+100
View File
@@ -0,0 +1,100 @@
---
type: concept
status: stable
related_pages: ["[[B03_FileInput/B03_backend]]", "[[B05_Profile/B05_frontend]]", "[[B06_Section/B06_frontend]]", "[[B07_Quantity/B07_frontend]]", "[[B08_DesignDetail/B08_frontend]]"]
last_updated: 2026-08-29
source: ["docs/raw/plans/2026-08-29_plan_B05_B06_structure_ui_unification.md", "docs/raw/plans/2026-08-29_plan_B07_CAD_scale_sheet_layout.md", "docs/raw/verification/2026-08-29_verify_B03_reupload_reanalysis_cache.md"]
---
# 2026-08-29 완료 반영
## B03 재업로드·B05 최신 조회
| 항목 | 위치 | 역할 |
|---|---|---|
| `_complete_file_input_if_ready()` | `B03_FileInput/B03_FileInput_Router.py:153` | 동일 파일 전송을 생략해도 완료 요청이면 하위 산출물을 초기화하고 WF1 재실행 |
| 업로드 완료 캐시 정리 | `B03_FileInput/B03_FileInput_UI_Page.ts:71` | route·section detail·preload 브라우저 캐시 제거 |
| `loadLatest(true)` | `B05_Profile/B05_Profile_UI_Page.ts:747` | B05 최초 접근에서 DB 최신 노선을 강제 조회 |
재업로드 버튼은 파일 변경 의사로 취급한다. 바이트가 같아 전송을 생략해도 자동계산 차단을 해제하고 재분석하며, B05 초기 진입의 빈 종단·유토곡선·테이블을 유발하던 오래된 route 캐시를 사용하지 않는다.
## B05/B06 구조물 UI 통합
| 항목 | 위치 | 역할 |
|---|---|---|
| 공용 구조물 진입점 | `A00_Common/b_structures_section.ts` | B05 구조물 배치 구현과 스타일을 B05·B06에 동일 공급 |
| B06 구조물 패널 | `B06_Section/B06_Section_UI_Page_Structures_Panel.ts` | 구조물 폼·목록 dock·횡단 조정 장착 |
| `focusStation()` | `B06_Section/B06_Section_UI_Section_View.ts:714` | 구조물 선택 시 최근접 횡단 카드 선택·스크롤 |
| `wireStructureSelection()` | `B06_Section/B06_Section_UI_Page_Structures_Panel.ts:371` | 횡단 구조물 선택을 좌측 폼과 연결 |
B06 A군 시설 추가·이동·삭제, 중복 제어 정리, B05 대형 패널 분리와 3D 개별 선택은 상시계획서 후속이다.
## B07 CAD 고정 척도·횡단 장 배치
| 항목 | 위치 | 역할 |
|---|---|---|
| 도면 척도 | `config/config_system.py:754` | 종단 1/1,000·1/200, 횡단 1/100 고정 |
| `_section_window()` | `B07_DesignDetail/B07_DesignDetail_Engine_Cad.py:337` | 설계선·원지반 교차 범위와 여유로 측점별 표시 폭 결정 |
| `plan_cross_sheets()` | `B07_DesignDetail/B07_DesignDetail_Engine_Cad_Sheet.py:84` | 횡단 블록을 좌하단부터 아래→위·좌→우 순서로 장 배치 |
| `DRAWING_GROUPS` | `B07_DesignDetail/B07_DesignDetail_UI_Page.ts:78` | 좌측 도면 12분류와 미구현 항목 비활성 표시 |
A1 고정 도각에서 시험 노선 종단 1장, 횡단 23측점 4장을 확인했다. `DRAWING_FORMAT` 8 상향과 장 단위 확정 실측은 상시계획서 후속이다.
## B07 CAD 테마
| 항목 | 위치 | 역할 |
|---|---|---|
| `theme.ts` | `openwebcad/src/theme.ts` | 부모 `frd_theme`와 CAD iframe 테마 동기화 |
| `paintColor()` | `openwebcad/src/theme.ts` | 저장 도면 색상을 화면 테마에 맞춰 표시 보정 |
| `bumpSceneVersion()` | `openwebcad/src/theme.ts` | 테마 전환 시 정적 장면 캐시 재생성 |
라이트·다크 토큰, 캔버스·도면 색상, 동일 오리진 `storage` 이벤트 동기화를 사용자 검증 완료로 기록했다.
## B07 CAD 확대·팬
| 항목 | 위치 | 역할 |
|---|---|---|
| `handleMouseWheel()` | `openwebcad/src/input-controller.ts` | 캔버스 핀치 기본 확대 차단 및 확대 처리 |
| `panScreen()` | `openwebcad/src/` | 트랙패드 두 손가락 이동을 팬으로 처리 |
마우스 휠은 델타 비례 확대, 트랙패드는 팬, `ctrl+wheel`은 CAD 내부 핀치로 처리한다. 핀치·팬 방향과 콘솔 로그 제거는 후속 결정이다.
## B07↔B08 순서
| 항목 | 변경 |
|---|---|
| workflow | 4=상세설계, 5=수량산출 |
| 폴더·라우트 | `B07_DesignDetail`·`b07-design-detail`, `B08_Quantity`·`b08-quantity` |
| 예외 | iframe 내부 `aislo:b08:*` 프로토콜·패키지명은 호환성 때문에 유지 |
폴더, 식별자, locale, stage, CAD 정적 경로 교환을 완료했다.
## 초기값 보전
| 항목 | 위치 | 역할 |
|---|---|---|
| `designing_lock_path()` | `common_util/common_util_initial_snapshot.py` | 계산 중 진입 차단 마커 경로 |
| `discard_initial_snapshot()` | `common_util/common_util_initial_snapshot.py` | 재설계 시 초기 스냅샷 무효화 |
| `routeAfterPreloadCheck` | `A00_Common/b_workflow_nav.ts` | `initial_design`이면 B11 준비 화면으로 라우팅 |
| `reset_route_design` 폴백 | `B05_Profile/B05_Profile_Router.py` | 재계산 전 편집 정본 삭제 |
계산 중 B05·B06 진입 차단, 재설계 시 스냅샷 삭제, 편집 정본 분리와 초기화 복원 실측을 완료로 기록했다. 새 업로드 화면 실측은 후속이다.
## 초기화 복원 실측
| 항목 | 확인 |
|---|---|
| 복원 응답 | `restored=true`, 기존 route 삭제 후 새 route 삽입 |
| 정본 복원 | 연장 350.11m·관 지점 4건이 스냅샷 값으로 복귀 |
| 처리 시간 | 복원 3초 이내, 폴백 재계산은 10초 이상 |
| 작업본 | 초기값 상태로 종결 |
## 배수시설 추천 기준
| 판단 대상 | 기준 |
|---|---|
| 관경 | Kirpich tc(하한 5분) → IDF → 합리식 Q → 2.0배 → Manning 유효직경 |
| 부속 | 유량이 아니라 계곡·옆도랑·변곡점·성토 위치 등 지형·배치로 판단 |
| 현재 단서 | 관 생성 사유 `source`, 종단 오목 변곡점, B06 성토부선·다단 기슭막이 |
상세 산식·DEM 기반 지형 보강·임계값 협의는 미결이다.
@@ -0,0 +1,37 @@
---
type: concept
status: stable
related_pages: ["[[B04_PreProcess/B04_backend]]", "[[B04_PreProcess/B04_frontend]]", "[[B05_Profile/B05_structures]]", "[[B05_Profile/B05_frontend]]", "[[B06_Section/B06_culvert_controls]]"]
last_updated: 2026-09-01
source: ["docs/raw/plans/2026-09-01_plan_B04_B05_B06_completed_work.md", "docs/raw/verification/2026-09-01_verify_B04_B05_B06_completed_work.md"]
---
# 2026-09-01 완료 — B04 지면 처리·B05/B06 배수 제어
## 완료 범위
| 항목 | 위치 | 역할 |
|---|---|---|
| `append_pipe_points_file()` | `common_util/common_util_drainage_pipes.py` | 저장된 노선 지문을 유지하며 레거시 기슭막이를 관 지점 정본에 추가 |
| `MigrationPlan`·`migrate_irregular_stations()` | `B05_Profile/B05_Profile_Structures_Migration.py` | 레거시 후보를 일반 구조물과 관 시설로 분리 |
| `migrate_structures()` | `B05_Profile/B05_Profile_Structures_Router.py` | 관 지점 파일이 있을 때만 기슭막이를 이관하고 이력을 기록 |
| `enforce_pipe_clearance` | `B05_Profile/`·`B06_Section/` | 횡단배수 최소고 강제를 사용자 선택 옵션으로 저장·전달 |
| `resolve_auto_source_filters()` | `B04_PreProcess/B04_PreProcess_Engine_Ground.py` | 분류 LAS는 classification+csf, 미분류 LAS는 csf를 자동 생성 |
| `build_ground_masks()` | `B04_PreProcess/B04_PreProcess_Engine_Ground.py` | CSF·grid·classification 지면 마스크 생성과 비율 경고 |
| `SURFACE_AUTO_METHODS` | `config/config_system.py` | 자동 생성은 기본 dtm 조합으로 제한하고 나머지는 요청 시 생성 |
| `analyzeSurface()` | `B04_PreProcess/B04_PreProcess_Api_Fetch.ts` | 저장되지 않은 필터·표현 조합의 온디맨드 생성 요청 |
## 저장·호환 규칙
- 레거시 기슭막이는 `facility=revetment`인 `pipe_points.json` 항목으로 이관한다.
- 관 지점 파일이 없으면 기슭막이 이력은 남기지 않아 B04 산출 후 다시 시도한다.
- 이관 시 기존 `route_signature`를 유지하며 같은 항목을 중복 추가하지 않는다.
- 지표면 manifest 서명은 생성 대상 목록과 분리되어 이미 만든 조합을 재사용한다.
- `classification` 필터는 class 2가 유효할 때만 자동 후보가 된다.
## 검증
- Python 교차검증: 36 passed.
- TypeScript 타입검사: 통과.
- B07 CAD 편의성 작업은 별도 전체 시험 실패로 완료 범위에서 제외했다.
@@ -0,0 +1,27 @@
---
type: concept
status: stable
related_pages: ["[[completed_2026-09-01]]", "[[completed_2026-08-29]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[B05_Profile/B05_frontend]]", "[[B08_DesignDetail/B08_frontend]]"]
last_updated: 2026-09-01
source: ["docs/raw/plans/2026-09-01_plan_remaining_checked_items.md", "docs/raw/plans/2026-09-01_plan_implementation_verification_hold.md", "docs/raw/plans/2026-09-01_plan_implementation_verification_context_hold.md", "docs/raw/verification/2026-09-01_verify_remaining_checked_items.md"]
---
# 2026-09-01 잔여 완료 체크 정리
상시 계획서의 혼합 섹션에 남아 있던 완료 체크 37개를 추가 아카이빙한 원장이다. 세부 구현 정의는 기존 기능별 위키를 정본으로 유지한다.
## 범위
| 영역 | 완료 내용 | 상세 위키 |
|---|---|---|
| B03/B04 | shapefile 노선 병합, 곡선 경고 현행 유지, 라이다·도엽 서피스 정합 조사 | [[B03_FileInput/B03_backend]], [[B04_PreProcess/B04_backend]] |
| B05/B06 | 구조물 UI 중복 정리와 관련 후속 판정 | [[B05_Profile/B05_frontend]], [[B06_Section/B06_frontend]] |
| B08 CAD | 전환·커서·패널, 잠금 도면층, 도각·표지·유역도 표현, 프로젝트 소유 검증 | [[B08_DesignDetail/B08_CAD_interaction]], [[B08_DesignDetail/B08_frontend]] |
| 좌표계 | 배수유역 역투영, 저장 좌표계, 도엽·라이다 공통 화면 원점 | [[crs_metadata]], [[drainage_watershed]] |
## 보류 구분
- B07 편의성 구현 기록은 CAD 전체 시험 실패로 완료 범위에 포함하지 않았다.
- B07 항목은 상시 계획서에서 재검증 대기 미체크 항목으로 유지한다.
- 노선 원천화·B04 3D 트림·보조 포트 분리의 구현 완료 기록은 별도 검증 보류 원문으로 분리하고, PLAN에는 실데이터·직접 기동 검증만 유지한다.
- PRJ 관련 기존 실패 10건 분류는 결론이 나지 않아 미체크 확인 과제로 바로잡았다.
@@ -0,0 +1,46 @@
---
type: concept
status: stable
related_pages: ["[[B04_PreProcess/B04_frontend]]", "[[B05_Profile/B05_backend]]", "[[B05_Profile/B05_corridor_cut_fill]]", "[[B08_DesignDetail/B08_frontend]]", "[[B08_DesignDetail/B08_CAD_title_block]]"]
last_updated: 2026-09-02
source: ["docs/raw/plans/2026-09-02_plan_completed_items.md", "docs/raw/plans/2026-09-02_plan_user_verified_completed_items.md", "docs/raw/plans/2026-09-02_plan_B05_profile_edit_followup_completed.md"]
---
# 2026-09-02 완료 항목
## 노선·지표면
- 용화 관 11개 측점은 트림 노선 0~1070.39m 안에 있고, 종단 PVI 13개가 관 측점과 일치한다.
- 용화 노선은 트림·조밀화 뒤 323정점·1070.39m이며 B04 최고 표고 평면에 표시된다.
- B04 화면맞춤은 전체 노선을 포함하고 종단 생성 경로는 `pipe_anchored`와 `station_alignment`로 구분한다.
- 용화 관 측점 11개의 재계산 계획고와 지반고 차이는 0.000m다.
## 작업 환경
- 보조 워크트리는 8001·5174, 메인 환경은 8000·5173으로 동시에 기동한다.
- CAD `dist/`는 서버 기동 빌드 체인에 포함되며 재시작 절차는 `CLAUDE.md`에 있다.
## CAD
- `desynchronized` 저지연 캔버스는 스냅 결함 때문에 철회된 상태다.
- 일반 그룹의 `groupId`는 JSON 저장·복원 시 ID 기준으로 왕복한다.
- CAD 패널 폭은 300px이며 반복 `setScreenScale` 콘솔 로그는 제거됐다.
- 명령행은 기본 숨김이며 전체 CAD 회귀 시험 87건이 통과했다.
- 표제란·표지는 프로젝트·회사·담당자·축척·날짜·도면번호를 공통 치환 경로로 공급한다.
- 회사 로고·서명 자산과 회사 도각 편집·기본 복원 경로가 연결됐다.
## B05 구조물 3D
- 평면 진단 스케치는 기본 숨김이며 디버그 스위치로 다시 표시한다.
- `patch`·`patchClip` 저장 왕복, BOX 패치 클리핑, 마스크 고리 단순화 결함을 반영했다.
- 지형 클리핑 윤곽 확장은 실측 최대 초과 0.23m라 현행 유지로 닫았다.
## B05 종단 편집 후속
- 최소고 판정은 `_Profile_Panel.applyEdits` 단일 창구에서 모든 편집 경로에 적용된다.
- 종단 편집 이력은 `b05:pipes` 관 목록도 함께 기록해 되돌리기에서 구조물 위치를 복원한다.
## 회귀 상태
- Python `tmp/tests/`는 343 passed, 17 skipped, 0 failed다.
- 별도 CAD 전체 시험은 87건 통과로 [[B08_DesignDetail/B08_CAD_usability_2026-09-01]]에서 완료 처리했다.
@@ -0,0 +1,29 @@
---
type: concept
status: stable
related_pages: ["[[B03_FileInput/B03_route_snapshot_crs]]", "[[B04_PreProcess/B04_drainage_compass_crs]]", "[[B05_Profile/B05_masshaul_structure_2026_09]]", "[[B06_Section/B06_masshaul_culvert_2026_09]]", "[[B08_DesignDetail/B08_cad_delivery_2026_09]]"]
last_updated: 2026-09-03
source: ["docs/raw/plans/2026-09-03_plan_completed_items.md"]
---
# 2026-09-03 완료 — 입력·배수·종횡단·CAD
사용자와 개발 담당 AI가 검증을 완료한 47개 항목이다. 사용자 지시에 따라 위키 관리자의 별도 2차 교차검증과 검증보고서는 생략했다.
## 완료 범위
| 영역 | 완료 내용 | 상세 |
|---|---|---|
| B03 | shapefile 변환 CSV 정본, LAS 없는 도엽 좌표계, 업로드 버튼 상태 | [[B03_FileInput/B03_route_snapshot_crs]] |
| B04 | 세부유역 다중 링·면적 보존, 종단 마루 분수령, 3D 방위, 좌표계 창구 | [[B04_PreProcess/B04_drainage_compass_crs]] |
| B05 | 유토곡선 공용화, 구조물 3D 판정, 편집 함수 유지 결정 | [[B05_Profile/B05_masshaul_structure_2026_09]] |
| B06 | I형 집수정 관 형상, 낡은 유토곡선 차단, 사면 경고, 파일 분리 | [[B06_Section/B06_masshaul_culvert_2026_09]] |
| B08 | SVG 서명, 횡단 장 확정, 해칭 절취, 자동 축척과 납품 표기 | [[B08_DesignDetail/B08_cad_delivery_2026_09]] |
## 공통 결정
- 절·성토 불균형은 자동 보정하지 않고 최종 누가토량으로 진단한다.
- B05와 B06은 같은 `mass_haul` 데이터·계산·템플릿을 사용한다.
- 세부유역은 구멍과 분리 조각을 보존하며 100㎡ 최소면적 필터를 적용하지 않는다.
- 작업 좌표계는 지형 PRJ를 우선하며 공통 해석 창구를 사용한다.
- B08 납품 도면은 길이별 자동 축척과 현행 표기 규약을 따른다.
@@ -0,0 +1,29 @@
---
type: concept
status: stable
related_pages: ["[[B03_FileInput/B03_upload_ui_2026_09]]", "[[B04_PreProcess/B04_compass_crs_2026_09]]", "[[B05_Profile/B05_profile_interaction_2026_09]]", "[[B06_Section/B06_cross_design_ui_2026_09]]", "[[B08_DesignDetail/B08_cad_delivery_2026_09]]"]
last_updated: 2026-09-03
source: ["docs/raw/plans/2026-09-03_plan_completed_items_2.md"]
---
# 2026-09-03 추가 완료 — 화면·종단·횡단
사용자와 개발 담당 AI가 검증을 완료한 추가 56개 항목이다. 사용자 지시에 따라 위키 관리자의 2차 교차검증과 별도 검증보고서는 생략했다.
## 완료 범위
| 영역 | 완료 내용 | 상세 |
|---|---|---|
| B03 | 파일 선택 화면 축소, 공용 안내 패널, LAS 없는 입력, SHP 전용 선택 | [[B03_FileInput/B03_upload_ui_2026_09]] |
| B04 | 3D 경사 나침반 링과 작업 좌표계 불일치 차단 | [[B04_PreProcess/B04_compass_crs_2026_09]] |
| B05 | 전 측점 종단곡선, 프론트 횡단 미러링, 3D 나침반 | [[B05_Profile/B05_profile_interaction_2026_09]] |
| B06 | 횡단 계산 TS 미러, 성토사면 길이, 배수관 공통 표기 | [[B06_Section/B06_cross_design_ui_2026_09]] |
| B07·B08 | 전체 성토구간 토적도 해석, 운반 블록 표시 확인, CAD 완료 판정 | [[B08_DesignDetail/B08_cad_delivery_2026_09]] |
## 최신 결정
- B03 사용자가 선택하는 계획노선은 SHP이며 CSV는 내부 계산 정본이다.
- B04 3D 방위 위젯은 축 트라이어드 시안을 거쳐 경사 나침반 링으로 확정됐다.
- B05 초기 종단선은 모든 내부 측점에 접선 종단곡선을 만들고 측점 계획고를 지반고와 맞춘다.
- 사용자 편집 중 횡단 계산은 TypeScript 미러가 즉시 수행하고 Python은 저장·검증 정본이다.
- 라이다와 도엽 좌표계 불일치는 B03 입력 단계에서 차단한다.
@@ -0,0 +1,64 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[B03_FileInput/B03_frontend]]", "[[B04_PreProcess/B04_frontend]]", "[[B05_Profile/B05_frontend]]", "[[B06_Section/B06_frontend]]", "[[B08_DesignDetail/B08_frontend]]", "[[ui_templates]]", "[[common_util]]"]
last_updated: 2026-09-04
source: ["docs/raw/plans/2026-09-04_plan_user_verified_completed_items.md", "docs/raw/plans/2026-09-04_plan_completed_items.md", "docs/raw/plans/2026-09-04_plan_700line_split.md", "docs/raw/plans/2026-09-04_plan_snapshot_before_cleanup.md"]
---
# 2026-09-04 완료 항목
사용자 검증 완료 20개 작업·체크 109개와 개발 담당 AI의 자체검증이 기록된 추가 완료 5개 작업 및 700줄 제한 분리 15개를 안정 상태로 반영했다. 추가 완료분은 2026-09-04 사용자 지시에 따라 위키 관리자의 별도 2차 교차검증과 검증보고서 작성을 생략했다. 미완료 항목이 남은 「B05 초기화 범위 확대 — 전체 결과 보존」과 착수 전인 죽은 코드·중복 코드 정리는 제외했다.
## 완료 범위
| 영역 | 완료 내용 | 관련 위키 |
|---|---|---|
| 공통 | 사용자 입력을 shapefile 중심으로 표기하고 내부 CSV 정본과 구분 | [[B03_FileInput/B03_frontend]] |
| 공통 | B03~B08 좌측 패널 제목 줄에 프로젝트명 표시 | [[ui_templates]] |
| B01 | 프로젝트 수정 시 회사 로고 기본 연결 | [[B01_Dashboard/B01_frontend]] |
| B01 | 모달 바깥 클릭 닫기와 변경 내용 확인 | [[B01_Dashboard/B01_frontend]] |
| B02·B03 | 계획노선 시·종점 누가거리 입력과 절단 여유 3m | [[B03_FileInput/B03_backend]] |
| B03 | 파일 카드 전폭 120px 미리보기, LAS 점 표본·GeoTIFF·부속 파일 정보 표시 | [[B03_FileInput/B03_frontend]] |
| B04·B05 | 배수유역도 줌 한계 확대와 노선 측점 표기 | [[drainage_watershed]] |
| B05 | 초기 진입 로딩을 3D 직전에 끝내고 3D를 후순위로 생성 | [[B05_Profile/B05_frontend]] |
| B05 | 초기화 시 계획선 편집 초안 제거와 `draft:none` 키 폐지 | [[B05_Profile/B05_frontend_alignment]] |
| B05 | 확정 시 포장 사용자 지정값 보존 확인 | [[B05_Profile/B05_structure_stations]] |
| B05 | 3D 구조물 개별 선택과 B05·B06 선택 상태 공유 | [[B05_Profile/B05_structures]] |
| B05 | 3D 절토 구간 측점 및 전체 라벨 표시 | [[B05_Profile/B05_frontend_viewer]] |
| B05 | 3D 카메라를 원근 투영으로 복원 | [[B05_Profile/B05_frontend_viewer]] |
| B05·B06 | 종단 줌 버튼 3개, 보이는 구간 Y 자동 맞춤, 유토곡선 연동 | [[B05_Profile/B05_profile_interaction_2026_09]] |
| B06 | 표준 횡단면 상세값을 단일 컨테이너로 통합 | [[B06_Section/B06_frontend]] |
| B08 도면 | 횡단면도 축척 일관성 정리 | [[B08_DesignDetail/B08_cross_structure_sheets]] |
| B08 도면 | 표준 횡단면 변수 모식도·치수·부분확대·암반선 | [[B08_DesignDetail/B08_cross_structure_sheets]] |
| B08 도면 | 계획평면도 3종에 수치등고선 배경 공유 | [[B08_DesignDetail/B08_frontend]] |
| B08 도면 | 계획평면도(라이다)에 3D 탑뷰 배치 | [[B08_DesignDetail/B08_frontend]] |
| B08 도면 | 용지도에 등고선·지적·행정구역·범례 배치 | [[B08_DesignDetail/B08_frontend]] |
## 추가 완료 범위
| 영역 | 완료 내용 | 관련 위키 |
|---|---|---|
| B03 | 업로드 카드에 경량 그래픽 미리보기와 노선·지형 범위 판정 추가 | [[B03_FileInput/B03_frontend]] |
| 공통 | B03~B08 진행단계 패널 드래그·영역 제한·열림 방향 자동 전환·세션 위치 보존 | [[ui_templates]] |
| B05 | 종단 계획선의 방향키 연속 이동과 단일 이력 처리 | [[B05_Profile/B05_profile_interaction_2026_09]] |
| B05 | 종단 X/Y 줌 조작구와 그래프·표·구조물 레인 정렬 유지 | [[B05_Profile/B05_profile_interaction_2026_09]] |
| B05 | 구조물 측점 값 열 표시 및 직선화 뒤 곡선 행 정리 | [[B05_Profile/B05_frontend]] |
## 700줄 제한 분리
- Python·TypeScript·CSS 대형 파일 15개를 기존 공개 심볼과 호출 경로를 유지한 채 하위 모듈로 분리했다.
- 최종 전수 점검에서 700줄 초과 파일은 0건이다. 자체검증 기록에는 `tsc --noEmit`, `ruff check`, 분리 전후 공개 심볼·라우트 대조, 화면 실측 및 `tmp/tests` 결과가 포함된다.
- B04 배수유역 분석 재실행 쓰기 경로는 산출물 덮어쓰기 위험 때문에 실행하지 않았다는 제한을 원문에 보존한다.
## 상시계획서 추가 완료 범위
- B03 계획노선 미리보기의 점선 상자 제거·녹색 실선, 완료 카드 파일 교체와 재분석, SHX·DBF·CPG·PRJ 상세값 및 래스터 테두리를 반영했다.
- B08 상세설계 화면의 횡단 칸 간격·리본 높이·도면 목록 라벨을 정리했다.
- B05/B06 종단·유토곡선의 변환 기반 세로 맞춤, 스크롤 성능, 완화된 창 전환, 클리핑과 구조물 누가거리 정본 맞춤을 반영했다.
- 위 완료 기록은 정리 전 상시계획서 원문 스냅샷에 보존하고, 미완료 하위 작업만 새 상시계획서로 옮겼다.
## 보존된 미완료 범위
- B05 초기화 스냅샷의 3D 코리도 포함 여부와 새 프로젝트 실경로 검증은 [[B05_Profile/B05_backend]] 관련 상시 계획으로 남아 있다.
- 죽은 코드·중복 코드 정리는 착수 지시 대기 상태이므로 완료 범위에 포함하지 않는다.
@@ -0,0 +1,32 @@
---
type: completion-summary
status: stable
related_pages: ["[[architecture/workflow_data_flow]]", "[[B05_Profile/B05_backend]]", "[[B06_Section/B06_backend]]", "[[B07_DesignDetail/B07_frontend]]", "[[B08_Quantity/B08_overview_2026_09]]"]
last_updated: 2026-09-09
source: ["docs/raw/plans/2026-09-07_plan_completed_items.md", "docs/raw/plans/2026-09-07_plan_completed_items_2.md", "docs/raw/plans/2026-09-07_plan_completed_items_3.md", "docs/raw/plans/2026-09-07_speed_watershed_shelved.md"]
---
# 2026-09-07 완료·보류 요약
## 완료 범위
| 영역 | 완료 내용 | 근거 상태 |
|---|---|---|
| 공통 | 노선 자동탐색 중단, 평면 법정검사, 계획노선 폴리라인·직선-곡선-직선 계약 | 사용자 확정과 자체검증 기록 |
| 공통 | B05·B06 캐시·세션 및 계산 자리 일원화, 노선 변경 후속 데이터 규칙 | 완료 아카이브 기록 |
| B01·B02 | 권한·회사·프로젝트 연결과 화면 후속 | 완료 아카이브 기록 |
| B03·B04 | 라이다 다중 파일 병합, LAS 없는 입력 검사, 대형 파일 분리 | 완료 아카이브 기록 |
| B05 | 구조물 선택 전달, 팬·테이블·유토곡선 UI, 누가거리 정본, 초기값 실경로 | 사용자 실측·자체검증 기록 |
| B06 | 곡선부 확폭, 구조물 절·성토 면적, 기슭막이 분리·연계, 소단·절토경사 입력 | 사용자 실측·자체검증 기록 |
| B07 | 외부 도각, DXF·DWG 내보내기, LibreDWG, 자리표 편집 | 완료 아카이브 기록 |
## 성능·운영 결정
- 노선 확인 시간은 293초에서 약 90초로 줄인 상태를 종료 기준으로 채택했다.
- 유역 속도 개선의 별도 갈래 3개는 구현하지 않기로 하고 보관본에 남겼다.
- 백엔드 감시 중단과 Vite IPv6 프록시 문제의 재발 방지 기록을 보존했다.
## 주의
- 이 페이지는 이관 문서의 완료 선언과 자체검증을 요약한다. 독립 검증보고서가 없는 항목은 세부 수치보다 원문 근거를 우선한다.
- 이후 2026-09-08~09 변경은 [[quantity_cost_contract]]와 각 B08·B09 페이지를 기준으로 판정한다.
+40
View File
@@ -0,0 +1,40 @@
---
type: concept
status: stable
related_pages: ["[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[dependencies]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-16
source: ["docs/raw/plans/2026-07-18_plan_crs_normalization.md", "docs/raw/verification/2026-07-18_verify_crs_and_polling_log.md"]
---
# CRS 메타데이터 정상화
## 검증된 판정
| 항목 | 위치 | 역할·판정 |
|---|---|---|
| `normalize_crs_metadata()` | `B03_FileInput/B03_FileInput_Engine_Analyze.py` | 복합 CRS를 수평·수직 요소로 분리하고 JSON 직렬화 가능한 공통 구조로 정규화 |
| `epsg` | B03 분석 메타데이터 | 복합 CRS 전체가 아니라 지도 변환에 쓰는 수평 EPSG를 유지; 실제 자료에서 `5187` 확인 |
| `horizontal_crs` | B03 분석 메타데이터 | 수평 CRS 식별 결과와 authority 보존 |
| `vertical_crs` | B03 분석 메타데이터 | KNGeoid24 같은 수직 기준을 수평 CRS와 분리 보존 |
| `crs_status` | B03 분석 메타데이터 | `identified`, `custom_vertical_crs`, `unknown_horizontal_crs`, `missing_crs` 구분 |
| `custom_authority_codes` | B03 분석 메타데이터 | KNGeoid24 WKT의 사설 코드 표식을 파싱용 WKT와 분리해 원문 정보 보존 |
## 데이터 흐름
| 생산자 | 처리 | 소비자 |
|---|---|---|
| GeoTIFF·PRJ·LAS 업로드 | `normalize_crs_metadata()` | `input_files` 메타데이터 및 B04/B05 좌표 변환 |
| 복합 CRS | 수평 EPSG와 수직 기준 분리 | `epsg=5187`, `vertical_crs=KNGeoid24` 형태 |
| 알 수 없는 수평 CRS | 추측하지 않고 `epsg=None` | 사용자 확인이 필요한 `unknown_horizontal_crs` 상태 |
## 검증 범위와 모순 이력
- 실제 `result.tif`, `result.prj`, `cloud_merged.las`로 수평 EPSG 5187과 KNGeoid24 분리 처리가 검증됐다.
- 같은 검증보고서에서 B04 status 폴링 로그 제거 방식은 전체 access log를 꺼 부작용이 있어 FAIL이었다.
- 해당 B04 실패는 후속 B04 검증에서 `access_log=False` 롤백과 일반 사용자 진입 가드 방식으로 대체됐다. CRS 정상화 PASS와 B04 폴링 FAIL을 하나의 상태로 합치지 않는다.
## 사용처
- [[B03_FileInput/B03_backend]] — 업로드 파일 메타데이터 분석과 DB 저장
- [[B04_PreProcess/B04_backend]] — 지표면·GIS 처리 좌표 기준
- [[dependencies]] — Rasterio/Pyproj PROJ 런타임 차이 모니터링
@@ -0,0 +1,98 @@
---
type: concept
status: stable
related_pages: ["[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-17
source: docs/raw/verification/2026-07-17_verify_b04_confirm_and_2d_map.md
---
# DB: 파일/지표면분석 테이블
← [[db_schema/overview]]
## upload_sessions (업로드 세션)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `varchar(36)` | NO | PRI | 세션 UUID |
| `project_id` | `varchar(36)` | NO | MUL | FK→projects.id |
| `original_filename` | `varchar(255)` | NO | | 원본 파일명 |
| `file_size_bytes` / `chunk_size_bytes` | `bigint(20)` | NO | | 파일크기 / 청크크기 |
| `total_chunks` / `completed_chunks` | `int(11)` | - | | 전체 청크수 / 완료 청크수 |
| `status` | `enum('PENDING','IN_PROGRESS','COMPLETED','FAILED')` | YES | MUL | `PENDING` |
| `created_at` / `updated_at` | `timestamp` | YES | | 생성 / 최종수정 일시 |
## upload_chunks (업로드 청크 데이터)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `session_id` | `varchar(36)` | NO | MUL | FK→upload_sessions.id |
| `chunk_index` | `int(11)` | NO | | 청크 인덱스 (0, 1, 2...) |
| `chunk_hash` | `varchar(64)` | YES | | 청크 검증용 체크섬 |
| `size_bytes` | `bigint(20)` | NO | | 청크 용량 |
| `stored_at` | `varchar(255)` | YES | | 임시 파일 저장 경로 |
| `completed_at` | `timestamp` | YES | MUL | 완료 일시 |
## input_files (입력 원본 파일)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `file_type` | `varchar(50)` | YES | | `las`/`tif`/`prj`/`tfw`/`dxf` 등 |
| `original_filename` / `raw_file_path` | `varchar` | NO | | 파일명 / storage 상대경로 |
| `file_size_mb` | `float` | YES | | 파일 크기 (MB) |
| `upload_by` / `upload_at` | - | - | MUL | 업로드 유저 FK / 일시 |
| `crs_epsg` | `int(11)` | YES | | EPSG 좌표계 정보 |
| `metadata` | `longtext` | YES | | 헤더/포인트수 등 분석 JSON |
| `status` | `varchar(50)` | YES | | `UPLOADED` ➡️ `PROCESSED` ➡️ `ARCHIVED` |
## processed_point_cloud (필터/변환 포인트클라우드)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `input_file_id` / `project_id` | - | NO | MUL | FK→input_files / projects |
| `process_type` | `varchar(50)` | YES | | 변환 필터 분류 |
| `processed_file_path` / `converted_file_path` | `varchar` | YES | | 저장 경로 / PLY/LAZ 경로 |
| `converted_format` | `varchar(50)` | YES | | 변환 포맷 |
| `point_count` | `int(11)` | YES | | 포인트 개수 |
| `min_z` / `max_z` / `mean_z` | `float` | YES | | 고도 최저 / 최고 / 평균 |
| `x_min` ~ `y_max` | `float` | YES | | X/Y 좌표 바운딩 박스 범위 |
| `density_per_sqm` | `float` | YES | | ㎡당 점 밀도 |
| `classification_summary` | `longtext` | YES | | ground/unclassified 통계 |
| `processing_params` | `longtext` | YES | | 분석 파라미터 JSON |
| `processed_at` / `status` | - | - | | 변환 일시 / `PROCESSING`\|`COMPLETE`\|`FAILED` |
## surface_models (지표면 모델 및 등고선)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `model_type` | `varchar(50)` | YES | | `dem_grid`/`tin`/`mesh`/`contour` |
| `source_file_id` / `processed_cloud_id` | `int(11)` | YES | MUL | FK→input_files / processed |
| `status` | `varchar(50)` | YES | | `PROCESSING` ➡️ `COMPLETE` / `FAILED` / `CONFIRMED` |
| `crs_epsg` / `resolution_m` | - | YES | | EPSG 좌표 / DEM 격자 해상도 |
| `model_file_path` | `varchar(500)` | YES | | 스토리지 상대 경로 |
| `generation_params` | `longtext` | YES | | 격자화 알고리즘 인자 JSON |
| `created_at` / `completed_at` | `timestamp` | - | | 생성 / 완료 일시 |
## terrain_layers (지형 레이어)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `surface_model_id` | `int(11)` | NO | MUL | FK→surface_models.id |
| `layer_name` | `varchar(100)` | YES | | 레이어 영문/한글 식별자 |
| `geometry_type` | `varchar(50)` | YES | | `POINTCLOUD`/`GRID`/`MESH`/`CONTOUR` |
| `layer_file_path` | `varchar(500)` | YES | | 개별 레이어 실 파일 경로 |
| `file_format` / `file_size_mb` | - | YES | | 포맷 (ply, tfw, las 등) / 크기 |
| `statistics` | `longtext` | YES | | 통계 수치 JSON |
| `created_at` | `timestamp` | NO | | 생성 일시 |
## input_files.status 값
`UPLOADED → PROCESSED → ARCHIVED`
## surface_models.status 값
`PROCESSING → COMPLETE / FAILED / CONFIRMED` (CONFIRMED는 사용자가 해당 모델을 설계 지표면 정보로 최종 확정했음을 의미)
## processed_point_cloud.status 값
`PROCESSING → COMPLETE / FAILED`
관련 함수 위치 → [[B04_PreProcess/B04_db]], 사용 라이브러리 → [[dependencies]]
@@ -0,0 +1,99 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-19
source: raw/guidelines/db_schema.md, raw/guidelines/backend.md, docs/raw/verification/2026-07-12_verify_add_phase4_role.md
---
# DB: 로그/모니터링 테이블
← [[db_schema/overview]]
## login_logs (로그인 시도 로그)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `bigint(20)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | YES | MUL | FK→users.id |
| `email` | `varchar(255)` | NO | | |
| `status` | `enum('SUCCESS','FAILURE')` | NO | | |
| `failure_reason` / `user_agent` | `varchar(100)` / `text` | YES | | |
| `login_at` | `timestamp` | NO | MUL | `current_timestamp()` |
## activity_logs (사용자 활동 로그)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `bigint(20)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | NO | MUL | FK→users.id |
| `action_type` | `varchar(100)` | NO | | 행위 종류 |
| `action_at` | `timestamp` | NO | | `current_timestamp()` |
| `resource_id` / `status` | `varchar(255)` / `enum` | - | | 리소스 ID / SUCCESS\|FAILURE |
| `details` | `longtext` | YES | | JSON 상세 데이터 |
## audit_logs (감사 로그)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | YES | MUL | FK→users.id |
| `action` / `entity_type` | `varchar(100)` | YES | | CRUD/EXPORT/DOWNLOAD 등 |
| `entity_id` | `varchar(36)` | YES | | 대상 UUID 등 |
| `timestamp` / `ip_address` | `timestamp` / `varchar(45)` | - | | 발생시각 / IP 주소 |
| `details` | `longtext` | YES | | JSON 상세 |
## system_audit_logs (프로젝트/조직 변경 감사 로그)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | NO | MUL | FK→users.id (행위자) |
| `action` / `resource_type` | `varchar(50)` | - | | PROJECT_CREATE 등 / 종류 |
| `resource_id` | `int(11)` | YES | | |
| `timestamp` | `timestamp` | YES | MUL | `current_timestamp()` |
| `ip_address` / `user_agent` | `varchar(50)` / `text` | YES | | IP 주소 / 브라우저 에이전트 |
## system_admin_logs (시스템 관리자 행위 로그)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `bigint(20)` | NO | PRI | `auto_increment` |
| `admin_user_id` | `int(11)` | NO | MUL | FK→users.id (관리자 ID) |
| `action_type` / `target_id` | `varchar(100)` / `varchar(255)`| - | | 변경종류(USER_STATUS) / 대상 ID |
| `action_at` | `timestamp` | NO | | `current_timestamp()` |
| `details` | `longtext` | YES | | JSON 형태의 변경 상세 |
## system_resources (시스템 자원 계측)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `timestamp` | `timestamp` | YES | MUL | `current_timestamp()` |
| `cpu_usage_percent` / `memory_usage_percent` | `float` | YES | | |
| `disk_usage_percent` / `total_storage_mb` | `float` | - | | 디스크사용률 / 전체 스토리지 용량 |
| `active_user_count` / `active_project_count` | `int(11)` | NO | | 활성 사용자 / 프로젝트 수 |
## support_requests (기술 지원 요청)
*실 DB 대조 및 A08 백엔드 코드와 100% 정합함 확인 완료 (계획 당시의 user_id/title 컬럼 스펙은 폐기됨).*
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `company_id` | `int(11)` | YES | MUL | FK→companies.id |
| `company_name` / `user_name` | `varchar(255)` | - | | 회사명 / 작성자명 |
| `user_email` / `user_phone` | `varchar(255)` / `varchar(30)` | - | | 이메일 / 전화번호 |
| `subject` / `message` | `varchar(255)` / `text` | NO | | 제목 / 문의 메시지 본문 |
| `status` | `enum('NEW','REVIEWED','RESOLVED','DELETED')` | NO | MUL | `NEW` |
| `reviewed_by` | `int(11)` | YES | MUL | FK→users.id (검토자) |
| `created_at` / `reviewed_at` / `review_notes` | - | - | | 접수 / 검토일시 / 메모 |
## change_logs (설계 변경 이력)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | | FK→projects.id |
| `changed_by` | `int(11)` | YES | MUL | FK→users.id (수정자) |
| `changed_at` | `timestamp` | NO | | `current_timestamp()` |
| `entity_type` / `entity_id` | `varchar(100)` / `int(11)` | YES | | 대상엔티티(routes 등) / 대상 PK |
| `old_value` / `new_value` | `longtext` | YES | | 변경 전 / 후 JSON 스냅샷 |
| `reason` | `varchar(255)` | YES | | 변경 사유 |
**사용처:** [[B01_Dashboard/B01_backend|B01_Dashboard]] (리소스·로그 섹션), [[A08_Support/A08_backend|A08_Support]] (support_requests INSERT)
## system_audit_logs — 사용처 (B01, B02)
- **프로젝트 생성**: `B02_ProjRegister_Repository.py:92` (`PROJECT_CREATE` 기록 ➡️ [[B02_ProjRegister/B02_backend]])
- **기타 관리 행위**: `B01_Dashboard_Repository.py:245,265` (수정·삭제), `:336` (회사 생성), `:609` (감사 로그 조회), `:758` (자동화 제어)
## 리소스 API (SYSTEM_ADMIN 전용)
`GET /api/dashboard/admin/resources?days=30` (실시간 계측 `current`, 30일 다운샘플링 시계열 `history` 및 활성 지표 `stats` 제공)
+64
View File
@@ -0,0 +1,64 @@
---
type: concept
status: draft
related_pages: ["[[architecture/shared_resources]]"]
last_updated: 2026-07-12
source: raw/guidelines/db_schema.md, raw/guidelines/agent.md
---
# DB 스키마 개요
**DB명:** `aislo_db` / MariaDB v10.6+ / utf8mb4_unicode_ci / 드라이버 aiomysql
> ✅ **모순 해결 (2026-07-12, 실 DB 직접 조회 `SHOW TABLES`로 검증):** 실제 운영 DB는 **34개 테이블**. `db_schema.md`(34개)가 정확했고 `agent.md`의 18개/23개는 갱신 안 된 값 — agent.md 쪽 오기로 판정.
>
> **raw 문서에 없던 실제 테이블 2개 발견:**
> - `project_workflow_stages` — [[workflow_state]] 설계가 **이미 구현되어 실 DB에 존재**함 (컬럼 구성이 계획서와 정확히 일치). status를 draft→stable로 갱신함.
> - `system_admin_logs` — 시스템 관리자(SYSTEM_ADMIN)가 회원/조직 상태(`status`) 등을 변경할 때 감사 이력을 INSERT하는 Write-Only 성격의 테이블 ➡️ [[db_schema/logs_monitoring]].
>
> ⚠️ **미확정/미연동 테이블 격리 규칙**:
> - 분석 중이거나 소스코드와의 구체적인 연결고리(백엔드/프론트엔드 실사용처)가 아직 확정되지 않은 테이블이 신규 추가될 경우, 상위 공식 그룹 파일에 포함하지 않고 [[db_schema/unconfirmed/README|미확정 폴더(unconfirmed/)]] 내에 개별 `[테이블명].md` 마크다운 파일로 저장하여 격리 관리합니다.
## 테이블 그룹 (9개)
| 그룹 | 테이블 수 | 상세 페이지 |
|---|---|---|
| 사용자/인증/조직 (핵심) | 7 | [[db_schema/users_auth]] |
| 로그/모니터링 | 8 | [[db_schema/logs_monitoring]] |
| 프로젝트 관리 | 3 | [[db_schema/projects]] |
| 파일/지표면분석 | 6 | [[db_schema/files_surface]] |
| 경로/종횡단 | 5 | [[db_schema/route_profile]] |
| 구조물/수량/산출물 | 4 | [[db_schema/structure_output]] |
| 미확정/연결 대기 테이블 | 0 | [[db_schema/unconfirmed/README]] |
## 파일 경로 추적 컬럼 (DB에 경로만 기록, 실 파일은 파일시스템)
| 테이블.컬럼 | 용도 | 사용 단계 |
|---|---|---|
| `input_files.raw_file_path` | 원본 입력 파일 | B03 |
| `processed_point_cloud.converted_file_path` | 변환된 포인트클라우드 | B04 |
| `surface_models.model_file_path` | 지표면 모델 | B04 |
| `routes.route_data_path` | 경로 데이터(GeoJSON) | B05 |
| `longitudinal_sections.longitudinal_file_path` | 종단면 | B06 |
| `cross_sections.cross_section_file_path` | 횡단면 | B06 |
| `structures.structure_data_path` | 구조물 배치 | B07 |
| `quantity_items.quantity_data_path` | 수량 항목 | B08 |
| `outputs.outputs_directory_path` | 산출물 폴더 | B09 |
| `output_files.output_file_path` | 개별 산출 파일 | B09 |
상세 경로 규칙 → [[storage_paths]]
## 설계 원칙
- DB에는 "어디에 무엇이 있는가"의 메타정보만 저장. 실제 대용량 파일(LAS/PLY/TIF/DXF/Excel/PDF/JSON)은 파일시스템.
- 공간 기하 데이터(GEOMETRY 타입 미지원) → JSON(GeoJSON 형식)으로 저장, 애플리케이션(Shapely/Geopandas)에서 파싱.
- 모든 주요 테이블에 soft delete(`deleted_at`) 적용.
## 테이블 관계 (핵심 흐름)
```
users ─company_id→ companies
projects ─user_id/company_id→ users/companies
└→ input_files → processed_point_cloud → surface_models → terrain_layers
└→ routes → route_points/route_statistics/longitudinal_sections/cross_sections → structures
└→ quantity_items
└→ outputs → output_files
```
+56
View File
@@ -0,0 +1,56 @@
---
type: concept
status: draft
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B02_ProjRegister/B02_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-12
source: raw/guidelines/db_schema.md, raw/plans/plan_workflow_state_management.md
---
# DB: 프로젝트 관리 테이블
← [[db_schema/overview]]
## projects (프로젝트)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `char(36)` | NO | PRI | 프로젝트 UUID |
| `user_id` / `company_id` | `int(11)` | NO | MUL | FK→users/companies |
| `name` | `varchar(255)` | NO | | 프로젝트명 |
| `region` / `road_type` | `varchar(100)` | YES | | 지역 / 임도종류 |
| `project_year` | `int(11)` | YES | | 사업년도 |
| `estimated_length_m` | `float` | YES | | 계획 연장(m) |
| `memo` | `text` | YES | | 메모 |
| `status` | `varchar(50)` | YES | | `NEW` (호환용 캐시) |
| `crs_epsg` | `int(11)` | YES | | `5178` (좌표계 EPSG) |
| `storage_path` | `varchar(500)` | YES | | 상대경로 ➡️ [[storage_paths]] |
| `created_at` / `updated_at` / `deleted_at` | `timestamp` | - | | 생성 / 수정 / soft-delete |
**사용처:** [[B01_Dashboard/B01_backend|B01_Dashboard]] (목록), [[B02_ProjRegister/B02_backend|B02_ProjRegister]] (생성)
## project_versions (프로젝트 버전 스냅샷)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `version_num` | `int(11)` | NO | | 버전 번호 |
| `status` | `varchar(50)` | YES | | 버전 상태 |
| `data` | `longtext` | YES | | 설계 스냅샷 JSON 데이터 |
| `snapshot_at` / `created_at` | `timestamp` | NO | | 생성일시 |
## project_automations (프로젝트 자동화 정책)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `name` | `varchar(100)` | NO | | 자동화 명칭 |
| `logic_type` | `varchar(50)` | NO | | `trigger_on_stage_complete` 등 |
| `config_json` | `longtext` | NO | | 설정 값 JSON |
| `status` | `enum('DRAFT','ACTIVE','INACTIVE')` | NO | MUL | `DRAFT` |
| `created_by` / `updated_by` | `int(11)` | - | MUL | FK→users.id |
| `last_executed_at` | `datetime` | YES | | 최종 실행 일시 |
**사용처:** [[B01_Dashboard/B01_backend|B01_Dashboard]] (자동화 로직 관리, USER는 조회 차단)
## project_workflow_stages (단계별 상세 상태)
- 본 테이블은 워크플로우 7단계(stage 0~6)의 세부 진행도(state, params, progress_percent 등)를 관리하는 SSOT입니다.
- 상세 테이블 정보 및 사용처 ➡️ [[workflow_state]]
@@ -0,0 +1,86 @@
---
type: concept
status: stable
related_pages: ["[[B05_Profile/B05_backend]]", "[[B06_Section/B06_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-19
source: docs/raw/verification/2026-07-19_verify_종횡단_생성_B05_이관.md
---
# DB: 경로/종횡단 테이블
← [[db_schema/overview]]
## routes (노선 경로)
*사용처: [[B05_Profile/B05_db]]*
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `surface_model_id` | `int(11)` | YES | MUL | FK→surface_models.id |
| `status` | `varchar(50)` | YES | | `DRAFT` ➡️ `CONFIRMED` ➡️ `ARCHIVED` |
| `start_chainage_m` / `end_chainage_m` | `float` | YES | | 시작 시점 / 끝 시점 연장(m) |
| `total_length_m` | `float` | YES | | 총 연장(m) |
| `grade_percent` | `longtext` | YES | | 경사도 정보 JSON |
| `constraints` / `algorithm_params` | `longtext` | YES | | 회피 구역 JSON / 알고리즘 가중치 파라미터 JSON |
| `route_data_path` | `varchar(500)` | YES | | 노선 데이터 (GeoJSON) 파일 경로 |
| `computed_at` / `created_at` | - | - | | 연산 완료 일시 / 생성 일시 |
## route_points (경로 좌표점)
*사용처: [[B05_Profile/B05_db]]*
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `route_id` | `int(11)` | NO | MUL | FK→routes.id |
| `chainage_m` | `float` | YES | | 시점 거리(m) |
| `elevation_m` / `slope_percent` | `float` | YES | | 표고(m) / 종단 경사율(%) |
| `sequence_num` | `int(11)` | YES | | 점 순서 |
## route_statistics (노선 통계)
*사용처: [[B05_Profile/B05_db]]*
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `route_id` | `int(11)` | NO | MUL | FK→routes.id |
| `min_slope` / `max_slope` / `mean_slope` | `float` | YES | | 최저 / 최고 / 평균 경사(%) |
| `cut_volume_m3` / `fill_volume_m3` | `float` | YES | | 절토량(㎥) / 성토량(㎥) |
| `tree_cutting_volume` / `cost_score` | `float` | YES | | 벌채량 / 평점 비용 스코어 |
## longitudinal_sections (종단면 설계)
*사용처: [[B05_Profile/B05_db]] (생성/저장), [[B06_Section/B06_db]] (조회/확정)*
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` / `route_id` | `char(36)` / `int` | NO | MUL | FK→projects / routes |
| `computed_at` | `timestamp` | YES | | 종단 계산 일시 |
| `data` | `longtext` | YES | | 지반고/계획고/구배 등 설계 데이터 JSON |
| `longitudinal_file_path` | `varchar(500)` | YES | | 종단도면 캐드 파일 경로 |
| `status` | `varchar(50)` | YES | | `DRAFT` / `CONFIRMED` |
### `data` 컬럼 내 `options` 스냅샷 구조 (2026-07-19 도입)
종횡단 계산(`solve_route`) 완료 시, `longitudinal_sections.data` 필드의 최상위 키 `"options"` 하위에 당시 적용한 측점/횡단 생성 파라미터가 JSON 구조로 영구 보존됩니다.
### `data` 컬럼 내 `profile_alignment` 구조 (2026-07-23 도입)
사용자가 직접 편집 및 확정한 종단 계획고 선형 기하 데이터(PVI 목록, 곡선 제원, 절성토 균형 지표, 규정 위반 목록 등)가 `"profile_alignment"` 키 하위에 저장됩니다. 상세한 스펙 및 JSON 예시는 [[db_schema/route_profile/longitudinal_alignment]] 문서를 참조하십시오.
## cross_sections (횡단면 설계)
*사용처: [[B05_Profile/B05_db]] (생성/저장), [[B06_Section/B06_db]] (조회/확정)*
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` / `route_id` | `char(36)` / `int` | NO | MUL | FK→projects / routes |
| `chainage_m` / `sequence_num` | - | YES | | 측정 체인 거리(m) / 단면 순서 |
| `data` | `longtext` | YES | | 좌우 사면 경사, 폭, 절성토 단면적 JSON |
| `cross_section_file_path` | `varchar(500)` | YES | | 횡단도면 캐드 파일 경로 |
| `status` | `varchar(50)` | YES | | `DRAFT` / `CONFIRMED` |
## routes.status 흐름
`DRAFT → CONFIRMED → ARCHIVED`
## cross_sections.data.structures
횡단면 하나에 배치된 구조물 ID 배열 → [[db_schema/structure_output]]#structures 참조
@@ -0,0 +1,68 @@
---
type: concept
status: stable
related_pages: ["[[B05_Profile/B05_backend]]", "[[B05_Profile/B05_db]]", "[[db_schema/route_profile]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-23
source: "docs/raw/verification/2026-07-23_verify_B05_종단_계획선_편집_체계_개편.md"
---
# DB: longitudinal_sections.data.profile_alignment 구조
종단 계획고 편집 개편에 따라 `longitudinal_sections.data` 내 `"profile_alignment"` 키 하위에 저장되는 선형 기하의 JSON 스펙입니다.
```jsonc
"profile_alignment": {
"station_interval_m": 20.0, // 기준 측점 간격(m)
"pvi": [ // 변화점(PVI) 목록
{
"chainage_m": 2400.0, // PVI 위치 누가거리(m)
"elevation_m": 409.96, // PVI 높이 표고(m)
"curve_l_m": 8.0, // 파생된 종단곡선 길이(m)
"curve_r_m": 359.2, // 설정된 종단곡선 반경 R(m)
"source": "auto" // 생성 주체: "auto"(자동산출) | "user"(사용자편집)
}
],
"overrides": {
"2440.0": 0.3 // 측점별 높이 편집 델타값 (기본값 대비 m) -> 원복(↺) 판단 근거
},
"segment_shifts": {
"3": -0.2 // 직선 세그먼트 인덱스별 상하 평행이동 델타값(m)
},
"segments": [ // 직선 구간(기울기) 기하 분석 결과
{
"from_m": 2400.0,
"to_m": 2460.0,
"length_m": 60.0, // 구간 길이(m)
"height_m": -2.86, // 높이 변화량(m)
"grade_percent": -4.77 // 기울기 구배(%)
}
],
"curves": [ // 종단곡선(R) 기하 분석 결과
{
"pvi_index": 1,
"bvc_m": 2476.0, // 곡선 시작점(BVC) 누가거리(m)
"evc_m": 2484.0, // 곡선 끝점(EVC) 누가거리(m)
"l_m": 8.0, // 곡선 길이(m)
"k": 3.59, // 곡선반경 성능 지표 K
"r_m": 359.2, // 반경 R(m)
"middle_ordinate_m": 0.56, // 중앙종거(m)
"omitted": false, // 비포장/대수차 5% 이하 예외에 따른 곡선 생략 여부
"omit_reason": null
}
],
"balance": { // 절성토 균형 지표
"cut_m3": 240.5, // 종단면 기준 간이 절토 단면적적분량
"fill_m3": 235.1, // 종단면 기준 간이 성토 단면적적분량
"imbalance_percent": 2.2, // 균형 오차 백분율
"within_tolerance": true // 허용 기준(10.0%) 충족 여부
},
"violations": [ // 규정 위반 검증 목록
{
"segment_index": 2,
"type": "grade_over", // 위반 유형 (grade_over: 구배 초과)
"value": 15.2, // 실제 수치
"limit": 14.0 // 규정 한계값
}
]
}
```
@@ -0,0 +1,70 @@
---
type: concept
status: draft
related_pages: ["[[B07_Quantity/B07_frontend]]", "[[B08_DesignDetail/B08_frontend]]", "[[B09_Estimation/B09_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-12
source: raw/guidelines/db_schema.md
---
# DB: 구조물/수량/산출물 테이블
← [[db_schema/overview]]
## structures (배치 구조물)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` / `cross_section_id` | - | - | MUL | FK→projects / cross_sections |
| `structure_type` | `varchar(100)` | YES | | 낙석방지책 / 계간수로 / 돌붙임 등 |
| `chainage_m` | `float` | YES | | 구조물 배치 체인 시점 거리(m) |
| `location` | `varchar(50)` | YES | | 좌 / 우 / 종단 등 배치 위치 |
| `length_m` / `width_m` / `height_m` | `float` | YES | | 길이 / 폭 / 높이 규격(m) |
| `material` | `varchar(100)` | YES | | 구조물 재질/자재 |
| `quantity` / `unit_price` | - | YES | | 수량 / 단가 |
| `design_notes` | `longtext` | YES | | 특기사항 등 메모 |
| `structure_data_path` | `varchar(500)` | YES | | 세부 구조 상세 데이터 파일 경로 |
| `last_modified_by` | `int(11)` | YES | MUL | FK→users.id (최종 수정자) |
| `created_at` / `updated_at` | `timestamp` | - | | 생성 / 수정 일시 |
## quantity_items (수량 산출 항목)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `category` | `varchar(100)` | YES | | 토공 / 구조물 / 포장 / 배수 등 공종 |
| `item_name` / `unit` | `varchar` | YES | | 품목 항목명 / 단위 (㎡, m 등) |
| `quantity_design` / `quantity_actual` | `float` | YES | | 설계 수량 / 최종 반영 수량 |
| `unit_price` / `total_price` | `float` | YES | | 단가 / 총 금액 |
| `standard_reference` | `varchar(255)` | YES | | 품셈 근거 코드/출처 |
| `computed_at` / `quantity_data_path` | - | YES | | 계산 일시 / 상세 산출근거 데이터 파일 경로 |
| `data` | `longtext` | YES | | 계산 세부 과정 통계 JSON |
## outputs (최종 견적/도면 산출 세션)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `project_id` | `char(36)` | NO | MUL | FK→projects.id |
| `output_type` | `varchar(100)` | YES | | `estimation_excel`/`drawing_dxf`/`report_pdf`/`all_bundle` |
| `status` | `varchar(50)` | YES | | `GENERATING` ➡️ `COMPLETE` / `FAILED` |
| `generated_by` / `generated_at` | - | - | MUL | 생성자 FK / 생성일시 |
| `version` | `int(11)` | YES | | 산출 버전 |
| `outputs_directory_path` | `varchar(500)` | YES | | 산출 파일 번들 디렉토리 경로 |
| `metadata` | `longtext` | YES | | 기타 도면 스케일 등 정보 JSON |
## output_files (개별 산출 파일 리스트)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `output_id` | `int(11)` | NO | MUL | FK→outputs.id |
| `file_type` | `varchar(50)` | YES | | `xlsx`/`pdf`/`dxf`/`dwg`/`json`/`zip` 등 |
| `original_filename` | `varchar(255)` | YES | | 원본 파일 식별 이름 |
| `output_file_path` | `varchar(500)` | YES | | 개별 파일 저장 경로 |
| `file_size_mb` / `download_count` | - | YES | | 파일 용량 / 다운로드 누적 카운트 |
| `created_at` | `timestamp` | NO | | 생성일시 |
## quantity_items 총비용 계산 예
```sql
SELECT SUM(quantity_actual * unit_price) AS total_cost, category
FROM quantity_items WHERE project_id = :project_id AND deleted_at IS NULL
GROUP BY category;
```
@@ -0,0 +1,13 @@
---
status: draft
related_pages: ["[[architecture/shared_resources]]"]
last_updated: 2026-07-17
---
# 미확정 테이블 보관소 (Unconfirmed DB Schemas)
본 디렉토리는 소스코드 연동 처리가 완료되지 않았거나, 비즈니스 로직(백엔드/프론트엔드) 상의 구체적인 연결고리가 식별되지 않은 미확정 테이블의 명세서 및 임시 분석 내용을 개별 마크다운 파일로 저장·격리하는 공간입니다.
## 운영 규칙
1. **임시 격리**: 신규 테이블 추가 또는 레거시 테이블 중 사용처를 즉시 규명하기 어려운 경우 `[테이블명].md`로 파일을 생성해 기록합니다.
2. **확정 이관**: 소스코드에서의 실제 사용처(라우터, 리포지토리 등)가 명확해지면, 상위의 공식 테이블 그룹(예: `users_auth.md`, `logs_monitoring.md` 등)으로 표 명세를 이관하고 본 폴더 내의 마크다운은 삭제합니다.
@@ -0,0 +1,92 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[auth_rbac]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-17
source: docs/raw/verification/2026-07-17_verify_auth_reverify.md
---
# DB: 사용자/인증/조직 테이블
Links: ← [[db_schema/overview]]
## users (사용자)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `email` | `varchar(255)` | NO | UNI | |
| `password_hash` | `varchar(255)` | NO | | |
| `name` | `varchar(255)` | NO | | |
| `position` / `department` | `varchar(100)` | YES | | 직위 / 부서 |
| `phone` | `varchar(20)` | YES | | |
| `company_id` | `int(11)` | YES | MUL | FK→companies.id |
| `role` | `enum('SYSTEM_ADMIN','ADMIN','USER')` | NO | MUL | `USER` |
| `is_master` | `tinyint(1)` | NO | | `0` (마스터 여부) |
| `status` | `enum('PENDING_EMAIL','NO_COMPANY','PENDING','ACTIVE','INACTIVE','REJECTED')` | NO | MUL | `PENDING_EMAIL` |
| `last_login` | `datetime` | YES | | 최종 로그인 일시 |
| `login_failures` | `int(11)` | NO | | `0` (실패 횟수) |
| `created_at` / `updated_at` / `deleted_at` | `timestamp` | - | | 생성 / 수정 / soft-delete |
* **사용처:** [[B01_Dashboard/B01_backend|B01_Dashboard]] (사용자 관리), 전 페이지 공통 인증 (`auth_expires_at` 컬럼 삭제 완료)
## companies (회사)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `name` | `varchar(255)` | NO | UNI | 회사명 |
| `business_registration_number` | `varchar(20)` | YES | UNI | 사업자번호 |
| `status` | `enum('ACTIVE','INACTIVE','SUSPENDED')` | NO | | `ACTIVE` |
| `subscription_status` | `enum('FREE','TRIAL','PAID','EXPIRED')` | NO | | `FREE` |
| `created_by` | `int(11)` | YES | MUL | FK→users.id (생성자) |
| `company_code` | `varchar(20)` | YES | | 참여용 코드 |
**사용처:** [[B01_Dashboard/B01_backend|B01_Dashboard]]
## sessions (세션)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `varchar(255)` | NO | PRI | 세션 ID (쿠키 값) |
| `user_id` | `int(11)` | NO | MUL | FK→users.id |
| `user_agent_hash` | `char(64)` | NO | | |
| `expires_at` | `timestamp` | NO | MUL | 만료일시 |
| `last_activity_at` | `timestamp` | NO | | 최종 활동일시 |
**사용처:** 전 페이지 공통 (세션 인증) — 상세 → [[auth_rbac]]
## email_otps (이메일 OTP)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `bigint(20)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | NO | MUL | FK→users.id |
| `purpose` | `enum('REGISTER','LOGIN','REVERIFY','PASSWORD_CHANGE')` | NO | | 용도 |
| `otp_hash` | `varchar(255)` | NO | | OTP 해시값 |
| `expires_at` / `consumed_at` | `timestamp` | - | | 만료일시 / 사용일시 |
## trusted_devices (신뢰 기기)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `bigint(20)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | NO | MUL | FK→users.id |
| `token_hash` | `varchar(255)` | NO | UNI | 디바이스 토큰 해시 (2026-07-17 추가) |
| `verified_at` / `last_used_at` | `timestamp` | NO | | 검증 / 최종 사용 일시 |
## join_requests (회사 가입 신청)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `int(11)` | NO | PRI | `auto_increment` |
| `user_id` / `company_id` | `int(11)` | NO | MUL | FK→users/companies |
| `status` | `enum('PENDING','APPROVED','REJECTED')` | NO | | `PENDING` |
| `requested_at` / `reviewed_at` | `timestamp` | - | | 신청 / 검토 일시 |
| `reviewed_by` | `int(11)` | YES | MUL | FK→users.id (검토자) |
**사용처:** [[B01_Dashboard/B01_backend|B01_Dashboard]] (`B01_Dashboard_Repository.py:378` 가입 신청·처리)
## user_consents (약관 동의)
| 컬럼 | 타입 | Null | Key | Default / Extra |
|---|---|---|---|---|
| `id` | `bigint(20)` | NO | PRI | `auto_increment` |
| `user_id` | `int(11)` | NO | MUL | FK→users.id |
| `terms_version` | `varchar(20)` | NO | | 동의한 약관 버전 |
| `terms_agreed` / `privacy_agreed` | `tinyint(1)` | NO | | 필수 동의여부 (1=동의) |
| `marketing_agreed` | `tinyint(1)` | NO | | `0` (선택 마케팅동의) |
| `agreed_at` | `timestamp` | NO | | 동의 일시 |
+41
View File
@@ -0,0 +1,41 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[B05_Profile/B05_backend]]", "[[B06_Section/B06_backend]]", "[[B07_Quantity/B07_backend]]", "[[B08_DesignDetail/B08_backend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-20
source: ["docs/raw/verification/2026-07-19_verify_b07_independent_cad.md", "docs/raw/verification/2026-07-20_verify_b08_quantity_template.md", "docs/raw/plans/2026-07-18_plan_dependency_upgrade.md"]
---
# 외부 라이브러리 의존성
[[architecture/shared_resources]]는 이 문서를 전체 의존성 정본으로 참조한다. Backend 의존성은 B01·B03~B08에, Frontend 의존성은 [[a00_app_shell_framework]]과 [[ui_templates]]에 연결된다.
## 백엔드 (Python 3.12.7)
| 라이브러리 | 용도 | 사용 페이지 |
|---|---|---|
| FastAPI / Pydantic | API 프레임워크 / 요청·응답 검증 | 전체; [[B01_Dashboard/B01_backend|B01_Dashboard]] 라우터·요청 모델 |
| Trimesh | 3D 메시 처리 | [[B04_PreProcess/B04_backend|B04_PreProcess]] (trimesh==4.12.2 모델 생성) |
| Whitebox | 지형 분석(D8 흐름누적 등) | [[B04_PreProcess/B04_backend|B04_PreProcess]], [[B05_Profile/B05_backend|B05_Profile]] (whitebox==2.3.6 skeleton 복구) |
| Geopandas | 공간 데이터프레임 | [[B04_PreProcess/B04_backend|B04_PreProcess]], [[B05_Profile/B05_backend|B05_Profile]] (geopandas==1.1.4) |
| Pyogrio | GeoPandas 파일 I/O 가속 | [[B05_Profile/B05_backend|B05_Profile]] (pyogrio==0.13.0 신규 도입) |
| Shapely | 기하 연산 (JSON 파싱 후) | [[B05_Profile/B05_backend|B05_Profile]], [[B06_Section/B06_backend|B06_Section]] (shapely==2.1.2) |
| NumPy | 격자·통계·비용면 및 LAS 통계 계산 | [[B03_FileInput/B03_backend|B03_FileInput]], [[B05_Profile/B05_backend|B05_Profile]] (numpy==2.5.0) |
| SciPy | 수치 보간·계산 보조, Delaunay 삼각망 생성 | [[B04_PreProcess/B04_backend|B04_PreProcess]] (scipy==1.18.0 삼각망 생성), [[B05_Profile/B05_backend|B05_Profile]] |
| Rasterio | 래스터(DEM/TIF) 입출력·메타데이터 | [[B03_FileInput/B03_backend|B03_FileInput]], [[B04_PreProcess/B04_backend|B04_PreProcess]] (rasterio==1.5.0) |
| Laspy | LAS/LAZ 포인트클라우드 파싱 | [[B03_FileInput/B03_backend|B03_FileInput]], [[B04_PreProcess/B04_backend|B04_PreProcess]] (laspy==2.7.0) |
| Pyproj | PRJ/TIF 좌표계 해석 | [[B03_FileInput/B03_backend|B03_FileInput]] |
| Openpyxl | 과거 엑셀 원가 수량 템플릿 계획에 사용 | 현행 B07 구현에서는 사용 미확인 |
| aiomysql | 비동기 MariaDB 드라이버 (Raw SQL) | 전체 |
| psutil | CPU·메모리 사용률 계측 | [[B01_Dashboard/B01_backend|B01_Dashboard]] 리소스 현황 |
## 프론트엔드 (TypeScript/Node.js)
| 항목 | 용도 | 사용처 |
|---|---|---|
| **three.js** (WebGL) | 3D 뷰어(WebGLRenderer, OrbitControls, Points/Mesh) | [[B04_PreProcess/B04_backend|B04_PreProcess]], [[B05_Profile/B05_backend|B05_Profile]] 구현 확인. B06은 미구현 (SVG 사용) |
| **openwebcad** (Canvas) | 내장 독립 2D CAD 에디터 및 뷰어 | [[B08_DesignDetail/B08_frontend|B08_DesignDetail]] (MIT 라이선스, iframe 임베딩) |
| Vite | 빌드 도구 | 전 프론트 |
> ⚠️ B04, B05는 three.js 기반 3D 지형/노선 뷰어가 구현되어 있으며, B06은 종횡단 조회 전용(SVG 렌더링)으로 Three.js를 사용하지 않습니다. B07은 내장된 독립 2D CAD(`openwebcad`)를 iframe으로 임베딩하여 활용합니다.
## 선정 원칙 (agent.md 3절)
프로젝트에 맞춰 호환 라이브러리 선정, 불필요한 함수 작성 최소화. `asyncmy` 대신 `aiomysql` 채택 이유: Cython 빌드가 Windows 환경에서 불필요.
+58
View File
@@ -0,0 +1,58 @@
---
type: concept
status: stable
related_pages: ["[[ui_templates]]", "[[architecture/shared_resources]]"]
last_updated: 2026-07-19
source: docs/raw/verification/2026-07-19_verify_scrollbar_theme.md
---
# 디자인 시스템 (Design System)
임도설계 및 견적자동화 웹앱(Aislo)의 공통 비주얼 테마, 타이포그래피, 간격 규칙 및 CSS 변수 명세 요약입니다.
## 비주얼 테마
* **Theme & Tone**: confident enterprise tool + approachable consumer product.
* **비주얼 키워드**: Confident (Assured), Clean (Geometric), Sunlit Atmosphere (Gradient wash).
* **대표 그라디언트**: 연한 라벤더 분위기를 연출하기 위해 흰색-보라색-피치 그라디언트를 접목하여 맑은 느낌 제공.
## 핵심 색상 토큰 (Colors)
| CSS 변수명 | hex 값 | 역할 / 비주얼 우선도 |
|---|---|---|
| `--color-deep-iris` | `#26114a` | 딥 바이올렛 데코레이션 디테일 (CTA 단추로 사용 금지) |
| `--color-plum-velvet` | `#312749` | 대시보드 네비게이션 텍스트, 카드 타이틀, 보조 제목 |
| `--color-royal-amethyst` | `#3e0079` | 링크, 입력 필드 포커스 링, 하이라이트 아이콘 (가장 채도 높음) |
| `--color-mist-violet` | `#edecff` | 연한 라벤더 분위기를 내는 소프트 하이라이트/배경색 |
| `--color-canvas` | `#ffffff` | 기본 페이지 배경, 카드 배경, 활성 입력 필드 |
| `--color-paper` | `#f6f7fa` | 미세한 대비를 주는 테이블 줄무늬 교대 배경, 보조 카드 배경 |
| `--color-mist` | `#e6e2e3` | 외곽 얇은 헤어라인 테두리, 구분선 |
## 타이포그래피 (Typography)
* **Britti Sans (display/heading)**: 24–64px 크기에 적용하며 geometric(기하학적) 인상을 강조하기 위해 line-height는 항상 `1.0` 고정. (대체 폰트: Plus Jakarta Sans / General Sans)
* **Inter (UI/body)**: UI 라벨 및 본문 기본 폰트. 자간 및 행간을 compact하게 배치하여 고밀도(data-dense) 정보 인터페이스를 제공. (대체 폰트: Inter / IBM Plex Sans)
| 서체 역할 | 크기 | 행간(Line-Height) | CSS 변수명 |
|---|---|---|---|
| caption | 12px | 1.3 | `--text-caption` |
| body-sm | 14px | 1.4 | `--text-body-sm` |
| body | 16px | 1.5 | `--text-body` |
| subheading | 24px | 1.0 | `--text-subheading` |
| heading-sm | 32px | 1.0 | `--text-heading-sm` |
| heading | 40px | 1.0 | `--text-heading` |
## 레이아웃 및 둥근 테두리 (Radius & Spacing)
* **기본 단위**: `8px` 배수 간격 시스템 (`--spacing-8`, `--spacing-16` 등)
* **둥근 곡률 (Border-radius)**:
* 카드, 입력 상자, 버튼: `8px`
* 태그/필 상태(Pills): `1440px` (원형 캡슐 스타일)
## 전역 스크롤바 디자인 (Scrollbars)
* **브라우저 충돌 가드**: Chromium/WebKit 환경에서 표준과 충돌하지 않도록 `@supports selector(::-webkit-scrollbar)` 블록 내의 `*` 선택자에 `scrollbar-width: auto;`를 적용하여 스타일 오버라이드를 제어함. (B07 WebCAD iframe 내부 제외)
* **미니멀 디자인**:
* 스크롤바 폭/높이: 얇은 `8px` 두께 고정 (`width: 8px; height: 8px;`)
* 트랙 배경: 완전 투명(`transparent`)으로 UI 배경 이질감 최소화
* 화살표 버튼: 기본 이동 버튼 제거 (`display: none; width: 0; height: 0;`)
* 스크롤 썸(Thumb) 불투명도: 기본 12% -> hover 시 20% -> active 시 28%로 은은하게 반응 튜닝
+79
View File
@@ -0,0 +1,79 @@
---
status: stable
related_pages: ["[[B04_PreProcess/B04_backend]]", "[[B04_PreProcess/B04_frontend]]", "[[B05_Profile/B05_backend]]", "[[B05_Profile/B05_frontend]]", "[[B08_DesignDetail/B08_drawing_masshaul_watershed]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-30
---
# 배수유역 해석 및 세부설계 (Drainage Watershed)
배수유역 구조는 B04 지표면 분석 단계에서 무거운 1차 격자 해석(30초)을 거치고, 이후 관 매설 편집 및 세부유역 분할 설계는 B04/B05 두 워크플로우 화면에서 **단일 데이터 소스(SSOT) 및 공용 API**를 통해 실시간으로 처리되도록 통합 관리됩니다.
사용처: [[B04_PreProcess/B04_frontend|B04_PreProcess]], [[B05_Profile/B05_frontend|B05_Profile]], [[B08_DesignDetail/B08_drawing_masshaul_watershed|B08 유역도]]
## 1. B04 vs B05 역할 분담 및 일원화
| 구분 | B04 지표면 분석 & 세부유역 설계 | B05 배수유역도 패널 & 종단 연동 |
|---|---|---|
| 역할 | ①~⑧ 전 해석 수행 및 관 매설 편집/세부유역 계산(분할)을 담당 | B04와 **동일한 단일 데이터**를 로드하여 지도 2D 오버레이 시각화 및 종단 그래프 드래그/우클릭과 배관 위치 양방향 동기화 |
| 저장소 | `B04_PreProcess/drainage/` 내 **`pipe_points.json` 단일 정본**을 두 화면이 공용으로 바라봄 (B05 사본 폴더는 완전히 폐지됨) |
| API | 두 화면 모두 **B04 공용 API**를 호출 (`GET/POST/PUT/DELETE /drainage/pipe-points` 및 `POST /drainage/detail-basins`) |
| 노선 원본 | B03 업로드 원청 계획노선 CSV (`common_util_route_geometry.py`) | B03 업로드 원청 계획노선 CSV |
## 2. 공용 배수 엔진 및 WAMIS 강우량 연동 (Phase 1~2, 2026-08-13 관측소 전환)
- **WAMIS 전국 621개 관측소 확률강우량 연동 (본토)**: `common_util/common_util_wamis_station.py`를 통해 공사지 기준 반경 10km (`WAMIS_STATION_RADIUS_M = 10000`) 내 WAMIS 관측소 xlsx를 다운로드·파싱하여 100년/24hr 강우량이 가장 높은 지점을 안전측으로 탐색·선정합니다.
- **제주도 등우선도 존치 및 지역 분기**: 제주 지역 공사지는 기존 `common_util_wamis_rainfall.py` 등우선 내삽(96조합)을 유지하며, `value_at()`에 10km 커버리지 검사를 추가하여 본토 공사지에서 제주 등우선으로 무단 폴백되는 결함을 엄격히 차단했습니다.
- **강우강도(IDF) 이원화 (Mononobe 기본)**: Mononobe형 IDF($a=(R_{24}/24)\cdot 1440^{0.557}$, $n=0.557$, $b=0$)를 기본 적용하고 General형 선택적 지원을 유지하여 하류 수리계산 계약을 완전 보존합니다.
- **수리계산 체인**: 100년 빈도·5분 하한·IDF·합리식·설계유량 2배·Manning으로 유효직경을 산출한다. Kirpich·유출계수·조도계수·유효 통수비율·관 경사값의 기술정보DB 근거 승격과 재확정은 미결이다.
- **추천과 자동 주입**: 유효직경 1,500mm 이하=규격 스냅 배관, 초과~2,000mm=BOX암거 후보, 2,000mm 초과=세월교·물넘이 검토다. 자동 배치에는 추천 관경·시설만 주입하며 사용자 수정값은 덮어쓰지 않는다. 사용처: [[B04_PreProcess/B04_backend]], [[B05_Profile/B05_structures]].
- **공용 엔진 승격**: `common_util/common_util_drainage_detail.py`가 유역 분할 및 수리계산 코어 알고리즘을 전담.
## 3. 구조물 3단 옵션 체계 & UI (Phase 3~5)
- **3단 계층 드롭다운**: 구조물 대분류(배관/기성막이/대피로/기타), 세부 유형(콘크리트관/PE관 등), 관경/규격(D800, D1000 등) 선택 드롭다운 연동.
- **D800 법정 예외 하한**: 임도 구조물 기본 규격 하한 D800 적용 및 수리 계산 $D_{\text{eff}}$ 초과 시 규격 자동 상향 (수동 지정 `userSized` 보존).
- **컨텍스트 메뉴 & 캔버스/3D 핀 마킹**: 종단 그래프/배수유역도 우클릭 구조물 추가, 3D 수직 핀 마커(depthTest off) 동기화.
- **하단 패널 레이아웃**: 테이블 서브패널 오버레이, 행제목 우측 정렬, Y축 텍스트 13px, 드래그 포인터 추적으로 UX 안정화.
## 4. 해석 알고리즘 — 등고선 하강 (Contour Descent)
TIN 보간 표고면의 웅덩이(Sink) 문제를 원천 차단하기 위해 표고면을 생성하지 않고 등고선 자체를 격자에 구워 방향을 계산합니다.
1. 등고선을 격자에 굽고 각 셀에 가장 가까운 등고 라인의 표고(밴드)를 부여
2. 각 밴드에서 한 단 낮은 등고 라인까지의 거리를 EDT(Euclidean Distance Transform)로 측정
3. `potential = 밴드순위 × span + 거리` (`span = 최대거리 + 2.0`)
- 흐름은 항상 potential이 낮은 방향으로 진행 (순환 및 웅덩이 원리적 부재)
4. 최하단 밴드는 Sink 셀(32)로 관리하며 방위는 32방위(0~31)로 저장 (1셀 1바이트)
5. 8이웃 중 화살표 방향에 가장 가까운 셀을 수신자로 지정하여 화살표/경로 불일치 0셀 달성
## 5. 적색/청색 판정 및 유역 확장
1. **세류선 지류 우선 확정**: 세류선과 겹치는 셀을 걷기 전 적색으로 선 확정
2. **수신자 사슬 추적**: 최외곽 셀에서 수신자 사슬을 추적
- 도로 셀 또는 세류 셀에 도착 시 사슬 전체 **적색** (배수 영향 유역)
- Sink 또는 영역 이탈 시 사슬 전체 **청색** (자연 유출 유역)
3. **세류망 노딩**: 세류망을 도로에서 절단하여 상류측만 남기고 `unary_union`으로 노딩
4. **확장 루프**: 최외곽 적색 셀 주변으로 50m(`DRAINAGE_RED_EXPAND_BAND_M`)씩 확장을 반복하다가 새로 붙은 셀에 적색이 없으면 멈춤 (2차 전체 배수유역 경계 닫힘)
## 6. 평균 흐름 화살표 (Flow Arrows) 및 흐름강도 램프
- **화살표**: 1m 격자 화살표 대신 10m 블록의 원형 평균 방위를 구하고 40m 간격으로 솎아서 백엔드가 산출합니다.
- **흐름강도 램프 (FlowRamp)**: 1m 구간별 유입 면적 강도 프로필 데이터를 B04/B05에 동일하게 표시하며, 이를 지도 우측 세로 눈금 범례(`createFlowLegend` in `_UI_FlowRamp.ts`)로 동적 시각화합니다.
## 7. 영구저장소 산출물 구조
`storage/{회사}/{사용자}/{프로젝트}/B04_PreProcess/drainage/`
- `00_watershed_response.json`: 백엔드 응답 전체 캐시
- `01_primary_region.geojson` / `.npz`: 1차 영역, 상/하류망, 격자 bbox
- `02_flow_direction.npz`: 방위, 도달여부, 수신자, 밴드 표고
- `03_road_routing.geojson` / `.npz`: 2차 유역 외곽선, 기본 관, 평균 흐름 화살표, 슬롯 정보
- `pipe_points.json` (정본): 사용자가 매설한 관의 지점 좌표 및 상세 속성 (구조물 유형, 관경 등)
- `04_detailed_basins.geojson`: 관 매설에 맞춰 분할 계산된 세부 배수유역 경계 정보
- `rainfall_table.json`: WAMIS 확률강우량 내삽 산출 테이블
- `manifest.json`: 단계별 실행 메타데이터
> [!NOTE]
> 유역 외곽선 편집기 및 오버라이드 코드(`boundary_overrides.json`)는 2026-08-01부로 전량 영구 제거되었습니다. B05 디렉토리 하위의 중복 복사본 폴더(`B05_Profile/drainage/`) 또한 완전히 폐지되었습니다.
## 8. B08 수리집수면적유역도
- B04 세부유역 GeoJSON과 등고선·하천중심선, 확정 종단 노선을 A1 1:6,000 도면으로 조립한다.
- 정보표에는 번호·측점·배수규격·유역면적·유역표고·유하거리만 표시하며 C·I·Q는 제외한다.
- 여러 도엽의 배경선은 합친 뒤 A1 작도영역으로 선분 절취한다. 상세는 [[B08_DesignDetail/B08_drawing_masshaul_watershed]]를 참조한다.
@@ -0,0 +1,43 @@
---
type: concept
status: stable
related_pages: ["[[B03_FileInput/B03_frontend]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_frontend]]", "[[B04_PreProcess/B04_backend]]", "[[B05_Profile/B05_backend]]", "[[drainage_watershed]]"]
last_updated: 2026-08-30
source: ["docs/raw/plans/2026-08-30_plan_las_free_sheet_surface.md", "docs/raw/verification/2026-08-30_verify_las_free_sheet_surface.md"]
---
# LAS 없는 도엽등고선 서피스
## 계약과 확정값
| 항목 | 값 |
|---|---|
| 입력 | 계획노선 CSV·PRJ/좌표계·1:5,000 도엽등고선 |
| 서피스 계약 | `dtm_sheet.npz`의 x/y/z/valid_mask와 GLB 프리뷰 |
| 절취 여유 | 300m |
| 격자 | 1m |
| 기본 보간 | 라플라스, 스무딩 사용 |
| 진입 정책 | 일반 사용자 자동확정·B04 진입차단 유지 |
## 흐름
| 항목 | 위치 | 역할 |
|---|---|---|
| `las_free` | B03 요청·stage 0 params | LAS 카드 비활성·필수검증 면제 |
| `run_sheet_surface_analysis()` | `B04_PreProcess_Engine_SheetSurface.py` | 도엽 병합·격자·프리뷰·모델 등록·자동확정 |
| `build_surface_sampler()` | `common_util_surface_sampler.py` | 종단·횡단·배수 공용 표고 조회 |
| 도엽 서피스 컨테이너 | B04 frontend | LAS 모델과 별도 비교 표시 |
도엽 선 정점, 등고선 사이 중간선, 하천중심선 Z 앵커와 마루 국소 경사를 이용한다. NURBS 프리뷰는 이중 평활로 확정 격자와 달라져 되돌렸으며 다시 적용하지 않는다.
## E2E 결과
- LAS 없는 업로드가 도엽 9매·등고선 3,413건에서 서피스 6종, 배수유역, B05 노선, B06 횡단까지 자동 완주했다.
- LAS 있는 신규 프로젝트도 같은 자동체인을 완주해 기존 경로 회귀가 없었다.
- 조밀 원청 CSV는 정점 135개·최대 평면 이탈 0m·길이 350.11m로 보존된다.
- 관 지점은 XY를 저장하며 노선 지문이 달라도 대상 노선에 투영해 이월한다.
## 미결
- 곡선 경고는 비용면 셀 크기와 분리된 고정 검사간격 또는 정식 IP/R 직접검사가 필요하다.
- 기본 관과 격자 유입 봉우리 2.3m 차이의 스냅 여부는 사용자 결정 대상이다.
+38
View File
@@ -0,0 +1,38 @@
---
type: concept
status: draft
related_pages: ["[[architecture/shared_resources]]"]
last_updated: 2026-08-09
source: "직접 확인 (docs/raw/law/original/임도기술교본/15. 부록/2. 임도설치 및 관리 등에 관한 규정.md)"
---
# 임도기술교본 원문 md 추출 품질 결함
`docs/raw/law/original/임도기술교본/` 하위 각 조항 `.md` 파일은 PDF 원문에서 추출한 텍스트다. **raw/는 절대 수정 금지**이므로 원본은 그대로 두고, 이 문서에 알려진 결함을 기록해 재조사를 반복하지 않는다.
## 확인 범위
원본 기록 `15. 부록/2. 임도설치 및 관리 등에 관한 규정.md` 1개 파일만 전수 확인함. 같은 변환 파이프라인을 거친 15장의 다른 파일, 1~14장 파일은 미확인이지만 동일 결함 가능성 높음.
## 결함 유형 (예시 = 위 파일 기준 줄번호)
1. **항(①②③...) 간 줄바꿈 소실** — 첫 항만 별도 줄, 나머지는 한 줄에 전부 이어붙음.
- L24: 제3조 ①만 분리, ②~⑮이 한 줄.
- L62: 제5조 "...필요성③" — 공백조차 없이 다음 항 번호가 바로 붙음.
2. **단어 사이 공백 소실** (줄 이어붙이며 공백 누락).
- L24: `자를포함한다`, `관리에관한법률`, `등의각종`, `나타낸것을`, `자를말한다`
- L32: `설치한시설<16>`
3. **공백 과다 삽입** (원문 자간 강조 표기를 스페이스로 오인식).
- L47: `마을의 연결을 위하여 필요한 임지` (더블스페이스 3곳)
- L92, L143, L275: 음절 사이마다 공백 (`박 사 학 위 를 받 은 자`)
4. **순서목록 번호 꼬임** (구조적으로 가장 심각) — 성격이 다른 두 목록이 줄바꿈 없이 이어지면서 번호가 연속으로 재부여됨.
- L32~35: 제3조 ⑮ 부속물 목록(1~7호) 뒤에 `<16>` "테마임도" 정의가 줄바꿈 없이 붙고, 그 하위 유형(산림휴양형/산림레포츠형)이 새 목록 1,2가 아니라 **8, 9호**로 표시됨.
- L63~66: 제5조 ④의 서류 목록도 같은 방식으로 **7,8,9**호로 이어짐 (원래 새 목록 1,2,3).
## 원인 추정
PDF → 마크다운 변환 시 조(항) 사이 개행이 소실되고, 순서목록이 markdown 렌더러에 의해 자동으로 이어서 번호매김된 것으로 보임. OCR 문제가 아니라 변환/정리 단계 문제로 추정 — 유사 증상(줄바꿈 소실 원인)이 원본 기록 `임도기술교본_한글교정_작업가이드`가 다루는 PDF `ToUnicode` 폰트 문제와는 별개 사안임 (그쪽은 글자 자체가 깨지는 문제, 이쪽은 줄바꿈/공백 손실 문제).
## 조치 상태
2026-08-09 기준 **미조치**. 사용자 결정: 원본은 그대로 두고 이 노트만 남겨 다음 세션이 참고. 실제 수정(재추출 또는 wiki 교정본 작성)은 아직 요청되지 않음.
+71
View File
@@ -0,0 +1,71 @@
---
type: concept
status: stable
related_pages: ["[[B05_Profile/B05_frontend_alignment]]", "[[B06_Section/B06_frontend]]", "[[B06_Section/B06_backend]]", "[[B07_Quantity/B07_frontend]]", "[[B09_Estimation/B09_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-30
source: ["docs/raw/2026-07-24_유토곡선_분석_및_웹앱_계산명세.md", "docs/raw/plans/2026-08-02_유토곡선_3공구_분석.md", "docs/raw/plans/2026-08-02_plan_mass_haul_multi_curve.md", "docs/raw/plans/2026-08-04_plan_mass_haul_spoil_scroll.md", "docs/raw/verification/2026-08-02_verify_mass_haul_distribution_and_refinements.md", "docs/raw/verification/2026-08-02_verify_mass_haul_multi_curve.md", "docs/raw/verification/2026-08-02_verify_panel_fold_B05_style.md", "docs/raw/verification/2026-08-02_verify_panel_height_first_render.md", "docs/raw/verification/2026-08-02_verify_backlog_reorg.md", "docs/raw/verification/2026-08-03_verify_후속작업_주의사항.md", "docs/raw/verification/2026-08-03_verify_B05_mass_haul_transfer.md", "docs/raw/verification/2026-08-03_verify_향후작업_반영완료.md", "docs/raw/verification/2026-08-04_verify_mass_haul_spoil_scroll.md"]
---
# 유토곡선 (Mass Haul Diagram) 계산 명세
## 1. 개요 및 분석 목적
* **분석 대상**:
* 1공구: `07.유토곡선.pdf` (측점 `0+0.0` ~ `60+0.0`, V=1:10,000, 최종 누가토량 1,171.00㎥)
* 3공구: `13 유토곡선(3공구).pdf` (측점 `120+0.0` ~ `176+10.0`, V=1:50,000, 최종 누가토량 12,888.98㎥)
* **역할**: 노선 내 절토 및 성토의 차이를 누적하여 토량 이동(토공 운반계획), 사토량/토취량, 운반장비(종무대, 불도저, 덤프트럭) 및 평균운반거리를 결정하는 도면/차트.
* **웹앱 명세 목적**: Aislo 웹앱 B08 수량산출 및 B09 내역서 연동 시 유토곡선 자동 계산 및 시각화를 위한 원리 명세화.
## 2. 주요 계산 수식 및 원리 (실무 관례 반영)
* **다짐상태 기준의 산출 (운반계획 실무 표준)**:
* 유토곡선은 다짐상태를 기준으로 유동 토량을 계산합니다.
* **측점별 순토량 ($N_i$)**:
$$N_i = \sum [C_{i, j} \times C_j] - F_i$$
* $C_{i, j}$: 현재 측점 구간의 $j$번째 지반유형별 절토량 (자연상태, ㎥)
* $C_j$: $j$번째 지반유형의 토량환산계수(다짐률)
* $F_i$: 현재 측점 구간의 성토량 (다짐상태, ㎥)
* **누가토량 ($M_i$)**:
$$M_i = M_{i-1} + N_i$$
* **곡선 증감 해석**:
* 상승 구간 ($M_i > M_{i-1}$): 절토 우세 구간
* 하강 구간 ($M_i < M_{i-1}$): 성토 우세 구간
* 극댓값/극솟값: 절토/성토 우세가 전환되는 변곡점
* 동일 누가토량 수평선: 구간 내 절토·성토 토량 균형 (Balance Line)
## 3. 지반유형별 토량환산계수 기본값 (`config_system.py`)
지반유형(`soil`, `ripping_rock`, `blasting_rock`)에 따른 체적 변화 계수(L: 흐트러진 상태, C: 다져진 상태) 기본값은 다음과 같이 관리하며, 현장별 조정을 위해 설정 가능하도록 제공합니다.
| B06 지반유형 | 대응 암종 | 팽창률 (L) | 다짐률 (C) |
|---|---|---|---|
| 토사 `soil` | 풍화토~점토 | 1.25 | 0.90 |
| 리핑암 `ripping_rock` | 풍화암~연암 하단 | 1.35 | 1.15 |
| 발파암 `blasting_rock` | 보통암 중앙 | 1.60 | 1.30 |
## 4. 토공 운반장비 선정거리 및 분배 기준 (`config_system.py`)
평균운반거리에 따른 장비 선정 기준은 오직 `config_system.py`의 `EARTHWORK_HAUL_EQUIPMENT_LIMITS_M` 상수에서 단일 관리됩니다. (3공구 도면 실측치 및 실무 관행 적용)
* **종무대 (무대운반)**: 운반거리 $\le$ 20.0m
* **불도저 (압토운반)**: 운반거리 $\le$ 50.0m
* **덤프트럭 (기타운반)**: 운반거리 50.0m 초과 (나머지 전체)
* **자연방토 (`natural_spoil_m3`)**: 성토 사면 경사가 `NATURAL_SPOIL_MIN_GROUND_SLOPE = 1/1.5` 이상으로 급하여 기계적으로 흙을 운반하지 않고 흘려보내는 자연탈락 물량. 사토 수량에서 자동 공제되어 balloon에 `M.N=측점` 형태로 표기됩니다.
## 5. 유토곡선 곡선 사양 (B06 구현 v2)
사용자가 비교 분석할 수 있도록 **기준 2종 × 지반유형 1종 = 총 2개 곡선**을 중첩하여 제공합니다.
* **기준 2종**:
1. **횡단 기준**: 실제 횡단 단면적 기반의 정밀 산출 (`design.cut_area_m2` / `fill_area_m2`)
2. **종단 기준**: 계획고 - 지반고 (`difference_m`) × 노반폭 기반의 개략 산출 (균형 판정 지표)
* **지반유형 1종**:
- 횡단도 기하 및 암 경계선 기준의 토사/암반 면적 분리 기능 신설에 따라, **지반유형별** L, C 팽창/다짐률 개별 적용 곡선만 유지합니다. (실제 정보가 없던 `토사 단일`, `환산 없음` 곡선은 삭제).
## 6. 웹앱 연동 및 시각화 명세 (2026-08-02 확정)
* **웹앱 연동 및 시각화 명세 (2026-08-03 확정)**:
* **자동 Y스케일 및 Y축 0선 표기**: Y축 눈금은 노선 데이터 범위 기반의 동적 Y스케일링을 수행하며, 차트 상 0선(Balance Line)에 명시적으로 눈금값 "0"을 렌더링합니다.
* **평형선 엔진 및 장비 띠 분할**: 순차 평형선 탐색 알고리즘(`computeHaulPlan`)을 기반으로 사토/토취 단차를 둔 평형선을 산출하며, 장비 한계거리별로 영역을 쪼갠 띠(`HaulBand`)를 반투명 다각형으로 렌더링합니다.
* **다중 곡선화 및 직선 보간**: `PARABOLIC_MASS_CURVE = false` 스위치 단일화로 포물선 오차를 제거하고 현 길이/그리기 기준을 직선 연결로 고정. 횡단/종단 기준 × 지반유형 옵션 오버레이 지원.
* **장거리 운반 상쇄 (`HaulTransfer`)**: 띠 분배 후 남은 사토/토취 잔량은 토공 최소화 원칙에 따라 최단거리 쌍으로 자동 상쇄 연계(덤프 운반) 처리하여 최종 사토량 항등식의 수치적 오차를 0으로 맞춥니다.
* **물량 육각 Balloon 인터랙션**: 충돌 회피(`findSlot` 링 탐색) 및 화면 이탈 방지 clamping이 적용되어 있고, 드래그 위치 보존 및 더블클릭 복귀를 지원합니다.
* **UI/UX 레이아웃 보정**: B06 상단 패널 접기 손잡이 `bottom: -24px` 독립 배치(`createWorkflowPanelHandle` collapseToward: up/down 확장), 첫 렌더 시 `panelHeight()` 인라인 CSS 변수 우선 참조로 종단면도 축소 결함 해결.
* **B05 유토곡선 슬라이드 패널 이관 & 공용화**: B05 노선 설계 화면에 유토곡선 2차 슬라이드 패널 구축, `common_util_mass_haul*.ts|css` 공용 모듈 분리 및 `MassHaulAxis` 파라미터화, B05-B06 간 싱글턴 캐시 공유(`ProfileCross_Section_Store.ts`).
* **사토장 모델 & B08 수량산출 인계 (2026-08-04 확정)**: 사토 balloon에 `L=` 및 장비 표기, 잔량 발생 시 다중 부지 매칭(`settleResiduals`)을 적용하며, 사토장 자동 선정 취소 및 B05 구조물 직접 배치 방식 전환에 따라 유토곡선->B08 수량산출 자동 인계는 최종 취소(운반비 미계상) 처리되었습니다. 자연방토 임계 경사(`NATURAL_SPOIL_MIN_GROUND_SLOPE = 1.0 / 1.5`)는 실무 도면 기재 관행을 반영하여 그대로 유지됩니다.
* **후속 주의사항 13개 지침**: 암 경계선 지반선 복사 오프셋, 표준단면 토큰 단일화, B06 상세조회 백엔드 반영 시점, 다짐상태 유토곡선 누적, `EARTHWORK_HAUL_EQUIPMENT_LIMITS_M` 단일참조, 토량 배분 3원칙, 사면-지반 첫 교차 정지 등 지침 통합 관리.
* **측점 간격**: 20m 간격 기준 (`config/config_system.py`의 `SECTION_STATION_INTERVAL_M = 20.0` 적용).
* **B08 납품도면**: 확정 종단 DB의 `mass_haul`을 사용해 A1 토적도를 H=1:2,000, 세로 1mm=50㎥로 생성합니다. 상세 구성과 후속 결정은 [[B08_DesignDetail/B08_drawing_masshaul_watershed]]를 참조합니다.
* **사용처**: [[B05_Profile/B05_frontend_alignment]], [[B06_Section/B06_frontend]], [[B06_Section/B06_backend]], [[B07_Quantity/B07_frontend]], [[B08_DesignDetail/B08_drawing_masshaul_watershed]], [[B09_Estimation/B09_frontend]]
@@ -0,0 +1,37 @@
---
type: concept
status: stable
related_pages: ["[[B08_Quantity/B08_overview_2026_09]]", "[[B09_Estimation/B09_overview_2026_09]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-09-09
source: ["docs/raw/plans/2026-09-08_plan_B08_B09_설계합의.md"]
---
# B08 수량 ↔ B09 원가 계약
## 책임 경계
| 단계 | 책임 | 산출 |
|---|---|---|
| B07 | 설계도면 | 도면·상세설계 |
| B08 | 수량산출 | 물량, 공종코드, 판정 근거, 자재총괄 |
| B09 | 원가계산 | 단가산출, 예산내역, 공사원가계산 |
경계선은 자재/작업이 아니라 **수량/금액**이다. B08은 금액을 만들지 않고 B09는 물량을 다시 세지 않는다.
## 저장·인계 규칙
| 자원 | 정본 | 사용처 |
|---|---|---|
| 공종 마스터·원단위표 | `resources/` 버전 파일+매니페스트 | B08 생산, B09 읽기 |
| 수량 결과·자재 총괄 | 프로젝트 영구저장소 | B08 저장, B09 소비 |
| 구조물 제원 | `B05_Profile/route/structures.json` + B06 횡단 제원 | B08 전개식 |
| 기준자료 버전 | `dataset_id`·`effective_date`·`sha256` | 프로젝트 재현성 |
B08→B09 인계는 공종코드·명칭·규격·단위·수량과 공급 구분, 암 갈래, 운반거리·수단, 할증 전후, 측점 구간, 규격 상세를 포함한다.
## 금지 규칙
- 할증은 자재 총괄에서 한 번만 적용한다. 원단위와 일위대가 재료비는 할증 전 값이다.
- `free_haul` 20m 이하는 품에 포함되므로 내역 줄을 만들지 않고 검산 수량으로만 보존한다.
- 문자열 이름 매칭 대신 공종코드를 사용한다.
- 성분·밑수·근거가 빠진 공종은 그럴듯한 금액을 만들지 않고 미확보로 표시한다.
+19
View File
@@ -0,0 +1,19 @@
---
type: concept
status: draft
related_pages: ["[[architecture/shared_resources]]"]
last_updated: 2026-07-12
source: raw/guidelines/backend.md
---
# 공통 스키마 (Pydantic 요청/응답 규칙)
## 검증 원칙 (backend.md 4절)
- 모든 JSON 요청은 라우터 진입 전 Pydantic 모델로 타입·범위 검증.
- 모든 지형/메쉬 연산은 `try-except` 필수.
- 에러 응답 표준 포맷: `{"status": "error", "message": "원인"}` — 전 라우터 공통, 프론트도 동일 포맷 기대.
## 명명 규칙
파일명 `[폴더명]_Schema.py`, 페이지 폴더 내부 배치 (전역 공유 스키마 폴더 없음 — 필요 시 여기에 항목 추가).
> 현재 raw 자료에서 페이지 간 공유되는 구체적 Pydantic 모델(예: 공통 페이지네이션, 공통 좌표 타입)은 확인되지 않음. 발견 시 이 페이지에 추가.
@@ -0,0 +1,34 @@
---
type: concept
status: draft
related_pages: ["[[B07_DesignDetail/B07_standard_drawings_2026_09]]", "[[quantity_cost_contract]]", "[[B08_Quantity/B08_overview_2026_09]]", "[[B09_Estimation/B09_overview_2026_09]]", "[[law_source_quality]]"]
last_updated: 2026-09-09
source: ["docs/raw/verification/2026-09-08_표준도_위_확정대기_배치.md", "docs/raw/verification/2026-09-08_남의_결론_검증_표준도.md", "docs/raw/verification/2026-09-08_표준도_B08_일감_크기.md", "docs/raw/verification/2026-09-08_B08화면과_표준도_오가는_길.md", "docs/raw/verification/2026-09-08_지식DB_재조사_안읽은파일.md", "docs/raw/verification/2026-09-08_실무원본_돌종류_채집여부.md", "docs/raw/verification/2026-09-08_법령_행정규칙_원문_점검.md", "docs/raw/verification/2026-09-09_B07_표준도_조사와_합의.md"]
---
# 표준도·수량·원가 입력의 미결 경계
## 확인된 분류
| 종류 | 예 | 처리 |
|---|---|---|
| 사용자 입력 | 표토 제거두께, 공급 구분, 돌 규격·쌓기 방식 | 프로젝트 설정에서 입력 |
| 자동 계산 | 구조물 원단위, 규준틀 조건, 유토곡선 평균운반거리 | 정본 제원·설계 결과에서 산출 |
| 기준자료 | 품셈, 노임·기계·요율, 법정 설계서 구성 | 버전 파일과 근거 보존 |
| 미확보 | BOX 두께, 일부 표준도 치수, 사급 단가 | 임의 확정 금지 |
## 재조사로 바뀐 판정
- 이음 간격은 “사용처 없음”이 아니라 표준도 표에 들어갈 자리로 확인됐다.
- 버림 콘크리트는 산출 대상이며 실무 원본에 두께 근거가 있다.
- 표토 제거두께는 품셈 고정값이 아니라 공식의 설계 입력 변수다.
- 목재틀흙막이 밑수 1㎥는 구조물 체적이 아니라 목재 채적이며 구조 등급 판정이 남는다.
- BOX암거 두께는 사용자 선택값이 아니라 하중 검토 또는 표준도 확보가 필요한 구조설계 결과다.
- 돌 재료는 야면석·채집석/구입석 갈래가 실무 원본에 있으나 선택 기준은 확정되지 않았다.
## 사용자·자료 대기
- 제잡비 밑수, 내역 수량 표시 자릿수, 목재틀 등급, 석재 할증 적용 여부.
- 사급 자재 단가, 유가 지역값, 밑수 미확보 항목, 표준도 제원.
- 미결은 `근거 미확인` 또는 사용자 확정 대기로 유지하며 웹 검색값이나 임의 수치로 채우지 않는다.
- 상세 화면·저장·도면 계약은 [[B07_DesignDetail/B07_standard_drawings_2026_09]]에 연결한다.
+50
View File
@@ -0,0 +1,50 @@
---
type: concept
status: draft
related_pages: ["[[B02_ProjRegister/B02_backend]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[B05_Profile/B05_backend]]", "[[B06_Section/B06_backend]]", "[[B07_Quantity/B07_backend]]", "[[B08_DesignDetail/B08_backend]]", "[[B09_Estimation/B09_frontend]]", "[[architecture/implementation_status]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-23
source: raw/guidelines/structure.md, raw/guidelines/db_schema.md, raw/guidelines/backend.md, raw/guidelines/agent.md, raw/plans/2026-07-17_plan_b04_defects.md, raw/plans/2026-07-26_plan_도엽_오버레이.md
---
# 저장 경로 규칙 (Workflow-based Folder Structure)
## 경로 패턴
```
storage/{company_slug}/{user_slug}/{project_id}/
├── B03_FileInput/input/{file_type}/ WF0 원본 입력
├── B04_PreProcess/
│ ├── processed/ 변환 지형 및 타 지도 가공 데이터
│ │ └── map_sheets/ 1:5,000 수치지형도 도엽 zip 및 metadata
│ └── models/ WF1 모델 (지면 필터 ground_points_{filter}.npz 캐시 포함)
├── B05_Profile/route/ WF2 경로·일반 구조물 structures.json
├── B05_Profile/corridor/ WF2 3D 코리도 corridor_{route:04d}.json
├── B06_Section/longitudinal/, cross_sections/ WF3 종횡단
├── B07_Quantity/ 현재 별도 산출물 없음
├── B08_DesignDetail/
│ ├── manifest.json 도면 확정 메타데이터·횡단 quantity_table
│ └── drawings/{drawing_id}.json 확정 CAD 도면
└── B09_Estimation/ 현재 산출 backend 미확인
```
## 원칙 (backend.md 3절)
1. **하드코딩 금지** — 경로는 `config/config_system.py`에서 import.
2. **물리 파일은 DB 저장 금지** — 대용량 파일은 파일시스템, DB에는 경로만.
3. **단계별 루트 강제** — 각 B0x 폴더명은 실제 워크플로우 페이지명과 동일해야 함. `raw/`, `processed/`, `computed/`를 프로젝트 루트 공용 폴더로 만들지 않음.
4. **경로 생성 책임** — 원칙상 단계별로 분리하되, 현재 B05가 B06 종횡단 파일을 생성하고 B08이 B06 단면을 재계산하므로 실제 구현 예외를 함께 추적한다.
5. **상대 경로만 DB 저장** — 프로젝트 루트 기준 상대경로. 사용자 입력 경로 직접 결합 금지(경로 이탈 방지), 절대경로 저장 금지.
## DB 컬럼 ↔ 실제 경로 매핑
상세 표 → [[db_schema/overview]] "파일 경로 추적 컬럼"
## 파일명 규칙 (structure.md 1절)
- 페이지 폴더: 로그인 전 `A0x_`, 로그인 후 `B0x_`, 워크플로우는 `wf[번호]` 접두사
- 파일명: `폴더명(페이지명)_기능_기타사양.확장자`
- 공통 유틸: `common_util/common_util_기능.확장자`
## 코드 감사 주의사항
- B05 `generate_sections()`가 `B06_Section/longitudinal`과 `cross_sections`를 생성한다.
- B05 일반 구조물은 `B05_Profile/route/structures.json`, 배관은 B04 공용 `pipe_points.json`이 각각 정본이다. [[B05_Profile/B05_structures]] 참조.
- B05 예상형상 코리도는 DB가 아닌 `B05_Profile/corridor/corridor_{route:04d}.json`에 입력 해시와 리본을 원자 저장한다. [[B05_Profile/B05_corridor_surface]] 참조.
- B08은 `B06_Section` 산출물을 읽고 `B08_DesignDetail/manifest.json` 및 `drawings/*.json`을 저장한다.
- `workflow.json`은 프로젝트 루트에 있지만 workflow 상태 SSOT는 아니다.
+33
View File
@@ -0,0 +1,33 @@
---
type: concept
status: stable
page_id: concept_temp_upload
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[B03_FileInput/B03_backend]]", "[[B03_FileInput/B03_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-08
source: docs/raw/verification/2026-08-08_verify_R1_R2_features.md
---
# Temp Upload (프로젝트 생성 전 임시 보관함)
R2 요구사항에 따른 프로젝트 생성 전 라이다/설계 자료 임시 보관 및 관리 기능 명세.
## 주요 개념 및 스펙
- **DB 테이블**: `temp_upload_batches` (임시 보관 묶음/그룹), `temp_upload_files` (보관 파일), `upload_sessions` (`project_id` NULL 허용 완화 및 `temp_batch_id` 연결).
- **만료 관리**: 30일 경과 만료 보관 자료 자동 삭제 정리 (`common_util_temp_cleanup.py` 내 `lifespan` 주기 루프).
- **영구 저장소 연동**: B03 파일 입력에서 [임시 보관함에서 불러오기] 선택 시 `attach` API 호출을 통해 영구 프로젝트 저장소로 이동 및 체인 자동 트리거.
## 주요 구성 요소
| 항목 | 위치 | 역할 |
|---|---|---|
| `010_temp_upload.sql` | `db_management/010_temp_upload.sql` | DB DDL 스크립트 |
| `B03_FileInput_Router_Temp.py` | `B03_FileInput/B03_FileInput_Router_Temp.py` | 임시 보관함 라우터 (묶음/파일 CRUD, attach) |
| `B03_FileInput_Schema_Temp.py` | `B03_FileInput/B03_FileInput_Schema_Temp.py` | Pydantic 스키마 |
| `B03_FileInput_Repository_Temp.py` | `B03_FileInput/B03_FileInput_Repository_Temp.py` | DB Access Repository |
| `common_util_temp_cleanup.py` | `common_util/common_util_temp_cleanup.py` | 만료 보관 자료 자동 삭제 크론/정리 |
| `B01_Dashboard_UI_TempUpload.ts` | `B01_Dashboard/B01_Dashboard_UI_TempUpload.ts` | 대시보드 하단 임시 보관함 표 |
| `B01_Dashboard_UI_TempModal.ts` | `B01_Dashboard/B01_Dashboard_UI_TempModal.ts` | 파일 등록 및 업로드 모달 |
## 사용처
- [[B01_Dashboard/B01_frontend]]
- [[B03_FileInput/B03_backend]]
- [[B03_FileInput/B03_frontend]]
+97
View File
@@ -0,0 +1,97 @@
---
status: stable
related_pages: ["[[A01_Home/A01_frontend]]", "[[A02_ProgDetail/A02_frontend]]", "[[B01_Dashboard/B01_frontend]]", "[[B03_FileInput/B03_frontend]]", "[[B04_PreProcess/B04_frontend]]", "[[B05_Profile/B05_frontend]]", "[[B06_Section/B06_frontend]]", "[[B07_Quantity/B07_frontend]]", "[[B08_DesignDetail/B08_frontend]]", "[[B09_Estimation/B09_frontend]]", "[[A06_Login/A06_frontend]]", "[[B10_Payment/B10_frontend]]", "[[B11_Status/B11_frontend]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-22
source: ["docs/raw/verification/2026-08-08_verify_dashboard_scroll_limit.md", "docs/raw/verification/2026-08-08_verify_project_delete_hard.md"]
---
# UI Templates — Localization & Components
프론트엔드 공통 UI 요소: 다국어(i18n), 공통 컴포넌트, 테마 스타일, 레이아웃, 리사이저, 지도 팔레트. 디자인 시스템: [[design]]
## ui_template_locale.ts (다국어 관리)
**파일**: `ui_template/ui_template_locale.ts` (배럴 파일) 및 하위 사전 파일 4종
| 항목 | 위치 | 역할 |
|---|---|---|
| `ui_template_locale.ts` | `ui_template/ui_template_locale.ts` | 배럴 파일. `ui_template_locale_common/a/b1/b2` 합성 및 `LANGUAGES`/`LanguageCode`/`currentLanguageIndex`/`setLanguage`/`t`/`ui_locales`/`LocaleKey` 동일 노출 |
| `ui_template_locale_common.ts` | `ui_template/ui_template_locale_common.ts` | 헤더/푸터/버튼/공통 문구 사전 (60개 키, 105줄) |
| `ui_template_locale_a.ts` | `ui_template/ui_template_locale_a.ts` | A그룹 (A01~A09 로그인 전) 문구 사전 (141개 키, 278줄) |
| `ui_template_locale_b1.ts` | `ui_template/ui_template_locale_b1.ts` | B그룹 전반부 (B01~B04) 문구 사전 (하드 삭제 경고 `B01_Dashboard_Confirm_DeleteProject_Hard` 추가) |
| `ui_template_locale_b2.ts` | `ui_template/ui_template_locale_b2.ts` | B그룹 후반부 (B05~B11) 문구 사전 (253개 키, 420줄) |
| `t(key)` | `ui_template/ui_template_locale.ts` | 지정된 키에 대응하는 현재 언어 텍스트 반환 |
## ui_template_resizer.ts (패널 리사이저 템플릿)
**파일**: `ui_template/ui_template_resizer.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `attachResizer(opts)` | `ui_template/ui_template_resizer.ts` | 패널 상하/좌우 드래그 리사이저 핸들 조립 (Pointer Capture 적용, CSS 변수 및 `sessionStorage` 연동) |
## ui_template_palette.ts (지도 팔레트 캐싱 유틸)
**파일**: `ui_template/ui_template_palette.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `themeColor(tokenName)` | `ui_template/themeColor(tokenName)` | CSS 변수 `--map-*` 33종 색상 토큰을 캔버스/SVG용 hex/rgb로 파싱 및 캐싱 |
## ui_template_general_blocks.ts (일반업무 공용 블록)
**파일**: `ui_template/ui_template_general_blocks.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `section(title, content)` | `ui_template/ui_template_general_blocks.ts:29` | 일반업무(B01/B02/B03/B10/B11)용 레이아웃 섹션 래퍼 |
| `buildSectionHeader(title)` | `ui_template/ui_template_general_blocks.ts:9` | 섹션 타이틀 헤더 렌더링 |
| `table(headers, rows)` | `ui_template/ui_template_general_blocks.ts:88` | 스타일이 적용된 데이터 테이블 조립 컴포넌트 |
| `limitVisibleRows(host, items, visible)` | `ui_template/ui_template_general_blocks.ts:53` | 지정한 개수 이상일 때 4행 높이에 맞춰 컨테이너의 `max-height`를 동적으로 재고 세로 스크롤 활성화 (WeakMap으로 리사이즈 중복 리스너 해제) |
## ui_template_general_layout.ts (일반업무 레이아웃)
**파일**: `ui_template/ui_template_general_layout.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `createGeneralLayout(opts)` | `ui_template/ui_template_general_layout.ts:20` | B01 스타일 기준의 중앙 콘텐츠 폭을 지닌 일반업무용 페이지 프레임 구성 |
## ui_template_elements.ts (공통 엘리먼트 템플릿)
**파일**: `ui_template/ui_template_elements.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `createButton(opts)` | `ui_template/ui_template_elements.ts:15` | 공통 버튼 생성 템플릿. `ButtonVariant` 타입에 `"glass"` 추가, 반투명 배경 및 블러 스타일(`.ui-btn--glass`) 지원 |
## ui_template_overlay.ts (오버레이 컴포넌트)
**파일**: `ui_template/ui_template_overlay.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `createVerticalStepBar(opts)` | `ui_template/ui_template_overlay.ts:15` | 우측 세로 진행단계 오버레이 패널 (기본 펼침, 접기/펼치기 및 sessionStorage에 토글 상태 보존) |
| `createWorkflowPanelHandle(opts)` | `ui_template/ui_template_overlay.ts:50` | 공통 접기/펼치기 핸들 컴포넌트 (placement 'side'/'bottom' 및 collapseToward 'left'/'right'/'up'/'down' 대응, CSS 삼각형 rotate 토글 적용) |
| `createTitleCard(title, subtitle)` | `ui_template/ui_template_overlay.ts:85` | 헤더 제거 페이지(B03, B04~B09)용 좌상단 오버레이 카드 |
| `createOptionOverlay(content)` | `ui_template/ui_template_overlay.ts:125` | 엔지니어링 그룹용 제목 카드 하단 옵션 배치 오버레이 |
## ui_template_workflow_layout.ts (엔지니어링 레이아웃)
**파일**: `ui_template/ui_template_workflow_layout.ts`
| 항목 | 위치 | 역할 |
|---|---|---|
| `createWorkflowLayout(opts)` | `ui_template/ui_template_workflow_layout.ts:28` | **상단 헤더(제목/단계)가 제거**되고, 전체 화면 폭 본문 + 좌상단 제목 카드 + 우측 세로 단계 오버레이가 결합된 완성형 엔지니어링 레이아웃 |
## theme.css (스타일 변수)
**파일**: `ui_template/theme.css`
| 항목 | 위치 | 역할 |
|---|---|---|
| `--color-primary`, `--color-primary-text` | `ui_template/theme.css:10` | 기본 색상 및 기본 텍스트 색상 |
| `--color-canvas`, `--color-paper` | `ui_template/theme.css:15` | 기본 캔버스 배경 및 레이어 카드 배경 |
| `--color-deep-iris`, `--color-mist-violet` | `ui_template/theme.css:22` | 라벤더 그라디언트 및 브랜드 서브 컬러 |
| `--spacing-8`, `--spacing-16` 등 | `ui_template/theme.css:45` | 기본 마진/패딩 간격 시스템 (8px 배수) |
| `--radius-cards`, `--radius-icons` | `ui_template/theme.css:110` | 8px 등의 둥근 테두리 곡률 반지름 변수 |
## 제약 (backend.md §1)
1. **다국어**: 모든 UI 문구는 반드시 `ui_locales` 등록 후 `L(key)` 또는 `t(key)`로만 참조
2. **스타일**: CSS는 `theme.css` 변수만 사용, 하드코드 색상/단위 금지
3. **컴포넌트 재사용**: `createGeneralLayout`, `createWorkflowLayout`, `createVerticalStepBar` 등 공용 템플릿 사용
## 남은 파일 한계
2026-08-22 현재 `ui_template_elements.ts`는 891줄이다. 동작 문제는 아니지만 단일 파일 700줄 제한을 넘으므로 후속 분리 대상이다.
+66
View File
@@ -0,0 +1,66 @@
---
type: concept
status: stable
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[B02_ProjRegister/B02_backend]]", "[[B03_FileInput/B03_backend]]", "[[B04_PreProcess/B04_backend]]", "[[B05_Profile/B05_backend]]", "[[B06_Section/B06_backend]]", "[[B07_Quantity/B07_backend]]", "[[B08_DesignDetail/B08_backend]]", "[[B09_Estimation/B09_frontend]]", "[[architecture/implementation_status]]", "[[architecture/shared_resources]]"]
last_updated: 2026-08-16
source: ["docs/raw/verification/2026-07-19_verify_webcad_poc.md", "docs/raw/verification/2026-07-19_verify_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md", "docs/raw/verification/2026-07-21_verify_B06_default_design_B07_gating.md", "docs/raw/verification/2026-08-04_verify_b05_b06_profile_ui_chain.md", "docs/raw/verification/2026-08-08_verify_R1_R2_features.md", "docs/raw/verification/2026-07-17_verify_workflow_stepbar.md"]
---
# Workflow 상태 관리
> DB 상태 유틸은 구현돼 있다. 그러나 B07은 임시 완료 우회, B09는 셸이므로 일곱 단계 전체가 업무 기능으로 완료된 것은 아니다.
## SSOT: `project_workflow_stages` 테이블 (실 DB 확인)
| 컬럼 | 타입 |
| --- | --- |
| id | INT PK |
| project_id | CHAR(36), FK |
| stage_no | TINYINT (0~6) |
| stage_key | VARCHAR(30) — FILE_INPUT/PREPROCESS/PROFILE/SECTION/QUANTITY/DESIGN_DETAIL/ESTIMATION |
| state | ENUM('NOT_STARTED','IN_PROGRESS','COMPLETE','FAILED','STALE') |
| progress_percent | TINYINT |
| params | LONGTEXT(JSON) — 재실행 시 폼 프리필용 |
| message, started_at, completed_at, updated_at | 진행/이력 |
생성 SQL: `db_management/006_workflow_state.sql`, 백필: `db_management/migrate_workflow_state.py`
## R1 워크플로우 단계 재편 (2026-08-08 반영)
- **B04_PreProcess** (stage 1: 지표면 분석)
- **B05_Profile** (stage 2: 경로 및 종단)
- **B06_Section** (stage 3: 횡단 및 유토곡선)
- **B07_Quantity** (stage 4: 수량 셸 신설, `confirm_quantity`로 stage 4 COMPLETE 전이)
- **B08_DesignDetail** (stage 5: CAD 도면/OpenWebCAD 이동, 정적 마운트 `/b08-cad`)
- **B09_Estimation** (stage 6: 설계도서 및 견적)
## 백그라운드 자동 계산 체인 및 사용자 설정 이월
* **업로드 후 자동 계산 체인 (B04 ➡️ B05 ➡️ B06)**: WF1(B04 지표면) 확정 성공 시 서버 백그라운드 태스크로 B05 기본 경로 계산·저장 ➡️ B06 일괄 횡단 설계를 연속 실행하여 대시보드/B05 진입 시 로딩 상태를 즉시 제공합니다.
* **B05/B06 자유 이동 및 동시 확정**: B06 전체 확정 시 stage 2와 3을 함께 COMPLETE 처리하고 B07 임시 셸로 이동한다.
* **B04 재확정 사용자 설정 이월 (`B03_FileInput_Service_Chain.py`)**: `run_redesign_chain`을 통해 B04 지표면이 재확정되어도 B05 사용자 제어점/경사 파라미터 및 B06 측점별 단면 설계를 이월하여 새 경로에 매칭 재계산 후 확정 전이시킵니다.
## 공통 유틸 `common_util/common_util_workflow_state.py`
| 함수 | 역할 |
|---|---|
| `initialize_project_stages(cursor, project_id)` | 프로젝트 생성 시 7행 NOT_STARTED 시드 |
| `start_stage(cursor, project_id, stage_no, params)` | IN_PROGRESS 전이 + N+1~6의 COMPLETE를 STALE로 전파 + `projects.status` 캐시 갱신 |
| `complete_stage(cursor, project_id, stage_no)` | COMPLETE 전이 (stage 6 완료 시 `projects.status='DONE'`) |
| `fail_stage(cursor, project_id, stage_no, message)` | FAILED 전이 |
| `update_stage_progress(cursor, project_id, stage_no, progress)` | 진행률만 갱신 |
| `get_workflow_state(cursor, project_id)` | 단건 조회, `current_stage` 계산 포함 |
| `reset_stages_after_input_change(cursor, project_id)` | B03 입력 변경 시 stage 1~6을 NOT_STARTED로 초기화 |
## 무효화의 실제 범위
| 처리 | 범위 |
|---|---|
| `start_stage()` | 뒤쪽 단계 중 `COMPLETE`만 `STALE`로 변경 |
| 공통 상태 유틸 | 단계 산출 파일·캐시를 삭제하지 않음 |
| 산출물 정리 | B03/B04/B05/B08 등 단계별 로직에 의존 |
| `workflow.json` | 초기 파일과 일부 호환 용도; DB workflow의 SSOT가 아님 |
## 조회 API
`GET /api/projects/{project_id}/workflow-state`
## 프론트엔드 게이팅 및 스텝바 연동
* **스텝바 일원화**: `createStepBar` 컴포넌트(`ui_template_workflow_layout.ts`)를 승격하여 B01 및 B03~B09에서 통합 관리.
* **게이팅 규칙**: B06 확정 후 B07로 이동한다. B07은 산출물 검사 없이 stage 4를 완료 처리하는 임시 우회다.
* **네비게이션**: `b_workflow_nav.ts` 모듈을 통해 `fetchWorkflowState`, `goToWorkflowStage` 공통 헬퍼 이용.
+74
View File
@@ -0,0 +1,74 @@
---
type: index
status: stable
last_updated: 2026-09-09
---
# Wiki Index
> 코드 어시스턴트는 프로젝트 전체 질문이면 아키텍처 지도, 특정 구현 질문이면 해당 canonical 페이지부터 읽는다.
## 우선 진입점
- [[architecture/project_map|프로젝트 지도]] — 현재 A/B 페이지 책임, 레거시 명칭 alias, 질문별 탐색 순서.
- [[architecture/workflow_data_flow|B01~B09 workflow 데이터 흐름]] — 생산·소비·상태 전이·정본 위치.
- [[architecture/implementation_status|현재 구현 현황]] — 소스 읽기 감사 기준 구현·부분 구현·임시 우회·셸 구분.
- [[architecture/shared_resources|공유 자원 영향 지도]] — DB·인증·저장소·공통 유틸·의존성 사용처.
- [[architecture/public_admin_map|공개·인증·관리 영역 지도]] — A01~A09와 B01 진입 흐름.
- [[ingest/index|인제스트 감사 원장]] — raw 180개의 명시적 근거와 계획·검증 대응 상태.
## 로그인 후 기능
- [[B01_Dashboard/B01_frontend|B01 Dashboard]] — 프로젝트·조직·사용자·임시보관·workflow 현황.
- [[B02_ProjRegister/B02_backend|B02 Project Register]] — 프로젝트 생성, workflow 7단계 시드, 저장소 초기화.
- [[B03_FileInput/B03_backend|B03 File Input]] — 업로드·WF1 실행과 [[las_free_sheet_surface|LAS 없는 도엽등고 설계]].
- [[B03_FileInput/B03_FileInput_plan_lidar_multi_file|B03 다중 라이다]] — 병합 방식 결정까지 보류.
- [[B04_PreProcess/B04_backend|B04 PreProcess]] — 지표면·GIS·도엽·배수유역 분석과 확정.
- [[B05_Profile/B05_backend|B05 Profile]] — 경로·종단·배수와 [[B05_Profile/B05_structure_stations|구조물 측점 공급]].
- [[B05_Profile/B05_completed_followups|B05 후속 완료]] · [[B05_Profile/B05_corridor_followup_decisions|3D 후속 판정]] · [[B05_Profile/B05_corridor_turn_correction_plan|급선회 계획]].
- [[B05_Profile/B05_corridor_plan_curves|B05 구조물 3D 투영 커브]] — 평면·비탈 투영, 날개벽 연결과 성토면 절단.
- [[B05_Profile/B05_corridor_cut_fill|B05 구조물 절취·성토 패치]] — 합집합 절취, 측벽, B06 구간별 성토 리본.
- [[B05_Profile/B05_corridor_patch_finish|B05 변형 성토면 마감]] — 패치 스커트, 원지반 재노출, 세월교 날개 역클리핑.
- [[B06_Section/B06_backend|B06 Section]] — 횡단·유토곡선·확정; [[B06_Section/B06_pavement_revetment|물넘이포장]], [[B06_Section/B06_revetment_link_controls|기슭막이 연동·경사·단별 제어]], [[B06_Section/B06_culvert_link_trim|인접 측점 트림]].
- [[B07_DesignDetail/B07_frontend|B07 DesignDetail]] — 상세설계·CAD·도각·설계도면과 [[B07_DesignDetail/B07_standard_drawings_2026_09|구조물 표준도]] 관리.
- [[B08_Quantity/B08_overview_2026_09|B08 Quantity]] — 토공·구조물·자재 수량산출과 B09 인계.
- [[B08_DesignDetail/B08_CAD_commands|B08 CAD 명령]] · [[B08_DesignDetail/B08_CAD_blocks|블록]] · [[B08_DesignDetail/B08_CAD_table_entity|표]] · [[B08_DesignDetail/B08_CAD_title_block|도각·표제란]].
- [[B08_DesignDetail/B08_CAD_usability_2026-09-01|B08 CAD 편의성]] — 편집 손실·확정 잠금·도면별 복구 구현 기록과 재검증 대기 상태.
- [[B08_DesignDetail/B08_cross_structure_sheets|B08 횡단 장]] · [[B08_DesignDetail/B08_drawing_masshaul_watershed|토적·유역도]].
- [[B09_Estimation/B09_overview_2026_09|B09 Estimation]] — 단가산출·예산내역·공사원가계산 5표 구현.
- [[B10_Payment/B10_frontend|B10 Payment]] · [[B11_Status/B11_frontend|B11 Status]] — 결제·진행상태 목업.
## 로그인 전·관리
- [[A00_Common/A00_Common|A00 Common]] — App Shell·라우터·공통 UI.
- [[A01_Home/A01_frontend|A01 Home]] · [[A02_ProgDetail/A02_frontend|A02 Program]] · [[A03_CompDetail/A03_frontend|A03 Company]].
- [[A04_NewsHistory/A04_frontend|A04 News]] · [[A05_EduDetail/A05_frontend|A05 Education]].
- [[A06_Login/A06_backend|A06 Login]] · [[A07_Register/A07_backend|A07 Register]].
- [[A08_Support/A08_backend|A08 Support]] · [[A09_Security/A09_backend|A09 Security]].
## 공통 개념
- 구조·UI: [[a00_app_shell_framework]], [[ui_templates]], [[design]].
- 2026-08-29 완료: [[completed_2026-08-29]] — B03 재업로드 재분석·B05 최신 조회, B05/B06 구조물 UI 통합, B07 CAD 고정 척도·횡단 장 배치 포함.
- 2026-09-01 완료: [[completed_2026-09-01]] — B04 지면 필터·온디맨드 산출, B05/B06 최소고 선택과 레거시 기슭막이 이관.
- 2026-09-01 추가 정리: [[completed_2026-09-01_followups]] — 혼합 섹션 잔여 완료 체크 37개와 B07 재검증 보류 구분.
- 2026-09-02 완료: [[completed_2026-09-02]] — 용화 노선 트림·배관 정착, 보조 포트, CAD 후속과 스테일 테스트 정리.
- 2026-09-03 완료: [[completed_2026-09-03]] — B03 정본·좌표계, B04 세부유역, B05/B06 유토곡선, B08 납품 CAD.
- 2026-09-03 추가 완료: [[completed_2026-09-03_additional]] — B03 화면, B04/B05 나침반, 종단곡선, 횡단 계산·표기.
- 2026-09-04 완료: [[completed_2026-09-04]] — B01 모달·로고, B03 미리보기, 공용 진행단계 패널, B05 3D·종단, B06 횡단, B08 도면, 700줄 제한 분리.
- 2026-09-07 완료: [[completed_2026-09-07]] — 노선·캐시·B01~B07 기능, 성능 종료 기준과 보류 갈래.
- 수량·원가 계약: [[quantity_cost_contract]] — B08 물량과 B09 금액의 책임·저장·금지 규칙.
- 표준도·입력 미결: [[standard_drawing_cost_inputs]] — 자동 계산·사용자 입력·기준자료·미확보 경계.
- 인증·상태: [[auth_rbac]], [[workflow_state]], [[temp_upload]].
- 데이터·경로: [[db_schema/overview]], [[storage_paths]], [[crs_metadata]].
- API·스키마·유틸: [[api_common]], [[schema_common]], [[common_util]].
- 도메인 흐름: [[drainage_watershed]], [[mass_haul_diagram]].
- 외부 자원: [[dependencies]], [[b07_external_webcad_demos]].
- 근거 품질: [[law_source_quality]], [[db_schema/unconfirmed/README|미확정 DB]].
## 현재 주의사항
- 2026-08-08 검증 기준 현재 workflow는 B07=수량, B08=상세설계/CAD다. 이전 B07/B08 명칭은 [[architecture/project_map]]의 alias만 사용한다.
- `draft` 페이지는 세부 사실의 독립 검증 근거가 부족한 문서다. 상위 stable 페이지와 raw 검증보고서를 함께 확인한다.
- 2026-09-08 기준 B07=상세설계, B08=수량산출, B09=원가계산이다. 구 `B07_Quantity`·`B08_DesignDetail` 문서는 레거시 경로다.
- 미확정 수치·DB 구조는 확정값으로 사용하지 않는다.
+40
View File
@@ -0,0 +1,40 @@
---
type: ingest-register-index
status: draft
related_pages: ["[[index]]"]
last_updated: 2026-09-04
---
# 인제스트 감사 원장
> raw 원본의 존재, 대응 계획·검증 후보, 현재 위키의 명시적 source 흔적을 추적한다. 상태는 내용 감사를 거쳐 확정한다.
## 상태 정의
| 상태 | 의미 |
|---|---|
| `referenced` | 현재 위키 또는 log에 파일명이 명시되어 있음. 내용 완전 반영 여부는 별도 감사 필요 |
| `covered_by_verified_pair` | 계획서와 정확히 대응하는 검증보고서가 위키 근거로 명시되어 최신 검증 결과가 우선 반영됨 |
| `covered_by_plan_reference` | 검증보고서의 대응 계획서가 위키에 명시되어 있으나 검증 결과 직접 연결은 추가 확인 필요 |
| `verification_exists_untraced` | 대응 검증보고서는 있으나 계획서 파일명의 명시적 반영 흔적 없음 |
| `plan_exists_untraced` | 대응 계획서는 있으나 검증보고서 파일명의 명시적 반영 흔적 없음 |
| `plan_only` | 자동 매칭되는 검증보고서를 찾지 못한 계획서 |
| `verification_only_untraced` | 자동 매칭되는 계획서를 찾지 못했고 명시적 반영 흔적도 없는 검증보고서 |
## 원장 페이지
- [[ingest/plan_2026_07]]
- [[ingest/plan_2026_08]]
- [[ingest/plan_undated]]
- [[ingest/verification_2026_07]]
- [[ingest/verification_2026_08]]
- [[ingest/plan_2026_09]]
- [[ingest/verification_2026_09]]
## 1차 집계
| 감사 상태 | 개수 |
|---|---:|
| `covered_by_verified_pair` | 59 |
| `referenced` | 160 |
| **합계** | **219** |
+68
View File
@@ -0,0 +1,68 @@
---
type: ingest-register
status: draft
related_pages: ["[[ingest/index]]"]
last_updated: 2026-08-16
---
# 계획서 인제스트 원장 — 2026-07
> 이 표는 파일명과 현재 위키의 명시적 source 흔적을 대조한 1차 감사 결과다. `referenced`는 완전 반영을 보증하지 않는다.
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---:|---|
| [2026-07-17_plan_B04_contour.md](../../raw/plans/2026-07-17_plan_B04_contour.md) | 2026-07-17_verify_B04_contour.md | 0 | `covered_by_verified_pair` |
| [2026-07-17_plan_b04_defects.md](../../raw/plans/2026-07-17_plan_b04_defects.md) | 2026-07-17_verify_b04_defects.md | 1 | `referenced` |
| [2026-07-17_plan_B04_Surface_Reorganization.md](../../raw/plans/2026-07-17_plan_B04_Surface_Reorganization.md) | 2026-07-17_verify_B04_Surface_Reorganization.md | 0 | `covered_by_verified_pair` |
| [2026-07-18_plan_b04_confirm_b05_rebuild.md](../../raw/plans/2026-07-18_plan_b04_confirm_b05_rebuild.md) | 2026-07-18_verify_b04_confirm_b05_rebuild.md | 0 | `covered_by_verified_pair` |
| [2026-07-18_plan_B04_old_align.md](../../raw/plans/2026-07-18_plan_B04_old_align.md) | 2026-07-18_verify_B04_old_align.md | 0 | `covered_by_verified_pair` |
| [2026-07-18_plan_B06_DrawingRendering.md](../../raw/plans/2026-07-18_plan_B06_DrawingRendering.md) | 2026-07-18_verify_B06_DrawingRendering.md | 0 | `covered_by_verified_pair` |
| [2026-07-18_plan_B06_ProfileCross.md](../../raw/plans/2026-07-18_plan_B06_ProfileCross.md) | 2026-07-18_verify_B06_ProfileCross.md | 0 | `covered_by_verified_pair` |
| [2026-07-18_plan_crs_normalization.md](../../raw/plans/2026-07-18_plan_crs_normalization.md) | - | 2 | `referenced` |
| [2026-07-18_plan_dependency_upgrade.md](../../raw/plans/2026-07-18_plan_dependency_upgrade.md) | - | 1 | `referenced` |
| [2026-07-18_plan_layout_improvement.md](../../raw/plans/2026-07-18_plan_layout_improvement.md) | 2026-07-18_verify_layout_improvement.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_b04_gis_theme.md](../../raw/plans/2026-07-19_plan_b04_gis_theme.md) | 2026-07-19_verify_b04_gis_theme.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_B05_B06_improvements.md](../../raw/plans/2026-07-19_plan_B05_B06_improvements.md) | 2026-07-19_verify_B05_B06_improvements.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_B05_B06_UI_Station_Improvement.md](../../raw/plans/2026-07-19_plan_B05_B06_UI_Station_Improvement.md) | 2026-07-19_verify_B05_B06_UI_Station_Improvement.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_B05_B06_차트_레이아웃_후속보정.md](../../raw/plans/2026-07-19_plan_B05_B06_차트_레이아웃_후속보정.md) | 2026-07-19_verify_B05_B06_차트_레이아웃_후속보정.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_b05_dark_theme.md](../../raw/plans/2026-07-19_plan_b05_dark_theme.md) | 2026-07-19_verify_b05_dark_theme.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md](../../raw/plans/2026-07-19_plan_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md) | 2026-07-19_verify_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_B07_DesignDetail.md](../../raw/plans/2026-07-19_plan_B07_DesignDetail.md) | 2026-07-19_verify_B07_DesignDetail.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_b07_external_webcad_demos.md](../../raw/plans/2026-07-19_plan_b07_external_webcad_demos.md) | 2026-07-19_verify_b07_external_webcad_demos.md | 1 | `referenced` |
| [2026-07-19_plan_b07_independent_cad.md](../../raw/plans/2026-07-19_plan_b07_independent_cad.md) | 2026-07-19_verify_b07_independent_cad.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_CrossPruning_and_CADStyle.md](../../raw/plans/2026-07-19_plan_CrossPruning_and_CADStyle.md) | 2026-07-19_verify_CrossPruning_and_CADStyle.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_half_width_persistence.md](../../raw/plans/2026-07-19_plan_half_width_persistence.md) | 2026-07-19_verify_half_width_persistence.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_responsive_layout_drag.md](../../raw/plans/2026-07-19_plan_responsive_layout_drag.md) | 2026-07-19_verify_responsive_layout_drag.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_scrollbar_theme.md](../../raw/plans/2026-07-19_plan_scrollbar_theme.md) | 2026-07-19_verify_scrollbar_theme.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_종횡단_생성_B05_이관.md](../../raw/plans/2026-07-19_plan_종횡단_생성_B05_이관.md) | 2026-07-19_verify_종횡단_생성_B05_이관.md | 0 | `covered_by_verified_pair` |
| [2026-07-19_plan_종횡단_이슈수정_3건.md](../../raw/plans/2026-07-19_plan_종횡단_이슈수정_3건.md) | 2026-07-19_verify_종횡단_이슈수정_3건.md | 0 | `covered_by_verified_pair` |
| [2026-07-20_plan_B05_longitudinal_grade_line.md](../../raw/plans/2026-07-20_plan_B05_longitudinal_grade_line.md) | 2026-07-20_verify_B05_longitudinal_grade_line.md | 0 | `covered_by_verified_pair` |
| [2026-07-20_plan_B06_profile_cross_design_elevation.md](../../raw/plans/2026-07-20_plan_B06_profile_cross_design_elevation.md) | 2026-07-20_verify_B06_profile_cross_design_elevation.md | 1 | `referenced` |
| [2026-07-20_plan_B07_상세설계개선.md](../../raw/plans/2026-07-20_plan_B07_상세설계개선.md) | 2026-07-20_verify_B07_상세설계개선.md | 0 | `covered_by_verified_pair` |
| [2026-07-20_plan_b08_quantity_template.md](../../raw/plans/2026-07-20_plan_b08_quantity_template.md) | 2026-07-20_verify_b08_quantity_template.md | 0 | `covered_by_verified_pair` |
| [2026-07-21_plan_B06_default_design_B07_gating.md](../../raw/plans/2026-07-21_plan_B06_default_design_B07_gating.md) | 2026-07-21_verify_B06_default_design_B07_gating.md | 1 | `referenced` |
| [2026-07-21_plan_B06_ground_section_type_B07_linkage.md](../../raw/plans/2026-07-21_plan_B06_ground_section_type_B07_linkage.md) | 2026-07-21_verify_B06_ground_section_type_B07_linkage.md | 1 | `referenced` |
| [2026-07-22_plan_B06_B07.md](../../raw/plans/2026-07-22_plan_B06_B07.md) | 2026-07-22_verify_B06_B07.md | 1 | `referenced` |
| [2026-07-23_plan_B05_종단_계획선_편집_체계_개편.md](../../raw/plans/2026-07-23_plan_B05_종단_계획선_편집_체계_개편.md) | 2026-07-23_verify_B05_종단_계획선_편집_체계_개편.md | 1 | `referenced` |
| [2026-07-24_plan_B05_B06_표준횡단.md](../../raw/plans/2026-07-24_plan_B05_B06_표준횡단.md) | 2026-07-24_verify_B05_B06_표준횡단.md | 0 | `covered_by_verified_pair` |
| [2026-07-24_plan_B05_irregular_stations.md](../../raw/plans/2026-07-24_plan_B05_irregular_stations.md) | 2026-07-24_verify_B05_irregular_stations.md | 0 | `covered_by_verified_pair` |
| [2026-07-24_plan_B05_layout_refinements.md](../../raw/plans/2026-07-24_plan_B05_layout_refinements.md) | 2026-07-24_verify_B05_layout_refinements.md | 0 | `covered_by_verified_pair` |
| [2026-07-24_plan_B05_layout_refinements_2.md](../../raw/plans/2026-07-24_plan_B05_layout_refinements_2.md) | 2026-07-24_verify_B05_layout_refinements_2.md | 0 | `covered_by_verified_pair` |
| [2026-07-24_plan_b05_reorganization.md](../../raw/plans/2026-07-24_plan_b05_reorganization.md) | 2026-07-24_verify_b05_reorganization.md | 1 | `referenced` |
| [2026-07-24_plan_B05_Route_Improvements.md](../../raw/plans/2026-07-24_plan_B05_Route_Improvements.md) | 2026-07-24_verify_B05_Route_Improvements.md | 1 | `referenced` |
| [2026-07-24_유토곡선_분석_및_웹앱_계산명세.md](../../raw/plans/2026-07-24_유토곡선_분석_및_웹앱_계산명세.md) | - | 4 | `referenced` |
| [2026-07-25_plan_b05_b06_3rd_4th_improvements.md](../../raw/plans/2026-07-25_plan_b05_b06_3rd_4th_improvements.md) | 2026-07-25_verify_b05_b06_3rd_4th_improvements.md | 1 | `referenced` |
| [2026-07-25_plan_b05_b06_modifications.md](../../raw/plans/2026-07-25_plan_b05_b06_modifications.md) | 2026-07-25_verify_b05_b06_modifications.md | 1 | `referenced` |
| [2026-07-25_plan_b06_2nd_improvements.md](../../raw/plans/2026-07-25_plan_b06_2nd_improvements.md) | 2026-07-25_verify_b06_2nd_improvements.md | 1 | `referenced` |
| [2026-07-25_plan_b06_n6_n7.md](../../raw/plans/2026-07-25_plan_b06_n6_n7.md) | 2026-07-25_verify_b06_n6_n7.md | 1 | `referenced` |
| [2026-07-25_plan_b07_design_detail.md](../../raw/plans/2026-07-25_plan_b07_design_detail.md) | 2026-07-25_verify_b07_design_detail.md | 1 | `referenced` |
| [2026-07-25_plan_b08_rebuild.md](../../raw/plans/2026-07-25_plan_b08_rebuild.md) | 2026-07-25_verify_b08_rebuild.md | 1 | `referenced` |
| [2026-07-25_plan_n2_n3_n4.md](../../raw/plans/2026-07-25_plan_n2_n3_n4.md) | 2026-07-25_verify_n2_n3_n4.md | 1 | `referenced` |
| [2026-07-26_plan_b06_aesthetics.md](../../raw/plans/2026-07-26_plan_b06_aesthetics.md) | 2026-07-26_verify_b06_aesthetics.md | 1 | `referenced` |
| [2026-07-26_plan_B07_도면_템플릿_및_도각_적용.md](../../raw/plans/2026-07-26_plan_B07_도면_템플릿_및_도각_적용.md) | 2026-07-26_verify_B07_도면_템플릿_및_도각_적용.md | 1 | `referenced` |
| [2026-07-26_plan_openwebcad_성능개선.md](../../raw/plans/2026-07-26_plan_openwebcad_성능개선.md) | 2026-07-26_verify_openwebcad_성능개선.md | 1 | `referenced` |
| [2026-07-26_plan_도엽_오버레이.md](../../raw/plans/2026-07-26_plan_도엽_오버레이.md) | 2026-07-26_verify_도엽_오버레이.md | 2 | `referenced` |
| [2026-07-28_plan_B04_B05_Drainage_Watershed.md](../../raw/plans/2026-07-28_plan_B04_B05_Drainage_Watershed.md) | 2026-07-28_verify_B04_B05_Drainage_Watershed.md | 1 | `referenced` |
| [2026-07-28_plan_B04_Map_Performance.md](../../raw/plans/2026-07-28_plan_B04_Map_Performance.md) | 2026-07-28_verify_B04_Map_Performance.md | 1 | `referenced` |
| [2026-07-31_plan_B03_planned_route_csv.md](../../raw/plans/2026-07-31_plan_B03_planned_route_csv.md) | 2026-07-31_verify_B03_planned_route_csv.md | 1 | `referenced` |
| [2026-07-31_plan_B05_drainage_watershed_pipe_edit.md](../../raw/plans/2026-07-31_plan_B05_drainage_watershed_pipe_edit.md) | 2026-07-31_verify_B05_drainage_watershed_pipe_edit.md | 1 | `referenced` |
+67
View File
@@ -0,0 +1,67 @@
---
type: ingest-register
status: draft
related_pages: ["[[ingest/index]]"]
last_updated: 2026-08-30
---
# 계획서 인제스트 원장 — 2026-08
> 이 표는 파일명과 현재 위키의 명시적 source 흔적을 대조한 1차 감사 결과다. `referenced`는 완전 반영을 보증하지 않는다.
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---|---|
| `2026-08-30_plan_B05_B06_ui_fixes.md` | B05/B06 UI | yes | ingested |
| `2026-08-30_plan_B08_CAD_commands.md` | B08 CAD 명령 | yes | ingested |
| `2026-08-30_plan_B08_masshaul_watershed_drawings.md` | B08 토적도·유역도 | yes | ingested |
| `2026-08-30_plan_B08_cross_structure_sheets.md` | B08 횡단 구조물·장 배치 | yes | ingested |
| `2026-08-30_plan_las_free_sheet_surface.md` | B03~B06 LAS 없는 설계 | yes | ingested |
| `2026-08-30_plan_B08_CAD_blocks_interaction_tables.md` | B08 블록·조작·표 | yes | ingested |
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---:|---|
| [2026-08-01_plan_B04_B05_drainage_ui_improvements.md](../../raw/plans/2026-08-01_plan_B04_B05_drainage_ui_improvements.md) | 2026-08-01_verify_B04_B05_drainage_ui_improvements.md | 1 | `referenced` |
| [2026-08-01_plan_B04_detailed_basins.md](../../raw/plans/2026-08-01_plan_B04_detailed_basins.md) | 2026-08-01_verify_B04_detailed_basins.md | 1 | `referenced` |
| [2026-08-01_plan_B04_inflow_strength_and_panel_cleanup.md](../../raw/plans/2026-08-01_plan_B04_inflow_strength_and_panel_cleanup.md) | 2026-08-01_verify_B04_inflow_strength_and_panel_cleanup.md | 0 | `covered_by_verified_pair` |
| [2026-08-01_plan_S8_B05_data_saving.md](../../raw/plans/2026-08-01_plan_S8_B05_data_saving.md) | 2026-08-01_verify_S8_B05_data_saving.md | 0 | `covered_by_verified_pair` |
| [2026-08-01_plan_ui_improvements_4_types.md](../../raw/plans/2026-08-01_plan_ui_improvements_4_types.md) | 2026-08-01_verify_ui_improvements_4_types.md | 0 | `covered_by_verified_pair` |
| [2026-08-02_plan_B04_B05_drainage_unification.md](../../raw/plans/2026-08-02_plan_B04_B05_drainage_unification.md) | 2026-08-02_verify_B04_B05_drainage_unification.md | 1 | `referenced` |
| [2026-08-02_plan_backlog_reorg.md](../../raw/plans/2026-08-02_plan_backlog_reorg.md) | 2026-08-02_verify_backlog_reorg.md | 0 | `covered_by_verified_pair` |
| [2026-08-02_plan_mass_haul_and_drainage_fixes.md](../../raw/plans/2026-08-02_plan_mass_haul_and_drainage_fixes.md) | 2026-08-02_verify_mass_haul_and_drainage_fixes.md | 1 | `referenced` |
| [2026-08-02_plan_mass_haul_distribution_and_refinements.md](../../raw/plans/2026-08-02_plan_mass_haul_distribution_and_refinements.md) | 2026-08-02_verify_mass_haul_distribution_and_refinements.md | 0 | `covered_by_verified_pair` |
| [2026-08-02_plan_mass_haul_multi_curve.md](../../raw/plans/2026-08-02_plan_mass_haul_multi_curve.md) | 2026-08-02_verify_mass_haul_multi_curve.md | 1 | `referenced` |
| [2026-08-02_plan_panel_fold_B05_style.md](../../raw/plans/2026-08-02_plan_panel_fold_B05_style.md) | 2026-08-02_verify_panel_fold_B05_style.md | 0 | `covered_by_verified_pair` |
| [2026-08-02_plan_panel_height_first_render.md](../../raw/plans/2026-08-02_plan_panel_height_first_render.md) | 2026-08-02_verify_panel_height_first_render.md | 0 | `covered_by_verified_pair` |
| [2026-08-02_plan_ui_template_locale_split.md](../../raw/plans/2026-08-02_plan_ui_template_locale_split.md) | 2026-08-02_verify_ui_template_locale_split.md | 1 | `referenced` |
| [2026-08-02_유토곡선_3공구_분석.md](../../raw/plans/2026-08-02_유토곡선_3공구_분석.md) | - | 2 | `referenced` |
| [2026-08-03_plan_B05_mass_haul_transfer.md](../../raw/plans/2026-08-03_plan_B05_mass_haul_transfer.md) | 2026-08-03_verify_B05_mass_haul_transfer.md | 1 | `referenced` |
| [2026-08-03_plan_향후작업_반영완료.md](../../raw/plans/2026-08-03_plan_향후작업_반영완료.md) | 2026-08-03_verify_향후작업_반영완료.md | 1 | `referenced` |
| [2026-08-03_plan_후속작업_주의사항.md](../../raw/plans/2026-08-03_plan_후속작업_주의사항.md) | 2026-08-03_verify_후속작업_주의사항.md | 1 | `referenced` |
| [2026-08-04_plan_b05_b06_profile_ui_chain.md](../../raw/plans/2026-08-04_plan_b05_b06_profile_ui_chain.md) | 2026-08-04_verify_b05_b06_profile_ui_chain.md | 1 | `referenced` |
| [2026-08-04_plan_mass_haul_spoil_scroll.md](../../raw/plans/2026-08-04_plan_mass_haul_spoil_scroll.md) | 2026-08-04_verify_mass_haul_spoil_scroll.md | 2 | `referenced` |
| [2026-08-05_plan_b04_b05_drainage_rainfall_structure.md](../../raw/plans/2026-08-05_plan_b04_b05_drainage_rainfall_structure.md) | 2026-08-05_verify_b04_b05_drainage_rainfall_structure.md | 1 | `referenced` |
| [2026-08-06_plan_B05_B06_feature_updates.md](../../raw/plans/2026-08-06_plan_B05_B06_feature_updates.md) | 2026-08-06_verify_B05_B06_feature_updates.md | 1 | `referenced` |
| [2026-08-06_plan_B05_bottom_panel_resize_bug.md](../../raw/plans/2026-08-06_plan_B05_bottom_panel_resize_bug.md) | 2026-08-06_verify_B05_bottom_panel_resize_bug.md | 1 | `referenced` |
| [2026-08-06_plan_B05_main_panel_resize_proportional.md](../../raw/plans/2026-08-06_plan_B05_main_panel_resize_proportional.md) | 2026-08-06_verify_B05_main_panel_resize_proportional.md | 1 | `referenced` |
| [2026-08-08_plan_B05_B06_fixes.md](../../raw/plans/2026-08-08_plan_B05_B06_fixes.md) | 2026-08-08_verify_B05_B06_fixes.md | 0 | `covered_by_verified_pair` |
| [2026-08-08_plan_dashboard_scroll_limit.md](../../raw/plans/2026-08-08_plan_dashboard_scroll_limit.md) | 2026-08-08_verify_dashboard_scroll_limit.md | 0 | `covered_by_verified_pair` |
| [2026-08-08_plan_db_initialization.md](../../raw/plans/2026-08-08_plan_db_initialization.md) | 2026-08-08_verify_db_initialization.md | 0 | `covered_by_verified_pair` |
| [2026-08-08_plan_project_delete_hard.md](../../raw/plans/2026-08-08_plan_project_delete_hard.md) | 2026-08-08_verify_project_delete_hard.md | 0 | `covered_by_verified_pair` |
| [2026-08-08_plan_R1_R2_features.md](../../raw/plans/2026-08-08_plan_R1_R2_features.md) | 2026-08-08_verify_R1_R2_features.md | 0 | `covered_by_verified_pair` |
| [2026-08-08_plan_server_and_e2e_fixes.md](../../raw/plans/2026-08-08_plan_server_and_e2e_fixes.md) | 2026-08-08_verify_server_and_e2e_fixes.md | 0 | `covered_by_verified_pair` |
| [2026-08-13_plan_rainfall_wamis_station.md](../../raw/plans/2026-08-13_plan_rainfall_wamis_station.md) | 2026-08-13_verify_rainfall_wamis_station.md | 0 | `covered_by_verified_pair` |
| [2026-08-16_plan_B05_구조물_수동추가.md](../../raw/plans/2026-08-16_plan_B05_구조물_수동추가.md) | 2026-08-16_verify_B05_구조물_수동추가_교차검증.md | 1 | `referenced` |
| [2026-08-17_plan_B04_등고선_추출_가속.md](../../raw/plans/2026-08-17_plan_B04_등고선_추출_가속.md) | 2026-08-17_verify_B04_등고선_추출_가속_교차검증.md | 1 | `referenced` |
| [2026-08-17_plan_B05_structure_options_profile_marks.md](../../raw/plans/2026-08-17_plan_B05_structure_options_profile_marks.md) | 사용자·타 AI 검증 확인(별도 보고서 생략) | 2 | `referenced` |
| [2026-08-17_plan_B05_box_ui_recommendations.md](../../raw/plans/2026-08-17_plan_B05_box_ui_recommendations.md) | 2026-08-17_verify_B05_box_ui_recommendations_external.md | 3 | `referenced` |
| [2026-08-18_plan_B05_sidebar_ui_page_improvements.md](../../raw/plans/2026-08-18_plan_B05_sidebar_ui_page_improvements.md) | 사용자 확인·자체검증 기록(별도 보고서 생략) | 2 | `referenced` |
| [2026-08-20_plan_B06_배수관_횡단도_세트.md](../../raw/plans/2026-08-20_plan_B06_배수관_횡단도_세트.md) | 2026-08-20_verify_B06_배수관_횡단도_세트_자체검증근거.md | 5 | `referenced` |
| [2026-08-22_plan_B06_배수관_구조물_기하_조작_체계.md](../../raw/plans/2026-08-22_plan_B06_배수관_구조물_기하_조작_체계.md) | 2026-08-22_verify_B06_배수관_구조물_기하_조작_체계_자체검증근거.md | 3 | `referenced` |
| [2026-08-27_plan_B05_B06_구조물_3D_절취_패치.md](../../raw/plans/2026-08-27_plan_B05_B06_구조물_3D_절취_패치.md) | 2026-08-27_verify_B05_B06_구조물_3D_절취_패치_교차검증.md | 4 | `referenced` |
| [2026-08-27_plan_B05_변형성토면_마감_날개패치.md](../../raw/plans/2026-08-27_plan_B05_변형성토면_마감_날개패치.md) | 2026-08-27_verify_B05_변형성토면_마감_날개패치_교차검증.md | 3 | `referenced` |
| [2026-08-28_plan_B05_구조물측점_단일공급자.md](../../raw/plans/2026-08-28_plan_B05_구조물측점_단일공급자.md) | 2026-08-28_verify_B05_구조물측점_단일공급자.md | 2 | `covered_by_verified_pair` |
| [2026-08-28_plan_B05_B06_물넘이포장_독립기슭막이.md](../../raw/plans/2026-08-28_plan_B05_B06_물넘이포장_독립기슭막이.md) | 2026-08-28_verify_B05_B06_물넘이포장_독립기슭막이.md | 2 | `covered_by_verified_pair` |
| [2026-08-28_plan_B05_구조물_3D_후속판정.md](../../raw/plans/2026-08-28_plan_B05_구조물_3D_후속판정.md) | 2026-08-28_verify_B05_구조물_3D_후속판정.md | 2 | `covered_by_verified_pair` |
| [2026-08-28_plan_B05_후속완료_정리.md](../../raw/plans/2026-08-28_plan_B05_후속완료_정리.md) | 2026-08-28_verify_B05_후속완료_정리.md | 2 | `covered_by_verified_pair` |
| [2026-08-29_plan_B05_B06_structure_ui_unification.md](../../raw/plans/2026-08-29_plan_B05_B06_structure_ui_unification.md) | 2026-08-29_verify_B05_B06_structure_ui_unification.md | 1 | `covered_by_verified_pair` |
| [2026-08-29_plan_B07_CAD_scale_sheet_layout.md](../../raw/plans/2026-08-29_plan_B07_CAD_scale_sheet_layout.md) | 2026-08-29_verify_B07_CAD_scale_sheet_layout.md | 1 | `covered_by_verified_pair` |
+20
View File
@@ -0,0 +1,20 @@
---
type: ingest-register
status: stable
related_pages: ["[[ingest/index]]", "[[completed_2026-09-01]]", "[[completed_2026-09-03]]", "[[completed_2026-09-03_additional]]", "[[completed_2026-09-04]]"]
last_updated: 2026-09-04
---
# 2026-09 계획 인제스트
| 원본 | 상태 | 반영 위치 |
|---|---|---|
| `docs/raw/plans/2026-09-01_plan_B04_B05_B06_completed_work.md` | `covered_by_verified_pair` | [[completed_2026-09-01]] |
| `docs/raw/plans/2026-09-01_plan_remaining_checked_items.md` | `covered_by_verified_pair` | [[completed_2026-09-01_followups]] |
| `docs/raw/plans/2026-09-03_plan_completed_items.md` | `referenced` | [[completed_2026-09-03]] 및 B03·B04·B05·B06·B08 상세 페이지 |
| `docs/raw/plans/2026-09-03_plan_completed_items_2.md` | `referenced` | [[completed_2026-09-03_additional]] 및 B03·B04·B05·B06 상세 페이지 |
| `docs/raw/plans/2026-09-04_plan_user_verified_completed_items.md` | `referenced` | [[completed_2026-09-04]] 및 관련 B01·B03·B04·B05·B06·B08 페이지 |
| `docs/raw/plans/2026-09-04_plan_completed_items.md` | `referenced_user_verification_waived` | [[completed_2026-09-04]] |
| `docs/raw/plans/2026-09-04_plan_700line_split.md` | `referenced_user_verification_waived` | [[completed_2026-09-04]] |
| `docs/raw/plans/2026-09-04_plan_dead_code_cleanup_parked.md` | `parked_not_started` | 위키 완료 범위 제외 |
| `docs/raw/plans/2026-09-04_plan_snapshot_before_cleanup.md` | `referenced_completed_with_open_items_carried_forward` | [[completed_2026-09-04]]; 미완료 21건은 `docs/raw/PLAN.md` 유지 |
+14
View File
@@ -0,0 +1,14 @@
---
type: ingest-register
status: draft
related_pages: ["[[ingest/index]]"]
last_updated: 2026-08-16
---
# 계획서 인제스트 원장 — undated
> 이 표는 파일명과 현재 위키의 명시적 source 흔적을 대조한 1차 감사 결과다. `referenced`는 완전 반영을 보증하지 않는다.
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---:|---|
| [plan_workflow_state_management.md](../../raw/plans/plan_workflow_state_management.md) | - | 3 | `referenced` |
+75
View File
@@ -0,0 +1,75 @@
---
type: ingest-register
status: draft
related_pages: ["[[ingest/index]]"]
last_updated: 2026-08-16
---
# 검증보고서 인제스트 원장 — 2026-07
> 이 표는 파일명과 현재 위키의 명시적 source 흔적을 대조한 1차 감사 결과다. `referenced`는 완전 반영을 보증하지 않는다.
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---:|---|
| [2026-07-12_verify_add_phase4_role.md](../../raw/verification/2026-07-12_verify_add_phase4_role.md) | - | 3 | `referenced` |
| [2026-07-16_verify_인증주기개선.md](../../raw/verification/2026-07-16_verify_인증주기개선.md) | - | 1 | `referenced` |
| [2026-07-17_verify_auth_reverify.md](../../raw/verification/2026-07-17_verify_auth_reverify.md) | - | 6 | `referenced` |
| [2026-07-17_verify_b04_confirm_and_2d_map.md](../../raw/verification/2026-07-17_verify_b04_confirm_and_2d_map.md) | - | 1 | `referenced` |
| [2026-07-17_verify_B04_contour.md](../../raw/verification/2026-07-17_verify_B04_contour.md) | 2026-07-17_plan_B04_contour.md | 2 | `referenced` |
| [2026-07-17_verify_b04_defects.md](../../raw/verification/2026-07-17_verify_b04_defects.md) | 2026-07-17_plan_b04_defects.md | 1 | `referenced` |
| [2026-07-17_verify_B04_Surface_Reorganization.md](../../raw/verification/2026-07-17_verify_B04_Surface_Reorganization.md) | 2026-07-17_plan_B04_Surface_Reorganization.md | 2 | `referenced` |
| [2026-07-17_verify_layout_and_payment_mockups.md](../../raw/verification/2026-07-17_verify_layout_and_payment_mockups.md) | - | 3 | `referenced` |
| [2026-07-17_verify_workflow_stepbar.md](../../raw/verification/2026-07-17_verify_workflow_stepbar.md) | - | 2 | `referenced` |
| [2026-07-18_verify_b04_confirm_b05_rebuild.md](../../raw/verification/2026-07-18_verify_b04_confirm_b05_rebuild.md) | 2026-07-18_plan_b04_confirm_b05_rebuild.md | 4 | `referenced` |
| [2026-07-18_verify_B04_old_align.md](../../raw/verification/2026-07-18_verify_B04_old_align.md) | 2026-07-18_plan_B04_old_align.md | 1 | `referenced` |
| [2026-07-18_verify_B06_DrawingRendering.md](../../raw/verification/2026-07-18_verify_B06_DrawingRendering.md) | 2026-07-18_plan_B06_DrawingRendering.md | 2 | `referenced` |
| [2026-07-18_verify_B06_ProfileCross.md](../../raw/verification/2026-07-18_verify_B06_ProfileCross.md) | 2026-07-18_plan_B06_ProfileCross.md | 2 | `referenced` |
| [2026-07-18_verify_crs_and_polling_log.md](../../raw/verification/2026-07-18_verify_crs_and_polling_log.md) | - | 5 | `referenced` |
| [2026-07-18_verify_layout_improvement.md](../../raw/verification/2026-07-18_verify_layout_improvement.md) | 2026-07-18_plan_layout_improvement.md | 1 | `referenced` |
| [2026-07-19_verify_b04_gis_theme.md](../../raw/verification/2026-07-19_verify_b04_gis_theme.md) | 2026-07-19_plan_b04_gis_theme.md | 2 | `referenced` |
| [2026-07-19_verify_B05_B06_improvements.md](../../raw/verification/2026-07-19_verify_B05_B06_improvements.md) | 2026-07-19_plan_B05_B06_improvements.md | 4 | `referenced` |
| [2026-07-19_verify_B05_B06_UI_Station_Improvement.md](../../raw/verification/2026-07-19_verify_B05_B06_UI_Station_Improvement.md) | 2026-07-19_plan_B05_B06_UI_Station_Improvement.md | 4 | `referenced` |
| [2026-07-19_verify_B05_B06_차트_레이아웃_후속보정.md](../../raw/verification/2026-07-19_verify_B05_B06_차트_레이아웃_후속보정.md) | 2026-07-19_plan_B05_B06_차트_레이아웃_후속보정.md | 4 | `referenced` |
| [2026-07-19_verify_b05_dark_theme.md](../../raw/verification/2026-07-19_verify_b05_dark_theme.md) | 2026-07-19_plan_b05_dark_theme.md | 1 | `referenced` |
| [2026-07-19_verify_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md](../../raw/verification/2026-07-19_verify_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md) | 2026-07-19_plan_B06_사이드바_버튼_폭_및_확정_후_B07_이동.md | 2 | `referenced` |
| [2026-07-19_verify_B07_DesignDetail.md](../../raw/verification/2026-07-19_verify_B07_DesignDetail.md) | 2026-07-19_plan_B07_DesignDetail.md | 3 | `referenced` |
| [2026-07-19_verify_b07_external_webcad_demos.md](../../raw/verification/2026-07-19_verify_b07_external_webcad_demos.md) | 2026-07-19_plan_b07_external_webcad_demos.md | 2 | `referenced` |
| [2026-07-19_verify_b07_independent_cad.md](../../raw/verification/2026-07-19_verify_b07_independent_cad.md) | 2026-07-19_plan_b07_independent_cad.md | 2 | `referenced` |
| [2026-07-19_verify_CrossPruning_and_CADStyle.md](../../raw/verification/2026-07-19_verify_CrossPruning_and_CADStyle.md) | 2026-07-19_plan_CrossPruning_and_CADStyle.md | 1 | `referenced` |
| [2026-07-19_verify_half_width_persistence.md](../../raw/verification/2026-07-19_verify_half_width_persistence.md) | 2026-07-19_plan_half_width_persistence.md | 3 | `referenced` |
| [2026-07-19_verify_responsive_layout_drag.md](../../raw/verification/2026-07-19_verify_responsive_layout_drag.md) | 2026-07-19_plan_responsive_layout_drag.md | 4 | `referenced` |
| [2026-07-19_verify_scrollbar_theme.md](../../raw/verification/2026-07-19_verify_scrollbar_theme.md) | 2026-07-19_plan_scrollbar_theme.md | 1 | `referenced` |
| [2026-07-19_verify_webcad_poc.md](../../raw/verification/2026-07-19_verify_webcad_poc.md) | - | 1 | `referenced` |
| [2026-07-19_verify_종횡단_생성_B05_이관.md](../../raw/verification/2026-07-19_verify_종횡단_생성_B05_이관.md) | 2026-07-19_plan_종횡단_생성_B05_이관.md | 3 | `referenced` |
| [2026-07-19_verify_종횡단_이슈수정_3건.md](../../raw/verification/2026-07-19_verify_종횡단_이슈수정_3건.md) | 2026-07-19_plan_종횡단_이슈수정_3건.md | 3 | `referenced` |
| [2026-07-20_verify_B05_longitudinal_grade_line.md](../../raw/verification/2026-07-20_verify_B05_longitudinal_grade_line.md) | 2026-07-20_plan_B05_longitudinal_grade_line.md | 2 | `referenced` |
| [2026-07-20_verify_B06_profile_cross_design_elevation.md](../../raw/verification/2026-07-20_verify_B06_profile_cross_design_elevation.md) | 2026-07-20_plan_B06_profile_cross_design_elevation.md | 2 | `referenced` |
| [2026-07-20_verify_B07_상세설계개선.md](../../raw/verification/2026-07-20_verify_B07_상세설계개선.md) | 2026-07-20_plan_B07_상세설계개선.md | 5 | `referenced` |
| [2026-07-20_verify_b08_quantity_template.md](../../raw/verification/2026-07-20_verify_b08_quantity_template.md) | 2026-07-20_plan_b08_quantity_template.md | 3 | `referenced` |
| [2026-07-21_verify_B06_default_design_B07_gating.md](../../raw/verification/2026-07-21_verify_B06_default_design_B07_gating.md) | 2026-07-21_plan_B06_default_design_B07_gating.md | 6 | `referenced` |
| [2026-07-21_verify_B06_ground_section_type_B07_linkage.md](../../raw/verification/2026-07-21_verify_B06_ground_section_type_B07_linkage.md) | 2026-07-21_plan_B06_ground_section_type_B07_linkage.md | 7 | `referenced` |
| [2026-07-22_verify_B06_B07.md](../../raw/verification/2026-07-22_verify_B06_B07.md) | 2026-07-22_plan_B06_B07.md | 5 | `referenced` |
| [2026-07-22_verify_B06_cross_scale_row_height.md](../../raw/verification/2026-07-22_verify_B06_cross_scale_row_height.md) | - | 2 | `referenced` |
| [2026-07-23_verify_B05_종단_계획선_편집_체계_개편.md](../../raw/verification/2026-07-23_verify_B05_종단_계획선_편집_체계_개편.md) | 2026-07-23_plan_B05_종단_계획선_편집_체계_개편.md | 3 | `referenced` |
| [2026-07-24_verify_B05_B06_표준횡단.md](../../raw/verification/2026-07-24_verify_B05_B06_표준횡단.md) | 2026-07-24_plan_B05_B06_표준횡단.md | 4 | `referenced` |
| [2026-07-24_verify_B05_irregular_stations.md](../../raw/verification/2026-07-24_verify_B05_irregular_stations.md) | 2026-07-24_plan_B05_irregular_stations.md | 2 | `referenced` |
| [2026-07-24_verify_B05_layout_refinements.md](../../raw/verification/2026-07-24_verify_B05_layout_refinements.md) | 2026-07-24_plan_B05_layout_refinements.md | 2 | `referenced` |
| [2026-07-24_verify_B05_layout_refinements_2.md](../../raw/verification/2026-07-24_verify_B05_layout_refinements_2.md) | 2026-07-24_plan_B05_layout_refinements_2.md | 1 | `referenced` |
| [2026-07-24_verify_b05_reorganization.md](../../raw/verification/2026-07-24_verify_b05_reorganization.md) | 2026-07-24_plan_b05_reorganization.md | 2 | `referenced` |
| [2026-07-24_verify_B05_Route_Improvements.md](../../raw/verification/2026-07-24_verify_B05_Route_Improvements.md) | 2026-07-24_plan_B05_Route_Improvements.md | 3 | `referenced` |
| [2026-07-24_verify_비정규측점_런타임테스트.md](../../raw/verification/2026-07-24_verify_비정규측점_런타임테스트.md) | - | 1 | `referenced` |
| [2026-07-25_verify_b05_b06_3rd_4th_improvements.md](../../raw/verification/2026-07-25_verify_b05_b06_3rd_4th_improvements.md) | 2026-07-25_plan_b05_b06_3rd_4th_improvements.md | 1 | `referenced` |
| [2026-07-25_verify_b05_b06_modifications.md](../../raw/verification/2026-07-25_verify_b05_b06_modifications.md) | 2026-07-25_plan_b05_b06_modifications.md | 4 | `referenced` |
| [2026-07-25_verify_b06_2nd_improvements.md](../../raw/verification/2026-07-25_verify_b06_2nd_improvements.md) | 2026-07-25_plan_b06_2nd_improvements.md | 2 | `referenced` |
| [2026-07-25_verify_b06_n6_n7.md](../../raw/verification/2026-07-25_verify_b06_n6_n7.md) | 2026-07-25_plan_b06_n6_n7.md | 1 | `referenced` |
| [2026-07-25_verify_b07_design_detail.md](../../raw/verification/2026-07-25_verify_b07_design_detail.md) | 2026-07-25_plan_b07_design_detail.md | 3 | `referenced` |
| [2026-07-25_verify_b08_rebuild.md](../../raw/verification/2026-07-25_verify_b08_rebuild.md) | 2026-07-25_plan_b08_rebuild.md | 4 | `referenced` |
| [2026-07-25_verify_n2_n3_n4.md](../../raw/verification/2026-07-25_verify_n2_n3_n4.md) | 2026-07-25_plan_n2_n3_n4.md | 3 | `referenced` |
| [2026-07-26_verify_b06_aesthetics.md](../../raw/verification/2026-07-26_verify_b06_aesthetics.md) | 2026-07-26_plan_b06_aesthetics.md | 1 | `referenced` |
| [2026-07-26_verify_B07_도면_템플릿_및_도각_적용.md](../../raw/verification/2026-07-26_verify_B07_도면_템플릿_및_도각_적용.md) | 2026-07-26_plan_B07_도면_템플릿_및_도각_적용.md | 3 | `referenced` |
| [2026-07-26_verify_openwebcad_성능개선.md](../../raw/verification/2026-07-26_verify_openwebcad_성능개선.md) | 2026-07-26_plan_openwebcad_성능개선.md | 2 | `referenced` |
| [2026-07-26_verify_도엽_오버레이.md](../../raw/verification/2026-07-26_verify_도엽_오버레이.md) | 2026-07-26_plan_도엽_오버레이.md | 3 | `referenced` |
| [2026-07-28_verify_B04_B05_Drainage_Watershed.md](../../raw/verification/2026-07-28_verify_B04_B05_Drainage_Watershed.md) | 2026-07-28_plan_B04_B05_Drainage_Watershed.md | 3 | `referenced` |
| [2026-07-28_verify_B04_Map_Performance.md](../../raw/verification/2026-07-28_verify_B04_Map_Performance.md) | 2026-07-28_plan_B04_Map_Performance.md | 2 | `referenced` |
| [2026-07-31_verify_B03_planned_route_csv.md](../../raw/verification/2026-07-31_verify_B03_planned_route_csv.md) | 2026-07-31_plan_B03_planned_route_csv.md | 4 | `referenced` |
| [2026-07-31_verify_B05_drainage_watershed_pipe_edit.md](../../raw/verification/2026-07-31_verify_B05_drainage_watershed_pipe_edit.md) | 2026-07-31_plan_B05_drainage_watershed_pipe_edit.md | 3 | `referenced` |
+66
View File
@@ -0,0 +1,66 @@
---
type: ingest-register
status: draft
related_pages: ["[[ingest/index]]"]
last_updated: 2026-08-30
---
# 검증보고서 인제스트 원장 — 2026-08
> 이 표는 파일명과 현재 위키의 명시적 source 흔적을 대조한 1차 감사 결과다. `referenced`는 완전 반영을 보증하지 않는다.
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---|---|
| `2026-08-30_verify_B05_B06_ui_fixes.md` | B05/B06 UI | yes | user-verified |
| `2026-08-30_verify_B08_CAD_commands.md` | B08 CAD 명령 | yes | user-verified |
| `2026-08-30_verify_B08_masshaul_watershed_drawings.md` | B08 토적도·유역도 | yes | user-verified |
| `2026-08-30_verify_B08_cross_structure_sheets.md` | B08 횡단 구조물·장 배치 | yes | user-verified |
| `2026-08-30_verify_las_free_sheet_surface.md` | B03~B06 LAS 없는 설계 | yes | user-verified |
| `2026-08-30_verify_B08_CAD_blocks_interaction_tables.md` | B08 블록·조작·표 | yes | user-verified |
| raw 파일 | 대응 문서 후보 | 위키 명시 참조 | 감사 상태 |
|---|---|---:|---|
| [2026-08-01_verify_B04_B05_drainage_ui_improvements.md](../../raw/verification/2026-08-01_verify_B04_B05_drainage_ui_improvements.md) | 2026-08-01_plan_B04_B05_drainage_ui_improvements.md | 4 | `referenced` |
| [2026-08-01_verify_B04_detailed_basins.md](../../raw/verification/2026-08-01_verify_B04_detailed_basins.md) | 2026-08-01_plan_B04_detailed_basins.md | 3 | `referenced` |
| [2026-08-01_verify_B04_inflow_strength_and_panel_cleanup.md](../../raw/verification/2026-08-01_verify_B04_inflow_strength_and_panel_cleanup.md) | 2026-08-01_plan_B04_inflow_strength_and_panel_cleanup.md | 2 | `referenced` |
| [2026-08-01_verify_S8_B05_data_saving.md](../../raw/verification/2026-08-01_verify_S8_B05_data_saving.md) | 2026-08-01_plan_S8_B05_data_saving.md | 2 | `referenced` |
| [2026-08-01_verify_ui_improvements_4_types.md](../../raw/verification/2026-08-01_verify_ui_improvements_4_types.md) | 2026-08-01_plan_ui_improvements_4_types.md | 1 | `referenced` |
| [2026-08-02_verify_B04_B05_drainage_unification.md](../../raw/verification/2026-08-02_verify_B04_B05_drainage_unification.md) | 2026-08-02_plan_B04_B05_drainage_unification.md | 5 | `referenced` |
| [2026-08-02_verify_backlog_reorg.md](../../raw/verification/2026-08-02_verify_backlog_reorg.md) | 2026-08-02_plan_backlog_reorg.md | 2 | `referenced` |
| [2026-08-02_verify_mass_haul_and_drainage_fixes.md](../../raw/verification/2026-08-02_verify_mass_haul_and_drainage_fixes.md) | 2026-08-02_plan_mass_haul_and_drainage_fixes.md | 5 | `referenced` |
| [2026-08-02_verify_mass_haul_distribution_and_refinements.md](../../raw/verification/2026-08-02_verify_mass_haul_distribution_and_refinements.md) | 2026-08-02_plan_mass_haul_distribution_and_refinements.md | 4 | `referenced` |
| [2026-08-02_verify_mass_haul_multi_curve.md](../../raw/verification/2026-08-02_verify_mass_haul_multi_curve.md) | 2026-08-02_plan_mass_haul_multi_curve.md | 2 | `referenced` |
| [2026-08-02_verify_panel_fold_B05_style.md](../../raw/verification/2026-08-02_verify_panel_fold_B05_style.md) | 2026-08-02_plan_panel_fold_B05_style.md | 3 | `referenced` |
| [2026-08-02_verify_panel_height_first_render.md](../../raw/verification/2026-08-02_verify_panel_height_first_render.md) | 2026-08-02_plan_panel_height_first_render.md | 2 | `referenced` |
| [2026-08-02_verify_ui_template_locale_split.md](../../raw/verification/2026-08-02_verify_ui_template_locale_split.md) | 2026-08-02_plan_ui_template_locale_split.md | 1 | `referenced` |
| [2026-08-03_verify_B05_mass_haul_transfer.md](../../raw/verification/2026-08-03_verify_B05_mass_haul_transfer.md) | 2026-08-03_plan_B05_mass_haul_transfer.md | 2 | `referenced` |
| [2026-08-03_verify_향후작업_반영완료.md](../../raw/verification/2026-08-03_verify_향후작업_반영완료.md) | 2026-08-03_plan_향후작업_반영완료.md | 2 | `referenced` |
| [2026-08-03_verify_후속작업_주의사항.md](../../raw/verification/2026-08-03_verify_후속작업_주의사항.md) | 2026-08-03_plan_후속작업_주의사항.md | 2 | `referenced` |
| [2026-08-04_verify_b05_b06_profile_ui_chain.md](../../raw/verification/2026-08-04_verify_b05_b06_profile_ui_chain.md) | 2026-08-04_plan_b05_b06_profile_ui_chain.md | 2 | `referenced` |
| [2026-08-04_verify_mass_haul_spoil_scroll.md](../../raw/verification/2026-08-04_verify_mass_haul_spoil_scroll.md) | 2026-08-04_plan_mass_haul_spoil_scroll.md | 2 | `referenced` |
| [2026-08-05_verify_b04_b05_drainage_rainfall_structure.md](../../raw/verification/2026-08-05_verify_b04_b05_drainage_rainfall_structure.md) | 2026-08-05_plan_b04_b05_drainage_rainfall_structure.md | 2 | `referenced` |
| [2026-08-06_verify_B05_B06_feature_updates.md](../../raw/verification/2026-08-06_verify_B05_B06_feature_updates.md) | 2026-08-06_plan_B05_B06_feature_updates.md | 2 | `referenced` |
| [2026-08-06_verify_B05_bottom_panel_resize_bug.md](../../raw/verification/2026-08-06_verify_B05_bottom_panel_resize_bug.md) | 2026-08-06_plan_B05_bottom_panel_resize_bug.md | 2 | `referenced` |
| [2026-08-06_verify_B05_main_panel_resize_proportional.md](../../raw/verification/2026-08-06_verify_B05_main_panel_resize_proportional.md) | 2026-08-06_plan_B05_main_panel_resize_proportional.md | 2 | `referenced` |
| [2026-08-08_verify_B05_B06_fixes.md](../../raw/verification/2026-08-08_verify_B05_B06_fixes.md) | 2026-08-08_plan_B05_B06_fixes.md | 2 | `referenced` |
| [2026-08-08_verify_dashboard_scroll_limit.md](../../raw/verification/2026-08-08_verify_dashboard_scroll_limit.md) | 2026-08-08_plan_dashboard_scroll_limit.md | 2 | `referenced` |
| [2026-08-08_verify_db_initialization.md](../../raw/verification/2026-08-08_verify_db_initialization.md) | 2026-08-08_plan_db_initialization.md | 1 | `referenced` |
| [2026-08-08_verify_project_delete_hard.md](../../raw/verification/2026-08-08_verify_project_delete_hard.md) | 2026-08-08_plan_project_delete_hard.md | 3 | `referenced` |
| [2026-08-08_verify_R1_R2_features.md](../../raw/verification/2026-08-08_verify_R1_R2_features.md) | 2026-08-08_plan_R1_R2_features.md | 3 | `referenced` |
| [2026-08-08_verify_server_and_e2e_fixes.md](../../raw/verification/2026-08-08_verify_server_and_e2e_fixes.md) | 2026-08-08_plan_server_and_e2e_fixes.md | 3 | `referenced` |
| [2026-08-13_verify_rainfall_wamis_station.md](../../raw/verification/2026-08-13_verify_rainfall_wamis_station.md) | 2026-08-13_plan_rainfall_wamis_station.md | 2 | `referenced` |
| [2026-08-16_verify_B05_구조물_수동추가.md](../../raw/verification/2026-08-16_verify_B05_구조물_수동추가.md) | 2026-08-16_plan_B05_구조물_수동추가.md | 1 | `referenced` |
| [2026-08-16_verify_B05_구조물_수동추가_교차검증.md](../../raw/verification/2026-08-16_verify_B05_구조물_수동추가_교차검증.md) | 2026-08-16_plan_B05_구조물_수동추가.md | 1 | `referenced` |
| [2026-08-17_verify_B04_등고선_추출_가속_교차검증.md](../../raw/verification/2026-08-17_verify_B04_등고선_추출_가속_교차검증.md) | 2026-08-17_plan_B04_등고선_추출_가속.md | 1 | `referenced` |
| [2026-08-17_verify_B05_box_ui_recommendations_external.md](../../raw/verification/2026-08-17_verify_B05_box_ui_recommendations_external.md) | 2026-08-17_plan_B05_box_ui_recommendations.md | 3 | `referenced` |
| [2026-08-20_verify_B06_배수관_횡단도_세트_자체검증근거.md](../../raw/verification/2026-08-20_verify_B06_배수관_횡단도_세트_자체검증근거.md) | 2026-08-20_plan_B06_배수관_횡단도_세트.md | 5 | `referenced` |
| [2026-08-22_verify_B06_배수관_구조물_기하_조작_체계_자체검증근거.md](../../raw/verification/2026-08-22_verify_B06_배수관_구조물_기하_조작_체계_자체검증근거.md) | 2026-08-22_plan_B06_배수관_구조물_기하_조작_체계.md | 3 | `referenced` |
| [2026-08-27_verify_B05_B06_구조물_3D_절취_패치_교차검증.md](../../raw/verification/2026-08-27_verify_B05_B06_구조물_3D_절취_패치_교차검증.md) | 2026-08-27_plan_B05_B06_구조물_3D_절취_패치.md | 4 | `referenced` |
| [2026-08-27_verify_B05_변형성토면_마감_날개패치_교차검증.md](../../raw/verification/2026-08-27_verify_B05_변형성토면_마감_날개패치_교차검증.md) | 2026-08-27_plan_B05_변형성토면_마감_날개패치.md | 3 | `referenced` |
| [2026-08-28_verify_B05_구조물측점_단일공급자.md](../../raw/verification/2026-08-28_verify_B05_구조물측점_단일공급자.md) | 2026-08-28_plan_B05_구조물측점_단일공급자.md | 2 | `covered_by_verified_pair` |
| [2026-08-28_verify_B05_B06_물넘이포장_독립기슭막이.md](../../raw/verification/2026-08-28_verify_B05_B06_물넘이포장_독립기슭막이.md) | 2026-08-28_plan_B05_B06_물넘이포장_독립기슭막이.md | 2 | `covered_by_verified_pair` |
| [2026-08-28_verify_B05_구조물_3D_후속판정.md](../../raw/verification/2026-08-28_verify_B05_구조물_3D_후속판정.md) | 2026-08-28_plan_B05_구조물_3D_후속판정.md | 2 | `covered_by_verified_pair` |
| [2026-08-28_verify_B05_후속완료_정리.md](../../raw/verification/2026-08-28_verify_B05_후속완료_정리.md) | 2026-08-28_plan_B05_후속완료_정리.md | 2 | `covered_by_verified_pair` |
| [2026-08-29_verify_B03_reupload_reanalysis_cache.md](../../raw/verification/2026-08-29_verify_B03_reupload_reanalysis_cache.md) | commit `60bbe89e` | 3 | `referenced` |
| [2026-08-29_verify_B05_B06_structure_ui_unification.md](../../raw/verification/2026-08-29_verify_B05_B06_structure_ui_unification.md) | 2026-08-29_plan_B05_B06_structure_ui_unification.md | 1 | `covered_by_verified_pair` |
| [2026-08-29_verify_B07_CAD_scale_sheet_layout.md](../../raw/verification/2026-08-29_verify_B07_CAD_scale_sheet_layout.md) | 2026-08-29_plan_B07_CAD_scale_sheet_layout.md | 1 | `covered_by_verified_pair` |
+13
View File
@@ -0,0 +1,13 @@
---
type: ingest-register
status: stable
related_pages: ["[[ingest/index]]", "[[completed_2026-09-01]]"]
last_updated: 2026-09-01
---
# 2026-09 검증 인제스트
| 원본 | 상태 | 반영 위치 |
|---|---|---|
| `docs/raw/verification/2026-09-01_verify_B04_B05_B06_completed_work.md` | `covered_by_verified_pair` | [[completed_2026-09-01]] |
| `docs/raw/verification/2026-09-01_verify_remaining_checked_items.md` | `covered_by_verified_pair` | [[completed_2026-09-01_followups]] |
+1403
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
---
type: page-frontend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A00_Common
last_updated: 2026-07-24
---
# A00_Common — 공통 프레임워크 & 유틸
A00_Common은 전체 웹 애플리케이션의 셸 레이아웃, SPA 클라이언트 라우터, 7단계 워크플로우 스테이지 게이팅 및 백엔드 데이터베이스/파일시스템 공통 유틸리티 모듈로 세분화되어 구성됩니다.
## 📂 세분화 마크다운 문서 목록
| 분류 | 세분화 마크다운 문서 | 핵심 역할 |
|---|---|---|
| 프론트엔드 | `[[A00_Common/frontend/A00_Common_AppShell]]` | 공통 상단 네비게이션 헤더 및 셸 레이아웃 |
| 프론트엔드 | `[[A00_Common/frontend/A00_Common_Router]]` | 해시 기반 SPA 라우터 및 페이지 라우팅 |
| 공통 백엔드 유틸 | `[[concepts/common_util/common_util_workflow_state]]` | 7단계 워크플로우 전이 및 `project_workflow_stages` DB 연동 |
| 공통 백엔드 유틸 | `[[concepts/common_util/common_util_storage]]` | 물리 저장소 절대경로 해석 및 디렉토리 관리 유틸 |
## 📋 개요
- 애플리케이션의 뼈대가 되는 셸 레이아웃과 7단계 상태 관리 트랜잭션을 전역 제공합니다.
@@ -0,0 +1,22 @@
---
type: file-frontend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A00_Common
source_file: "A00_Common/app_shell.ts"
last_updated: 2026-07-24
---
# app_shell.ts
웹 애플리케이션의 공통 상단 네비게이션 헤더, 모바일 드로어 메뉴, 시스템 대시보드 상태 및 테마 전환 레이아웃을 렌더링하는 클라이언트 셸 모듈입니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `renderAppShell()` | `A00_Common/app_shell.ts` | 메인 헤더 및 워크플로우 셸 레이아웃 DOM 구조 렌더링 |
| `updateActiveNav()` | `A00_Common/app_shell.ts` | 현재 URL 라우트 경로에 따라 헤더 네비게이션 활성 탭 하이라이트 |
## 🔗 연관 개념 및 의존성
- `A00_Common/router.ts` — 클라이언트 라우터와 네비게이션 상태 공유
@@ -0,0 +1,22 @@
---
type: file-frontend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A00_Common
source_file: "A00_Common/router.ts"
last_updated: 2026-07-24
---
# router.ts
해시 기반(`/#/path`) 클라이언트 사이드 라우팅 및 페이지 전환, 브라우저 뒤로가기/앞으로가기 이벤트를 바인딩하는 싱글 페이지 애플리케이션(SPA) 라우터 모듈입니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `initRouter()` | `A00_Common/router.ts` | `hashchange` 이벤트 수신기 바인딩 및 초기 경로 파싱 라우팅 |
| `navigate()` | `A00_Common/router.ts` | 프로그래밍 방식 해시 URL 변경 및 렌더러 격발 |
## 🔗 연관 개념 및 의존성
- `A00_Common/b_workflow_nav.ts` — 7단계 워크플로우 게이팅 라우팅 바인딩
@@ -0,0 +1,37 @@
---
type: page-frontend-detail
status: draft
page_id: A01_Home
related_pages: ["[[A01_Home/A01_frontend]]", "[[ui_templates]]", "[[a00_app_shell_framework]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
source: 상위 프로젝트 A01_Home 코드 인제스트 보완 (2026-07-12)
---
# A01_Home — 세부 구현
## 스타일
| 항목 | 역할 |
|---|---|
| `.a01-home`, `.a01-hero` | 페이지 래퍼·히어로 배경 |
| `.a01-news-list`, `.a01-news-row` | 뉴스 목록과 행 레이아웃 |
| `.a01-feature-grid`, `.a01-feature-card` | 3열 기능 카드 그리드 |
| 900px 이하 | 기능 그리드 1열·히어로 제목 축소 |
## 의존성
| 항목 | 역할 |
|---|---|
| [[a00_app_shell_framework]] | `navigateTo()` 라우팅 |
| `config_frontend.ts` | `ROUTES` 상수 |
| [[ui_templates]] | 공통 버튼·카드·태그·다국어 |
## 데이터 흐름
| 단계 | 흐름 |
|---|---|
| 1 | `renderA01Home(root)` → `buildHero()`·`buildNews()`·`buildFeatures()` |
| 2 | `buildNews()`는 현재 `MOCK_NEWS` 사용 |
| 3 | CTA 클릭 → A07_Register 또는 A02_ProgDetail 이동 |
## 미해결
| 항목 | 상태 |
|---|---|
| `GET /api/a01/news` | 백엔드 미구현; 현재 뉴스는 하드코딩 |
+62
View File
@@ -0,0 +1,62 @@
---
status: draft
page_id: A01_Home
related_pages: ["[[A02_ProgDetail/A02_frontend]]", "[[A04_NewsHistory/A04_frontend]]", "[[a00_app_shell_framework]]", "[[ui_templates]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A01_Home — Frontend
[[architecture/public_admin_map]]은 이 페이지를 방문자의 공개 진입점으로 라우팅하고, [[A01_Home/frontend/A01_Home_UI_Page]]가 화면을 구현한다.
로그인 전 01: 홈 페이지. 소개 히어로 + 최신 소식 + 주요 기능 3가지를 showcase하는 정적 소개 페이지. 백엔드 없음.
## 파일 구조
| 파일 | 세분화 위키 명세 | 역할 |
|---|---|---|
| `A01_Home_UI_Page.ts` | `[[A01_Home/frontend/A01_Home_UI_Page]]` | 페이지 렌더링 로직 (buildHero, buildNews, buildFeatures) |
| `A01_Home_UI_Style.css` | `A01_Home/A01_Home_UI_Style.css` | 스타일 (theme.css 변수만 사용) |
## 컴포넌트
### Hero 섹션
- **함수:** `buildHero()` (A01_Home_UI_Page.ts:52-85)
- **구성:** 제목 + 부제목 + 2개 CTA 버튼 (회원가입/프로그램 상세)
- **색상:** 라벤더 그라디언트 배경 (`--color-mist-violet` → `--color-canvas`)
### 최신 소식 섹션
- **함수:** `buildNews()` (A01_Home_UI_Page.ts:87-116)
- **데이터:** MOCK_NEWS 배열 (A01_Home_UI_Page.ts:32-36, 백엔드 연결 전)
- **각 항목:** 태그 + 뉴스 제목 + 날짜
### 주요 기능 섹션
- **함수:** `buildFeatures()` (A01_Home_UI_Page.ts:118-146)
- **레이아웃:** 3열 그리드 (반응형: 900px 이하 1열)
- **카드:** createCard 공통 컴포넌트 사용
## 이벤트 핸들러
| 함수 | 위치 | 동작 |
|---|---|---|
| `onA01_Home_GetStarted_Click()` | A01_Home_UI_Page.ts:41-43 | 회원가입(A07_REGISTER) 이동 |
| `onA01_Home_Explore_Click()` | A01_Home_UI_Page.ts:45-47 | 프로그램 상세(A02_PROG_DETAIL) 이동 |
## 로컬라이제이션
모든 텍스트는 `ui_locales[key][currentLanguageIndex]` 형식으로 [[ui_templates]] 에서 로드.
하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목 | `A01_Home_Title` |
| 히어로 부제목 | `A01_Home_Hero_Subtitle` |
| CTA 버튼 (Primary/Secondary) | `A01_Home_Hero_CtaPrimary`, `A01_Home_Hero_CtaSecondary` |
| 소식 섹션 제목 | `A01_Home_News_SectionTitle` |
| 소식 태그 | `A01_Home_News_Tag` |
| 기능 섹션 제목 | `A01_Home_Features_SectionTitle` |
| 기능 카드 1~3 | `A01_Home_Feature{1..3}_Title`, `A01_Home_Feature{1..3}_Desc` |
## 세부 구현
스타일 구조·의존성·데이터 흐름·미해결 사항은 [[A01_Home/A01_components]]에 분리했다.
@@ -0,0 +1,29 @@
---
type: file-frontend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A01_Home
source_file: "A01_Home/A01_Home_UI_Page.ts"
last_updated: 2026-07-24
---
# A01_Home_UI_Page.ts
로그인 전 서비스 메인 홈 랜딩 페이지 모듈입니다. 다국어 i18n 로케일(`ui_template_locale`) 적용, 히어로 영역 CTA, 최신 소식 타임라인 목록 및 3대 핵심 기능 Showcase 카드 그리드를 조립합니다.
## 🛠️ 주요 함수 및 인터페이스 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `renderA01Home()` | `A01_Home/A01_Home_UI_Page.ts` | 메인 페이지 진입점. Hero, News, Features 섹션을 순차 빌드하여 root DOM에 마운트 |
| `buildHero()` | `A01_Home/A01_Home_UI_Page.ts` | 메인 타이틀, 서브타이틀 및 시작하기/둘러보기 CTA 버튼 섹션 DOM 생성 |
| `buildNews()` | `A01_Home/A01_Home_UI_Page.ts` | `MOCK_NEWS` 데이터를 순회하며 태그, 소식 제목, 날짜 행 목록 DOM 생성 |
| `buildFeatures()` | `A01_Home/A01_Home_UI_Page.ts` | 3대 핵심 기능(Feature 1~3) 카드 그리드 DOM 생성 |
| `onA01_Home_GetStarted_Click()` | `A01_Home/A01_Home_UI_Page.ts` | 시작하기 클릭 시 회원가입 페이지(`A07_REGISTER`)로 이동하는 라우터 핸들러 |
| `onA01_Home_Explore_Click()` | `A01_Home/A01_Home_UI_Page.ts` | 둘러보기 클릭 시 기술 소개 페이지(`A02_PROG_DETAIL`)로 이동하는 라우터 핸들러 |
| `L()` | `A01_Home/A01_Home_UI_Page.ts` | `ui_locales` 다국어 키 기반 현재 언어 텍스트 반환 헬퍼 |
| `NewsItem` | `A01_Home/A01_Home_UI_Page.ts` | 최신 소식 항목 인터페이스 (`id`, `title`, `date`) |
## 🔗 연관 개념 및 의존성
- `A00_Common/router.ts` — `navigateTo` SPA 페이지 이동 연동
- `ui_template_elements.ts` — `createButton`, `createCard`, `createTag` 공통 UI 컴포넌트 활용
@@ -0,0 +1,38 @@
---
type: page-frontend-detail
status: draft
page_id: A02_ProgDetail
related_pages: ["[[A02_ProgDetail/A02_frontend]]", "[[ui_templates]]", "[[a00_app_shell_framework]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
source: A02_ProgDetail 코드 인제스트 보완 및 구조화 일관성 적용
---
# A02_ProgDetail — 세부 구현
## 스타일 (CSS)
| 항목 | 역할 |
|---|---|
| `.a02-prog-detail` | 페이지 루트 컨테이너 (gap: section-gap, padding-bottom: spacing-64) |
| `.a02-hero`, `.a02-hero__inner` | 히어로 영역 배경(라벤더 그라디언트) 및 콘텐츠 중앙 정렬 |
| `.a02-workflow-list`, `.a02-workflow-row` | 6단계 워크플로우 리스트(flex 열) 및 배지+텍스트 행 레이아웃 |
| `.a02-workflow-row__badge` | 40×40px 원형 배지 (primary 배경) |
| `.a02-tech-grid`, `.a02-tech-card` | 핵심 기술 소개 3열 카드 그리드 (900px 이하 대응) |
## 의존성
| 항목 | 역할 |
|---|---|
| [[a00_app_shell_framework]] | `navigateTo()` 라우팅 기능 활용 |
| `config_frontend.ts` | `ROUTES` 경로 상수 참조 |
| [[ui_templates]] | 공통 버튼(`createButton`) 및 카드(`createCard`) 엘리먼트 활용 |
| `ui_template_locale.ts` | 다국어 문구(`ui_locales`) 적용 |
## 데이터 흐름
| 단계 | 흐름 |
|---|---|
| 1 | `renderA02ProgDetail(root)` ➡️ `buildHero()` ➡️ `buildWorkflow()` ➡️ `buildTech()` 순서로 구성 요소를 렌더링하고 `root`에 추가 |
| 2 | 사용자가 히어로의 CTA 버튼 클릭 시 `onA02_ProgDetail_Start_Click()` 핸들러가 작동하여 `navigateTo(ROUTES.A07_REGISTER)` 호출 |
## 미해결 / 특이사항
| 항목 | 상태 |
|---|---|
| 정적 페이지 | 백엔드 API와의 연동이 필요 없는 완전한 정적 소개 페이지임 |
@@ -0,0 +1,36 @@
---
status: draft
page_id: A02_ProgDetail
related_pages: ["[[A01_Home/A01_frontend]]", "[[a00_app_shell_framework]]", "[[ui_templates]]", "[[A02_ProgDetail/A02_components]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A02_ProgDetail — Frontend
[[architecture/public_admin_map]]의 기능 탐색 경로이며 [[A02_ProgDetail/frontend/A02_ProgDetail_UI_Page]]가 화면을 구현한다.
로그인 전 프로그램 상세 페이지. 6단계 워크플로우 시각화 + 핵심 기술 소개.
## 구조
- **세분화 명세**: `[[A02_ProgDetail/frontend/A02_ProgDetail_UI_Page]]`
- **소스 경로**: `A02_ProgDetail/A02_ProgDetail_UI_Page.ts`
- **스타일**: `A02_ProgDetail/A02_ProgDetail_UI_Style.css`
## 컴포넌트 분석
| 컴포넌트 | 역할 | 로케일 키 |
|---|---|---|
| `buildHero()` | 히어로 섹션(제목+부제+CTA) | `A02_ProgDetail_Title`, `A02_ProgDetail_Hero_Subtitle`, `A02_ProgDetail_Hero_Cta` |
| `buildWorkflow()` | 6단계 워크플로우 리스트(배지+텍스트) | `A02_ProgDetail_Workflow_SectionTitle`, `A02_ProgDetail_Step[1-6]_Title`, `A02_ProgDetail_Step[1-6]_Desc` |
| `buildTech()` | 기술 3종 카드 그리드 | `A02_ProgDetail_Tech_SectionTitle`, `A02_ProgDetail_Tech[1-3]_Title`, `A02_ProgDetail_Tech[1-3]_Desc` |
## 제약 준수
- ✅ 모든 문구 `ui_template_locale.ts` 참조
- ✅ 색상/간격 `theme.css` 변수만 사용
- ✅ 공통 컴포넌트 `createButton`/`createCard` 사용
- ✅ 이벤트 핸들러 명명 `on[페이지]_[기능]_[액션]`
## 세부 구현
스타일 구조·의존성·데이터 흐름·특이사항은 [[A02_ProgDetail/A02_components]]에 분리했다.
@@ -0,0 +1,27 @@
---
type: file-frontend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A02_ProgDetail
source_file: "A02_ProgDetail/A02_ProgDetail_UI_Page.ts"
last_updated: 2026-07-24
---
# A02_ProgDetail_UI_Page.ts
로그인 전 서비스 02: 프로그램 상세 소개 랜딩 페이지 모듈입니다. 6단계 임도 설계 워크플로우(지표면 분석, 경로 설계, 종횡단 상세, 구조물 설계, 수량 산출, 견적) 및 3대 핵심 지원 기술을 시각화합니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `renderA02ProgDetail()` | `A02_ProgDetail/A02_ProgDetail_UI_Page.ts` | 프로그램 상세 메인 진입점. Hero, Workflow, Tech 섹션을 생성하여 root DOM에 마운트 |
| `buildHero()` | `A02_ProgDetail/A02_ProgDetail_UI_Page.ts` | 메인 타이틀, 서브타이틀 및 시작하기 CTA 버튼 섹션 DOM 생성 |
| `buildWorkflow()` | `A02_ProgDetail/A02_ProgDetail_UI_Page.ts` | 6단계 워크플로우(Step 1~6) 순번 배지 및 제목/설명 행 리스트 DOM 생성 |
| `buildTech()` | `A02_ProgDetail/A02_ProgDetail_UI_Page.ts` | 3대 핵심 지원 기술(Tech 1~3) 카드 그리드 DOM 생성 |
| `onA02_ProgDetail_Start_Click()` | `A02_ProgDetail/A02_ProgDetail_UI_Page.ts` | 시작하기 클릭 시 회원가입 페이지(`A07_REGISTER`)로 이동하는 라우터 핸들러 |
| `L()` | `A02_ProgDetail/A02_ProgDetail_UI_Page.ts` | `ui_locales` 다국어 키 기반 현재 언어 텍스트 반환 헬퍼 |
## 🔗 연관 개념 및 의존성
- `A00_Common/router.ts` — `navigateTo` SPA 페이지 이동 연동
- `ui_template_elements.ts` — `createButton`, `createCard` 공통 UI 컴포넌트 활용
@@ -0,0 +1,69 @@
---
status: draft
page_id: A03_CompDetail
related_pages: ["[[a00_app_shell_framework]]", "[[ui_templates]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A03_CompDetail — Frontend
[[architecture/public_admin_map]]의 공개 회사 소개 경로이며 [[a00_app_shell_framework]]의 SPA 라우터가 이 화면을 로드한다.
로그인 전 회사 상세 페이지. 미션 + 핵심 가치 + 연락처.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A03_CompDetail_UI_Page.ts` | `A03_CompDetail/A03_CompDetail_UI_Page.ts:1-114` | 페이지 렌더링 로직 |
| `A03_CompDetail_UI_Style.css` | `A03_CompDetail/A03_CompDetail_UI_Style.css:1-100` | 스타일 (theme.css 변수만 사용) |
## 컴포넌트 (섹션 빌더)
| 함수 | 위치 | 역할 |
|---|---|---|
| `buildHero()` | `A03_CompDetail/A03_CompDetail_UI_Page.ts:23-41` | Hero(제목+부제목), mist-violet→canvas 그라디언트 |
| `buildMission()` | `A03_CompDetail/A03_CompDetail_UI_Page.ts:43-57` | 미션 섹션 제목+본문(중앙정렬, max 60자) |
| `buildValues()` | `A03_CompDetail/A03_CompDetail_UI_Page.ts:59-87` | 핵심가치 3열 카드그리드(createCard 3개) |
| `buildContact()` | `A03_CompDetail/A03_CompDetail_UI_Page.ts:89-103` | 연락처 섹션 제목+이메일 |
| `renderA03CompDetail()` | `A03_CompDetail/A03_CompDetail_UI_Page.ts:108-113` | 페이지 진입점(4개 섹션 조립) |
## 로컬라이제이션
모든 텍스트는 `ui_locales[key][currentLanguageIndex]` 형식으로 [[ui_templates]]에서 로드.
하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목 | `A03_CompDetail_Title` |
| 히어로 부제목 | `A03_CompDetail_Hero_Subtitle` |
| 미션 섹션 제목 | `A03_CompDetail_Mission_SectionTitle` |
| 미션 본문 | `A03_CompDetail_Mission_Body` |
| 가치 섹션 제목 | `A03_CompDetail_Value_SectionTitle` |
| 가치 1~3 | `A03_CompDetail_Value{1..3}_Title`, `A03_CompDetail_Value{1..3}_Desc` |
| 연락처 섹션 제목 | `A03_CompDetail_Contact_SectionTitle` |
| 연락처 이메일 | `A03_CompDetail_Contact_Email` |
## 스타일 (CSS)
### CSS 클래스 구조
- `.a03-comp-detail` — 페이지 래퍼 (flex column, gap: section-gap)
- `.a03-hero` — 그래디언트 배경
- `.a03-hero__inner` — 중앙 정렬 컨테이너
- `.a03-hero__title` — heading-lg, deep-iris, max 18자
- `.a03-hero__subtitle` — body 텍스트, slate, max 56자
- `.a03-section` — 공통 섹션 (max-width: page-max-width, padding: spacing-32)
- `.a03-section__title` — heading-sm, deep-iris, 중앙 정렬
- `.a03-mission__body` — body, slate, 중앙 정렬, max 60자
- `.a03-value-grid` — 3열 그리드 (gap: spacing-24)
- `.a03-value-card` — 카드 (min-height: 140px)
- `.a03-value__desc` — body-sm, slate
- `.a03-contact__email` — body, charcoal, 중앙 정렬
### 반응형
- **900px 이하:** 가치 그리드 1열, 히어로 제목 폰트 축소
## 의존성
- [[a00_app_shell_framework]] — 공통 헤더·푸터
- [[ui_templates]] — `createCard()` 공통 컴포넌트 + 다국어
@@ -0,0 +1,88 @@
---
status: draft
page_id: A04_NewsHistory
related_pages: ["[[A01_Home/A01_frontend]]", "[[a00_app_shell_framework]]", "[[ui_templates]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A04_NewsHistory — Frontend
[[architecture/public_admin_map]]의 공개 소식 경로이며 [[a00_app_shell_framework]]의 SPA 라우터가 이 화면을 로드한다.
로그인 전 최신 소식 및 개선 이력 페이지. 타임라인 목록 형태.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A04_NewsHistory_UI_Page.ts` | `A04_NewsHistory/A04_NewsHistory_UI_Page.ts:1-117` | 페이지 렌더링 로직 + Mock 데이터 |
| `A04_NewsHistory_UI_Style.css` | `A04_NewsHistory/A04_NewsHistory_UI_Style.css:1-87` | 스타일 (theme.css 변수만 사용) |
## 컴포넌트 (섹션 빌더)
| 함수 | 위치 | 역할 |
|---|---|---|
| `buildHero()` | `A04_NewsHistory/A04_NewsHistory_UI_Page.ts:50-68` | Hero(제목+부제목), mist-violet→canvas 그라디언트 |
| `buildTimeline()` | `A04_NewsHistory/A04_NewsHistory_UI_Page.ts:70-106` | 타임라인(태그+제목+날짜 행), 빈 상태 처리 |
| `renderA04NewsHistory()` | `A04_NewsHistory/A04_NewsHistory_UI_Page.ts:111-116` | 페이지 진입점(Hero+타임라인 조립) |
- **데이터:** MOCK_HISTORY 배열 (A04_NewsHistory_UI_Page.ts:33-38, 백엔드 연결 전) — 추후 `GET /api/a04/history`로 교체 예정
- **빈 상태:** MOCK_HISTORY.length === 0이면 `A04_NewsHistory_Empty` 로케일 키 표시
## Mock 데이터 구조
**타입:**
```typescript
type HistoryKind = "feature" | "fix" | "notice";
interface HistoryItem {
id: number;
kind: HistoryKind;
title: string;
date: string;
}
```
**태그 변형 매핑** (KIND_META):
- `"feature"` → variant: "accent" → `A04_NewsHistory_Tag_Feature`
- `"fix"` → variant: "success" → `A04_NewsHistory_Tag_Fix`
- `"notice"` → variant: "neutral" → `A04_NewsHistory_Tag_Notice`
## 로컬라이제이션
모든 텍스트는 `ui_locales[key][currentLanguageIndex]` 형식으로 [[ui_templates]]에서 로드.
하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목 | `A04_NewsHistory_Title` |
| 히어로 부제목 | `A04_NewsHistory_Hero_Subtitle` |
| 태그 라벨 (feature/fix/notice) | `A04_NewsHistory_Tag_Feature`, `A04_NewsHistory_Tag_Fix`, `A04_NewsHistory_Tag_Notice` |
| 빈 상태 메시지 | `A04_NewsHistory_Empty` |
## 스타일 (CSS)
### CSS 클래스 구조
- `.a04-news-history` — 페이지 래퍼 (flex column, gap: section-gap)
- `.a04-hero` — 그래디언트 배경
- `.a04-hero__inner` — 중앙 정렬 컨테이너
- `.a04-hero__title` — heading-lg, deep-iris, max 18자
- `.a04-hero__subtitle` — body 텍스트, slate, max 56자
- `.a04-section` — 공통 섹션 (max-width: page-max-width, padding: spacing-32)
- `.a04-timeline` — flex 열 (gap: spacing-8)
- `.a04-timeline-row` — flex row, 태그+제목+날짜 (gap: spacing-16, padding: spacing-16 spacing-24)
- `.a04-timeline-row__title` — flex: 1, body-sm, charcoal
- `.a04-timeline-row__date` — caption, ash
- `.a04-timeline__empty` — 중앙 정렬, slate, body
### 반응형
- **900px 이하:** 히어로 제목 폰트 축소
## 의존성
- [[a00_app_shell_framework]] — 공통 헤더·푸터
- [[ui_templates]] — `createTag()` 공통 컴포넌트 + 다국어
## 미해결 사항
- MOCK_HISTORY 데이터: 현재 하드코딩 (4개 항목)
- 백엔드 API 미구현: `GET /api/a04/history` 코드 주석에 언급됨
@@ -0,0 +1,71 @@
---
status: draft
page_id: A05_EduDetail
related_pages: ["[[a00_app_shell_framework]]", "[[ui_templates]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A05_EduDetail — Frontend
[[architecture/public_admin_map]]의 공개 교육 경로이며 [[a00_app_shell_framework]]의 SPA 라우터가 이 화면을 로드한다.
로그인 전 교육 상세 페이지. 교육 과정 소개 + 문의 CTA.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A05_EduDetail_UI_Page.ts` | `A05_EduDetail/A05_EduDetail_UI_Page.ts:1-106` | 페이지 렌더링 로직 |
| `A05_EduDetail_UI_Style.css` | `A05_EduDetail/A05_EduDetail_UI_Style.css:1-87` | 스타일 (theme.css 변수만 사용) |
## 컴포넌트 (섹션 빌더)
| 함수 | 위치 | 역할 |
|---|---|---|
| `buildHero()` | `A05_EduDetail/A05_EduDetail_UI_Page.ts:33-51` | Hero(제목+부제목), mist-violet→canvas 그라디언트 |
| `buildCourses()` | `A05_EduDetail/A05_EduDetail_UI_Page.ts:53-81` | 교육과정 3열 카드그리드(createCard 3개) |
| `buildCta()` | `A05_EduDetail/A05_EduDetail_UI_Page.ts:83-95` | 문의 CTA 버튼(variant: filled) |
| `renderA05EduDetail()` | `A05_EduDetail/A05_EduDetail_UI_Page.ts:100-105` | 페이지 진입점(3개 섹션 조립) |
## 로컬라이제이션
모든 텍스트는 `ui_locales[key][currentLanguageIndex]` 형식으로 [[ui_templates]]에서 로드.
하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목 | `A05_EduDetail_Title` |
| 히어로 부제목 | `A05_EduDetail_Hero_Subtitle` |
| 과정 섹션 제목 | `A05_EduDetail_Course_SectionTitle` |
| 과정 1~3 | `A05_EduDetail_Course{1..3}_Title`, `A05_EduDetail_Course{1..3}_Desc` |
| CTA 버튼 라벨 | `A05_EduDetail_Cta` |
## 스타일 (CSS)
### CSS 클래스 구조
- `.a05-edu-detail` — 페이지 래퍼 (flex column, gap: section-gap)
- `.a05-hero` — 그래디언트 배경
- `.a05-hero__inner` — 중앙 정렬 컨테이너
- `.a05-hero__title` — heading-lg, deep-iris, max 18자
- `.a05-hero__subtitle` — body 텍스트, slate, max 56자
- `.a05-section` — 공통 섹션 (max-width: page-max-width, padding: spacing-32)
- `.a05-section__title` — heading-sm, deep-iris, 중앙 정렬
- `.a05-course-grid` — 3열 그리드 (gap: spacing-24)
- `.a05-course-card` — 카드 (min-height: 140px)
- `.a05-course__desc` — body-sm, slate
- `.a05-cta` — align-items: center (버튼 중앙 정렬)
### 반응형
- **900px 이하:** 과정 그리드 1열, 히어로 제목 폰트 축소
## 이벤트 핸들러
| 함수 | 위치 | 동작 |
|---|---|---|
| `onA05_EduDetail_Inquiry_Click()` | A05_EduDetail_UI_Page.ts:26-28 | A08_SUPPORT로 이동 |
## 의존성
- [[a00_app_shell_framework]] — `navigateTo()` 라우팅
- `config_frontend.ts` — `ROUTES` 상수 (A08_SUPPORT)
- [[ui_templates]] — `createButton()`, `createCard()` 공통 컴포넌트 + 다국어
+66
View File
@@ -0,0 +1,66 @@
---
status: stable
page_id: A06_Login
related_pages: ["[[A06_Login/A06_frontend]]", "[[A07_Register/A07_backend]]", "[[A09_Security/A09_backend]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-17
source: docs/raw/verification/2026-07-17_verify_auth_reverify.md
---
# A06_Login — Backend
세션 쿠키 기반 로그인 + OTP 재인증 + 디바이스 토큰(기기 신뢰) + 세션/비밀번호 관리 API.
## 파일 구조
| 파일 | 세분화 위키 명세 | 역할 |
|---|---|---|
| `A06_Login_Router.py` | `[[A06_Login/backend/A06_Login_Router]]` | 인증 API 라우터 (prefix `/api/auth`) |
| `A06_Login_Schema.py` | `A06_Login/A06_Login_Schema.py` | 요청 검증 Pydantic 모델 3종 |
## API 엔드포인트
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `POST /api/auth/login/request` | `A06_Login/A06_Login_Router.py:51` | 1차 로그인(이메일+비번). 신규 브라우저/주기 재인증 시 `otp_required` 반환 |
| `POST /api/auth/login/verify` | `A06_Login/A06_Login_Router.py:113` | OTP 검증 후 세션 발급, 디바이스 토큰 쿠키 생성/발급 |
| `GET /api/auth/session` | `A06_Login/A06_Login_Router.py:145` | 현재 세션 사용자 조회 (id/email/name/role/company_id/is_master) |
| `POST /api/auth/logout` | `A06_Login/A06_Login_Router.py:160` | 세션 삭제 + 쿠키 제거 |
| `POST /api/auth/password` | `A06_Login/A06_Login_Router.py:170` | 비밀번호 변경 (현재 비번 검증, 재인증 필요 반환) |
## 내부 헬퍼
| 함수 | 위치 | 역할 |
|---|---|---|
| `_send_otp(user, purpose, label)` | `A06_Login/A06_Login_Router.py:44` | OTP 생성·해시 저장·메일 발송 |
| `_finish_login(user, request)` | `A06_Login/A06_Login_Router.py:87` | 세션 생성·로그인 성공 기록, 디바이스 토큰 생성(32바이트) 및 SHA256 해시 DB 저장, 쿠키 설정 |
## 요청 스키마 (Pydantic)
| 모델 | 위치 | 필드 |
|---|---|---|
| `LoginRequest` | `A06_Login/A06_Login_Schema.py:6` | email(EmailStr), password(8~128자) |
| `OtpVerifyRequest` | `A06_Login/A06_Login_Schema.py:11` | email(EmailStr), otp_code(정규식 `^\d{6}$`) |
| `PasswordChangeRequest` | `A06_Login/A06_Login_Schema.py:16` | current_password, new_password(8~128자), logout_all(기본 True) |
## 로그인 로직 흐름
1. `login/request`: 이메일 조회 → 계정 잠금 확인 → 비밀번호 검증 → 계정 상태 확인(`ACTIVE`/`NO_COMPANY`/`PENDING`만 허용)
2. **OTP 트리거 조건** (둘 중 하나면 OTP 요구):
- 주기적 재인증: `last_email_verified_at`이 `EMAIL_REVERIFY_DAYS`(90일) 이전
- 신규 브라우저: `device_token` 쿠키 미보유 또는 DB(`trusted_devices.token_hash`) 대조 불일치
3. `login/verify`: OTP 검증 → 소비 → `last_email_verified_at` 갱신 → `_finish_login`
4. `_finish_login`: 로그인 실패 초기화 → 디바이스 토큰 발급 및 쿠키(HttpOnly, Secure, SameSite=Lax, Max-Age=90일) 설정 → 세션 생성 (`auth_expires_at` 중복 필드 제거 완료)
## 보안 정책 (실 코드 기준)
- **비밀번호 실패**: `record_failed_login()` 누적, 5회 이상 & ADMIN_EMAIL 설정 시 보안 경고 메일 발송
- **계정 잠금**: `account_locked_until`이 미래면 423 반환
- **로그인 기록**: 모든 시도를 `record_login()`으로 기록(성공/실패 사유 포함)
- **디바이스 토큰 신뢰**: 조회 시 `last_used_at`이 90일 이내인 기기 토큰만 유효 처리하며, 로그인 시 `last_used_at`을 주기적으로 갱신
## 의존성 (공통 유틸)
- [[common_util]] — `common_util_auth`(세션/OTP/디바이스토큰/쿠키헬퍼), `common_util_auth_repository`(DB 조회), `common_util_email`(메일 발송)
- 인증/세션/OTP 정책 상세 → [[auth_rbac]]
- `config_system` — `ADMIN_EMAIL`, `EMAIL_REVERIFY_DAYS`
+94
View File
@@ -0,0 +1,94 @@
---
status: stable
page_id: A06_Login
related_pages: ["[[A06_Login/A06_backend]]", "[[A07_Register/A07_frontend]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-17
source: docs/raw/verification/2026-07-17_verify_auth_reverify.md
---
# A06_Login — Frontend
로그인 화면. 이메일+비밀번호 1차 → 필요 시 OTP 입력으로 전환하는 단일 폼 (2026-07-17 UX 개선 반영).
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A06_Login_UI_Auth_Page.ts` | `A06_Login/A06_Login_UI_Auth_Page.ts:1-80` | 로그인 폼 렌더링 + 제출/재발송/뒤로가기 제어 로직 |
| `A06_Login_UI_Style.css` | `A06_Login/A06_Login_UI_Style.css:1-52` | 스타일 (theme.css 변수만 사용) |
| `A06_Login_Api_Fetch.ts` | `A06_Login/A06_Login_Api_Fetch.ts:1-57` | 인증 API 클라이언트 (`credentials: "include"`) |
## 컴포넌트 / 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `renderA06Login(root)` | `A06_Login/A06_Login_UI_Auth_Page.ts:17` | 카드+폼(email/password/otp/submit/resend/back) 조립 |
| `onA06_Login_Submit_Click(event)` | `A06_Login/A06_Login_UI_Auth_Page.ts:34` | 폼 제출 핸들러(검증→요청→OTP 전환/성공) |
| `onA06_Login_Resend_Click()` | `A06_Login/A06_Login_UI_Auth_Page.ts:50` | OTP 재발송 요청 및 60초 쿨다운 비활성화 제어 |
| `onA06_Login_Back_Click()` | `A06_Login/A06_Login_UI_Auth_Page.ts:65` | OTP 단계를 취소하고 비밀번호 입력 화면으로 복귀 |
## API 클라이언트 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `requestLogin(email, password)` | `A06_Login/A06_Login_Api_Fetch.ts:30` | `POST /auth/login/request` |
| `verifyLogin(email, otpCode)` | `A06_Login/A06_Login_Api_Fetch.ts:34` | `POST /auth/login/verify` |
| `fetchSession()` | `A06_Login/A06_Login_Api_Fetch.ts:38` | `GET /auth/session` → boolean(로그인 여부) |
| `fetchSessionUser()` | `A06_Login/A06_Login_Api_Fetch.ts:43` | `GET /auth/session` → SessionUser 객체 |
| `logout()` | `A06_Login/A06_Login_Api_Fetch.ts:54` | `POST /auth/logout` |
- `SessionUser` 타입: id, email, name?, role?, company_id?, is_master?
- `fetchSession`/`fetchSessionUser`/`logout`은 [[a00_app_shell_framework]]에서도 사용 (공유 자원)
## 제출 및 OTP 제어 로직 (2단계 폼 전환)
1. **초기 화면**: 이메일 유효성 검사 (isBlank/isValidEmail) → 실패 시 필드 에러. `[hidden]` css 속성이 `ui_template_elements.ts` 전역 기본 스타일에 적용되어 OTP 필드는 숨김 상태로 시작.
2. **1차 로그인**: 비밀번호 필수 입력 → `requestLogin` 호출
3. **OTP 전환 (`status === "otp_required"`)**:
- `otpRequired` true 설정. password 필드 숨김, OTP 필드 노출.
- 제출 버튼 라벨 → `A06_Login_Verify`
- **재발송 버튼 & 뒤로가기 링크 활성화**: 메일 미수신 시 대처할 수 있도록 노출.
4. **뒤로가기 클릭**: `otpRequired` 상태를 해제하고, 이메일 필드 활성화 및 비밀번호 필드 표시 상태로 복원.
5. **재발송 클릭**: `login/request` API를 재요청하고 60초간 버튼을 비활성화하며 `A06_Login_Resend_Cooldown` 리소스를 기준으로 남은 쿨다운 초수 표시.
6. **2차 OTP 검증**: 6자리 숫자 입력 검증 → `verifyLogin` 호출
7. **로그인 성공**: 성공 토스트 메시지 표출 후 `navigateTo(ROUTES.B01_ACCOUNT)`로 이동.
## 로컬라이제이션
모든 텍스트는 [[ui_templates]]에서 로드. 하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목 | `A06_Login_Title` |
| 이메일/비번/OTP 필드 | `A06_Login_Field_Email`, `A06_Login_Field_Password`, `A06_Login_Field_Otp` |
| 제출/인증 버튼 | `A06_Login_Submit`, `A06_Login_Verify` |
| 회원가입 이동 | `A06_Login_ToRegister` |
| 안내/성공 | `A06_Login_OtpSent`, `A06_Login_Success` |
| 재발송 / 뒤로가기 / 쿨다운 | `A06_Login_Resend`, `A06_Login_BackToLogin`, `A06_Login_Resend_Cooldown` |
| 오류 | `A06_Login_Error_Email`, `A06_Login_Error_Required`, `A06_Login_Error_Request` |
## 스타일 (CSS)
- `.a06-login` — 페이지 래퍼 (중앙 정렬, 상단 정렬)
- `.a06-login__card` — 로그인 카드 (max-width: 400px, surface 배경, border)
- `.a06-login__title` — heading-sm, deep-iris, 중앙 정렬
- `.a06-login__form` — flex 열 (gap: spacing-16)
- `.a06-login__submit` / `.a06-login__link` — 전체 너비 버튼
## 이벤트 핸들러
| 함수 | 위치 | 동작 |
|---|---|---|
| `onA06_Login_Submit_Click()` | `A06_Login/A06_Login_UI_Auth_Page.ts:34` | 로그인/OTP 제출 |
| `onA06_Login_Resend_Click()` | `A06_Login/A06_Login_UI_Auth_Page.ts:50` | OTP 재발송 및 쿨다운 제어 |
| `onA06_Login_Back_Click()` | `A06_Login/A06_Login_UI_Auth_Page.ts:65` | 이전 단계 복귀 |
| (인라인) 회원가입 버튼 | `A06_Login/A06_Login_UI_Auth_Page.ts:75` | A07_REGISTER로 이동 |
## 의존성
- [[a00_app_shell_framework]] — `navigateTo()` 라우팅
- `config_frontend.ts` — `ROUTES`, `API_BASE_URL`
- `common_util_validate` — `isBlank`, `isValidEmail`
- [[ui_templates]] — `createButton`, `createInputField`, `showLoadingOverlay`/`hideLoadingOverlay`, `showToast`
- 백엔드 API → [[A06_Login/A06_backend]]
@@ -0,0 +1,28 @@
---
type: file-backend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A06_Login
source_file: "A06_Login/A06_Login_Router.py"
last_updated: 2026-07-24
---
# A06_Login_Router.py
사용자 비밀번호/OTP 로그인, 디바이스 토큰(HttpOnly) 기기 신뢰 90일 만료 재인증, 세션 상태 확인 및 비밀번호 변경 API 라우터 모듈입니다.
## 🛠️ 라우터 API 및 주요 헬퍼 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `request_login()` | `A06_Login/A06_Login_Router.py` | `POST /api/auth/login/request` — 이메일/비밀번호 1차 검증 (5회 실패 계정 잠금, 90일 정기/신규 브라우저 OTP 발송) |
| `verify_login()` | `A06_Login/A06_Login_Router.py` | `POST /api/auth/login/verify` — 2차 OTP 코드 검증 및 로그인 완료 처리 |
| `current_session()` | `A06_Login/A06_Login_Router.py` | `GET /api/auth/session` — 현재 접속 세션 사용자 상태 및 역할(role/is_master) 반환 |
| `logout()` | `A06_Login/A06_Login_Router.py` | `POST /api/auth/logout` — 세션 쿠키 삭제 및 DB 세션 레코드 폐기 |
| `update_password()` | `A06_Login/A06_Login_Router.py` | `POST /api/auth/password` — 현재 비밀번호 확인 후 신규 비밀번호 변경 및 세션 재인증 요구 |
| `_finish_login()` | `A06_Login/A06_Login_Router.py` | 디바이스 토큰 생성·저장, 세션 레코드 생성 및 HttpOnly 세션/디바이스 쿠키 바인딩 헬퍼 |
| `_send_otp()` | `A06_Login/A06_Login_Router.py` | 6자리 OTP 코드 생성, 해시 저장 및 배경 이메일 발송 헬퍼 |
## 🔗 연관 개념 및 의존성
- `common_util_auth.py` — 세션 쿠키 암호화 및 디바이스 토큰 헬퍼
- `common_util_auth_repository.py` — `users`, `sessions`, `device_tokens`, `otp_codes` DB CRUD
@@ -0,0 +1,59 @@
---
status: stable
page_id: A07_Register
related_pages: ["[[A07_Register/A07_frontend]]", "[[A06_Login/A06_backend]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-17
source: docs/raw/verification/2026-07-17_verify_auth_reverify.md
---
# A07_Register — Backend
회원가입(2단계: 요청 → OTP 검증) + 회사 검색 API. prefix `/api/auth` ([[A06_Login/A06_backend]]와 공유).
## 파일 구조
| 파일 | 세분화 위키 명세 | 역할 |
|---|---|---|
| `A07_Register_Router.py` | `[[A07_Register/backend/A07_Register_Router]]` | 회원가입/회사검색 API 라우터 |
| `A07_Register_Schema.py` | `A07_Register/A07_Register_Schema.py` | 요청 검증 Pydantic 모델 2종 |
## API 엔드포인트
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `GET /api/auth/companies?q=` | `A07_Register/A07_Register_Router.py:26` | 회사명 검색(1~100자) → id/name 목록 |
| `POST /api/auth/register/request` | `A07_Register/A07_Register_Router.py:31` | 1차 가입 요청(202). OTP 메일 발송, PENDING_EMAIL 계정 생성 |
| `POST /api/auth/register/verify` | `A07_Register/A07_Register_Router.py:57` | OTP 검증 → 가입 완료(NO_COMPANY 상태) 및 디바이스 토큰 발급/신뢰 등록 처리 |
## 요청 스키마 (Pydantic)
| 모델 | 위치 | 필드 |
|---|---|---|
| `RegisterRequest` | `A07_Register/A07_Register_Schema.py:6` | email, password/password_confirm(8~128), name, position?, phone?, terms_version, terms_agreed, privacy_agreed, marketing_agreed |
| `RegisterVerifyRequest` | `A07_Register/A07_Register_Schema.py:27` | email(EmailStr), otp_code(정규식 `^\d{6}$`) |
- `RegisterRequest.validate_registration` (model_validator): 필수 약관 동의 확인 + 비밀번호 일치 확인
## 가입 로직 흐름
1. `register/request`:
- 기존 이메일 조회 → `PENDING_EMAIL`이 아니면 409(이미 등록됨)
- `PENDING_EMAIL`(미인증)이면 `refresh_pending_registration()`으로 갱신
- 신규면 `create_registration()`으로 생성
- OTP 생성·해시 저장·메일 발송
2. `register/verify`:
- `PENDING_EMAIL` 상태 확인 → OTP 검증(만료/해시) → 소비
- `complete_registration()` → 상태 `NO_COMPANY`로 전환
- **디바이스 신뢰 연계**: 무작위 32바이트 디바이스 토큰 생성 → 브라우저 쿠키(`device_token`)에 90일 만료 및 HttpOnly 옵션으로 설정 → 토큰 SHA256 해시를 `trusted_devices` 테이블에 저장하여, 첫 로그인 시 OTP 재인증 단계 생략
- **회사 생성/연결은 로그인 후 B01_Dashboard에서 진행** (가입 시점엔 회사 없음)
## 의존성 (공통 유틸)
- [[common_util]] — `common_util_auth`(OTP/해시/디바이스토큰/쿠키헬퍼), `common_util_auth_repository`(가입/회사검색/기기신뢰 DB), `common_util_email`(메일)
- 사용자 상태 생명주기(PENDING_EMAIL → NO_COMPANY) → [[auth_rbac]]
- 회원 테이블 → [[db_schema/users_auth]]
## 참고
- 회원가입은 회사 없이 완료됨(NO_COMPANY). 회사 검색 API는 프론트 자동완성용이나,
실제 회사 연결은 B01_Dashboard에서 처리 → [[B01_Dashboard/B01_backend]]
@@ -0,0 +1,91 @@
---
status: draft
page_id: A07_Register
related_pages: ["[[A07_Register/A07_backend]]", "[[A06_Login/A06_frontend]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A07_Register — Frontend
회원가입 화면. 정보 입력 + 약관 아코디언 동의 → OTP 입력으로 전환하는 2단계 폼.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A07_Register_UI_Auth_Page.ts` | `A07_Register/A07_Register_UI_Auth_Page.ts:1-208` | **실사용** 회원가입 UI (약관·OTP·실 API) |
| `A07_Register_UI_Page.ts` | `A07_Register/A07_Register_UI_Page.ts:1-142` | ⚠️ 구버전 잔재 (미사용, 아래 참고) |
| `A07_Register_UI_Style.css` | `A07_Register/A07_Register_UI_Style.css:1-103` | 스타일 (theme.css 변수만 사용) |
| `A07_Register_Api_Fetch.ts` | `A07_Register/A07_Register_Api_Fetch.ts:1-47` | 회원가입/회사검색 API 클라이언트 |
> ⚠️ **라우터는 `A07_Register_UI_Auth_Page`만 사용** (router.ts:30 확인). `A07_Register_UI_Page.ts`는
> 회사명+이름+이메일+비번만 받는 단순 폼이며 백엔드 미연동(TODO 주석, `navigateTo`만) — 구버전 잔재로 판단. 정리 권장.
## 컴포넌트 / 함수 (UI_Auth_Page — 실사용)
| 함수 | 위치 | 역할 |
|---|---|---|
| `renderA07Register(root)` | `A07_Register/A07_Register_UI_Auth_Page.ts:68` | 카드+폼 조립, 약관 텍스트 비동기 로드 후 렌더 |
| `onA07_Register_Submit_Click(event)` | `A07_Register/A07_Register_UI_Auth_Page.ts:146` | 제출 핸들러(검증→가입요청→OTP 전환→검증) |
| `checkboxWithAccordion(label, text)` | `A07_Register/A07_Register_UI_Auth_Page.ts:22` | 체크박스+펼침 상세(약관 본문) 컴포넌트 |
| `loadAgreementText(filename)` | `A07_Register/A07_Register_UI_Auth_Page.ts:58` | `resources/legal/*.txt` 약관 파일 fetch |
## API 클라이언트 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `requestRegistration(payload)` | `A07_Register/A07_Register_Api_Fetch.ts:28` | `POST /auth/register/request` |
| `verifyRegistration(email, otpCode)` | `A07_Register/A07_Register_Api_Fetch.ts:32` | `POST /auth/register/verify` |
| `searchCompanies(query)` | `A07_Register/A07_Register_Api_Fetch.ts:39` | `GET /auth/companies?q=` → id/name 목록 |
- `RegisterPayload` 타입: email, password, password_confirm, name, position, phone, terms_version, terms_agreed, privacy_agreed, marketing_agreed
## 제출 로직 (2단계 폼 전환)
1. **입력 검증**: 이름/이메일/비번/비번확인 필수, 이메일 형식, 비번 8자 이상, 비번 일치, 필수 약관(terms/privacy) 체크
2. `requestRegistration()` 호출 (`terms_version: "1.0"` 고정, terms_agreed/privacy_agreed true)
3. 성공 시 `verifyStep = true`: 입력 필드 숨기고 OTP 필드 노출, 버튼 라벨 → `A07_Register_Verify`
4. OTP 제출 → `verifyRegistration()` → 성공 토스트 → `navigateTo(ROUTES.A06_LOGIN)`
## 약관 동의 (아코디언)
- `checkboxWithAccordion`으로 이용약관/개인정보/마케팅 3종 생성
- 약관 본문은 `resources/legal/{terms_of_service,privacy_policy,marketing_consent}.txt`에서 fetch
- 마케팅은 선택(marketing_agreed), 이용약관·개인정보는 필수
## 로컬라이제이션
모든 텍스트는 [[ui_templates]]에서 로드. 하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목 | `A07_Register_Title` |
| 필드 | `A07_Register_Field_Name`, `_Position`, `_Email`, `_Phone`, `_Password`, `_PasswordConfirm`, `_Otp` |
| 약관 | `A07_Register_Terms`, `_Privacy`, `_Marketing` |
| 제출/인증 | `A07_Register_Submit`, `A07_Register_Verify` |
| 안내/성공 | `A07_Register_OtpSent`, `A07_Register_Success` |
| 오류 | `A07_Register_Error_Required`, `_Email`, `_Password`, `_PasswordMismatch`, `_Terms`, `_Request` |
| 로그인 이동 | `A07_Register_ToLogin` |
## 스타일 (CSS)
- `.a07-register__card` — 카드 (max-width: 420px)
- `.a07-register__agreement` — 약관 컨테이너(border, overflow hidden)
- `.a07-register__agreement-summary` — 체크박스+라벨 헤더(클릭 시 상세 토글)
- `.a07-register__agreement-details` / `-content` — 펼침 약관 본문(max-height 200px, pre-wrap)
## 이벤트 핸들러
| 함수 | 위치 | 동작 |
|---|---|---|
| `onA07_Register_Submit_Click()` | `A07_Register/A07_Register_UI_Auth_Page.ts:146` | 가입/OTP 제출 |
| (인라인) 로그인 버튼 | `A07_Register/A07_Register_UI_Auth_Page.ts:201` | A06_LOGIN으로 이동 |
| (인라인) 약관 요약 클릭 | `A07_Register/A07_Register_UI_Auth_Page.ts:47` | 상세 아코디언 토글 |
## 의존성
- [[a00_app_shell_framework]] — `navigateTo()` 라우팅
- `config_frontend.ts` — `ROUTES`, `API_BASE_URL`
- `common_util_validate` — `isBlank`, `isValidEmail`, `hasMinLength`
- [[ui_templates]] — `createButton`, `createInputField`, `showLoadingOverlay`/`hideLoadingOverlay`, `showToast`
- 백엔드 API → [[A07_Register/A07_backend]]
@@ -0,0 +1,23 @@
---
type: file-backend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A07_Register
source_file: "A07_Register/A07_Register_Router.py"
last_updated: 2026-07-24
---
# A07_Register_Router.py
신규 회원가입 2단계 (가입 신청 ➡️ 이메일 OTP 검증), 디바이스 신뢰 쿠키 자동 발급 및 소속 회사 검색 API 라우터 모듈입니다.
## 🛠️ 라우터 API 및 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `find_companies()` | `A07_Register/A07_Register_Router.py` | `GET /api/auth/companies` — 소속 회사 선택용 등록 회사명 검색 |
| `request_registration()` | `A07_Register/A07_Register_Router.py` | `POST /api/auth/register/request` — 회원가입 1단계 신청, PENDING_EMAIL 상태 기록 및 OTP 발송 |
| `verify_registration()` | `A07_Register/A07_Register_Router.py` | `POST /api/auth/register/verify` — 회원가입 2단계 OTP 검증, 가입 완료(`NO_COMPANY`) 및 디바이스 신뢰 쿠키 발급 |
## 🔗 연관 개념 및 의존성
- `common_util_auth_repository.py` — `create_registration`, `complete_registration`, `trust_device` DB 트랜잭션
@@ -0,0 +1,61 @@
---
status: stable
page_id: A08_Support
related_pages: ["[[A08_Support/A08_frontend]]", "[[A06_Login/A06_backend]]", "[[db_schema/logs_monitoring]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-19
source: docs/raw/verification/2026-07-12_verify_add_phase4_role.md
---
# A08_Support — Backend
기술지원 문의 접수 API. `support_requests` 테이블 저장 + 관리자 알림 메일.
## 파일 구조
| 파일 | 세분화 위키 명세 | 역할 |
|---|---|---|
| `A08_Support_Router.py` | `[[A08_Support/backend/A08_Support_Router]]` | 문의 접수 API (prefix `/api/a08`) |
| `A08_Support_Schema.py` | `A08_Support/A08_Support_Schema.py` | 문의 요청 검증 Pydantic 모델 |
## API 엔드포인트
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `POST /api/a08/support` | `A08_Support/A08_Support_Router.py:27` | 문의 접수. DB 저장 + ADMIN_EMAIL로 알림 메일 |
## 내부 헬퍼
| 함수 | 위치 | 역할 |
|---|---|---|
| `_get_company_name(company_id)` | `A08_Support/A08_Support_Router.py:16` | company_id로 회사명 조회 (없으면 None) |
## 요청 스키마 (Pydantic)
| 모델 | 위치 | 필드 |
|---|---|---|
| `SupportRequestPayload` | `A08_Support/A08_Support_Schema.py:6` | name(1~255), email(EmailStr), phone?(≤30), subject(1~255), message(1~5000) |
## 접수 로직
1. `get_optional_session()`으로 로그인 여부 확인 (비로그인 허용)
2. 로그인 상태면 세션의 `company_id` → `_get_company_name()`으로 회사명 조회, 비로그인이면 None
3. `support_requests` INSERT (아래 컬럼)
4. ADMIN_EMAIL 설정 시 관리자에게 문의 알림 메일 발송
## DB 저장 컬럼 (실 코드 INSERT 기준)
`support_requests`에 INSERT하는 컬럼:
`company_id, company_name, user_name, user_email, user_phone, subject, message`
→ 테이블 정의 → [[db_schema/logs_monitoring]]
## 특징
- **비로그인도 문의 가능** (`get_optional_session`): 세션 없으면 회사 정보만 None으로 저장
- 로그인 상태면 회사 정보 자동 연결
## 의존성 (공통 유틸)
- [[common_util]] — `common_util_auth`(`get_optional_session`), `common_util_email`(`send_email_background`), `common_util_email_templates`(`support_request_email`)
- `config_system` — `ADMIN_EMAIL`
- DB → [[db_schema/logs_monitoring]]
@@ -0,0 +1,76 @@
---
status: draft
page_id: A08_Support
related_pages: ["[[A08_Support/A08_backend]]", "[[a00_app_shell_framework]]", "[[ui_templates]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A08_Support — Frontend
기술지원 문의 폼. 이름·이메일·연락처·제목·문의내용(textarea) 입력 후 제출.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A08_Support_UI_Page.ts` | `A08_Support/A08_Support_UI_Page.ts:1-217` | 문의 폼 렌더링 + 제출 로직 |
| `A08_Support_UI_Style.css` | `A08_Support/A08_Support_UI_Style.css:1-64` | 스타일 (theme.css 변수만 사용) |
## 컴포넌트 / 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `renderA08Support(root)` | `A08_Support/A08_Support_UI_Page.ts:69` | 카드+폼 조립, 세션 정보 자동 채움 |
| `onA08_Support_Submit_Click(event)` | `A08_Support/A08_Support_UI_Page.ts:133` | 제출 핸들러(검증→fetch POST) |
| `createTextAreaField(label, placeholder)` | `A08_Support/A08_Support_UI_Page.ts:32` | 여러 줄 textarea 필드(에러 슬롯 포함) 생성 |
## 제출 로직
1. 필수값 검사(name/email/subject/message), 이메일 형식 검사
2. `fetch("/api/a08/support", POST)` 직접 호출 (별도 Api_Fetch 파일 없음)
3. 성공: 폼 리셋 + 성공 메시지(`A08_Support_Success`) 표시
4. 실패: nameField에 오류 메시지 표시
## 세션 자동 채움
- 렌더 후 백그라운드에서 `fetchSessionUser()`([[A06_Login/A06_frontend]]) 호출
- 로그인 상태면 name/email 필드 자동 입력 (렌더링 지연 없음)
## 로컬라이제이션
모든 텍스트는 [[ui_templates]]에서 로드. 하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목/부제 | `A08_Support_Title`, `A08_Support_Subtitle` |
| 필드 | `A08_Support_Field_Name`, `_Email`, `_Phone`, `_Subject`, `_Message` (+각 Placeholder) |
| 제출 | `A08_Support_Submit` |
| 성공 | `A08_Support_Success` |
| 오류 | `A08_Support_Error_Required`, `A08_Support_Error_Email` |
## 스타일 (CSS)
- `.a08-support__card` — 카드 (max-width: 520px)
- `.a08-support__success` — 성공 메시지(success 색, mist-violet 배경), 기본 hidden
- `.a08-support__form` — flex 열 (gap: spacing-16)
- `.a08-support__textarea` — resize vertical, min-height 120px
- `.a08-support__submit` — 전체 너비 버튼
## 이벤트 핸들러
| 함수 | 위치 | 동작 |
|---|---|---|
| `onA08_Support_Submit_Click()` | `A08_Support/A08_Support_UI_Page.ts:133` | 문의 검증·제출 |
## 의존성
- `config_frontend.ts` — (직접 `/api/a08/support` 상대경로 fetch)
- `common_util_validate` — `isBlank`, `isValidEmail`
- [[A06_Login/A06_frontend]] — `fetchSessionUser` (세션 자동 채움)
- [[ui_templates]] — `createButton`, `createInputField` (textarea는 자체 구현)
- 백엔드 API → [[A08_Support/A08_backend]]
## 참고
- 문의 폼은 로그인/비로그인 모두 사용 가능 (세션 있으면 name/email 자동 입력)
- textarea는 공통 컴포넌트에 없어 `createTextAreaField`로 자체 구현 (`.ui-field`/`.ui-input` 스타일 상속)
@@ -0,0 +1,23 @@
---
type: file-backend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A08_Support
source_file: "A08_Support/A08_Support_Router.py"
last_updated: 2026-07-24
---
# A08_Support_Router.py
로그인/비로그인 사용자의 기술지원 및 문의 요청을 접수하여 `support_requests` DB 테이블에 기록하고 관리자 이메일 알림을 격발하는 백엔드 라우터 모듈입니다.
## 🛠️ 라우터 API 및 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `submit_support_request()` | `A08_Support/A08_Support_Router.py` | `POST /api/a08/support` — 문의 접수, 세션 회사명 조회 결합, `support_requests` INSERT 및 관리자 이메일 발송 |
| `_get_company_name()` | `A08_Support/A08_Support_Router.py` | `company_id`로 `companies` 테이블에서 회사명 조회 |
## 🔗 연관 개념 및 의존성
- `common_util_email.py` — `send_email_background` 메일 발송 헬퍼
- `common_util_auth.py` — `get_optional_session` 비인가/인가 선택적 세션 추출
@@ -0,0 +1,77 @@
---
status: draft
page_id: A09_Security
related_pages: ["[[A09_Security/A09_frontend]]", "[[A06_Login/A06_backend]]", "[[A07_Register/A07_backend]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A09_Security — Backend
마스터(회사관리자)·시스템관리자 보안/조직 관리 API + 활동 로그 기록. prefix `/api/security`.
## 파일 구조
| 파일 | 세분화 위키 명세 | 역할 |
|---|---|---|
| `A09_Security_Router.py` | `[[A09_Security/backend/A09_Security_Router]]` | 마스터/시스템관리자/활동로그 API |
| `A09_Security_Schema.py` | `A09_Security/A09_Security_Schema.py` | 요청 검증 Pydantic 모델 3종 |
## API 엔드포인트
### 마스터(회사 관리자) 전용 — `require_master`
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `GET /api/security/master/dashboard` | `A09_Security/A09_Security_Router.py:28` | 마스터 대시보드(회사 기준) |
| `GET /api/security/master/members` | `A09_Security/A09_Security_Router.py:33` | 회사 팀원 목록 |
| `GET /api/security/master/join-requests` | `A09_Security/A09_Security_Router.py:38` | 가입 요청 목록 |
| `POST /api/security/master/join-requests/{id}/decision` | `A09_Security/A09_Security_Router.py:43` | 가입 승인/거부 + 결과 메일 발송 |
| `POST /api/security/master/members/{id}/remove` | `A09_Security/A09_Security_Router.py:59` | 팀원 비활성화(내보내기) |
### 시스템 관리자 전용 — `require_system_admin`
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `GET /api/security/admin/dashboard` | `A09_Security/A09_Security_Router.py:86` | 시스템 대시보드 + psutil 리소스(cpu/memory/disk/process) |
| `GET /api/security/admin/{collection}` | `A09_Security/A09_Security_Router.py:101` | 컬렉션 목록(companies/users/support) |
| `PATCH /api/security/admin/{entity}/{id}/status` | `A09_Security/A09_Security_Router.py:110` | 엔티티 상태 변경(company/user/support) |
### 인증 사용자 공통 — `verify_session`
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `POST /api/security/activity` | `A09_Security/A09_Security_Router.py:66` | 활동 로그 기록(202), `activity_logs` INSERT |
## 요청 스키마 (Pydantic)
| 모델 | 위치 | 필드 |
|---|---|---|
| `JoinDecisionRequest` | `A09_Security/A09_Security_Schema.py:8` | approved(bool), comment?(≤1000) |
| `AdminStatusRequest` | `A09_Security/A09_Security_Schema.py:13` | status(3~20), reason(1~500) |
| `ActivityLogRequest` | `A09_Security/A09_Security_Schema.py:18` | action_type(Literal 5종), resource_id?, status(SUCCESS/FAILURE), details(dict) |
- `action_type` Literal: FILE_UPLOAD, FILE_DOWNLOAD, PROJECT_SAVE, DATA_PROCESS, PAGE_VIEW
## DB 저장 (activity_logs)
`POST /activity`가 INSERT하는 컬럼: `user_id, action_type, resource_id, status, details(JSON)`
→ 테이블 정의 → [[db_schema/logs_monitoring]]
## 권한 헬퍼
- `require_master` — 회사 마스터(is_master) 권한
- `require_system_admin` — SYSTEM_ADMIN 역할
- `verify_session` — 로그인 세션
- 권한 체계 상세 → [[auth_rbac]]
## 의존성 (공통 유틸)
- [[common_util]] — `common_util_auth`(권한 데코레이터), `common_util_auth_repository`(마스터/관리자 조회·처리), `common_util_email`(가입 결과 메일)
- 외부 라이브러리: `psutil`(관리자 대시보드 리소스 계측) → [[dependencies]]
- DB → [[db_schema/logs_monitoring]](activity_logs), [[db_schema/users_auth]](join_requests/companies)
## 참고
- 이 백엔드 API는 마스터/시스템관리자용이나, **프론트(`A09_Security_UI_Page.ts`)는 약관 열람만 하고 이 API를 사용하지 않음**.
API 클라이언트(`A09_Security_Api_Fetch.ts`)는 정의만 되고 미연동 상태 → [[A09_Security/A09_frontend]] 참고
- B01_Dashboard의 관리자 기능과 역할이 겹칠 수 있음 (마스터 대시보드/멤버관리) — 향후 연동처 확인 필요
@@ -0,0 +1,78 @@
---
status: draft
page_id: A09_Security
related_pages: ["[[A09_Security/A09_backend]]", "[[A06_Login/A06_frontend]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
last_updated: 2026-07-12
---
# A09_Security — Frontend
보안·약관 열람 페이지. 이용약관/개인정보/세션 보안정책 텍스트를 버전과 함께 표시.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `A09_Security_UI_Page.ts` | `A09_Security/A09_Security_UI_Page.ts:1-30` | **실사용** 약관 열람 페이지 렌더링 |
| `A09_Security_Terms.ts` | `A09_Security/A09_Security_Terms.ts:1-16` | 약관 텍스트 데이터(한/영), 버전 상수 |
| `A09_Security_UI_Style.css` | `A09_Security/A09_Security_UI_Style.css:1-14` | 스타일 (theme.css 변수만 사용) |
| `A09_Security_Api_Fetch.ts` | `A09_Security/A09_Security_Api_Fetch.ts:1-61` | ⚠️ API 클라이언트 (정의만, **미사용** — 아래 참고) |
> ⚠️ **프론트/백엔드 기능 불일치**: `A09_Security_UI_Page.ts`는 약관 텍스트 열람만 하며
> `A09_Security_Api_Fetch.ts`를 import하지 않는다. API 클라이언트(마스터/관리자 8함수)는 정의만 되고
> 어디서도 사용되지 않음(grep 확인). 백엔드 API(`/api/security`)는 완비돼 있으나 프론트 연동 미완.
## 컴포넌트 / 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `renderA09Security(root)` | `A09_Security/A09_Security_UI_Page.ts:7` | 제목+버전+3개 약관 섹션 렌더 |
## 약관 데이터 (A09_Security_Terms.ts)
| 항목 | 위치 | 내용 |
|---|---|---|
| `SECURITY_TERMS_VERSION` | `A09_Security/A09_Security_Terms.ts:1` | 약관 버전 상수 `"1.0"` |
| `securityTerms.terms` | `A09_Security/A09_Security_Terms.ts:4` | 이용약관(한/영) |
| `securityTerms.privacy` | `A09_Security/A09_Security_Terms.ts:8` | 개인정보(한/영, "IP 미수집" 명시) |
| `securityTerms.security` | `A09_Security/A09_Security_Terms.ts:12` | 세션 보안정책(한/영) |
## API 클라이언트 함수 (⚠️ 미사용, 정의만)
| 함수 | 위치 | 대응 API |
|---|---|---|
| `getMasterDashboard()` | `A09_Security/A09_Security_Api_Fetch.ts:14` | `GET /security/master/dashboard` |
| `getMembers()` | `A09_Security/A09_Security_Api_Fetch.ts:18` | `GET /security/master/members` |
| `getJoinRequests()` | `A09_Security/A09_Security_Api_Fetch.ts:22` | `GET /security/master/join-requests` |
| `decideJoinRequest(id, approved, comment?)` | `A09_Security/A09_Security_Api_Fetch.ts:26` | `POST .../join-requests/{id}/decision` |
| `removeMember(userId)` | `A09_Security/A09_Security_Api_Fetch.ts:37` | `POST .../members/{id}/remove` |
| `getAdminDashboard()` | `A09_Security/A09_Security_Api_Fetch.ts:41` | `GET /security/admin/dashboard` |
| `getAdminCollection(collection)` | `A09_Security/A09_Security_Api_Fetch.ts:45` | `GET /security/admin/{collection}` |
| `updateAdminStatus(entity, id, status, reason)` | `A09_Security/A09_Security_Api_Fetch.ts:51` | `PATCH /security/admin/{entity}/{id}/status` |
## 로컬라이제이션
모든 텍스트는 [[ui_templates]]에서 로드. 하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목/버전 | `A09_Security_Title`, `A09_Security_Version` |
| 섹션 제목 | `A09_Security_Terms`, `A09_Security_Privacy`, `A09_Security_Policy` |
- 약관 본문은 로케일이 아닌 `A09_Security_Terms.ts`에 한/영 배열로 별도 관리(`[currentLanguageIndex]`로 선택)
## 스타일 (CSS)
- `.a09-security` — 문서 컨테이너(max-width 800px, surface 배경, border)
- `.a09-security section` — 섹션 간격(margin-top: spacing-32)
## ⚠️ 약관 텍스트와 실 코드 불일치
`securityTerms.security`는 "세션 12시간 또는 4시간 비활동 후 만료"로 안내하나,
A06 실 코드는 `auth_expires_at = NOW() + 3개월` 방식 → [[A06_Login/A06_backend]] 참고.
약관 텍스트도 [[auth_rbac]] 계획서 기준으로 작성됨 (실 정책 검증 후 갱신 필요).
## 의존성
- [[ui_templates]] — `ui_locales`, `currentLanguageIndex` (다국어)
- 백엔드 API(미연동) → [[A09_Security/A09_backend]]
@@ -0,0 +1,30 @@
---
type: file-backend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/public_admin_map]]"]
page_id: A09_Security
source_file: "A09_Security/A09_Security_Router.py"
last_updated: 2026-07-24
---
# A09_Security_Router.py
회사 마스터 조직 관리(팀원 승인/제거), 사용자 활동 감사 로그 기록(`activity_logs`) 및 시스템 관리자 전용 서버 자원 모니터링(`psutil`) API 라우터 모듈입니다.
## 🛠️ 라우터 API 및 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `get_master_dashboard()` | `A09_Security/A09_Security_Router.py` | `GET /api/security/master/dashboard` — 마스터 전용 회사 대시보드 통계 조회 |
| `get_members()` | `A09_Security/A09_Security_Router.py` | `GET /api/security/master/members` — 소속 회사 팀원 목록 조회 |
| `get_join_requests()` | `A09_Security/A09_Security_Router.py` | `GET /api/security/master/join-requests` — 대기 중인 회사 가입 요청 목록 조회 |
| `review_join_request()` | `A09_Security/A09_Security_Router.py` | `POST /api/security/master/join-requests/{id}/decision` — 가입 신청 승인/거절 및 이메일 결과 통보 |
| `deactivate_member()` | `A09_Security/A09_Security_Router.py` | `POST /api/security/master/members/{id}/remove` — 소속 팀원 권한 비활성화 |
| `write_activity()` | `A09_Security/A09_Security_Router.py` | `POST /api/security/activity` — 사용자 액션 및 리소스 변경 감사 로그 `activity_logs` INSERT |
| `get_admin_dashboard()` | `A09_Security/A09_Security_Router.py` | `GET /api/security/admin/dashboard` — 시스템 관리자 메트릭 및 `psutil` 기반 CPU/메모리/디스크 실시간 자원 조회 |
| `get_admin_collection()` | `A09_Security/A09_Security_Router.py` | `GET /api/security/admin/{collection}` — 컬렉션별 시스템 관리자 대상 리스팅 |
| `set_admin_status()` | `A09_Security/A09_Security_Router.py` | `PATCH /api/security/admin/{entity}/{id}/status` — 엔티티 상태 변경 패치 |
## 🔗 연관 개념 및 의존성
- `common_util_auth.py` — `require_master`, `require_system_admin` RBAC 권한 검증
- `common_util_auth_repository.py` — `master_dashboard`, `decide_join_request`, `admin_dashboard` DB 함수
+61
View File
@@ -0,0 +1,61 @@
---
type: page-api
status: draft
page_id: B01_Dashboard
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[B01_Dashboard/B01_backend]]", "[[B01_Dashboard/B01_db]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-08
source: 상위 프로젝트 B01_Dashboard_Router.py 실 코드 직접 확인 (2026-08-08)
---
# B01_Dashboard — API
이 API는 [[B01_Dashboard/B01_frontend]]의 요청을 받아 [[B01_Dashboard/B01_backend]]가 처리하며, 인증·오류 규칙은 [[auth_rbac]]과 [[api_common]]을 사용한다.
기본 prefix: `/api/dashboard` (`B01_Dashboard_Router.py:50`). 공통 인증·오류 형식은 [[auth_rbac]], [[api_common]] 참조.
## 사용자·회사
| 항목 | 위치 | 역할 |
|---|---|---|
| `GET /me` | `B01_Dashboard_Router.py:88` | 로그인 사용자 대시보드 정보 조회 (하드 삭제 스위치 `project_delete_hard` 포함) |
| `PATCH /me` | `B01_Dashboard_Router.py:98` | 내 기본정보 수정 |
| `GET /user/projects` | `B01_Dashboard_Router.py:107` | 내 프로젝트와 workflow 상태 조회 |
| `GET /user/company` | `B01_Dashboard_Router.py:112` | 소속 회사 조회 |
| `GET /user/companies` | `B01_Dashboard_Router.py:117` | 가입 대상 회사 검색 |
| `POST /user/company/create` | `B01_Dashboard_Router.py:126` | 회사 생성 후 생성자 연결 |
| `POST /user/company/join` | `B01_Dashboard_Router.py:135` | 회사 가입 신청 |
## 회사 관리자
| 항목 | 위치 | 역할 |
|---|---|---|
| `GET /admin/members` | `B01_Dashboard_Router.py:144` | 회사 팀원 목록 |
| `POST /admin/members` | `B01_Dashboard_Router.py:152` | 이메일로 팀원 추가 |
| `DELETE /admin/members/{user_id}` | `B01_Dashboard_Router.py:163` | 팀원 회사 연결 해제 |
| `GET /admin/join-requests` | `B01_Dashboard_Router.py:172` | 회사 가입 신청 목록 |
| `PATCH /admin/join-requests/{request_id}` | `B01_Dashboard_Router.py:177` | 가입 신청 승인·거절 |
| `GET /admin/projects` | `B01_Dashboard_Router.py:195` | 회사 프로젝트 목록 |
## 프로젝트·자동화
| 항목 | 위치 | 역할 |
|---|---|---|
| `PUT /projects/{project_id}` | `B01_Dashboard_Router.py:203` | 프로젝트 기본정보 수정 |
| `DELETE /projects/{project_id}` | `B01_Dashboard_Router.py:219` | SYSTEM_ADMIN 프로젝트 삭제 (개발 모드 시 하드 삭제, 운영 모드 시 소프트 삭제 분기) |
| `GET /projects/{project_id}/automations` | `B01_Dashboard_Router.py:366` | 자동화 목록; USER 차단 |
| `POST /projects/{project_id}/automations` | `B01_Dashboard_Router.py:379` | 자동화 생성 |
| `PUT /automations/{automation_id}` | `B01_Dashboard_Router.py:396` | 자동화 수정 |
| `DELETE /automations/{automation_id}` | `B01_Dashboard_Router.py:414` | 자동화 삭제 |
| `POST /automations/{automation_id}/execute` | `B01_Dashboard_Router.py:429` | 자동화 실행시각 기록 |
## 시스템 관리자
| 항목 | 위치 | 역할 |
|---|---|---|
| `GET /admin/companies` | `B01_Dashboard_Router.py:246` | 전체 회사 조회 |
| `POST /admin/companies` | `B01_Dashboard_Router.py:252` | 시스템 관리자 회사 생성 |
| `GET /admin/users` | `B01_Dashboard_Router.py:261` | 전체 사용자 조회 |
| `PATCH /admin/users/{user_id}/role` | `B01_Dashboard_Router.py:267` | 역할 변경과 마지막 ADMIN 보호 |
| `PUT /admin/users/{user_id}` | `B01_Dashboard_Router.py:285` | 사용자 관리정보 수정 |
| `PATCH /admin/users/{user_id}/company` | `B01_Dashboard_Router.py:304` | 사용자 회사 배정·해제 |
| `GET /admin/join-requests-all` | `B01_Dashboard_Router.py:316` | 전체 가입 신청 조회 |
| `PATCH /admin/join-requests/{request_id}/approve` | `B01_Dashboard_Router.py:322` | 시스템 관리자 가입 승인 |
| `GET /admin/audit-logs` | `B01_Dashboard_Router.py:332` | 시스템 감사 로그 페이지 조회 |
| `GET /admin/resources` | `B01_Dashboard_Router.py:342` | 1~90일 리소스 통계 조회 |
| `GET /admin/projects-all` | `B01_Dashboard_Router.py:351` | 전체 프로젝트 조회 |
@@ -0,0 +1,66 @@
---
type: page-backend
status: stable
page_id: B01_Dashboard
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[B01_Dashboard/B01_api]]", "[[B01_Dashboard/B01_db]]", "[[B01_Dashboard/B01_dependencies]]", "[[auth_rbac]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-08
source: docs/raw/verification/2026-08-08_verify_project_delete_hard.md
---
# B01_Dashboard — Backend
## 세분화 백엔드 위키 명세
- `[[B01_Dashboard/backend/B01_Dashboard_Router]]`: FastAPI 대시보드 API 엔드포인트 명세
- `B01_Dashboard_Repository.py`: Raw SQL 회사, 사용자, 프로젝트 CRUD
- `B01_Dashboard_Schema.py`: Pydantic 요청/응답 검증 모델
- `common_util_project_delete.py`: 프로젝트 하드 삭제 전용 분리 모듈 (700줄 제한 준수)
## 라우터 권한 헬퍼
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `require_company_admin()` | `B01_Dashboard_Router.py` | ADMIN 또는 SYSTEM_ADMIN 의존성 검사 |
| `_require_company_id()` | `B01_Dashboard_Router.py` | 세션 회사 ID 필수 검사 |
| `_same_company()` | `B01_Dashboard_Router.py` | 요청자와 대상의 회사 일치 검사 |
| `_can_edit_project()` | `B01_Dashboard_Router.py` | 역할·회사 기준 프로젝트 수정 검사 |
| `_can_manage_automation()` | `B01_Dashboard_Router.py` | 자동화 관리 권한 검사 |
| `_can_edit_user()` | `B01_Dashboard_Router.py` | 사용자 수정 범위 검사 |
상세 권한 규칙은 [[auth_rbac]]에서 1차 정의한다.
## 저장소 및 삭제 함수
| 항목 | 위치 | 역할 |
| ----------------------------------------------------------------------------- | ----------------------------------------- | -------------------------- |
| `get_dashboard_me()` / `update_user_profile()` | `B01_Dashboard_Repository.py:47,65` | 내 정보 조회(auth_expires_at 대신 `last_email_verified_at + 90일`로 만료일 동적 계산 표시)·수정 |
| `get_workflow_states_for_projects()` | `B01_Dashboard_Repository.py:83` | 여러 프로젝트의 workflow 상태 배치 조회 |
| `list_user_projects()` / `list_company_projects()` / `list_all_projects()` | `B01_Dashboard_Repository.py:144,165,188` | 역할 범위별 프로젝트 목록 조회 |
| `get_project()` / `update_project()` / `soft_delete_project()` | `B01_Dashboard_Repository.py:210,222,253` | 프로젝트 조회·수정·소프트 삭제 |
| `hard_delete_project()` | `common_util/common_util_project_delete.py:18` | 프로젝트 DB 삭제(ON DELETE CASCADE 연쇄) 및 영구저장소 디스크 통삭제 |
| `get_user_company()` / `search_companies()` | `B01_Dashboard_Repository.py:273,293` | 소속 회사와 회사 검색 |
| `create_company()` / `create_system_company()` | `B01_Dashboard_Repository.py:307,347` | 사용자·시스템 관리자 회사 생성 |
| `join_company()` | `B01_Dashboard_Repository.py:378` | 회사 가입 신청과 사용자 상태 전이 |
| `list_company_members()` / `add_company_member()` / `remove_company_member()` | `B01_Dashboard_Repository.py:401,416,439` | 회사 팀원 관리 |
| `list_join_requests()` / `process_join_request()` | `B01_Dashboard_Repository.py:453,471` | 가입 신청 조회·승인·거절 |
| `list_all_companies()` / `list_all_users()` | `B01_Dashboard_Repository.py:507,522` | 시스템 관리자 전체 목록 |
| `change_user_role()` / `get_user_admin_target()` / `update_admin_user()` | `B01_Dashboard_Repository.py:538,547,562` | 사용자 역할·관리정보 변경 |
| `count_company_admins()` / `assign_user_company()` | `B01_Dashboard_Repository.py:584,596` | 마지막 관리자 보호와 회사 배정 |
| `list_audit_logs()` / `get_system_resources()` | `B01_Dashboard_Repository.py:609,624` | 감사 로그와 리소스 통계 조회 |
| `list_project_automations()` / `create_project_automation()` | `B01_Dashboard_Repository.py:682,696` | 자동화 목록·생성 |
| `get_project_automation()` / `update_project_automation()` | `B01_Dashboard_Repository.py:722,735` | 자동화 단건 조회·수정 |
| `delete_project_automation()` / `mark_project_automation_executed()` | `B01_Dashboard_Repository.py:758,779` | 자동화 삭제·실행시각 기록 |
## 요청 스키마
| 항목 | 위치 | 역할 |
|---|---|---|
| `UpdateUserRequest` | `B01_Dashboard_Schema.py:6` | 내 정보 수정 검증 |
| `CreateCompanyRequest` | `B01_Dashboard_Schema.py:13` | 회사 생성 검증 |
| `JoinCompanyRequest` / `AddMemberRequest` | `B01_Dashboard_Schema.py:20,24` | 회사 가입·팀원 추가 검증 |
| `ProcessJoinRequest` / `ChangeUserRoleRequest` | `B01_Dashboard_Schema.py:28,33` | 가입 처리·역할 변경 검증 |
| `AssignCompanyRequest` / `UpdateProjectRequest` | `B01_Dashboard_Schema.py:37,41` | 회사 배정·프로젝트 수정 검증 |
| `AdminUpdateUserRequest` / `AutomationRequest` | `B01_Dashboard_Schema.py:51,57` | 관리자 사용자 수정·자동화 검증 |
## 기술부채
| 항목 | 위치 | 역할 |
|---|---|---|
| 레거시 상태 추론 | `B01_Dashboard_Repository.py:20` | `_stage_from_status()`가 `project_workflow_stages` 미조회 시 보조값 생성 |
| 700줄 초과 | `B01_Dashboard_Repository.py:1` | 790줄로 프로젝트 단일 파일 제한 초과; 도메인별 저장소 분할 검토 필요 |
| 물리적 파일 하드 삭제 모듈 분산 | `common_util_project_delete.py` | 700줄 한계 준수를 위해 신규 파일 삭제 모듈은 레포지토리 외부에 위치 |
+33
View File
@@ -0,0 +1,33 @@
---
type: page-db
status: draft
page_id: B01_Dashboard
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B01_Dashboard/B01_api]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-08
source: 상위 프로젝트 B01_Dashboard_Repository.py 및 common_util_project_delete.py 실 코드 직접 확인 (2026-08-08)
---
# B01_Dashboard — DB 사용 관계
공유 테이블의 정의는 concepts에만 둔다. 이 문서는 B01의 사용 목적과 실제 접근 위치만 기록한다.
| 항목 | 위치 | 역할 |
|---|---|---|
| `users` | `B01_Dashboard_Repository.py:47` | 내 정보·팀원·전체 사용자·역할·회사 연결 관리 → [[db_schema/users_auth]] |
| `companies` | `B01_Dashboard_Repository.py:273` | 소속·검색·생성·전체 회사 조회 → [[db_schema/users_auth]] |
| `join_requests` | `B01_Dashboard_Repository.py:378` | 회사 가입 신청·승인·거절 → [[db_schema/users_auth]] |
| `projects` | `B01_Dashboard_Repository.py:144`, `common_util_project_delete.py:33` | 역할 범위별 목록·수정·소프트 삭제, 개발 모드 시 하드 삭제 → [[db_schema/projects]] |
| `project_workflow_stages` | `B01_Dashboard_Repository.py:83` | 프로젝트 목록의 7단계 상태 배치 조회 → [[workflow_state]] |
| `project_automations` | `B01_Dashboard_Repository.py:682` | 자동화 CRUD와 실행시각 기록 → [[db_schema/projects]] |
| `system_audit_logs` | `B01_Dashboard_Repository.py:245`, `common_util_project_delete.py:64` | 프로젝트·회사·자동화 관리 행위 기록·조회 → [[db_schema/logs_monitoring]] |
| `system_resources` | `B01_Dashboard_Repository.py:624` | 기간별 CPU·메모리·디스크 시계열 조회 → [[db_schema/logs_monitoring]] |
## 트랜잭션 경계
| 항목 | 위치 | 역할 |
|---|---|---|
| 회사 생성 | `B01_Dashboard_Repository.py:307` | 회사 INSERT, 사용자 연결, 감사 로그를 한 트랜잭션으로 처리 |
| 가입 신청 처리 | `B01_Dashboard_Repository.py:471` | `FOR UPDATE`로 신청 행 잠금 후 신청·사용자 상태 동시 변경 |
| 프로젝트 수정·소프트 삭제 | `B01_Dashboard_Repository.py:222,253` | 프로젝트 변경과 감사 로그를 같은 트랜잭션으로 처리 |
| 프로젝트 하드 삭제 | `common_util_project_delete.py:31` | 프로젝트 SELECT(검증), DELETE 및 `PROJECT_HARD_DELETE` 감사 로그 인서트 성공 시 커밋 |
> B01 코드가 직접 기록하는 감사 테이블은 `audit_logs`가 아니라 `system_audit_logs`다.
@@ -0,0 +1,29 @@
---
type: page-dependencies
status: draft
page_id: B01_Dashboard
related_pages: ["[[B01_Dashboard/B01_frontend]]", "[[B01_Dashboard/B01_backend]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-12
source: 상위 프로젝트 B01_Dashboard import 구문 직접 확인 (2026-07-12)
---
# B01_Dashboard — Dependencies
외부 라이브러리의 1차 정의는 [[dependencies]]에 둔다.
| 항목 | 위치 | 역할 |
|---|---|---|
| FastAPI | `B01_Dashboard_Router.py:5` | APIRouter·Depends·HTTPException 제공 |
| Pydantic | `B01_Dashboard_Schema.py:3` | 요청 모델 타입·범위 검증 |
| aiomysql | `B01_Dashboard_Repository.py:10` | MariaDB 비동기 Raw SQL 접근 |
| psutil | `B01_Dashboard_Repository.py:11` | 현재 CPU·메모리 사용률 측정 |
| `shutil` | `B01_Dashboard_Repository.py:6` | 저장소 디스크 사용량 측정 |
| TypeScript DOM | `B01_Dashboard_UI_Page.ts:81` | 역할별 대시보드와 이벤트 구성 |
## 프로젝트 공통 모듈
| 항목 | 위치 | 역할 |
|---|---|---|
| `common_util_auth` | `B01_Dashboard_Router.py:10` | 세션·SYSTEM_ADMIN 권한 의존성 → [[auth_rbac]] |
| `config_db.get_db_pool` | `B01_Dashboard_Repository.py:13` | MariaDB 커넥션 풀 획득 |
| `ui_template_elements` | `B01_Dashboard_UI_Resources.ts:2` | 공통 선형 차트 생성 → [[ui_templates]] |
| `ui_template_locale` | `B01_Dashboard_UI_Resources.ts:1` | 한·영 UI 문자열 선택 → [[ui_templates]] |
@@ -0,0 +1,65 @@
---
type: page-frontend
status: stable
page_id: B01_Dashboard
related_pages: ["[[B01_Dashboard/B01_backend]]", "[[B01_Dashboard/B01_api]]", "[[B01_Dashboard/B01_db]]", "[[ui_templates]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-08
source: ["docs/raw/verification/2026-08-08_verify_dashboard_scroll_limit.md", "docs/raw/verification/2026-07-17_verify_workflow_stepbar.md"]
---
# B01_Dashboard — Frontend
## 파일과 진입점
| 항목 | 위치 | 역할 |
|---|---|---|
| `renderB01Dashboard()` | `B01_Dashboard_UI_Page.ts` | 대시보드 조립 및 메인 오케스트레이션 |
| `request()` | `B01_Dashboard_Api_Fetch.ts` | 쿠키 포함 요청과 공통 오류 처리 |
| `buildResourcePanel()` | `B01_Dashboard_UI_Resources.ts` | CPU·메모리·디스크 현황과 추이 차트 생성 |
| `B01_Dashboard_UI_Style.css` | `B01_Dashboard_UI_Style.css` | 대시보드·표·모달 스타일 |
## 분할된 UI 컴포넌트 파일
| 파일 | 역할 | 주요 구성 요소 |
|---|---|---|
| [[B01_Dashboard/frontend/B01_Dashboard_UI_Page|B01_Dashboard_UI_Page.ts]] | 메인 진입점, 조립 | `renderB01Dashboard`, `loadRoleData`, `buildPage`, `buildHeader` |
| `B01_Dashboard_UI_Common.ts` | 공용 빌딩 블록 | `roleLabel` 및 페이지 전용 텍스트/액션 페어, `DASHBOARD_VISIBLE_ROWS = 4` 높이 제한 상수 정의 |
| `B01_Dashboard_UI_Projects.ts` | 프로젝트 목록 렌더링 | `projectTable`, `workflow` (4행 제한 `limitVisibleRows` 동적 적용) |
| `B01_Dashboard_UI_Company.ts` | 회사 및 멤버 관리 패널 | `buildCompanyPanel`, `memberTable`, `joinRequestTable`, `companyTable` (각 4행 제한 적용) |
| `B01_Dashboard_UI_Admin.ts` | 시스템 관리자 전용 뷰 | `userTable`, `auditLogTable` (각 4행 제한 적용) |
| `B01_Dashboard_UI_Profile.ts` | 사용자 프로필 및 보안 설정 폼 | `buildProfileForm`, `buildSecurityForm` |
| `B01_Dashboard_UI_TempUpload.ts` | 임시 보관함 목록 렌더링 | R2 프로젝트 생성 전 임시 보관함 그룹 렌더링 (4행 스크롤 제한 및 접기/펼치기 토글 시 `remeasureGroups` 재계산 처리) |
| `B01_Dashboard_UI_TempModal.ts` | 임시 보관함 등록 모달 | 모달 내부 업로드 진행률(Progress bar) 표시 및 파일 등록 관리 |
| `B01_Dashboard_Api_Temp.ts` | 임시 보관함 API 바인딩 | 임시 보관함 묶음/파일 API 호출 |
## UI 권한 헬퍼
| 항목 | 위치 | 역할 |
|---|---|---|
| `canEditProject()` | `B01_Dashboard_UI_Helper.ts` | 프로젝트 수정 버튼 표시 판단 |
| `canDeleteProject()` | `B01_Dashboard_UI_Helper.ts` | SYSTEM_ADMIN 삭제 버튼 표시 판단 |
| `canAddUser()` | `B01_Dashboard_UI_Helper.ts` | ADMIN 이상 팀원 추가 표시 판단 |
| `canChangeRole()` | `B01_Dashboard_UI_Helper.ts` | SYSTEM_ADMIN 역할 변경 표시 판단 |
| `canDeleteUser()` | `B01_Dashboard_UI_Helper.ts` | 사용자 제거 표시 판단 |
| `canManageAutomation()` | `B01_Dashboard_UI_Helper.ts` | ADMIN 이상 자동화 관리 표시 판단 |
> UI 헬퍼는 표시만 제어한다. 최종 권한 검증은 백엔드가 수행한다. 상세: [[auth_rbac]].
## 모달
| 항목 | 위치 | 역할 |
|---|---|---|
| `openEditProjectModal()` | `B01_Dashboard_UI_Modals.ts` | 프로젝트 기본정보 수정 |
| `openDeleteProjectModal()` | `B01_Dashboard_UI_Modals.ts` | 프로젝트 삭제 확인 (`DashboardUser.project_delete_hard` 플래그에 따라 하드 삭제 전용 물리 삭제 경고 문구로 스위칭) |
| `openEditUserModal()` | `B01_Dashboard_UI_Modals.ts` | 사용자 정보 수정 |
| `openChangeRoleModal()` | `B01_Dashboard_UI_Modals.ts` | 사용자 역할 변경 |
| `openDeleteUserModal()` | `B01_Dashboard_UI_Modals.ts` | 사용자 제거 확인 |
| `openCreateCompanyModal()` | `B01_Dashboard_UI_Modals.ts` | 회사 생성 |
| `openFindCompanyModal()` | `B01_Dashboard_UI_Modals.ts` | 회사 검색·가입 신청 |
| `openAddMemberModal()` | `B01_Dashboard_UI_Modals.ts` | 회사 팀원 추가 |
| `openAutomationModal()` | `B01_Dashboard_UI_Modals.ts` | 프로젝트 자동화 조회·관리 |
| `openTempUploadModal()` | `B01_Dashboard_UI_TempModal.ts` | 임시 보관함 자료 등록 모달 |
## 공유 자원 연결
| 항목 | 위치 | 역할 |
|---|---|---|
| 인증·역할 | `B01_Dashboard_UI_Page.ts` | 역할별 섹션 제어 → [[auth_rbac]] |
| workflow 상태 | `B01_Dashboard_UI_Projects.ts` | 공통 `createStepBar(compact)` 호출 및 배치 `workflow_state` 데이터 매핑 → [[workflow_state]] |
| 임시 보관함 | `B01_Dashboard_UI_TempUpload.ts` | R2 임시 보관함 자료 관리 → [[temp_upload]] |
| 공통 UI / 높이 제한 | `B01_Dashboard_UI_Projects.ts` | `limitVisibleRows()` 헬퍼를 이용해 4행 제한 안쪽 스크롤 레이아웃 적용 → [[ui_templates]] |
@@ -0,0 +1,29 @@
---
type: file-backend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
page_id: B01_Dashboard
source_file: "B01_Dashboard/B01_Dashboard_Router.py"
last_updated: 2026-08-08
---
# B01_Dashboard_Router.py
역할별(USER, ADMIN, SYSTEM_ADMIN, MASTER) 대시보드, 내 프로젝트 관리, 소속 회사 생성/가입 신청, 팀원 관리 및 시스템 자원 모니터링 API 라우터 모듈입니다.
## 🛠️ 라우터 API 및 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `dashboard_me()` / `patch_dashboard_me()` | `B01_Dashboard/B01_Dashboard_Router.py` | `GET/PATCH /api/dashboard/me` — 사용자 프로필 조회 및 수정 (GET 응답 `user`에 `project_delete_hard` 포함) |
| `user_projects()` | `B01_Dashboard/B01_Dashboard_Router.py` | `GET /api/dashboard/user/projects` — 내 참여/소유 프로젝트 목록 조회 |
| `user_company()` / `user_company_create()` | `B01_Dashboard/B01_Dashboard_Router.py` | `GET/POST /api/dashboard/user/company` — 소속 회사 정보 조회 및 신규 회사 생성(마스터 권한 자동 부여) |
| `user_company_join()` | `B01_Dashboard/B01_Dashboard_Router.py` | `POST /api/dashboard/user/company/join` — 기존 회사 가입 신청 접수 |
| `admin_members()` / `admin_add_member()` / `admin_remove_member()` | `B01_Dashboard/B01_Dashboard_Router.py` | `/api/dashboard/admin/members` — 회사 팀원 목록 조회, 초대 추가 및 제거 |
| `admin_join_requests()` / `admin_process_join_request()` | `B01_Dashboard/B01_Dashboard_Router.py` | `/api/dashboard/admin/join-requests` — 회사 가입 신청 목록 조회 및 승인/거절 처리 |
| `dashboard_update_project()` / `dashboard_delete_project()` | `B01_Dashboard/B01_Dashboard_Router.py` | `/api/dashboard/projects/{id}` — 권한 체크 기반 프로젝트 정보 수정 및 삭제 (`PROJECT_DELETE_HARD_ENABLED` 스위치에 따라 소프트 또는 하드 삭제 실행) |
## 🔗 연관 개념 및 의존성
- `B01_Dashboard_Repository.py` — Raw SQL 기반 회사, 사용자, 프로젝트 DB 조작
- `common_util_project_delete.py` — 프로젝트 하드 삭제 처리 함수 (`hard_delete_project`)
- `common_util_auth.py` — `verify_session`, `require_system_admin` 권한 체크
@@ -0,0 +1,21 @@
---
type: file-frontend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
page_id: B01_Dashboard
source_file: "B01_Dashboard/B01_Dashboard_UI_Page.ts"
last_updated: 2026-07-24
---
# B01_Dashboard_UI_Page.ts
프로젝트 대시보드 메인 페이지 조립, 워크플로우 진행 상태 바인딩 및 회사/사용자/시스템 리소스 모니터링 컴포넌트를 연결하는 프론트엔드 UI 페이지 모듈입니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `renderB01Dashboard()` | `B01_Dashboard/B01_Dashboard_UI_Page.ts` | 프로젝트 대시보드 카드, 7단계 진행 배지 및 시스템 자원 모니터링 DOM 렌더링 |
## 🔗 연관 개념 및 의존성
- `B01_Dashboard_UI_Panel.ts` — 대시보드 관리자 제어 패널
@@ -0,0 +1,75 @@
---
status: draft
page_id: B02_ProjRegister
related_pages: ["[[B02_ProjRegister/B02_frontend]]", "[[B02_ProjRegister/B02_db]]", "[[B01_Dashboard/B01_backend]]", "[[B03_FileInput/B03_backend]]", "[[workflow_state]]", "[[storage_paths]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-12
---
# B02_ProjRegister — Backend
신규 임도 설계 프로젝트 생성. DB 저장 + 저장소 폴더 초기화 + 워크플로우 7단계 시드 + 감사 로그.
> ⚠️ raw structure.md에는 B02가 프론트만 있는 것으로 기재됐으나, 실 코드에 백엔드가 이미 구현됨 (2026-07-12 확인).
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `B02_ProjRegister_Router.py` | `B02_ProjRegister/B02_ProjRegister_Router.py:1-44` | 프로젝트 생성 API (prefix `/api/b02`) |
| `B02_ProjRegister_Schema.py` | `B02_ProjRegister/B02_ProjRegister_Schema.py:1-30` | 요청/응답 Pydantic 모델 2종 |
| `B02_ProjRegister_Repository.py` | `B02_ProjRegister/B02_ProjRegister_Repository.py:1-136` | Raw SQL 저장소 + 저장소 초기화 |
## API 엔드포인트
| 엔드포인트 | 위치 | 역할 |
|---|---|---|
| `POST /api/b02/project` | `B02_ProjRegister/B02_ProjRegister_Router.py:15` | 신규 프로젝트 생성. `require_company`로 회사 연결 확인 |
## 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `post_project()` | `B02_ProjRegister/B02_ProjRegister_Router.py:15` | 세션 company_id 검증 → create_project 호출, ValueError→400, 기타→500 |
| `create_project()` | `B02_ProjRegister/B02_ProjRegister_Repository.py:44` | 트랜잭션: projects INSERT + 워크플로우 시드 + 감사로그 + 저장소 초기화 |
| `get_project_by_id()` | `B02_ProjRegister/B02_ProjRegister_Repository.py:120` | 프로젝트 단건 조회(deleted_at IS NULL) |
| `_build_project_storage()` | `B02_ProjRegister/B02_ProjRegister_Repository.py:20` | 저장 경로 생성 + 저장소 루트 이탈 방지 검증 |
| `_initialize_project_storage()` | `B02_ProjRegister/B02_ProjRegister_Repository.py:29` | 단계별 폴더 생성 + workflow.json/project_manifest.json 원자적 기록 |
## 요청/응답 스키마 (Pydantic)
| 모델 | 위치 | 필드 |
|---|---|---|
| `CreateProjectRequest` | `B02_ProjRegister/B02_ProjRegister_Schema.py:6` | name(1~255), region(1~100), road_type(main/branch/fire/stream), project_year(2000~2100), estimated_length_m?(≥0), memo?(≤1000) |
| `CreateProjectResponse` | `B02_ProjRegister/B02_ProjRegister_Schema.py:17` | project_id, name, region, road_type, project_year, estimated_length_m, memo, status, storage_path, created_at |
## 생성 로직 (create_project 트랜잭션)
1. `project_id = uuid4()`, 저장 경로 생성·검증(`_build_project_storage`)
2. **트랜잭션 시작**:
- `projects` INSERT (status `'NEW'`, crs_epsg `5178` 고정)
- `initialize_project_stages(cursor, project_id)` — 워크플로우 7단계 시드 → [[workflow_state]]
- `system_audit_logs` INSERT (`PROJECT_CREATE`, resource_type `project`)
- `_initialize_project_storage()` — 저장소 폴더 + workflow.json + project_manifest.json
- commit (실패 시 rollback)
3. 생성된 프로젝트 재조회 후 반환
## DB 저장 컬럼 (projects INSERT)
`id, user_id, company_id, name, region, road_type, project_year, estimated_length_m, memo, status('NEW'), crs_epsg(5178), storage_path, created_at, updated_at`
→ 테이블 정의 → [[db_schema/projects]]
## 의존성 (공통 유틸)
- [[common_util]] — `common_util_auth`(`require_company`), `common_util_json`(`atomic_write_json`), `common_util_storage`(`PROJECT_STORAGE_LAYOUT_V2`), `common_util_workflow`(`load_project_workflow`), `common_util_workflow_state`(`initialize_project_stages`)
- 워크플로우 시드 → [[workflow_state]]
- 저장소 경로 규칙 → [[storage_paths]]
- `config_system` — `STORAGE_BASE_DIR`
- DB → [[db_schema/projects]], `system_audit_logs` → [[db_schema/logs_monitoring]]
## 참고
- 프로젝트 생성이 워크플로우 진입점: 생성 직후 프론트는 B03_FileInput으로 이동
- `workflow.json`은 저장소에 기록되나 실제 단계 판정은 `project_workflow_stages`(DB)가 SSOT → [[workflow_state]]
- 하위 컴포넌트: [[B02_ProjRegister/backend/B02_ProjRegister_Router|B02_ProjRegister_Router]]
@@ -0,0 +1,30 @@
---
status: draft
page_id: B02_ProjRegister
related_pages: ["[[B02_ProjRegister/B02_backend]]", "[[B02_ProjRegister/B02_frontend]]", "[[db_schema/projects]]", "[[workflow_state]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-12
---
# B02_ProjRegister — DB
이 페이지가 쓰는 테이블 (정의는 concepts에, 여기선 용도만).
## 쓰는 테이블
| 테이블 | 이 페이지의 용도 | 정의 |
|---|---|---|
| `projects` | 신규 프로젝트 INSERT (status `'NEW'`, crs_epsg `5178`). 단건 조회 | [[db_schema/projects]] |
| `project_workflow_stages` | 생성 시 7단계 시드(`initialize_project_stages`) | [[workflow_state]] |
| `system_audit_logs` | `PROJECT_CREATE` 행위 기록 | [[db_schema/logs_monitoring]] |
## 저장소(파일시스템)
- `storage/{company_id}/{user_id}/{project_id}/` 생성 + `workflow.json`/`project_manifest.json` 원자적 기록
- 경로 생성 책임·규칙 → [[storage_paths]]
- `PROJECT_STORAGE_LAYOUT_V2` 기준 단계별 폴더
## 참고 (계획 당시 의도)
- 계획서(plan_workflow_state_management)에는 "생성 시 project_workflow_stages 7행 시드"가 마이그레이션 Phase 1 과제로 기재됐으나,
**실 코드에 이미 구현됨**(`B02_ProjRegister_Repository.py:90` `initialize_project_stages`). → 규칙6, 실 코드 채택
- `workflow.json`도 저장소에 기록되나 단계 판정 SSOT는 `project_workflow_stages`(DB) → [[workflow_state]]
@@ -0,0 +1,83 @@
---
status: draft
page_id: B02_ProjRegister
related_pages: ["[[B02_ProjRegister/B02_backend]]", "[[B02_ProjRegister/B02_db]]", "[[ui_templates]]", "[[a00_app_shell_framework]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-12
---
# B02_ProjRegister — Frontend
신규 임도 설계 프로젝트 등록 폼. 기본정보(이름·지역·임도종류·연도·연장·메모) 입력 → 생성 후 B03으로 이동.
## 파일 구조
| 파일 | 위치 | 역할 |
|---|---|---|
| `B02_ProjRegister_UI_Page.ts` | `B02_ProjRegister/B02_ProjRegister_UI_Page.ts:1-179` | 등록 폼 렌더링 + 제출 로직 |
| `B02_ProjRegister_UI_Style.css` | `B02_ProjRegister/B02_ProjRegister_UI_Style.css:1-66` | 스타일 (theme.css 변수만 사용) |
## 컴포넌트 / 함수
| 함수 | 위치 | 역할 |
|---|---|---|
| `renderB02ProjRegister(root)` | `B02_ProjRegister/B02_ProjRegister_UI_Page.ts:35` | 헤더+카드(2열 그리드 폼) 조립 |
| `onB02_Proj_Submit_Click()` | `B02_ProjRegister/B02_ProjRegister_UI_Page.ts:96` | 제출 핸들러(검증→fetch POST→B03 이동) |
## 입력 필드
| 필드 | 컴포넌트 | 비고 |
|---|---|---|
| 프로젝트명 | createInputField | 필수 |
| 지역 | createInputField | 필수 |
| 임도 종류 | createSelectField | main/branch/fire/stream 4종 |
| 사업연도 | createInputField(number) | 기본 올해, min 2000/max 올해+5 |
| 예상 연장(m) | createInputField(number) | 선택, min 0 |
| 메모 | createInputField(text) | 선택 |
## 제출 로직
1. **1차 유효성 검사**: name/region 필수, project_year 정수·2000~2100, estimated_length_m ≥0(입력 시)
2. `fetch("${API_BASE_URL}/b02/project", POST)` 직접 호출 (별도 Api_Fetch 파일 없음)
- body: name, region, road_type, project_year, estimated_length_m, memo
3. 성공: `localStorage`에 `CURRENT_PROJECT_ID_KEY`로 project_id 저장 → 성공 토스트 → `navigateTo(ROUTES.B03_FILE_INPUT)`
4. 실패: 응답 detail/message 파싱해 에러 토스트
## 로컬라이제이션
모든 텍스트는 [[ui_templates]]에서 로드. 하드코딩 금지.
| UI 요소 | 로케일 키 |
|---|---|
| 제목/부제 | `B02_Proj_Title`, `B02_Proj_Subtitle` |
| 필드 | `B02_Proj_Field_Name`, `_Region`, `_RoadType`, `_Year`, `_Length`, `_Memo` (+각 Placeholder) |
| 임도종류 옵션 | `B02_Proj_RoadType_Main`, `_Branch`, `_Fire`, `_Stream` |
| 제출/성공 | `B02_Proj_Submit`, `B02_Proj_Success` |
| 오류 | `B02_Proj_Error_Required`, `Common_Validation_NumberRange`(공통) |
## 스타일 (CSS)
- `.b02-proj` — 페이지 래퍼 (max-width: 720px)
- `.b02-proj__header` — 제목+부제
- `.b02-proj__grid` — 2열 필드 그리드 (640px 이하 1열)
- `.b02-proj__select` — 드롭다운 화살표 여백
- `.b02-proj__submit` — 좌측 정렬 버튼
- 폼 전체는 `createCard({ raised: true })`로 감쌈
## 이벤트 핸들러
| 함수 | 위치 | 동작 |
|---|---|---|
| `onB02_Proj_Submit_Click()` | `B02_ProjRegister/B02_ProjRegister_UI_Page.ts:96` | 프로젝트 생성 검증·제출 |
## 의존성
- [[a00_app_shell_framework]] — `navigateTo()` 라우팅
- `config_frontend.ts` — `ROUTES`, `API_BASE_URL`, `CURRENT_PROJECT_ID_KEY`
- `common_util_validate` — `isBlank`
- [[ui_templates]] — `createButton`, `createInputField`, `createSelectField`, `createCard`, `showLoadingOverlay`/`hideLoadingOverlay`, `showToast`
- 백엔드 API → [[B02_ProjRegister/B02_backend]]
## 참고
- 프론트가 fetch를 직접 호출 (A08처럼 별도 API 클라이언트 파일 없음)
- 프로젝트 생성 성공 시 `CURRENT_PROJECT_ID_KEY`가 이후 워크플로우(B03~) 진입의 컨텍스트가 됨
@@ -0,0 +1,21 @@
---
type: file-backend
status: draft
related_pages: ["[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
page_id: B02_ProjRegister
source_file: "B02_ProjRegister/B02_ProjRegister_Router.py"
last_updated: 2026-07-24
---
# B02_ProjRegister_Router.py
신규 임도 설계 프로젝트 생성(`POST /api/b02/project`) 트랜잭션 라우터입니다. `projects` 레코드 INSERT, 7단계 워크플로우 상태 시드, 감사 로그 작성 및 저장소 디렉토리 생성을 트랜잭션으로 처리합니다.
## 🛠️ 주요 함수 목록
| 항목 | 위치(상대 경로) | 역할 |
|---|---|---|
| `create_project()` | `B02_ProjRegister/B02_ProjRegister_Router.py` | `POST /api/b02/project` 신규 프로젝트 생성 및 7단계 워크플로우 시드 데이터 트랜잭션 기입 |
## 🔗 연관 개념 및 의존성
- `common_util_workflow_state.py` — 7단계 시드 데이터 초기화
@@ -0,0 +1,16 @@
---
type: page-plan
status: draft
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_backend]]", "[[storage_paths]]", "[[workflow_state]]"]
last_updated: 2026-08-18
source: ["docs/raw/PLAN.md"]
---
# B03 다중 라이다 파일·대용량 처리 보류 계획
라이다 원본은 공사 면적에 따라 여러 도엽으로 나뉘지만 현재 파일 종류별 업로드 슬롯은 하나다. 확인된 운용 범위는 평상시 최대 2장·30GB 미만, 최대 3장·50GB 미만이다.
현재 결정은 구현 보류다. 드론 라이다 프로그램 전처리에서 병합 가능 여부를 먼저 확인하며, 이번 범위에서는 병합 로직과 노선 버퍼 클리핑을 구현하지 않는다. 전처리 분석은 병합된 전체 범위를 대상으로 하는 방침이다.
착수 전 완료 조건은 드론 프로그램의 병합 가능 여부 확인, 용량 대책 방식 합의, 별도 계획 수립이다.
+35
View File
@@ -0,0 +1,35 @@
---
type: page-api
status: stable
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_frontend]]", "[[B03_FileInput/B03_backend]]", "[[B03_FileInput/B03_db]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-31
source: ["docs/raw/verification/2026-07-31_verify_B03_planned_route_csv.md"]
---
# B03_FileInput — API
이 API는 [[B03_FileInput/B03_frontend]]의 업로드 요청을 [[B03_FileInput/B03_backend]]에 연결하고 [[workflow_state]]의 stage 0·1 상태를 조회·변경한다.
기본 prefix: `/api/projects` (`B03_FileInput_Router.py:66`). 세션 인증과 공통 오류 형식은 [[auth_rbac]], [[api_common]]을 참조한다.
## 일반 업로드
| 항목 | 위치 | 역할 |
|---|---|---|
| `POST /{project_id}/files` | `B03_FileInput_Router.py:267` | 계획노선 CSV (필수) / LAS / TIF / TFW / PRJ / DXF 다중 업로드·검증·메타데이터 등록 |
## 청크 업로드
| 항목 | 위치 | 역할 |
|---|---|---|
| `POST /{project_id}/upload-sessions` | `B03_FileInput_Router.py:400` | 청크 업로드 세션 생성 |
| `POST /{project_id}/chunks` | `B03_FileInput_Router.py:443` | 청크 1개 저장 및 진행률 반환 |
| `POST /{project_id}/finalize` | `B03_FileInput_Router.py:507` | 모든 청크 병합·원본 파일 등록 |
| `GET /{project_id}/upload-status/{session_id}` | `B03_FileInput_Router.py:623` | 세션 상태·완료 청크 인덱스 조회 |
## workflow 조회
| 항목 | 위치 | 역할 |
|---|---|---|
| `GET /{project_id}/workflow-state` | `B03_FileInput_Router.py:667` | `current_stage`와 7단계 상태 반환 (필수 계획노선 검증 연동) |
전체 경로는 `/api/projects/{project_id}/...`이며, workflow 상태 공통 정의는 [[workflow_state]]에 둔다.
@@ -0,0 +1,63 @@
---
type: page-backend
status: stable
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_frontend]]", "[[B03_FileInput/B03_api]]", "[[B03_FileInput/B03_db]]", "[[B03_FileInput/B03_dependencies]]", "[[las_free_sheet_surface]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-30
source: ["docs/raw/verification/2026-08-08_verify_server_and_e2e_fixes.md", "docs/raw/verification/2026-08-29_verify_B03_reupload_reanalysis_cache.md"]
---
# B03_FileInput — Backend
`las_free=true`이면 LAS 필수검사를 면제하고 stage 0 params에 저장해 [[las_free_sheet_surface|도엽등고선 서피스 체인]]으로 분기한다. 청크 세션을 포함한 LAS 업로드는 세션·API·화면에서 차단한다.
## 입력 검증·파일 처리
| 항목 | 위치 | 역할 |
|---|---|---|
| `FileUploadDescriptor` | `B03_FileInput_Schema.py` | 경로 이탈·확장자·크기 검증 및 계획노선 CSV 헤더(`route_name`, `sequence`, `x`, `y`, `z`, `crs_epsg`), 순번, 수치, 단일 EPSG 일치성 검증 |
| `resolve_upload_destination()` | `B03_FileInput_Engine.py` | 프로젝트 WF0 저장 목적지 결정 |
| `save_upload_stream()` | `B03_FileInput_Engine.py` | 일반 업로드 스트림 저장 및 계획노선 CSV 원본 보존 |
| `resolve_chunk_session_dir()` | `B03_FileInput_Engine.py` | 임시 청크 디렉터리 결정 |
| `save_upload_chunk()` / `merge_upload_chunks()` | `B03_FileInput_Engine.py` | 청크 저장·순서 병합 |
| `remove_chunk_session()` | `B03_FileInput_Engine.py` | 청크 임시 디렉터리 정리 |
| `finalize_project_upload()` | `B03_FileInput_Router.py` | finalize 시 `upload_session` 변수 분리로 404 방지 및 WF1 자동 실행 복구 |
| `_complete_file_input_if_ready()` | `B03_FileInput_Router.py:153` | 동일 파일 전송 생략을 포함한 완료 요청에서 하위 산출물·초기설계 상태를 초기화하고 WF1 예약 |
## 메타데이터 분석 및 파일 지문
| 항목 | 위치 | 역할 |
|---|---|---|
| `normalize_crs_metadata()` | `B03_FileInput_Engine_Analyze.py` | 복합 CRS 수평/수직 분리 및 규격화 (사설 수직 CRS 보존 포함) |
| `analyze_las_metadata()` | `B03_FileInput_Engine_Analyze.py` | LAS 포인트 수·범위·밀도 분석 |
| `analyze_prj_metadata()` | `B03_FileInput_Engine_Analyze.py` | PRJ CRS 분석 |
| `analyze_tfw_metadata()` | `B03_FileInput_Engine_Analyze.py` | TFW 변환계수 분석 |
| `analyze_tif_metadata()` | `B03_FileInput_Engine_Analyze.py` | TIF 래스터·CRS·범위 분석 |
| `analyze_input_metadata()` | `B03_FileInput_Engine_Analyze.py` | 확장자별 분석 라우팅 |
| `B03_FileInput_Fingerprint.ts` | `B03_FileInput_Fingerprint.ts` | SHA-256 파일 지문 기반 중복 전송 스킵 및 다른 파일 변경 시 SUPERSEDED 처리 |
## 임시 보관함 (R2 Temp Upload)
| 항목 | 위치 | 역할 |
|---|---|---|
| `B03_FileInput_Router_Temp.py` | `B03_FileInput_Router_Temp.py` | 임시 보관함 묶음/파일 CRUD, attach API (`linked` 묶음 대시보드 목록 쿼리 제외) |
| `B03_FileInput_Schema_Temp.py` | `B03_FileInput_Schema_Temp.py` | 임시 보관함 Pydantic 스키마 |
| `B03_FileInput_Repository_Temp.py` | `B03_FileInput_Repository_Temp.py` | `temp_upload_batches`, `temp_upload_files` Access |
| `cleanup_expired_temp_uploads()` | `common_util_temp_cleanup.py` | 30일 경과 만료 임시 보관 자료 자동 삭제 |
## 저장소 및 초기화
| 항목 | 위치 | 역할 |
|---|---|---|
| `create_input_file()` | `B03_FileInput_Repository.py` | `input_files` 원본 메타데이터 및 계획노선 CSV 용도 등록 |
| `get_project_storage_relative_path()` | `B03_FileInput_Repository.py` | 프로젝트 상대 저장경로 조회 |
| `create_upload_session()` / `get_upload_session()` | `B03_FileInput_Repository.py` | 청크 세션 생성·조회 |
| `upsert_upload_chunk()` / `list_completed_chunk_indexes()` | `B03_FileInput_Repository.py` | 청크 기록·완료 인덱스 조회 |
| `reset_project_subsequent_stages()` | `common_util_project_reset.py` | 자료 교체/연결 시 stage 1 이후 하위 단계 산출물 자동 초기화 |
## workflow·알림
| 항목 | 위치 | 역할 |
|---|---|---|
| `trigger_wf1_analysis_and_email()` | `B03_FileInput_Router.py` | WF1 분석 실행과 완료·실패 이메일 연결 |
| `start_stage()` | `B03_FileInput_Router.py` | WF1 시작, stage 1 IN_PROGRESS 전이 (동시 실행 가드 및 stage 3 완료 스피너 잠금) |
| `complete_stage()` | `B03_FileInput_Router.py` | WF0/WF1 완료 전이 (계획노선 CSV 필수 검증 후 전이 허용) |
| `fail_stage()` | `B03_FileInput_Router.py` | WF1 실패 전이 (`fail_stage` 메시지 200자 제한 클램프) |
| `get_project_workflow_state()` | `B03_FileInput_Router.py` | 단일 프로젝트 workflow 상태 반환 |
workflow 정의: [[workflow_state]], 저장경로: [[storage_paths]], 임시보관함: [[temp_upload]].
+29
View File
@@ -0,0 +1,29 @@
---
type: page-db
status: draft
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_backend]]", "[[B03_FileInput/B03_api]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-12
source: 상위 프로젝트 B03_FileInput_Repository.py 실 코드 직접 확인 (2026-07-12)
---
# B03_FileInput — DB 사용 관계
공유 테이블 정의는 [[db_schema/files_surface]]에서 1차 관리한다.
| 항목 | 위치 | 역할 |
|---|---|---|
| `input_files` | `B03_FileInput_Repository.py:11` | 원본 파일 유형·상대경로·크기·메타데이터 등록 |
| `upload_sessions` | `B03_FileInput_Repository.py:89` | 청크 업로드 세션과 전체 파일 정보 저장 |
| `upload_chunks` | `B03_FileInput_Repository.py:165` | 청크 인덱스·해시·크기 저장 |
| `projects` | `B03_FileInput_Router.py:111` | 업로드·WF1 진행상태 호환 캐시 갱신 |
| `project_workflow_stages` | `B03_FileInput_Router.py:175` | stage 0/1 시작·완료·실패 전이와 상태 조회 |
## 파일 경로
| 항목 | 위치 | 역할 |
|---|---|---|
| 원본 입력 | `B03_FileInput_Engine.py:15` | `B03_FileInput/input/{file_type}/`에 저장 |
| 청크 임시파일 | `B03_FileInput_Engine.py:64` | 프로젝트 저장소 하위 임시 세션 디렉터리 사용 |
| DB 저장값 | `B03_FileInput_Repository.py:64` | 프로젝트 루트 기준 상대경로 저장 |
경로 규칙 상세: [[storage_paths]].
@@ -0,0 +1,30 @@
---
type: page-dependencies
status: draft
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_frontend]]", "[[B03_FileInput/B03_backend]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-07-12
source: 상위 프로젝트 B03_FileInput import 구문 직접 확인 (2026-07-12)
---
# B03_FileInput — Dependencies
공유 의존성의 1차 정의는 [[dependencies]]에 둔다.
| 항목 | 위치 | 역할 |
|---|---|---|
| FastAPI | `B03_FileInput_Router.py:10` | multipart 파일·폼 요청과 라우터 |
| Pydantic | `B03_FileInput_Schema.py:6` | 파일명·크기·확장자·청크 요청 검증 |
| aiomysql | `B03_FileInput_Router.py:9` | MariaDB 비동기 트랜잭션 |
| laspy | `B03_FileInput_Engine_Analyze.py:7` | LAS 포인트클라우드 메타데이터 분석 |
| rasterio | `B03_FileInput_Engine_Analyze.py:9` | TIF 래스터 메타데이터 분석 |
| pyproj | `B03_FileInput_Engine_Analyze.py:10` | PRJ/TIF CRS 해석 |
| numpy | `B03_FileInput_Engine_Analyze.py:8` | LAS 통계 계산 |
## 공통 모듈
| 항목 | 위치 | 역할 |
|---|---|---|
| `common_util_storage` | `B03_FileInput_Engine.py:11` | 단계별 저장경로 생성·해석 → [[storage_paths]] |
| `common_util_workflow_state` | `B03_FileInput_Router.py:50` | stage 상태 전이 → [[workflow_state]] |
| `common_util_email` | `B03_FileInput_Email.py:8` | 업로드·분석 완료/실패 이메일 발송 |
| `common_util_json` | `B03_FileInput_Router.py:47` | workflow 보조 JSON 원자적 저장 |
@@ -0,0 +1,49 @@
---
type: page-frontend
status: stable
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_backend]]", "[[B03_FileInput/B03_api]]", "[[B03_FileInput/B03_db]]", "[[las_free_sheet_surface]]", "[[architecture/project_map]]", "[[architecture/workflow_data_flow]]"]
last_updated: 2026-08-30
source: ["docs/raw/verification/2026-07-31_verify_B03_planned_route_csv.md", "docs/raw/verification/2026-08-29_verify_B03_reupload_reanalysis_cache.md"]
---
# B03_FileInput — Frontend
`las_free` 토글은 LAS 카드와 필수검증을 비활성화하고 계획노선·도엽등고선만으로 WF1을 실행한다. 상세 계약은 [[las_free_sheet_surface]]를 따른다.
## 페이지·업로드 흐름
| 항목 | 위치 | 역할 |
|---|---|---|
| `renderB03FileInput()` | `B03_FileInput_UI_Page.ts:52` | 일반업무 레이아웃(`createGeneralLayout`) 적용 및 계획노선 CSV 선택 필수 입력 영역 조립 |
| 청크 세션 생성 | `B03_FileInput_UI_Page.ts` | 대용량 파일을 청크 업로드로 시작 |
| 청크 병합 완료 | `B03_FileInput_UI_Page.ts` | 서버 병합 결과를 상태에 저장 |
| 필수 파일 검증 | `B03_FileInput_UI_Page.ts` | 계획노선 CSV 누락/오류 시 B04 이동 버튼 차단 |
| WF1 진행률 폴링 | `B03_FileInput_UI_Page.ts` | 분석 상태와 진행률 갱신 |
| 업로드 완료 캐시 정리 | `B03_FileInput_UI_Page.ts:71` | route 최신값·section detail·preload 표식을 제거해 B05가 재분석 결과를 조회 |
| B04 이동 | `B03_FileInput_UI_Page.ts` | WF1 및 필수 계획노선 검증 완료 시 `ROUTES.B04_WF1_SURFACE`로 이동 |
## UI 지원 유틸리티 (분할 완료)
| 항목 | 위치 | 역할 |
|---|---|---|
| 카드 템플릿 및 포맷터 | `B03_FileInput_UI_Support.ts` | UI 생성 템플릿 및 파일 크기/ETA 포맷터 등 분리하여 단일 파일 700줄 제한 준수 |
## API 클라이언트
| 항목 | 위치 | 역할 |
|---|---|---|
| `uploadProjectFiles()` | `B03_FileInput_Api_Fetch.ts:60` | 계획노선 CSV 및 지형 다중 파일 업로드 |
| `createUploadSession()` | `B03_FileInput_Api_Fetch.ts:82` | 청크 세션 생성 |
| `uploadFileChunk()` | `B03_FileInput_Api_Fetch.ts:100` | 단일 청크 전송 |
| `finalizeUploadSession()` | `B03_FileInput_Api_Fetch.ts:119` | 청크 병합 요청 |
| `fetchUploadStatus()` | `B03_FileInput_Api_Fetch.ts:133` | 청크 업로드 상태 조회 |
| `checkWF1AnalysisStatus()` | `B03_FileInput_Api_Fetch.ts:154` | WF1 분석 상태 조회 |
## 브라우저 상태·오프라인 보조
| 항목 | 위치 | 역할 |
|---|---|---|
| `loadB03ProjectState()` | `B03_FileInput_State.ts:23` | 프로젝트별 저장 상태 복원 |
| `saveB03UploadedFile()` | `B03_FileInput_State.ts:34` | 업로드 파일 결과 저장 |
| `updateB03AnalysisState()` | `B03_FileInput_State.ts:53` | 분석 상태·진행률 저장 |
| `restoreB03ProjectState()` | `B03_FileInput_State.ts:71` | 재진입 시 상태와 완료 콜백 복원 |
공통 UI는 [[ui_templates]], 단계 상태는 [[workflow_state]]를 참조한다.
@@ -0,0 +1,31 @@
---
type: page-backend
status: stable
page_id: B03_FileInput
related_pages: ["[[B03_FileInput/B03_backend]]", "[[B03_FileInput/B03_frontend]]", "[[B04_PreProcess/B04_drainage_compass_crs]]", "[[completed_2026-09-03]]"]
last_updated: 2026-09-03
source: ["docs/raw/plans/2026-09-03_plan_completed_items.md"]
---
# B03 계획노선 정본·좌표계 후속
## 계획노선 정본
| 항목 | 위치 | 역할 |
|---|---|---|
| `save_initial_snapshot()` | `common_util/common_util_initial_snapshot.py` | 사업지 좌표계로 변환·트림·조밀화한 `planned_route.csv`를 초기값 정본으로 저장 |
| 스냅샷 체인 | `B03_FileInput/B03_FileInput_Service_Chain.py` | 체인에서 만든 계획노선 점을 정본 저장 창구에 전달 |
| `load_design_route()` | `common_util/common_util_route_geometry.py` | `surface_params`가 있는 설계 호출은 초기값 CSV를 우선 사용 |
| `discard_initial_snapshot()` | `common_util/common_util_initial_snapshot.py` | 지표면·노선 변경 시 CSV를 포함한 초기 스냅샷 폐기 |
프론트엔드는 업로드한 원본 파일명을 표시하고, 백엔드는 변환 CSV를 계산 정본으로 사용한다. 트림 전 범위가 필요한 호출은 원본 경로를 유지한다.
## LAS 없는 설계와 업로드 상태
| 항목 | 위치 | 역할 |
|---|---|---|
| `run_sheet_surface_analysis()` | `B04_PreProcess/B04_PreProcess_Engine_SheetSurface.py` | 공통 계획노선 로더와 지형 PRJ 좌표계로 도엽 서피스 생성 |
| `download_geodata()` | `B04_PreProcess/` | 노선 PRJ가 아닌 지형 PRJ 폴더에서 도엽 좌표계 탐색 |
| `lasFreeCheck` change | `B03_FileInput/B03_FileInput_UI_Page.ts` | 토글 직후 필수 슬롯과 업로드 버튼 활성 상태 재평가 |
검증 자료에서는 변환 정본 643점, 최대 좌표차 0.00007m, 연장 2136.2m가 원본 처리 결과와 일치했고 LAS 없는 자동 체인이 완료됐다.

Some files were not shown because too many files have changed in this diff Show More