Build Log: TASK-001 모노레포 만들기
vibePulse의 첫 번째 실제 작업으로 TASK-001 모노레포를 구성했습니다. Next.js, NestJS, worker, Postgres/TimescaleDB, Redis, CI, /health 체크까지 한 번에 잡으면서 빠른 구현보다 먼저 기준을 세우는 것이 왜 중요한지 돌아봤습니다. 운영 DB 데이터 전략과 named volume에 대한 고민도 함께 정리했습니다.
블로그에서 읽기롱폼 글은 goodtek과 동일 운영자가 운영하는 blog.goodtek.xyz에서 이어집니다.
vibePulse의 첫 번째 실제 작업으로 TASK-001 모노레포를 구성했습니다. Next.js, NestJS, worker, Postgres/TimescaleDB, Redis, CI, /health 체크까지 한 번에 잡으면서 빠른 구현보다 먼저 기준을 세우는 것이 왜 중요한지 돌아봤습니다. 운영 DB 데이터 전략과 named volume에 대한 고민도 함께 정리했습니다.
블로그에서 읽기vibeops init으로 프로젝트 골격을 만들고, LLM과 티키타카하며 VibePulse의 아키텍처, 기술 스택, UX, 알림 구조, 데이터 보존 전략, TASK 단위 로드맵을 먼저 정리한 과정입니다. 코딩을 시작하기 전에 AI에게 맡길 것과 사람이 통제할 기준을 어떻게 나눴는지 기록했습니다.
블로그에서 읽기요즘 바이브코딩이라는 말을 정말 자주 봅니다. 예전에는 서비스를 하나 만들려면 기획하고, 디자인하고, 개발하고, 배포하고, 운영하는 과정이 꽤 멀게 느껴졌습니다. 아이디어가 있어도 “이걸 실제 서비스로 만들 수 있을까?”라는 질문 앞에서 오래 멈추는 일이 많았습니다. 그런데 이제는 조금 다릅니다. 아이디어만 있으면 AI와 함께 빠르게 화면을 만들고, 기능을 붙이고, 배포까지 해볼 수 있는 시대가 됐습니다. 저도 그 흐름 안에서 여러 실험을 하고 있습니다. 그런데 직접 만들어보니 금방 알게 됐습니다. 서비스는 만드는 것보다 계속 살아 있게 하는 것이 더 어렵습니다. 처음 배포했을 때는 분명 잘 돌아갔습니다. 빌드도 성공했고, 화면도 열렸고, “오, 됐다” 싶은 순간도 있었습니다. 그런데 문제는 그 다음부터였습니다. 어느 날 갑자기 서버가 죽을 수도 있습니다. API가 응답하지 않을 수도 있습니다. 배포는 성공했다고 나오는데 실제 페이지는 안 열릴 수도 있습니다. 환경변수
블로그에서 읽기vibeops init으로 프로젝트 골격을 만들고, LLM과 티키타카하며 VibePulse의 아키텍처, 기술 스택, UX, 알림 구조, 데이터 보존 전략, TASK 단위 로드맵을 먼저 정리한 과정입니다. 코딩을 시작하기 전에 AI에게 맡길 것과 사람이 통제할 기준을 어떻게 나눴는지 기록했습니다.
블로그에서 읽기AI가 빨라진 게 아니라 기록이 빨라졌다. TASK 문서, Git 히스토리, PR, 검증 로그가 컨텍스트로 쌓이면서 goodtek-web의 개발 속도는 10~20분 단위로 빨라졌다. 이번 TASK-025에서는 AdSense 승인 준비를 위해 robots.txt, sitemap.xml, Contact, Privacy, Start Here, Projects, 허브 SEO를 정리하며 기초가 속도가 되는 과정을 기록했다.
블로그에서 읽기운영 서버 배포는 새 코드를 올리는 일이 아니라, 사용자의 접속을 끊지 않고 시스템을 교체하는 일입니다. goodtek이 유료 회원에게 404를 보여주지 않기 위해 Blue/Green 배포, Caddy upstream 전환, health check, 실제 끊김 테스트까지 구축하고 검증한 과정을 정리했습니다.
블로그에서 읽기짧은 작업 메모는 notes.goodtek.xyz에서 이어집니다.
Summary CI/CD를 CI / CD 워크플로 분리로 정리하고, Actions 이름을 읽기 쉽게 맞춘 뒤 main까지 반영했다. 이어서 **React hydration 418 수정, 모바일·데스크톱 헤더/navigation 개선(TASK-020~023)을 develop에 merge했다. CI/CD — TASK-019 배경 TASK-018 workflo…
오늘은 notes.goodtek.xyz를 위한 공개 노트 구조를 만들었다. Obsidian에서 Markdown을 작성하고, Quartz로 정적 사이트를 만든 뒤, Cloudflare Pages로 배포하는 방식을 선택했다. 오늘 한 일 goodtek-notes 저장소를 준비했다. Quartz를 설치하고 초기화했다. notes.goodtek.xyz를 기본 U…
빌드 로그는 힘줘서 쓰지 않는다. 목표는 좋은 글을 쓰는 것이 아니라, 나중에 다시 볼 수 있는 작업 흔적을 남기는 것이다. 블로그 글처럼 완성도를 높이려고 하면 지속하기 어렵다. 빌드 로그는 작업이 끝난 뒤 짧게 남기는 기록이면 충분하다. 원칙 작업 중간에는 쓰지 않는다. 작업이 끝난 뒤 5분만 정리한다. 문장보다 bullet 위주로 남긴다. 모든 로그…
토론과 질문은 community.goodtek.xyz에서 이어집니다.
goodtek
goodtek vibepulse % vibeops init Agent clients Which coding agents will you use? (Space toggle · Enter confirm) Cursor (.cursor/rules, .cursor/skills) Branch policy Branch policy GitFlow lite — develop (integration) + main (production) → vibeops init → /Users/hjhamm/goodtek/vibepulse project: vibepulse vibeops: 2.3.0 clients: Cursor (.cursor/rules, .cursor/skills) git: integration=develop, production=main ✓ created .cursor/rules/01-task-source-of-truth.mdc ✓ created .cursor/rules/02-git-safety.mdc ✓ created .cursor/rules/03-docs-before-ship.mdc ✓ created AGENTS.md ✓ created docs/logs/README.md ✓ created docs/project/03-architecture.md ✓ created docs/project/05-current-state.md ✓ created docs/project/06-decisions.md ✓ created docs/tasks/TASK-000-template.md ✓ created .cursor/skills/implement-task/SKILL.md ✓ created .cursor/skills/plan-task/SKILL.md ✓ created .vibeops.json ✓ created .vibeops.env.example ✓ created .gitignore done: 14 created, 0 overwritten, 0 skipped. Git repository Create initial commit? Yes Initial commit message initialize vibepulse project Git setup: ✓ git init ✓ production branch main ✓ initial commit on main ✓ integration branch develop Remote origin is required for push and merge requests. GitHub repository name (owner/repo or name for gh to create) vibepulse Creating GitHub repository via gh… Remote bootstrap: ✓ pushed main → origin ✓ pushed develop → origin Next steps: Read AGENTS.md Cursor: @docs/tasks/TASK-001-….md in Ask, then Agent (+ /plan-task, /implement-task) vibeops llm connect — LLM for task add / task ship Push branches to origin (first time only): git push -u origin main git push -u origin develop vibeops task add — branches from develop (pulls latest first) vibeops task ship → merge → sync — TASK lifecycle on github goodtek vibepulse %
여러분이라면 goodtek에 SSO를 지금 도입하시겠습니까? 솔직히 말하면, SSO라는 단어는 꽤 매력적입니다. 서비스가 여러 개로 나뉘기 시작하면 이런 생각이 바로 듭니다. “로그인을 하나로 묶어야 하지 않을까?” 현재 goodtek이 가려는 구조를 보면 더 그렇습니다. goodtek.xyz — 메인 웹사이트 blog.goodtek.xyz — Ghost 블로그 community.goodtek.xyz — NodeBB 커뮤니티 notes.goodtek.xyz — 공개 노트 / 개발 로그 app.goodtek.xyz — 나중에 SaaS 앱들 이렇게 보면 SSO 방향 자체는 맞아 보입니다. 웹사이트, 블로그, 커뮤니티, 노트, SaaS 앱이 하나의 생태계로 묶이는 그림이니까요. 사용자 입장에서도 한 번 로그인해서 여러 서비스를 오가는 경험은 분명 좋습니다. 그런데 여기서 질문이 하나 생깁니다. 지금 goodtek이 해결해야 할 가장 중요한 문제가 정말 “통합 로그인”일까요? 저는 이 지점에서 조금 멈췄습니다. SSO가 필요한가보다 중요한 질문 SSO가 필요한지 아닌지만 보면 답은 쉽습니다. 언젠가는 필요할 수 있습니다. 문제는 “언젠가”가 아니라 지금입니다. 지금 Keycloak 같은 중앙 인증 서버를 직접 붙이면, 인증은 단순 기능이 아니라 하나의 운영 대상이 됩니다. 로그인만 되는 게 아닙니다. 세션 관리 리프레시 토큰 이메일 인증 비밀번호 초기화 OAuth 설정 백업 업그레이드 장애 대응 보안 패치 운영 모니터링 이 모든 게 따라옵니다. 처음에는 “로그인 통합하면 깔끔하겠다”로 시작했는데, 어느 순간 인증 서버 자체가 또 하나의 제품이 될 수 있습니다. 문제는 SSO가 좋은 기술이냐가 아니라, 지금 인증이 goodtek의 핵심 병목이냐입니다. 지금 goodtek에 더 급한 것들 goodtek 입장에서는 이미 해야 할 일이 많습니다. 웹사이트를 만들고, 블로그를 운영하고, 커뮤니티를 키우고, 공개 노트를 정리하고, SaaS 앱을 만들고, CI/CD와 운영 자동화도 다듬어야 합니다. 이 상황에서 Keycloak까지 직접 운영하기 시작하면, 제품보다 인프라가 더 무거워질 수 있습니다. 제 기준으로 보면 지금은 이렇게 나누는 게 더 현실적입니다. 영역 지금 선택 이유 웹사이트 로그인 없음 랜딩, SEO, AdSense, 연결 구조가 먼저 Ghost 블로그 Ghost 기본 멤버 뉴스레터와 구독 기능이 이미 있음 NodeBB 커뮤니티 자체 로그인 + 소셜 로그인 초기 커뮤니티에는 충분함 Notes 공개 문서 신뢰 자산과 개발 로그 역할 SaaS 앱 앱 자체 인증 또는 SaaS형 인증 실제 인증이 필요한 핵심 영역 즉, 모든 곳에 중앙 인증을 먼저 깔기보다 로그인이 진짜 필요한 곳부터 가볍게 시작하는 방식입니다. Keycloak이 틀렸다는 말은 아닙니다 여기서 오해하면 안 되는 게 있습니다. 저는 Keycloak이 나쁘다고 생각하지 않습니다. 오히려 특정 시점이 오면 굉장히 좋은 선택이 될 수 있습니다. 예를 들면 이런 상황입니다. SaaS 앱이 여러 개 생긴다 커뮤니티 계정과 SaaS 계정을 반드시 하나로 묶어야 한다 조직/팀 단위 계정이 필요하다 RBAC, 그룹, 역할 관리가 복잡해진다 고객사별 SSO 요청이 들어온다 SAML, OIDC 같은 B2B 요구사항이 생긴다 자체 호스팅을 유지해야 하는 명확한 이유가 있다 이 정도까지 가면 이야기가 달라집니다. 그때는 Keycloak이 단순한 오버엔지니어링이 아니라 필요한 기반 인프라가 될 수 있습니다. 하지만 지금이 “나중에 필요할 것 같으니 미리 붙이자”에 가깝다면, 저는 조금 빠르다고 봅니다. 지금은 설계상 여지만 남기기 제가 생각하는 현실적인 선택은 이겁니다. SSO를 완전히 무시하지는 않되, 지금 당장 운영하지는 않는다. 예를 들어 SaaS 앱의 DB 설계에서 나중에 외부 IdP로 옮길 수 있는 여지만 남깁니다. users id email name avatar_url provider provider_account_id created_at accounts user_id provider provider_account_id access_token refresh_token memberships user_id product role status 이 정도만 해두면 나중에 Keycloak, Authentik, Zitadel, Auth0, Clerk 같은 선택지로 갈 때 완전히 막히지는 않습니다. 처음부터 중앙 인증 서버를 운영하는 것과, 나중에 옮길 수 있게 데이터 구조를 열어두는 것은 다릅니다. 저는 후자가 지금 goodtek에 더 맞다고 봅니다. 지금 필요한 건 완성된 통합 인증 시스템이 아니라, 나중에 통합할 수 있는 느슨한 구조입니다. 제 결론 제 결론은 이렇습니다. 지금 goodtek은 SSO를 도입하지 않는 쪽이 맞다. 조금 더 정확히 말하면, SSO 방향은 고려하되, Keycloak 같은 중앙 인증 서버를 지금 직접 운영하지는 않는다. 현재 단계에서는 이렇게 가는 게 가장 현실적이라고 봅니다. 웹사이트: 로그인 없음 블로그: Ghost 기본 멤버 기능 커뮤니티: NodeBB 기본 로그인 + Google/GitHub 로그인 Notes: 공개 운영 SaaS 앱: 앱 자체 인증 또는 Better Auth / Auth.js / Supabase Auth / Clerk 같은 가벼운 인증 그리고 실제로 커뮤니티와 SaaS가 연결되고, 결제/권한/등급/조직 계정이 얽히기 시작하면 그때 SSO를 진지하게 검토합니다. 그때 Keycloak을 붙여도 늦지 않다고 생각합니다. 오히려 지금은 콘텐츠, 커뮤니티, 제품이 먼저입니다. 인증 시스템이 아무리 잘 되어 있어도 들어올 사용자가 없으면 운영할 것도 없습니다. 반대로 사용자가 생기고 서비스 간 연결이 진짜 필요해지면, 그때의 SSO는 훨씬 명확한 이유를 갖게 됩니다. 여러분은 어떻게 생각하시나요? 여러분이라면 goodtek 같은 구조에서 SSO를 지금 도입하시겠습니까? 아니면 일단 각 서비스를 독립적으로 운영하고, SaaS 앱에만 가벼운 인증을 붙인 뒤 나중에 통합하시겠습니까? 특히 궁금한 건 이 부분입니다. 초기부터 SSO를 깔아두는 게 장기적으로 이득일까요, 아니면 지금은 오히려 제품보다 인프라를 키우는 선택일까요? 저는 지금 단계에서는 후자에 가깝다고 봅니다. 하지만 SSO를 초기에 깔아두고 나중에 덕을 본 경험이 있다면, 그 이야기도 들어보고 싶습니다.
Android에서 Obsidian으로 메모를 수정하고, Termux에서 Git으로 "pull", "commit", "push"를 해보면서 중요한 걸 하나 배웠습니다. Git은 파일을 잘 합쳐주지만, 같은 파일의 같은 위치를 여러 기기에서 동시에 수정하면 자동으로 처리하기 어렵다는 점입니다. 예를 들어 PC에서 "content/backlog/tasks.md"를 수정하고 GitHub에 push했습니다. 그런데 Android에서도 같은 "tasks.md"를 수정한 상태에서 "git pull --rebase"를 실행하면 충돌이 날 수 있습니다. GitHub: A → B Android: A → C Git은 GitHub의 최신 변경사항 "B" 위에 Android의 변경사항 "C"를 다시 얹으려고 합니다. A → B → C 하지만 "B"와 "C"가 같은 파일, 같은 줄 근처를 수정했다면 Git은 어느 쪽 내용을 살려야 할지 판단하지 못합니다. 그래서 이런 충돌이 발생합니다. CONFLICT (content): Merge conflict in content/backlog/tasks.md 이건 Git이 망가진 것이 아니라, 오히려 내용을 함부로 덮어쓰지 않기 위해 멈춘 것입니다. 동시에 수정하면 왜 어려운가 서로 다른 파일을 수정하면 Git이 대부분 자동으로 합칠 수 있습니다. PC → content/blog/idea.md 수정 Android → content/backlog/tasks.md 수정 이 경우는 충돌 가능성이 낮습니다. 하지만 같은 파일을 양쪽에서 수정하면 충돌 가능성이 높아집니다. PC → content/backlog/tasks.md 수정 Android → content/backlog/tasks.md 수정 특히 같은 줄 근처를 수정하면 Git은 사람이 판단해야 한다고 보고 멈춥니다. 결국 문제는 “Git을 못 써서”가 아니라, 하나의 파일을 여러 기기에서 동시에 편집하는 구조 자체가 충돌에 취약하다는 점입니다. 앞으로의 운영 원칙 Goodtek notes는 Android, PC, GitHub가 함께 쓰이는 구조입니다. 그래서 앞으로는 아래 원칙으로 운영하는 것이 좋겠습니다. 수정 전에는 먼저 받기 수정 후에는 바로 올리기 Android에서 작업할 때는 먼저 최신 상태를 받습니다. pull-notes 그 다음 Obsidian에서 메모를 수정합니다. 수정이 끝나면 바로 올립니다. sync-notes PC에서 작업할 때도 마찬가지입니다. git pull --rebase origin main 메모 수정 git add content git commit -m "Update notes" git push 핵심 흐름은 단순합니다. 받고 → 쓰고 → 올리기 파일을 쪼개면 충돌이 줄어든다 "tasks.md" 하나에 모든 백로그를 계속 적으면 충돌이 자주 날 수 있습니다. 특히 Android와 PC에서 자주 열어보는 파일이라면 더 그렇습니다. 그래서 하나의 큰 파일에 모든 걸 넣기보다, 역할별로 나누는 편이 좋습니다. 예를 들면 이렇게 나눌 수 있습니다. content/backlog/ ├── inbox.md ├── tasks.md ├── ideas.md └── content-ideas.md 더 충돌을 줄이려면 날짜별 파일도 괜찮습니다. content/backlog/daily/ ├── 2026-06-03.md ├── 2026-06-04.md └── 2026-06-05.md 또는 월별로 나눌 수도 있습니다. content/backlog/ ├── tasks-2026-06.md ├── ideas-2026-06.md └── content-ideas-2026-06.md 이렇게 하면 PC와 Android가 같은 파일을 동시에 수정할 확률이 줄어듭니다. Goodtek notes 추천 구조 Goodtek notes에서는 Android와 PC의 역할을 나누는 방식이 좋아 보입니다. Android → 빠른 메모, 순간적으로 떠오른 생각 기록 PC → 정리, 편집, 블로그 글로 확장, 구조화 그래서 Android에서는 주로 "inbox.md"를 사용합니다. content/backlog/inbox.md 생각난 것은 일단 여기에 빠르게 적습니다. 나중에 Android Git 동기화 글 블로그로 정리하기 notes.goodtek.xyz 백로그 구조 정리하기 sync-notes 충돌 방지 로직 개선하기 그리고 PC에서 시간이 날 때 정리합니다. inbox.md → tasks.md → content-ideas.md → build-log → blog.goodtek.xyz 글 이렇게 하면 Android에서는 빠르게 기록하고, PC에서는 천천히 정리할 수 있습니다. 정리 이번에 배운 것은 단순한 Git 명령어가 아닙니다. Obsidian 노트를 여러 기기에서 운영하려면 Git 충돌을 없애는 것보다, 충돌이 덜 나게 쓰는 구조를 만드는 것이 더 중요하다는 점입니다. 앞으로 Goodtek notes는 이렇게 운영합니다. Android에서 쓰기 전 pull-notes Android에서 쓴 후 sync-notes PC에서 쓰기 전 git pull --rebase PC에서 쓴 후 git push Android는 inbox 중심 PC는 정리와 편집 중심 하나의 큰 파일보다 작은 파일 여러 개 동시에 같은 파일 수정하지 않기 결국 핵심은 이것입니다. Git을 잘 쓰는 방법은 충돌을 잘 해결하는 것만이 아니다. 충돌이 덜 나는 기록 구조를 만드는 것이다. Goodtek notes도 이런 작은 운영 원칙을 하나씩 쌓아가면서 더 오래 유지할 수 있는 기록 시스템으로 만들어가야겠습니다.