Show GN: 코드 대신 한국어 명세를 커밋하고 있습니다 — 명세 3장으로 PWA 앱+서버
(github.com/SoliEstre)AI한테 코딩을 시키면서 계속 걸렸던 게 하나 있습니다. 결과물 코드는 남는데, 그 코드를 만들어 낸 대화와 의도는 날아갑니다. 석 달 뒤에 "이 코드가 왜 이렇게 돼 있지?"라고 물을 곳이 없습니다.
그래서 방향을 뒤집어 봤습니다. 의도를 담은 명세를 git에 커밋하고, 코드는 빌드 산출물로 취급하는 겁니다. 검증 삼아 작은 앱을 하나 끝까지 만들어 공개했습니다.
Rimlog라는 PWA인데, 독서·학습 기록에 AI가 예전 메모를 이어 붙여 줍니다. 서버 없음, 가입 없음, 데이터는 브라우저에만 있습니다.
앱은 평범합니다. 공유하고 싶은 건 만든 방식입니다.
방식
리포의 eux/ 폴더에 한국어 명세 3장이 있습니다. 앱 골격 전체가 40줄, AI 카드 위젯이 25줄, 인사이트 서버가 한 장. 이런 문장들로 돼 있습니다.
saveCapture : 캡처 폼(소스명·인용·내 생각·태그) 저장 — captures 맨 앞 삽입 + 로컬 스토리지 반영 + "저장됐어요" 토스트 + 기록 탭으로 전환.
이 파일을 EstreUX라는 도구에 넣으면 코드가 나옵니다(brew라고 부릅니다). 생성된 코드에는 명세의 해시가 박히고, 명세만 고치거나 코드만 고치면 pre-commit에서 커밋이 막힙니다. 명세가 낡는 순간 거짓말이 되는 문제를 게이트로 막는 겁니다.
수치도 재 봤습니다. 프레임워크에 원래 있던 152줄짜리 숫자 키패드를 28줄 명세로 되돌리는 식으로 실측했더니, 사람이 유지하는 줄 수가 60~82% 줄었습니다. 생성 코드 자체는 원본보다 길어지기도 합니다. 줄어드는 건 사람이 읽고 고치는 쪽입니다. 측정 기록은 리포에 있습니다.
서버도 명세 한 장입니다
Pages 데모는 서버리스라 AI가 태그 겹침 폴백으로만 돕니다. 제대로 돌리려고 셀프호스트 서버를 넣었는데, 이것도 명세 한 장에서 brew한 의존성 0짜리 node 단일 파일입니다. 백엔드를 골라 씁니다.
nvidia(기본): build.nvidia.com의 무료 API입니다. 카드 등록 없이 키를 주고, OpenAI 호환에 분당 40회쯤이라 개인 일지엔 넉넉합니다claude-cli/codex-cli: 요청마다claude -p/codex exec를 자식 프로세스로 부릅니다. 이미 내는 Claude/ChatGPT 구독을 API 키 없이 재활용하는 경로입니다openai/google: 그냥 키 프록시
키와 인증은 서버에만 있고 브라우저로는 안 나갑니다.
아직 확신이 없는 것들
명세↔코드 정합 판정을 정적 diff에 더해 property 기반 동적 검사로 확장하는 중인데, 가중치 캘리브레이션이 아직입니다. 그리고 headless DOM 환경에서 프레임워크 렌더가 실브라우저와 다르게 도는 거짓 양성 클래스를 발견해서, 검증 환경을 실브라우저로 승격하는 것도 숙제입니다. 커밋 이력을 처음부터 보시면 스캐폴드→명세→생성→다듬기 과정이 순서대로 남아 있습니다.
- 라이브: https://soliestre.github.io/Rimlog/
- 리포: https://github.com/SoliEstre/Rimlog
- 빌드 기록(상세): https://estreui.tistory.com/5
두 가지가 궁금합니다. 명세를 SSoT로 두는 방식의 함정이 뭐라고 보시나요? 특히 명세의 표현력이 코드를 못 따라가는 지점을 어디서 만나셨는지 궁금합니다. 그리고 claude -p를 앱 백엔드로 쓰는 구독 재활용 경로, 실사용에서 걸릴 만한 게 있을까요(레이트·약관·레이턴시 관점에서).