devplan — 작업 규칙 (rules)
상태·이력은
handoff.md, 규칙은 이 파일. 새 규칙이 생기면 그 답변에서 바로 🆕 신규에 1줄 append하고, 안정화되면 확립 규칙의 해당 §로 원문 이관한다.
📑 인덱스
- 🆕 신규 (최근 확립)
- §1 테마 — 테라코타 웜톤이 기본
- §2 페이지 등록·생성
- §3 서버·API
🆕 신규
- 2026-08-17 [페페→코디] 페페가 고치는 설정은 자유 텍스트로 두지 말고 「선택 메뉴 → 코디가 반영」으로 만든다. 페페 지시 = "텍스트 수정으로 내가 하면 실수할 수 있으니 조정 사항을 선택할 수 있는 메뉴옵션으로 정리해라. 지정하면 코디가 읽고 반영한다." 구현 =
tools_state.py의SKILL_OPTIONS(노브·선택지·설명이 한 곳) → 페이지가 라디오로 그리고 → 「저장 및 반영」이 헤드리스claude -p를 띄워 SKILL.md 본문을 그 뜻대로 다시 쓴다. ⚠페이지가 문장을 조립하지 않는 게 핵심 — 템플릿 조립이면 「결과 기록 = handoff.md에 남겨라」처럼 본문 밖 행동이 표현이 안 되고 문장이 템플릿티를 낸다. 실측 13.6초/17.0초, 기존 영어 문체 유지하며 필요한 문장만 추가·교체했다. - 2026-08-17 [코디] devplan에서 헤드리스 claude 를 쓸 땐
cwd를%TEMP%로 빼고 훅·MCP·Skill 을 다 끈다.cwd가C:\dev안이면C:\dev\CLAUDE.md가 딸려와 산출물에 답변 꼬리표가 붙는다(26.8.14 실측, 고객 게시글까지 나갔던 그 사고). 추가로--disallowedTools Skill이 없으면 상시작동된grilling이 헤드리스 안에서 자기를 발동해 질문만 하다 끝날 수 있다(스킬을 고치러 간 런이 스킬에 걸리는 자기참조). 세트 =--settings '{"hooks":{}}'·--strict-mcp-config --mcp-config empty_mcp.json·--disallowedTools Skill Task WebSearch WebFetch·--permission-mode bypassPermissions. 선례 =tools_state.reflect(). - 2026-08-17 [코디] 메뉴 되돌리기는 「문장 삭제」가 아니라 「반대 문장 추가」로 나온다 — 본문이 계속 자란다. 「질문 총량 = 최대 5개」를 넣었다가 「제한 없음」으로 되돌리면 그 줄이 지워지는 게 아니라
Do not cap the number of questions…로 교체된다(실측). 의미는 맞지만 반영을 반복하면 본문이 길어진다 → 가끔 ⚙ 직접 편집으로 정리하면 된다. 되돌릴 원본은_tools_backup/<타임스탬프>-reflect/에 매번 남는다. - 2026-08-17 [코디]
.det input{width:100%}같은 포괄 규칙에 라디오·체크박스가 걸리면 컨트롤이 엉뚱한 데로 밀린다. 옵션 메뉴 첫 렌더에서 라디오가 라벨과 멀찍이 떨어져 찍혔다(육안으로만 잡힌다 — 폰트·테마 게이트는 둘 다 PASS였다). 수정 =input:not([type=radio])로 좁히고.opt를 flex 로. 폼 컨트롤에 폭을 줄 땐 타입을 배제해라. - 2026-08-16 [코디] 사이드바 NAV에 항목을 추가하면
apply_shell.py --renav까지가 한 작업. NAV 단일 출처는apply_shell.py의NAV리스트지만, 쉘은 각 페이지에 박제돼 있어 이미 적용된 35개 페이지는 자동으로 안 바뀐다. 게다가 재적용은hub-shell-v1표식이 막아서(:149)--all로 다시 돌려도 소용없다 → 이번에 사이드바<ul class="nav flex-column pb-3">블록만 갈아끼우는--renav모드를 신설했다(build_hub.py의 하드코딩 사이드바도 같이 고쳐야 허브 메인이 안 어긋난다 — 둘은 별개 사본이다). - 2026-08-16 [코디] 리포·도구 목록의 원천 =
devplan/tools_catalog.json하나. catalog.html에 다시 하드코딩 금지. 원래 42항목이catalog.html안 JS 배열로 박혀 있었는데tools.html이 같은 목록을 쓰게 되면서 분리했다. 양쪽 다 fetch로 읽는다. ⚠분리 스크립트를 다시 쓸 일이 있으면 문자열 안을 건드리지 않는 파서를 써라 — 무따옴표 키에 따옴표 붙이는 단순 정규식은desc:"…사이트, http://100.108.234.45:8799)"의, http:를 키로 오인해 조용히 깨뜨린다(실제로 1회 터졌다). - 2026-08-16 [코디]
app.py가 쓰는 파이썬은 3.9다 — devplan에 새로 만든 모듈은 3.9에서도 돌려보고 넘긴다. 상주 프로세스가Python39\pythonw.exe라 3.12 문법(X | Y타입·str.removeprefix등)을 쓰면 개발 셸에선 통과하고 서버에서만 500이 난다.tools_state.py --selftest를 3.12·3.9 양쪽으로 돌려 확인했다. - 2026-08-08 [코디] 「글자 13px 미만 금지」의 사각지대 = qahelper 위젯 자체(공용, 12px 5요소).
check_font.py는 정적 검사라assets/qahelper.js가 런타임에 주입하는 스타일을 못 본다 → 실브라우저로 재면 어느 페이지에서든.qa-h-status-text·.qa-h-copy·.qa-h-export·.qa-h-reset·.qa-h-count가 12px로 잡힌다(대조군callbot.html에서 동일 5곳 재현 = 페이지 탓 아님). ⚠실브라우저 글자 검사에서[class*="qa-h"]를 제외하지 않으면 신규 페이지가 남의 위젯 때문에 FAIL로 오진된다(오늘 실제로 오진 1회). 위젯 자체 상향은 별건 — 지시 없이 손대지 않음. 검사 선례 =devplan/_verify_safety_page.py. - 2026-08-04 [페페] GPT가 쓰는 페이지는 「앵커만 HTML, 내용은 JSON」으로 짠다 — 페페 지시: "나는 HTML 직접 안 건드린다. GPT가 내용·수정위치 정리→코디 지시문→코디가 수정. 상의하는 동안 실시간으로 HTML에 반영돼야 한다." → 페이지엔 구역 앵커
id만 박고(ai-stack-map.html=s0~s8), 내용은<페이지>-notes.json에 두고 JS가 10초 폴링해 렌더한다. 🔑정적 JSON fetch라 8799 재시작이 필요 없다(app.py 라우트 추가는 상승권한이라 코디가 못 한다 — design-refscatalog.json선례). 실측 = 새로고침 없이 1.2초 반영. 메모를 HTML에 하드코딩하면 코디 반영이 매번 HTML 편집이 돼서 이 구조가 성립 안 한다. 남이 쓴 텍스트는textContent로만 넣는다(innerHTML = XSS + 재빌드 스파이크). 기본 접힘/펼침은 내용 있는 구역만 펼침(빈 구역 9개가 안내문으로 도배된다). → §2 - 2026-08-04 [코디] 🔁재발 —
python -c "…"안의 백틱은 조용히 증발한다(CLAUDE.md 절대규칙 6에 이미 있는데 또 걸렸다). HANDOFF에 긴 항목을 넣으려고python -c로 문자열 치환을 했더니 bash가 백틱을 명령치환으로 먹어`plan_read`등 7곳이 통째로 빈 문자열이 됐다(**`만 남았다). 파일 쓰기는 성공하고 글자수도 정상이라 **에러 없이 조용히 망가진다**. → **.md` 편집은 반드시 Edit 도구로. 스크립트로 해야 하면 백틱 없는 텍스트만. 검증도 "썼다"가 아니라 grep으로 백틱 토큰이 실제로 있는지 확인한다. → §2 - 2026-08-04 [코디] HTML을 LLM에게 텍스트로 줄 땐 「표 보존 + 태그 사이 공백」 둘이 함정이다 —
plan_read(gateway) 구현 중 실측. ①표를 그냥 이어붙이면 12층 매트릭스가 뭉개져 페페가 보는 위치와 안 맞는다 → 마크다운 표로 변환해야 한다. ②HTMLParser.handle_data에서 공백만 있는 데이터를 버리면● 있음watcher.py:258처럼 붙어버린다(소스엔 공백이 있는데 죽는다) — 공백 노드는 1칸으로 살린다. ③표 셀 안에서는 목적지가_cell인데_buf를 검사하는 실수를 하기 쉽다. ④쉘(hub-side·offcanvas)·<script>는 화면에 안 보이므로 반드시 제외. 검증은 "핵심 문구 유실 0 + 표 헤더 존재 + 구역 순서 일치"를 assert로 박는다. → §2 - 2026-08-04 [코디]
apply_shell.py는 head 링크를 중복 삽입한다 — 신규 페이지엔 링크를 미리 넣지 말거나, 적용 후 중복을 지워라(실측,ai-stack-map.html생성 중 발견). CLAUDE.md는 "새 페이지는<head>에 링크 4개를 순서대로 넣어라"라고 하고,apply_shell.py는<head>직후에HEAD_LINKS를 무조건 삽입한다(apply_shell.py:157). 재적용 방지 표식은<body>의hub-shell-v1만 보므로(:149) 링크 단위 중복 검사가 없다 → 규칙대로 만든 새 페이지에 쉘을 씌우면 링크가 두 벌이 되고, 두 번째 벌엔theme.css가 없어 부트스트랩이theme.css뒤에 실려--bs-*테라코타 브리지가 파랑에 진다(= CLAUDE.md가 경고한 바로 그 순서 사고). ⚠check_theme.py도check_font.py도 이걸 못 잡는다(둘 다 PASS했다) — 링크 순서는 어느 게이트도 안 본다. 조치 = 적용 후grep -n 'rel="stylesheet"'로 4줄·부트스트랩→아이콘→theme→shell 순인지 눈으로 확인. → §2 - 2026-08-04 [코디] 빌드 게이트 강제 수준이 게이트마다 다르다 —
check_font.py는build_hub.py --selftest에 import돼 FAIL로 빌드를 막지만(build_hub.py:85),check_theme.py는 안 물려 있다(CLAUDE.md에 "돌려라"고만 적힘) = 폰트는 강제, 테마는 수동 권고.check_font와 같은 패턴 한 줄이면 맞춰진다(미조치, 저긴급). → §2 - 2026-08-04 [코디] 새 카드의 상태층 항목은 CLI로 못 만든다 —
project_state.py set은 없는 프로젝트면[FAIL] 없는 프로젝트로 죽는다(추가 서브커맨드 없음). 신규 카드는project_state.json에 빈 스켈레톤을 먼저 넣고(기존 항목의 키를 그대로 복제, 값 null) 그 다음set/report로 채운다. 안 그러면build_hub.py가 카드↔상태 1:1 FAIL로 멈춘다. → §2 - 2026-08-04 [코디] 2단 레이아웃 페이지는
body의 레이아웃을.hub-main으로 이관해야 한다(페페 신고 "furniture-learn 자가학습 검토가 안 보인다"로 발견). 원인 = 그 페이지들은body{display:flex;height:100%}로 좌(목차)·우(본문)를 나눴는데, 쉘이 내용을.hub-main안으로 넣고html > body{display:block}으로 body를 무력화하니 좌우가 위아래로 쌓여 본문이 화면 밖으로 내려갔다(목차만 보임). 해결 =apply_shell.py --fixbody— body 규칙에서 레이아웃 속성만(display/flex-/height/overflow/width/gap/align-/grid-) 떼어.hub-main으로 옮기고 배경·색·폰트는 body에 남긴다.height:100%는.hub-main부모가 auto라 안 먹으므로calc(100vh - 48px)*(navbar 높이)로 치환. 해당 = ai-study-vibecoding·furniture-{expert,gpt-bridge,learn}·background-ops 5개. 신규 적용에도 자동 포함(transform ⑤단계). → §1 - 2026-08-04 [코디] 검증 판정이 느슨하면 깨진 페이지를 통과시킨다 — 위 사고 때 전수검증은 "본문 텍스트 300자 이상"만 봐서 목차만 보이는 페이지를 PASS로 찍었다(실제 1263자). 레이아웃 검증은 첫 화면(뷰포트)에 실제로 보이는 텍스트 양과
.hub-main직계 블록의 y좌표 분포까지 본다. 화면을 재는 판정은 "존재하는가"가 아니라 "보이는가"여야 한다. → §1 - 2026-08-04 [페페] 전 페이지 공용 쉘 =
assets/shell.css+apply_shell.py(2단계 지시 "전체 페이지 수정 진행해", 방식은 페페 택1 = 연결된 페이지만 정적 변환). 대상 = 허브·사이드바·카드 url·admin_url로 실제 열리는 30페이지(미연결 28개 목업·구버전은 손대지 않는다). 변환 =PYTHONUTF8=1 python apply_shell.py --all(원본은_trash/devplan-preshell-YYYYMMDD/백업,hub-shell-v1표식으로 재적용 방지). 넣는 것 = ①head 링크 4개(부트스트랩→아이콘→theme.css→shell.css 순서 강제) ②navbar+사이드바+.hub-main래핑 ③bootstrap.bundle.min.js④13px 미만 글자 상향. 페이지 고유 콘텐츠·JS·자체 헤더는 안 건드린다(본문 안으로 들어갈 뿐). 허브index.html도 같은 shell.css를 링크한다(중복 CSS 32줄 제거 = 쉘 규칙 단일 출처). 새 페이지도 이 순서·클래스를 그대로 쓴다. → §1 - 2026-08-04 [코디] 남의 페이지에 쉘을 씌울 때 터진 함정 4개(전부 실측) — ①
body{display:flex}·max-width·padding이 쉘을 부순다(본문이 412px 밀리거나 폭이 잘림). 내용은 이미.hub-main안으로 옮겨졌으니html > body{display:block;margin:0;padding:0;max-width:none}로 무력화(특정도 0,0,2로 페이지body{}0,0,1을 이긴다 —!important불필요). ②<body>도<head>도 없는 페이지가 있다(암묵 태그) → 본문 시작점을</style>→</title>순으로 폴백. ③글자 상향은<style>만 훑으면 놓친다 — 인라인style=·JS 템플릿 문자열·em/%(code{.85em}=11.9px)까지 문서 전체를 훑어야 한다(em/%는 본문 14px 기준 환산). ④브라우저 캐시가 검증을 거짓으로 만든다 — 파일을 고쳤는데 옛 화면을 재서 "쉘이 안 붙었다"고 3번 오판했다. 검증은?cb=<시각>+ CSS에cache-control:no-cache라우트로 돌린다. → §1 - 2026-08-04 [페페] 순번·짧은 라벨은 줄바꿈 금지 / 굵은 글씨 남발 금지 / N 배지 얇게 — ①4자 이하 라벨(회차·배지·트랙·단계)은
white-space:nowrap+ 열에min-width를 줘서 접히지 않게 공간을 확보한다(진행판은min-width:1090px, 레일 옆에선 계속 접혀 전폭으로 내림). ②굵기는 카드 제목·브랜드만 700, 프로젝트명 600, 나머지 500~600(적용 후 화면 전체 bold 요소 8개). ③N(신규) 배지는 800→500. → §1 - 2026-08-03 [페페] 화면 글자는 13px 미만 금지(전 페이지 기준) — "나는 폰트크기 13 이상을 원한다. 그 미만은 글씨가 작아서 읽기 불편하다". 기계 게이트 =
devplan/check_font.py(font-size전량 px 환산, rem×16, 13px 미만이면 FAIL /--selftest7항목),build_hub.py --selftest에 물려 있다(11항목). ⚠부트스트랩.badge(.75em)·small(.875em)·code(.875em)는 상대단위라 부모가 작으면 같이 작아진다 → 페이지에 바닥 규칙 3줄(.badge/small,.small/code,kbd= 13px)을 깔고, 게이트도 그 3줄 존재를 확인한다. 정적 검사로는 em 체인을 못 푸니 브라우저 computed 값으로도 확인(직접 텍스트를 가진 전 요소 순회 → 13px 미만 0). 허브 적용 결과 = 본문 14 / 표 셀 14 · 헤더·배지·날짜 13 / 카드헤더 15 / 사이드바 14(행 높이 25→35px는 가독성 대가로 수용). → §1 - 2026-08-03 [페페] 표 안 아이콘 버튼은 테두리 없이 크게 — "바로가기 버튼이 너무 작다. 아이콘 테두리는 삭제해라. 그것만 해도 아이콘 자체 크기가 커진다". 테두리·배경 제거 + 글리프 19px·클릭영역 26×26. ⚠flex 자식은
flex:none을 안 주면 열이 좁을 때 쪼그라든다(실측 26→19px — 크게 만들었는데 화면에선 안 커 보였다) → 아이콘 컨테이너 폭(colgroup)도 같이 넓힌다(66→100px). → §1 - 2026-08-03 [페페] 사이드바는 폭 고정 170px · 안내문구 금지 · 목록 행에 바로가기 아이콘(부트스트랩 전환 직후 지시 "가로폭 줄여라, 공간낭비.
등록·수정 = projects.json → build_hub.py문구는 페이지에 필요 없다. 절약한 공간으로 프로젝트별 기획·관리 페이지 아이콘을 바로 클릭하게"). ①사이드바 =col-lg-2(1680px에서 277px) → flex 고정 170px(화면이 넓어져도 사이드바는 그대로, 본문이 +107px). navbar 브랜드도 같은 170px로 맞춘다. ②빌드·운영 방법 안내는 페이지에 쓰지 않는다(그건 rules/CLAUDE.md 몫). ③목록 표에 바로가기 열 신설 = 기획📋(projects.json의url) · 관리⚙(project_state.json의admin_url) · 사이트🔗(site, 새 탭), 없는 것도 흐린 아이콘으로 자리 유지(열이 안 흔들린다), 행 클릭(모달)과 분리(stopPropagation). 진행판의 📋⚙와 같은 의미·같은 출처다. → §1 - 2026-08-03 [코디] 부트스트랩
.row안에서 폭 고정 사이드바를 만들 땐 본문flex-basis:0(flex:1 1 0) —auto로 두면 콘텐츠 폭이 기준이 돼 남은 공간을 넘고, flex는 줄이기 전에 줄바꿈부터 한다 → 본문이 사이드바 아래로 통째로 내려간다(실측: main.y=1050). 눈으로는 스크롤해야 보이는 사고라 위치를 좌표로 확인한다(getBoundingClientRect().y가 사이드바와 같은 줄인지). 겸사겸사.row > *의width:100%도width:auto로 덮어야 한다(같은 특정도 → 우리<style>이 뒤에 와야 이긴다). → §1 - 2026-08-03 [페페] devplan UI = 부트스트랩으로 전격 전환, 색은 테라코타 유지 — 지시 "다운받은 bootstrap ui를 사용, 먼저 메인페이지만. 확인 후 나머지 연결 페이지 전부. 색상은 현재 테라코타 유지". 껍데기 = 공식 dashboard 예제(상단 고정 navbar + 좌측 사이드바
offcanvas-md+ 본문, 페페 택1). CSS/JS는 design-refs 게시본을 링크한다 —/design-refs/bootstrap-5.3.8/dist/css/bootstrap.min.css·/dist/js/bootstrap.bundle.min.js· 아이콘/design-refs/bootstrap-icons-1.13.1/bootstrap-icons.min.css(devplan 안에 사본 만들지 말 것. 경로 상수는build_hub.py의BS/BI한 곳). 색은assets/theme.css가 부트스트랩 변수(--bs-primary·--bs-body-bg·--bs-link-color·.btn-primary등)를 테라코타로 덮는다 → 링크 순서 부트스트랩 → theme.css → 페이지<style>(순서 틀리면 파랑이 이긴다). 페이지에서 색 hex를 새로 박지 말고var(--accent)계열만 쓴다. 나머지 페이지 전환은 페페 확인 후. → §1 - 2026-08-03 [코디] 부트스트랩 페이지의 3대 함정(전부 실측으로 태움) — ①부트스트랩 여백 유틸(
px-*·m-*)은!important라 내 CSS로 못 이긴다 → 여백을 CSS로 잡을 자리엔 그 클래스를 아예 붙이지 않는다. ②우상단 88px(top14·right29·42×42·z=99998)은 qahelper 토글이 덮는다 → 그 자리에 조작 요소를 두면 "보이는데 클릭이 안 먹는다"(navbar 검색 지우기·모바일 햄버거·offcanvas 닫기 X가 실제로 다 막혔다). 대응 = 검색줄padding-right:5.5rem· 햄버거는 왼쪽 · offcanvas 닫기me-5. ③offcanvas-md는 md 이상에서background:transparent !important→ 사이드바 배경색은 바깥 col에 준다(부트스트랩 dashboard 예제가 두 군데 다 배경 클래스를 주는 이유). 목록 표는table-layout:fixed(.hub-list) 없으면 colgroup 고정폭이 무시돼 가로스크롤이 생긴다. → §1 - 2026-08-03 [코디] 테마 게이트는 벤더 CSS를 판정하지 않는다(
check_theme.py) — 링크된 CSS 중theme.css·/design-refs/·bootstrap(정규식VENDOR)은 스캔에서 제외. 부트스트랩엔.bg-dark같은 유틸 색이 당연히 들어있고 우리가 그 클래스를 안 쓰면 화면에 안 나온다 — 테라코타 유지 책임은theme.css의--bs-*브리지가 지고, 게이트는 페이지가 직접 쓴 색만 본다. 자체검사에 케이스 추가(--selftest9항목). → §1 - 2026-08-03 [페페] 허브 메인 = 진행판(단계 게이지+회차 배지) — v4 목업 채택안을 build_hub.py 템플릿에 반영. 분야별 카드 그리드는 진행판으로 교체(최근 보드·고정·사이드바·모달은 유지), 다른 페이지는 유지(UI 전면 개편은 추후 선택 후). 데이터 =
devplan/project_state.json단일 출처(범위×차수·단계·회차·이번 회차 기준·다음 액션+주체·결재선·최근 진행·보류·last_progress·admin_url), 갱신 =project_state.pyCLI(보류=사유+재개조건 필수·회차+1=--why필수·단계전환=last_progress 자동 — 완료 목표 운영규칙을 코드로 강제). 빌드 게이트: 카드↔상태 1:1 아니면, dev_track 미분류면, 재개조건 없는 보류면build_hub.py가 FAIL → 카드 추가 = 상태 등록까지가 한 작업. 순위 고정 규칙 =devplan/priority_rules.md(사람 편집). 티어 유도 = hold→보류 / stage5→완료·유지 / stage≤2→계획·대기 / 나머지→실행중. 시간 신호 =last_progress무전환 8일↑ "정체 N일"(D-day 아님·퍼센트 금지). 건수·합계 전부 자동 계산. 초기 36건 = 서브에이전트 4개가 BRIEF·handoff 실독 초안(evidence 인용) → 코디 검수 교정 12건. - 2026-07-31 테라코타 웜톤 = devplan 전 페이지·전 생성기의 기본 테마(페페 지시). 정본 토큰 단일 출처 =
C:\dev\devplan\assets\theme.css, 기계 판정 게이트 =check_theme.py(FAIL 0). 새 페이지·자동생성 산출물은<head>에<link rel="stylesheet" href="/assets/theme.css">를 넣고 색은 그 변수로 쓴다. 다크 스킴(--bg-base:#0F1117계열·mockup-common.css)을 새로 복사해 오지 말 것. → §1 - 2026-08-03 [코디] 8799 서버는 코디가 재시작할 수 없고 정션을 못 넘는다 — 실행 중인
app.py프로세스가 상승권한이라 같은 계정인데도taskkill이 "액세스 거부"(예약작업devplan-dashboard는 delix·Limited인데 실행본은 별개). ⇒app.py를 고쳐도 즉시 반영되지 않는다(재시작 필요한 변경은 다음 부팅이나 페페 몫). 또 그 프로세스는 정션(mklink /J)을 못 넘어간다(실측: 같은 깊이 실디렉터리 200 / 정션 404, 새로 띄운 py3.12 http.server는 같은 정션 200) → devplan 밖 폴더를 정션으로 붙이지 마라. 게시(복사)로 붙인다(선례 =design-refs/publish_devplan.py). →projects/design-refs/rules.md§3 - ~~2026-08-03 [코디] devplan 페이지에 외부 CSS 프레임워크(부트스트랩 등)를 링크하지 않는다~~ ⚠같은 날 페페 지시로 폐기 — 이제 부트스트랩을 링크한다(위 전환 규칙). 당시 근거였던 "팔레트가 덮어써 FAIL"은 ①
theme.css의--bs-*브리지 ②게이트의 벤더 제외로 해소됐다. 아래는 폐기 전 원문: 테라코타 웜톤을 그쪽 팔레트가 덮어써check_theme.py가 FAIL한다. 남의 UI를 보여줘야 하면 iframe으로 격리한다(아이콘 웹폰트 CSS처럼 색 선언이 없는 것만 예외, FAIL 0 실측). 선례 =design-refs.html. - 2026-08-03 [코디] 서브에이전트 목업 조각을 한 페이지로 조립할 땐 4가지를 기계 검사한다 — 조각(
<section class="mk mk-{id}">)마다 ①CSS 선택자 전량이.mk-{id}접두인지 정규식 검사(체인 선택자 중간이 전역으로 새는 사고가 실제로 20개 발생) ②조각 내<script>0 ③<html>/<head>/<body>없음(⚠<header>는 정상 요소 —<head[\s>]로 매칭해야 오탐이 안 난다) ④id가mk-{id}-접두. 페이지 단위로는 CSS-only 탭 배선(라디오 n ↔.panel-(n-1), 기본 선택 정확히 1개) +check_theme.pyFAIL 0 + 외부 리소스 0 +build_hub.py --selftest. 검사기 =PYTHONUTF8=1 python check_mockup.py <파일>(devplan 루트, RESULT PASS여야 함). 목업 라운드마다 조립 스크립트는 직전 판을 복사해 고치고, 직전 페이지는_trash/devplan-mockup-v{N}-superseded-YYYYMMDD/에 보존한 뒤 같은 파일명을 덮어쓴다. - 2026-07-31 허브 우측 사이드바 데이터는
activity.py+/api/activity(정적 빌드에 박지 않는다). 상단=최근 작업(user_brief 세션문서), 하단=프로젝트 미생성 세션(세션문서 + 클로드코드 대화로그). 판정 기준 =projects.json허브 카드 유무. → §3
§1 테마 — 테라코타 웜톤이 기본 (2026-07-31 확립)
- 정본 토큰 =
assets/theme.css(=index.html/build_hub.py값과 동일). 바꿀 일이 생기면 이 파일만 고친다.--bg:#f6f3ee --bg-soft:#faf7f2 --bg-panel:#fff --bg-sidebar:#efe9e1 / --ink:#2b2622 --text:#24211c --text-dim:#7d7267 / --accent:#c97c4a --accent-hover:#b86a39 --accent-soft:#f3e3d5 --accent-deep:#8a5a3c / --line:#e6ddd2 / --live:#4c8c5a --cand:#8a6fb0 --hold:#9a8f82 --warn:#b3541e --err:#a8443a - 페이지가 자체
:root를 두면 그게 이긴다 → theme.css 링크는 자체<style>앞에 둔다(순서가 규칙). - 검사 =
PYTHONUTF8=1 python check_theme.py [파일…]. 판정 로직 = 색 선언 휘도. 어두운 배경(luma<.35) / 차가운 밝은 글자(#67E8F9·#CBD5E1 류) /mockup-common.css링크 = 잔재. 3곳 이상 FAIL, 1~2곳 WARN(의도된 툴팁·강조는 WARN으로 남겨도 된다). 자체검사--selftest. - 다크모드 토글이 있는 페이지는 예외(
site-analytics.html=@media(prefers-color-scheme:dark)·[data-theme=dark]블록). 그건 기능이지 잔재가 아니다 → 라이트 블록만 웜톤으로 맞추고 다크 블록은 그대로 둔다. - ⚠적록색약:
--live(초록)↔--accent(테라코타)는 protan에서 거의 같게 보인다 → 상태 구분은 아이콘+라벨 병기, 색만으로 구분 금지. - 흰 글자(
#fff)는 테라코타·컬러 배경 위에서만. 밝은 배경 위 글자는 항상 어두운 색.
§2 페이지 등록·생성
- 새 페이지 = 만들면 허브 카드 등록까지가 한 작업:
projects.json항목 추가 →PYTHONUTF8=1 python build_hub.py.index.html직접 편집 금지(빌드 산출물). - 모든 페이지
</body>직전<script src="/assets/qahelper.js"></script>필수. - HTML을 만드는 생성기 3개 =
build_hub.py(index.html) ·build_dashboard.py(dashboard-review.html, 재실행 금지) ·C:\dev\tools\coupang-spend\coupang_spend.py(coupang-spend.html). 생성기 템플릿도 테라코타 기본을 지켜야 한다 (색을 고칠 땐 산출 HTML만 고치지 말고 템플릿을 같이 고친다 — 안 그러면 다음 재생성 때 되돌아간다). devplan/rollcalc/는 별도 미니앱(공개 사이트 시안)이라 devplan 테마 대상이 아니다.
§3 서버·API
- 서버 =
app.py(8799,pythonw, 시작프로그램devplan-dashboard.vbs). API 추가·수정 후 재시작 필요 (taskkill 후wscript devplan-dashboard.vbs— 세션1·일반권한이라 UAC 불필요). - API =
/api/decisions/api/comments/api/learn/api/kb/api/favs/api/kakao/*/api/activity. /api/activity= 허브 우측 사이드바(activity.py, 120초 캐시). 원천 =user_brief/projects/*/session-*.md+~/.claude/projects/C--dev/*.jsonl(첫 지시문). 대화로그는 앞부분만 읽는다(전량 파싱 금지 — 파일이 MB급).