docs(master_data): 관리자 화면 계약 — M01 API 길·응답 모양

읽기(그룹·파일·줄·표·로직) · 시험 계산 · 저장(409·422) 약속

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
This commit is contained in:
2026-09-19 18:11:40 +09:00
co-authored by Claude Opus 5
parent 8946cadb58
commit 6b34f5d7d3
+59
View File
@@ -0,0 +1,59 @@
# 관리자 화면 계약 (M01)
`resources/master_data/` 첫 층 JSON 을 보고 고치는 화면과 서버(`M01_MasterData/`) 사이의 약속. 파일 모양은 `_틀.md`.
## 1. 공통
- 길 머리 `/api/m01` · 시스템 관리자만(아니면 403).
- 봉투 칸 이름은 영문 · 줄·표·로직 알맹이는 파일 그대로(한글 칸).
- 수는 JSON 수로 옴.
- `version` = 파일 판본(내용 해시). 읽을 때 받아 두고 저장 때 그대로 돌려줌.
- `file` = 파일 이름(`소요량_건설품셈_기계설비7장.json`). 밑줄 파일·하위 폴더는 없음.
- 없는 파일·열쇠 = 404 · 틀린 요청 = 400.
## 2. 읽기
| 길 | 받음 | 줌 |
|---|---|---|
| `GET /groups` | | `{groups: [{group, files, rows}]}` — 그룹 차례는 `_틀.md` 2장 |
| `GET /groups/{group}/files` | | `{files: [{file, book, chapter, edition, rows, version}]}` |
| `GET /rows` | `file` · `page`(1) · `size`(50) · `q` | `{file, version, total, page, size, rows: [줄…]}` |
| `GET /tables` | `file` · `q` | `{file, version, tables: [{열쇠, 이름, 기준, 출처, 조건, 값칸, count}]}` |
| `GET /table` | `file` · `key` | `{file, version, table: {표 하나 통째}}` |
| `GET /logics` | `book` · `chapter` · `q` · `blocked`(0/1) | `{logics: [{file, book, chapter, 열쇠, 이름, 결과단위, 출처, blocked, reasons}]}` |
| `GET /logic` | `book` · `key` | `{file, version, logic: {로직 한 줄 통째}, blocked, reasons}` |
- `rows` 는 요소·로직 파일은 `줄`, 표형 파일(소요량·계수)은 `표` 를 줄로 봄.
- `q` = 이름 찾기 — `열쇠`·`이름` 에 든 글(대소문자 무시).
- `chapter` = 파일 이름의 장(`13장` · `01장`) · 없으면 "".
- `blocked` = 로직 검사(`check_master.py 로직`)에 걸림 · `reasons` = 걸린 까닭 글.
## 3. 시험 계산
`POST /calc` 받음 `{book, key, inputs: {이름: 값}}`
- 됨 — `{ok: true, lines: [{이름, 단위, 수량, 단가, 금액, 비목: {비목: 금액}}], sums: {노무비, 재료비, 경비, 계}, middle: {이름: 값}}`
- 돈 아닌 로직 — `{ok: true, result, middle}`
- 멈춤 — `{ok: false, reason}` (200). 까닭 = 엔진 글 그대로(「입력 「돌」 없음」 · 「값 없음 — 관리자가 채울 값」 …).
- 계산은 저장된 파일로만 — 화면 캐시의 고친 값은 [저장] 뒤에 반영.
## 4. 저장
`POST /save` 받음 `{files: [{file, version, changes: [{op, key, row}]}]}`
- `op``edit`(열쇠 `key` 줄을 `row` 로 바꿈) · `add`(`row` 더함 · `key` 안 씀) · `delete`(`key` 줄 지움).
- 요소 파일 = `줄` 한 줄 · 표형 파일 = `표` 하나 · 로직 파일 = 로직 한 줄. `row` 는 통째(칸 일부만 보내지 않음).
- 화면은 조작을 캐시에 쌓고 [저장] 한 번에 보냄 — 서버는 이때만 파일에 씀.
- 순서: 모든 `version` 대조 → 모두 적용(메모리) → 검사 → 모두 씀. 하나라도 걸리면 아무것도 안 씀.
| 답 | 뜻 | 몸 |
|---|---|---|
| 200 | 씀 | `{files: [{file, version}]}` — 새 판본 |
| 409 | 낡은 화면 — 그 사이 파일이 바뀜 | `{detail: {stale: [file…]}}` → 다시 읽고 다시 고침 |
| 422 | 검사 걸림 | `{detail: {errors: [글…]}}` |
| 404 | 없는 파일·열쇠 | `{detail}` |
| 400 | 틀린 `op` · 더할 열쇠가 이미 있음 · 고친 줄의 열쇠가 딴 줄과 겹침 | `{detail}` |
- 검사 = `check_master.py` 의 틀(고친 파일) + 로직 변수(모든 로직 파일, 고친 뒤 마스터 기준). **고친 뒤 새로 생긴 걸림**만 막음 — 원래 있던 걸림은 막지 않음.
- 요소를 지워 어떤 로직이 가리키던 것이 사라지면 로직 변수 검사에 걸림(422).
- 쓰기는 UTF-8 · LF · 들여쓰기 2칸.