블로그
블로그
기술 메모와 개발 인사이트를 정리한 글 목록입니다.
블로그 태그- Golang에서 API 서버를 구현할 때의 기본 정책
단일 바이너리 + cobra, Operation 중심, HTTP/CLI 분리, secure error handling, graceful shutdown까지 Go로 API 서버를 쓸 때 자신의 기본 방침을 정리했다.
- Screen Time API로 iOS 셀프 컨트롤 앱을 만들기 위한 설계 가이드
NEDNSProxyProvider의 함정부터 FamilyControls + ManagedSettings 설계, 두 개의 Shield Extension, App Group 기반 언락 handoff, Personal Team 제약까지. Screen Time API로 iOS 차단 앱을 만드는 전체 그림을 정리했다.
- IT 엔지니어가 들어야 할 K-POP 곡
IT 용어와 사이버 컨셉이 담긴 추천 K-POP 5선. aespa의 메타버스, NCT DREAM의 글리치, STAYC의 'GPT' 등 시각과 사운드로 테크놀로지를 느낄 수 있는 곡들을 소개합니다.
- TypeScript Monorepo 최적해를 정리하는 2026년판
pnpm workspace, Turborepo, TypeScript Project References, Biome, WXT의 역할을 정리해, 범용의 무난해와 4 패키지 구성으로의 실무해를 나누어 정리했다.
- Shield Extension에서 메인 앱으로의 언락을 App Group 경유로 구현하기
ShieldActionDelegate에서 메인 앱을 직접 실행할 수는 없다. App Group 공유 스토리지에 언락 요청을 기록하고 앱 쪽에서 읽어 가는 handoff 패턴을 정리했다.
- FamilyControls + ManagedSettings로 iOS 자체 제한 블록 설계
AuthorizationCenter, FamilyActivityPicker, ManagedSettings의 세 가지 요소가 어떻게 결합됩니까? 프리텍스트의 도메인 입력이 아닌 토큰 기반 설계로 해야 하는 이유와 그 구현의 골격을 정리했다.
- iOS에서 사이트 블록을 만들 때 NEDNSProxyProvider를 선택하지 마십시오.
App Store 배포의 셀프 컨트롤 계 iOS 앱에서 NEDNSProxyProvider를 사용하는 것이 기술적·정책적으로 어떻게 문제인가, Screen Time API로의 이행 판단에 이르기까지의 조사를 기록했다.
- Personal Team에서는 Family Controls를 실기기에서 테스트할 수 없다
무료 Personal Team 계정으로는 Family Controls Development entitlement를 받을 수 없다. 왜 Apple Developer Program 가입이 실기기 테스트의 전제가 되는지와 영향 범위를 정리했다.
- iOS Shield UI에는 확장 하나가 아니라 둘이 필요하다
ManagedSettings로 차단을 설정했을 때 표시되는 shield 화면은 Action Extension과 Configuration Extension이라는 두 개의 별도 타깃으로 구성된다. 올바른 NSExtensionPointIdentifier와 principal class를 정리했다.
- SolidJS 베스트 프랙티스를 skills.sh에서 스킬로 공개했다
Claude Code의 스킬 기능을 활용해 SolidJS 베스트 프랙티스를 skills.sh에 공개한 기록. description의 정확도가 트리거 정확도를 결정한다는 점, with/without 테스트로 차이를 확인하는 프로세스에 대해 썼다.
- M4 Mac mini 셋업
Amazon의 이상한 세일에서 M4 Mac mini가 싸게 나와서 모아 둔 포인트까지 써서 사 버렸다. 이후 NixOS 기반 관리까지 염두에 두고 진행한 셋업 작업 기록을 남긴다.
- @hsblabs/web-stream-extras를 npm에 publish하면서 막혔던 것들 전부
수동 publish에서 GitHub Actions + npm Trusted Publisher로 이전할 때 실제로 겪은 실패를 시간 순서대로 정리했다. provenance 422, 태그와 버전 순서, publish 전 검증까지.
- @hsblabs/web-stream-extras를 출시했다
브라우저와 Node.js에서 ReadableStream<Uint8Array> 를 다루기 위한 작은 TypeScript 유틸리티 라이브러리. 바이트 변환 헬퍼, 트랜스폼 스트림, Web Crypto API 기반 스트림 암호화까지 포함한다.
- Web Crypto로 브라우저에서 바이트 스트림 암호화하기
Web Crypto는 강력한 암호 프리미티브를 제공하지만 스트림용 인터페이스는 없다. @hsblabs/web-stream-extras 의 encryption 서브패스로 ReadableStream<Uint8Array> 를 암호화하는 방법, 파일 암호화, 스트림별 키 관리, 파이프라인 합성까지 정리한다.
- 같은 Web Streams 보일러플레이트를 계속 쓰는 데 지쳤다
ReadableStream<Uint8Array> 유틸리티를 반복해서 다시 작성하다가 @hsblabs/web-stream-extras로 묶게 된 이유. 계속 반복되던 세 가지 패턴, ByteTransformStream 기반 클래스, Web Crypto 기반 스트림 암호화까지 정리한다.
- AWS Cross-Region VPC Peering 失敗ログ
大阪と東京のVPCピアリング設定でハマった。--peer-region忘れでfailed状態になり、削除もできなくなった件。
- `Cache-Control: max-age=3, must-revalidate`를 내 방식대로 정리해 보기
마이크로 캐싱이라고 불리는 Cache-Control 설정의 동작을 정리했다. `max-age=3`와 `must-revalidate` 조합이 실제로 무엇을 의미하는지, 시간 순서에 따른 동작 흐름과 구체적인 활용 사례를 다룬다.
- Astro 프로젝트에 개발 전용 Live 에디터 구현하기
Astro에서 개발 모드 전용 브라우저 에디터를 구현하는 방법. Vite 미들웨어와 React를 사용하여 프로덕션 빌드에 전혀 영향을 주지 않으면서 개발 중 콘텐츠 관리를 편리하게 만드는 절차를 정리.
- 웹 엔지니어가 생각하는 모바일 앱 설정 관리: 시작 시 메타데이터 가져오기 접근법
웹 프론트엔드와 인프라 경험에서 모바일 앱 도메인 관리 및 버저닝 과제를 정리합니다. CloudFront+S3를 활용한 시작 시 메타데이터 가져오기 방식을 제안하고, Firebase Remote Config 등의 기존 솔루션과의 비교도 함께 살펴 봅니다.
- Astro + bun dev 환경에서 /blog 404의 원인과 해결 절차
Astro + bun dev에서 /blog 404를 링크 확인, 라우트 생성, 전달 경로 순서로 분리해 진단하는 방법입니다. 디렉터리 충돌 수정 방법까지 포함합니다.
- Codex Cloud에서 mise 버전 고정이 안 될 때 대처법
Codex Cloud에서 mise install bun은 성공하는데 command not found가 나오는 원인과, setup.sh에서 mise use -g와 mise activate로 해결한 과정을 정리했다.
- lefthook 도입 절차: pre-commit과 pre-push에서 Biome 자동 실행하기
lefthook으로 커밋 시점과 푸시 시점에 Biome 포맷팅과 린트를 자동 실행하는 도입 절차를 정리했습니다. ADR 작성부터 설정, 설치, 동작 확인까지 한 번에 따라갈 수 있습니다.
- 빌드 산출물에 포함된 의존성 분석하기
Go로 빌드한 바이너리에는 사용된 의존성과 빌드 설정 정보가 내장됩니다.
- Claude용 성격 분석 스킬 personality-analyzer를 만든 이야기
Claude와의 대화 내용에서 HEXACO와 MBTI 점수를 YAML 형식으로 출력하는 스킬 개발 기록. AI와의 대화에서 성격 특성을 정량화해 보려는 시도.
- age-tar로 디렉터리 단위 암호화 백업 자동화하기
age와 tar를 조합해 하위 디렉터리마다 암호화 아카이브를 만드는 셸 스크립트. 일본어 디렉터리명을 포함한 운영에서도 CLI 호환성을 유지할 수 있다.
- UUID v7 구현 가이드 : JavaScript, Go, Shell로 만들기
UUID v7의 비트 구조, version/variant의 비트 설정, JavaScript·Go·Shell에서의 최소 구현, 구현시의 체크 항목, RFC의 참조처를 1페이지로 정리. 시계열 정렬하기 쉬운 ID를 안전하게 도입하고 싶은 개발자용으로 생성 로직의 확인 포인트를 정리한 실천 가이드. 구현 전의 확인에 사용할 수 있다.
- Glossary와 Dictionary의 차이를 정리하기
Glossary(용어집)와 Dictionary(사전)의 차이를 범위, 목적, 수록 단어, 작성자 관점에서 비교 정리했다.
- esbuild/Vite 번들 JS에서 라이선스 주석 제거하기
esbuild나 Vite로 빌드할 때 출력 파일의 라이선스 주석을 제거해 번들 크기를 조금 줄이는 방법.
- WXT에서 React Compiler를 활성화하는 설정 방법
WXT 프레임워크에서 React Compiler를 활성화하는 방법. babel-plugin-react-compiler 설치와 설정 연결을 정리한다.
- Cloudflare Workers에서 하위 디렉토리를 라우팅하는 설정 방법
Cloudflare Workers에서 하위 디렉터리 아래에 Astro 프로젝트를 배포할 때의 구성 단계입니다. wrangler.json과 astro.config를 조정하는 방법을 정리.
- sh -c 거동 및 zsh 구성 파일 읽기 규칙
sh -c 명령의 거동, 환경 변수의 상속 룰, shebang의 유효성, zsh 설정 파일(.zshrc, .zshenv등)이 스크립트 실행시에 어떻게 읽혀지는지를 정리.
- TypeScript에서 CRC32 해시 구현
CRC32 해시 알고리즘을 TypeScript로 구현하는 순서. 룩업 테이블을 사용한 고속화 기법과 실제 사용 예를 정리.
- Astro/Vue/Svelte 파일에서 Biome 미사용 경고 끄기
Astro, Vue, Svelte 파일에서 발생하는 Biome의 미사용 import/변수 경고를 overrides 설정으로 비활성화하는 방법.
- Go 환경 구성 메모: Web 프레임워크와 개발 도구
Go 개발 환경을 구성하면서 찾아본 Web 프레임워크와 개발 도구 메모. Echo 프레임워크와 Air 라이브 리로드 도구를 간단히 정리했다.
- libavif로 이미지를 AVIF 형식으로 변환하기
Homebrew로 libavif를 설치하고 JPEG/PNG를 AVIF로 변환하는 방법. 단일 변환과 배치 처리 모두 대응.
- macOS Launchd에서 정기 실행 스크립트 이동
macOS Launchd에서 Cron처럼 매분 실행하는 스크립트를 빌드하는 방법. 환경 변수 문제를 피하고 로그 관리를 포함한 설정 절차.
- zabrze로 시작하는 셸 약어 확장: zsh-abbr보다 단순한 선택지
셸 약어 확장 도구 zabrze의 설치와 사용법. zsh-abbr의 대안으로 더 단순한 설정으로 효율적인 명령 입력을 만드는 방법을 정리했다.
- TransformStream으로 줄 단위 텍스트 분할 구현하기: LineSplitTransform
스트림에서 받은 바이너리 데이터를 줄 단위로 분할하는 TransformStream 구현. 로그 파일과 텍스트 스트림의 점진 처리에 유용하다.
- OffscreenCanvas와 Web Worker로 이미지 처리를 구현하기
Web Worker와 OffscreenCanvas를 사용해 메인 스레드를 막지 않고 이미지 처리를 수행하는 방법. WebP 변환 예제를 중심으로 정리했다.
- 값을 ReadableStream으로 변환하는 TypeScript 유틸리티 함수
String이나 객체 등을 ReadableStream으로 변환하는 유틸리티 함수. Blob을 거치지 않고 임의 타입으로 스트림을 다루는 구현을 정리했다.
- TypeScript에서 CIDR 범위의 IP 주소 결정 구현
CloudFront Function 등 외부 모듈을 사용할 수 없는 환경용으로 CIDR 범위 내의 IP 주소 판정을 자체 구현. 비트 연산을 사용한 클래스 구문의 구현을 정리.
- Bun+Hono로 빌드된 API 서버를 AWS Lambda에서 실행하는 방법
Bun 런타임에서 Hono API 서버를 AWS Lambda에서 실행하는 단계. Single File Executable로 컴파일하고, Lambda Web Adapter로 움직이는 구성을 해설.
- generate-project-summary.py를 Bun + TypeScript로 다시 구현한 이야기
Python으로 작성된 프로젝트 구조 요약 스크립트를 Bun + TypeScript로 다시 구현했다. 저장소 전체를 LLM에 읽히기 위한 실행 파일 설계와 구현을 정리한다.
- 해상도로 미디어 파일을 정렬하는 TypeScript 구현
영상이나 이미지를 해상도(너비 × 높이) 기준으로 정렬하는 간결한 TypeScript 구현. Twitter 미디어 정렬에 활용할 수 있다.
- CloudFront + S3로 SPA를 배포하는 배포 스크립트
CloudFront 뒤의 S3에서 SPA를 제공할 때 쓸 수 있는 실전형 배포 스크립트. Cache-Control 설정, 블루그린 스타일 배포 구조, 롤백 절차를 정리했다.
- AWS Athena에서 비어 있지 않은 데이터베이스를 삭제하는 방법
AWS Athena에서 비어 있지 않은 데이터베이스를 삭제하려고 할 때 발생하는 오류의 해결 방법. DROP DATABASE CASCADE 사용법을 정리했다.
- TypeScript로 로토6·로토7 추첨 숫자 생성하기
메르센 트위스터를 사용해 로토6·로토7 번호를 생성하는 TypeScript 구현. 의사난수 생성기의 실전 예시.
- IAM 인증이 켜진 API Gateway에 TypeScript로 요청하기
AWS SDK for JavaScript의 SigV4를 사용해 로컬 환경의 TypeScript 코드에서 IAM 인증이 적용된 API Gateway로 요청을 보내는 구현 방법.
- markdown-confluence CLI로 Markdown을 Confluence에 동기화하는 운영
Git 저장소 안의 Markdown 문서를 Confluence로 동기화하기 위한 `@markdown-confluence/cli` 도입과 운영 방법. ADR과 각종 문서를 Confluence로 공유하는 흐름을 정리했다.
- Pinia 없이 글로벌 상태 관리Vue Composable
Pinia를 사용하지 않고 Vue의 reactive와 toRefs로 글로벌 스테이트 관리를 실현하는 경량의 구현 방법.
- Vue에서 v-if의 분기가 증가하면 전략 패턴을 고려하십시오.
v-if에 의한 조건 분기가 3 패턴 이상이 되면, 전략 패턴으로 컴퍼넌트를 동적으로 전환하는 구현을 검토. 가독성과 유지 보수성 향상.
- HTMLVideoElement에서 이미지를 생성하는 TypeScript 구현
Canvas와 VideoElement를 사용하여 동영상의 현재 프레임을 이미지로 추출하는 TypeScript 구현. Promise 기반으로 blob 생성하는 방법을 정리.
- PM2로 Cron 작업 만들기: launchd의 대안으로
macOS에서 launchd 대신 PM2를 사용해 Cron 작업을 만드는 방법. 설정 파일과 Bun을 사용한 주기 실행 예시를 정리했다.
- 처음 만드는 Vite 플러그인 구현: 빌드 메타데이터 자동 생성
Vite Plugin API를 사용해 Vite 빌드 라이프사이클에 커스텀 처리를 끼워 넣는 방법. 시간 기반 시맨틱 버전을 생성하는 플러그인 구현으로 정리했다.
- starlight-obsidian 플러그인에서 Vault 대상을 루트로 변경
starlight-obsidian 플러그인의 기본 동작을 변경하고 Obsidian Vault를 src/content/docs 바로 아래에 복사하는 방법. 사이드 바 계층 구조의 차이를 해소하는 구현을 정리.
- 이체 문자 선택기를 사용한 Steganography의 TypeScript 구현
Unicode의 이체자 셀렉터를 활용해, 외형에는 보이지 않는 비밀의 캐릭터 라인을 텍스트에 임베드하는 스테가노그래피 기법의 TypeScript 구현.
- Twitter 동영상 URL에서 크기 정보를 추출하는 TypeScript 구현
Twitter(X) 동영상 URL에 포함된 해상도 정보를 정규표현식으로 추출하는 TypeScript 구현. URL 패턴과 크기 추출 방법을 정리했다.
- 브라우저에서 Google Fonts에서 WOFF 파일을 가져 오는 데 실패한 비망록
클라이언트 측에서 Google Fonts에서 ttf/otf/woff 파일을 가져와 @vercel/satori에서 사용하려고 시도한 시행 착오 기록. User-Agent 헤더 제한 및 woff2 비대응 문제에 대한 정리.
- Bitbucket Pipelines에서 Yarn v4 (PnP 모드)를 돌리는 설정
Bitbucket Pipelines에서 Yarn v4의 PnP 모드를 쓰는 프로젝트를 빌드하는 설정 방법. 캐시 설정과 corepack 활성화 절차를 정리했다.
- Cloudflare Pages에서 Pagefind 검색이 동작하지 않았던 이유: 원인은 Rocket Loader였다
Astro + Pagefind 조합이 로컬에서는 정상인데 Cloudflare Pages 배포 후 검색이 동작하지 않았던 문제의 원인과 해결 방법.
- 이미지 관리 앱 Eagle을 구입하고 느낀 것
구매한 이미지 관리 앱 Eagle을 구입한 이유와 리뷰. Mac/Win 양대응, 라이브러리 관리, 브라우저 확장 기능의 편리함을 소개.
- Svelte로 Google Apps Script 기반 고기능 웹앱 만들기
Google Apps Script의 웹앱 공개 기능과 Svelte를 조합해, 스프레드시트를 데이터베이스처럼 사용하는 고기능 SPA를 만드는 방법.
hsb.horse