바로신고

바로신고 다산콜센터(120), 경찰청(112), 소방서(119)에 문자 기반 긴급 신고를 빠르고 간편하게 할 수 있는 앱입니다. 주요 기능 신고 대상 선택 — 다산콜센터, 경찰청, 소방서 중 선택 간편한 신고 작성 — 상황 설명 입력 + 사진 첨부 신고 이력 관리 — 접수완료, 처리중 등 상태 실시간 확인 알림 기능 — 신고 접수 및 처리 완료 푸시 알림 기술 스택 영역 기술 Backend Rails 8 + Turbo iOS Hotwire Native 1.2.2 (Swift, XcodeGen) Android Hotwire Native 1.2.5 (Kotlin) 호스팅 Render 다운로드 App Store (심사 중) Google Play (준비 중) 지원 문의: theqwe2000@naver.com ...

2026-03-07 · 1분 소요 · Seunghan

Flutter+Rails 실시간 인프라 4대 단절 고치기 — FCM 딥링크, ActionCable JWT, 익명→회원 연결

토너먼트 앱 하나를 Flutter로 전환하고 있는데, 사용자 입장에서 제일 중요한 시나리오가 동작을 안 했다. “로그인 → 알림 수신 → 알림 탭 → 내 코트로 이동 → 대기/경기/결과 확인”. 이게 끊기면 앱이 있으나 마나다. 처음에는 코드 조각은 대부분 있는 것 같았다. FCM 토큰 등록 로직도 있고, ActionCable 클라이언트 클래스도 있고, 스코어 입력 화면도 있다. 그런데 막상 실제로 알림을 탭해도 앱이 홈으로만 열린다. 실시간 업데이트도 안 온다. 왜? 탐색해보니 연결된 것처럼 보이는 부품 사이에 네 군데가 끊겨 있었다. 이 포스트는 그 네 군데를 하루 세션에서 다 고친 기록이다. 각 단절마다 왜 그게 2026년에도 여전히 함정인지 근거도 같이 정리한다. ...

2026-04-16 · 9분 소요 · Seunghan

LLM이 지어낸 법령을 DB로 걸러내기 — 한국어 법률 인용 환각 방지 실전

법률 AI 서비스를 만들다 보면 이런 순간이 온다. LLM이 자신감 있게 “민법 제103조의2에 따라…” 라고 답변을 줬는데, 확인해보니 제103조의2라는 조문은 존재하지 않는다. 본조인 제103조만 있고 가지조문은 만들어진 것이다. 이게 얼마나 심각한 일인지는 이미 유명한 사건이 증명했다. 2023년 미국 Mata v. Avianca 소송에서 뉴욕의 한 변호사가 ChatGPT가 생성한 판례를 법원 제출서류에 인용했다가 제재를 받았다. 판례가 전부 지어낸 것이었던 거다. 법률 도메인에서 AI 환각은 그냥 버그가 아니라 법률 책임 문제로 번진다. 이번 작업에서 내가 만든 서비스도 같은 위험에 노출돼 있었다. 사용자가 법령 개정 diff를 보면서 “이 개정이 우리 회사에 어떤 영향?” 같은 후속 질문을 하면, LLM이 답변을 돌려주면서 근거 조문을 인용한다. 그 인용이 진짜인지 아닌지를 사용자에게 떠넘길 수는 없었다. ...

2026-04-09 · 10분 소요 · Seunghan

AI로 디자인 시스템 마이그레이션했는데 사실 CSS 리스킨이었다 — Token/Component/Template/Page 4-layer 재설계 회고

Rails 8 + Hotwire 프로젝트에 iOS 26 Liquid Glass 디자인 시스템을 전면 도입했다. 7주간 39개 페이지를 마이그레이션했고, 디자인 가이드 위반 417건이 0건이 됐다. 18개 파일로 구성된 마이그레이션 설계서도 있었고, 단계별(Phase 1-7) 체크리스트도 있었다. 스스로 만족했다. 그 다음에 사용자가 한마디 했다. “토큰/컴포넌트/템플릿/페이지 형태로 반영이되어야하는데 디자인시스템부터 점검해” 그 문장 하나로 전부 무너졌다. 점검해보니 내가 한 건 디자인 시스템이 아니라 CSS 리스킨이었다. 이 글은 그 깨달음과 재설계 과정의 기록이다. AI 코딩의 함정 — 페이지마다 “시스템처럼” 보이게 만들기 처음에는 단계별로 잘 진행했다고 생각했다. 토큰 파일을 만들었고(iOS 26 79개 컬러 × 4모드), 6개 공통 ERB 파셜을 만들었고(toolbar, list_row, button 등), 각 페이지마다 전용 CSS 파일을 분리했다. 39개 페이지가 모두 새 디자인으로 바뀌었고, grep으로 위반을 측정했더니 0건이었다. ...

2026-04-08 · 10분 소요 · Seunghan

프로필 페이지 발표자료 핀 시스템 — Instagram 스타일 +N 오버레이 카드 만들기

공개 프로필 페이지를 만들고 있었다. link-in-bio 스타일로, /@username 경로에서 사용자의 소개, 링크, 발표자료를 보여주는 페이지다. 발표자료가 9개 올라가 있었는데, 전부 나열하니까 프로필이 포트폴리오 사이트처럼 변해버렸다. 스크롤이 길어지고, 정작 중요한 링크들이 묻혔다. 사용자가 원하는 3개만 “핀"해서 보여주고, 나머지는 별도 페이지로 유도하는 게 맞았다. 그런데 “더보기"를 어떻게 보여줄지가 문제였다. 별도 버튼? 빈 카드? 결국 Instagram 앨범처럼 마지막 썸네일 위에 반투명 오버레이를 올리는 방식으로 갔다. 이 글은 그 과정의 기록이다. 기존 구조: 전부 보여주기 처음 구현은 단순했다. 컨트롤러에서 published.on_profile 스코프로 가져온 발표자료를 전부 넘기고, 프론트에서 2열 그리드로 렌더링했다. ...

2026-04-05 · 7분 소요 · Seunghan

Inertia.js v2→v3 마이그레이션 — Svelte 5 + Rails 8 실전 삽질 기록

Rails 8 + Svelte 5 프로젝트에서 @inertiajs/svelte를 v2에서 v3로 올렸다. “패키지 버전만 올리면 되겠지"라는 안일한 생각으로 시작했다가 반나절을 날렸다. 이 글은 그 삽질의 기록이다. 왜 업그레이드해야 했나 프로젝트에서 Svelte 5를 쓰고 있었는데, @inertiajs/svelte v2는 Svelte 5를 “대충” 지원했다. 문제는 persistent layout이었다. Svelte 5는 컴포넌트를 함수로 컴파일하는데, Inertia v2는 page.default.layout = AppLayout 처럼 클래스 기반 컴포넌트에 속성을 추가하는 방식을 썼다. Svelte 5에서는 이게 작동하지 않았다. 결과적으로 40개 넘는 페이지에 <AppLayout>을 수동으로 감싸야 했다. 유지보수 악몽이었다. ...

2026-04-04 · 7분 소요 · Seunghan

Hotwire Native에서 Flutter BLoC으로 — 네이티브 앱 전환 실전기

Rails 웹앱에 Hotwire Native로 iOS 앱을 감싸서 출시했는데, 접속 오류로 심사가 반복 반려됐다. WebView 기반의 한계를 느끼고 Flutter + BLoC 패턴으로 순수 네이티브 전환을 결정했다. 이 글은 실제로 웹앱을 Flutter 앱으로 전환하면서 겪은 설계, 삽질, 해결 과정을 정리한 것이다. Hotwire Native가 안 된 이유 Hotwire Native는 WKWebView 위에 얇은 네이티브 셸을 씌우는 구조다. Turbo Navigator가 URL 기반으로 네비게이션을 처리하고, Bridge Component로 네이티브 UI를 부분적으로 제어한다. 웹 개발자 입장에서는 최소 비용으로 앱을 만들 수 있어서 매력적이다. ...

2026-03-31 · 9분 소요 · Seunghan

Hotwire Native에서 Flutter로 — Rails 앱의 모바일 네이티브 전환 실전기

Rails 8 + Hotwire로 웹을 만들고, Hotwire Native로 iOS/Android를 감싸면 꽤 그럴듯한 앱이 나온다. WebView가 서버 렌더링 HTML을 그대로 보여주니 코드 한 벌로 3플랫폼을 커버할 수 있다. 실제로 이 방식으로 프로덕션에서 잘 돌아가는 앱을 운영하고 있었다. 그런데 점점 한계가 보이기 시작했다. 오프라인 지원이 안 되고, 네이티브 애니메이션도 못 쓰고, WebView 특유의 뚝뚝 끊기는 느낌이 있었다. 결국 Flutter로 풀 네이티브 전환을 결정했고, 설계부터 프로덕션 배포까지 약 2주 만에 끝냈다. 그 과정을 정리한다. ...

2026-03-31 · 9분 소요 · Seunghan

Rails 8에서 Devise 걷어내기 — has_secure_password로 마이그레이션한 실전 기록

Devise가 Inertia.js와 싸우기 시작했다 Rails 8 + Inertia.js + Svelte 5 스택으로 운영하던 프로젝트에서 로그인이 안 되는 버그가 터졌다. 에러 메시지도 없고, 401만 돌아왔다. 로그를 보니 Warden의 database_authenticatable strategy가 valid_for_params_auth? = false를 찍고 있었다. 쿼리가 0개 — DB에 접근조차 안 한 것이다. 원인은 Devise의 Warden 미들웨어가 request.params[:user]를 읽는데, Inertia.js는 {email, password}를 flat하게 보내서 Rails의 ParamsWrapper가 session 키로 감싸버리는 구조적 충돌이었다. # Inertia.js가 보내는 것 { email: "user@example.com", password: "secret" } # Rails ParamsWrapper가 변환한 것 { email: "...", password: "...", session: { email: "...", password: "..." } } # Devise/Warden이 찾는 것 { user: { email: "...", password: "..." } } # ← 이게 없다 normalize_sign_in_params라는 핵으로 params[:user]를 세팅했지만, Warden은 ActionController의 params가 아니라 **Rack 레벨의 request.params**를 따로 읽었다. 두 객체는 완전히 별개다. ...

2026-03-31 · 7분 소요 · Seunghan

Render 배포 실패 두 가지 — npm lockfile dev 플래그와 DATABASE_URL 소켓 오류

Render에서 배포가 갑자기 안 되기 시작했다. 한 번도 아니고 두 번 연속으로, 서로 다른 이유로. 첫 번째는 Vite 빌드에서 패키지를 못 찾는다는 에러, 두 번째는 Rails 서버가 PostgreSQL에 소켓으로 연결하려다 죽는 오류였다. 둘 다 원인을 찾기까지 상당히 헤맸다. 첫 번째 오류: Cannot find package 'vite-plugin-ruby' 빌드 로그에 이런 에러가 찍혔다. failed to load config from /opt/render/project/src/.../vite.config.ts error during build: Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'vite-plugin-ruby' imported from vite.config.ts vite-plugin-ruby는 분명히 package.json의 dependencies에 들어있었다. devDependencies가 아니라 dependencies에. ...

2026-03-30 · 4분 소요 · Seunghan
개인정보처리방침 이용약관 면책조항 문의