Skip to content

RE-FRIDGE-Team/REF_Core_Fridge_Service

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

210 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧊 REF_Core_Fridge_Service

RE:FRIDGE의 핡심 λ°±μ—”λ“œ μ„œλΉ„μŠ€ β€” 냉μž₯κ³  관리, μƒν’ˆ 인식, μ‹μž¬λ£Œ μΆ”μΆœμ„ λ‹΄λ‹Ήν•˜λŠ” 도메인 쀑심 μ„œλΉ„μŠ€μž…λ‹ˆλ‹€.


πŸ“Œ ν”„λ‘œμ νŠΈ κ°œμš”

RE:FRIDGEλŠ” 영수증 OCR, μƒν’ˆλͺ… 인식, ML 기반 μ‹μž¬λ£Œ λΆ„λ₯˜λ₯Ό 톡해 냉μž₯κ³  λ‚΄ μ‹μž¬λ£Œλ₯Ό μžλ™μœΌλ‘œ κ΄€λ¦¬ν•˜λŠ” ν’€μŠ€νƒ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μž…λ‹ˆλ‹€.

Core Fridge ServiceλŠ” 이 μ‹œμŠ€ν…œμ˜ μ€‘μΆ”λ‘œμ„œ, λ‹€μŒκ³Ό 같은 핡심 μ±…μž„μ„ μˆ˜ν–‰ν•©λ‹ˆλ‹€:

  • μƒν’ˆ 인식 νŒŒμ΄ν”„λΌμΈ β€” μž…λ ₯된 μƒν’ˆλͺ…μœΌλ‘œλΆ€ν„° μ‹μž¬λ£Œλ₯Ό μžλ™ μΆ”μΆœν•˜λŠ” 5단계 Chain of Responsibility νŒŒμ΄ν”„λΌμΈ
  • 도메인 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 β€” μ‹μž¬λ£Œ, μ‹μ œν’ˆ, μΉ΄ν…Œκ³ λ¦¬ 정보에 κ΄€ν•œ CRUD와 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직 μ „λ‹΄
  • μ‹λ£Œν’ˆ 데이터 μ„œλΉ„μŠ€ β€” μ•½ 1,100건의 ν•œκ΅­ μ‹λ£Œν’ˆ μƒν’ˆ 데이터 기반 μ‚¬μ „Β·μΈλ±μŠ€ 검색 제곡 (TODO: 23,000건으둜 ν™•λŒ€ μž‘μ—… μ§„ν–‰ 쀑)
  • ML 폴백 연동 β€” 사전/인덱슀 λ§€μΉ­ μ‹€νŒ¨ μ‹œ μ™ΈλΆ€ ML μ„œλΉ„μŠ€λ₯Ό ν†΅ν•œ κ°œλ°©ν˜• λΆ„λ₯˜ (TODO: DAPT-KoBERT + LLM FineTuning μ˜ˆμ •)

πŸ—οΈ 기술 μŠ€νƒ

μ˜μ—­ 기술
Framework Spring Boot 4.0.2
Language Java 21 (Virtual Threads)
Architecture DDD (Domain-Driven Design)
ORM Spring Data JPA + QueryDSL 5.1.0
Cache Redis + StringRedisTemplate
Observability Micrometer + Prometheus + Grafana
Profiling AOP 기반 ν•Έλ“€λŸ¬λ³„ λ ˆμ΄ν„΄μ‹œ 계츑, JMH 벀치마크
Load Test Locust (Master-Slave λΆ„μ‚° ꡬ쑰)
Build Gradle

🏠 둜컬 μ‹œμŠ€ν…œ μ•„ν‚€ν…μ²˜

개발 ν™˜κ²½μ—μ„œμ˜ 전체 μ‹œμŠ€ν…œ ꡬ성은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

Local System Architecture

Core Fridge ServiceλŠ” Flutter ν΄λΌμ΄μ–ΈνŠΈλ‘œλΆ€ν„° REST μš”μ²­μ„ μˆ˜μ‹ ν•˜κ³ , Redis μΊμ‹œ λ ˆμ΄μ–΄λ₯Ό 거쳐 도메인 λ‘œμ§μ„ μ²˜λ¦¬ν•©λ‹ˆλ‹€. μƒν’ˆ 인식 μš”μ²­ μ‹œμ—λŠ” λ‚΄λΆ€ νŒŒμ΄ν”„λΌμΈμ„ 톡해 단계별 맀칭을 μ‹œλ„ν•˜λ©°, μ΅œμ’… 폴백 λ‹¨κ³„μ—μ„œ μ™ΈλΆ€ ML μ„œλΉ„μŠ€(FastAPI)와 μ—°λ™λ©λ‹ˆλ‹€.


πŸ”— μƒν’ˆ 인식 νŒŒμ΄ν”„λΌμΈ

클래슀 λ‹€μ΄μ–΄κ·Έλž¨

Recognition Pipeline Class Diagram

νŒŒμ΄ν”„λΌμΈ ꡬ쑰

μƒν’ˆ 인식 νŒŒμ΄ν”„λΌμΈμ€ Chain of Responsibility νŒ¨ν„΄μœΌλ‘œ μ„€κ³„λ˜μ–΄, 각 ν•Έλ“€λŸ¬κ°€ 순차적으둜 μƒν’ˆλͺ…을 λΆ„μ„ν•˜κ³  μ‹μž¬λ£Œλ₯Ό μΆ”μΆœν•©λ‹ˆλ‹€. μ–΄λŠ λ‹¨κ³„μ—μ„œλ“  μœ νš¨ν•œ κ²°κ³Όκ°€ λ„μΆœλ˜λ©΄ 체인이 μ¦‰μ‹œ μ’…λ£Œλ©λ‹ˆλ‹€.

μž…λ ₯(μƒν’ˆλͺ…)
  β”‚
  β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 1. Name Parser Handler          β”‚  ← λΈŒλžœλ“œΒ·λ…Έμ΄μ¦ˆ 제거, 핡심 μ‹μž¬λ£Œλͺ… μΆ”μΆœ
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 2. Exclusion Filter Handler     β”‚  ← λΉ„μ‹ν’ˆ(μ„Έμ œ, 비닐 λ“±) 사전 필터링
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 3. Dictionary Match Handler     β”‚  ← μ‹μž¬λ£Œ 사전 속 단어가 λ‹¨μΌλ‘œ ν¬ν•¨λœ 경우 λ§€μΉ­
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 4. Product Index Search Handler β”‚  ← μƒν’ˆ 인덱슀 DB LIKE / μ—­LIKE μ—°μ‚° 검색 (Bottleneck)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 5. ML Prediction Handler        β”‚  ← μ™ΈλΆ€ ML μ„œλΉ„μŠ€ 폴백 (TODO: DAPT-KoBERT)
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

ν•Έλ“€λŸ¬λ³„ μ—­ν• 

μˆœμ„œ ν•Έλ“€λŸ¬ μ—­ν•  λΉ„κ³ 
1 NameParserHandler Aho-Corasick 기반 λΈŒλžœλ“œ λ§€μΉ­, 40+ μ •κ·œμ‹ λ…Έμ΄μ¦ˆ νŒ¨ν„΄ 제거, 핡심 μ‹μž¬λ£Œλͺ… μ •μ œ Early-skip μ΅œμ ν™” 적용
2 ExclusionFilterHandler λΉ„μ‹ν’ˆ ν‚€μ›Œλ“œ(μ„Έμ œ, λ΄‰νˆ¬, 건전지 λ“±) 감지 μ‹œ μ¦‰μ‹œ REJECTED λ°˜ν™˜ Aho-Corasick Trie + Word Boundary 검증
3 DictionaryMatchHandler μ‹μž¬λ£Œ 사전 속 단어가 μ •μ œλœ μ œν’ˆλͺ…에 λ‹¨μΌλ‘œ ν¬ν•¨λœ 경우 λ§€μΉ­ 2개 이상 λ§€μΉ­ μ‹œ λ‹€μŒ λ‹¨κ³„λ‘œ μœ„μž„
4 ProductIndexSearchHandler μƒν’ˆ 인덱슀 DB λŒ€μƒ LIKE / μ—­LIKE μ—°μ‚° 기반 검색 및 μš°μ„ μˆœμœ„ λ§€μΉ­ λ ˆμ΄ν„΄μ‹œ 병λͺ© ꡬ간
5 MLPredictionHandler μ™ΈλΆ€ ML μ„œλΉ„μŠ€ ν˜ΈμΆœμ„ ν†΅ν•œ κ°œλ°©ν˜• μ‹μž¬λ£Œ λΆ„λ₯˜ TODO: DAPT-KoBERT 연동 μ˜ˆμ •

⚑ μ„±λŠ₯ μ΅œμ ν™”

계츑 인프라

νŒŒμ΄ν”„λΌμΈ μ„±λŠ₯ 뢄석을 μœ„ν•΄ λ‹€μŒκ³Ό 같은 κ΄€μΈ‘ 인프라λ₯Ό κ΅¬μΆ•ν–ˆμŠ΅λ‹ˆλ‹€:

  • Micrometer + AOP β€” @Profile("perf") ν™˜κ²½μ—μ„œ 각 ν•Έλ“€λŸ¬μ˜ μ‹€ν–‰ μ‹œκ°„μ„ μžλ™ 계츑
  • Prometheus β€” ν•Έλ“€λŸ¬λ³„ λ ˆμ΄ν„΄μ‹œ, 호좜 λΉˆλ„, λ§€μΉ­ κ²°κ³Ό(HIT/NO_MATCH) λ©”νŠΈλ¦­ μˆ˜μ§‘
  • Grafana λŒ€μ‹œλ³΄λ“œ β€” PromQL 기반 μ‹€μ‹œκ°„ μ‹œκ°ν™” 및 병λͺ© ꡬ간 식별
  • JMH 벀치마크 β€” Spring Context 톡합 ν™˜κ²½μ—μ„œμ˜ 마이크둜벀치마크 μˆ˜ν–‰

μ΅œμ ν™” κ²°κ³Ό

Recognition Optimization

μ„±λŠ₯ ν”„λ‘œνŒŒμΌλ§μ„ 톡해 ProductIndexSearchHandlerκ°€ 전체 νŒŒμ΄ν”„λΌμΈ λ ˆμ΄ν„΄μ‹œμ˜ μ£Όμš” 병λͺ©μž„을 μ‹λ³„ν–ˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό 기반으둜 λ‹€μŒκ³Ό 같은 μ΅œμ ν™”λ₯Ό μ§„ν–‰ν–ˆμŠ΅λ‹ˆλ‹€:

  • 사전 λ§€μΉ­ 단계(Handler 1~3)μ—μ„œμ˜ μ‘°κΈ° μ’…λ£Œμœ¨μ„ λ†’μ—¬ 인덱슀 검색 μ§„μž… λΉˆλ„ 자체λ₯Ό κ°μ†Œ
  • Name Parser의 Early-skip 둜직 κ°•ν™”λ‘œ λΆˆν•„μš”ν•œ μ •κ·œμ‹ 평가 단계 μΆ•μ†Œ
  • Dictionary Match λ‹¨κ³„μ˜ 인메λͺ¨λ¦¬ 사전 ꡬ쑰 μ΅œμ ν™”

Grafana λŒ€μ‹œλ³΄λ“œ μ§€ν‘œλ₯Ό 톡해 μ΅œμ ν™” μ „ν›„μ˜ ν•Έλ“€λŸ¬λ³„ λ ˆμ΄ν„΄μ‹œ 뢄포, λ§€μΉ­ 성곡λ₯  λ³€ν™”, 전체 νŒŒμ΄ν”„λΌμΈ μ²˜λ¦¬λŸ‰ κ°œμ„ μ„ μ •λŸ‰μ μœΌλ‘œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.


πŸ“‚ ν”„λ‘œμ νŠΈ ꡬ쑰

core_server/src/main/java/com/refridge/core_server/
β”‚
β”œβ”€β”€ bootstrap/                              # μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ΄ˆκΈ°ν™” (ApplicationRunner)
β”‚   β”œβ”€β”€ dto/                                #   CSV/JSON νŒŒμ‹±μš© DTO
β”‚   └── strategy/                           #   사전 μ΄ˆκΈ°ν™” Strategy νŒ¨ν„΄ κ΅¬ν˜„μ²΄
β”‚
β”œβ”€β”€ common/                                 # 곡톡 λͺ¨λ“ˆ
β”‚   β”œβ”€β”€ REFEntityTimeMetaData               #   μ—”ν‹°ν‹° μ‹œκ°„ 메타데이터 (@Embeddable)
β”‚   └── REFQueryDslConfig                   #   QueryDSL JPAQueryFactory μ„€μ •
β”‚
β”œβ”€β”€ config/                                 # 인프라 μ„€μ •
β”‚   └── REFRedisConfig                      #   Redis + CacheManager μ„€μ •
β”‚
β”œβ”€β”€ groceryItem/                            # μ‹μž¬λ£Œ Bounded Context
β”‚   β”œβ”€β”€ application/                        #   μ„œλΉ„μŠ€ (LifeCycle, Query, Categorical, InformationUpdate)
β”‚   β”‚   β”œβ”€β”€ dto/command/                    #     Command DTO (Create, Delete, Update, CategoryChange)
β”‚   β”‚   β”œβ”€β”€ dto/query/                      #     Query DTO
β”‚   β”‚   β”œβ”€β”€ dto/result/                     #     Result DTO (Summary, Detail, Upsert, ProductNameMatch)
β”‚   β”‚   └── mapper/                         #     MapStruct 맀퍼
β”‚   β”œβ”€β”€ domain/                             #   도메인 계측
β”‚   β”‚   β”œβ”€β”€ ar/REFGroceryItem               #     Aggregate Root (@Entity)
β”‚   β”‚   β”œβ”€β”€ service/                        #     도메인 μ„œλΉ„μŠ€ (μΉ΄ν…Œκ³ λ¦¬ 검증)
β”‚   β”‚   β”œβ”€β”€ dto/                            #     도메인 DTO
β”‚   β”‚   └── vo/                             #     Value Objects (Name, Status, Classification, Image, CategoryRef)
β”‚   └── infra/                              #   인프라 계측
β”‚       └── persistence/                    #     QueryDSL Repository κ΅¬ν˜„μ²΄ + Projection DTO
β”‚
β”œβ”€β”€ grocery_category/                       # μΉ΄ν…Œκ³ λ¦¬ Bounded Context
β”‚   β”œβ”€β”€ application/                        #   μ„œλΉ„μŠ€ (LifeCycle, InformationQuery)
β”‚   β”‚   β”œβ”€β”€ dto/command/                    #     Command DTO (Major/Minor Create, Remove)
β”‚   β”‚   β”œβ”€β”€ dto/result/                     #     Result DTO (Hierarchy, BulkCreation)
β”‚   β”‚   └── mapper/                         #     계측 ꡬ쑰 κ²°κ³Ό 맀퍼
β”‚   β”œβ”€β”€ domain/                             #   도메인 계측
β”‚   β”‚   β”œβ”€β”€ ar/                             #     Aggregate Roots (MajorCategory, MinorCategory)
β”‚   β”‚   └── vo/                             #     Value Objects (CategoryName, ColorTag, ItemType, TypeGroup)
β”‚   └── infra/                              #   인프라 계측
β”‚       └── persistence/                    #     QueryDSL Repository κ΅¬ν˜„μ²΄ + Projection DTO
β”‚
β”œβ”€β”€ product/                                # μ‹μ œν’ˆ Bounded Context
β”‚   β”œβ”€β”€ application/                        #   μ„œλΉ„μŠ€ (LifeCycle - upsert)
β”‚   β”œβ”€β”€ domain/                             #   도메인 계측
β”‚   β”‚   β”œβ”€β”€ ar/REFProduct                   #     Aggregate Root (@Entity)
β”‚   β”‚   └── vo/                             #     Value Objects (ProductName, BrandName, Type, Status, GroceryItemRef)
β”‚   └── infra/                              #   인프라 계측
β”‚       β”œβ”€β”€ converter/                      #     JPA AttributeConverter (Status, Type)
β”‚       β”œβ”€β”€ dto/                            #     검색 κ²°κ³Ό Projection DTO
β”‚       └── persistence/                    #     QueryDSL Repository (LIKE/μ—­LIKE λ§€μΉ­ 둜직)
β”‚
└── product_recognition/                    # μƒν’ˆ 인식 Bounded Context
    β”œβ”€β”€ application/                        #   μ„œλΉ„μŠ€ (Recognition, Batch, PipelineCache)
    β”‚   └── dto/                            #     Command / Result DTO (Cached, Batch, Response)
    β”œβ”€β”€ domain/                             #   도메인 계측
    β”‚   β”œβ”€β”€ ar/                             #     Aggregate Roots (ProductRecognition, RecognitionDictionary)
    β”‚   β”œβ”€β”€ pipeline/                       #     νŒŒμ΄ν”„λΌμΈ μ½”μ–΄ (Context, Handler μΈν„°νŽ˜μ΄μŠ€)
    β”‚   β”œβ”€β”€ service/                        #     도메인 μ„œλΉ„μŠ€ (REFRecognitionPipeline)
    β”‚   β”œβ”€β”€ port/                           #     포트 μΈν„°νŽ˜μ΄μŠ€ (Parser, Matcher, Searcher, MLClient)
    β”‚   β”œβ”€β”€ dto/                            #     도메인 DTO (DictMatch, IndexSearch, MLPrediction)
    β”‚   β”œβ”€β”€ event/                          #     도메인 이벀트 (Completed, DictionarySynced)
    β”‚   └── vo/                             #     Value Objects (Status, ProcessingPath, DictionaryType, Entry λ“±)
    β”œβ”€β”€ infra/                              #   인프라 계측
    β”‚   β”œβ”€β”€ pipeline/                       #     ν•Έλ“€λŸ¬ κ΅¬ν˜„μ²΄ 5μ’… (Exclusion, NameParsing, DictMatch, IndexSearch, ML)
    β”‚   β”œβ”€β”€ adapter/                        #     포트 κ΅¬ν˜„μ²΄ (Aho-Corasick Matcher, QueryAdapter, Parser)
    β”‚   β”œβ”€β”€ aop/                            #     AOP μ„±λŠ₯ 계츑 (@Profile("perf"))
    β”‚   β”œβ”€β”€ sync/                           #     사전 동기화 (DB β†’ Redis β†’ Trie)
    β”‚   β”œβ”€β”€ converter/                      #     JPA AttributeConverter
    β”‚   β”œβ”€β”€ mapper/                         #     MapStruct 맀퍼 (Cross-Context ACL)
    β”‚   └── dto/                            #     인프라 DTO
    └── presentation/                       #   ν”„λ ˆμ  ν…Œμ΄μ…˜ 계측
        β”œβ”€β”€ dto/                            #     Request DTO (단건, 배치)
        └── mapper/                         #     Request β†’ Command 맀퍼

πŸš€ μ‹€ν–‰ 방법

사전 μš”κ΅¬μ‚¬ν•­

  • JDK 21+
  • Docker (Redis, Prometheus, Grafana μ»¨ν…Œμ΄λ„ˆ)
  • .env 파일 μ„€μ • (springboot4-dotenv μ‚¬μš©)

둜컬 μ‹€ν–‰

# 인프라 μ»¨ν…Œμ΄λ„ˆ 기동
docker-compose up -d

# μ• ν”Œλ¦¬μΌ€μ΄μ…˜ μ‹€ν–‰
./gradlew bootRun

# μ„±λŠ₯ ν”„λ‘œνŒŒμΌλ§ λͺ¨λ“œ μ‹€ν–‰
./gradlew bootRun --args='--spring.profiles.active=perf'

JMH 벀치마크

./gradlew jmh

πŸ“„ License

This project is part of the RE:FRIDGE system.

About

RE:FRIDGE's Core Fridge Service - Fridge Inventory, Stocking, Ingredient Catalog etc

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages