Rails8 Cross Project Patterns And Improvements

Rails 8 프로젝트 간 패턴 교차 적용 — rack-attack, PWA 배너, Sentry, FCM 멀티디바이스

두 개의 Rails 8 프로젝트를 병렬로 운영하다 보면 한쪽에서 공들여 만든 패턴이 다른 쪽에는 빠져있는 경우가 자주 생긴다. 기능을 구현할 때는 당장의 요구사항에 집중하다 보니 다른 프로젝트의 좋은 구현을 챙기지 못하는 것이다. 이번에 두 프로젝트를 나란히 놓고 비교하면서 빠진 부분을 서로 채워주는 작업을 했다. 주로 보안, PWA 경험, 에러 추적, 푸시 알림 인프라에 관한 내용이다. 비교 분석 방법 두 프로젝트의 주요 파일을 나열하고 대조했다. 확인 항목 ├── Gemfile (gem 목록) ├── config/initializers/ (설정 파일) ├── app/javascript/controllers/ (Stimulus 컨트롤러) ├── app/views/layouts/application.html.erb (레이아웃) ├── db/schema.rb (DB 스키마) └── ios/ (iOS 네이티브 설정) 결과적으로 아래 6가지를 양방향으로 이식했다. ...

2026-02-20 · 6분 소요 · Seunghan
Rails Sso Turbo Drive Debugging

Rails SSO 구현 중 Turbo Drive가 유발한 두 가지 버그 디버깅

Rails 앱 간 SSO(Single Sign-On)를 HMAC 기반으로 구현하던 중 예상치 못한 두 가지 버그를 만났다. 둘 다 Turbo Drive와 ERB의 동작 방식에서 비롯된 문제였다. 구현 개요 구조 IdP (Identity Provider): 사용자 인증을 담당하는 Rails 앱 (OTP 로그인) SP (Service Provider): IdP에서 인증받아 로그인하는 Rails 앱 플로우 SP 로그인 버튼 클릭 → SP: state 생성 후 세션 저장, IdP /authorize로 리다이렉트 → IdP: 로그인 확인 후 One-Time Token 발급 → IdP: authorize_complete 페이지 표시 (2초 후 SP callback으로 자동 리다이렉트) → SP callback: state 검증 + token 검증 → 로그인 완료 핵심 보안 요소 CSRF 방지: SP에서 생성한 state를 세션에 저장하고 callback에서 검증 HMAC 서명: SP가 IdP의 /verify 엔드포인트에 서명된 요청으로 token 검증 One-Time Token: 한 번 사용하면 무효화되는 토큰 버그 1: “state mismatch” — Turbo Drive prefetch가 세션을 덮어쓴다 증상 SP의 “SSO 로그인” 버튼을 클릭하면 IdP에서 인증 완료 페이지까지 잘 가는데, SP callback에서 항상 state mismatch 에러가 발생했다. ...

2026-02-13 · 4분 소요 · Seunghan
Rails Rfc3161 Tsa Blockchain Merkle Debugging

RFC 3161 TSA 타임스탬프 + 블록체인 Merkle 앵커링: Rails에서 삽질 기록

전자계약 보관 시스템에 법적 증거력을 부여하기 위해 두 가지를 동시에 구현해야 했다: 블록체인 Merkle Tree 앵커링 — 계약 해시들을 모아 Merkle Root를 L2 체인에 기록 RFC 3161 TSA 타임스탬프 — 신뢰할 수 있는 제3자 시간 증명 간단해 보였는데, 삽질의 연속이었다. 1. RFC 3161 TSA란? RFC 3161은 Time-Stamp Authority(TSA) 프로토콜로, 특정 데이터가 특정 시점에 존재했음을 제3자가 증명해주는 표준이다. 흐름은 간단하다: 클라이언트 → SHA-256 해시 생성 → TSA 서버에 요청 → 서명된 타임스탬프 토큰 수신 무료 TSA 서버들: ...

2026-02-06 · 4분 소요 · Seunghan
Rails Turbo Actioncable 500 Debug

Rails Turbo Stream 500 에러 3종 세트 디버깅 — broadcast, SolidCable, Telegram Markdown

Rails 8 + Hotwire(Turbo) 기반 앱을 운영하다 보면 broadcast_append_to 계열 콜백이 조용히 500을 내뱉는 경우가 있다. 거기에 SolidCable 초기 설정 문제와 Telegram Bot 메시지 파싱 오류가 겹치면 로그 해석도 헷갈린다. 이번에 세 가지가 한꺼번에 터져서 순서대로 해결한 과정을 정리한다. 문제 1: No unique index found for id — broadcast 콜백 500 현상 메시지나 알림을 생성할 때 컨트롤러에서 500이 발생한다. 로그를 보면: MessagesController#create error: No unique index found for id 원인 Rails after_create_commit 콜백 안에서 broadcast_append_to 를 호출할 때, 내부적으로 ActionCable 채널을 통해 메시지를 전달하는 과정에서 예외가 발생한다. SolidCable을 쓰는 경우 특히 초기 설정이 완전하지 않으면 이 에러가 자주 나온다. ...

2026-01-09 · 4분 소요 · Seunghan
Rails Ruby3 Kwargs Dispatch Integration Debug

하루 종일 삽질한 것들 — Ruby 3.0 kwargs, Docker env, NAS 크론, SSH 특수문자

AI 에이전트가 Rails API 서버를 호출해서 티켓을 자동 배정하는 디스패처를 만들었다. 로직 자체는 간단한데 붙이는 과정에서 예상치 못한 곳에서 계속 막혔다. 겪은 것들을 기록해 둔다. 1. Ruby 3.0 kwargs 분리 — render_success(key: val) 가 왜 터지나 가장 오래 고생한 것. Rails 컨트롤러에서 응답 헬퍼를 이렇게 호출했다: render_success(tickets: tickets_list, pagination: pagination_data) 서버 로그에 찍힌 에러: ArgumentError - unknown keywords: :tickets, :pagination 헬퍼 정의는 이렇다: def render_success(data, status: :ok) render json: { success: true, data: data }, status: status end Ruby 2.x에서는 render_success(tickets: ..., pagination: ...) 호출 시 {tickets: ..., pagination: ...} 해시가 data에 들어갔다. ...

2026-01-02 · 5분 소요 · Seunghan
Crypto Exchange Api Integration Lessons

5개 암호화폐 거래소 API 연동하면서 겪은 삽질 모음

Ruby on Rails로 여러 암호화폐 거래소의 펀딩레이트(funding rate)를 수집하는 기능을 만들면서 겪은 문제들을 정리한다. 5개 거래소를 붙이면서 각 거래소마다 API 동작 방식이 달랐고, 공식 문서와 실제 동작이 다른 경우도 있었다. 거래소 API의 공통 기반 클라이언트 만들기 여러 거래소를 붙이기 전에 공통 HTTP 클라이언트를 먼저 만들었다. Faraday를 사용했고, 재시도와 Circuit Breaker를 여기에 몰아 넣었다. Faraday + faraday-retry 설정 # Gemfile gem "faraday" gem "faraday-retry" def connection @connection ||= Faraday.new(url: base_url) do |f| f.request :retry, { max: 3, interval: 0.5, backoff_factor: 2, interval_randomness: 0.5, # jitter retry_statuses: [429, 503, 504], retry_block: -> (env, options, retries, exc) { Rails.logger.warn("[#{exchange_name}] Retrying... #{retries} left. Status: #{env.status}") } } f.adapter Faraday.default_adapter f.options.timeout = 10 f.options.open_timeout = 5 end end backoff_factor: 2와 interval_randomness: 0.5(jitter)를 조합하면 재시도 간격이 0.5초 → 1초 → 2초로 지수 증가하면서 약간의 무작위성이 붙는다. 거래소 API가 Rate Limit(429)을 돌려줄 때 모든 클라이언트가 동시에 재시도하는 “thundering herd” 문제를 막아준다. ...

2025-12-06 · 6분 소요 · Seunghan
Telegram Bot Intent Classification Bugs

Telegram 봇 의도 분류 버그 3가지와 Inline Keyboard 확인 플로우 구현

Telegram 봇에 자연어로 할 일을 추가하는 기능을 운영하던 중 발생한 버그 3가지와, 사용자 경험 개선을 위한 inline keyboard 확인 플로우 구현 내용을 정리한다. 버그 1: “저녁9시” → 09:00(AM)으로 파싱되는 문제 현상 입력: "내일 저녁 커피챗 미팅 저녁9시일정추가" 기대: due_time = "21:00" 실제: due_time = "09:00" 원인 extract_time_from_text 메서드에서 패턴 체크 순서가 잘못되어 있었다. # 버그 코드 if match = text.match(/오후\s*(\d{1,2})시/) # 1) 오후 ... end if match = text.match(/오전\s*(\d{1,2})시/) # 2) 오전 ... end if match = text.match(/(\d{1,2})시\s*(\d{1,2})?분?/) # 3) 숫자시 ← 여기서 "9시" 매칭 hour = match[1].to_i # 9 → "09:00" 반환, 아래 case/when은 도달 불가 return "#{hour.to_s.rjust(2, '0')}:00" end case text when /저녁/ return "18:00" # ← 절대 도달 못 함 end “저녁9시"에서 오후, 오전 패턴은 불일치하지만 세 번째 /(\d{1,2})시/ 패턴이 9시를 잡아 09:00을 반환해버린다. 그 아래 case when /저녁/은 절대 실행되지 않는다. ...

2025-06-25 · 5분 소요 · Seunghan
개인정보처리방침 문의