nogamsung
앱 안 통화를 OS 통화로 등록해 백그라운드에서도 음성 유지하기

앱 안 통화를 OS 통화로 등록해 백그라운드에서도 음성 유지하기

Flutter와 LiveKit으로 만든 통화가 홈으로 나가면 음성이 끊기고 다이나믹 아일랜드도 뜨지 않던 문제를 정리합니다. UIBackgroundModes audio만으로는 부족했고, 직접 건 통화와 앱 안에서 받은 통화까지 CallKit·Android Telecom에 등록하고 오디오 세션의 주인을 CallKit 하나로 정해 해결했습니다. 웹 통화의 오디오 재부착과 영상통화 백그라운드 처리도 함께 다룹니다.

GitHub Environment Secrets와 Kamal로 서버 env 관리하기, 값은 숨기고 실패 이유는 남기기

GitHub Environment Secrets와 Kamal로 서버 env 관리하기, 값은 숨기고 실패 이유는 남기기

서버에서 vi로 고치던 env 파일을 GitHub Environment Secret 번들 하나로 옮기고, 배포 때마다 Kamal이 읽는 서버 파일을 원자적으로 다시 쓰게 바꾼 과정을 정리합니다. 값은 로그에 절대 남기지 않으면서도 실패 이유는 행 번호와 고정된 분류 코드로 남기는 방법, 첫 전환 때 옛 서버 값과 다르면 컨테이너 교체 전에 멈추는 안전장치, SSHKit 호스트 키 핀 문제를 다룹니다.

모노레포 배포 시간 실측과 단축기, 35분 걸리던 백엔드 전체 배포를 13분으로

모노레포 배포 시간 실측과 단축기, 35분 걸리던 백엔드 전체 배포를 13분으로

백엔드 10개·웹 13개 모노레포의 배포 73회를 실측해 보니 60%가 전체 배포였고, 원인은 공용 모듈의 응답 코드 enum 하나와 Dockerfile의 chown -R 한 줄이었습니다. 응답 코드를 서비스별로 나누고, 이미지가 나오는 대로 배포하고, 프런트·Flutter는 실제 의존 그래프로 영향 범위만 빌드·검사하게 바꿔 전체 배포를 35.6분에서 13.7분으로 줄인 과정을 정리합니다.

권한을 바꿨는데 30분 동안 옛 권한으로 동작한다, JWT에 권한 버전 심기

권한을 바꿨는데 30분 동안 옛 권한으로 동작한다, JWT에 권한 버전 심기

stateless JWT의 roles 클레임은 발급 시점 값이라 관리자가 권한을 바꿔도 토큰 수명(30분) 동안 옛 권한으로 메뉴와 API가 동작했습니다. 블랙리스트 대신 토큰에 권한 계산 시각(pv)을 넣고 Redis의 변경 시각과 비교해 401로 끊는 설계, 커밋 전 캐시 재적재 레이스, fail-open 선택까지 정리합니다.

내부 서비스 호출에 서킷브레이커를 넣으며 권한 조회를 fail-open에서 fail-closed로 바꾼 이야기

내부 서비스 호출에 서킷브레이커를 넣으며 권한 조회를 fail-open에서 fail-closed로 바꾼 이야기

서비스 API 9개가 account 서비스에 권한을 묻는 구조에서, 조회 실패 시 "허용"하던 fail-open 설계는 장애가 곧 권한 우회였습니다. Resilience4j로 호출부 단위 회로 4개를 두고, 무엇을 실패로 셀지(4xx 제외), 회로 OPEN을 liveness에 연결하지 않는 이유, 권한 조회를 503 fail-closed로 바꾼 결정과 그 직후 드러난 배포 공백 문제까지 정리합니다.

Claude Code와 Codex를 같은 하네스로, CLAUDE.md에서 AGENTS.md로

Claude Code와 Codex를 같은 하네스로, CLAUDE.md에서 AGENTS.md로

한쪽 구독이 끊겨도 다른 쪽 하나로 전부 돌아가게, 그리고 손으로 두 벌 고치는 설정 파일 없이. 지침 파일을 AGENTS.md 하나로 바꾸고, 빌드·커버리지 게이트를 에이전트 훅에서 git 훅으로 옮기고, 스킬 32개를 한 폴더에 모으고, PR마다 반대편 모델이 리뷰하게 만든 하루의 PR 다섯 개를 정리합니다. 그 과정에서 발견한 "한 번도 막지 못하고 있던 훅"과 "한 번도 돌지 않고 있던 git 훅" 이야기도 함께.

Spring Boot 4 업그레이드, 그리고 final 엔티티 때문에 LAZY가 사실 EAGER였다

Spring Boot 4 업그레이드, 그리고 final 엔티티 때문에 LAZY가 사실 EAGER였다

Spring Boot 3.4에서 4.1로, Kotlin 1.9에서 2.3(K2)으로 18개 모듈을 하루에 올리며 알게 된 것들. Kotlin 2.x의 plugin.jpa가 all-open을 켜면서 final이던 엔티티가 open이 되고, 그제야 @ManyToOne(LAZY) 67곳이 지금까지 EAGER로 돌고 있었다는 사실과 가짜 fetch join 179곳이 드러났습니다. Jackson 3 때문에 전 요청이 39ms 만에 408이 난 사고도 함께 정리합니다.