요양보호사·간병인·가사도우미와 요양시설을 연결하는 구인구직 매칭 웹 서비스를 만들며 남기는 정리 글.
기간: 2026-09-07 ~ (발표 2026-09-21)
CareMatch는 요양보호사·간병인·가사도우미(구직회원)와 요양시설(시설회원), 그리고 개인적으로 요양보호사를 찾는 소비자(보호자회원)를 연결하는 구인구직 매칭 플랫폼이다. 여기에 운영을 위한 관리자 계정까지 더해 4종의 회원 유형이 존재한다.
backend/ · frontend/ · docs/)10일 남짓한 기간 동안 331개 커밋, 146건의 PR 머지가 쌓였다. 매일 새 기능이 붙고, 그만큼 버그도 그날그날 잡아나간 프로젝트였다.
| 구분 | 기술 |
|---|---|
| 프론트엔드 | React 19 · Vite · TypeScript · Tailwind CSS · React Router (Vercel 배포) |
| 백엔드 | Spring Boot 3 · Spring Security(JWT/OAuth2) · Spring Data JPA (Render 배포, Docker) |
| DB | PostgreSQL(Neon) — 로컬은 H2 인메모리 |
| 마이그레이션 | Flyway (prod만 자동 적용, local/test는 H2 create-drop) |
| 파일 스토리지 | Cloudflare R2 (S3 호환, presigned URL) |
| 결제 | 포트원(PortOne) V2 — 서버가 결제 결과를 재조회해 검증 |
| 지도 | 카카오맵 SDK — 반경 검색 + 클러스터링 |
배포 스택은 처음에 "여러 서비스를 써봤다"는 방향으로 흩어놓기보다, Cloudflare R2를 실제로 구현하는 깊이를 포트폴리오 카드로 삼기로 팀 안에서 정리했다. 그 결과 프론트는 Vercel, 백엔드는 Render, DB는 Neon으로 각자 역할이 뚜렷한 스택이 됐다(파일 스토리지만 Cloudflare R2로 실제 presigned URL 흐름까지 구현).
| 이름 | 역할 | GitHub |
|---|---|---|
| 혁 (팀장) | 백엔드 | @heo-hyuk |
| 신영 | 프론트엔드 | @syyu21b |
| 경수 | 백엔드 | @HurKyungsoo |
| 동한 | 프론트엔드 | @Kim-dong-han |
역할별로 브랜치 접두사(feature/be-*, feature/fe-*)를 나누고, main은 직접 push를 막아 PR로만 병합하는 GitHub Flow를 초반부터 고정했다. 배포 시점은 별도 브랜치 대신 main에 태그(vX.Y.Z)로만 남기기로 했다.
초기 며칠은 모노레포 구조 전환, CODEOWNERS·CI 세팅, 회원/인증 도메인처럼 다른 모든 기능이 딛고 설 기반을 다지는 데 썼다. 이후로는 구인공고 → 인재정보/구직신청 → 포인트·결제 → 인증구직자 마크 → 알림/관리자 순으로 도메인이 하나씩 늘었고, 마지막 며칠은 매칭점수 정렬, 모바일 반응형, 회원가입 중복 알림 같은 다듬기 작업과 README 갱신이 이어졌다.
PR은 총 146건, 거의 매 기능 단위로 쪼개 올렸고 리뷰 승인 후 머지하는 흐름을 지켰다. wip: 커밋으로 미완성 작업을 중간 저장했다가, main으로 올라갈 때는 Squash and merge로 압축해 히스토리를 깔끔하게 유지했다.
기록해둘 만한 이슈만 추리면 이렇다.
build.gradle의 toolchain 고정을 걷어내고 options.release = 17로 전환, wrapper 커밋 + .gitattributes로 개행 문자 고정.SecurityConfig → OAuth2SuccessHandler → AuthService → PasswordEncoder(SecurityConfig 내부 빈)로 자기 자신을 참조. PasswordConfig로 분리해 해결.setAllowedOriginPatterns로 전환.backend로, IntelliJ도 backend/만 Gradle 프로젝트로 재임포트.$PORT 동적 주입을 못 받아 배포 실패. server.port: ${PORT:8080} 추가.@Lob→oid 문제 — 운영 DB가 비어 있는데 ddl-auto: validate였던 문제, 그리고 @Lob String이 Hibernate 6+PostgreSQL에서 oid 컬럼으로 생성되던 문제(H2에선 안 드러나 로컬 테스트로는 못 잡음). @Column(columnDefinition = "TEXT")로 전환하고 Flyway를 도입해 이후 스키마 변경을 마이그레이션 파일 추가만으로 처리하게 정리.main이 깨진 걸 몰랐던 사고. GitHub Actions CI(ci-frontend.yml, ci-backend.yml)를 PR 트리거로 붙이고서야 재발이 멈췄다.account_email 동의항목은 카카오 심사(수일)가 필요해, 승인 전까지는 이메일 없이도 로그인이 되도록 임시 이메일 채움 처리로 우회.