πŸ—‚οΈ E-Commerce 앱을 μœ„ν•œ ν™•μž₯ κ°€λŠ₯ν•œ μΉ΄ν…Œκ³ λ¦¬ μ‹œμŠ€ν…œ 섀계

λ°œν–‰: (2026λ…„ 2μ›” 6일 μ˜€ν›„ 03:26 GMT+9)
5 λΆ„ μ†Œμš”
원문: Dev.to

Source: Dev.to

πŸ—‚οΈ 섀계 κ°€λŠ₯ν•œ μΉ΄ν…Œκ³ λ¦¬ μ‹œμŠ€ν…œμ„ μœ„ν•œ 컀버 이미지

e‑commerce μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ ꡬ좕할 λ•Œ, μΉ΄ν…Œκ³ λ¦¬λŠ” μ²˜μŒμ— 간단해 λ³΄μž…λ‹ˆλ‹€ β€” μ œν’ˆ μˆ˜κ°€ μ¦κ°€ν•˜κ³  λΉ„μ¦ˆλ‹ˆμŠ€μ—μ„œ λ‹€μŒμ„ μš”κ΅¬ν•  λ•ŒκΉŒμ§€:

  • ν•˜μœ„ μΉ΄ν…Œκ³ λ¦¬
  • 쀑첩 메뉴
  • λΈŒλ ˆλ“œν¬λŸΌ
  • SEOβ€‘μΉœν™”μ μΈ URL
  • μ†μ‰¬μš΄ μž¬μ •λ ¬

이 READMEλŠ” μ‹€μ œ μ‹œμŠ€ν…œμ—μ„œ μ‚¬μš©λ˜λŠ” ν™•μž₯ κ°€λŠ₯ν•˜κ³  ν”„λ‘œλ•μ…˜β€‘μ€€λΉ„λœ μΉ΄ν…Œκ³ λ¦¬ 섀계λ₯Ό κ³Όλ„ν•œ μ—”μ§€λ‹ˆμ–΄λ§ 없이 μ„€λͺ…ν•©λ‹ˆλ‹€.

일반적인 μ‹€μˆ˜

Many apps start with separate tables:

categories
sub_categories
sub_sub_categories

This breaks immediately when:

  • you need more depth β†’ 더 κΉŠμ€ 계측이 ν•„μš”ν•  λ•Œ
  • the hierarchy changes β†’ 계측 ꡬ쑰가 변경될 λ•Œ
  • queries become complex β†’ 쿼리가 λ³΅μž‘ν•΄μ§ˆ λ•Œ

일반적인 μ‹€μˆ˜ 일러슀트

ν™•μž₯ κ°€λŠ₯ν•œ μ†”λ£¨μ…˜ (단일 μΉ΄ν…Œκ³ λ¦¬ ν…Œμ΄λΈ”)

ν•˜λ‚˜μ˜ ν…Œμ΄λΈ”μ„ μ‚¬μš©ν•˜κ³  자체 μ°Έμ‘°λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€.

CREATE TABLE categories (
    id          UUID PRIMARY KEY,          -- or BIGINT
    name        VARCHAR(255) NOT NULL,
    slug        VARCHAR(255) UNIQUE NOT NULL,
    parent_id   UUID REFERENCES categories(id),
    level       INT NOT NULL,
    path        VARCHAR(500) NOT NULL,
    sort_order  INT DEFAULT 0,
    is_active   BOOLEAN DEFAULT TRUE,
    created_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at  TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

이 κ΅¬μ‘°λŠ” λ¬΄μ œν•œ 쀑첩을 μ§€μ›ν•˜λ©° 쿼리가 κΉ”λ”ν•©λ‹ˆλ‹€.

계측 ꡬ쑰 μž‘λ™ 방식

μ˜ˆμ‹œ ꡬ쑰

Electronics
 └── Mobiles
      β”œβ”€β”€ Smartphones
      └── Feature Phones

μ €μž₯된 데이터

idnameparent_idlevelpathsort_order
1ElectronicsNULL011
2Mobiles111/21
3Smartphones221/2/31
4Feature Phones221/2/42

Source: …

ν•„λ“œ μ„ΈλΆ€ μ„€λͺ… (μ€‘μš” λΆ€λΆ„)

1️⃣ slug – URLβ€‘μΉœν™”μ μΈ μ‹λ³„μž

μŠ¬λŸ¬κ·ΈλŠ” URL에 μ‚¬μš©λ˜λŠ” 읽기 μ‰¬μš΄ λ¬Έμžμ—΄μž…λ‹ˆλ‹€.

"Smart Phones" β†’ "smart-phones"

μ‚¬μš© 예:

/category/electronics/mobiles/smartphones

μŠ¬λŸ¬κ·Έκ°€ μ€‘μš”ν•œ 이유

  • SEO μΉœν™”μ 
  • μ•ˆμ •μ μΈ URL
  • ID λ…ΈμΆœ λ°©μ§€

2️⃣ level – μΉ΄ν…Œκ³ λ¦¬ 깊이

level은 μΉ΄ν…Œκ³ λ¦¬κ°€ μ–Όλ§ˆλ‚˜ κΉŠμ€μ§€ λ‚˜νƒ€λƒ…λ‹ˆλ‹€.

level 0 = μ΅œμƒμœ„ μΉ΄ν…Œκ³ λ¦¬
level 1 = ν•˜μœ„ μΉ΄ν…Œκ³ λ¦¬
level 2 = ν•˜μœ„β€‘ν•˜μœ„ μΉ΄ν…Œκ³ λ¦¬

쑴재 이유

  • ν™ˆνŽ˜μ΄μ§€μ— μ΅œμƒμœ„ μΉ΄ν…Œκ³ λ¦¬λ§Œ ν‘œμ‹œ
  • μ΅œλŒ€ 깊이 μ œν•œ
  • κ°„λ‹¨ν•œ 필터링

쿼리 μ˜ˆμ‹œ

SELECT * FROM categories WHERE level = 0;

3️⃣ path – 전체 계측 ꡬ쑰 (Materialized Path)

pathλŠ” 루트 β†’ ν˜„μž¬ λ…Έλ“œκΉŒμ§€μ˜ 전체 계보λ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.

Electronics β†’ Mobiles β†’ Smartphones
path = "1/2/3"

κ°•λ ₯ν•œ 이유

  • μž¬κ·€ 없이 전체 μ„œλΈŒνŠΈλ¦¬ 쑰회 κ°€λŠ₯
  • λΈŒλ ˆλ“œν¬λŸΌμ„ μ‰½κ²Œ 생성
  • SEO URL 생성에 ν™œμš©

쿼리 μ˜ˆμ‹œ

SELECT * FROM categories WHERE path LIKE '1/2/%';

4️⃣ sort_order – ν‘œμ‹œ μˆœμ„œ μ œμ–΄ (계측 ꡬ쑰와 무관)

sort_orderλŠ” UIμ—μ„œ μΉ΄ν…Œκ³ λ¦¬κ°€ ν‘œμ‹œλ˜λŠ” μˆœμ„œλ₯Ό μ œμ–΄ν•©λ‹ˆλ‹€.

  • 없을 경우 β†’ 예츑 λΆˆκ°€λŠ₯ν•œ μˆœμ„œ
  • μžˆμ„ 경우 β†’ λΉ„μ¦ˆλ‹ˆμŠ€κ°€ μ •μ˜ν•œ μˆœμ„œ

쿼리 μ˜ˆμ‹œ

SELECT * FROM categories ORDER BY sort_order ASC;

μ‚¬μš© μš©λ„

  • λ„€λΉ„κ²Œμ΄μ…˜ λ°” μˆœμ„œ μ§€μ •
  • μ£Όμš” μΉ΄ν…Œκ³ λ¦¬ κ°•μ‘°
  • μ‹œμ¦Œλ³„ μž¬λ°°μ—΄

μ™œ level + pathλ₯Ό ν•¨κ»˜ μ‚¬μš©ν•˜λ‚˜μš”?

μ‚¬μš© 사둀levelpath
μ΅œμƒμœ„ ν•„ν„°λ§βœ…βŒ
μ΅œλŒ€ 깊이 κ²€μ¦βœ…βŒ
ν•˜μœ„ 트리 μΏΌλ¦¬βŒβœ…
λΈŒλ ˆλ“œν¬λŸΌβŒβœ…
SEO URLβŒβœ…

그듀은 쀑볡이 μ•„λ‹ˆλΌ μ„œλ‘œ λ‹€λ₯Έ 문제λ₯Ό ν•΄κ²°ν•©λ‹ˆλ‹€.

μ œν’ˆ μ—°κ΄€μ„±

μ œν’ˆμ€ 일반적으둜 leaf category에 μ†ν•©λ‹ˆλ‹€.

CREATE TABLE products (
    id          UUID PRIMARY KEY,
    name        VARCHAR(255) NOT NULL,
    slug        VARCHAR(255) UNIQUE NOT NULL,
    price       NUMERIC(10,2) NOT NULL,
    category_id UUID REFERENCES categories(id)
);

μ΅œμ’… ꢌμž₯ 사항

  • βœ… 단일 categories ν…Œμ΄λΈ”
  • βœ… ꡬ쑰λ₯Ό μœ„ν•œ parent_id
  • βœ… 깊이 λ‘œμ§μ„ μœ„ν•œ level
  • βœ… λΉ λ₯Έ 쑰회λ₯Ό μœ„ν•œ path
  • βœ… κΉ”λ”ν•œ URL을 μœ„ν•œ slug
  • βœ… UI μ œμ–΄λ₯Ό μœ„ν•œ sort_order

이 μ„€κ³„λŠ” μŠ€νƒ€νŠΈμ—… MVPμ—μ„œ λŒ€κ·œλͺ¨ λ§ˆμΌ“ν”Œλ ˆμ΄μŠ€λ‘œ μŠ€ν‚€λ§ˆ λ³€κ²½ 없이 ν™•μž₯λ©λ‹ˆλ‹€.

인터뷰 ν•œ 쀄 μš”μ•½

ν™•μž₯ κ°€λŠ₯ν•œ μΉ΄ν…Œκ³ λ¦¬ μ‹œμŠ€ν…œμ€ λ¬΄ν•œ 깊이λ₯Ό μ§€μ›ν•˜κ³ , λΉ λ₯Έ 읽기, κΉ”λ”ν•œ URL, UIβ€‘μ œμ–΄ 정렬을 μœ„ν•΄ 자체 μ°Έμ‘° ν…Œμ΄λΈ”κ³Ό λ¬Όλ¦¬ν™”λœ 경둜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

Back to Blog

κ΄€λ ¨ κΈ€

더 보기 Β»

μ™œ AIλŠ” 디버깅 κΈ°μˆ μ„ λŒ€μ²΄ν•  수 μ—†λŠ”κ°€ (그리고 λŒ€μ‹  ν•  수 μžˆλŠ” 방법)

AIλŠ” μ½”λ“œ μž‘μ„±μ— 맀우 λŠ₯μˆ™ν•΄μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€. μ‹œμŠ€ν…œμ„ scaffoldν•˜κ³ , λͺ¨λ“ˆμ„ refactorν•˜λ©°, μˆ˜μ • 사항을 μ œμ•ˆν•˜κ³ , 심지어 stack tracesλ₯Ό μ„€λͺ…ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ μžμ—°μŠ€λŸ½κ²Œ 묻게 λ©λ‹ˆλ‹€: Will A...

쒋은 μ½”λ“œμ˜ μ‘°μš©ν•œ 죽음

μ €λŠ” κ²½λ ₯을 μ‹œμž‘ν•˜κΈ° μ „λΆ€ν„°, 쀑학생 μ‹œμ ˆ 어릴 λ•ŒλΆ€ν„° β€œGood Codeℒ”λ₯Ό μž‘μ„±ν•˜λŠ” 데 열정을 κ°€μ§€κ³  μžˆμŠ΅λ‹ˆλ‹€. β€œGood Codeβ€λž€ 무엇인가…