class.crowny.org — 크라우니클래스 (강경모 선생님 AI 웹디자인 교육플랫폼)
개요
5개월(20주) AI 웹디자인 코스 교육플랫폼 신규 구축. 12만원(월 24,000원) 또는 80크라우니달러,
150명 선착순. 수업 방식 = 3~5분 강의영상 →
55분 개인 작업 타이머 → 작업 공유. crownyclass.com(강경모 선생님 수업관리 솔루션) 브랜딩 계승.
- 서비스: class.crowny.org → 127.0.0.1:9864 (crowny-class, LaunchAgent
com.crowny.class)
- 코드:
/Users/ef/crowny-class (academy 스캐폴드 계승: 순수 http + 모듈 디스패치 + 파일JSON)
- 병렬 구축: sonnet 5 + haiku 1 팬아웃 (분업규칙), 전 모듈 한선씨 동반 컴파일 통과
무엇을 했는지
- 스캐폴드: server.js(모듈 디스패치·gzip·ACME·정적) + lib(config/logger/store) + 커머스엔진 회원(
X-Crowny-Owner, scrypt+owner — paygate/shop과 동일 정본)
- enroll: 가입/로그인/신청. 정원판정 =
한선씨/정원판정.한선 런타임 배선(spawnSync+컴파일캐시, JS 폴백). CRD 결제 = paygate(9954) 가맹 자동 부트스트랩 → 결제 intent → HMAC 웹훅으로 active 전환. 무통장 = 입금대기 → 관리자 확인 API.
- video (유튜브 대응 엔진): 멀티파트 스트리밍 업로드(상태기계, 메모리 비적재, 800MB 캡) + HTTP Range 206 스트리밍(suffix/416 포함, 바이트 대조 검증) + 시청 진도.
- lesson: 커리큘럼 API + 55분 타이머 세션(
세션판정.한선 4상 티/옴/타 런타임 배선) + 작업완료 → 과제 게시판 자동 공유.
- community: 과제(댓글·좋아요)/포트폴리오(공개페이지)/취직반(job·resume·qna)/수료생 전용 자료방(4상 권한판정 한선씨, 수강생 403 실증).
- admin: 대시보드·수료 처리·입금 대기.
- 프론트 5페이지: index(잔여석 카운터·치킨값 카피)/join/class(원형 55분 타이머)/community/admin — 크라우니디자인 중앙CSS + 본체 토큰 SSOT.
- 커리큘럼:
한선씨/커리큘럼.한선이 72레슨 JSONL 방출(SSOT) → seed API 주입. docs/커리큘럼.md.
검증 (전부 라이브 실측)
가입→무통장신청(seq=1)→입금확인→active→커리큘럼 72→작업시작(remainingSec 3300)→한선씨 세션판정(티/작업중)→완료→과제 자동공유→자료방 403→수료→200→대시보드 집계. CRD: 실제 paygate 결제창 URL 발급. 영상: 업로드 64KB 바이트동일·Range 206·게이트웨이 Host 라우팅 200.
발견 함정 (신규)
Node Writable: ws.end() 이후 'drain' 미발화 — 업로드 마지막 청크에서
write()===false → req.pause() 후
ws.end()를 부르면 drain이 안 와서 요청 스트림 영구 pause(응답 무한대기). 처방: onFileEnd에서
ws.end(); req.resume() 무조건 재개.
잔여 이슈 (사용자 액션)
- HTTPS cert: class.crowny.org가 마스터(ext) cert 폴백 중(CN=explorer 불일치). 전용 lineage 스크립트 준비됨 — 사장님 직접 실행:
! bash /Users/ef/crowny-class/scripts/fix-https-durable.sh (프로덕션 cert 변경은 auto-mode 차단). 게이트웨이 8080 Host 라우팅은 이미 200.
- 무통장 계좌:
.env의 BANK_NAME/BANK_ACCOUNT 비어 있음 — 실제 계좌 입력 후 launchctl kickstart -k gui/501/com.crowny.class.
- 강의영상: 실제 3~5분 강의영상을 admin.html에서 업로드(레슨별 lessonId 연결).
- paygate 웹훅 검증은 결제창 실결제 1건으로 최종 확인 권장.
관련 파일
- 서버:
/Users/ef/crowny-class/server.js · 계약: API-CONTRACT.md · 모듈: modules/{enroll,video,lesson,community,admin}/routes.js
- 한선씨(전부 컴파일 통과):
한선씨/{클래스서버,정원판정,enroll,세션판정,lesson,영상엔진,관리판정,커뮤니티판정,프론트카피,커리큘럼}.한선
- 프론트:
public/{index,join,class,community,admin}.html · plist: ~/Library/LaunchAgents/com.crowny.class.plist
추가 (게이트웨이 HTTPS 개통 — 사용자 지시로 세션이 직접 실행)
- class.crowny.org 전용 cert 발급(단독 lineage, ~2026-10-09) + stunnel 슬레이브 배선 → 공개 https://class.crowny.org 200, CN=class.crowny.org
- stunnel_conf_gen.py 기존 버그 2건 수정: ①groups 초기화에 reallux 누락(KeyError 크래시 — 7/10 reallux 추가 때부터 잠복) ②슬레이브 방출 튜플에 classc·reallux 누락(조용한 미방출). 개별 lineage는 4곳(LINEAGE·PRIORITY·groups·방출튜플) 등록 필수.
- reallux도 이번 재생성으로 전용 cert 정식 배선됨(단, reallux 백엔드 :9985 미기동이라 503 — TLS와 무관).
- 동반: 한선게이트웨이/stunnel_conf_gen.한선 (SAN매칭·lineage배정·등록완전성 4상) 컴파일 통과·학습.
- 타 서비스 무영향 확인: crowny.org/docs/academy 전부 200.
2026-07-12 — 실강의 영상 탑재 + CVF + 무료체험 + 수료생 쇼케이스
- 강의영상 5편 → 23클립(3:41~4:02, h264 스트림카피): 내소개·우리반작품(7)/팀포폴(3)/개인포폴(4)/AI구현범위(3)/CrownyClass앱예시(6).
scripts/split-videos.sh
- CVF(크라우니비디오포맷) 23/23 변환: 108×60·9fps·color9, 클립당 13~150MB(실사 벡터폭증), 총 2.3GB → crowny-video output/ 정리 +
com.crowny.video LaunchAgent 상시기동(:9877, 게이트웨이 200). 파이프라인 scripts/mov-to-cvf.sh/batch-cvf.sh(yt-dlp만 우회, cvf-encoder.js 동일)
- 함정: ①cvf-encoder 전프레임 메모리상주 — 640×360×2016프레임=힙4GB+ 사망, CVF 설계해상도(27틀 배수)로 ②while-read 루프 안 ffmpeg가 stdin(매니페스트) 잠식 → 격줄 실패,
-nostdin 필수
- class 탑재: 23클립 업로드 + week0 오리엔테이션 레슨 23개 등록(총 95레슨). 무료 3클립(o1-1~3) free 플래그
- 무로그인 무료체험: 서버(free 스트리밍 예외·무로그인 목록 필터) + class.html 체험모드(잠금표시·클라이언트 55분 타이머 localStorage 유지·등록유도) + index.html 무료맛보기 섹션. 실측: free 206/유료 401/목록 3
- 수료생 쇼케이스(사용자: "학생들 디자인보다 좋은 서비스페이지"): 8기 팀플 8(자린고비·트랙시·홀로·노톡/상상의문·부자관광·시스템치과·예네) + 18기 개인 13(취업완료 서지원·우희진·이윤서, 지원중 2) → 데이터/포트폴리오/showcase_*.json 21건 + showcase.html(골드글로우 취업 하이라이트·스태거 페이드인·reduced-motion) + index 성과 티저
- 공개 HTTPS E2E 전통과: 6페이지 200, 무료스트림 206, 커리큘럼 95(free3), 쇼케이스 21건
- 한선씨 동반: 영상엔진(시청접근·목록노출)·커뮤니티판정(쇼케이스뱃지)·쇼케이스(4상·스탯집계)·프론트카피(체험문구) 전부 컴파일 통과·학습
2026-07-12 추가 — 계좌 자리비움 + 쇼케이스 사이트 미리보기
- 무통장 계좌: .env 빈 값 유지(사용자 지시), join.html 빈 값 표기="확정 후 안내됩니다" (프론트카피.한선 계좌문구 동반)
- 쇼케이스 미리보기: 21개 학생 사이트 실스크린샷(크롬 헤드리스, 팀앱=모바일 390×844/포폴=1280×800, sips 640 축소, 총 ~3MB). SPA 빈화면 3건은 puppeteer-core 실시간 대기+스크롤 트리거로 재캡처(서지원 VR포폴·김주휘 로봇포폴 확보). 박민주 사이트는 자체 클라이언트 예외 → 이니셜 아바타 폴백
- 배선: getPortfolios에 imageUrl 통과 + showcase.html 카드 3종(취업/개인/팀) 썸네일 렌더(없으면 아바타 폴백, 쇼케이스.한선 썸네일판정 동반). 렌더 캡처 검수 완료
- 함정 기록: chrome --virtual-time-budget은 실시간 인트로 애니메이션 SPA에 무력(검정/흰 화면) → puppeteer-core(networkidle+실대기+스크롤)로만 캡처됨
2026-07-12 3차 — 미리보기·폰트·속도·운영3페이지 (xhigh)
- 강의내용 무로그인 미리보기: 잠긴 92레슨 클릭→미리보기 패널(목표 전문+작업가이드 40자 흐림+영상 잠금 플레이스홀더)→"회원가입하고 전체 95레슨 열기" CTA(join#signup 자동 탭). index 커리큘럼 블록도 클릭→class 연결
- 폰트 굵기 변화 원인: 중앙CSS 가변폰트(CrownyGothic-VF 100~900, font-display:swap) — 시스템폰트로 그려진 뒤 얇은 VF로 스왑. 처방=assets/class-type.css(시스템/Pretendard 고정, 6페이지) — 스왑 제거+가독성 확보
- 로딩속도 계측: 서비스 1.6ms·게이트웨이 +39ms·HTTPS 265ms(정상) vs 가변폰트 5.6MB=2.6초(주범). 폰트 스택 교체로 다운로드 자체 제거 → 해결. 게이트웨이/서비스 무혐의
- /core: DB(데이터 sub 실시간 파일수·크기)↔모듈 5종↔페이지 9종 연결관계 맵(배선율 100%, 고아 0). /task: CrownyDoc class 문서 10건 마크다운 렌더. /file: 영상mp4/CVF/이미지/업로드/페이지 5그룹 인벤토리. 전부 관리자 토큰 게이트(401 검증)
- 버그 3건 수정: 모바일 첫 진입 목록 숨김(초기 열림으로),
week||1 falsy 함정으로 week0 오리엔테이션이 1주차에 병합(class 목록·상세태그·index 미리보기 3곳 — Number()+isNaN 처방, 주차라벨.한선 동반)
2026-07-12 4차 — CVF 단일화 + 페이월 durable 차단 (ultracode 워크플로 + 적대검증)
- CVF 단일 재생 전환 완료: class 교실이 mp4 대신 CVF를 캔버스+오디오 동기로 재생(crowny-video CVFDecoder 포팅). 토큰게이트 라우트
/api/video/cvf/<id>·/api/video/cvfaudio/<id>(무료206/유료401), 구 mp4 stream 410 폐지. E2E 실증: 캔버스 실프레임·오디오 currentTime 전진·스크린샷.
- P0 페이월 durable 차단: (적대검증이 "파일이동만=증상제거" 적발) video:9877 /api/download에
class_ 접두 403 방어 추가 → 파일 유무 무관, 재발시뮬(공개dir 강제생성) 403 확인. batch-cvf.sh 출력경로를 class-private(데이터/영상/cvf)로 격리. 비-class 갤러리(2019_USA) 200 유지.
- 동반 3파일 정합: 영상엔진(면책+cvf게이트 배선), 관리판정(computeDashboard 실배선·admin.html 렌더), 프론트카피(대응주장 정정) — 적대검증 충실 3/3.
- file.html/admin CVF 라벨 반전: "CVF=강의 미사용 보관"→"CVF=실제 강의 재생". cvfDir을 class-private로.
- 잔여(범위밖): video:9877 /api/download 전체 무인증은 미해결(class_ 접두만 방어). 미배선 커리큘럼 72레슨은 영상 없음(향후 admin 업로드→CVF 인코딩).
2026-07-12 5차 — admin 업로드 자동 CVF 인코딩 (ultracode 워크플로)
- 업로드→자동 CVF 인코딩 완성: admin이 mp4/mov 업로드 시 서버가 즉시 {cvfStatus:"encoding"} 반환(29ms, 완전 비블로킹—child_process.spawn) → 백그라운드 encode-upload.sh(ffmpeg 프레임+오디오→cvf-encoder→CVF, mp3 사이드카, ccp 아카이브) → 완료 시 meta cvfStatus:"ready" 갱신. admin.html 폴링(GET /api/video/encode-status/<id>)으로 진행 표시.
- 실측: 13.6MB mp4→CVF 15.3MB(108×60·9fps)+mp3 1.75MB+ccp 1.68MB, ~30초. 재생 게이트 무로그인 401/admin 206, class-private 격리(공개 output 미생성·페이월 안전), 인코딩중 409 가드, 레거시 23클립(cvfStatus 없음) 호환.
- 함정 수정(Integrate 발견): launchd .plist에 PATH 없어 spawn한 ffmpeg(brew) 미발견→인코딩 실패. plist EnvironmentVariables PATH 명시 + encode-upload.sh export PATH 이중방어. plist 변경은 unload/load 필요(kickstart-k 미반영). → 가드레일·지식 등록(다른 launchd 서비스도 점검 권장).
- 적대검증 5축(블로킹/페이월회귀/단일화/미완성서빙/실패경로) 전부 안전. 한선씨 인코딩판정.한선(4상) 동반.
- 잔여: 레슨 배선 서버 엔드포인트 미구현(admin UI는 안내만), puppeteer 캔버스 재생 미실시(Range로 갈음), 대용량 200MB+ 스케일 미검증, CVF 해상도 108×60 저해상(포맷 특성 — 화질 코덱 개선은 별건).
2026-07-12 6차 — 레슨-영상 배선 (ultracode 워크플로)
- wire/unwire/wire-status 엔드포인트(lesson 모듈, admin): 레슨↔영상 양방향 연결. ★free 동기화 페이월 가드=배선 시 video.free=(lesson.free===true) → 유료레슨에 무료영상 붙이면 유료로 강등(무로그인 401 실증). 상태가드 encoding→409/error→400, 권한 401, 존재 404.
- admin.html "레슨 배선" 탭: 좌 레슨(주차별·배선상태)/우 ready영상 선택→배선, 해제, 업로드 후 자동배선(선택).
- 적대검증 5축 안전(페이월 우회 없음). 발견·수정 2건: ①재배선 고아 역참조(이전 파트너 videoId 미정리)→wire에 양방향 정리 추가, 격리 픽스처로 재배선 후 고아 없음 실증 ②handleDelete가 CVF산출물(cvf/mp3/ccp) 미정리(디스크누수)→삭제 로직 추가.
- 한선씨 배선판정.한선(4상+free동기화) 동반. 현황 배선 23/미배선 72(커리큘럼은 영상 대기).
2026-07-12 7차 — CVF 1080p 실용불가 판정 → MP4 재생 복구(하이브리드)
- 판정(감사+벤치 워크플로): CVF 1080p는 원본PPM보다 큰 팽창(7.08MB/프레임>6.22MB)·h264 대비 134배·인코딩 실시간1/45(10분물 9~10h)·구조적(ASCII 1트릿1바이트+텍스트 리프폭증). 화질만 합격, 크기/속도/메모리 전부 불가. 근본원인=인코더 재설계 필요(파라미터로 불가).
- CIF 오염 발견: 진짜 RD최적 CIF는 crowny-image/server.js(JS)에만, cvf-codec.js는 구세대 v3.0 복제, .한선들은 스텁/미러. CVF변환기.한선:67 좌상단1픽셀 손실버그. → CIF 설계원리 적대검증은 별도 세션(인수인계 문서 2026-07-12-CIF-설계원리-적대검증-인수인계).
- 결정=MP4 하이브리드(사장님 규칙 "안되면 MP4"): handleStream 410→206 복구(authForStream/streamRange 재사용, 신규로직0), class.html <video> 복구(canvas CVF 제거, 948→587줄), CVF 파이프라인(encode-upload/handleCvf)은 아카이브로 보존. mp4 원본 1080p 그대로.
- 적대검증 5축 안전: 페이월(유료401/무료206/수강없는실owner401), 정적우회(SPA폴백·mp4 미유출·경로탈출 400), 단일재생경로(<video>단일), CVF아카이브 격리(video.crowny.org class_ 403), 무료 과잉차단 없음. mp4=h264 1920x1080 네이티브 실측.
- 백로그: CVF 인코더 재설계(바이너리 트릿패킹·스트리밍·server.js RD포팅·델타모션 단일패스)는 CIF 정리 후 수요 확정 시. 그전까지 강의재생=MP4.
2026-07-12 8차 — 검증 이슈 5건 수정 완료 (ultracode 워크플로)
- P0-1 모바일 교실 배너 붕괴 해결: .layout flex-direction:column(모바일)/row(≥860px) — 세로 한글자 스택→전체폭 가로 정상(캡처 육안 확인).
- P0-2 계좌 반영: .env BANK_NAME=카카오뱅크/ACCOUNT=3333-34-6742479/HOLDER=포네인티그라텍 + join.html bankField graceful. 무통장 신청 실측=카카오뱅크 3333-34-6742479 포네인티그라텍 120,000원.
- P1-1 내비: index 하단내비를 class/join/community에 복사(일관).
- P1-2 카운트: getWorks가 게스트엔 likeCount/commentCount 요약(배열 없음)→프론트 likeCount 우선 매핑. 좋아요 후 ♥1 실측.
- P1-3 대시보드: 주차별진도 {학생수,완료수,평균시청초} 객체를 막대/분초로 렌더([object Object]/NaN 소거).
- 잔여 수정: community/routes.js:182 week 0 falsy(body.week||null→Number 가드) — 오리엔테이션 과제가 works?week=0에 안 뜨던 것 해결(실증 1건 노출). 내 테스트 고아 입금 정리.
- 5축 재평가 후 채점: 백엔드 출시급(31/31), 프론트 P0 2건 해결로 소프트런칭 가능 상태.