← 목록
AI 2026-07-17 11KB 읽기 12분

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을 직접 로드해 실측한 결과 실제 구조는 다음과 같았다:

  1. 셸/모듈은 함수 컴포넌트 Dispatcher(name)가 감싸며 <StreamableComponent __name={name}/>
를 렌더한다.
  1. StreamableComponent가 유일한 진짜 클래스 컴포넌트(fiber.tag===1). 그 인스턴스의
.logic 필드가 실제 "class Component extends DCLogic {state=...}" 인스턴스 — .logic.state/.logic.setState()가 진짜 앱 상태 API.
  1. fiber.memoizedProps.__name이 등록명 — 셸="index", 모듈패널="ERPModule"+모듈id 첫글자
대문자(dash→ERPModuleDash, mrp→ERPModuleMrp, hr→ERPModuleHr 등 8종 전부 실측 확인).
  1. window.getDC/window.__dcRegistry는 컴포넌트 "정의"(템플릿/생성자) 캐시일 뿐 라이브
인스턴스가 아니다 — 스냅샷/복원엔 fiber 워크만 사용.
  1. 모듈 패널은 dc-import로 지연 마운트 — 한 번도 방문 안 한 모듈은 registry/fiber 어디에도
없다(정직 null, restore()가 셸 모듈 전환으로 지연마운트를 유도한 뒤 재탐색).

이 재검증을 반영해 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.한선 — 순수 판정 로직 교차검증
정본(적용대상판정·설치가드·유효모듈인가·모듈레지스트리이름·셸판정·복원판정). 자체시험 20/20 PASS.
  • /Users/ef/CrownyBrowser/bundle/erp/bridge/ERP저장.한선 — cdf(CWDv2) 저장/열기 엔진.
문서저장.한선의 v2직렬화/v2역직렬화/무결성검사/v2저장/v2열기를 그대로 이식, 본문 섹션에 상태 JSON을 담는다. CLI: 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.mCAErpIO 카테고리 신설
(caIsActiveTabErp/caSaveErpDocument/caOpenErpDocument/caOpenErpCDFAtURL/caExportErpState) + WKUserScript 등록은 전 세션이 이미 완료(caErpBridgeScriptSource, 무변경).
  • /Users/ef/CrownyBrowser/native/crowny-ai-main.m — menuSave/menuOpen/menuExportHTML을
활성 탭이 ERP인지로 분기(오피스 디스패치 무변경, 탭 URL 기준 라우팅).

공유장부 발행(계약 §1/§2 최소분)

저장 성공 시 native가:

  • ~/Documents/CrownyShared/docindex.psvid|title|erp|mtime|meta upsert(id=파일명).
  • ~/Documents/CrownyShared/이벤트버스.psvts|erp|erp.snapshot.saved|{"title":..} append.
구독측(빌딩/투데이) 배선은 계약 §1 각주대로 아직 없음 — 각 모듈의 후속 punch.

검증

  1. crownyBridge.js 순수부 — Node 하네스 16/16 PASS(살균/스냅샷유효/요약/요약문자열 등).
  2. 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% 적중).
  1. crownyBridge.한선 — hanseonc_high 컴파일 통과, 자체시험 20/20 PASS.
  2. ERP저장.한선 — hanseonc_high 컴파일 통과, 자체시험 19/19 PASS(한글 포함 JSON 왕복,
메타 필드, 무결성검사, 세미콜론 이스케이프 등). CLI save/open 모드 수동 실행으로 실제 .cdf 생성 + 재오픈 시 상태 JSON 바이트 동일 확인(diff 없음).
  1. make ai — 에러 0 · 경고 0(-Wall 기준) 클린 빌드. ./CrownyAI 기동 3초 생존 확인.
  2. 라이브 네이티브 GUI 왕복(⌘S→cdf 생성→⌘O)미완. 이 macOS 데스크톱은 다수
세션이 동시 사용 중이며(스크린샷에서 다른 세션의 Design/Terminal/Fable 창들과 함께 이미 실행 중인 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",
무관), 나머지 MISS(신규 로직으로 직접 생성).
  • learn add 2건: ERP상태스냅샷_cdf저장(ERP저장.한선), ERP브릿지_모듈레지스트리이름_유효모듈판정
(crownyBridge.한선).

잔여 이슈

  • 라이브 네이티브 GUI ⌘S/⌘O 종단 검증(위 §6) — 단독 데스크톱 세션에서 재시도 필요.
  • 빌딩/투데이의 CrownyShared 구독측 배선(계약 §1 각주, 각 모듈 후속 punch).
  • 자연어 명령 분해(ERP 일정 + 빌딩 기기 제어 동시 처리, 계약 §2 하단) — 옴니바/크라우니AI
레이어 후속.
  • restore()의 순차 모듈 복원은 150ms 지연 후 재탐색하는 휴리스틱 — 매우 무거운 초기 렌더
환경에서 타이밍이 빠듯할 수 있음(실사용 중 실패율 관찰 필요, 필요시 지연시간 조정 여지).

관련 파일

  • /Users/ef/CrownyBrowser/bundle/erp/spec/ERP-연동계약.md(계약 SSOT, §0 실측 각주 필요 —
이번 세션 발견을 반영하려면 별도 편집 필요, 이번 세션은 무수정 원칙상 spec은 손대지 않음)
  • /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 인스턴스(./CrownyAI crowny://erp) 기동 → System Events 메뉴 항목 "저장" 직접 click(키스트로크 아님 — 포커스 무탈취, 사용자 작업/타 세션 인스턴스 무접촉).
  • 결과 3산출 전부 확인:
  • ~/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행
  • ERP저장.한선 자체시험 19/19 독립 재실행 PASS(메인 세션 재컴파일).
  • 잔여 축소: GUI ⌘O 종단(파일 다이얼로그 자동화 필요 — CLI open+CDP restore 왕복은 기검증), 모듈요약 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).