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 |
κ°λ° νκ²½μμμ μ 체 μμ€ν ꡬμ±μ λ€μκ³Ό κ°μ΅λλ€.
Core Fridge Serviceλ Flutter ν΄λΌμ΄μΈνΈλ‘λΆν° REST μμ²μ μμ νκ³ , Redis μΊμ λ μ΄μ΄λ₯Ό κ±°μ³ λλ©μΈ λ‘μ§μ μ²λ¦¬ν©λλ€. μν μΈμ μμ² μμλ λ΄λΆ νμ΄νλΌμΈμ ν΅ν΄ λ¨κ³λ³ λ§€μΉμ μλνλ©°, μ΅μ’ ν΄λ°± λ¨κ³μμ μΈλΆ ML μλΉμ€(FastAPI)μ μ°λλ©λλ€.
μν μΈμ νμ΄νλΌμΈμ 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 ν΅ν© νκ²½μμμ λ§μ΄ν¬λ‘λ²€μΉλ§ν¬ μν
μ±λ₯ νλ‘νμΌλ§μ ν΅ν΄ 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'./gradlew jmhThis project is part of the RE:FRIDGE system.


