← 홈으로토스에서 앱 열기
리뷰테크 — 앱인토스 미니앱 · 2026.05–09 단독 개발

느낀 점 한 줄이면, 자연스러운 리뷰 초안 세 개.

LLM에게 리뷰를 시키면 “AI 티”가 난다. 리뷰테크는 생성 한 번으로 끝내지 않고 retrieve → generate → critique → revise 파이프라인으로 품질을 시스템으로 관리한다. 아래 데이터는 전부 2026-09-19 실제 API 호출로 추적한 실측이다.

실제 화면 흐름 — 유저가 하는 일의 전부
11.9초 뒤리뷰 초안 3개 완성 — 길이별로 골라 쓴다
마음에 드는 초안을 복사하면 끝. 로그인하면 내가 고른 리뷰의 말투를 학습해 다음 초안에 반영한다.
4단계 파이프라인
51예시 리뷰 코퍼스
8지원 플랫폼
119커밋 · 넉 달
리뷰테크 앱 화면 — 포기한 후기 적립금, 리뷰테크로 챙겨요
scroll
02 — 문제 정의

쓸 말이 없어서가 아니라,
글로 다듬는 일이 번거로워 포기합니다.

후기를 쓰면 적립금을 주는데도 사람들은 포기한다. 느낀 점이 없어서가 아니다 — 한 줄짜리 감상을 몇 문단의 글로 늘리는 일이 귀찮아서다. 그래서 리뷰테크는 느낀 점 한 줄만 받는다. 나머지는 AI가 늘린다.

그런데 그 “늘리는 일”을 LLM에 한 번 호출로 시키면 문제가 생긴다. 예시도 검증도 없이 생성하면 모델은 자꾸 광고 문구처럼 정리하고, 정중하게 권유하고, “최고”를 남발한다. 사람이 쓴 리뷰처럼 읽히지 않으면 유저는 그대로 복사하지 못한다.

실제로 검수 LLM이 적발한 문장 —
“결론부터 말하면 완전 대만족이에요.”
reason: 정리 표현

같은 입력으로 예시 주입 없이 생성한 결과와 파이프라인을 통과한 결과를 나란히 두면 차이가 보인다. (아래는 실측 comparison 데이터 — 왼쪽은 프로덕션 폴백 경로와 동일한 단독 호출)

03 — 파이프라인 탐색

리뷰 하나가 통과하는 네 개의 관문

사람도 글을 잘 쓰려면 잘 쓴 글을 먼저 보고 → 초안을 쓰고 → 읽어보고 → 고친다. 리뷰테크는 이 과정을 그대로 자동화했다. 버튼 한 번 뒤에서 이런 일이 벌어진다.

1
예시 찾기
retrieve

비슷한 상황에서 진짜 사람이 쓴 리뷰 4개를 먼저 찾아요

2
초안 쓰기
generate

그 말투를 참고해서 서로 다른 리뷰 3개를 써요

3
검사하기
critique

“AI가 쓴 티”가 나는 문장을 다른 AI가 찾아내요

4
고쳐 쓰기
revise

걸린 문장만 사람처럼 다시 써요

아래는 시연이 아니라 실제 기록이다. 시나리오를 고르고 스크롤을 내리면, 그날 각 단계가 실제로 찾고·쓰고·잡아내고·고친 내용이 카드로 쌓인다.

04 — 실험 타임라인

119개 커밋, 넉 달의 실험

전부 저장소 git 이력에서 그대로 가져온 기록이다. 만들고, 부수고, 되돌린 순서.

2026-05-19

첫 커밋 — 크롤링 + 생성 MVP

상품 링크를 붙여넣으면 크롤링 → Gemini로 리뷰 생성. 이틀 만에 8개 플랫폼 파서와 베스트 리뷰 코퍼스(예시 주입의 시작)까지.

c38fd89 초기 커밋 · bc059f4 best reviews corpus + dynamic exemplar retrieval
2026-07-10

“Load failed” — 첫 번째 프로덕션 장애

Mixed Content·CORS로 브라우저 API가 전면 실패. 큰 원본 사진 업로드가 끊기던 문제는 클라이언트 압축으로 해결.

a86e4e7 Mixed Content·CORS 방어 · 8899876 업로드 전 클라이언트 압축
2026-08-02

디자인 시스템 패스

그림자 elevation → 모션 → 타입 위계 → 간격 리듬, 네 단계로 나눠 하루에 리스킨.

f9307aa→c1ecf6e 4단계 스타일 패스
2026-09-08

하루 만의 설계 반전 — LangGraph를 버리다

아침에 LangGraph Reflection + RAG 설계 문서를 쓰고, 같은 날 “분기 하나짜리 순차 흐름에 프레임워크는 과하다”는 결론으로 제거. 일반 async 함수로 파이프라인을 구현하고 단위 테스트를 CI에 편입했다. 같은 날 구글이 text-embedding-004를 API에서 제거해 임베딩 모델도 강제 교체.

b3de0b7 LangGraph 설계 · 133dd39 제거 확정 · 80b35fe 파이프라인 구현 · 62d8921 임베딩 교체 · 895b411 테스트 CI 편입
2026-09-08

외부 의존이 또 끊기다

네이버 쇼핑 API 서비스 종료(7/31). 제품 검색을 Gemini 그라운딩으로 교체 — 그라운딩은 JSON 모드와 병행이 안 돼 프롬프트로 형식을 강제했다.

2acb42e 검색을 그라운딩으로 교체
2026-09-15

앱인토스 미니앱 마이그레이션

.ait 번들 빌드, 토스 로그인, 교차 출처에서 쿠키가 막혀 Bearer 토큰 병행 체계로 전환.

32e9d89 미니앱 마이그레이션 · a3b9b19 쿠키 차단 대응
2026-09-18

심사 반려 → 당일 대응 → 정식 출시

뒤로가기 UX로 반려. SDK backEvent 연동, 위저드 백스택 누수 수정, confirm() 의존 제거까지 당일 처리하고 재심사 통과. 같은 날 서비스명도 ‘리뷰테크’로 리브랜딩(동명 미니앱 충돌).

72b1e77 backEvent 연동 · 5b8d42c 웹뷰 안정화 · f34a7b6 리브랜딩
2026-09-19

수익화와 SEO

리뷰 생성 대기 시간에 전면 광고 노출(하루 첫 생성은 광고 없음), robots·sitemap·JSON-LD 등 기술 SEO 기반 구축.

aa1be70 전면 광고 연동 · 04e41b8 기술적 SEO
05 — 버그 해결 · 배포 · 출시

출시일에 서버가 죽으면 생기는 일

SSH 없이 프로덕션 장애를 복구하다

2026-09-18 · 출시 당일 전면 장애

출시 직후 앱이 전면 “Load failed”. 원인은 무인 보안 업데이트가 nginx를 재시작하는 틈에, 과거 실험의 잔재였던 root 계정 pm2 프로세스(nodeapp)가 80/443 포트를 선점한 것. 로컬에 SSH 키가 없는 상황 — GitHub Actions에 임시 진단 워크플로를 만들어 원격으로 조사하고, 같은 방식으로 복구했다.

nginx 죽음잔재 nodeapp이 80/443 선점 Actions 워크플로로 원격 진단pm2-root 정지·비활성nginx 재기동pm2 startup 등록으로 재발 방지
8f82557→1286ef2 진단·복구 워크플로 · c794360 pm2 startup 등록

토스 웹뷰에서 뒤로가기가 세 번 씹히던 버그

심사 반려의 진짜 원인

입력 위저드가 단계마다 backEvent 핸들러를 쌓기만 하고 해제하지 않아, 위저드를 떠난 뒤에도 죽은 핸들러가 뒤로가기를 3~4회 삼켰다. 핸들러 해제 함수를 ref 배열에 모아 unmount에서 일괄 해제하는 것으로 수정. 웹 브라우저에선 재현되지 않고 토스 웹뷰에서만 드러나는 종류의 버그였다.

5b8d42c 위저드 백스택 누수 수정 + confirm() 의존 제거

배포는 지루할수록 좋다

CI/CD — push마다 lint·빌드·테스트, master 머지 시 자동 배포

GitHub Actions 2개 워크플로: ci.yml이 모든 push를 검증하고, deploy.yml이 master 반영을 Lightsail(nginx + pm2)에 배포한다. 수동 배포로 먼저 검증한 뒤 자동화를 켰고, SQLite는 pm2 cron으로 매일 VACUUM INTO 백업. 파이프라인 단위 테스트도 CI에 물려 있어 프롬프트를 고치다 회귀가 나면 머지 전에 잡힌다.

fc2c806 Actions 도입 · 0587f5a 자동 배포 활성화 · 521aa4c 일일 백업 체계 · 895b411 테스트 CI 편입
06 — 한계

숨기지 않는 것들

critique는 스킵될 수 있다

생성이 13초를 넘기면 critique를, 20초를 넘기면 revise를 건너뛰고 초안을 반환한다. 품질 단계가 응답 시간을 볼모로 잡지 않게 한 선택이지만, 운영 로그에서 실제로 스킵이 발생한다.

품질 판단이 LLM 하나에 의존한다

정량 평가셋이 없다. “AI 티”의 기준은 critique 프롬프트의 금지 패턴 목록이 전부이고, 이 페이지의 추적 통계도 표본 3회다(3회 중 2회 revise 발동).

외부 의존은 내가 통제할 수 없다

넉 달 사이 임베딩 모델(text-embedding-004 API 제거)과 검색 API(네이버 쇼핑 종료)를 강제로 교체당했다. 크롤 차단(403)은 우회하는 대신 공유텍스트·그라운딩·사진의 3중 폴백으로 설계를 바꿨다.

출시 전 전수 테스트 결과표 — 데이터 준비 중

8개 플랫폼 23개 링크 전수 테스트 기록은 저장소 밖에 있어 회수·재실행이 필요하다.

07 — 기술선택의 이유

뭘 안 썼는지가 더 중요했다

일반 async 함수 파이프라인
LangGraph

분기 하나짜리 순차 흐름. 그래프 프레임워크가 주는 건 러닝커브와 디버깅 난이도뿐이었다. 설계 문서까지 쓴 뒤 같은 날 제거했다. (133dd39)

51건 인메모리 임베딩 캐시
벡터 DB

코퍼스가 51건이면 첫 요청 때 한 번 임베딩해 메모리에 들고 있으면 된다. 코사인×10 + 톤3·평점2·길이1 하이브리드 랭킹, 실패 시 키워드 사전 폴백. (985df47)

최악 3회 호출 고정
수렴할 때까지 재비평 루프

critique→revise→재critique 루프는 지연의 상한이 없다. 생성 1 + 비평 1 + 수정 1로 상한을 고정하고, 대신 시간 예산 게이트를 달았다. (b19cc4d, 889d15e)

gemini-2.5-flash · thinkingBudget 0
더 큰 모델

리뷰 3안 생성에 추론 토큰은 낭비다. temperature 1.15·topP 0.97로 사람 글의 편차를 흉내 내고, 응답은 JSON 모드로 고정. 잘린 JSON은 괄호 스택 복구로 살린다.

SQLite(@libsql) + bcryptjs
better-sqlite3 / bcrypt

서버에서 네이티브 컴파일이 반복적으로 말썽이라 prebuilt/순수 JS 구현으로 교체. 단일 서버 규모에 DB 서버는 과하다. (d502b09, 747f1a9)

React 19 + Vite / Fastify

클라이언트는 .ait 번들과 PWA를 같은 코드베이스로. 서버는 라우트 + 서비스 레이어 분리 정도의 얇은 구조면 충분했다.