모두의포트폴리오
PE · FDE 직군을 위한 포트폴리오 밀키트
예전 판입니다 (1판)이 문서는 2026-08-25 에 새 판으로 개정됐습니다. 오너가 산출물 형태 불일치로 반려해 재생성했습니다. 제목이 가리키는 형태와 예측 UI·1주차 산출물이 서로 달랐습니다.최신 판 보기 →
경력힉스 · [힉스] 사용자를 이해하는 Backend Product Engineer 채용

매장 담당자를 위해 발 치수에 맞춰 실제로 만들 수 있는 신발 구성을 경로 근거까지 돌려주는 API입니다.

힉스 공고에서 뽑은 세 가지 시그널.

힉스의 CUSME SHOES는 발 측정 데이터와 3D 파츠 데이터를 같은 제품 안에서 다루고 제조 지식그래프를 신규 기능으로 올리고 있어서, 추천이 취향 점수가 아니라 실제로 만들 수 있는 조합인지에 걸립니다. 라스트와 파츠가 호환되지 않으면 아무리 잘 맞는 치수여도 제조가 안 되므로, 추천과 제조 제약이 한 그래프에서 함께 풀려야 하는 구조는 힉스의 맞춤 제조 맥락에서 나옵니다. 이 포트폴리오가 보여주는 것은 도메인 관계를 그래프로 모델링해 탐색하고 그 경로를 근거로 API에 실어 내는 기술이며, 신발 제조나 족부 계측 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.

01

발 데이터 기반 추천 백엔드

발 측정 데이터를 관리하고 그 데이터로 만든 추천 로직을 서비스 API로 연결해 운영하는 일을 주요 업무로 둡니다.

발 데이터 기반 추천 로직 등 AI 기능을 서비스 API로 연결상품·주문·발 측정 데이터를 관리하는 백엔드 시스템CUSME SHOES
02

제조 지식그래프 적재·조회

제조 지식그래프 같은 신규 기능의 데이터 적재와 조회 백엔드를 직접 개발하고 스키마를 설계합니다.

제조 Knowledge Graph 등 신규 기능의 데이터 적재·조회REST API 설계, 데이터베이스 스키마 설계3D 파츠 데이터 업로드·저장·처리
03

낯선 도메인 빠른 학습

익숙하지 않은 도메인을 빠르게 익혀 제품에 적용하고 요구사항이 덜 정해진 상태에서도 구현 방향을 잡는 일을 요구합니다.

익숙하지 않은 도메인을 빠르게 학습하고 제품에 적용요구사항이 완전히 정해지기 전에도 사용자 문제를 바탕으로AI Product Engineer와 함께 기획·설계 단계부터 협업

포트폴리오 요약

힉스가 CUSME SHOES에서 발 측정 데이터로 맞춤 신발을 만들고 제조 지식그래프로 파츠를 관리하는 맥락에서, 발 길이·볼폭·발등높이를 받아 라스트와 파츠·소재의 호환 관계를 담은 그래프를 타고 실제로 만들 수 있는 신발 구성을 찾아 그 경로를 근거로 돌려주는 추천 API와 확인 화면입니다. 발 측정값과 파츠 카탈로그는 실 데이터 대신 더미를 가정합니다.

고객 정의

발이 넓어 늘 반 치수 크게 신다가 뒤꿈치가 벗겨지던 손님에게 어떤 라스트와 파츠 조합을 권해야 할지 매번 선배에게 물어보던 매장 담당자가, 치수를 넣으면 만들 수 있는 조합과 그 이유를 바로 받아보고 싶은 사람입니다.

고민 지점

라스트와 파츠, 소재의 호환 관계를 그래프로 두면 발 치수에서 시작해 실제로 제조 가능한 조합만 남기고 그 경로를 근거로 보여줄 수 있다는 가정입니다.

주차별 일정

1주차여기까지로 완성

치수를 넣으면 만들 수 있는 조합과 그 경로가 나옵니다

발 치수를 넣으면 라스트·파츠·소재 호환 그래프를 타고 제조 가능한 신발 구성을 찾아 각 조합이 선택된 경로를 근거로 돌려주는 REST API와, 그 결과를 펼쳐 보는 확인 화면이 도는 완결품입니다. 3D 파츠 파일 처리는 파츠 메타데이터를 가정하고 시작합니다.

  1. 1일 · 라스트·파츠·소재 노드와 호환 간선 규칙, 측정 항목 스키마를 정하고 결측·극단 사이즈·단종 파츠·표기 흔들림을 섞은 더미를 만듭니다.
  2. 2-3일 · 발 치수에서 시작해 호환 간선을 타고 제조 가능한 조합만 남기는 그래프 탐색 엔진을 구현합니다.
  3. 4-5일 · 조합과 경로 근거를 돌려주는 REST API와 결과를 펼쳐 보는 확인 화면, 경로 설명 문장 생성을 붙입니다.
2주차선택 성장

AWS에 올리고 추천이 맞았는지 잽니다

1주차 API를 AWS로 배포해 운영하고, 기대 조합을 붙인 발 치수 표본으로 추천 일치율과 폴백 발동률을 재 볼폭 미측정 같은 결측에서 어떤 조합이 나오는지 정리합니다.

  1. 8-9일 · 추천 API를 AWS로 배포하고 운영 상태를 확인합니다.
  2. 10일 · 기대 조합을 붙인 발 치수 표본으로 추천 일치율과 폴백 발동률을 잽니다.
3주차선택 성장

파츠가 늘어도 조회가 느려지지 않게 합니다

2주차 배포 위에 파츠 카탈로그를 수천 건 규모로 늘려 그래프 조회 인덱스를 적용하고, 적용 전후 응답 시간을 나란히 보여주며 카탈로그가 바뀔 때 그래프를 다시 채우는 적재 흐름을 자동화합니다.

  1. 12-13일 · 파츠 카탈로그를 수천 건으로 늘려 그래프 조회 인덱스를 적용하고 응답 시간을 비교합니다.
  2. 14일 · 카탈로그가 바뀔 때 그래프를 다시 채우는 적재 흐름을 자동화합니다.

데모 · 측정 지표

01

발 치수를 넣으면 그래프 탐색부터 제조 가능한 조합과 경로 근거, 설명 문장까지 한 응답에 담기는 과정을 시연합니다.

02

추천된 조합이 호환 간선을 실제로 만족하는지 조합별로 대조해 만들 수 없는 조합이 섞이지 않음을 보여주되, 파츠 카탈로그와 기대 조합을 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.

03

볼폭 미측정·극단 사이즈·단종 파츠·파츠명 표기 흔들림 30종을 넣어도 API가 멈추지 않고 조합이나 사유를 돌려주는 강건성을 보여줍니다.

04

파츠 카탈로그를 수천 건으로 늘렸을 때 인덱스 적용 전후 응답 시간 변화를 나란히 보여줍니다.

정직 경계선

진짜 성능 검증은 여기서 멈춥니다

위 수치는 더미데이터 자가채점이며, 실제 추천 만족도와 제조 적합성은 힉스의 실 파츠 카탈로그와 실 발 측정 데이터, 실 제조 담당자가 있어야 측정 가능합니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다.

미리 알아둬야 할 것들

수치는 합성 데이터 자가채점이라 성능 증명이 아니므로, 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.

정답을 작성자가 만들었으니 잘 맞는 게 당연하므로, 볼폭 미측정·극단 사이즈·단종 파츠·표기 흔들림 같은 경계 케이스를 더미에 일부러 섞어 쉬운 문제만 푸는 함정을 피합니다.

이 포트폴리오가 보여주는 것은 도메인 관계를 그래프로 모델링해 탐색하고 경로를 근거로 내는 기술이며, 신발 제조나 족부 계측 도메인 전문성은 주장하지 않습니다. 조합 선택은 그래프 탐색이 하고 LLM은 설명 문장만 맡습니다.

치수가 맞는 조합이 곧 잘 맞는 신발인 것은 아니어서 착용감은 측정값만으로 결정되지 않으므로, 추천 결과에 착용 만족을 단정하는 문구를 쓰지 않습니다.

실제 도입 때는 파츠가 단종되고 라스트가 개정되어 호환 간선이 수시로 바뀌므로, 카탈로그 변경을 그래프에 반영하는 적재 운영을 도입 단계 과제로 둡니다.

더미 데이터

① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.

foot_measurementsTABLE· 12 rows

추천 입력이 되는 발 측정 기록으로, 볼폭 미측정·극단 사이즈·좌우 편차 같은 하드 케이스를 일부러 섞어 폴백과 그래프 탐색이 제대로 도는지 확인합니다.

② foot_measurements.seed.json 다운로드
① 인라인 샘플 (프리뷰 5 / 12)
scan_idcustomer_idsidelength_mmwidth_mminstep_mmarch_type_rawarch_type_idpreferred_part_raw
S-001C-01L258101.574보통NORMAL쿠션 미드솔
S-002C-01R261.510475.5보통NORMAL쿠션 미드솔
S-003C-02L243—68평발FLAT—
S-004C-02R243.5——평발FLAT—
S-005C-03L31011888요족CAVUS와이드 라스트
③ 증강 프롬프트 (본인 LLM 에 붙여서 N 배 늘리기)
다음 JSON Schema 에 맞는 발 측정 행을 더 생성하세요: {"type":"object","properties":{"scan_id":{"type":"string"},"customer_id":{"type":"string"},"side":{"type":"string","enum":["L","R"]},"length_mm":{"type":"number"},"width_mm":{"type":["number","null"]},"instep_mm":{"type":["number","null"]},"arch_type_raw":{"type":"string"},"arch_type_id":{"type":["string","null"]},"preferred_part_raw":{"type":["string","null"]}},"required":["scan_id","customer_id","side","length_mm","arch_type_raw"]} 쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라: width_mm 가 null 이라 볼폭 폴백이 필요한 결측, width_mm 와 instep_mm 가 함께 null 인 이중 결측, length_mm 가 215 나 310 처럼 사이즈 구간 양 끝인 극단값, 같은 customer_id 의 좌우 측정값이 크게 어긋나는 편차(한쪽 130, 다른 쪽 76), arch_type_id 가 null 이라 아치 유형 마스터에 매핑 안 된 미등록 유형, preferred_part_raw 가 같은 파츠의 표기 흔들림(경량 아웃솔 X9 를 경량아웃솔X9 로)이라 정규화가 필요한 경우. 좌우를 한 쌍으로 만들고, 형식 깨뜨리기 시도(스키마 타입 위반) 3건은 데이터가 아니라 별도 목록으로 표시하세요.
schema (3 층의 단일 출처)
{"type":"object","properties":{"scan_id":{"type":"string"},"customer_id":{"type":"string"},"side":{"type":"string","enum":["L","R"]},"length_mm":{"type":"number"},"width_mm":{"type":["number","null"]},"instep_mm":{"type":["number","null"]},"arch_type_raw":{"type":"string"},"arch_type_id":{"type":["string","null"]},"preferred_part_raw":{"type":["string","null"]}},"required":["scan_id","customer_id","side","length_mm","arch_type_raw"]}
part_compatibility_graphTABLE· 12 rows

라스트와 파츠, 소재의 호환 관계를 담은 그래프 간선으로, 단종 파츠와 상충 조합 같은 하드 케이스를 섞어 탐색이 만들 수 없는 조합을 걸러 내는지 확인합니다.

② part_compatibility_graph.seed.json 다운로드
① 인라인 샘플 (프리뷰 5 / 12)
edge_idfrom_nodefrom_typeto_nodeto_typerelationmin_length_mmmax_length_mmdiscontinued
G-001LAST-STD-260lastPART-MID-CUSHpartfits250269.9false
G-002LAST-WIDE-260lastPART-MID-CUSHpartfits250269.9false
G-003LAST-WIDE-310lastPART-OUT-X9partfits300320false
G-004PART-MID-CUSHpartMAT-EVAmaterialrequires——false
G-005PART-OUT-X9partMAT-RUBBERmaterialrequires——false
③ 증강 프롬프트 (본인 LLM 에 붙여서 N 배 늘리기)
다음 JSON Schema 에 맞는 제조 호환 간선 행을 더 생성하세요: {"type":"object","properties":{"edge_id":{"type":"string"},"from_node":{"type":"string"},"from_type":{"type":"string","enum":["last","part","material"]},"to_node":{"type":"string"},"to_type":{"type":"string","enum":["last","part","material"]},"relation":{"type":"string","enum":["fits","requires","conflicts"]},"min_length_mm":{"type":["number","null"]},"max_length_mm":{"type":["number","null"]},"discontinued":{"type":"boolean"}},"required":["edge_id","from_node","from_type","to_node","to_type","relation","discontinued"]} 쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라: discontinued 가 true 라 탐색에서 빠져야 하는 단종 파츠 간선, relation 이 conflicts 라 함께 못 쓰는 조합, min_length_mm 과 max_length_mm 이 딱 맞닿아 경계 치수에서 어느 라스트를 고를지 갈리는 구간, min_length_mm 이 null 이라 치수 제약이 없는 간선, 어떤 라스트에서도 닿지 않아 고아로 남는 파츠 노드, 특정 치수 구간에 fits 간선이 하나도 없어 추천 조합이 나오지 않는 구멍. 노드 종류를 골고루 섞고, 형식 깨뜨리기 시도(스키마 타입 위반) 3건은 데이터가 아니라 별도 목록으로 표시하세요.
schema (3 층의 단일 출처)
{"type":"object","properties":{"edge_id":{"type":"string"},"from_node":{"type":"string"},"from_type":{"type":"string","enum":["last","part","material"]},"to_node":{"type":"string"},"to_type":{"type":"string","enum":["last","part","material"]},"relation":{"type":"string","enum":["fits","requires","conflicts"]},"min_length_mm":{"type":["number","null"]},"max_length_mm":{"type":["number","null"]},"discontinued":{"type":"boolean"}},"required":["edge_id","from_node","from_type","to_node","to_type","relation","discontinued"]}

기술 상세 · 아키텍처·운영·출력 스키마

기술 스택 매핑
Python그래프 탐색과 추천 규칙, 적재 배치를 구현합니다.
FastAPI발 치수를 받아 추천 조합과 경로 근거를 돌려주는 REST API를 구현합니다.
PostgreSQL라스트·파츠·소재 노드와 호환 간선을 저장하고 조회 인덱스로 응답 시간을 줄입니다.
제조 지식그래프라스트와 파츠, 소재의 호환 관계를 노드와 간선으로 모델링해 제조 가능한 조합만 남깁니다.
React추천 조합과 선택 경로, 폴백 표시를 펼쳐 보는 확인 화면을 구현합니다.
AWS2주차부터 추천 API를 AWS로 배포하고 운영합니다.
LLM API(Claude)그래프가 고른 경로가 왜 그 조합을 만드는지 매장 담당자가 읽을 설명 문장으로 요약하고, 조합 선택은 그래프 탐색이 합니다.
JSON Schema발 측정값과 추천 결과의 모양을 강제해 필드 누락을 막고 더미 증강에 씁니다.
LLM 선택
model
Claude(추천 경로 설명 문장 생성) + 그래프 탐색 기반 조합 선택입니다.
prompt
그래프가 고른 조합과 그 경로 노드만 넣고 매장 담당자용 설명 문장을 JSON으로 받는 스키마 강제 구조이며, 경로에 없는 파츠나 이유를 덧붙이지 말라고 못박습니다. 어떤 조합이 가능한지 고르는 일은 LLM이 아니라 그래프 탐색과 치수 규칙이 합니다.
rationale
제조 가능 여부는 호환 간선의 존재로 결정되는 결정론 판정이라 LLM이 조합을 고르면 만들 수 없는 신발을 추천하게 됩니다. LLM은 이미 확정된 경로가 왜 그 조합을 만드는지 사람이 읽을 문장으로 요약합니다. 조합 선택에는 개입하지 않습니다. 파츠 카탈로그는 내부 데이터라 외부 지식 검색(RAG)이 필요 없습니다.
결정 게이트
1주차 끝볼폭 미측정·극단 사이즈·단종 파츠를 섞은 발 치수 더미를 넣어도 제조 가능한 조합이 나오고, 조합이 없을 때 그 이유가 경로로 표시되는지 확인합니다.

✓ pass → 그대로 멈춰도 완결입니다. 더 키우려면 2주차에서 AWS 배포와 추천 일치율 측정을 붙입니다.

2주차 끝AWS에 배포된 API가 응답하고, 기대 조합을 붙인 표본에서 추천 일치율과 폴백 발동률이 나오는지 확인합니다.

✓ pass → 여기서 멈춰도 검증된 완결입니다. 더 키우려면 3주차에서 카탈로그 확장과 조회 성능을 다룹니다.

재사용 레이어 · 코어 70% / 도메인 30%
core (재사용 가능)
  • 노드와 호환 간선으로 도메인 제약을 모델링하는 그래프 스키마
  • 입력 조건에서 시작해 제약을 만족하는 조합만 남기는 탐색 엔진
  • 선택된 경로를 근거로 함께 돌려주는 추천 API 구조
  • 측정값 결측과 미등록 항목을 폴백으로 메우고 그 사실을 남기는 처리
  • 확정된 경로만 넣어 설명 문장을 만드는 스키마 강제 프롬프트
  • 결측·경계값·미등록 파츠·표기 흔들림을 섞는 더미 측정값 생성기
domain (교체 대상)
  • 노드 종류와 호환 간선 규칙은 제품군별로 갈아끼웁니다
  • 측정 항목 세트와 사이즈 구간 규칙은 신체 부위·품목별로 갈아끼웁니다
  • 폴백 종류 enum(볼폭 추정·기본 아치·후보 없음)은 도메인별로 갈아끼웁니다
출력 스키마 · shoe_recommendation

발 측정 한 건에 대한 추천 조합과 그 조합이 선택된 경로를 함께 내보내, 만들 수 없는 조합이나 근거 없는 추천이 API 밖으로 나가지 않게 합니다.

schema (JSON Schema)
{"type":"object","properties":{"scan_id":{"type":"string"},"last_id":{"type":["string","null"]},"parts":{"type":"array","items":{"type":"string"}},"path":{"type":"array","items":{"type":"object","properties":{"edge_id":{"type":"string"},"relation":{"type":"string","enum":["fits","requires","conflicts"]}},"required":["edge_id","relation"]}},"fallbacks":{"type":"array","items":{"type":"string","enum":["width_estimated","arch_default","no_candidate"]}},"explanation":{"type":"string"},"hedge":{"type":["string","null"]}},"required":["scan_id","last_id","parts","path","fallbacks","explanation"]}
모범 출력 (4)
[
  {
    "scan_id": "S-001",
    "last_id": "LAST-STD-260",
    "parts": [
      "PART-MID-CUSH",
      "MAT-EVA"
    ],
    "path": [
      {
        "edge_id": "G-001",
        "relation": "fits"
      },
      {
        "edge_id": "G-004",
        "relation": "requires"
      }
    ],
    "fallbacks": [],
    "explanation": "발 길이 258mm가 표준 라스트 260의 적용 구간에 들어가고, 쿠션 미드솔이 그 라스트에 맞으며 EVA 소재를 함께 요구해 이 조합이 나왔습니다.",
    "hedge": null
  },
  {
    "scan_id": "S-003",
    "last_id": "LAST-FLAT-243",
    "parts": [
      "PART-ARCH-SUP",
      "MAT-TPU"
    ],
    "path": [
      {
        "edge_id": "G-008",
        "relation": "requires"
      },
      {
        "edge_id": "G-009",
        "relation": "requires"
      }
    ],
    "fallbacks": [
      "width_estimated"
    ],
    "explanation": "볼폭이 측정되지 않아 길이 기준 평균 볼폭으로 추정했고, 평발 라스트 243이 아치 서포트를 요구해 TPU 소재까지 이어졌습니다.",
    "hedge": "볼폭을 추정값으로 채웠으므로 실제 계측 후 라스트가 바뀔 수 있습니다(합성 기준 추정)."
  },
  {
    "scan_id": "S-007",
    "last_id": null,
    "parts": [],
    "path": [],
    "fallbacks": [
      "arch_default",
      "no_candidate"
    ],
    "explanation": "길이 215mm 구간의 라스트에 연결된 파츠가 단종되어 현재 만들 수 있는 조합이 없습니다.",
    "hedge": "아치 유형이 마스터에 없어 기본값으로 처리했고, 단종 파츠를 빼면 후보가 남지 않아 조합을 비웠습니다."
  },
  {
    "scan_id": "S-005",
    "last_id": "LAST-WIDE-310",
    "parts": [
      "PART-OUT-X9",
      "MAT-RUBBER"
    ],
    "path": [
      {
        "edge_id": "G-003",
        "relation": "fits"
      },
      {
        "edge_id": "G-005",
        "relation": "requires"
      }
    ],
    "fallbacks": [],
    "explanation": "길이 310mm와 넓은 볼폭이 와이드 라스트 310에 맞고, 경량 아웃솔 X9가 러버 소재를 요구해 이 조합이 확정됐습니다.",
    "hedge": null
  }
]
검증 노트 (자동 vs 수동)

[자동 검증] 1. path 의 각 edge_id 가 호환 그래프에 실제로 있는 간선인지 대조하고, 없는 간선을 인용한 추천을 거릅니다. 2. parts 의 모든 항목이 path 를 따라가면 도달하는 노드인지 확인해, 경로 없이 끼어든 파츠를 걸러 냅니다. 3. discontinued 가 true 인 간선이 path 에 있으면 실패로 표시해 단종 파츠 추천을 막습니다. 4. relation 이 conflicts 인 두 파츠가 parts 에 함께 들어 있으면 불일치로 표시합니다. 5. width_mm 가 null 인데 fallbacks 에 width_estimated 가 없으면 폴백 누락으로 표시합니다. [수동 검증] 1. 좌우 측정값이 크게 어긋날 때 어느 쪽을 기준으로 라스트를 고를지 제조 담당자가 정합니다. 2. 경계 치수에서 두 라스트가 모두 가능할 때 우선순위를 담당자가 정합니다.