v1 마감 — 쿠키 인증 전환, 웹·앱 통일, 그리고 실사용이 찾아낸 버그들
7월 8일에 시작한 프로젝트를 오늘 v1으로 닫았다. 하루 동안 PR 12개를 머지했는데, 절반은 계획한 작업이고 절반은 직접 써 보다가 발견한 문제였다. 테스트 1,043건과 회귀 하네스가 전부 초록인 상태에서 나온 버그들이라 기록해 둔다.
요약
| 영역 | 내용 |
|---|---|
| Mova | 재학습 없이 도구 6 → 10개(봤어요·취향 추천·비슷한 영화·취향 요약), 동행 조건 추천, 에디터 리뷰 출처 링크 |
| 인증 | 웹 토큰을 localStorage → httpOnly 쿠키(BFF)로 전환 |
| Gildle | 웹과 앱을 같은 API·같은 기능·같은 표기로 통일, 앱 v1.0.1 번들 |
| 실사용 수정 | 채팅 “봤어” 기록 실패, 마이페이지 진입 불가, 목업으로 보이던 작품 8편, 말하지 않은 별점 기록 |
| 점검 | pytest 1,043 · 아키텍처 계약 6개 · 회귀 하네스 28/28 · 16/17 · flutter analyze 0건 |
더 학습하지 않기로 한 결정
판단 모델을 v10, v11로 다시 학습했지만 같은 평가셋 86에서 v9(77)를 넘지 못했다(68, 72). 새로 학습할 때마다 점수가 출렁였고, 양자화를 바꿔도 같았다. 2.4B의 천장으로 보고 방향을 바꿨다 — v9 모델은 그대로 두고 새 도구 4개를 프롬프트 예시로만 얹었다. 운영에서 “인셉션 봤어 4점”이 기록되는 것을 확인하고 배포했다.
돌아보면 아쉬운 것 하나: v9의 어댑터를 남기지 않고 GGUF만 보관해서, “v9에서 이어 학습”이라는 선택지가 처음부터 막혀 있었다. 잘 나온 회차의 어댑터는 남긴다.
토큰을 쿠키로 — 그리고 그 뒤의 회귀 세 건
로그인 토큰이 브라우저 저장소에 있으면 스크립트 공격 한 번에 통째로 빠져나간다. Next.js 프록시가 게이트웨이를 대신 호출해 받은 토큰을 자기 도메인의 httpOnly 쿠키로 심고, 이후 모든 백엔드 호출은 프록시가 쿠키를 읽어 대행하게 바꿨다(BFF). 백엔드는 한 줄도 바꾸지 않았고, 저장 위치와 수명 정책을 동시에 바꾸지 않으려고 토큰 수명(7일)은 그대로 뒀다.
배포 뒤 세 가지가 드러났다.
- 화면은 로그인 상태인데 “인증이 필요합니다” — 전환 전에 로그인해 둔 브라우저에는 표시만 있고 쿠키가 없었다. 프리뷰는 주소가 달라 새로 로그인했기 때문에 보이지 않았다. 페이지를 열 때 쿠키가 유효한지 확인해 어긋나면 표시를 지우게 했다.
- 마이페이지가 로그인 화면으로 되돌아가는 반복 — 프록시를 일괄 치환하면서 변수명이
request인 것만 잡고req를 쓰는 9개를 놓쳤다. 패턴이 아니라 “바뀌어야 할 것”을 다른 표현으로 다시 세어 잔여 0을 확인했다. - 본문 없는 응답(204)이 500 — 프록시가 빈 본문을 실어 응답 생성이 실패했다. 방문자 집계 호출이 기록은 되고 응답만 500이었다.
셋 다 “200과 401은 확인했지만 그 밖은 보지 않았다”는 같은 뿌리다.
Gildle — 화면이 아니라 데이터 모양부터 맞추기
이틀 전 웹에만 경로 후보·문장 추천·반려동물 장소를 넣었더니 앱과 벌어졌다. 앱은 경로 1개와 거리 슬라이더, 웹은 후보 목록과 추천. 상태 모델이 다르면 같은 화면을 만들 수 없고 다음 기능도 한쪽에만 들어간다. 그래서 엔드포인트와 상태(options · selected · plan)부터 같게 했다. 앱은 웹의 기능을, 웹은 앱의 기록 삭제·끝내기 확인·페이스·위치 잡음 필터를 받았고, 거리·시간·날짜 표기도 한 규칙으로 맞췄다.
맞추다 웹의 버그도 하나 나왔다. “동물병원으로 가는 최단 경로”를 받으면 목적지에서 출발지로 직선이 하나 더 그려졌다 — “추천이면 루프”라고 가정한 탓이다.
실사용 한 번이 하네스를 이겼다
저녁에 채팅을 직접 써 보니 이런 대화가 나왔다.
나: 스파이더맨 최신꺼 봤어
봇: 비슷한 제목이 여러 편이에요: 노 웨이 홈 (2021), 어크로스 더 유니버스 (2023), 브랜드 뉴 데이 (2026)…
나: 2026작품이겠지? 최신이면
봇: 말씀하신 작품을 카탈로그에서 찾지 못했어요.
나: 브랜드 뉴 데이 봤어
봇: '브랜드 뉴 데이'을(를) 카탈로그에서 못 찾았어요.
나: 니가 말한거잖아?
모델 탓이 아니었다. 코드 네 곳이 겹쳐 있었다.
| # | 원인 | 수정 |
|---|---|---|
| 1 | 후보 문구 형식이 두 가지라 파서가 세 편을 한 제목으로 읽음 | 문구를 한 함수에서만 만든다 |
| 2 | 후보 선택을 잇는 단계가 에이전트 뒤에 있어 실행되지 않음 | 에이전트 앞으로 — 되묻기에 대한 답은 새 판단이 아니라 하던 일의 계속 |
| 3 | 제목 검증이 정확 일치뿐 (모델이 붙인 “(2026)”에도 실패) | 연도 꼬리 제거 → 정확 → 부분 한 편 → 연도 → 직전 응답의 작품 → 되묻기 |
| 4 | 선택 뒤 이을 수 있는 일이 평가·예매뿐 | “봤어”도 잇는다 |
고치고 나니 다른 문제가 나왔다. “고지전 봤어”만 말했는데 별점 4점이 기록됐다. 봤어요 확인 문구에 넣어 둔 예시(“‘제목 4점’처럼 말씀해 주세요”)를 모델이 베껴 제목에 붙였고, 방금 넣은 ‘제목에 붙은 별점 분리’가 그걸 받아 준 것이다. 모델이 읽는 대화 기록에 넣는 문구는 곧 모델의 입력이다. 별점은 사용자가 이번에 말한 숫자일 때만 기록하게 하고, 안내 문구에서 숫자 예시를 뺐다.
이 장면들은 회귀 하네스 45개 어디에도 없었다. 다음 버전의 첫 작업은 기록 후속 장면을 하네스에 넣는 것이다.
화면을 안 보고 배포한 대가
마이페이지 목록을 고치다 편집용 표식 문자가 그대로 운영에 나갔다. 타입 검사와 린트는 통과였고, 화면은 보지 않았다. 그 뒤로 화면이 바뀌는 변경은 로컬에서 띄워 헤드리스 브라우저로 캡처해 확인한 뒤 배포한다. 이 글의 스크린샷도 같은 방법으로 찍었다.
v1에서 남긴 것
- 짧은 토큰 수명과 상시 갱신, 채팅 스트리밍, 더 큰 판단 모델 검토
- 길들 앱 Play 출시(내부 → 비공개 테스트)
- 회귀 하네스에 기록 후속 장면 추가
오늘의 교훈
- 테스트가 전부 초록이어도 직접 써 보면 다른 것이 나온다. 하네스는 아는 장면만 지킨다.
- 모든 요청이 지나가는 코드를 바꿨으면 성공·실패 말고 “본문 없음”, “기존 사용자”까지 확인한다.
- 일괄 치환 뒤에는 치환한 패턴이 아니라 남아 있으면 안 되는 것을 다시 센다.
- 두 클라이언트를 맞출 때는 화면이 아니라 데이터 모양부터.