CrownyAI ERP 모듈 — 브릿지 본 구현 + cdf 정본 저장/열기
개요
전 세션이 장착한 crowny://erp(bundle/erp) 모듈에 브릿지 실기능(snapshot/restore)과
cdf(CWDv2) 정본 저장/열기(⌘S/⌘O/⌘⇧E)를 배선했다. 오피스 Phase2-1(문서저장.한선) 패턴의
ERP 미러이며, 계약 SSOT는 bundle/erp/spec/ERP-연동계약.md.
핵심 발견 — dc 런타임 구조 재검증(계약 §0 초안과 실측이 달랐음)
계약 문서 초안은 "셸/모듈이 React 클래스 컴포넌트, fiber.stateNode.state/.setState로 직접
도달 가능"이라 적었으나, headless Chrome CDP로 bundle/erp/app/index.html을 직접 로드해
실측한 결과 실제 구조는 다음과 같았다:
- 셸/모듈은 함수 컴포넌트
Dispatcher(name)가 감싸며<StreamableComponent __name={name}/>
StreamableComponent가 유일한 진짜 클래스 컴포넌트(fiber.tag===1). 그 인스턴스의
.logic 필드가 실제 "class Component extends DCLogic {state=...}" 인스턴스 —
.logic.state/.logic.setState()가 진짜 앱 상태 API.
fiber.memoizedProps.__name이 등록명 — 셸="index", 모듈패널="ERPModule"+모듈id 첫글자
window.getDC/window.__dcRegistry는 컴포넌트 "정의"(템플릿/생성자) 캐시일 뿐 라이브
- 모듈 패널은 dc-import로 지연 마운트 — 한 번도 방문 안 한 모듈은 registry/fiber 어디에도
이 재검증을 반영해 crownyBridge.js를 새 구조에 맞게 재작성했다(구 클래스컴포넌트 직접
탐색 코드는 fiber는 찾지만 stateNode.state가 셸 state와 무관한 {__v,__err}만 갖고 있어
전부 폴백값(fallback {module:'dash'})만 반환하는 조용한 실패였음 — 라이브 CDP 검증이
아니었으면 이 오류가 배포됐을 것).
산출 파일
/Users/ef/CrownyBrowser/bundle/erp/bridge/crownyBridge.js— 본 구현. 순수부
ErpBridgePure.*(module.exports로 Node 하네스 가능) + DOM부(fiber 탐색/snapshot/
restore/summary). `window.__crownyErpBridge = {version:2, snapshot(), restore(snap),
summary()}`.
/Users/ef/CrownyBrowser/bundle/erp/bridge/crownyBridge.한선— 순수 판정 로직 교차검증
/Users/ef/CrownyBrowser/bundle/erp/bridge/ERP저장.한선— cdf(CWDv2) 저장/열기 엔진.
CROWNY_ERP_MODE=save|open + TITLE_FILE/JSON_FILE/TS/SUMMARY/
OUT_FILE(save) 또는 IN_FILE/OUT_JSON_FILE/OUT_META_FILE(open). 자체시험 19/19 PASS.
/Users/ef/CrownyBrowser/native/crowny-ai-content.m—CAErpIO카테고리 신설
/Users/ef/CrownyBrowser/native/crowny-ai-main.m— menuSave/menuOpen/menuExportHTML을
공유장부 발행(계약 §1/§2 최소분)
저장 성공 시 native가:
~/Documents/CrownyShared/docindex.psv에id|title|erp|mtime|metaupsert(id=파일명).~/Documents/CrownyShared/이벤트버스.psv에ts|erp|erp.snapshot.saved|{"title":..}append.
검증
- crownyBridge.js 순수부 — Node 하네스 16/16 PASS(살균/스냅샷유효/요약/요약문자열 등).
- crownyBridge.js DOM부(fiber) — headless Chrome CDP로
file:///…/erp/app/index.html
snapshot()이 셸 state({module,paletteOpen,guideOpen,paletteQuery})와 dash 모듈
state({period,askQuery,askAnswer})를 정확히 포착.
- summary()가 mountedCount/counts를 정확히 계산.
- restore()로 한 번도 방문한 적 없는 finance 모듈을 스냅샷에서 복원 — 셸 전환 →
지연 마운트 대기(150ms) → setState 순서로 실제 DOM에 "회계" 패널이 렌더되고 커스텀
테스트 값("cdp시험필터" 등 한글 포함)이 왕복 확인됨. `restored:["shell","dash",
"finance"], failed:[]`.
- 8개 모듈 전부(dash/finance/sales/purchase/inventory/mrp/hr/approval) 레지스트리명
실측 확인(ERPModuleMrp/ERPModuleHr 포함, 단순 대문자화 규칙 100% 적중).
- crownyBridge.한선 — hanseonc_high 컴파일 통과, 자체시험 20/20 PASS.
- ERP저장.한선 — hanseonc_high 컴파일 통과, 자체시험 19/19 PASS(한글 포함 JSON 왕복,
- make ai — 에러 0 · 경고 0(-Wall 기준) 클린 빌드.
./CrownyAI기동 3초 생존 확인. - 라이브 네이티브 GUI 왕복(⌘S→cdf 생성→⌘O) — 미완. 이 macOS 데스크톱은 다수
CrownyAI.app(pid 상이) 확인), osascript로 `tell application
"CrownyAI" to activate`를 실행했더니 내가 방금 빌드한 raw 바이너리(pid 480)가 아니라
그 기존에 떠 있던 다른 인스턴스가 활성화됐다(이름 충돌). 다른 세션의 라이브 앱에
키 입력을 잘못 흘릴 위험이 확인된 시점에 자동화를 중단했다(가드레일 "장기 백그라운드
폭주 방지"/세션 간섭 회피 원칙). 대신 raw 바이너리는 즉시 kill해 정리했다. 그 결과
⌘S/⌘O의 실제 NSTask 파이프라인(evaluateJavaScript→파일 IO→ERP저장.toau→docindex/
이벤트버스 발행)은 코드 리뷰 + 컴파일 + CLI 동일 경로 수동 실행으로만 검증했고,
메뉴 키 입력을 통한 종단 GUI 시나리오는 이 세션에서 실측하지 못했다. 후속 세션이 단독
사용 가능한 시점에 ⌘S→cdf 확인→⌘O 왕복을 재시도할 것.크라우니코드 학습
- lookup: "상태 스냅샷"/"cdf 저장"/"reactFiber"/"docindex" 검색 — HIT 1건("정통화_스냅샷_RPN",
- learn add 2건:
ERP상태스냅샷_cdf저장(ERP저장.한선),ERP브릿지_모듈레지스트리이름_유효모듈판정
잔여 이슈
- 라이브 네이티브 GUI ⌘S/⌘O 종단 검증(위 §6) — 단독 데스크톱 세션에서 재시도 필요.
- 빌딩/투데이의 CrownyShared 구독측 배선(계약 §1 각주, 각 모듈 후속 punch).
- 자연어 명령 분해(ERP 일정 + 빌딩 기기 제어 동시 처리, 계약 §2 하단) — 옴니바/크라우니AI
- restore()의 순차 모듈 복원은 150ms 지연 후 재탐색하는 휴리스틱 — 매우 무거운 초기 렌더
관련 파일
/Users/ef/CrownyBrowser/bundle/erp/spec/ERP-연동계약.md(계약 SSOT, §0 실측 각주 필요 —
/Users/ef/CrownyBrowser/bundle/erp/bridge/crownyBridge.js/Users/ef/CrownyBrowser/bundle/erp/bridge/crownyBridge.한선/Users/ef/CrownyBrowser/bundle/erp/bridge/ERP저장.한선/Users/ef/CrownyBrowser/native/crowny-ai-content.m(CAErpIO 카테고리)/Users/ef/CrownyBrowser/native/crowny-ai-main.m(⌘S/⌘O/⌘⇧E 분기)
추가 실측 (2026-07-17 12:29 — 메인 세션 GUI 종단)
잔여였던 네이티브 GUI 저장 종단을 실측 완료:
./CrownyAI crowny://erp) 기동 → System Events 메뉴 항목 "저장" 직접 click(키스트로크 아님 — 포커스 무탈취, 사용자 작업/타 세션 인스턴스 무접촉).~/Documents/CrownyERP/크라우니ERP-dash-20260717-1229.cdf — CWDv2 본문에 실상태 JSON(셸 {module:dash,...} + dash {period:"월간",askQuery,askAnswer}, 미마운트 모듈 null) 확인~/Documents/CrownyShared/docindex.psv upsert 1행 (...|erp|1784258992|module:dash/...)~/Documents/CrownyShared/이벤트버스.psv erp.snapshot.saved 1행dash:0 카운트 방식은 코스메틱(본문 데이터 무손실).GUI ⌘O 종단 + restore 재설계 (2026-07-17 오후 — 메인 세션)
실측 결과
- GUI ⌘O 종단 PASS(포커스 무탈취 — NSOpenPanel을 AX로 조작: 파일행 선택→Open 클릭. System Events 클래스명 함정:
split group아님 →splitter group): 테스트 cdf(shell=hr, dash.period=연간) 열기 → dash state 실복원 확인. - 수리 1 — 셸 표류: 구 restore가 모듈 순회 후 셸을 마지막 모듈에 방치 → 스냅샷 셸로 복귀 수정 →
크라우니ERP-hr-*.cdf재저장 실증. - 수리 2 — 지연적용 재설계: dc-import가 비활성 모듈을 언마운트해 순회식 복원 state가 소실 → restore를 pendingRestore(마운트 시 감시자 400ms 폴링이 2회 연속 관측 후 1회 적용) 방식으로 재작성. 긍정 실증 PASS: 미마운트 hr에 pending 걸고 ⌘7 첫 전환 → 0.6초 내 적용·큐 소거·감시자 자동종료.
debug()진단 접근자 추가(계약 외).
⚠발견 — 앱(dc 런타임) 자체 결함: 모듈 재마운트 불가
- 브릿지 무개입 대조실험(관측만 주입, 앱 고유 ⌘7→⌘1 키보드 전환): 한 번 언마운트된 모듈(dash)은 영영 재마운트되지 않음(에러 0, headless Chrome·WKWebView 동일). 사용자가 그냥 앱만 써도 모듈 왕복 시 빈 패널.
- 영향: 지연복원은 "첫 마운트 전 모듈"에만 실효. 재마운트 버그가 수리되면 현 설계가 그대로 전 모듈 커버.
- dc 계열 공통 위험: 같은 dc 런타임을 쓰는 크라우니투데이(4탭)·크라우니빌딩(9모듈)도 동일 결함 가능성 — 각 트랙 확인 권장.
- 다음 punch: dc 런타임 재마운트 수리(부트 전 몽키패치 주입 검토 — 앱 번들 무수정 원칙 유지) 또는 상류(디자인 파이프라인) 재생성.
검증 하니스
- CDP 포트 9345 전용(9333은 오피스 회귀와 충돌 실측 — cdp평가.js가 첫 page 타겟을 잡아 오피스 앱에 평가됨). 러너=세션 스크래치 erp-restore-verify.js + 판정정본 erp-restore-verify.한선(4상, 자체시험 4/4).