데일리샷
경력근거: 커머스, 풀필먼트, 위치 기반 서비스 구축·운영 경험이 있으신 분
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고가 우대사항에 '커머스, 풀필먼트, 위치 기반 서비스 구축·운영 경험이 있으신 분' 을 적었고, 주요업무에는 'Python·Django·DRF 기반 API 서버 및 Django Admin 개발' 과 '서버의 안정성·확장성·효율성 개선' 을 두었습니다. 주문을 어느 매장에서 내줄지는 그 셋이 함께 걸리는 계산이고, 이 포트폴리오는 그 계산을 재고표와 차감 순서로 만듭니다. '직무의 경계를 나누는 대신 한 사람이 자신의 전문 영역(웹 / 앱 / 서버)을 중심으로 프로젝트 전반을 주도' 하는 조직이라, 규칙을 데이터로 두면 화면과 서버가 같은 답을 냅니다. 이 포트폴리오가 보여주는 것은 재고와 운영 조건을 데이터로 두고 주문 줄과 맞춰 배정 여부를 가르는 기술이며, 주류 유통 규제나 물류 운영 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
'커머스, 풀필먼트, 위치 기반 서비스 구축·운영 경험이 있으신 분'. 주문을 어느 매장에 붙일지가 그 셋이 만나는 자리입니다.
'Python·Django·DRF 기반 API 서버 및 Django Admin 개발' 과 '서버의 안정성·확장성·효율성 개선'. 배정은 그 서버가 매번 푸는 계산입니다.
'직무의 경계를 나누는 대신 한 사람이 자신의 전문 영역(웹 / 앱 / 서버)을 중심으로 프로젝트 전반을 주도'. 규칙을 데이터로 두면 화면과 서버가 같은 답을 냅니다.
들어온 주문 줄을 매장 재고표와 맞춰 그 매장에서 내줄 수 있는지 가려 화면에 사유별로 묶어 보여줍니다. 매장별 재고표에 품목별 보유 수량과 영업 시각, 맡는 권역을 두고 주문 줄을 먼저 들어온 순서대로 훑어 재고를 차례로 빼며, 남으면 배정으로 넘기고 그렇지 않으면 재고 부족·영업 시간 밖·권역 밖 중 어느 쪽인지 사유로 남깁니다. 재고 수가 안 잡힌 품목은 셀 수 없다고 표시하고, 그 매장이 취급하지 않는 품목은 미취급으로 남겨 사람이 다른 매장을 찾게 합니다. 주문과 재고는 실 운영 자료 대신 지원자가 공개 상품 정보로 만든 것을 가정합니다.
주류 커머스의 매장 운영 담당자입니다. 터미널을 쓰지 않고 하루 종일 주문 현황 화면을 열어 두는 사람이라, 화면에는 재고가 남아 보이는데 매장이 전화로 없다고 알려 오면 그때마다 주문을 손으로 다른 매장에 옮기던 자리에 있습니다.
매장마다 품목 재고와 영업 시각, 맡는 권역을 표로 두고 주문 줄을 들어온 순서대로 훑으면, 내줄 수 있는 줄과 못 내주는 줄이 배정 전에 갈리고 그 이유가 근거로 남는다는 가정입니다. 취급하지 않는 품목은 미취급으로 빠지므로 그 매장에 없는 품목이 그대로 드러납니다.
주문 줄과 매장 재고표를 넣으면 먼저 들어온 순서대로 재고를 빼며 줄마다 배정·보류를 판정하고, 보류면 재고 부족·영업 시간 밖·권역 밖·재고 미상·미취급 중 어느 쪽인지 붙여 사유별로 묶어 보여주는 화면이 도는 완결품입니다. 카드를 펼치면 그 판단의 근거 값이 나옵니다.
공개 상품 정보로 만든 주문 1000줄에 손으로 계산한 정답 배정과 대조해 일치율을 내고, 미취급이 몰리는 품목과 매장을 모아 재고표가 비는 자리를 목록으로 냅니다.
못 내주는 줄에 같은 권역에서 재고가 남는 다른 매장을 후보로 붙여 내고, 한 주문이 두 매장으로 갈리는 경우를 따로 모아 사람이 정하게 하는 단계입니다.
매장 운영 담당자가 주문 줄과 재고표를 넣으면 줄마다 배정 여부와 보류 사유가 사유별로 묶여 화면에 뜨는 과정을 시연합니다.
공개 상품 정보로 만든 주문 1000줄과 손으로 계산한 정답 배정을 대조해 일치율을 냅니다. 단, 정답과 주문·재고를 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
수량이나 재고가 비었거나 품목 표기가 흔들리거나 재고표에 없는 품목이 섞인 입력 30종을 넣어도 화면이 안 깨지고 사유별로 빠지는 비율을 보여줍니다.
차감 순서를 주문 시각에서 희망 시각으로 바꿨을 때 배정이 어떻게 뒤집히는지 회귀로 확인합니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 작성자가 만든 주문의 자가채점이며, 실제 배정 정확도는 데일리샷의 실 주문량과 실 매장 재고가 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아니므로, 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 붙였으니 잘 맞는 게 당연하므로, 재고 결측과 앞 주문이 먼저 가져간 자리, 재고표에 없는 품목을 일부러 섞어 쉬운 줄만 푸는 함정을 피합니다.
이 포트폴리오가 보여주는 것은 재고와 운영 조건을 데이터로 두고 주문 줄과 맞춰 배정 여부를 가르는 기술이며, 주류 유통 규제나 물류 운영 전문성은 주장하지 않습니다. 결제나 성인 확인은 다루지 않고 배정 계산까지만 하며, 판정은 수량 빼기와 시각 비교가 하고 LLM 은 담당자가 읽을 사유 문장만 맡습니다.
실제 운영에서는 재고가 매장에서도 함께 줄어 이 계산과 어긋날 수 있어서, 배정 계획을 확정이 아니라 그 시점의 제안으로 냅니다.
실제 도입 때는 매장과 권역이 자주 바뀌므로, 재고표와 권역 규칙을 이어서 고치는 일을 운영 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
들어온 주문을 품목 단위로 편 것입니다. 줄 번호와 주문번호, 품목 이름, 수량, 희망 매장, 고객 권역, 희망 수령 시각, 주문 시각을 한 행에 둡니다. 한 주문에 품목이 여럿 붙고, 같은 품목을 여러 주문이 같은 매장에서 찾으면 먼저 들어온 주문부터 재고가 빠집니다. 수량이나 권역이 빈 행, 마감 뒤 시각을 적은 행, 그 매장이 취급하지 않는 품목을 일부러 섞어 두어 사유가 갈리게 둡니다.
| line_no | order_no | item_raw | qty | store_raw | zone_raw | wanted_at | ordered_at |
|---|---|---|---|---|---|---|---|
| OL-001 | OD-5001 | 싱글몰트 12년 | 2 | 성수점 | Z-01 | 2026-08-23T19:00:00 | 2026-08-23T10:00:00 |
| OL-002 | OD-5001 | 토닉워터 | 6 | 성수점 | Z-01 | 2026-08-23T19:00:00 | 2026-08-23T10:00:00 |
| OL-003 | OD-5002 | 싱글몰트 12년 | 3 | 성수점 | Z-01 | 2026-08-23T20:00:00 | 2026-08-23T10:20:00 |
| OL-004 | OD-5003 | 내추럴 와인 | 1 | 연남점 | Z-02 | 2026-08-23T23:30:00 | 2026-08-23T11:00:00 |
| OL-005 | OD-5004 | 내추럴 와인 | 2 | 연남점 | Z-05 | 2026-08-24T15:00:00 | 2026-08-23T12:00:00 |
아래 JSON Schema 를 그대로 만족하는 주문 줄을 1000개 더 만들어 주세요. 매장을 대여섯 곳, 품목을 열댓 종 두고 한 주문에 품목을 하나에서 셋까지 붙입니다. 같은 매장의 같은 품목을 여러 주문이 찾게 해 재고가 앞 주문부터 빠지도록 두고, 2할은 수량이나 권역을 비우며, 몇 행은 희망 시각을 자정 가까이 두고 몇 행은 매장이 안 맡는 권역을 적으세요. 재고표에 없는 품목도 몇 행 넣습니다. 배정 결과는 넣지 마세요.
{"type": "object", "properties": {"line_no": {"type": "string"}, "order_no": {"type": "string"}, "item_raw": {"type": "string"}, "qty": {"type": ["integer", "null"]}, "store_raw": {"type": "string"}, "zone_raw": {"type": ["string", "null"]}, "wanted_at": {"type": "string"}, "ordered_at": {"type": "string"}}, "required": ["line_no", "order_no", "item_raw", "qty", "store_raw", "zone_raw", "wanted_at", "ordered_at"]}{"type": "object", "properties": {"line_no": {"type": "string"}, "order_no": {"type": "string"}, "item_raw": {"type": "string"}, "qty": {"type": ["integer", "null"]}, "store_raw": {"type": "string"}, "zone_raw": {"type": ["string", "null"]}, "wanted_at": {"type": "string"}, "ordered_at": {"type": "string"}}, "required": ["line_no", "order_no", "item_raw", "qty", "store_raw", "zone_raw", "wanted_at", "ordered_at"]}매장별 재고와 운영 조건표입니다. 재고 번호와 매장, 품목, 보유 수량, 영업 시작·종료 시각, 맡는 권역 목록, 담당을 한 행에 둡니다. 같은 품목이라도 매장마다 수량과 영업 시각이 달라, 어느 매장으로 들어오느냐로 결과가 갈립니다. 주문에 나오는 품목 중 일부는 그 매장에 두지 않아 미취급이 도출되게 하고, 몇 행은 보유 수량을 비워 셀 수 없는 자리를 만듭니다.
| stock_no | store_raw | item_raw | on_hand | open_hour | close_hour | serve_zones | owner_name |
|---|---|---|---|---|---|---|---|
| ST-01 | 성수점 | 싱글몰트 12년 | 4 | 11 | 22 | ["Z-01","Z-04"] | 성수매장 |
| ST-02 | 성수점 | 토닉워터 | 24 | 11 | 22 | ["Z-01","Z-04"] | 성수매장 |
| ST-03 | 연남점 | 내추럴 와인 | 6 | 12 | 23 | ["Z-02"] | 연남매장 |
| ST-04 | 연남점 | 수제 맥주 6종 | 10 | 12 | 23 | ["Z-02"] | 연남매장 |
| ST-05 | 판교점 | 수제 맥주 6종 | 8 | 10 | 21 | ["Z-03"] | 판교매장 |
아래 JSON Schema 를 그대로 만족하는 매장 재고 행을 60개 더 만들어 주세요. 매장마다 품목을 예닐곱 종 두고 보유 수량을 0 에서 30 사이로, 영업 시각을 10시에서 23시 사이로 둡니다. 맡는 권역은 매장마다 한둘씩 적고, 몇 행은 보유 수량을 비웁니다. 주문에 나오는 품목 중 일부는 그 매장에 넣지 마세요 — 미취급이 있어야 재고표가 비는 자리가 드러납니다. 배정 결과는 넣지 마세요.
{"type": "object", "properties": {"stock_no": {"type": "string"}, "store_raw": {"type": "string"}, "item_raw": {"type": "string"}, "on_hand": {"type": ["integer", "null"]}, "open_hour": {"type": "integer"}, "close_hour": {"type": "integer"}, "serve_zones": {"type": "array", "items": {"type": "string"}}, "owner_name": {"type": "string"}}, "required": ["stock_no", "store_raw", "item_raw", "on_hand", "open_hour", "close_hour", "serve_zones", "owner_name"]}{"type": "object", "properties": {"stock_no": {"type": "string"}, "store_raw": {"type": "string"}, "item_raw": {"type": "string"}, "on_hand": {"type": ["integer", "null"]}, "open_hour": {"type": "integer"}, "close_hour": {"type": "integer"}, "serve_zones": {"type": "array", "items": {"type": "string"}}, "owner_name": {"type": "string"}}, "required": ["stock_no", "store_raw", "item_raw", "on_hand", "open_hour", "close_hour", "serve_zones", "owner_name"]}| Python | 주문 줄을 순서대로 훑으며 재고를 빼고 시각과 권역을 견주는 배정기를 맡습니다. |
| Django | 배정 결과를 담고 운영 화면에 넘기는 API 를 맡습니다. |
| MySQL | 매장별 재고와 주문 줄을 담습니다. |
| React | 사유별로 묶은 주문 카드와 근거 값을 보여주는 화면을 맡습니다. |
✗ fail → 미취급이 절반을 넘으면 재고표를 먼저 채웁니다.
✓ pass → 2주차 정답 대조로 넘어갑니다.
✗ fail → 어긋난 줄을 모아 차감 순서와 권역 정의를 다시 봅니다.
✓ pass → 3주차 대체 매장으로 넘어갑니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
pickup_code사유 라벨 · line_no + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
assignable배정 가능stock_short재고 부족store_closed영업 시간 밖zone_unserved권역 밖item_unhandled미취급 품목stock_missing재고 미상주문 줄 하나와 매장 재고가 만나는 자리마다 그 매장에서 내줄 수 있는지 정합니다. 못 내주면 재고 부족·영업 시간 밖·권역 밖·재고 미상·미취급 중 어느 쪽인지 싣습니다. 배정 계획은 이 사유 코드로 묶습니다.
{"type": "object", "properties": {"verdict_no": {"type": "string"}, "line_no": {"type": "string"}, "order_no": {"type": "string"}, "store_raw": {"type": "string"}, "stock_no": {"type": ["string", "null"]}, "pickup_code": {"type": "string", "enum": ["assignable", "stock_short", "store_closed", "zone_unserved", "item_unhandled", "stock_missing"]}, "stock_left": {"type": ["integer", "null"], "description": "그 매장 재고에서 앞 주문부터 차례로 뺀 뒤 이 줄의 수량까지 뺀 남은 수량입니다. 배정되는 줄에만 채웁니다."}, "on_hand": {"type": ["integer", "null"]}, "owner_name": {"type": ["string", "null"]}, "evidence": {"type": "array", "items": {"type": "object", "properties": {"field": {"type": "string"}, "agg": {"type": ["string", "null"]}, "value": {}}, "required": ["field", "value"]}}, "summary": {"type": "string"}, "hedge": {"type": ["string", "null"]}}, "required": ["verdict_no", "line_no", "order_no", "store_raw", "pickup_code", "evidence", "summary"]}[
{
"verdict_no": "PV-001",
"line_no": "OL-001",
"order_no": "OD-5001",
"store_raw": "성수점",
"stock_no": "ST-01",
"pickup_code": "assignable",
"stock_left": 2,
"on_hand": 4,
"owner_name": "성수매장",
"evidence": [
{
"field": "qty",
"agg": null,
"value": 2
},
{
"field": "on_hand",
"agg": null,
"value": 4
}
],
"summary": "넉 병 중 두 병을 빼도 남아 이 매장에서 내줍니다.",
"hedge": null
},
{
"verdict_no": "PV-002",
"line_no": "OL-002",
"order_no": "OD-5001",
"store_raw": "성수점",
"stock_no": "ST-02",
"pickup_code": "assignable",
"stock_left": 18,
"on_hand": 24,
"owner_name": "성수매장",
"evidence": [
{
"field": "qty",
"agg": null,
"value": 6
},
{
"field": "on_hand",
"agg": null,
"value": 24
}
],
"summary": "같은 주문의 다른 품목도 같은 매장에서 함께 내줍니다.",
"hedge": null
},
{
"verdict_no": "PV-003",
"line_no": "OL-003",
"order_no": "OD-5002",
"store_raw": "성수점",
"stock_no": "ST-01",
"pickup_code": "stock_short",
"stock_left": null,
"on_hand": 4,
"owner_name": "성수매장",
"evidence": [
{
"field": "qty",
"agg": null,
"value": 3
},
{
"field": "on_hand",
"agg": null,
"value": 4
}
],
"summary": "앞 주문이 두 병을 먼저 가져가 두 병만 남아 이 줄을 다 채우지 못합니다.",
"hedge": null
},
{
"verdict_no": "PV-004",
"line_no": "OL-004",
"order_no": "OD-5003",
"store_raw": "연남점",
"stock_no": "ST-03",
"pickup_code": "store_closed",
"stock_left": null,
"on_hand": 6,
"owner_name": "연남매장",
"evidence": [
{
"field": "wanted_at",
"agg": null,
"value": "2026-08-23T23:30:00"
},
{
"field": "close_hour",
"agg": null,
"value": 23
}
],
"summary": "희망 시각이 마감 뒤라 그 시간에는 받을 사람이 없습니다.",
"hedge": null
},
{
"verdict_no": "PV-005",
"line_no": "OL-005",
"order_no": "OD-5004",
"store_raw": "연남점",
"stock_no": "ST-03",
"pickup_code": "zone_unserved",
"stock_left": null,
"on_hand": 6,
"owner_name": "연남매장",
"evidence": [
{
"field": "zone_raw",
"agg": null,
"value": "Z-05"
},
{
"field": "serve_zones",
"agg": null,
"value": [
"Z-02"
]
}
],
"summary": "그 매장이 맡는 권역 밖이라 다른 매장을 찾아야 합니다.",
"hedge": null
},
{
"verdict_no": "PV-006",
"line_no": "OL-008",
"order_no": "OD-5006",
"store_raw": "판교점",
"stock_no": "ST-06",
"pickup_code": "stock_missing",
"stock_left": null,
"on_hand": null,
"owner_name": "판교매장",
"evidence": [
{
"field": "on_hand",
"agg": null,
"value": null
},
{
"field": "qty",
"agg": null,
"value": 1
}
],
"summary": "그 매장 재고 수가 안 잡혀 내줄 수 있는지 셀 수 없습니다.",
"hedge": "실사 전이라 값이 빈 것일 수 있어 매장에 확인합니다."
},
{
"verdict_no": "PV-007",
"line_no": "OL-011",
"order_no": "OD-5009",
"store_raw": "성수점",
"stock_no": null,
"pickup_code": "item_unhandled",
"stock_left": null,
"on_hand": null,
"owner_name": null,
"evidence": [
{
"field": "item_raw",
"agg": null,
"value": "논알콜 스피릿"
},
{
"field": "stock_no",
"agg": "count",
"value": 12
}
],
"summary": "그 매장이 취급하지 않는 품목이라 재고표 열두 행 어디에도 없습니다.",
"hedge": null
},
{
"verdict_no": "PV-008",
"line_no": "OL-009",
"order_no": "OD-5007",
"store_raw": "성수점",
"stock_no": "ST-02",
"pickup_code": "assignable",
"stock_left": 6,
"on_hand": 24,
"owner_name": "성수매장",
"evidence": [
{
"field": "qty",
"agg": null,
"value": 12
},
{
"field": "on_hand",
"agg": null,
"value": 24
}
],
"summary": "앞 주문이 여섯을 가져가고도 열둘이 남아 그대로 내줍니다.",
"hedge": null
}
][자동 검증 · 코드가 판정합니다] 1. pickup_code 가 enum 여섯 값 중 하나인지 확인합니다. 2. verdict_no·line_no·order_no·store_raw·pickup_code·evidence·summary 가 모두 채워졌는지 확인합니다. 3. line_no 가 주문 줄에 실재하는 번호인지 대조합니다. 4. stock_no 가 있으면 재고표에 실재하는 행 번호인지 대조합니다. 5. stock_no 가 있으면 on_hand·owner_name 이 그 재고 행의 값과 같은지 대조합니다. 6. store_raw·item_raw 를 띄어쓰기를 접어 재고표와 맞추고, 맞는 행이 없으면 pickup_code 가 item_unhandled 인지 확인합니다. 7. stock_left 를 on_hand 에서 같은 매장·품목의 앞 주문 수량을 차례로 빼고 이 줄의 qty 까지 빼 다시 계산합니다. 8. on_hand 나 qty 가 비어 있으면 pickup_code 가 stock_missing 인지 확인합니다. 9. 앞 줄까지 빼고 남은 수량이 qty 에 못 미치면 pickup_code 가 stock_short 인지 다시 계산합니다. 10. wanted_at 의 시가 open_hour 보다 이르거나 close_hour 보다 늦으면 pickup_code 가 store_closed 인지 다시 확인합니다. 11. zone_raw 가 serve_zones 에 없으면 pickup_code 가 zone_unserved 인지 확인합니다. 12. pickup_code 가 assignable 이면 위 검사를 모두 통과하고 stock_left 가 0 이상인지 다시 확인합니다. 13. evidence 의 field 이름이 주문 줄과 재고표에 실재하는 컬럼인지 대조합니다. 14. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 같은지 확인합니다. 15. summary 가 존댓말로 끝나는지 확인합니다. [평가 러너 · 2주차] 공개 상품 정보로 만든 주문 1000줄에 손으로 계산한 정답 배정과 대조해 일치율과 사유 코드별 분포를 내고, 미취급이 몰리는 품목과 매장을 목록으로 냅니다. [수동 검증 · 사람이 봅니다] 1. 재고 수가 안 잡힌 품목을 매장이 실사해 채웁니다. 2. 한 주문이 두 매장으로 갈릴 때 나눠 보낼지 운영 담당이 정합니다.