결과부터: 파일 7개, 설치 가능 판정, 오프라인 동작
만든 앱은 “세 줄 루틴”입니다. 하루에 지킬 습관 세 개를 체크하고, 세 개를 모두 채운 날이 며칠 연속인지 보여 줍니다. 기록은 서버 없이 폰 브라우저에만 저장됩니다. 일부러 작게 잡았습니다. 첫 앱에서 로그인·결제·개인정보를 빼라는 건 바이브코딩 입문에서 정리한 원칙 그대로입니다.

| 확인 항목 | 결과 |
|---|---|
| 파일 수·크기 | 7개(HTML 1, JS 2, 매니페스트 1, 아이콘 3), 코드 217줄, 전체 32KB |
| 크롬의 설치 가능 판정 | 통과 (beforeinstallprompt 이벤트 발생) |
| 서비스 워커 | 활성화, 파일 7개 캐시 |
| 서버에 파일이 없을 때(404) 새로고침 | 정상 표시, 기록 유지 |
| 연속 일수 계산 테스트 | 7개 중 7개 통과 (월말·연말 경계 포함) |
| 파일 생성부터 로컬 검증까지 | 약 3분 (AI 에이전트 작업 시간, 사람의 검토 시간 제외) |
같은 앱을 techworklog.com/demo/three-habits에 올려 두었습니다. 안드로이드 크롬에서는 “홈 화면에 설치” 버튼이나 주소창 메뉴의 설치로, 아이폰은 공유 버튼 → “홈 화면에 추가”로 설치됩니다. 기록은 여러분 기기에만 남고 테크로그 서버로 오지 않습니다. 올리는 과정에서 한 번 막혔습니다. 로컬 미리보기 서버는 폴더 주소(/three-habits/)를 열지 못해 시작 주소를 index.html로 바꿨는데, 실제 호스팅(Cloudflare)은 반대로 index.html 요청을 폴더 주소로 리다이렉트했습니다. 서비스 워커가 리다이렉트된 응답을 캐시하면 오프라인에서 화면이 깨질 수 있어서, 시작 주소와 캐시 목록을 폴더 주소로 되돌리고 캐시 이름을 v2로 올렸습니다. 로컬에서 되던 게 호스팅에서 달라지는 전형적인 경우라, 올린 뒤에 실제 주소로 한 번 더 열어 보는 게 좋습니다.
“앱”에는 세 갈래가 있고 비용이 다릅니다
바이브코딩 도구 비교 글에서 도구를 먼저 고르지 말라고 했는데, 앱은 그보다 먼저 어떤 형태의 앱인지를 정해야 합니다. 형태에 따라 드는 돈과 기다리는 시간이 완전히 다릅니다.
| 형태 | 폰에 들어가는 방식 | 필수 비용 | 첫 배포까지 걸리는 것 |
|---|---|---|---|
| 설치형 웹앱(PWA) | 브라우저에서 홈 화면에 설치 | 0원 (HTTPS 호스팅만) | 파일 올리면 끝 |
| Expo(React Native) 테스트 | Expo Go 앱으로 내 폰에서 실행 | 0원 | 개발용. 남에게 배포하려면 결국 스토어 |
| 구글 플레이 출시 | 플레이스토어 설치 | 등록비 미화 25달러, 한 번 | 2023년 11월 13일 이후 만든 개인 계정은 테스터 12명이 14일 연속 비공개 테스트 후 프로덕션 신청 |
| 앱스토어 출시 | 앱스토어 설치 | 연 99달러 (Apple Developer Program) | 심사, iOS 빌드 환경 |
구글 플레이의 “12명·14일” 조건은 과소평가하기 쉽습니다. 코드는 하루 만에 나와도 스토어 출시는 최소 2주가 걸린다는 뜻이고, 테스터 12명을 모으는 것 자체가 일입니다. 그래서 첫 앱은 PWA로 내 폰과 주변 몇 명의 폰에 먼저 깔아 써 보고, 계속 쓸 만하면 스토어로 가는 순서가 비용 면에서 합리적입니다.
PWA가 설치되려면 조건이 있습니다. MDN 문서 기준으로 크롬·삼성 인터넷·엣지는 매니페스트에 name 또는 short_name, 192px과 512px 아이콘, start_url, display가 있어야 하고, 페이지는 HTTPS 또는 localhost로 열려야 합니다. 서비스 워커는 설치 조건은 아니지만 오프라인 동작에 필요합니다.

아이폰은 따로 기억할 게 있습니다. iOS에서는 설치 버튼을 띄우는 beforeinstallprompt 이벤트가 지원되지 않아서, 사용자가 공유 메뉴에서 직접 “홈 화면에 추가”를 눌러야 합니다. iOS 16.4부터는 사파리뿐 아니라 크롬·엣지·파이어폭스에서도 공유 메뉴로 설치할 수 있습니다.
실제로 준 프롬프트
이번 실험은 테크로그가 쓰는 AI 브라우저 Aside의 에이전트가 아래 요구사항을 받아 파일 작성부터 검증까지 진행했습니다. 코드는 한 줄도 손으로 고치지 않았고, 결과를 읽으며 검토할 지점을 따로 정리했습니다. 프롬프트에서 가장 신경 쓴 건 기능 목록보다 완료 조건입니다. “앱을 만들어 줘”로 끝내면 AI는 그럴듯한 화면을 내놓고 끝나지만, “브라우저가 설치 가능하다고 판정할 것”이라고 적으면 매니페스트와 아이콘 크기까지 챙깁니다.
휴대폰 홈 화면에 설치되는 습관 체크 앱을 만들어줘.
기능
1) 하루에 체크할 항목 3개를 사용자가 정한다
2) 오늘 체크 여부와 "세 개 모두 채운 날"의 연속 일수를 보여준다
3) 최근 7일을 한 줄로 보여준다
제약
- 서버 없이 기기 브라우저에만 저장
- 파일은 index.html, 매니페스트, 서비스 워커, 아이콘만. 빌드 도구 없이
- 날짜는 한국 시간 기준으로 바뀌어야 한다
완료 조건
- localhost에서 크롬이 설치 가능하다고 판정한다(beforeinstallprompt 발생)
- 서버에서 파일을 치운 뒤 새로고침해도 열리고 기록이 남는다
- 연속 일수 계산은 Node로 테스트한다(월말·연말 경계 포함)
“날짜는 한국 시간 기준”이라는 한 줄은 일부러 넣었습니다. 아래 “검토할 곳”에서 이유를 설명합니다.
만들어진 파일과 역할
| 파일 | 줄 수 | 하는 일 |
|---|---|---|
| index.html | 141 | 화면, 체크 저장(localStorage), 설치 버튼, 서비스 워커 등록 |
| streak.js | 38 | 날짜 키 만들기, 연속 일수 계산. 브라우저와 Node 테스트가 같이 씀 |
| sw.js | 22 | 처음 열 때 파일 7개를 캐시하고 이후 캐시를 먼저 사용 |
| manifest.webmanifest | 16 | 앱 이름, 아이콘 192·512, display: standalone |
| 아이콘 3개 | 192·512(안드로이드), 180(아이폰 홈 화면) |
빌드 도구도 프레임워크도 없습니다. 첫 앱에 React나 Expo를 붙이지 않은 이유는 단순합니다. 파일이 적을수록 AI가 만든 결과를 사람이 끝까지 읽을 수 있습니다. 이 블로그 자체를 AI로 만든 과정(바이브코딩 블로그 제작기)에서도 “검토 가능한 크기”가 가장 중요한 기준이었습니다.
설치 가능 판정과 오프라인 검증
검증은 프롬프트의 완료 조건을 그대로 순서대로 확인했습니다. 로컬 서버(python3 -m http.server)로 띄우고 크롬 계열 브라우저로 열었습니다.

오프라인 확인 방법은 이렇게 했습니다. 앱을 한 번 연 뒤 서버 폴더에서 앱 파일을 치웠더니 curl로 요청한 주소가 404를 돌려줬습니다. 그 상태에서 브라우저를 새로고침해도 앱이 그대로 열렸고, 체크해 둔 세 항목과 “1일 연속”이 남아 있었습니다. 화면은 서비스 워커 캐시에서, 기록은 localStorage에서 온 것입니다.
설치 가능 판정은 beforeinstallprompt 이벤트로 확인했습니다. MDN 설명대로 이 이벤트는 브라우저가 설치 조건을 충족했다고 판단했을 때 발생하고, 앱은 이걸 받아 자체 “홈 화면에 설치” 버튼을 띄웁니다. 이벤트가 오지 않았다면 버튼도 나타나지 않았을 것입니다.
테스트를 통과해도 검토할 곳 세 군데
AI가 만든 코드가 테스트를 통과해도 따로 확인해야 할 지점이 남습니다. 이번 결과물에서는 세 군데였고, 둘은 테스트로는 드러나지 않는 종류입니다.
1. 날짜를 UTC로 자르는 함정. 자바스크립트에서 날짜 문자열을 만들 때 흔히 쓰는 toISOString().slice(0, 10)은 UTC 기준입니다. 한국은 UTC보다 9시간 빠르므로 오전 9시 전에 체크하면 전날 기록으로 들어갑니다. 위 로그에서 9월 29일 오전 8시 30분이 2026-09-28로 찍힌 게 그 예입니다. 이번 결과물은 getFullYear()·getMonth()·getDate()로 로컬 날짜를 만들어 이 문제를 피했습니다. 프롬프트에 “한국 시간 기준”을 적은 이유이고, 날짜가 들어간 AI 코드를 검토할 때 가장 먼저 볼 곳입니다. 같은 종류의 날짜 경계 문제는 구글 앱스 스크립트 자동화 글에서도 다뤘습니다.
2. 캐시를 먼저 쓰면 업데이트가 안 퍼집니다. 서비스 워커가 캐시를 먼저 보여 주는 방식이라 오프라인에는 강하지만, 코드를 고쳐 다시 올려도 이미 설치한 사람은 옛 파일을 계속 봅니다. 새 버전을 내보내려면 sw.js의 캐시 이름(three-habits-v1)을 v2로 바꿔야 새 파일을 받습니다. 테스트로는 드러나지 않는 운영 문제라 만든 사람이 알고 있어야 합니다.
3. 기록이 기기 브라우저에만 있다는 것의 의미. 서버가 없으니 개인정보 걱정은 없지만, 브라우저 데이터를 지우거나 폰을 바꾸면 기록이 사라집니다. 다른 기기와 동기화하려면 로그인과 서버가 필요해지고, 그 순간 첫 앱의 범위를 넘어섭니다. 이 한계를 사용자에게 알리려고 화면 아래에 “이 기기의 브라우저에만 저장” 문구를 넣었습니다.
PWA로 부족할 때, 스토어로 가는 길
PWA로 충분한 경우나와 지인이 쓰는 도구, 사내용 체크리스트, 기록·계산기류. 설치·오프라인·홈 화면 아이콘이 필요하고 스토어 검색 노출은 필요 없을 때.
플레이스토어로 가는 경우검색으로 모르는 사람에게 발견돼야 할 때. MDN은 설치 조건을 갖춘 PWA를 PWABuilder로 포장해 스토어에 올리는 방법을 안내합니다. 비용은 25달러 한 번이지만 12명·14일 테스트를 먼저 채워야 합니다.
앱스토어로 가는 경우아이폰 사용자를 스토어에서 받아야 할 때. 연 99달러이고, 매년 갱신해야 스토어에 남습니다.
처음부터 네이티브가 필요한 경우블루투스·백그라운드 위치처럼 브라우저가 못 여는 기기 기능이 핵심이라면 Expo(React Native)로 시작하세요. Expo Go 앱으로 내 폰에서 바로 확인하면서 만들 수 있습니다.
어느 경우든 바이브코딩 도구의 역할은 같습니다. 완료 조건을 문장으로 주고, 결과를 조건대로 검증하는 것입니다. 에디터형·터미널형·웹앱 생성형 도구의 차이는 바이브코딩 툴 비교에 정리해 두었습니다. 웹앱 생성형 도구로 만든 결과물도 매니페스트와 아이콘만 갖추면 같은 방식으로 PWA가 됩니다.
자주 묻는 질문
코딩을 전혀 몰라도 이 정도는 되나요?
파일을 만드는 건 AI가 합니다. 다만 “설치 가능한지”, “서버 없이 열리는지”를 확인하는 방법은 알아야 합니다. 이 글의 완료 조건을 그대로 복사해 쓰면 AI가 검증 단계까지 해 줍니다.
PWA도 푸시 알림이 되나요?
안드로이드는 오래전부터 되고, 아이폰은 iOS 16.4부터 홈 화면에 설치한 웹앱에서 가능해졌습니다. 다만 알림은 서버에서 보내야 하므로 이번처럼 서버 없는 앱의 범위를 넘습니다.
설치 버튼이 안 떠요.
아이폰이라면 정상입니다. 공유 메뉴에서 “홈 화면에 추가”를 쓰세요. 안드로이드 크롬인데 안 뜬다면 HTTPS 여부, 매니페스트의 192·512 아이콘, display 값을 먼저 확인하세요. 이미 설치했다면 버튼은 다시 뜨지 않습니다.
앱 이름과 아이콘을 바꾸고 싶어요.
매니페스트의 name과 아이콘 파일을 바꾸고, 서비스 워커 캐시 이름도 올려야 이미 설치한 기기에 반영됩니다.
스토어 등록비 말고 드는 돈은요?
무료 앱이라면 스토어 수수료는 없습니다. 유료 판매나 인앱 결제를 하면 스토어 수수료가 붙고, 조건과 지역에 따라 비율이 다릅니다.
2026년 9월 29일 MDN의 Making PWAs installable, Apple Developer Program 안내, Google Play Console 도움말(Play Console 시작하기, 새 개인 개발자 계정의 앱 테스트 요구사항), Expo 개발 환경 설정 문서를 직접 확인했습니다. 앱은 같은 날 직접 만들어 macOS의 크롬 계열 브라우저와 로컬 서버에서 설치 가능 판정·오프라인 새로고침·연속 일수 테스트를 실행했습니다. 실제 안드로이드·아이폰 기기에 설치해 본 결과는 이 글에 포함하지 않았고, 스토어 출시 과정도 직접 진행하지 않았습니다.
MDN · Making PWAs installable ↗ · Apple Developer Program ↗ · Play Console 시작하기 ↗ · 새 개인 개발자 계정 테스트 요구사항 ↗ · Expo 개발 환경 설정 ↗