프로젝트
iOS · 1인 출시 · Lunarc

LunarcAI가 틀려도 화면은 깨지지 않게

시간 블록으로 하루를 설계하는 iOS 앱을 혼자 출시해 운영합니다. LLM 기능 2종을 붙이면서 시간 대부분을 모델 바깥의 경계와 검증에 썼습니다.

투데이 화면
투데이오늘 남은 시간과 살아온 날을 한 화면에. 취침까지 남은 시간이 호로 줄어듭니다.
스케줄 화면
스케줄하루를 시간 블록으로 설계합니다. 주 단위로 한눈에 봅니다.
매트릭스 화면
매트릭스할 일을 중요 · 계획 · 위임 · 보류 네 칸으로 나눕니다.
주간 회고 화면
주간 회고좋았던 것부터 다음 주의 나에게 쓰는 편지까지, 한 주를 돌아봅니다.

App Store에서 보기 ↗

  • 11개국마케팅 없이 설치 · 현지화 뒤 해외 비중 32% → 76%
  • 204건번역 모델 A/B를 행 단위로 판정
  • 월 $0출시 2~4개월 지연을 감수한 백엔드 이관 뒤 운영비

1인 전담 · 기획 · 디자인 · 개발 · 출시 · 운영2026.03 ~ 현재 · App Store 출시 2026.07.15Swift · Cloudflare Workers · D1 · Workers AI

TL;DR

문제

LLM 기능은 프롬프트만으로 막을 수 없는 비용 · 오염 · 절단 · 장애를 함께 가져왔습니다.

한 일

기획부터 출시 · 운영까지 혼자 맡아 모델 바깥의 경계 · 모델 평가 · 백엔드 이관을 설계하고 판정했습니다.

결과

11개국에 설치되고 현지화 뒤 해외 비중이 32%에서 76%로 바뀌었습니다. 운영비 월 $0 · 인젝션 영향은 본인 행 1건.

대표 사례

면접에서 가장 먼저 이야기하고 싶은 세 가지

AI 신뢰 경계

모델을 부르는 일보다 그 바깥을 막는 일이 대부분이었다

주간 리포트의 일정 자동 분류. 사용자가 쓴 제목이 그대로 프롬프트에 들어가고 모델이 낸 값을 그대로 쓰면 데이터가 오염됩니다. 프롬프트만으로는 막을 수 없어 호출 바깥에 경계를 다섯 겹 두었습니다.

  1. 비용 상한분류가 빈 행만 추론 · 상한이 쿼리 조건에서 성립
  2. 누락 채움응답에 빠진 행은 기타로 채워 재추론 누수를 막음
  3. 출력 불신화이트리스트 밖은 기타, 요청하지 않은 id는 폐기
  4. 토큰 역산항목당 5~8토큰으로 상한을 역산해 응답 절단 제거
  5. 실패해도 렌더500 대신 degraded, 실패 경로 4종을 따로 기록
  6. LLM 호출Workers AI

인젝션이 성공해도 영향은 본인 행 1건 · 추론은 사용자당 주 1회 · AI 장애가 리포트 장애로 번지지 않음

CASE-05 전체 읽기 →

모델 평가

번역 모델을 감이 아니라 표로 골랐다

사용자가 쓴 한 줄 다짐을 다른 언어로 보여 주는 기능. 전용 번역 모델이 나을 거라는 직관이 있었지만 근거가 없어 전량을 돌려 한 표에 놓고 판정했습니다.

51문장×2언어×2모델=204건
후보품질비용판정
전용 번역 모델m2m100뜻이 뒤집히거나 원문을 그대로 통과새 비용 라인탈락
범용 LLMllama-3.3-70b한↔일에서만 문자 섞임 → 가드로 보정이미 쓰던 모델 · 추가 0채택

평가에서 나온 실패가 그대로 출력 가드가 됐습니다

  1. 요청문장 단위
  2. D1 캐시 조회있으면 바로 반환
  3. Workers AI 호출없을 때 · 예산 1.5초
  4. 출력 게이트길이 · 문자 체계 · 원문 누출 · 욕설
  5. 캐시 저장예산 초과분은 백그라운드로
  6. 실패하면 원문피드는 막지 않음

직관이 틀렸습니다. 전용 모델 탈락 · 지연 p50 832ms / p95 1,595ms · 새 비용 라인 0

CASE-07 전체 읽기 →

제품 판단

출시를 미루고 백엔드를 전면 이관했다

출시 직전, 상시 인스턴스 구성은 사용자가 없어도 고정비가 들고 콜드스타트가 남았습니다. 지연 자체를 비용으로 적고 세 안을 비교했습니다. 14개 모듈은 한 번에 옮기지 않고 단계별로 이관했습니다.

선택지비용리스크
현행 유지 후 출시즉시 출시 가능고정비 지속 · 콜드스타트
BaaS 전환구현량 최소인증 · 결제 로직이 벤더에 종속
Workers + D1선택출시 2~4개월 지연엣지 런타임 제약 · 이관 중 유실

이관 뒤 구조

iOS 앱SwiftUI · WidgetKit · StoreKit 2
Cloudflare WorkersHono · 인증 · API
D1 · KV일정 · 캐시 · 원장
Workers AI주간 활동 분류 · 읽기 시 번역

운영비 월 $0 · 이관 중 서비스 중단 0 · 데이터 유실 0

CASE-01 전체 읽기 →

출시 뒤 바꾼 화면

장식 대신 다짐으로 들어가는 길

Lunarc v1.1 투데이 화면
v1.1위쪽 170pt를 별무리 장식이 차지했고 다른 사람의 다짐은 별무리를 눌러야 열렸습니다.
Lunarc v1.3 투데이 화면
v1.3장식을 걷어내고 탭바 위 손잡이를 위로 쓸면 다짐을 한 장씩 넘겨 봅니다. 읽기는 쓰기보다 싼 행동이라 들어가는 문턱부터 낮췄습니다.

티켓 LTV130-002 · 두 화면 모두 App Store에 올린 실제 스크린샷

일하는 방식

티켓 하나가 커밋까지 이어집니다

버전마다 스프린트 보드를 열고 문제를 티켓으로 적고 티켓 코드를 커밋과 PR에 남겼습니다. 코드 검색 한 번이면 티켓에서 커밋까지 거슬러 갈 수 있습니다. 완료는 자동 검증 통과만으로 정하지 않고 화면 확인과 판정이 남은 항목은 확인 목록으로 따로 넘겼습니다.

스프린트별 티켓 수 · 2026.07.15 출시 이후 · 날짜는 종료일

  • 7V1.01~07.18
  • 4V1.02~07.22
  • 27V1.10~07.31
  • 18V1.20~08.14
  • 15V1.30~09.03
  • 6V1.40~09.09
  • 32V1.50진행 중

추적 예시 · 결함 1건

  1. Obsidian 티켓

    [LTV150-034]

    할 일 생성이 스트립 선택일을 무시하고 오늘로 저장된다

  2. Pull Request

    #770

    리뷰 · 테스트 통과 뒤 머지

  3. 커밋 · 2026.09.22

    ce5358b

    fix(ios): 할 일 생성 시트는 스트립 선택일로 시작한다 (LTV150-034)

  • 109티켓
  • 7스프린트
  • 177티켓 코드가 남은 커밋

그 밖의 결정

문제 → 결정 → 결과

한계

하지 않은 것과 그 이유

  • 규모누적 다운로드 44. 대규모 트래픽을 운영해 본 적이 없어 스테이징에서 한계를 미리 쟀습니다 — 300 RPS에서 p95 144ms · 오류 0, 저하는 500~750 RPS 구간(단일 발신 기준).
  • RAG쓰지 않았습니다. 분류와 번역 모두 외부 문서를 검색할 필요가 없는 문제였습니다.
  • 협업혼자 만든 제품이라 팀 리뷰 대신 모델을 바꿔 같은 PR을 다시 읽는 교차 검증을 두었습니다.
연락
김성재 사진

함께 일할 팀을 찾고 있습니다

AI 엔지니어 · AX 엔지니어 정규직 포지션에 지원하고 있습니다. 편하게 메일 주세요.