TASK-003: 기능을 붙이기 전에, 전체 화면을 먼저 만들었습니다

goodtek은 Build in Public 방식으로 vibePulse SaaS를 만들고 있습니다. TASK-003에서는 기능을 하나씩 붙이기 전에, 출시까지 필요한 전체 화면의 흐름을 먼저 그렸습니다. DESIGN.md로 일관성을 유지하면서도 기능 범위와 연결 구조를 더 선명하게 확인한 프론트 구현 기록입니다.

Share
TASK-003: 기능을 붙이기 전에, 전체 화면을 먼저 만들었습니다
TASK-003 기능 전 전체 화면 설계

goodtek은 지금 Build in Public 방식으로 vibePulse라는 SaaS를 만들고 있습니다.

vibePulse는 바이브코더를 위한 업타임 모니터링 SaaS입니다. 배포한 웹앱이 살아 있는지, cron이나 봇 같은 백그라운드 작업이 멈추지 않았는지 확인하고, 문제가 생기면 Telegram, Discord, Slack, KakaoTalk 같은 채널로 알려주는 제품으로 만들고 있습니다.

개발 중인 사이트는 아래 주소에서 직접 확인할 수 있습니다.

https://dev-vibepulse.goodtek.xyz

개발 사이트 바로 가기

아직 완성된 서비스는 아닙니다. 로그인도 붙는 중이고, 대시보드도 실제 데이터와 연결되기 전입니다. 하지만 저는 이 상태도 일부러 공개하고 있습니다. 완성된 결과물만 보여주기보다, 어떤 순서로 판단하고, 왜 그렇게 만들었는지를 남기는 것이 goodtek의 Build in Public 방식이기 때문입니다.

여정을 함께하고 싶으시거나 제품 개발 방향에 건의 사항이나 의견이 있으시면 어떤 방식으로든 연락 주세요!

이번 기록은 vibePulse의 TASK-003입니다.

처음에는 기능부터 하나씩 붙일 수도 있었습니다. 로그인 기능을 만들면서 로그인 화면을 만들고, 대시보드 기능을 만들면서 대시보드 화면을 만들고, 알림 기능을 만들면서 알림 설정 화면을 만드는 식입니다.

그런데 이번에는 그렇게 하지 않았습니다.

저는 먼저 출시까지 필요한 전체 화면의 껍데기를 구현했습니다.

기능을 완성한 것이 아니라, 기능이 들어갈 자리를 먼저 그렸습니다. 마케팅 랜딩, 요금제, 헤더와 푸터, 시작 방식 안내, 상태 카드 UI, 다국어 구조, 브랜드 아이콘, 그리고 앞으로 붙을 기능들이 들어올 전반적인 디자인 방향을 먼저 세웠습니다.

이번 TASK-003은 “기능 구현”이라기보다, 기능을 담을 제품의 첫 화면 구조를 세운 작업이었습니다.

기능부터 붙이는 길도 있었습니다

처음에는 저도 기능 단위로 가는 방식이 더 자연스럽다고 생각했습니다.

로그인 화면을 만들고 Better Auth를 붙입니다.
온보딩 화면을 만들고 첫 모니터 등록 기능을 붙입니다.
대시보드를 만들고 실제 API 데이터를 연결합니다.
알림 설정 화면을 만들고 Telegram이나 Discord 연동을 붙입니다.

이렇게 하면 한 TASK마다 “실제로 동작하는 것”이 생깁니다. 진행 상황도 분명해 보입니다. 특히 혼자 만드는 SaaS에서는 이런 방식이 심리적으로 좋습니다. 버튼을 눌렀을 때 뭔가 작동하면, “그래도 앞으로 가고 있다”는 느낌이 생기기 때문입니다.

하지만 동시에 걱정도 있었습니다.

기능별로 화면을 만들면, 각 화면은 그럭저럭 좋아 보일 수 있습니다. 문제는 나중에 전체를 이어봤을 때입니다. 로그인 화면의 밀도, 대시보드 카드의 느낌, 요금제 페이지의 톤, 상태 페이지의 정보 구조가 조금씩 달라질 수 있습니다.

그때 가서 전체 디자인을 맞추려면 다시 왔다 갔다 해야 합니다.

기능부터 붙이는 방식
├─ 로그인 기능 + 로그인 화면
├─ 대시보드 기능 + 대시보드 화면
├─ 알림 기능 + 알림 화면
└─ 나중에 전체 흐름과 디자인 정리

이번에 선택한 방식
├─ 출시까지 필요한 화면을 먼저 나열
├─ 메뉴별 화면 껍데기를 먼저 구현
├─ 전체 디자인 톤과 구조 확인
└─ 다음 TASK부터 기능을 하나씩 입히기

둘 중 어느 방식이 항상 정답이라고 생각하지는 않습니다. 다만 이번 vibePulse 단계에서는 후자가 더 맞다고 판단했습니다.

아직 제품의 기능이 고정되지 않았고, 사용자 흐름도 계속 바뀔 가능성이 컸습니다. 그래서 기능을 깊게 파기 전에, 먼저 전체 화면을 펼쳐놓고 보는 편이 낫다고 봤습니다.

DESIGN.md가 있어도 전체 흐름은 따로 봐야 했습니다

vibePulse에는 DESIGN.md가 있습니다.

이 문서에는 색상, 타이포그래피, 컴포넌트 사용 방식, 간격, 카드 스타일, 다크 모드 기준 같은 디자인 규칙을 정리해두었습니다. AI와 함께 화면을 만들 때도 이 문서를 기준으로 삼으면 일정 수준의 일관성은 유지할 수 있습니다.

그래서 처음에는 이렇게 생각했습니다.

“기능별로 화면을 만들어도 DESIGN.md가 있으니 괜찮지 않을까?”

어느 정도는 맞습니다. 버튼 색이 갑자기 달라지거나, 카드 radius가 제멋대로 바뀌거나, 페이지마다 폰트 크기가 심하게 튀는 문제는 줄일 수 있습니다.

그런데 실제로 생각해보니 DESIGN.md가 해결하지 못하는 영역이 있었습니다.

기준

DESIGN.md로 잡을 수 있는 것

직접 화면을 그려야 보이는 것

색상

primary, background, border 토큰

어느 화면에서 오렌지를 얼마나 써야 하는지

컴포넌트

버튼, 카드, 배지의 기본 형태

어떤 패턴을 반복해야 제품처럼 보이는지

간격

section padding, grid gap

화면을 이어봤을 때 밀도가 맞는지

타이포그래피

제목, 본문, caption 크기

사용자가 어디서 먼저 읽어야 하는지

정보 구조

기본 레이아웃 규칙

메뉴 간 이동 흐름과 기능 연결

제품 감각

브랜드 톤

“이게 vibePulse답다”는 전체 인상

결국 DESIGN.md는 규칙입니다. 하지만 제품의 흐름은 규칙만으로 나오지 않았습니다.

로그인 화면이 혼자 있을 때 괜찮아도, 랜딩 페이지에서 가입 버튼을 누른 뒤 이어지는 화면으로 자연스러운지는 직접 봐야 합니다. 대시보드 카드가 예뻐도, 상태 페이지의 카드와 같은 제품처럼 보이는지는 나란히 놓고 봐야 합니다.

디자인 규칙은 일관성을 지켜주지만, 전체 화면 설계는 제품의 방향을 보여줍니다.

이번 TASK-003은 그 차이를 확인한 작업이었습니다.

출시까지 필요한 화면을 먼저 펼쳐봤습니다

출시까지 필요한 전체화면 설계

이번 작업에서 저는 “지금 당장 구현할 기능”보다 “출시까지 필요한 화면”을 먼저 봤습니다.

vibePulse의 첫 출시를 생각하면 필요한 화면이 꽤 많습니다.

vibePulse 출시 범위 화면
├─ 마케팅 랜딩
├─ 요금제
├─ 로그인 / 가입
├─ 온보딩
├─ 대시보드
├─ 모니터 관리
├─ 알림 설정
├─ 공개 상태 페이지
└─ 공통 헤더 / 푸터 / 네비게이션

이번 TASK-003에서 이 모든 화면을 완성한 것은 아닙니다. 실제 기능도 아직 대부분 붙지 않았습니다.

하지만 적어도 마케팅 셸과 핵심 UI의 방향은 잡았습니다. 사용자가 처음 들어왔을 때 어떤 제품인지 이해할 수 있어야 했고, 다음 TASK에서 로그인과 온보딩을 붙였을 때 화면이 따로 놀지 않아야 했습니다.

처음에는 이 작업이 조금 돌아가는 길처럼 느껴졌습니다.

기능을 붙이지 않고 화면을 먼저 만든다는 게, 개발자로서는 어쩐지 덜 실질적인 작업처럼 느껴질 때가 있습니다. “버튼도 아직 안 되는데 이게 진척인가?” 싶은 순간도 있었습니다.

그런데 브라우저에서 화면을 보면서 생각이 바뀌었습니다.

화면을 먼저 그려보니 기능의 범위가 더 잘 보였습니다.
요금제를 만들다 보니 플랜 제한이 보였습니다.
상태 카드 UI를 만들다 보니 필요한 데이터가 보였습니다.
시작 방식 섹션을 만들다 보니 온보딩 질문이 보였습니다.
다국어 URL을 정리하다 보니 공유 URL과 시스템 URL의 경계가 보였습니다.

즉, 프론트 껍데기가 단순한 장식이 아니었습니다.

기능 설계를 다시 묻게 만드는 도구였습니다.

마케팅 랜딩은 “예쁜 첫 화면”이 아니라 제품 설명의 기준이었습니다

vibePulse 랜딩페이지 초안

이번 TASK에서 가장 먼저 잡은 것은 마케팅 랜딩의 흐름이었습니다.

vibePulse는 업타임 모니터링 SaaS지만, 단순히 “URL을 감시합니다”라고만 말하면 너무 평범합니다. 이미 업타임 모니터링 도구는 많습니다. 그래서 vibePulse가 누구를 위한 제품인지 더 분명히 해야 했습니다.

핵심 사용자는 혼자 또는 소규모로 서비스를 만드는 바이브코더입니다. 밤에 Cursor로 기능을 만들고, cron을 돌리고, 작은 봇을 운영하고, 배포 후에 “이거 아직 살아 있나?”를 계속 확인해야 하는 사람입니다.

그래서 히어로 문장도 그 맥락에서 잡았습니다.

밤새 바이브코딩한 그 앱, 혼자 죽게 두지 마세요.

이 문장은 기술 설명보다 상황을 먼저 보여줍니다. “업타임 모니터링”이라는 기능보다, 사용자가 실제로 겪는 불안을 먼저 건드립니다.

다만 여기서도 과하게 감성적으로 흐르지 않으려고 했습니다. vibePulse는 결국 도구입니다. 그래서 바로 옆에는 상태 카드 UI를 두었습니다. 감정적인 문장과 실제 제품 UI가 같이 있어야 신뢰가 생긴다고 봤습니다.

데모 카드에는 일부러 “느려짐”을 넣었습니다

히어로 오른쪽의 상태 카드 UI는 실제 데이터와 연결된 것은 아닙니다. 아직은 프론트 데모입니다.

그런데 이 데모를 만들 때도 고민이 있었습니다.

처음에는 모든 모니터를 정상 상태로 보여주면 깔끔할 것 같았습니다. 초록색 막대가 쭉 이어지고, “모든 서비스 정상”이라고 보여주면 안정적으로 보입니다.

하지만 업타임 모니터링 제품에서 전부 정상인 화면은 의외로 약했습니다.

사용자가 궁금한 것은 “정상일 때 예쁜가?”가 아니라 “문제가 생기면 내가 알아챌 수 있는가?”였습니다.

그래서 하나의 서비스는 느려진 상태로 넣었습니다.

데모 요소

구현한 방향

이유

전체 상태

서비스 1개 느려짐 감지

제품의 감지 가치를 보여주기 위해

모니터 목록

정상 / 느려짐 상태 혼합

전부 초록인 화면의 밋밋함을 줄이기 위해

응답 속도

240ms, 980ms 등 표시

느려짐이 숫자로도 보이게 하기 위해

히스토리 막대

초록, 노랑, 빨강 혼합

최근 상태 흐름을 한눈에 보이게 하기 위해

마지막 확인

12초 전, 2분 전

계속 감시 중이라는 느낌을 주기 위해

이것은 기능 구현은 아닙니다. 하지만 앞으로 실제 대시보드를 만들 때 무엇을 보여줘야 하는지 알려주는 기준이 됐습니다.

가짜 데이터를 넣더라도, 가짜 방향을 잡으면 안 된다고 느꼈습니다.
데모 UI는 껍데기였지만, 그 안에 넣은 판단은 실제 제품 기준이었습니다.

시작 방식 섹션에서 온보딩 범위가 보였습니다

vibePulse는 사용자가 서비스를 등록하는 방식이 하나만 있지 않습니다.

URL만 넣고 감시할 수도 있고, cron이나 봇에서 신호를 보내게 할 수도 있습니다. 바이브코더라면 Cursor나 Claude Code에 안내를 붙여넣고 연결하도록 도울 수도 있습니다.

처음에는 이걸 단순히 “세 가지 방법”으로 보여주면 된다고 생각했습니다. 그런데 화면으로 만들다 보니 중요한 차이가 보였습니다.

이 세 가지는 순서가 아니었습니다.

사용자가 모두 따라 해야 하는 단계가 아니라, 자기 상황에 맞게 하나를 고르는 선택지였습니다.

시작 방식
├─ 주소로 확인
│  └─ 배포된 URL만 넣고 감시 시작
├─ 바이브 설치
│  └─ Cursor, Claude Code, Codex에 안내 붙여넣기
└─ 직접 설치
   └─ 폼과 가이드를 보고 직접 연결

그래서 제목을 “세 가지로 시작하세요”가 아니라 **“어떻게 시작할까요?”**로 잡았습니다.

이 문장은 작지만 중요했습니다. 사용자가 해야 할 일을 명령하는 느낌보다, 사용자의 상황을 먼저 묻는 느낌이었습니다.

그리고 이 섹션을 만들면서 온보딩 기능의 범위도 더 분명해졌습니다.

앞으로 온보딩에서는 사용자가 먼저 “무엇을 지킬지”를 고르고, 그다음 감시 방식을 선택하고, 주기와 알림 채널을 설정하고, 마지막으로 테스트한 뒤 켜는 흐름이 필요합니다.

즉, 랜딩 페이지의 작은 섹션이 다음 TASK의 온보딩 설계로 이어졌습니다.

카피를 바꾸면서 기능 난이도도 낮아졌습니다

이번 작업에서 의외로 시간을 쓴 부분은 단어였습니다.

개발 중에는 probe, ping, heartbeat, degraded 같은 단어를 자연스럽게 씁니다. 내부적으로는 정확한 표현입니다. 하지만 마케팅 페이지나 온보딩 화면에 그대로 노출하면 사용자가 느끼는 난이도가 올라갑니다.

저도 처음에는 별생각 없이 썼습니다. 그런데 화면으로 보니 제품이 갑자기 인프라 도구처럼 멀어졌습니다.

vibePulse는 개발자를 위한 제품이지만, 모든 사용자가 모니터링 용어에 익숙하다고 가정하면 안 됐습니다. 특히 바이브코더라면 앱은 만들고 있지만, 관측성이나 인프라 용어에는 낯설 수 있습니다.

그래서 화면에서는 사용자 언어로 바꾸기 시작했습니다.

내부에서 편한 말

화면에 쓴 말

바꾼 이유

URL Probe

주소로 확인

사용자가 할 행동이 바로 보입니다

ping

신호 / 코드 한 줄

개발자 은어 느낌을 줄였습니다

degraded

느려짐

상태 의미가 바로 전달됩니다

test ping

잘 되는지 테스트

다음 행동이 분명해집니다

monitor target

지킬 대상

사용자가 왜 등록하는지 먼저 보입니다

이 과정에서 느낀 것이 있습니다.

카피는 장식이 아니라, 기능의 진입 장벽을 낮추는 UI였습니다.

같은 기능이어도 어떤 단어로 보여주느냐에 따라 사용자가 느끼는 난이도는 달라졌습니다.

요금제 페이지를 먼저 만든 이유

요금제 페이지 초안

이번 TASK에서는 실제 결제 기능이 없습니다. Stripe도 아직 붙지 않았고, 플랜 제한도 코드로 강제하지 않았습니다.

그런데 요금제 페이지는 먼저 만들었습니다.

처음에는 이게 조금 이른 작업처럼 느껴졌습니다. 실제 결제도 없는데 가격표를 먼저 만드는 게 맞나 싶었습니다.

하지만 요금제는 결제 기능만의 문제가 아니었습니다. 제품의 약속을 정하는 페이지였습니다.

Free에서 어디까지 줄 것인지. Starter와 Pro는 어떤 차이를 둘 것인지. Team은 지금 바로 받을 것인지, 준비 중으로 둘 것인지. 모니터 수와 기록 보관 기간은 어느 정도가 현실적인지.

이런 질문을 요금제 페이지를 만들면서 다시 보게 됐습니다.

플랜

가격

모니터

확인 주기

기록

Free

$0

1개

10분

7일

Starter

$9

10개

5분

14일

Pro

$19

30개

1분

30일

Team

$29

50개+

30초

90일

처음에는 더 큰 숫자를 넣고 싶은 마음도 있었습니다. SaaS 요금제에서 숫자가 커 보이면 좋아 보입니다. 하지만 업타임 모니터링은 서버 자원을 계속 쓰는 제품입니다. 확인 주기와 모니터 수는 곧 비용입니다.

그래서 보수적으로 잡았습니다.

마케팅 숫자는 그냥 숫자가 아니라, 나중에 인프라가 감당해야 할 약속입니다.

이 판단은 기능 구현보다 앞서 필요했습니다. 대시보드에서 모니터 생성 제한을 어떻게 둘지, 기록 보관을 어떻게 설계할지, 알림 채널을 플랜별로 어떻게 나눌지에 영향을 주기 때문입니다.

알림 채널도 제품 방향을 보여줬습니다

초기에는 Email이나 Webhook도 당연히 요금제에 넣어야 하나 고민했습니다. 모니터링 도구라면 Email 알림은 익숙한 기능입니다.

그런데 vibePulse의 초기 사용자를 다시 생각해보니 우선순위가 달라졌습니다.

혼자 만들고 있는 바이브코더가 실제로 빨리 반응하는 채널은 이메일보다 채팅일 가능성이 높습니다. Telegram, Discord, Slack, KakaoTalk 같은 채널이 더 직접적입니다.

그래서 런칭 초반에는 채팅 알림을 우선으로 정리했습니다. Email과 Webhook은 후순위로 뺐습니다.

이것도 단순한 UI 선택이 아니었습니다. 제품이 누구를 먼저 돕는지에 대한 결정이었습니다.

선택지

판단

Email 우선

전통적인 모니터링 도구 느낌은 있지만 초기 타깃과 거리가 있었습니다

Webhook 전면 노출

확장성은 있지만 초반 사용자에게는 복잡할 수 있었습니다

Telegram / Discord 우선

혼자 운영하는 바이브코더에게 더 즉각적이라고 봤습니다

Slack / KakaoTalk 확장

팀과 국내 사용자 맥락을 함께 고려했습니다

기능은 아직 구현하지 않았지만, 프론트에 어떤 채널을 먼저 보여줄지 정하면서 제품의 우선순위가 더 선명해졌습니다.

i18n URL은 지금 정하지 않으면 나중에 흔들릴 문제였습니다

이번 TASK에서는 next-intl 기반으로 한국어와 영어 구조도 잡았습니다.

단순히 번역 파일을 나누는 것보다 더 중요했던 건 URL 전략이었습니다.

한국어가 기본인 서비스에서 모든 경로에 /ko가 붙으면 조금 어색합니다. 그래서 기본 locale인 한국어는 prefix 없이 가고, 영어만 /en을 붙이는 방식으로 정리했습니다.

사람이 보는 페이지
├─ /pricing
└─ /en/pricing

시스템이 호출하거나 공유되는 URL
├─ /s/my-app
├─ /ping/abc123
└─ /api/...

여기서 더 중요한 건 “사람이 보는 페이지”와 “시스템이 쓰는 URL”을 나눈 것입니다.

상태 페이지 URL이나 ping URL은 사용자가 README, 환경 변수, 문서에 붙여넣을 수 있습니다. 이런 URL에 /ko/en이 붙으면 나중에 언어 설정과 공유 경로가 섞입니다.

그래서 원칙을 정했습니다.

  • 마케팅 페이지는 locale을 가질 수 있습니다.
  • 한국어 기본 페이지는 prefix 없이 둡니다.
  • 영어 페이지는 /en으로 둡니다.
  • 발급 URL과 API URL은 locale 밖에 둡니다.

이 결정은 지금 당장 눈에 띄는 기능은 아닙니다. 하지만 나중에 바꾸려면 비용이 큽니다. 그래서 TASK-003에서 미리 정리했습니다.

favicon과 브랜드 아이콘도 껍데기의 일부였습니다

이번 작업에서는 favicon과 브랜드 아이콘도 정리했습니다.

작은 일처럼 보입니다. 실제 모니터링 기능과 직접 연결되지도 않습니다. 하지만 개발 중인 사이트를 브라우저 탭에 띄워놓고 보니 아이콘이 없는 상태가 계속 신경 쓰였습니다.

제품은 사용자가 보는 모든 작은 신호로 신뢰를 만듭니다. 헤더의 로고, 탭의 favicon, 버튼의 색, 요금제 카드의 강조 방식이 모두 합쳐져서 “이 서비스가 어느 정도 정리되어 있는지”를 전달합니다.

그래서 단일 SVG를 기준으로 아이콘 파이프라인을 만들었습니다.

icon.svg
├─ favicon.ico
├─ apple-icon.png
├─ icon-192.png
├─ icon-512.png
└─ manifest.webmanifest

이런 작업은 기능 중심으로 보면 뒤로 밀리기 쉽습니다. 하지만 이번 TASK-003의 목표가 “프론트 껍데기 구현”이라면, 이런 작은 브랜드 요소도 범위에 들어간다고 판단했습니다.

껍데기는 겉치장이 아니라, 사용자가 처음 접하는 제품의 표면입니다.

애니메이션은 적게, 하지만 방향은 있게

프론트 껍데기를 만들 때 애니메이션도 고민했습니다.

framer-motion을 붙일 수도 있었습니다. 하지만 이번 단계에서는 CSS와 IntersectionObserver만으로 충분하다고 판단했습니다. 아직 실제 기능보다 전체 인상과 구조가 중요한 단계였기 때문입니다.

영역

구현 방향

판단

Hero 진입

CSS keyframes

첫 화면에만 가볍게 움직임

스크롤 reveal

IntersectionObserver

섹션이 자연스럽게 나타나도록

헤더 상태

스크롤 감지

읽는 중에도 위치감 유지

Pro 카드 강조

CSS glow / shimmer

추천 플랜만 조용히 강조

상태 pulse

CSS animation

살아 있는 느낌을 주되 과하지 않게

처음에는 애니메이션이 너무 약해서 있는지 없는지 잘 보이지 않았습니다. 그래서 duration과 stagger를 조금 조정했습니다.

하지만 반대로 너무 화려하면 제품보다 효과가 먼저 보입니다. 그래서 기준을 계속 확인했습니다.

움직임은 멋을 위한 것이 아니라, 시선의 흐름을 돕기 위한 것이어야 했습니다.

구현 파일을 보며 구조를 다시 정리했습니다

이번 TASK는 단순히 페이지 몇 개를 만든 것이 아니라, 앞으로 프론트가 커질 구조도 같이 잡는 작업이었습니다.

대략적인 파일 구조는 이런 방향으로 정리했습니다.

apps/web
├─ app
│  ├─ [locale]
│  │  └─ (marketing)
│  │     ├─ page.tsx
│  │     └─ pricing
│  │        └─ page.tsx
│  ├─ icon.svg
│  ├─ favicon.ico
│  └─ manifest.ts
├─ components
│  ├─ marketing
│  ├─ status
│  └─ ui
├─ i18n
│  └─ routing.ts
├─ messages
│  ├─ ko.json
│  └─ en.json
└─ scripts
   └─ generate-icons.mjs

이 구조를 만들면서도 고민이 있었습니다.

마케팅 컴포넌트와 실제 앱 컴포넌트를 어디까지 나눌지. 상태 카드 UI는 마케팅용 데모로만 둘지, 나중에 대시보드에서도 재사용할지. UI primitive는 shadcn 기반으로 유지하되, vibePulse만의 status 컴포넌트를 별도 폴더로 둘지.

이런 판단은 지금은 작아 보이지만, 나중에 기능이 붙으면 중요해집니다. 특히 AI와 함께 개발할 때는 폴더 구조가 모호하면 컴포넌트가 엉뚱한 위치에 생기기 쉽습니다.

그래서 이번에는 marketing, status, ui를 분리했습니다.

  • marketing은 랜딩, 헤더, 푸터, 섹션 중심입니다.
  • status는 모니터링 상태를 표현하는 UI입니다.
  • ui는 shadcn 기반의 기본 컴포넌트입니다.

이렇게 나눠두면 다음 TASK에서 실제 대시보드를 만들 때도 status 관련 UI를 다시 볼 수 있습니다.

문서에 결정도 같이 남겼습니다

이번 작업에서 중요하게 생각한 것은 문서 동기화였습니다.

바이브코딩은 빠르게 바뀝니다. Cursor와 함께 작업하다 보면 좋은 아이디어가 즉석에서 나오고, 화면을 보다가 바로 수정하게 됩니다. 이 흐름은 장점이 큽니다.

하지만 기록하지 않으면 위험합니다.

/ko/pricing이 아니라 /pricing인지. 왜 Email보다 Telegram과 Discord가 먼저인지. 왜 Team 플랜은 준비 중으로 뒀는지. 왜 요금제 숫자를 크게 잡지 않았는지.

이런 결정은 코드만 보면 잘 보이지 않습니다.

그래서 결정 문서에 남겼습니다.

결정

내용

i18n URL 전략

기본 한국어는 prefix 없이, 영어는 /en

발급 URL 전략

상태 페이지, ping, API는 locale 밖

알림 채널 우선순위

런칭 초반은 채팅 채널 중심

요금제 구조

Free / Starter / Pro / Team 4티어

Team 상태

초기에는 준비 중으로 표시

Email / Webhook

후순위 기능으로 분리

바이브코딩에서 중요한 것은 빠르게 바꾸는 것만이 아니라, 왜 바꿨는지 남기는 일이었습니다.

저는 이것이 goodtek의 Build in Public 기록과도 연결된다고 생각합니다. 외부에는 블로그로 과정을 공유하고, 내부에는 문서로 판단을 남깁니다. 둘 다 없으면 프로젝트는 점점 블랙박스가 됩니다.

이번 방식의 장점과 부담

전체 화면을 먼저 그리는 방식이 무조건 편한 것은 아니었습니다.

기능이 아직 없기 때문에 불안한 순간이 있습니다. 버튼은 있는데 동작하지 않고, 카드에는 실제 데이터가 없고, 요금제도 아직 결제와 연결되지 않습니다. 겉으로 보기에는 “완성된 척”처럼 보일 위험도 있습니다.

그래서 이 작업의 범위를 스스로 계속 확인해야 했습니다.

이번 TASK는 기능을 구현한 것이 아니라, 기능이 들어올 자리를 구현한 것입니다.

이 기준을 놓치면 껍데기 작업이 과해질 수 있습니다. 디자인만 계속 만지고 실제 기능으로 넘어가지 못할 수도 있습니다.

그래서 장점과 부담을 같이 봤습니다.

항목

장점

부담

전체 화면 선구현

출시 범위가 빨리 보입니다

실제 기능 진척이 느리게 느껴질 수 있습니다

디자인 톤 선확정

후반 정리 비용이 줄어듭니다

초기 화면 수정이 많아집니다

카피 선정리

사용자 언어가 빨리 잡힙니다

기능이 바뀌면 카피도 다시 봐야 합니다

요금제 선구성

제품 약속이 명확해집니다

인프라 현실을 계속 검증해야 합니다

문서 동기화

다음 TASK가 덜 흔들립니다

기록하는 시간이 추가로 듭니다

이번에는 이 부담을 감수할 만하다고 판단했습니다. vibePulse는 이제 막 기능을 입히기 시작하는 단계이기 때문에, 초반에 제품의 얼굴과 흐름을 잡는 것이 더 중요했습니다.

개인적으로 가장 크게 바뀐 생각

이번 TASK-003을 하면서 가장 크게 바뀐 생각은 이것입니다.

프론트는 마지막에 붙이는 껍데기가 아니었습니다.

예전에는 백엔드나 기능 로직을 먼저 만들고, 프론트는 그것을 보여주는 화면이라고 생각하는 경향이 있었습니다. 물론 많은 경우 그 방식이 맞습니다.

하지만 이번에는 반대였습니다.

프론트를 먼저 그리니 기능 질문이 더 빨리 나왔습니다.

  • 사용자가 첫 모니터를 만들기 전에 어떤 선택을 해야 하는가?
  • URL 감시와 heartbeat 감시는 같은 온보딩에서 처리할 수 있는가?
  • 느려짐 상태는 대시보드에서 얼마나 강하게 보여줘야 하는가?
  • 무료 플랜의 제한은 어디에서 안내해야 하는가?
  • 알림 채널은 가입 중에 연결해야 하는가, 나중에 설정에서 연결해야 하는가?
  • 상태 페이지 URL은 어느 시점에 발급되어야 하는가?

이 질문들은 코드만 보고 있을 때보다 화면을 보면서 더 선명해졌습니다.

그래서 이번 작업은 “프론트 구현”이면서 동시에 “기능 범위 확인”이었습니다.

다음 TASK부터는 기능을 입힙니다

이제 다음 단계부터는 이 껍데기 위에 실제 기능을 하나씩 입힐 차례입니다.

로그인과 가입이 붙고, 온보딩에서 첫 모니터를 만들고, 대시보드에서 실제 상태를 보고, 상태 페이지를 공개하고, 알림 채널을 연결하게 될 겁니다.

아마 그 과정에서 이번에 만든 화면도 다시 바뀔 겁니다. 실제 기능이 들어오면 지금의 가정이 틀린 부분도 나올 겁니다.

하지만 괜찮습니다.

이번 TASK-003의 목적은 절대 안 바뀌는 최종 디자인을 만드는 것이 아니었습니다. 목적은 기능이 들어올 수 있는 일관된 첫 구조를 만드는 것이었습니다.

TASK-003 이후 흐름
├─ 전체 화면 껍데기 구현
├─ 기능 범위와 연결 구조 확인
├─ 로그인 / 온보딩 기능 연결
├─ 대시보드 실제 데이터 연결
├─ 상태 페이지와 알림 기능 확장
└─ 변경된 판단은 계속 문서화

결국 이번 TASK에서 남은 것

TASK-003을 끝내고 나니, 완성된 SaaS가 생긴 것은 아닙니다.

대신 vibePulse의 첫 얼굴이 생겼습니다. 사용자가 처음 들어왔을 때 어떤 제품인지 느낄 수 있는 화면이 생겼고, 앞으로 기능이 어디에 붙어야 하는지 볼 수 있는 구조가 생겼습니다.

그리고 저에게는 기준이 하나 남았습니다.

바이브코딩은 무계획이 아니라, 바뀔 수 있는 계획에 가깝습니다.

처음부터 모든 것을 워터폴처럼 확정할 수는 없습니다. 실제로 만들다 보면 생각이 바뀌고, 화면을 보며 다시 판단하게 됩니다. 하지만 그 판단을 기록하고, 전체 흐름을 계속 확인하면 프로젝트는 블랙박스가 되지 않습니다.

goodtek은 vibePulse를 그렇게 만들고 있습니다.

완성된 기능만 보여주는 것이 아니라, 왜 이 순서로 만들었는지, 어떤 고민을 했는지, 어디서 생각이 바뀌었는지를 계속 남기겠습니다. 지금 개발 중인 화면은 dev-vibepulse.goodtek.xyz에서 확인할 수 있습니다.

비슷하게 혼자 SaaS를 만들고 있거나, 기능부터 붙일지 전체 화면부터 잡을지 고민하고 있는 분이라면 이 여정을 함께 봐주시면 좋겠습니다. 제품에 방향에 의견이 있으신 분들은 댓글, 이메일, 쓰레드, 커뮤니티 등을 통해 연락 주세요!

다음 기록에서는 이 껍데기 위에 실제 기능을 어떻게 입혀가는지 이어서 남기겠습니다.

Read more

AI와 함께 코딩할 때 먼저 배운 것: 만든 것과 만들려던 것을 구분하기

AI와 함께 코딩할 때 먼저 배운 것: 만든 것과 만들려던 것을 구분하기

AI와 함께 코딩하면 계획, 프롬프트, 문서, 실제 코드가 쉽게 섞입니다. 이번 TASK-013에서는 공개 상태 페이지를 만들려 했지만, 실제로 ship된 것은 실시간 대시보드, 알림 테스트 상태 추적, 디자인 정합 작업이었습니다. 이번 글에서는 TASK 이름보다 머지된 코드를 기준으로 사실을 검증한 과정과, Realtime 아키텍처·비동기 상태 모델·공통 계약 관리 등 AI와 함께 개발할 때 놓치기 쉬운 기준들을 정리합니다. Build in Public 관점에서 ‘만들려던 것’과 ‘실제로 만든 것’을 구분하는 방법을 공유합니다.

By ● goodtek
감지 → 판단 → 알림: vibePulse의 심장을 만든 6개의 TASK

감지 → 판단 → 알림: vibePulse의 심장을 만든 6개의 TASK

goodtek이 만들고 있는 vibePulse는 "내가 만든 웹/API가 지금 살아 있는가"를 확인하고, 죽으면 즉시 알려주는 초간단 생존 확인 SaaS입니다. 이번 글은 그 핵심 파이프라인 — 모니터를 만들고(TASK-006), 주기적으로 찌르고(007), 장애를 판단하고(008), 신호가 끊기면 알아채고(009), 알림을 큐에 태워(010), 슬랙·카카오톡으로 보내기까지(011) — 를 한 호흡에 만든 기록입니다.

By ● goodtek