전체 글 112

[App] 백엔드 연동 FCM 푸쉬 알림 구현 - 토픽 메시징 방식

공지사항을 등록한 뒤 앱 사용자 전체에게 푸쉬 알림을 발송하고, 알림을 탭하면 해당 공지사항 화면으로 이동하는 기능을 구현했다.Firebase Cloud Messaging(FCM)을 사용하되, 개별 토큰을 DB에 저장하는 방식 대신 토픽 메시징(Topic Messaging) 을 선택했다.🔹Firebase 프로젝트 초기 연동 순서1. Firebase 프로젝트 생성console.firebase.google.com 접속프로젝트 추가 → 이름 입력 → 생성생성 후 좌측 Engage → Messaging 활성화 확인2. Android 앱 등록프로젝트 홈에서 Android 아이콘 클릭패키지명 입력 — capacitor.config.json의 appId와 반드시 동일해야 함등록 후 google-services.j..

[App] Android WebView CORS 에러(with CapacitorHttp)

🔹문제 상황Capacitor로 빌드한 Android 앱에서 로그인 후 API 요청이 전부 실패했다.에뮬레이터 logcat을 확인하니 CORS 오류가 찍히고 있었다.Access to XMLHttpRequest at 'http://서버주소/api/v1/...' from origin 'http://localhost' has been blocked by CORS policy 웹 브라우저에서는 Vite 개발 서버가 프록시로 중계해줘서 CORS가 없었지만, Android 앱에서는 달랐다.🔹원인 분석Capacitor 앱의 요청 출처Capacitor 앱은 내부적으로 WebView 위에서 동작한다.앱이 로드되는 주소는 http://localhost (또는 capacitor://localhost)이며,이 주소에서 외부..

[App] Vue 웹 프로젝트 Capacitor + Ionic 도입

사내에서 운영 중인 Vue 3 기반 웹 플랫폼에 대해 앱 버전이 필요하다는 요청을 받았다.이번 마이그레이션은 별도 앱을 새로 만들지 않고, 기존 웹 소스를 그대로 유지하면서 모바일 앱을 함께 제공하는 구조를 목표로 했다.네이티브 앱을 처음부터 새로 개발하는 것은 리소스 낭비라고 판단했고, 웹과 앱을 단일 코드베이스에서 관리할 수 있는 방향을 찾았다. 🔹 기술 선택1. Capacitor + IonicCapacitor기존 웹 앱을 네이티브 앱으로 감싸는 브릿지 역할React Native처럼 별도 런타임이 필요 없고, 기존 Vite + Vue 빌드 파이프라인을 그대로 사용 가능Ionic Vue모바일 UX에 최적화된 컴포넌트 제공 (IonPage, IonHeader, IonNav 등)기존 웹 화면은 손대지 않..

[Linux] 서버 작업 기록 - Tomcat 다중 인스턴스 구성

기존 운영 중인 Tomcat 인스턴스와 별도로 신규 프로젝트용 Tomcat 인스턴스를 동일 서버에 추가 구성하였다.하나의 서버에 두 개의 Tomcat 인스턴스를 띄우고, 각각 독립된 포트와 경로로 운영하는 것이 목표다. 1. 현재 서버 상태 확인# 실행 중인 Tomcat 프로세스 확인ps -ef | grep tomcat# 열려있는 포트 확인ss -tlnp# DB(postgres) 상태 확인- {port}는 사용중인 포트ps -ef | grep postgresss -tlnp | grep {port} # Tomcat 설치 경로 탐색find / -name "catalina.sh" 기존 인스턴스는 apt 패키지로 설치되어 있었다.패키지 설치 방식은 리눅스 규칙에 따라 바이너리/설정/데이터를 각각 다른 경로에 ..

[Vue] 라이브러리 없이 Vue 3 그리드 직접 구현하기

기존 시스템은 IBSheet라는 상용 그리드를 사용하고 있었는데,Vue 3 전환 시점에 대체 라이브러리를 검토하다가 비용 및 라이선스 문제로 Vue3 방식으로 내부 구현하였다. 전체 구조레이어를 두 개로 분리했다. 상태(State)와 뷰(View)를 분리한 이유는 간단하다.마스터/디테일처럼 한 화면에 그리드가 여러 개인 경우, useGrid()를 여러 번 호출하기만 하면 각각 독립적인 상태를 가진다.Pinia에 올렸다면 화면마다 store 모듈을 따로 만들거나 네임스페이스를 관리해야 했을 것이다. useGrid : 행 상태 추적 설계_key : 행의 고유 식별자서버 PK 대신 내부 시퀀스 키를 별도로 부여한다. 모듈 레벨에서 선언하기 때문에 여러 useGrid() 인스턴스가 공유하고, 두 그리드 사이..

[Swagger] Spring MVC 환경에서 Springfox 3.0.0 Swagger 적용

Spring Boot가 아닌 순수 Spring MVC 기반의 WAR 프로젝트에서 REST API를 개발하면서 프론트엔드 협업과 테스트 편의를 위해 Swagger UI를 도입했다.흔히 Swagger 적용은 springfox-boot-starter 하나 추가하면 끝난다고 알려져 있지만, Spring Boot 없이 직접 설정하는 경우에는 몇 가지 추가 작업이 했다. 환경 정보항목내용프레임워크Spring MVC 5.3.30 (non-Boot)배포 방식WAR Swagger 라이브러리springfox 3.0.0Java17인증 방식JWT (CommonInterceptor에서 토큰 검증) 1단계: 의존성 추가 (pom.xml)Spring Boot 환경에서는 springfox-boot-starter 하나로 충분하..

[인증/Axios] 동시 요청 처리 - 동시성 제어와 비동기 타이밍 문제

문제 상황페이지가 로드되자마자 API 3개가 동시에 날아갔는데, 마침 Access Token이 만료된 상태였다.요청A → GET /api/users → 401 요청B → GET /api/menus → 401요청C → GET /api/settings → 401 세 요청이 동시에 401을 받았고, Axios 인터셉터가 세 번 실행됐다.이 상황을 제대로 처리하지 않으면 세 가지 문제가 생긴다.Refresh Token 중복 호출대기 중인 요청 처리 누락재시도 무한 루프 각각 어떻게 막는지 정리해봤다. 원인과 해결 구조1. isRefreshing : 재발급 중복 방지isRefreshing이 없으면 세 요청이 각자 /api/v1/refresh를 호출한다.요청A → POST /api/v1/r..

[REST API/보안] HTTPS와 CSRF 제대로 이해하기

URL 노출과 암호화는 다른 문제다GET 대신 POST를 쓰면 데이터가 URL에 노출되지 않는다. 맞는 말이다. 그런데 여기서 많이들 멈추는데, 사실 이건 브라우저 주소창과 서버 로그 얘기다. 네트워크 구간 얘기가 아니다. HTTP면 GET이든 POST든 네트워크에서 평문으로 노출된다. 암호화는 HTTPS(TLS)가 담당하는 영역이고, GET/POST 선택과는 완전히 별개의 문제다. 요청이 전달되는 레이어 구조애플리케이션@RequestBody / URLSearchParams Spring이 데이터를 파싱하는 레이어GET/POST 구분이 여기서 의미 있음HTTP요청 메서드, 헤더, Body가 여기 있음.HTTP면 이 내용이 그대로 평문으로 전송됨TLS (HTTPS)이 레이어가 전체 HTTP 내용을 암호화함..

[REST API] @RequestParam vs @RequestBody vs URLSearchParams

REST API 구조로 전환하면서 클라이언트 요청 방식을 전면 재검토하게 됐다. 기존에는 CmmnUtil.getParameters(request)로 request에서 파라미터를 통째로 꺼내는 방식을 쓰고 있었는데, REST API로 전환하면서 @RequestParam, @RequestBody, URLSearchParams 중 무엇을 어떻게 써야 하는지 서버단과 화면단에서 통일을 해야하므로 한번 정리해보았다. 기존 레거시 코드는 HttpServletRequest에서 직접 파라미터를 꺼내는 구조@RequestMapping(value = "/getPost")@ResponseBodypublic Object getPost(HttpServletRequest request) throws Exception { ..