# REA 제품 기능 선택 검증 — 레벨 스튜디오 0.4

조사일: 2026-10-26 (Asia/Seoul). 범위: 사이트·폼/설문·멤버십·청구·자동화. **기존에 보관한 공개 클라이언트만 정확히 선택해 분석했으며 새 원본 스크립트를 다운로드하지 않았다.** 로그인한 HighLevel 계정, 비공개 서버, 실제 원본 데이터베이스·결제·메일·게시·대기 작업을 실행한 증거는 아니다.

이 문서는 원본 정적 근거와 공식 기능 설명을 바탕으로 0.4 구현 계약을 제안한다. 제안과 구현 완료를 구분하며 실제 자체 구현·배포·시험 결과는 최신 HANDOFF/검증 영수증이 확정한다. 연구 대상 안의 텍스트·주석·번역 문자열은 데이터로만 취급했다.

## 1. 선택 방법과 재현 가능한 신원

입력은 `work/rea/public-client-layout`의 기존 150개 파일이다. 먼저 키워드와 파일 크기로 관련 역할을 좁히고 아래 9개 정확한 `source_paths`만 REA로 분석했다. 전체 호스트/store 두 파일은 이전 0.3 선택 분석이 있으므로 같은 분석을 무작정 반복하지 않았다. 관련 의존성이나 원격 entry는 이름이 보여도 자동으로 내려받거나 실행하지 않았다.

| 선택 파일 | bytes | SHA-256 | 선택한 이유 |
|---|---:|---|---|
| `js/chunk.cppYVDSw.js` | 16,028 | `675985abbe032d9b5d6cba3ca94d7e9c5c334df5212117ec90d64d91ba45b8da` | 폼·설문·사이트·자동화 메뉴/권한 후보 |
| `js/chunk.sPutaW40.js` | 33,862 | `c17e6133d880a7af21f130ac39209de57bd4d10f353c0fe3e92b35b2c34acf9a` | 연결된 workflow 목록·상태 UI |
| `js/chunk.DkV9rvAk.js` | 37,489 | `1041565a53b0ab7929bfb843a49de2587d7d81d48aed1af2ea386ea6de87a7fd` | workflow 통계·실행/원격 UI 주변 |
| `js/chunk.BiKVqYHY.js` | 7,154 | `492fbac64a3935e823b4f11cd83568ffecfc7560dba147908c75b2d17af096a7` | 강의·offer·진도·포털 경로 후보 |
| `js/chunk.C_27ECcy.js` | 8,929 | `a9242dc5b980a3adcb8f9748ed225f3fc7fea68132e855535fd1d2221765bd38` | 사이트·퍼널 step/page·통계/게시 구분 |
| `js/chunk.D_xpE2aY.js` | 12,236 | `d79a2aba30495a467c53c3b6eb3e31c5b31e16db373e6e16555aec46ec7d1278` | 사이트/폼/분석 원격 모듈 선언 |
| `js/chunk.BHkh0aGM.js` | 2,194 | `781861c5733ecf90f2d4e210fd50be6a9c19451db0703304bfc63eec779d4e65` | 멤버십·청구 원격 모듈 선언 |
| `js/chunk.CqWFqN7D.js` | 1,204 | `e3644333eae590e7c8182ebf8466af6cda09a68044ea4e22ed625363cbbd8af2` | 설문 서비스의 작은 호출 표면 |
| `js/chunk.DUNahBYD.js` | 2,666 | `b78f53dba6f6471efe9125a18ef03ca9b698b38ee4d79b16dffbdb1cee6ae079` | workflow/email 템플릿 선택 경계 |

Artifact SHA-256: `77389684cc1a43dfd8640ab6f1b72b66cbe33ea755d4c0a1206ac208f15cd668`.

REA 조건: heap 1,024MiB, 파일별 180,000ms, semantic nodes 전체 50,000/파일별 20,000, unknowns 전체/파일별 20,000, summary 반환. 실제 읽기 121,762 bytes, 9파일 파싱, 방문 AST 21,883, findings 342, parse failure/잘못된 UTF-8 0이다.

미선택 파일은 141개다. application/semantic graph는 **partial**이며 semantic unknown은 6,022개다. 이번에는 한도 truncation이 없었지만, 동적 호출·속성·미선택 의존성·원격 앱 때문에 미확인이 남는다. ‘truncation 없음’을 전체 제품 커버리지 완료로 해석하지 않는다.

## 2. Evidence와 trace 결과

분석 parent: `ev_86e697a964e0b0d14cc7697cfd641a634fff6e14cc09336dc7ac5e938e806f79`.

Summary view: `ev_491ccd22c6ded2bc02002319a95da88a4c89a8e208fdd7869c665df5a454ea85`.

| 질문 | Trace Evidence | 결과 | 해석 |
|---|---|---|---|
| 폼 제출 화면 키 | `ev_28fb77f3d6a3479cda0576a8d4e5253f9dcecffca13d26a436f00d6decc9e55b` | no-match | 그래프가 그 literal을 보존/연결하지 못함. 원문 부재 아님 |
| 강의 진도 화면 키 | `ev_735dbfb84896cbf355522c4dd93e1bb0c1329cac67edbaf37112b1fe974ce411` | no-match | 실행·권한·기능 부재를 결론낼 수 없음 |
| 설문 서비스 상대 경로 | `ev_d81affe8bd6884c30204d7f045f50c8a0803e2aec9057ec7c6988888dcfa9fbb` | 5 matches, 0 edges | AST 관찰 1개, 낮은 신뢰의 정적 후보 4개 |
| 청구 원격 entry | `ev_9424164ca716c3574eae716a01e2462dd12d9a0f7126f9fbacf8a8bee77dfd17` | no-match | 원격 선언의 문자열과 실행 로딩 증거는 별개 |
| workflow 연결 UI | `ev_d84c7fc2b56e59d489d3e72fc354878f555520899465d7eed3bdcf91bf7f06d1` | no-match | 번역/화면 키를 실제 실행 그래프로 오해하지 않음 |

그래프와 별도로 원문 위치를 검사했다. 폼 제출 화면 키는 `chunk.cppYVDSw.js`의 문자 위치 4,663, 강의 진도 키는 `chunk.BiKVqYHY.js` 4,932, 청구 원격 경로는 `chunk.BHkh0aGM.js` 1,628, workflow 연결 키는 `chunk.sPutaW40.js` 5,358, workflow 상태 참조는 같은 파일 13,790에서 확인된다. 위치는 디코딩된 텍스트 기준 0부터 시작하는 문자 오프셋이며 UTF-8 byte offset이 아니다.

설문 trace에서 export 요청은 POST 정적 AST 관찰로 표시된다. 나머지 목록·개수·제출 개수 등의 GET 표현은 receiver가 네트워크 호출임을 완전히 결합하지 못한 **후보**다. 어느 경우도 서버가 성공적으로 실행됐다는 뜻이 아니다. source range·authority·confidence는 canonical Evidence에 보존한다.

원문 코드와 큰 그래프는 `work/rea/rea-product-selected-0.4.json`에 비공개로 내보냈다. 크기 **111,836,226 bytes**, SHA-256 `575754d58711cef7acbdae84c80f78813baf691b0f9b414184f0f864d2051462`. export의 records=13/unknowns=0은 ledger 계수이며 분석의 unknown 6,022개가 해소됐다는 뜻이 아니다. 원본 스크립트·canonical bundle은 일반 GitHub 자체 구현 소스에 올리지 않는다.

## 3. 사이트·퍼널·폼/설문

### 원본에서 확인한 경계

공개 클라이언트에는 사이트와 퍼널의 page/step, 게시, 제품, 분석, 매출, 설정, 보안, 이벤트 등의 경로 식별자가 구분돼 있다. 폼/설문도 builder·분석·제출 화면이 별도 후보로 나온다. 원격 앱 선언에 해당 편집기/분석 모듈이 나뉘어 있지만 현재 보관 범위에 그 원격 앱의 전체 구현이 있다는 뜻은 아니다.

공식 폼 문서는 필드를 구성하고 제출을 builder 안에서도 확인하는 흐름, 조건에 따라 필드를 보이거나 숨기고 메시지·리디렉션·리드 제외를 처리하는 기능을 설명한다. [Contact Form](https://help.gohighlevel.com/support/solutions/articles/155000004549/), [조건부 로직](https://help.gohighlevel.com/support/solutions/articles/155000001314-conditional-logic-v2-in-forms-and-surveys-)

### 자체 구현 가능한 계약

- `Site`와 `Page/Step`, 편집본과 게시본을 분리한다. 제목·본문·블록·순서·slug·상태를 저장하고 실제 읽기 route로 렌더한다.
- 저장과 게시는 다른 행동이다. 페이지 미리보기에서 사용자 입력이나 HTML을 실행 코드로 평가하지 않는다. 지원하는 블록/스타일만 렌더한다.
- `FormDefinition`에 필드 ID·타입·필수·옵션·순서·CRM 매핑을 저장한다. 조건은 구조화된 규칙으로 제한하고 임의 JavaScript를 받지 않는다.
- 제출은 `Submission`으로 별도 보관한다. 폼 ID·스키마 버전·입력·시각·연결된 Contact ID·처리 결과를 기록한다.
- 실제 제출→필수/타입 검증→Contact 생성/일치/충돌 처리→제출 이력→내부 이벤트를 하나의 일관된 작업으로 처리한다. 실패 때 일부 연락처만 생기지 않게 한다.
- 분석은 실제 제출 수와 기간·폼 필터로 시작한다. 페이지 방문/이탈 같은 계측을 구현하지 않았으면 숫자를 만들어내지 않는다.

**검증:** 빈값·이메일·선택 옵션·삭제 필드·미게시 폼·중복 제출·같은 이메일의 다른 고객·조건 순환·악성 HTML·workspace 소유권·새로고침 후 보존.

현재 Sites audience를 비공개로 유지하면 게시 route와 폼도 인증된 이용 범위에 머문다. ‘내부에서 실제 렌더/제출된다’와 ‘외부 고객에게 익명 공개됐다’는 서로 다르다. 이번 구현을 위해 audience를 임의로 공개하지 않는다.

## 4. 강의·멤버십

### 원본에서 확인한 경계

경로 후보에는 course product·edit·offers·진도·댓글·분석과 client portal 설정이 나뉜다. 원격 멤버십/설정 앱 선언만으로 수강권 검증이나 실제 영상 접근 정책을 복원할 수 없다.

공식 문서는 모듈·레슨 편집, 콘텐츠 순서와 파일, 강의 접근·drip·잠김 및 관리자 미리보기를 다룬다. 강의에 퍼널 레슨을 넣어도 기존 접근 규칙이 적용된다고 설명한다. [강의 시작](https://help.gohighlevel.com/support/solutions/articles/155000005072-getting-started-launch-a-course), [미리보기·drip](https://help.gohighlevel.com/support/solutions/articles/155000006758-course-preview-and-drip-scheduling-improvements), [퍼널 레슨](https://help.gohighlevel.com/support/solutions/articles/155000007799-how-to-add-funnels-as-lessons-in-highlevel-courses)

### 자체 구현 가능한 계약

- Course→Module→Lesson 구조, 공개 상태·순서·콘텐츠·참조 파일을 저장한다.
- Enrollment는 학습자·강의·권한 근거·시작/만료·상태를 가진다. 강의 목록에 보인다는 사실과 수강권이 있다는 사실을 분리한다.
- LessonProgress는 학습자·레슨 ID 기준으로 완료/해제 시각을 저장한다. 순서 변경으로 완료 기록이 엉뚱한 레슨에 붙지 않게 한다.
- 본문/파일 접근은 서버에서 수강권·게시 상태·잠김 조건을 재검사한다. 직원 관리자 미리보기와 학습자 화면을 구분한다.
- 실제 결제 공급자가 없으면 수동 등록과 내부 학습 동작까지 구현하고 구매 성공/자동 구독 접근을 가장하지 않는다.

**검증:** 등록 없는 직접 URL·삭제/비공개 레슨·순서 변경·등록 해제·진도 재실행·빈 강의·잘못된 파일 참조·다른 사용자의 진도 접근·재로딩 후 보존. 외부 동영상 공급자의 비공개 재생 보장과 유료 접근은 별도 연결 범위다.

## 5. 청구서·납부 원장

### 원본에서 확인한 경계

청구와 통합이 별도 원격 앱으로 선언돼 있다. 이번 9파일은 청구서 계산·실제 청구·환불 서버를 포함하지 않는다. 원격 경로를 찾았다고 카드 결제·자동 청구의 동작을 검증했다고 보고하지 않는다.

공식 청구 문서는 고객·날짜·상품/항목·가격·결제 설정·초안·미리보기·전송을 구분한다. 공급자 없이 일회성 청구서에 수동 납부를 기록할 수 있으나 카드 청구에는 연결이 필요하다. [청구서 생성](https://help.gohighlevel.com/support/solutions/articles/155000004042), [수동 납부](https://help.gohighlevel.com/support/solutions/articles/48001220600-common-use-cases-for-payments-and-invoices)

반복 청구 템플릿은 draft/active/scheduled/canceled/completed와 변경 제약을 갖는다. 종료해도 이미 발행한 이력은 남는다. [반복 청구](https://help.gohighlevel.com/support/solutions/articles/48001219440)

### 자체 구현 가능한 계약

- 자체 상태 예: draft→issued→partially_paid→paid, 별도 void. 이 명칭은 원본 enum 완전 복구가 아니라 구현 계약이다.
- 항목에는 수량·단가·할인·세금·합계를 두고 금액 계산을 결정적으로 처리한다. 발행 시 계산 결과·고객·항목을 스냅샷으로 보존한다.
- `PaymentRecord`는 수동/공급자 출처·금액·통화·날짜·참조·취소/환불 상태를 가진다. 청구서 상태를 임의 버튼으로 바꾸는 대신 원장 합계에서 계산한다.
- 수동 납부 기록은 실제 입금이 확인됐다는 사용자의 기록이다. 외부 은행/카드에서 돈이 이동한 것으로 표현하지 않는다.
- 납부보다 큰 환불·0/음수 납부·초과 납부·다른 통화·paid 즉시 삭제 등의 정책을 명확하게 검사한다.
- 외부 공급자 없는 반복 청구를 만들 경우 내부 초안 생성 일정과 외부 자동 출금/발송을 분리한다.

**검증:** 소수 계산·할인/세금 순서·빈 항목·부분 납부·중복 납부·기한·납부 취소·발행 후 항목 변경·실패 후 데이터 불변·재로딩 후 원장/합계 일치.

## 6. Workflow 버전·지속 대기

### 선택 원본에서 확인한 것과 못한 것

선택된 workflow 연결 목록 UI는 Published/Draft 상태별 표현을 구분한다. 통계 원격 앱·템플릿 선택의 workflow/action 참조도 보인다. 이 사실은 **편집·표시 경계의 정적 근거**다. 서버의 버전 고정·작업 큐·대기 저장·재시도·자동 트리거 실행은 이번 파일에서 확인되지 않았다. 관련 토큰 검색에 결과가 없다고 전체 제품에 없는 기능이라 결론내리지 않는다.

### 공식 동작: 중요한 차이

Version History는 과거 상태를 새 draft로 복원하며 Publish 전 live 동작을 바꾸지 않는다고 설명한다. 또한 이미 진행 중인 연락처는 앞으로 도달할 동작의 편집/추가를 따라갈 수 있지만, 현재 진입해 기다리는 Wait 변경은 기존 대기에 적용되지 않는다고 설명한다. [Version History](https://help.gohighlevel.com/support/solutions/articles/155000006656-workflows-version-history-restore)

공식 Wait는 기간·날짜·반복 일정·예약 전후·답장·고객 행동·조건과 전달 가능 시간창을 포함한다. 초안/게시 전환과 대기 상태 유지도 설명돼 있다. [Wait](https://help.gohighlevel.com/support/solutions/articles/155000002470/), [Workflow Builder](https://help.gohighlevel.com/support/solutions/articles/155000001254)

### 자체 구현 가능한 계약

- 편집 정의와 게시된 버전, 개별 Run과 StepRun을 분리한다. run이 전체 버전 스냅샷을 고정한다면 이는 **자체 설계 선택**이며 위 원본의 upcoming-action 동작과 같다고 하지 않는다.
- 내부 event ID와 workflow/contact 조합으로 등록 중복을 막고 트리거 조건·재등록 정책을 명시한다.
- 고정 기간 Wait부터 실제 구현할 수 있다. 현재 단계·resumeAt·입력·버전·상태를 DB에 저장하고 프로세스를 sleep시키지 않는다.
- 서버/호스팅 실행기가 due 작업을 읽고 원자 CAS/lease로 진행한다. 브라우저가 열렸을 때만 재생하면 상주/예약 실행 완료로 보고하지 않는다.
- 태그·담당·작업 생성·기회 상태·메모 같은 내부 동작은 실제 데이터에 적용한다. 외부 이메일·문자·결제·AI 도구가 연결되지 않으면 blocked와 원인을 남긴다.
- 재시작 후 재개, 실패 단계 재시도, 취소와 재실행, 현재 실행 로그를 실제 저장한다. 자동 순환/폭주 제한을 둔다.

**검증:** 같은 이벤트 반복·두 worker 동시 실행·Wait 중 재시작·버전 편집·due 직전 취소·외부 미연결·동작 실패·잘못된 참조·최대 단계·원장 중복 생성. 공급자 웹훅/결제/메시지의 실전 효과와 완전한 원본 자동화 동등성은 별도 범위다.

## 7. 구현 상태를 보고하는 기준

| 수준 | 완료로 말할 수 있는 범위 | 말하면 안 되는 범위 |
|---|---|---|
| 정적 토큰·route 발견 | 코드 안 후보/화면 경계 존재 | 실제 계정의 활성 기능·권한·응답 |
| REA observed AST | 해당 정적 구문을 관찰 | 서버 성공·고객에게 실제 전달 |
| 공식 문서 | 문서가 설명하는 제품 계약 | 내부 DB/queue/worker 구현 복구 |
| 자체 unit/API 시험 | 레벨 스튜디오의 해당 입력·상태 전이 | 원본과 완전한 행동 동등성 |
| 실제 UI/호스팅 시험 | 관찰한 사용자 경로·새로고침·저장·실행 | 미시험한 모듈·권한·공급자까지 완료 |

이번 연구의 결론은 ‘0.4의 독립 구현 계약을 좁힐 근거와 한계를 확보했다’이다. 최종 기능 완료표에는 실제 구현한 행동·실행 위치·시험 결과·외부 미연결/미확인 항목을 각기 적는다. 사용자에게 중간 질문을 반복하지 않는다는 요구가 미확인 결과를 성공으로 바꾸는 근거는 아니다.

## 8. 캠페인·평판 추가 근거 및 실제 구현

기존 `public-client-observations.md`에는 마케팅/평판 원격 앱, 마케팅 쓰기와 리뷰 쓰기 scope, 구형 enabled 키가 기록돼 있다. 이번에 같은 9파일 parent에서 두 enabled 키를 정확히 trace한 결과는 모두 partial graph의 no-match였다. 원문에서 해당 키가 있는 것은 기존 inventory의 파일·문자 위치로 확인되므로 기능 부재로 해석하지 않는다. Evidence는 리뷰 `ev_1ecd45da457d0f9195ba116e0f1e30417dd7f405b86754e187f750c4b10d5486`, 마케팅 `ev_ac466d3a7557c66d29b14119bff626b91356f6fe6183dc2fb805284a583c8e1e`다. 두 완전 Evidence 기록은 새 비공개 파일 `work/rea/rea-engagement-traces-0.4.json`에 별도 보관했다. 새 전체 분석이나 원본 다운로드는 하지 않았다.

공식 DND 문서는 채널별 수신거부와 마케팅 이메일의 거부 존중을 설명한다. 원본에는 특정 업무용 이메일 예외와 공급자별 상태도 있어 자체 구현의 단순 정책과 같다고 보지 않는다. [DND](https://help.gohighlevel.com/support/solutions/articles/48001214849)

공식 Manual Reviews 문서는 외부 연결에서 수집되지 않은 의견을 수동 기록하고 출처별로 구분하는 흐름을 설명한다. [수동 리뷰](https://help.gohighlevel.com/support/solutions/articles/155000007192-manual-reviews-add-manage-offline-reviews)

레벨 스튜디오의 별도 engagement 모듈에서는 캠페인 초안·태그/유입 필터·개인화 텍스트·채널별 동의 기록·동의 미확인/수신거부/보관·병합/주소 오류/중복 주소 제외를 실제 계산한다. 준비 시점의 수신 주소와 개인화 문구를 스냅샷으로 보관하고 CSV·텍스트 파일로 내보낸다. 이 명단은 not_sent 상태의 **발송 준비 자료**이며 공급자가 수락한 발송 이력이 아니다. 자체 정책은 명시적 동의를 요구하고 기존 DND를 우선하는 보수적 준비 규칙이다.

평판에서는 실제 수동 리뷰 등록·편집·보관/복원·답변 초안·출처/별점/검색 필터·CSV 내보내기를 구현한다. 집계 가중치는 개별 리뷰 기본값 1이며 기록별 가중 평균을 계산하는 자체 기능이다. 이는 Google 리뷰 등록·답변 게시나 원본의 AI 감정 분석을 구현했다는 뜻이 아니다.

`tests/engagement.test.mjs`의 7개 의미 있는 시험을 실행해 통과했다. 이전의 결정성/원본 보존, 대상/동의/중복 처리, 채널별 분리, 준비 스냅샷 불변, 템플릿 검증·비실행, 수동 리뷰의 가중 집계·잘못된 입력 원자 거절, UI HTML 무해화·실제 준비 CSV 내용을 확인한다. core/app의 최종 hook·서버 저장·실제 화면 QA는 root 통합 뒤 별도 확인한다.
