레거시를 분석해 서비스 구조를 다시 설계합니다
- 레거시 시스템 분석, 구조 개선
- 요구사항 재정의 및 리뉴얼 방향 수립
- DDD 기반 도메인 구조 설계
- 서비스 아키텍처 및 기능 흐름 재구성
FULLSTACK DEVELOPER
CONTACT
ms1114@kakao.com
010.5543.4341
github.com/xowlsakffl
확장성과 유지보수성을 우선으로 설계하는 개발자
요구사항을 일관된 구조, 문서로 정리하고
변화에 유연한 시스템을 구축하며
지속 가능한 코드와 아키텍처를 만듭니다.
PROFILE
광고 자동화, 이커머스, 의료·뷰티 플랫폼을 개발해 약 5년의 실무 경험을 가진 백엔드 중심 풀스택 개발자입니다.
Laravel과 CodeIgniter 기반 실무에서 요구사항 분석, 데이터베이스 및 API 설계, 관리자 시스템 개발, 외부 API 연동, 배포와 운영까지 서비스 전반을 경험했습니다. React와 Next.js를 활용한 프론트엔드 개발 경험도 갖추고 있어 화면, API, 데이터 흐름을 하나의 시스템 관점에서 이해하고 있습니다.
최근에는 Laravel 12와 Next.js 기반의 레거시 앱·서버 리뉴얼을 진행하며 도메인 분리 구조, 역할별 서비스 구성, Redis 기반 큐, 트랜잭션과 중복 요청 방지 구조를 적용했습니다. 또한 Spring Boot 기반 개인 프로젝트를 통해 Java 백엔드 개발 역량을 확장하고 있습니다.
기능 구현에 그치지 않고 데이터 정합성, 운영 안정성, 유지보수성을 함께 고려하는 개발을 지향합니다.
성형·뷰티 플랫폼 레거시 앱·서버 리뉴얼, 백엔드 및 관리자 시스템 설계·개발 리딩
광고 관리 프로그램 개발·유지보수, 광고 API 연동, 접근 제어와 개인정보 보호
Google·Kakao·Facebook 광고 데이터 수집과 캠페인 운영 자동화 시스템 개발
쇼핑몰, 행사 ERP와 웹사이트 빌더 백엔드 개발
기업·소상공인 웹사이트 제작 및 운영·유지보수
COMPETENCIES
DEVELOPMENT PRINCIPLE
좋은 코드는 단순히 기능이 동작하는 데서 끝나지 않고, 변경과 장애 상황에서도 책임질 수 있는 구조로 구현되어야 한다고 생각합니다.
요구사항을 정확히 구조화하고 데이터 정합성, 유지보수성, 배포 이후의 운영까지 함께 고려하며 서비스를 개발합니다.
COMPETENCIES
STRENGTHS FROM EXPERIENCE
뷰랩스 리뉴얼 프로젝트에서 기존 앱과 서버의 기능, 데이터 구조와 사용자별 운영 흐름을 분석했습니다. 권한 처리, API 응답과 예외 처리 방식이 일관되지 않았고 사용자 유형에 따른 서비스 경계도 명확하지 않았습니다. 코드뿐 아니라 관리자 화면과 실제 운영 절차까지 확인하며 기능이 사용되는 맥락을 기준으로 문제를 정리했습니다.
요구사항과 기능 흐름을 다시 정리해 Staff, Hospital, Beauty, User의 역할을 분리했습니다. 병원, 이벤트, 지갑, 채팅과 알림 기능을 도메인 단위로 나누고 각 기능의 책임과 변경 범위가 명확해지도록 전체 구조를 재설계했습니다. Controller는 요청과 응답 연결에 집중하고 핵심 규칙은 Action과 Query 계층에서 처리하도록 구성했습니다.
케어랩스와 세이브마케팅에서 Google, Kakao, Facebook 등 광고 매체 API를 연동해 광고 데이터 수집과 캠페인 관리 기능을 개발했습니다. 매체마다 다른 요청과 응답을 공통 데이터 구조로 변환하고 인증 만료와 호출 실패도 함께 처리했습니다. 데이터 갱신 주기와 호출량을 고려해 크론과 배치 작업으로 수집 시점을 분리했습니다.
뷰랩스에서는 API 명세와 데이터 구조를 먼저 정의한 뒤 권한 검증과 트랜잭션 등의 핵심 규칙을 서비스 계층에서 처리했습니다. SMS와 알림처럼 즉시 처리할 필요가 없는 작업은 큐로 분리해 요청과 외부 발송이 서로 영향을 주지 않도록 구성했습니다. 외부 연동 실패 시에는 재시도하고 최종 처리 상태와 원인을 기록하도록 설계했습니다.
케어랩스에서 광고 매체별 관리자 페이지에서 반복하던 데이터 수집과 캠페인 관리 업무를 자동화했습니다. 광고 데이터를 공통 기준으로 통합하고 신청, 집행과 성과 확인 과정을 연결해 반복 수작업을 약 40% 줄였습니다. 담당자가 여러 화면을 오가지 않고 하나의 시스템에서 진행 상태와 결과를 확인할 수 있도록 구성했습니다.
처리 결과와 실패 원인을 확인할 수 있도록 로그와 상태 관리 구조를 적용했습니다. 메씨인터내셔날의 행사 ERP와 웹사이트 빌더에서도 비용 계산과 사이트 구성처럼 반복되는 업무를 기능화해 실제 운영 시간을 줄였습니다. 운영 중 문제가 발생하면 기록을 기준으로 원인을 빠르게 찾고 다시 처리할 수 있도록 개선했습니다.
뷰랩스 프로젝트에서 요구사항과 화면 흐름 정리부터 데이터베이스, API, 백엔드와 관리자 시스템 개발까지 전반을 주도했습니다. AWS 운영 환경과 Redis 큐, 실시간 통신 구조를 구성하고 중복 요청, 외부 API 실패와 장애 상황까지 고려했습니다. Next.js 모노레포에서는 내부 운영자용 관리자와 사용자 서비스 웹을 분리하고, 병원·뷰티 파트너 관리자 페이지까지 확장할 수 있도록 앱의 역할과 공통 패키지 경계를 설계했습니다.
깃 브랜치와 커밋 규칙을 정리하고 API 명세와 데이터 구조를 문서화해 개발 기준을 통일했습니다. 담당 기능만 구현하는 데 그치지 않고 기획, 설계, 개발, 배포와 운영이 하나의 흐름으로 이어지도록 관리했습니다. 배포 이후에도 로그와 처리 상태를 확인하며 발생한 이슈를 수정하고 재발 방지 기준을 반영했습니다.
COMPETENCIES
SKILL
레거시 분석과 요구사항 정의부터 백엔드·관리자 프론트엔드·운영 구조까지 전반을 주도한 성형·뷰티 플랫폼 리뉴얼
뷰랩은 성형·시술 병원과 뷰티·라이프스타일 업체를 함께 다루는 플랫폼입니다. 기존 시스템은 일반 사용자, 병원·뷰티 파트너와 내부 운영자의 기능이 한 구조에 섞여 있었고, 일부 접근 제어가 서버 권한 검증보다 메뉴 노출 여부에 의존했습니다. 여러 개발자를 거치며 API 응답, 예외 처리와 데이터 구조도 일관되지 않아 기능을 추가할수록 변경 범위가 커지는 상태였습니다.
합류 후 바로 기능을 추가하지 않고 기존 관리자 동선, API, 인증·권한, 데이터와 미디어 처리 방식을 먼저 분석했습니다. 분석 결과를 바탕으로 요구사항과 기능 흐름, ERD, 도메인·상태 정의, API 명세를 정리한 뒤 사용자 역할과 업무 도메인을 분리하는 방향으로 백엔드와 관리자 시스템을 재설계했습니다.
백엔드는 Actor별 API와 도메인 규칙, 데이터 정합성, 큐·실시간 통신을 담당합니다. 프론트엔드는 내부 운영자용 `staff-web`, 사용자 서비스 앱의 웹 버전인 `user-web`, 병원·뷰티 파트너 관리자 페이지인 `hospital-web`과 `beauty-web`으로 역할을 구분했습니다. 현재는 `staff-web`의 주요 운영 기능과 `user-web`의 인증·채팅·알림 기능이 구현돼 있습니다.
백엔드는 Laravel 기반으로 다시 정리했습니다. 뷰랩 플랫폼은 Staff, Hospital, Beauty, User가 각각 다른 진입점과 인증 정책을 가지므로, 라우트를 Actor 기준으로 분기하고 도메인 비즈니스 로직은 Domain 계층으로 분리하는 방향으로 구조를 잡았습니다. Controller는 요청과 응답 연결에 집중시키고, 실제 상태 변경 규칙은 Action, Query, Policy, Model 계층에 두는 방식으로 정리했습니다.
기존 구조에서 가장 먼저 손봐야 했던 부분도 바로 이 경계였습니다. 레거시 관리자에서는 권한이 실제 서버 검증보다 메뉴 표시 여부에 가까웠고, Actor별 API 경계도 분리되지 않아 내부 운영자, 병원 파트너, 뷰티 파트너가 같은 구조 안에서 섞여 있었습니다. 그래서 신규 백엔드에서는 `/api/v1/staff`, `/api/v1/hospital`, `/api/v1/beauty`, `/api/v1/user`로 진입점을 나누고, Sanctum ability와 permission을 함께 확인하는 방식으로 기준을 다시 세웠습니다.
기존 API를 문서화한 뒤 요구사항 정의서, Information Architecture, 와이어프레임, 플로우차트, 권한·가드 정의서, ERD, 도메인·상태 정의, API 명세와 운영 배포 체크리스트를 작성했습니다. 코드부터 시작하지 않고 구현 기준을 먼저 고정해 병원, 콘텐츠, 지갑, 알림과 채팅처럼 성격이 다른 기능도 같은 구조와 응답 규칙으로 확장할 수 있게 했습니다.
운영 기준도 함께 묶었습니다. 공통 ApiResponse와 traceId, Redis Queue, Horizon, Reverb, 알림 구조, Scheduler, Logging, Error Handling 문서를 정리했고, 내부 운영자가 API와 운영도구를 분리된 정책으로 접근할 수 있도록 별도 내부도구 허브도 구성했습니다. 단순히 API를 만드는 데서 끝나는 것이 아니라, 개발 이후 운영까지 이어지는 백엔드 체계를 만드는 데 집중한 프로젝트였습니다.
스토리지와 리소스 문제도 백엔드 관점에서 함께 정리해야 했습니다. 기존에는 이미지와 동영상이 같은 서버 자원 안에서 혼재되어 있었고, 서버 용량과 메모리 한계가 이미 운영 문제로 드러난 상태였습니다. 이 프로젝트에서는 단순 CRUD를 넘어서 미디어 관리, 업로드 정책, 비동기 처리, 운영 도구 접근 정책까지 같이 설계해 더 이상 한 서버 안에서 무질서하게 누적되지 않도록 구조를 바꾸는 데 집중했습니다.
이후 콘텐츠 운영 도메인은 토크, 토크 댓글, 성형/시술 후기, 후기 댓글, 병의원 평가, 채팅 신고까지 확장했습니다. 카테고리 도메인 분리, 다중 카테고리 검증, 작성자/병의원/의료진 DTO 객체화, 멘션 처리, 이미지 요약 응답, 영수증 인증 상태, 평점 평균, 노출/미노출 이력, 신고 상태를 각각 분리해 화면 요구사항이 바뀌어도 API 계약이 무너지지 않도록 정리했습니다.
인증, 권한, 실시간 이벤트, 비동기 처리, 운영 로그, 스케줄 모니터링까지 모두 하나의 백엔드 기준으로 정리한 점이 이 프로젝트의 핵심이었습니다.
API는 Actor별 guard와 ability를 분리해 인증했습니다. Staff, Hospital, Beauty, User 각각 `/api/v1/{actor}` 진입점이 다르고, 보호 라우트는 Sanctum 토큰과 actor ability를 함께 검사합니다. Staff/Hospital/Beauty는 Spatie Permission으로 role과 permission을 관리했고, 권한 문자열과 역할 문자열은 `AccessPermissions`, `AccessRoles`를 단일 소스로 유지해 시더를 통해 동기화되도록 구성했습니다.
설계의 중심은 Actor와 Domain의 경계를 분리하는 것이었습니다. `Staff`, `Hospital`, `Beauty`, `User`는 API 사용 주체의 경계이고, `Hospital`, `Beauty`, `HospitalVideo`, `HospitalEventAd`, `HospitalWallet`, `Talk`, `HospitalReview`, `HospitalEvaluation`, `Chat`, `Notification`, `Sms`, `Notice`, `Faq`, `Common/ContentReport`는 업무 책임의 경계입니다. HTTP 진입점은 `app/Modules/*`, 비즈니스 규칙은 `app/Domains/*`, 공통 응답과 예외/권한 상수는 `app/Common/*`에 두어 책임이 섞이지 않게 만들었습니다.
Staff API와 관리자 운영 기능을 중심으로 구현하고 Hospital, Beauty, User는 별도 인증 진입점과 각 Actor가 실제 사용하는 API만 분리했습니다. 현재 코드에 없는 미래 기능은 구현 범위에 포함하지 않았습니다.
beaulab/
├── app/
│ ├── Common/ # 공통 응답, 예외, 권한 상수, 미들웨어
│ ├── Domains/ # 도메인 모델, Action, Query, DTO, Policy
│ │ ├── AccountStaff/
│ │ ├── AccountHospital/
│ │ ├── AccountBeauty/
│ │ ├── AccountUser/
│ │ ├── Hospital/
│ │ ├── Beauty/
│ │ ├── HospitalDoctor/
│ │ ├── BeautyExpert/
│ │ ├── HospitalVideo/
│ │ ├── HospitalEventAd/
│ │ ├── HospitalWallet/
│ │ ├── HospitalReview/
│ │ ├── HospitalEvaluation/
│ │ ├── Talk/
│ │ ├── Chat/
│ │ ├── Notice/
│ │ ├── Faq/
│ │ └── Common/
│ │ ├── ContentReport/
│ │ ├── Notification/
│ │ └── Sms/
│ ├── Modules/ # Actor별 HTTP 진입점
│ │ ├── Staff/
│ │ ├── Hospital/
│ │ ├── Beauty/
│ │ └── User/
│ └── Providers/
├── bootstrap/app.php # 라우팅, 미들웨어, 전역 예외 처리
├── config/
├── database/
├── develop-doc/
├── resources/views/tools/
├── routes/
│ ├── api.php
│ ├── web.php
│ ├── channels.php
│ └── console.php
└── artisan
예외 처리는 `bootstrap/app.php` 단일 지점에서 관리했습니다. Validation, Authentication, Authorization, ModelNotFound, MethodNotAllowed, Rate Limit, Token Error, QueryException, 기타 Throwable을 ErrorCode와 HTTP Status로 매핑하고, 모든 API 에러 응답은 `success`, `error.code`, `error.message`, `traceId` 구조로 통일했습니다. 운영 환경에서는 상세 SQL이나 내부 구현 정보를 응답에 노출하지 않고, 추적은 `traceId` 기준으로 하도록 설계했습니다.
{
"success": false,
"error": {
"code": "INVALID_REQUEST",
"message": "요청 값이 올바르지 않습니다."
},
"traceId": "request-trace-id"
}
로그는 앱 로그, 감사 로그, 큐/Horizon 로그, 스케줄 모니터 로그, Telescope 관측 로그로 나눠 봤습니다. 앱 로그는 `storage/logs/laravel.log`, 감사 로그는 `activity_log`, 실패 큐는 `failed_jobs`, 배치 상태는 `job_batches`, 스케줄 상태는 Schedule Monitor 테이블, 개발/디버그 관측은 Telescope 테이블로 관리했습니다. `RequestId` 미들웨어가 `X-Request-Id`를 읽거나 UUID를 생성해 로그 컨텍스트와 응답 헤더, API 응답의 `traceId`에 공통으로 반영하도록 정리한 점도 운영 측면에서 중요했습니다.
동시에 같은 데이터가 바뀌거나 모바일 재전송이 발생할 수 있는 기능은 DB transaction, row lock, unique 제약, idempotency key를 기준으로 처리했습니다. 1:1 채팅은 사용자쌍 기준 match key로 중복 채팅방 생성을 막고, client message id로 같은 메시지 재전송을 멱등하게 처리했습니다. 충전금과 환불은 지갑 row를 잠근 뒤 잔액 검증, 예약금 반영, 업무 Operation, 실제 Transaction 원장 생성을 같은 흐름으로 묶어 잔액과 이력이 어긋나지 않게 구성했습니다.
SMS와 Push처럼 외부 발송이 필요한 작업은 DB에 발송 대상을 먼저 확정한 뒤 Redis Queue와 Horizon worker가 처리하도록 분리했습니다. Worker는 pending row를 claim하고 처리 상태를 바꾼 뒤 외부 provider를 호출하며, 실패 시 재시도와 failed 상태를 남겨 운영자가 누락과 장애 원인을 추적할 수 있게 했습니다.
비동기 런타임은 Redis + Horizon 기준으로 정리했습니다. 큐 레인은 `critical`, `mail`, `sms`, `chat`, `notifications`, `default`, `maintenance`로 분리했고, Horizon Supervisor도 레인별로 나눠 적체와 병목을 빠르게 파악할 수 있게 구성했습니다. Job은 기술 종류가 아니라 업무 소유 도메인 기준으로 배치해 어떤 도메인이 이 후처리를 책임지는지가 구조상 분명하게 드러나도록 했습니다.
스케줄러는 OS crontab이 매분 `php artisan schedule:run`을 실행하고, Laravel Scheduler가 `routes/console.php`의 작업을 수행하며, Spatie Schedule Monitor가 실행 결과를 DB에 기록하는 구조입니다. 실제 운영 작업으로는 `schedule-monitor:sync`, `notice:cleanup-temp-editor-images --hours=24`, `horizon:snapshot`, `queue:prune-batches`, `queue:prune-failed` 등을 관리했습니다.
아래 이미지는 제가 합류 후 가장 먼저 정리했던 기존 API 분석 문서와, 신규 개발을 위해 직접 만든 요구사항 정의서, 문서 체계, ERD 일부입니다. 이 프로젝트에서는 개발을 빨리 시작하는 것보다 무엇을 어떤 기준으로 만들지 먼저 고정하는 일이 더 중요했습니다.
프론트엔드는 Next.js App Router, pnpm workspace와 Turborepo 기반 모노레포로 구성했습니다. 실제 제품 구현의 중심은 내부 운영자용 `apps/staff-web`이며, `apps/user-web`은 향후 서비스 앱과 같은 사용자 기능을 제공할 웹 버전입니다. 현재 `user-web`에는 인증과 1:1 채팅·알림, Reverb 실시간 통신이 우선 구현돼 있습니다. 공통 HTTP, 인증, 타입과 관리자 UI는 `packages/api-client`, `packages/auth`, `packages/types`, `packages/ui-admin`으로 분리했습니다.
`staff-web`은 병의원, 의료진, 동영상, 이벤트, 공지사항, 토크, 후기, 병의원 평가, 신고와 지갑처럼 실제 운영 기능을 도메인 단위로 분리했습니다. 직원 관리자 shell, 사이드바, 세션과 route guard는 앱 공통 레이어가 소유하고, 특정 업무를 모르는 Table, form, modal, uploader와 layout만 `ui-admin`에서 재사용하도록 책임을 나눴습니다.
검색·필터·정렬·페이지 상태는 URL query로 관리하고 `returnTo`와 `highlight`로 목록 복귀 흐름을 유지했습니다. 공통 API client에는 인증 토큰, `401/419` 처리와 `AbortController`를 적용해 화면 전환 전의 오래된 응답이 최신 상태를 덮지 않도록 했으며, 메뉴와 route guard는 같은 permission source를 사용하되 최종 권한 검증은 서버가 담당하도록 구성했습니다.
`staff-web`은 로그인·세션 복구, 권한 기반 관리자 shell과 병의원·의료진·동영상·이벤트·광고·토크·후기·평가·신고·공지·회원·카테고리·해시태그·지갑 운영 화면을 담당합니다. `user-web`은 사용자 서비스 앱의 웹 버전이며, 현재 로그인, 사용자 채팅, 읽음, 알림과 Reverb private channel 기능부터 구현했습니다.
`hospital-web`은 병원 파트너 관리자 페이지, `beauty-web`은 뷰티 파트너 관리자 페이지로 역할을 정의했습니다. 두 파트너 앱은 현재 구현 예정 단계이며, Staff Web에서 라우트만 존재하고 내용이 placeholder인 화면도 구현 성과에서 제외했습니다.
beaulab_frontend/
├── apps/
│ ├── staff-web/
│ │ ├── app/
│ │ │ ├── (admin)/
│ │ │ └── (auth)/
│ │ ├── components/
│ │ │ ├── common/
│ │ │ ├── hospital/
│ │ │ ├── doctor/
│ │ │ ├── video/
│ │ │ ├── notice/
│ │ │ ├── hashtag/
│ │ │ ├── talk/
│ │ │ ├── hospital-review/
│ │ │ ├── hospital-evaluation/
│ │ │ └── reported-content/
│ │ ├── hooks/
│ │ └── lib/
│ ├── user-web/
│ │ └── app/
├── packages/
│ ├── api-client/
│ ├── auth/
│ ├── types/
│ └── ui-admin/
├── doc/
│ ├── architecture.md
│ └── staff-web-rules.md
├── package.json
├── pnpm-workspace.yaml
├── turbo.json
└── tsconfig.base.json
`packages/*`는 Actor나 업무 도메인을 모르는 범용 레이어로 두고 `apps/staff-web`이 관리자 제품 로직을 소유하도록 했습니다. 페이지 라우트는 App Router, fetch·submit과 화면 상태는 `*Client.tsx`, 도메인 전용 UI는 `components/{domain}`, endpoint와 field에 묶인 로직은 `hooks/{domain}`, `lib/{domain}`으로 나눴습니다.
`ui-admin`은 도메인 개념 없이 렌더링 가능한 공통 UI만 제공하고, 병원·이벤트·후기처럼 API 계약과 운영 규칙을 아는 코드는 앱 안에 유지했습니다. 이 기준으로 화면 복제를 줄이면서도 특정 도메인의 변경이 공통 패키지 전체로 번지지 않게 했습니다.
Staff 운영자가 반복적으로 사용하는 이벤트·병의원·의료진·동영상·후기·신고·공지·해시태그 도메인을 따로 정리했습니다. 각 화면은 단순 CRUD 캡처가 아니라 목록에서 조건을 좁히고, 상세에서 운영 판단에 필요한 정보를 확인한 뒤, 수정 화면에서 상태와 파일을 정리하는 실제 업무 흐름을 기준으로 구성했습니다.
이벤트 관리는 단순 목록 화면보다 운영 상태를 빠르게 판단하는 쪽이 중요했습니다. 목록 상단에는 진행중, 최근 생성, 종료 예정, 검수 상태, 파트너십 수치를 요약하고, 기간·노출여부·카테고리·수량·금액·검수상태·검색어를 한 화면에서 조합해 필터링할 수 있도록 구성했습니다. 상세 화면에서는 노출/미노출, 검수 상태, 관리자 메모, 히스토리, 썸네일과 이벤트 페이지 이미지를 함께 확인할 수 있게 했습니다.
수정 화면은 병의원 선택, 카테고리 선택, 이벤트명/설명, 기간, VAT, 정상가·이벤트가, 할인율, 상담신청단가, 부작용 안내, 썸네일/이벤트 페이지 업로드까지 하나의 흐름으로 묶었습니다. 미리보기 적용 후 모바일 화면에서 실제 유저가 보는 가격, 설명, 상담 신청 CTA가 어떻게 보이는지 확인할 수 있게 만든 점이 운영 품질 측면에서 중요했습니다.
병의원 도메인은 운영 상태, 검수 상태, 등록일·수정일, 검색 조건을 기준으로 병원 데이터를 빠르게 찾고 검수할 수 있게 구성했습니다. 상세와 수정 화면에서는 병원 기본 정보, 사업자 정보, 카테고리, 운영 시간, 주소, 로고와 대표/내부 이미지를 한 흐름에서 확인하도록 했습니다.
의료진 도메인은 병원 소속, 직책, 전문의 여부, 경력기간, 운영/검수 상태를 목록에서 비교하고, 상세에서 면허·학력·경력·활동 자료를 확인할 수 있게 만들었습니다. 수정 화면은 프로필 사진, 주요 시술 분야, 증빙 파일, 경력/학력/활동 이력을 한 번에 관리하도록 구성했습니다.
동영상 도메인은 병의원 파트너가 신청한 영상의 배포 채널, 게시 기간, 운영 상태, 검수 상태를 운영자가 확인하는 화면입니다. 상세와 수정 화면에서는 병원·의료진 연결, 외부 영상 URL, 재생 시간, 무기한 게시 여부, 썸네일과 원본 파일 정보를 함께 관리하도록 구성했습니다.
후기 도메인은 성형후기·시술후기를 게시글과 댓글 단위로 나누고, 카테고리, 가격, 평점, 노출 여부, 저장수, 댓글수, 조회수 같은 운영 지표를 목록에서 확인하게 했습니다. 상세 화면에서는 작성자와 병의원/의료진 정보, 이미지, 본문, 댓글, 노출 이력을 같은 화면에서 검토할 수 있도록 구성했습니다.
신고 도메인은 후기와 댓글을 신고 건수, 최초 신고일, 신고 사유, 노출 여부, 처리 상태 기준으로 분류해 운영자가 조치할 수 있게 만든 화면입니다. 상세에서는 신고자 목록과 신고 사유를 확인한 뒤 노출중지, 정상노출, 경고, 무시 같은 처리 선택지를 제공해 운영 이력을 남기도록 했습니다.
공지사항은 채널, 운영 상태, 상단 공지, 관리자 메인 팝업, 무기한 게시 같은 게시 옵션과 에디터 본문, 첨부파일을 함께 관리하도록 구성했습니다. 해시태그는 검색 키, 연결 수, 운영 상태를 목록에서 확인하고 콘텐츠·카테고리 운영과 연결되는 공통 분류 데이터로 관리했습니다.
개발툴 관리자는 일반 관리자와 별개로 API Docs, Horizon, Telescope를 관리하기 위한 내부 운영 도구입니다. 백엔드 문서에서 정리한 것처럼 `tool_staff` 세션 인증, 허용 IP, Gate 기준을 함께 적용해 브라우저 기반 내부도구 접근 정책을 따로 분리했고, 로그인 후 하나의 허브 화면에서 필요한 도구로 이동할 수 있게 구성했습니다.
이 부분은 단순 편의 기능이 아니라 운영 안정성과도 연결됩니다. API 명세 확인, 큐 상태 모니터링, 요청/쿼리/예외 추적을 같은 관리 흐름 안에 두면 개발자와 운영자가 문제를 훨씬 빠르게 확인할 수 있기 때문입니다.
여러 광고 매체의 성과와 집행 상태를 통합하고 조건 기반 자동화, 이벤트 신청 데이터와 외부 제휴 전송까지 연결한 사내 운영 시스템
기존 광고 운영 도구는 PHP 5.x 환경에서 오랫동안 기능이 누적되어 목록과 리포트 조회가 느렸고, 기능을 수정할 때 영향 범위를 파악하기 어려웠습니다. 일부 매체 업무와 신청 데이터 처리도 수작업으로 이어져 운영자가 여러 화면과 절차를 반복해야 했습니다.
매체마다 다른 캠페인 계층, 상태값과 성과 지표를 같은 기준으로 확인하고, 반복적인 상태·예산 변경을 자동화할 수 있도록 CodeIgniter 4 기반 통합 백오피스로 개편했습니다. 광고 운영과 이벤트 신청 데이터, 내부 협업 기능이 하나의 운영 흐름으로 이어지도록 구성했습니다.
매체별 API 응답을 그대로 화면에 노출하지 않고 운영에 필요한 공통 지표와 상태로 변환했습니다. 운영자는 한 화면에서 광고 성과와 심사 상태를 비교하고, 캠페인 계층별 상태와 예산을 조정할 수 있습니다.
자동화는 광고주, 계정, 캠페인, 광고그룹과 광고를 대상으로 일정과 성과 조건을 조합합니다. 조건을 충족하면 매체 API를 통해 상태나 예산을 변경하고 대상·조건·작업 결과를 기록해 운영자가 실행 원인을 추적할 수 있도록 했습니다.
백오피스는 광고주와 이벤트, 전송 정책을 관리하고 별도 랜딩 운영 모듈은 실제 방문자의 신청 요청을 검증·저장한 뒤 외부 제휴 시스템으로 전달합니다. 관리 기준과 실행 코드를 분리하면서도 신청 데이터와 광고 성과는 같은 운영 흐름 안에서 확인할 수 있도록 연결했습니다.
백엔드는 PHP + CodeIgniter 4, 인증은 CodeIgniter Shield, 데이터와 외부 연동은 MySQL, Slack, Jira, 광고 매체 API를 기준으로 구성했습니다. 프론트 정적 에셋은 Bootstrap 5, Bootstrap Icons, jQuery, jQuery UI, DateRangePicker, DataTables, JSZip, pdfmake 기준으로 구성되어 있어, 사내 운영 도구 특유의 테이블 중심 화면과 폼 중심 화면을 빠르게 다룰 수 있도록 맞춰져 있습니다.
아래 이미지는 제니스 관리자 화면 일부입니다. 통합 광고관리, 운영 데이터 관리, 자동화 목록처럼 운영자가 실제로 자주 사용하는 화면 위주로 정리했고, 좌측 사이드바와 테이블 중심 레이아웃을 통해 사내 운영 도구의 성격이 바로 드러나도록 구성했습니다.
기존 PHP 운영 도구와 업무 흐름 분석, CodeIgniter 4 백오피스 개발, 광고 API 연동, 자동화 조건·일정·로그 기능, 이벤트 신청 데이터 운영과 인증·보안 개선을 담당했습니다. 공개 저장소에는 회사 데이터와 인증 정보를 제외하고 컨트롤러, 화면과 정적 자산 중심의 코드만 정리했습니다.
제니스 프로젝트에는 백오피스 외에 광고/이벤트 캠페인용 랜딩 페이지를 실제로 운영하는 별도 PHP 모듈도 함께 있었습니다. 이 모듈은 여러 도메인에서 방문자를 받아 랜딩 페이지를 출력하고, 신청 데이터를 수집한 뒤 중복 검증, 상태 분류, 외부 제휴 전송, 완료 페이지 이동까지 처리하는 실행 계층입니다.
역할을 나누면, 제니스 백오피스가 이벤트, 광고주, 매체, 전송 조건 같은 운영 데이터를 관리하고, 랜딩 운영 모듈은 그 설정을 바탕으로 실제 방문 요청을 받아 처리하는 구조였습니다. 즉 관리자에서 운영 기준을 만들고, 랜딩 모듈이 현장에서 그 기준을 실행하는 형태로 맞물려 있었습니다.
별도의 Composer/NPM 빌드 구조가 아니라, 이벤트별 PHP 템플릿과 정적 HTML/CSS/JS 파일을 직접 로드하는 방식으로 운영했습니다. 프레임워크 없이 전역 include와 파일 규칙으로 동작하므로, 실제 배포 구조와 디렉터리 배치가 코드 실행에 직접 영향을 주는 형태였습니다.
zenith_core.php # 랜딩 라우팅, 페이지 렌더링, 신청 처리, 완료 페이지 이동
zenith_check_proc.php # 신청 데이터 검증, 상태 분류, 저장 후처리
zenith_interlock.php # 외부 제휴 연동 결과 기록 및 재전송 처리
zenith_encryption.php # 신청 데이터 암복호화
zenith_ip.php # 방문자 IP 확인, 내부망/차단 처리
zenith_cookie.php # 운영 쿠키 생성 및 조회
interlock_resend.php # 특정 실패 건 재전송
interlock_resend_all.php # 조건 기반 일괄 재전송
zenith_test.php # 연동/요청 테스트 스크립트
zenith_test_form.php # 폼 전송 테스트 화면
이 모듈은 단순 랜딩 출력기가 아니라, 실무 마케팅 운영에서 필요한 검증과 후처리를 직접 수행하는 코드였습니다. 이름/전화번호/IP/쿠키 기준 중복 검증, 블랙리스트 전화번호 차단, 나이 제한 검증, 상태 코드 분류, 메모 기록, 제휴사 interlock 전송 실패 건 재전송까지 포함돼 있어 실제 리드 운영 프로세스와 바로 연결되는 구조였습니다.
재사용 가능한 화면 조각과 기능 팩을 조합해 학술대회·정부 행사·기업 이벤트 사이트를 구축하는 Laravel 기반 솔루션
행사 사이트는 주최 기관과 행사 성격에 따라 구성이 달라지지만, 상단·메뉴·본문·게시판·하단처럼 반복되는 화면과 기능이 많았습니다. 사이트를 수주할 때마다 비슷한 코드를 다시 만들면 제작 기간이 길어지고, 공통 기능을 수정할 때 여러 프로젝트를 각각 고쳐야 했습니다.
이를 해결하기 위해 웹사이트를 완성된 한 장의 화면이 아니라 재사용 가능한 구성 조각으로 분해했습니다. 사용자는 드래그 앤 드롭 방식으로 필요한 조각을 선택해 사이트를 구성하고, 운영자는 관리자에서 조각의 HTML/CSS, 레이아웃 템플릿, 행사 프로젝트와 게시판·페이지 기능 팩을 관리하도록 설계했습니다.
`works`와 `sites`가 행사 프로젝트와 사이트 설정을 담당하고, `layout_tops`, `layout_navigations`, `layout_middles`, `layout_bottoms`에는 위치별 HTML/CSS 조각을 저장했습니다. `layouts`는 이 조각들과 글꼴·전환 설정을 하나의 템플릿으로 묶고, `packs`는 게시판과 일반 페이지처럼 화면과 함께 필요한 기능을 분리해 관리합니다.
화면의 모양과 콘텐츠를 데이터로 관리하면서 같은 조각을 여러 행사 사이트에서 재사용할 수 있고, 개별 사이트를 다시 개발하지 않아도 조합을 변경해 다른 구성을 만들 수 있도록 했습니다. 사이트 제작 기능과 운영 데이터를 분리해 공통 조각의 수정과 행사별 콘텐츠 운영도 독립적으로 처리할 수 있게 구성했습니다.
제품 전체의 드래그 앤 드롭 편집 화면은 별도 빌더 클라이언트에서 동작했습니다. 공개 저장소에는 제가 담당한 구성 조각 관리자와 사용자 인증/API 계층이 담겨 있으며, 두 저장소가 빌더와 실제 행사 사이트가 사용할 기준 데이터와 계정 흐름을 제공합니다.
아래 이미지는 EventsPack 사용자 서비스 화면입니다. 행사별 화면은 빌더에서 조합한 레이아웃과 콘텐츠를 기준으로 구성되고, 공통 계정과 접근 권한은 사용자 API에서 처리했습니다.
행사 사이트 제작 흐름과 운영 요구사항을 바탕으로 프로젝트·사이트·레이아웃 조각·기능 팩의 데이터 구조를 설계하고, Laravel MVC 기반 관리자와 사용자 인증/API를 구현했습니다. 관리자 화면, 데이터베이스 모델링, API와 Passport 인증 흐름까지 백엔드 전반을 담당했으며 실제 행사 사이트가 재사용 가능한 구성 요소를 사용할 수 있는 기반을 만들었습니다.
공개본은 회사 데이터와 실제 빌더 클라이언트를 제외한 관리자 및 인증/API 서버입니다. 관리자 저장소에서는 구성 조각과 템플릿을, 사용자 API 저장소에서는 중앙 계정과 외부 서비스 접근 흐름을 확인할 수 있습니다.
일반 구매, 정기배송, 연계상품의 서로 다른 주문 흐름과 결제·운영 기능을 하나로 연결한 Laravel 기반 건강식품 쇼핑몰
건강식품 판매에는 한 번 구매하는 일반 상품뿐 아니라 이용 기간과 결제 조건을 선택하는 정기배송 상품, 별도의 신청 정보와 비회원 조회가 필요한 연계상품이 함께 존재했습니다. 판매 유형마다 상품 구성, 주문 정보, 배송 조건과 운영 방식이 달라 하나의 단순 주문 구조만으로 처리하기 어려웠습니다.
공통 회원·배송지·운영 기능은 함께 사용하면서도 일반 주문, 정기배송 주문, 연계상품 주문은 각각의 데이터와 처리 흐름으로 분리했습니다. 사용자 구매 화면과 관리자 백오피스는 하나의 Laravel 애플리케이션 안에서 연결해 주문 접수부터 결제 상태 확인과 운영 처리까지 이어지도록 구성했습니다.
사용자가 상품 유형에 맞는 주문서를 작성하면 일반 주문, 정기배송 주문 또는 연계상품 주문으로 저장하고 결제 방식에 따라 Toss Payments 승인이나 무통장 접수 흐름으로 연결했습니다. 결제 성공과 가상계좌 입금 결과는 거래 이력에 저장한 뒤 해당 주문과 주문 항목의 상태에 반영하고, 변경 내용은 별도의 주문 이력으로 남겼습니다.
사용자는 마이페이지에서 자신의 주문과 배송지를 확인하고, 비회원은 주문 정보로 연계상품 신청 내역을 조회할 수 있게 했습니다. 운영자는 관리자에서 판매 유형별 주문을 검색하고 상태를 변경하며 처리 이력과 문의, 상품 정보를 함께 관리하도록 구성했습니다.
메인 화면, 장바구니, 주문조회 흐름을 함께 넣었습니다. 일반 주문, 정기배송, 연계상품, 결제, 백오피스를 하나의 Laravel 커머스 구조로 연결해 구현했습니다.
상품과 판매 유형별 주문 구조 설계, 데이터베이스 모델링, 사용자 구매 화면, Toss Payments와 Aligo SMS 연동, 마이페이지와 관리자 백오피스 개발을 담당했습니다. 일반 구매와 정기배송, 연계상품의 서로 다른 흐름을 하나의 서비스 안에서 운영할 수 있도록 구매부터 운영까지 전 과정을 구현했습니다.
지역·업종별 뷰티 업체 탐색과 비교, 이벤트 신청부터 상담·예약까지 연결하기 위해 개발 중인 Spring Boot·Next.js 사업화 프로젝트
네이버 플레이스처럼 사용자가 지역과 업종을 기준으로 뷰티 업체를 찾되, 시술 종류와 가격, 담당 전문가, 작업 이미지, 영업정보와 업체별 이벤트를 한곳에서 비교하는 K-뷰티 특화 플랫폼입니다. 관심 있는 이벤트를 신청하고 업체와 상담한 뒤 예약까지 이어지도록 해 장소 검색과 시술 선택 과정을 하나의 흐름으로 연결하는 것을 목표로 하고 있습니다.
파트너 업체는 자신의 매장과 서비스·전문가·미디어·이벤트 정보를 관리하고 신청과 예약을 확인하며, 플랫폼 운영자는 입점 정보와 사업자 증빙, 이벤트를 검수해 정보 품질을 관리합니다. 현재는 사업의 공급 기반을 먼저 확보하기 위해 운영자 업체 관리와 파트너 온보딩을 구현하고 있으며, 이후 이벤트·신청, 사용자 탐색, 상담·예약과 후기 기능으로 확장할 계획입니다.
일반적인 장소 검색 정보만으로는 뷰티 서비스를 결정할 때 중요한 시술 종류와 가격, 담당 전문가와 작업 결과를 같은 기준으로 비교하기 어렵습니다. 반영구, 에스테틱, 헤어, 왁싱, 타투, 네일과 마사지 업체는 업종별 서비스 옵션과 전문가, 미디어, 영업시간과 사업자 정보를 함께 관리해야 합니다. 입점 신청, 검수, 승인, 운영중지처럼 상태도 계속 바뀌며 내부 운영자와 파트너가 같은 데이터를 다룰 때 허용되는 조회와 변경 범위도 달라야 합니다.
결제나 정산부터 기능을 넓히기보다 Staff, Partner, User의 접근 경계와 인증 세션, 업체 운영과 파트너 온보딩, 변경 이력과 동시 수정 제어를 먼저 구현했습니다. 현재는 운영자가 업체를 등록하고 검수하며 담당자와 파트너 계정을 연결하는 흐름을 중심으로 서비스 기반을 완성하고 있습니다.
Access Token은 프론트 메모리에만 보관하고 Refresh Token은 HttpOnly 쿠키로 전달했습니다. 공통 API Client가 인증 만료 시 토큰을 갱신하고 원 요청을 한 번만 재시도하며, Redis에는 로그인 실패 횟수와 로그아웃된 토큰 정보를 저장했습니다. Staff는 역할·권한을, Partner는 소유 리소스를 기준으로 서버에서 최종 접근 권한을 검증합니다.
쓰기 기능은 Application Service의 트랜잭션 안에서 처리하고 업체, 사업자등록번호, 서비스 옵션, 전문가와 초대 데이터에는 비관적 잠금을 적용했습니다. 상태와 주요 필드의 변경 전후 값을 운영 이력으로 저장하고, 미디어 교체와 캐시 무효화는 데이터베이스 커밋 결과에 맞춰 처리하도록 구성했습니다.
서비스 요구사항과 운영 흐름 정의부터 도메인·상태·권한 정책, 데이터베이스와 API, Spring Boot 백엔드, Next.js 운영자 화면과 공통 패키지까지 전 과정을 단독으로 설계·구현하고 있습니다. 구현 상태를 문서와 테스트로 관리하고, 완료되지 않은 사용자 서비스와 상담·예약 기능은 현재 기능처럼 표시하지 않고 후속 범위로 분리했습니다.
빗썸 KRW 마켓을 대상으로 거래대금 상위 종목을 스캔하고 RSI와 이동평균 조건으로 매수 시도를 기록하는 Python 자동화 봇
Bithumb RSI Auto Buyer는 빗썸 KRW 마켓을 대상으로 동작하는 자동 매수 봇입니다. 거래대금 상위 마켓을 조회하고, 이동평균과 RSI 조건을 만족하는 종목을 찾아 일일 예산 범위 안에서 매수 시도를 기록하도록 만들었습니다.
이 프로젝트의 핵심은 외부 거래소 API 연동, 주문 전 검증, 예산 제한, 상태 기록, 실거래 안전장치까지 포함한 자동화 구조를 구현한 점입니다. 기본값을 `PAPER=true`로 두고 실제 주문이 발생하지 않도록 설계했으며, 실거래 전 검증 가능한 구조로 정리했습니다.
봇은 거래대금 상위 KRW 마켓을 순회하면서 최근 종가가 이동평균선보다 높고, RSI가 설정한 매수 기준값보다 낮은 종목을 찾습니다. 조건을 만족하는 후보가 여러 개라면 RSI가 가장 낮은 종목을 우선 선택합니다.
전략 자체는 의도적으로 단순하게 유지했습니다. 이 프로젝트에서 중요했던 부분은 고급 매매 로직이 아니라, 실거래로 이어질 수 있는 자동화 코드에서 주문 전 검증과 예산 제한, 상태 저장, 실거래 차단 로직을 어떻게 넣을지였습니다.
| 파일 | 역할 |
|---|---|
main.py |
스캔 루프, 예산 체크, 매수 흐름 제어 |
broker.py |
빗썸/ccxt 연동, 재시도 처리, 주문 전 검증 |
strategy.py |
RSI와 이동평균 기반 매수 조건 |
state.py |
로컬 JSON 상태 저장/조회 |
config.py |
환경변수 기반 설정과 값 검증 |
기본 실행 모드는 페이퍼 트레이딩입니다. `PAPER=true`와 `RUN_ONCE=true`로 한 번만 실행하는 방식으로 테스트할 수 있고, 실거래는 `PAPER=false`, `LIVE_CONFIRM=true`, API Key/Secret이 모두 설정된 경우에만 동작하게 해 실수로 실제 주문이 나가지 않도록 했습니다.
PAPER=false
LIVE_CONFIRM=true
BITHUMB_API_KEY=your-api-key
BITHUMB_API_SECRET=your-api-secret
상태는 `state.json`에 저장합니다. 오늘 사용한 KRW 금액, 오늘 이미 매수한 심볼, 마지막 매수 시각을 기록해 중복 매수와 예산 초과를 막고, 쿨다운 체크까지 가능하도록 했습니다.
테스트는 `requirements-dev.txt`와 `pytest` 기준으로 구성했고, 실거래 전에는 반드시 `PAPER=true` 상태로 충분히 검증해야 한다는 점을 전제로 했습니다. 또한 빗썸 최소 주문 금액, API 권한, 수수료 정책을 먼저 확인해야 하며, API Key와 Secret은 절대 Git에 커밋하지 않도록 구조를 분리했습니다.
현재 코드는 매도 로직, 리밸런싱, 변동성 기반 포지션 사이징, 백테스트, 손실 제한 로직까지 포함한 완성형 트레이딩 시스템이 아니라, 실거래 안전장치와 상태 관리까지 포함한 매수 자동화 구조를 보여주는 프로젝트입니다.
JWT 인증, 파티 권한 정책, 실시간 채팅과 음성 상태, React 프론트 통합 배포 구조까지 포함한 Spring Boot + React 멀티 모듈 웹 서비스
GameHub는 디스코드형 게임 파티 운영을 위한 멀티 모듈 기반 웹 서비스입니다. 사용자 인증, 친구 기능, 파티 모집/참가, 실시간 채팅, 음성채널 상태, 권한/초대/뮤트 관리, 프론트엔드 번들 통합까지 포함한 Spring Boot + React 모노레포로 구성했습니다.
이 프로젝트의 핵심은 단일 백엔드가 아니라 `domain / core / user-api / admin-api / front-end`로 역할을 나눈 상태에서 JWT 인증, WebSocket(STOMP) 실시간 이벤트, 파티 멤버 권한 정책, 초대코드 기반 진입 흐름, 프론트 빌드 산출물의 백엔드 통합까지 실제 서비스 구조로 연결했다는 점입니다.
onion/
├── onion-domain/ # Entity, Enum, Repository
├── onion-core/ # DTO, Service, Security, Exception
├── onion-user-api/ # 사용자 REST API, WebSocket, 정적 리소스 서빙
├── onion-admin-api/ # 관리자 API 확장 모듈
├── front-end/ # React + Vite 프론트엔드
├── postman/ # Postman 컬렉션
├── build.gradle # 루트 Gradle 설정
└── settings.gradle # 멀티 모듈 구성
`onion-domain`은 엔티티와 Enum, Repository를 담당하고, `onion-core`는 서비스 로직, DTO, JWT 보안 구성, 공통 예외 처리, ModelMapper 기반 매핑을 담당합니다. `onion-user-api`는 인증/친구/파티/채팅/음성 API와 WebSocket 설정, 프론트 정적 리소스 서빙까지 맡고, `onion-admin-api`는 운영 기능을 확장하기 위한 관리자 API 모듈입니다. `front-end`는 React 라우팅과 파티 카드, 친구 패널 UI, Axios 기반 API 호출을 담당합니다.
이 프로젝트에서 중요했던 부분은 REST API만 구현하는 데서 끝나지 않고, JWT 기반 인증과 실시간 이벤트를 서비스 흐름에 자연스럽게 연결하는 것이었습니다. 파티 멤버 권한을 `LEADER`, `MANAGER`, `MEMBER`로 나누고, 수정/승인/강퇴/위임/뮤트 정책을 세분화해 운영 기준이 코드 구조에 직접 드러나게 정리했습니다.
WebSocket 쪽도 단순 채팅 푸시가 아니라, 실시간 채팅과 읽음 상태 저장/조회 API, 음성채널 접속 상태, 파티 브로드캐스트, 사용자 푸시 알림까지 연결했습니다. 특히 WebSocket JWT 인증 인터셉터와 인바운드 채널 보안을 추가해 실시간 계층도 REST와 같은 인증 기준으로 관리되도록 보완했습니다.
배포 구조 역시 포인트였습니다. `onion-user-api`가 Gradle `node` 플러그인을 통해 `front-end`의 `npm run build`를 수행하고, 결과물을 `src/main/resources/static`으로 복사하도록 구성해 프론트 별도 개발 서버와 백엔드 통합 배포 두 방식을 모두 지원하도록 정리했습니다.
현재 핵심 실행 모듈은 `onion-user-api`입니다. `onion-admin-api`는 관리자 API 확장 지점 성격이 강하고, 테스트 태스크는 각 모듈에서 `enabled = false`로 비활성화되어 있습니다. JPA 설정은 `ddl-auto: update`, `show-sql: true` 기준이며, 프론트엔드 `dist` 산출물은 이미 `onion-user-api/src/main/resources/static` 아래에도 반영되는 구조입니다.
이 프로젝트는 멀티 모듈 백엔드와 React 프론트가 결합된 게임 파티 허브형 웹 서비스 모노레포입니다.
Spring Boot 백엔드와 React 프론트엔드를 함께 구성하고, Instagram 피드 패턴을 참고한 단일 컬럼 SNS UI까지 정리한 풀스택 프로젝트
`SNS Service`는 게시글 기반 소셜 피드, 댓글, 좋아요, 알림, 신고 처리까지 포함한 풀스택 SNS 프로젝트입니다. 백엔드는 Spring Boot로 인증/도메인/API를 담당하고, 프론트엔드는 React로 피드 경험을 제공하도록 구성했습니다.
프론트 UI는 Instagram 웹/모바일 피드 구조를 참고한 클론형 인터페이스로 정리했습니다. 브랜드를 그대로 재사용한 것이 아니라, 피드 카드, 스토리, 하단 탭, 단일 컬럼 소비 흐름 같은 UI 패턴을 참고해 구현했고, 현재는 PC에서도 모바일과 같은 단일 컬럼 레이아웃으로 동작합니다.
인증, 실시간 이벤트, 콘텐츠 관리, 프론트 UI 흐름까지 한 번에 포함한 통합 레포지토리입니다.
sns_service/
├── src/main/java/dev/be/snsservice/
│ ├── configuration/ # Security, Redis, JWT, Local seed
│ ├── controller/ # User/Post/Report API
│ │ ├── request/ # 요청 DTO
│ │ └── response/ # 응답 DTO
│ ├── exception/ # 예외/에러코드/전역 핸들러
│ ├── model/ # 도메인 모델, enum
│ │ └── entity/ # JPA Entity
│ ├── repository/ # JPA/캐시/SSE Repository
│ ├── service/ # 비즈니스 로직
│ └── util/ # JWT/유틸
├── src/main/resources/
│ └── application.yml
├── front-end/ # React 프론트엔드
│ ├── src/layouts/ # 피드/인증/알림/게시글 화면
│ ├── src/hooks/ # 무한 스크롤 훅
│ ├── src/utils/ # 프로필/이미지 메타, 병합 유틸
│ └── screenshots/mobile/ # README용 모바일 화면 캡처
├── database/ # DB 도커 설정
├── redis/ # Redis 도커 설정
└── docker-compose-local.yml
이 프로젝트에서 중요한 부분은 백엔드 기능 구현만이 아니라, 그 기능이 실제 피드 UI 경험과 자연스럽게 연결되도록 만드는 것이었습니다. 피드 카드, 스토리, 하단 탭, 게시글 상세, 댓글, 알림 화면을 같은 톤으로 묶고, PC에서도 모바일과 같은 단일 컬럼 레이아웃으로 고정해 소비 흐름을 일관되게 만들었습니다.
백엔드 쪽은 JWT 인증을 전제로 쓰기 API를 보호하고, 좋아요와 댓글 이벤트를 SSE 알림으로 연결했습니다. 또한 게시글 수정/삭제 권한 체크를 엔티티 참조 비교가 아니라 ID 비교로 정리하고, JWT/SSE 구독 처리 안정성과 요청 검증 및 전역 예외 응답 구조를 보강했습니다.
신고 기능도 단순 등록에서 끝내지 않고, 누적 임계치 기반 자동 블라인드와 관리자 승인/반려, 검색과 집계 API까지 넣어 운영형 서비스 관점으로 확장했습니다. 즉 사용자 경험은 익숙한 피드 UI 패턴으로, 운영 기능은 실제 관리 흐름으로 연결한 점이 이 프로젝트의 핵심입니다.
.\gradlew.bat build
.\gradlew.bat bootRun
cd front-end
npm install
npm run start
docker compose -f docker-compose-local.yml up -d
로컬 `local` 프로필에서는 데모 데이터가 자동으로 들어가도록 구성했습니다. 일반 사용자 `demo / password123!`, 관리자 사용자 `admin / admin1234!` 계정으로 바로 로그인할 수 있고, 사용자 6명, 게시글 12개, 댓글 8개, 좋아요 20개, 알림 6개, 신고 3개가 자동 생성됩니다.
이 덕분에 백엔드 API뿐 아니라 프론트 피드, 댓글, 알림, 신고 화면까지 별도 수동 입력 없이 바로 확인하고 캡처할 수 있도록 정리했습니다.
모든 이미지는 모바일 기준 캡처입니다. 로그인, 회원가입, 피드, 게시글 작성, 내 게시물, 게시글 상세, 알림 화면 순서로 정리했습니다.
주소 검색, 거리 계산, 추천 순위, 단축 URL, 길안내와 로드뷰 이동까지 하나의 검색 경험으로 연결한 Spring Boot 기반 주차장 추천 웹 솔루션
주차장 추천은 사용자가 입력한 주소를 기준으로 주변 주차장을 탐색하고, 거리 기준 추천 결과를 지도와 카드 UI로 보여주는 Spring Boot 기반 웹 솔루션입니다.
핵심은 단순 목록 조회가 아니라, 주소 검색 API(Kakao Local), 거리 계산, 추천 순위, 단축 URL, 길안내와 로드뷰 이동을 하나의 검색 경험으로 연결한 점입니다. 검색 화면에서 반경과 추천 개수를 조절하고, 결과 화면에서는 지도와 추천 카드를 함께 보며 위치와 이동 동선을 바로 비교할 수 있도록 구성했습니다.
src/
├── main/
│ ├── java/dev/be/parkingmap/
│ │ ├── api/ # Kakao API 연동 서비스/DTO
│ │ ├── direction/ # 단축 URL, 방향/링크 처리
│ │ ├── parking/ # 주차장 조회/추천 서비스
│ │ └── config/ # Retry, RestTemplate 설정
│ └── resources/
│ ├── static/ # 공통 CSS, JS
│ ├── templates/ # main.hbs, output.hbs
│ └── application.yaml
└── test/
├── groovy/
└── java/
database/
├── init/
└── config/
MariaDB 없이 화면과 흐름을 빠르게 확인할 때 사용하는 실행 방식입니다.
$env:SPRING_PROFILES_ACTIVE="local"
$env:SPRING_DATASOURCE_DRIVER_CLASS_NAME="org.h2.Driver"
$env:SPRING_DATASOURCE_URL="jdbc:h2:mem:parking-preview;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"
$env:SPRING_DATASOURCE_USERNAME="sa"
$env:SPRING_DATASOURCE_PASSWORD=""
$env:SPRING_JPA_HIBERNATE_DDL_AUTO="create-drop"
$env:KAKAO_REST_API_KEY="your_kakao_rest_api_key"
$env:PARKING_RECOMMENDATION_BASE_URL="http://localhost:8080/dir/"
.\gradlew.bat bootRun
docker compose -f docker-compose-local.yml up -d
$env:SPRING_DATASOURCE_USERNAME="root"
$env:SPRING_DATASOURCE_PASSWORD="your_password"
$env:KAKAO_REST_API_KEY="your_kakao_rest_api_key"
.\gradlew.bat bootRun
기본 타깃은 Java 17이며, 로컬에 JDK 17이 없어도 Gradle toolchain 기준으로 빌드와 테스트가 가능하도록 정리했습니다.
| 변수 | 설명 |
|---|---|
SPRING_PROFILES_ACTIVE |
실행 프로필 (`local`, `prod`) |
SPRING_DATASOURCE_DRIVER_CLASS_NAME |
DB 드라이버 클래스 |
SPRING_DATASOURCE_URL |
DB 연결 URL |
SPRING_DATASOURCE_USERNAME |
DB 계정 |
SPRING_DATASOURCE_PASSWORD |
DB 비밀번호 |
KAKAO_REST_API_KEY |
Kakao Local API REST 키 |
PARKING_RECOMMENDATION_BASE_URL |
단축 URL 생성 기준 URL |
이 프로젝트는 CRUD보다는 검색 경험 설계에 더 가깝습니다. 주소 입력, 거리 계산, 추천 순위, 지도 표현, 링크 이동까지 이어지는 흐름을 웹 UI로 완성했다는 점이 핵심입니다.
특히 결과 화면을 `지도 + 추천 카드 + 정렬 옵션 + 추천 이유` 구조로 정리하면서, 실제 서비스 화면에 가깝게 구성했습니다.
React + Vite 프론트엔드와 Spring Boot API 서버를 분리 구성하고, 전자제품 전문 쇼핑몰 사용자 화면과 관리자 콘솔까지 연결한 이커머스 프로젝트
기어허브는 컴퓨팅, 오디오, 게이밍, 모바일 액세서리를 중심으로 한 전자제품 전문 이커머스 서비스입니다. 프론트엔드는 React + Vite 기반으로 사용자 쇼핑몰 화면과 관리자 운영 콘솔을 구성했고, 백엔드는 Spring Boot 기반으로 인증, 상품, 장바구니, 배송지, 주문/결제, 관리자 API를 제공합니다.
핵심은 프론트에서 `shop / admin / components / store / api`, 백엔드에서 `controller / service / repository / model / payload / security`로 역할을 분리하고, JWT 인증 상태를 기준으로 사용자 쇼핑 흐름과 관리자 운영 흐름을 명확히 나눈 점입니다. 사용자단과 관리자단을 모두 갖춘 구조로 구성했습니다.
src/
├── api/ # Axios 인스턴스, JWT 헤더 주입
├── assets/ # 정적 에셋
├── components/
│ ├── account/ # 마이페이지, 주문 내역
│ ├── auth/ # 로그인, 회원가입
│ ├── cart/ # 장바구니
│ ├── checkout/ # 배송지, 결제 수단, 주문 요약
│ ├── home/ # 홈 화면, 배너
│ ├── products/ # 상품 목록, 필터, 상세
│ └── shared/ # 공통 UI
├── hooks/ # 상품 필터 훅
├── modules/
│ ├── admin/ # 관리자 라우트와 화면
│ └── shop/ # 사용자 쇼핑몰 라우트
├── store/ # Redux store, reducer, action
└── utils/ # 가격 포맷, 텍스트 유틸
src/main/java/com/ecommerce/project/
├── config/ # 공통 설정, 데모 데이터, 정적 이미지 핸들러
├── controller/ # REST API 컨트롤러
├── exceptions/ # 공통 예외와 전역 예외 처리
├── model/ # JPA Entity, Role Enum
├── payload/ # DTO, API 응답 객체
├── repository/ # Spring Data JPA Repository
├── security/ # SecurityFilterChain, JWT 필터, 요청/응답 DTO
├── service/ # 비즈니스 로직
└── util/ # 인증 사용자 조회 유틸
src/main/resources/
└── application.properties # 서버, DB, JWT, CORS, Stripe 설정
사용자 화면과 관리자 화면을 `src/modules/shop`, `src/modules/admin`으로 분리해 라우트 경계가 코드 구조에 그대로 드러나도록 정리했습니다. 홈, 상품, 상세, 장바구니, 체크아웃, 계정 페이지를 사용자 흐름에 맞춰 묶고, 관리자 영역은 별도 레이아웃과 전용 페이지 세트로 분리했습니다.
상태 관리는 Redux 기준으로 인증 사용자 정보, 장바구니 상품과 합계, 상품 목록, 카테고리, 결제 수단, 로딩 및 오류 상태를 나눠 관리했습니다. API 쪽은 `localStorage.auth.jwtToken`을 Authorization 헤더로 자동 주입하고, `withCredentials`도 함께 사용해 인증 흐름을 정리했습니다.
백엔드는 JWT 인증과 Spring Security 권한 정책을 기준으로 공개 조회, 사용자 API, 관리자 API를 나눴습니다. 공개 회원가입은 `ROLE_USER`만 부여하고, `/api/admin/**` 경로는 `ROLE_ADMIN`으로 제한해 사용자 흐름과 운영 흐름이 섞이지 않도록 구성했습니다.
주문 생성 시 서버 장바구니 기준으로 주문 상품을 만들고 상품 재고를 차감하며, 관리자 영역에서는 전체 주문 조회와 상태 변경을 처리합니다. 즉 프론트의 사용자 경험과 백엔드의 비즈니스 로직이 한쪽으로 치우치지 않게 연결한 구조가 핵심입니다.
npm install
npm run dev
npm run build
npm run preview
.\mvnw.cmd spring-boot:run
.\mvnw.cmd -DskipTests package
java -jar target/sb-ecom-0.0.1-SNAPSHOT.jar
| 영역 | 변수 | 설명 |
|---|---|---|
| Frontend | VITE_BACK_END_URL |
Spring Boot API 서버 주소 |
| Frontend | VITE_FRONTEND_URL |
프론트엔드 실행 주소 |
| Backend | SERVER_PORT |
서버 실행 포트 |
| Backend | SPRING_DATASOURCE_URL |
JDBC URL |
| Backend | JWT_SECRET |
JWT 서명 키 |
| Backend | FRONTEND_URL |
CORS 허용 프론트 주소 목록 |
| Backend | IMAGE_BASE_URL |
상품 이미지 기본 URL |
| Backend | STRIPE_SECRET_KEY |
Stripe secret key |
프론트와 백엔드 모두 `demo / password123!`, `admin / admin1234!` 계정을 기준으로 정리했습니다. 백엔드의 `DemoDataInitializer`는 서버 시작 시 사용자 계정, 관리자 계정, 전자제품 카테고리, 데모 상품, 배송지, 장바구니를 보강해 로컬에서 바로 사용자 흐름과 관리자 흐름을 확인할 수 있게 구성했습니다.
MOTIVATION
보다 체계적인 개발 프로세스와 명확한 기준 속에서 서비스의 전 과정을 깊이 있게 수행하고자 지원하게 되었습니다.
그동안 다양한 프로젝트를 경험하며 요구사항 정의부터 설계, 개발, 운영까지 전반적인 흐름을 직접 수행했습니다. 특히 레거시 시스템 분석을 기반으로 요구사항을 재정의하고, 데이터 구조와 API를 설계하며 서비스를 개선하는 과정에서 전체 흐름을 이해하는 것이 개발의 완성도를 좌우한다는 것을 체감했습니다.
다만 이러한 경험을 쌓는 과정에서 프로젝트마다 기준과 프로세스가 다르거나 명확히 정립되어 있지 않은 환경에서는 동일한 문제를 반복하거나 비효율이 발생하는 한계도 함께 느꼈습니다. 이로 인해 단순히 기능을 구현하는 것을 넘어 체계적인 프로세스와 일관된 기준 속에서 개발을 수행하는 것이 얼마나 중요한지에 대해 고민하게 되었습니다.
명확한 개발 프로세스와 협업 체계를 기반으로 서비스를 운영하고 있으며, 이러한 환경 속에서 요구사항 정의부터 설계, 개발, 운영까지의 전 과정을 보다 정교하게 수행하고 개선해 나갈 수 있다고 판단했습니다. 특히 단기적인 기능 구현이 아닌 구조와 흐름을 기반으로 서비스를 발전시키는 방향성과 제가 지향하는 개발 방식이 부합한다고 생각합니다.
입사 후에는 기존에 쌓아온 구조 분석 및 설계 경험을 바탕으로 서비스의 전체 흐름을 이해하고, 비용을 개선하며 안정성과 확장성을 고려한 구조를 만들어 가는 데 기여하고자 합니다. 또한 체계적인 프로세스 안에서 개발을 수행하며, 단순 구현을 넘어 실제 서비스에 지속적으로 가치를 더할 수 있는 개발자로 성장하고 싶습니다.
구조를 이해하고 개선하는 개발자로서,
실질적인 가치를 만드는 데 기여하고 싶습니다.
CONTACT
ms1114@kakao.com
010.5543.4341
github.com/xowlsakffl