
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
-
본 서비스는 요양보호사 구직 시장의 특징을 분석하여,
요양 센터와 요양보호사 간의 구인·구직 과정을 보다 간편하게 지원하는 애플리케이션입니다. -
워크넷에 매일 등록되는 요양보호사 구인 공고와 위도 경도 기반위치 정보를 자동 크롤링하여 수집하고,
이를 사용자에게 필요한 정보만으로 정재하여 위치 정보를 기반으로 가까운 공고를 제공합니다. -
요양보호사는 관심 있는 공고에 대해 센터에 전화하거나, 채팅 기능을 통해 직접 문의할 수 있습니다.
👉 불필요한 탐색 없이, 위치 기반으로 실시간 맞춤 공고를 확인하고,
즉시 소통 가능한 채널을 통해 효율적인 구직 활동을 지원합니다.
항목 | 내용 |
---|---|
📆 진행 기간 | 2025.01 ~ 운영 중 |
🤖 백엔드 기술 스택 | Kotlin, Spring Boot, Spring Batch, Spring Data JPA, MySQL, Redis, S3 |
⚙️ 인프라 기술 스택 | Docker, GitHub Actions, Firebase Cloud Messaging, Sentry, Nginx, AWS (VPC, Internet Gateway, NAT Gateway, Route Table, Security Group, EC2, RDS 등) → 이후 비용 문제로 Home Server 환경으로 이전 |
🖥️ 고정 IP 및 외부 접근 설정
Ubuntu가 설치된 노트북에서 DHCP 설정을 비활성화하여 내부 IP를 고정하고,
공유기에서 포트 포워딩을 통해 외부에서 접속 가능한 홈 서버 환경을 구축하였습니다.
🌐 Dynamic DNS를 통한 도메인 연결
공인 IP가 주기적으로 변경되는 문제를 해결하기 위해,
Dynamic DNS 서비스를 사용하여 IP 변경 시에도 도메인으로 서버에 안정적으로 접근할 수 있도록 구성했습니다.
🔐 보안 설정 및 SSL 처리
- SSH 접속은 RSA 키 기반 인증으로 보안을 강화하였습니다.
- 443 포트로 들어오는 HTTPS 요청에 대해서는 Nginx에서 SSL Termination을 적용해 암호화를 처리하였습니다.
🔁 Nginx 리버스 프록시 구성
Nginx에서 /caremeet-dev
, /caremeet
등의 경로에 따라
각기 다른 포트에서 실행 중인 개발용 및 운영용 애플리케이션 서버로 트래픽을 분기하였습니다.
✅ 리버스 프록시 및 보안 구성
Nginx를 통해 외부 요청을 수신하고, URL 경로(/caremeet-dev
, /caremeet
)에 따라 트래픽을 개발 환경과 운영 환경으로 분기하도록 리버스 프록시를 설정했습니다. 또한, HTTPS 및 WebSocket Secure(wss)에 대해 SSL 인증서를 적용하여 보안 통신을 지원하였습니다.
🔒 내부 리소스 보안 강화
MySQL, Redis 등 내부 리소스는 외부에서 직접 접근할 수 없도록 구성하고, SSH 터널링을 통해서만 접근 가능하게 설정하여 네트워크 보안성을 높였습니다.
⚙️ CI/CD 자동화 구성
GitHub Actions를 활용해 CI/CD 파이프라인을 자동화하였고, 빌드된 이미지는 AWS ECR (Elastic Container Registry) 에 저장된 후 배포되었습니다.
📡 Redis 활용
Redis는 단순 캐시를 넘어, 실시간 처리와 데이터 조회 최적화를 위한 핵심 컴포넌트로 다음과 같이 활용되었습니다:
-
채팅 Pub/Sub 메시지 브로커 및 세션 저장소
Redis의 Pub/Sub 구조를 통해 채팅 메시지를 실시간으로 중계하고,
채팅 중인 유저 세션 정보를 저장하여 알림 전송 시 수신 대상 필터링이 가능하도록 구현하였습니다. -
읽음 처리 Write 최소화 전략
Redis에는 채팅방별 최신 메시지 시퀀스와 사용자별 마지막 읽은 시퀀스를 저장하였고,
이를 기반으로 잦은 업데이트 쿼리( MySQL의 is_read 컬럼 업데이트)를 제거하였습니다. -
채팅방 목록 조회 최적화 (JOIN 제거)
Redis에 저장된 채팅방별 메시지 시퀀스 정보와 MySQL의 채팅방 * 메시지 데이터를 조합하여 복잡한 JOIN 없이 채팅방 목록, 안읽은 메시지 개수 및상태를 효율적으로 조회할 수 있도록 구성하였습니다. 이를 통해 슬로우 쿼리를 유발하던 JOIN 연산을 제거하고, 응답 속도를 개선하였습니다. -
위치 기반 공고 조회
기존의 ST_Buffer 기반 MySQL 공간 쿼리를 제거하고, Redis의 GEO 자료구조를 활용하여 사용자의 현재 위치 기준 반경 내 공고 조회 성능을 크게 향상시켰습니다.
🗄️ MySQL 활용
MySQL은 핵심 비즈니스 데이터를 안정적으로 관리하고, Redis와의 조합을 통해 실시간성과 정합성을 모두 충족시키는 기반 저장소로 활용되었습니다.
-
핵심 비즈니스 데이터 저장소
사용자, 센터, 센터장, 채팅방, 채팅 메시지 등 주요 엔터티를 MySQL에 저장하여 데이터 정합성과 일관성을 유지하였습니다. -
최적화된 조회 쿼리 설계
- 카디널리티를 고려한 인덱스 설계 및 실행 계획(EXPLAIN) 분석을 통해 주요 조회 성능을 개선하였습니다.
- 채팅방 목록 조회 시, LATERAL JOIN을 활용하여 각 채팅방의 최신 메시지를 효율적으로 가져오는 쿼리 구조를 구성하였습니다.
- Time-based UUID를 직접 생성하여 기본 키로 사용함으로써 추후 Replication 환경에서도 안정적인 Row 기반 복제를 지원할 수 있도록 두고, Spring Data JPA의 save 메서드 실행 후 발생하는 불필요한 ID 조회 쿼리를 제거하였습니다.
-
데이터 무결성과 동시성 제어
- 애플리케이션 레벨에서 발생할 수 있는 중복 요청과 경쟁 조건을 방지하기 위해, 중복이 발생할 수 있는 필드에 Unique 인덱스를 설정하여 동시성 문제를 예방하였습니다.
-
불필요한 데이터 정리 자동화
- 2주 이상 경과한 크롤링 공고 데이터는 자동으로 삭제되도록 스케줄러 + MySQL 이벤트 프로시저(Event + Stored Procedure)를 통해
데이터를 주기적으로 정리하는 자동화 로직을 구현하였습니다.
- 2주 이상 경과한 크롤링 공고 데이터는 자동으로 삭제되도록 스케줄러 + MySQL 이벤트 프로시저(Event + Stored Procedure)를 통해
인 앱공고 | 워크넷공고 | 프로필 |
![]() |
![]() |
![]() |
회원탈퇴 | 카톡공유 | 딥링크/지연된 딥링크 |
![]() |
![]() |
![]() |
회원가입 1 | 회원가입 2 | 로그인 및 인증대기 |
![]() |
![]() |
![]() |
신규 비밀번호 발급 | 공고 등록 1 | 공고 등록 2 |
![]() |
![]() |
![]() |
지원자 확인 |
![]() |
FCM | 알림 센터 |
![]() |
![]() |

