이하진 HAJIN LEE

Backend / Product Engineer

현장에서 생기는 문제를 실제 기능으로 구현합니다.

Backend / Product Engineer

운영 흐름을 이해하고,
실제로 쓰이는 기능을 만듭니다.

Java와 Spring Boot를 기반으로 주문·결제·품절·매출처럼 실제 운영 과정에서 필요한 기능을 구현했습니다. 화면에서 시작한 문제도 API, 비즈니스 로직, SQL과 DB까지 따라가며 원인을 확인하고 해결하는 편입니다.

8s 0.43–0.50s
Dashboard response 실 DB 기준
22/24
Admin API 2026.09.02 QA
17/18
Kiosk API Flow 수동 검증 포함
2 9주
Team & Duration 2026.07.02 — 09.02
06 About

개발 전에는 매장 운영과 관리 업무를 오래 경험했습니다. 그래서 기능을 만들 때도 화면 자체보다 실제 업무가 어떤 순서로 진행되고, 어디에서 불편이나 오류가 생기는지를 먼저 봅니다.

ASAK 프로젝트에서는 관리자 영역을 중심으로 React 화면, Spring Boot API, MySQL을 연결하며 주문·품절·결제·매출 기능을 구현했습니다. 문제가 생기면 프론트에서 임시로 맞추기보다 API 응답과 비즈니스 로직, SQL까지 확인하면서 원인을 찾았습니다.

02 Engineering Highlights
01

Data Modeling

메뉴마다 반복되던 옵션 데이터를 공통 정책으로 분리하고, 메뉴별 적용 관계와 예외만 따로 관리했습니다.

02

Business Logic

메뉴·옵션·재료 품절, 주문 상태 전이, 취소 가능 조건을 서로 다른 규칙으로 분리했습니다. 화면에 보이는 상태와 실제 서버 판단이 다르지 않도록 API와 DB 로직을 함께 확인했습니다.

03

Performance

Mapper별 시간을 측정해 대시보드 병목을 찾고 약 8초의 응답을 0.43~0.50초로 줄였습니다. View를 수정한 뒤 오히려 약 5배 느려진 것을 확인해 해당 변경은 원복했습니다.

04 Experience
2026.07 — 09

Full-stack 공동 개발 · Admin/Backend 중심 · ASAK 팀 프로젝트

2인 팀으로 진행해 프론트와 백엔드를 완전히 나누기보다 기능 단위로 함께 개발했습니다. 관리자·백엔드 구현을 중심으로 DB·API 작업과 함께 WBS, 개발 문서, QA도 정리했습니다. 메뉴 → 품절 → 주문 → 결제 → 취소 → 매출 전 과정을 실제 데이터로 확인했습니다.

React Vite Zustand Spring Boot MyBatis MySQL Figma Bruno
01 Featured Projects
키오스크 · 매장 운영
ASAK (Kiosk + Admin)
2026.07.02 — 09.02 · 2인 팀 · Full-stack 공동 개발 · Admin/Backend 중심

고객 주문부터 매장 관리까지 하나의 흐름으로 연결한 샐러드 키오스크 프로젝트입니다. 주문·결제·환불, 품절 정책, 매출 통계와 관리자 기능을 구현하고 DB 모델링·QA·기술 조율을 함께 맡았습니다. 실제 병목을 추적해 대시보드 응답을 0.43~0.50초까지 개선했습니다.

Spring Boot MyBatis MySQL React Technical Coordination
Developer Tooling · Team Workflow
ASAK Agent Kit
팀 공용 개발 규칙 · 6개 개발 환경 지원

프로젝트 규칙과 검증 기준이 도구마다 달라지는 문제를 줄이기 위해 공통 원본을 각 환경의 형식으로 배포하는 툴킷을 구성했습니다. Windows 설치·검증 스크립트와 기존 설정을 덮어쓰지 않는 배포 흐름을 함께 정리했습니다.

SSOT PowerShell Installer Validation
03 Case Study — ASAK
01 Project & Role

2인 팀으로 프론트와 백엔드를 역할별로 고정하지 않고, 기능 단위로 함께 개발했습니다

ASAK은 고객의 키오스크 주문부터 매장의 주문 관리까지 연결한 9주 팀 프로젝트입니다. Admin/Backend를 중심으로 개발했고, DB 모델링과 API 구현뿐 아니라 WBS와 QA 기록도 함께 관리했습니다.

React Spring Boot MyBatis MySQL Vite 2026.07.02 — 09.02
02 Data Modeling

메뉴마다 복제되던 옵션을 재사용 가능한 정책으로 분리했습니다

Before · 메뉴별 복제
menu
 ├─ menu_option
 └─ menu_option_group
legacy rows · 9,166
After · 공통 정책 재사용
opt_group
 ├─ opt_item
 └─ opt_policy
     └─ opt_policy_item

menu ── menu_opt_policy
policy 82 · policy item 734

공통 선택 규칙과 메뉴 연결을 분리해 중복을 줄이고, 메뉴별 차이는 예외 데이터로 관리할 수 있게 했습니다.

03 Technical Decisions

중요한 운영 규칙은 화면이 아닌 서버에서 검증하도록 구현했습니다

  • 품절 대상을 메뉴·옵션·재료로 분리했습니다. 관리 화면에서는 한 목록으로 다루되 서버에서는 대상 유형별 규칙을 유지했습니다. MENU와 OPTION_ITEM은 Kiosk 반영을 확인했고, INGREDIENT 연쇄 반영 실패는 QA에 그대로 남겼습니다.
  • 매출 API를 조회 목적에 따라 분리했습니다. 오늘 매출, 월별 매출, 일별 매출, 시간대 매출을 각각 독립된 API로 구성했습니다.
    sales-api.http
    GET /api/admin/sales/summary?period=month
    GET /api/admin/sales/monthly?year=2026
    GET /api/admin/sales/daily?from=2026-07-01&to=2026-07-31
    GET /api/admin/sales/daily/time-slots?date=2026-07-20&intervalMinutes=30
  • 주문이 없는 시간대는 Service에서 0으로 채웠습니다. DB에는 실제 주문 데이터만 유지하고, 차트에 필요한 연속된 시간대는 영업시간 10:00~22:00 기준으로 Service에서 생성했습니다.
    responsibility
    DB        실제 주문 데이터 저장
    Service   빠진 시간대를 생성하고 0으로 보정
    API       연속된 시간축으로 반환
    Frontend  반환된 데이터를 차트로 표현
  • 주문 상태에 따라 가능한 동작을 제한했습니다. RECEIVED → PREPARING → COMPLETED 흐름과 취소 가능 조건을 API에 적용했습니다. READY 주문의 취소 요청은 409 ORDER_CANCEL_NOT_ALLOWED로 차단됩니다.
  • 결제 완료 응답의 기준 필드를 고정했습니다. 조회 시점의 건수를 다시 계산하지 않고 결제 시 주문에 저장된 일별 고정 번호 waitingOrderNo를 완료 화면과 영수증 요청에서 사용했습니다.
  • 코드가 있다고 해서 완료로 처리하지 않았습니다. API·DB·build 결과를 확인하고, 브라우저와 장치에서 확인하지 못한 범위는 별도로 기록했습니다.
04 Performance & QA

대시보드 응답 약 8초 → 0.43–0.50초

초기 응답DB 호출 약 10회 약 8초
KPI 조회 통합DB 호출 6회 3.7–3.9초
집계 View 우회Mapper에서 기간 범위 직접 조회 1.6–1.7초
최근 주문 직접 조회베이스 테이블 경로로 전환 0.43–0.50초

KPI의 중복 조회를 합친 뒤, 전체 데이터를 먼저 집계하던 View 대신 필요한 기간과 최근 주문만 베이스 테이블에서 조회했습니다. 결과값을 기존 View와 비교하면서 단계별로 측정해 최종 응답을 0.43~0.50초까지 줄였습니다.

Failed experiment · reverted 1.3s → 6.6~6.8s

`vw_order_list_summary`를 상관 서브쿼리 방식으로 바꾸면 빨라질 것으로 예상했지만, MySQL이 View를 `TEMPTABLE`로 구체화해 약 5배 느려졌습니다. 실제 View 실행계획을 확인한 뒤 즉시 원복하고 Mapper에서 필요한 조회만 직접 수행했습니다.

Admin API 22 / 24 PASS
Kiosk API Flow 17 / 18 PASS
Build Admin · Kiosk PASS

아직 해결하지 못한 항목도 그대로 남겼습니다. 결제수단의 Kiosk 반영과 일부 재료 품절 연쇄는 최종 QA에서 실패로 기록했습니다. Admin 브라우저 전체 클릭, 실PG, 실물 장치/RTOS E2E는 검증하지 않았습니다.

05 Project Coordination

개발뿐 아니라 팀이 같은 기준으로 작업할 수 있도록 문서와 진행 방식도 정리했습니다

요구사항부터 시나리오·화면·API·WBS·테스트까지 ID로 추적했습니다. API나 DB가 바뀌면 영향을 받는 화면과 작업 순서를 함께 정리하고, 실제로 확인하지 못한 항목은 완료 상태로 두지 않았습니다.

  • 요구사항 → 사용자 시나리오 → Screen ID → API → WBS → 테스트 추적
  • 코드 존재와 실제 API·DB·화면 검증 상태 분리
  • 회의 결정사항, 후속 작업, 일일 워크로그와 온보딩 문서 관리
  • 공통 개발 규칙을 6개 도구에 배포하는 ASAK Agent Kit 구성
프로젝트 운영 방식과 실제 문서 보기
Project flow
요구사항 → 시나리오 → 화면 → DB / API → WBS → 테스트 → 최종 시연
Schedule
07/02  프로젝트 시작
07월   화면·계약·핵심 기능
08월   연동·성능·통합 QA
09/02  최종 검증·시연
05 Skills
Backend
  • Java · Spring Boot
  • REST API · DTO
  • Service · Transaction
Database
  • MySQL · MyBatis
  • 3NF Data Modeling
  • JOIN · EXISTS · Dynamic SQL
Frontend
  • React · JavaScript
  • Vite · Zustand · Axios
  • Admin UI · State UI
DevOps & Tools
  • Git · GitHub
  • Bruno · Figma
  • Vercel · PowerShell

이 포트폴리오는 vanilla HTML · CSS · JS로 직접 구성했습니다. 소스 보기

07 Contact

이하진 · Backend / Product Engineer · 2026

Deployed & QA Screens

실제 구현 화면

ASAK Admin과 Kiosk의 주요 구현 결과입니다. 이미지를 누르면 원본 크기로 확인할 수 있습니다.

MySQL Schema

ASAK 핵심 데이터 구조

전체 스키마 중 옵션 정책과 주문·결제 구조를 설명하는 핵심 테이블만 정리했습니다. 테이블명과 관계는 실제 MySQL 스키마를 기준으로 했습니다.

01 · Option policy model

공통 옵션 정책은 재사용하고, 메뉴별 적용 관계는 따로 관리했습니다

menu

  • PK id
  • FK cat_id
  • price · sold_out
1N

menu_opt_policy

  • FK menu_id
  • FK policy_id
  • required · priority
N1

opt_policy

  • PK id
  • FK opt_group_id
  • min_select · max_select
1N

opt_policy_item

  • FK policy_id
  • FK opt_item_id
  • recommended · is_default
N1

opt_item

  • PK id
  • FK opt_group_id
  • add_price · sold_out
02 · Order & payment

주문 내용과 결제·환불 이력을 분리해 저장했습니다

orders

  • PK id
  • order_no · status_id
  • total_price · waiting_order_no
1 → N · items

order_item

  • FK order_id
  • FK menu_id
  • quantity · price
1 → N · payment attempts

payment

  • FK order_id
  • amount · status_id
  • idempotency_key UNIQUE
1 → N · refunds

payment_refund

  • FK payment_id
  • amount · reason
  • cancel transaction key

orders는 order_item과 payment에 각각 1:N으로 연결됩니다. 메뉴 선택 옵션은 order_item_option에서 별도 이력으로 보존합니다.

QA Results · 2026.09.02

최종 QA 결과와 남은 확인 항목

Admin API22 / 24 PASS

주문·매출·품절·결제수단 API를 실행하고 DB 결과와 대조했습니다.

Kiosk API Flow17 / 18 PASS

메뉴 조회부터 장바구니·주문·결제 완료까지 API 흐름을 확인했습니다.

Frontend Build2 / 2 PASS

Admin과 Kiosk의 production build를 각각 확인했습니다.

FAIL

실패로 남긴 항목

결제수단 변경 후 Kiosk 반영과 일부 재료 품절의 메뉴 반영은 최종 QA에서 통과하지 못했습니다.

OPEN

추가 확인이 필요한 항목

Admin 전체 화면의 브라우저 QA와 실PG, 실물 장치, RTOS 연동은 최종 시연 범위에서 확인하지 못했습니다.

RULE

완료 기준

코드가 작성됐다는 이유만으로 완료 처리하지 않았습니다. API·DB·빌드·화면에서 실제로 확인한 항목만 완료 근거로 남겼습니다.