All Posts

가장 게으른 시니어처럼, AI가 코드를 덜 쓰게 만드는 Ponytail
AI 코딩 에이전트가 과설계하는 습관을 잡아주는 오픈소스 스킬 Ponytail을 직접 붙여 써봤습니다. YAGNI 사다리로 코드를 덜 쓰게 만드는 원리와, 디바운스 훅 하나를 서른 줄에서 두 줄로 줄인 체험을 정리했습니다.

truncate와 line-clamp, 말줄임이 안 먹을 때 뭘 봐야 할까?
truncate와 line-clamp는 동작 기반이 다릅니다. flex와 함께 쓰면 왜 조용히 안 잘리는지, 그럴 때 무엇부터 확인해야 하는지 정리했습니다.
June 26, 2026SSE 이벤트 프로토콜로 AI 채팅 스트리밍 설계하기
LLMOps 플랫폼에서 답변 텍스트, 참고 문서, 워크플로우 실행 흐름을 동시에 전달하는 AI 채팅 스트리밍 설계 과정

인덱스 파헤쳐보기
프론트 작업 중 만난 인덱스 검증 컴포넌트 하나를 제대로 읽기 위해, SQL 인덱스를 처음부터 다시 파본 기록. 인덱스가 뭔지부터 옵티마이저·EXPLAIN·INVISIBLE까지 익히고, 그 지식으로 검증 컴포넌트를 한 줄씩 읽습니다.
June 24, 2026QA도, 시간도 없던 팀이 AI Agent로 테스트 자동화를 정착시킨 방법
테스트 코드 작성이 늘 뒤로 밀리는 현실 속에서, AI로 이를 자동화해본 경험과 배운 점을 공유합니다.

웹스토어에 없는 크롬 확장, zip으로 설치하기 (압축 해제된 항목 로드)
웹스토어에 올라가 있지 않은 크롬 확장을 zip으로 받아 "압축 해제된 항목 로드(unpacked)"로 설치하는 방법을 정리했습니다.
June 22, 2026
discriminated union, 무엇이고 언제 쓰면 좋을까
discriminated union이 무엇인지, 그리고 종류마다 데이터가 다른 상황에서 왜 유용한지 정리했습니다. 판별자와 타입 좁히기부터 never 완전성 검사까지, 폼 필드 하나로 풀어 봅니다.
June 16, 2026
optional로 범벅이던 폼을 z.discriminatedUnion으로 다시 짰다
같은 필드인데 생성은 필수, 편집은 선택이라 아무도 정답을 몰랐던 폼. 타입 분리가 없는 게 문제로 보였지만 진짜 문제는 중복이었고, 중복부터 걷어낸 뒤에야 discriminatedUnion으로 도메인을 다시 모델링할 수 있었던 과정을 공유합니다.
June 16, 2026
Zod로 폼 검증할 때 아무도 안 알려주는 것들
discriminatedUnion으로 폼을 깔끔하게 짠 다음 실제로 겪은 Zod 함정 세 가지. union 에러 메시지, superRefine과 DU 사이의 선택, 그리고 defaultValues가 유니온 타입과 부딪히던 지점을 정리했습니다.
June 16, 2026
아직도 AI에게 코딩만 부탁하시나요? 디버깅, 검증도 맡길 수 있습니다
스크린샷 첨부 대신 AI에게 직접 페이지를 열어 확인하게 시키는 Playwright MCP를, 평소 쓰는 패턴과 함께 소개합니다.
May 12, 2026
Claude Code의 Playwright MCP, 내 Chrome 프로필 그대로 쓰기
매번 새 프로필로 뜨는 Playwright MCP를 평소 쓰는 Chrome 프로필에 연결하는 방법을 정리했습니다.
May 7, 2026
Radix UI vs Base UI: 어떤 Headless 라이브러리를 선택할까
Headless UI 라이브러리 Radix UI와 Base UI의 설계 철학, API, 접근성, 개발 경험을 비교합니다
April 24, 2026
i18n 미사용 키 정리
공식 i18next-cli가 네임스페이스를 통째로 지우려 한 실측에서 출발해, ts-morph 커스텀 스크립트와 GitHub Actions 주간 자동 PR로 번역 카탈로그를 안전하게 정리하는 파이프라인을 만든 과정
April 13, 2026
React Router는 자체 ErrorBoundary를 갖고 있다
ErrorBoundary를 감쌌는데 에러가 안 잡히는 상황. React Router가 내부에서 먼저 에러를 잡고 있었고, errorElement로 해결한 과정을 공유한다.
April 9, 2026
시뮬레이터에선 되던 앱이 실기기에서 터진 이유
Flutter 시뮬레이터에서 잘 되던 API 호출이 실기기에서 Connection refused, localhost가 가리키는 곳이 달랐다. 원인을 찾고 device_info_plus로 자동 감지까지 구현한 과정.
April 9, 2026
Orval 코드 생성 시 500개 파일 diff가 생긴다면
Orval이 생성하는 파일 헤더의 OpenAPI spec version 때문에 500개 파일에 불필요한 diff가 생기는 문제를, 커스텀 header 함수로 해결한 경험.
April 1, 2026
Obsidian 블로그 워크플로우
Next.js 블로그에 Obsidian과 AI를 연동한 글쓰기 환경 구축기
March 27, 2026
Obsidian 이미지를 Next.js 블로그에서 렌더링하기 - 커스텀 remark 플러그인
Obsidian의 ![[이미지.webp]] 문법이 MDX에서 깨지는 문제를 커스텀 remark 플러그인으로 해결한 과정
March 25, 2026
파일 업로드 리팩토링기
산발적 파일 관리 로직의 문제를 인식하고, useTempFileManager를 v1에서 v2로 리팩토링한 과정
March 25, 2026
배포했는데 왜 안 바뀌죠 - Version Polling으로 SPA 업데이트 알림 배너 만들기
SPA에서 배포 후에도 사용자 화면이 갱신되지 않는 문제를, Service Worker 없이 version.json 폴링과 Cache API로 해결한 과정.
March 20, 2026
에러 핸들링 시리즈
TanStack Query 에러 타입 지정부터 인터셉터 통합, 에러 UI 설계, ErrorBoundary 안전망까지 — 에러가 만들어지고 보여지고 잡히는 흐름 전체를 개선한 과정
March 13, 2026
Zustand scoped store 시리즈
글로벌 store의 한계에서 출발해, createStore() + React Context 패턴으로 scoped store를 구현하고, ~40줄 유틸리티로 추상화하는 과정
March 13, 2026
F12 누르면 비밀번호가 보인다 - 프론트엔드에서 SHA-256 해싱으로 로그인 평문 노출 막기
로그인 보안 태스크를 받고, SHA-256 해싱을 처음 접하며 하나씩 질문하고 답을 찾아간 과정을 공유합니다.
March 11, 2026
런타임에 변하는 한글 - i18next에서 조사를 자동으로 선택하기
{{name}}에 어떤 단어가 올지 모르는데, 을/를은 어떻게 정하지? i18next post-processor로 번역 키 하나만으로 조사를 자동 선택한 과정.
February 27, 2026입사 6개월, 회사 어워즈를 받았어요
송년회 시상식에서 '조언.bot' 부문으로 받은 작은 상에 대한 짧은 기록
January 2, 2026TypeScript는 왜 내 코드를 의심할까
TypeScript는 왜 내 코드를 의심할까
April 12, 2024if문 하나로 TypeScript가 똑똑해지는 이유
if문 하나로 TypeScript가 똑똑해지는 이유
April 9, 2024