포컴퍼니
인턴·신입근거: 데이터를 활용해 제품과 업무 현황을 파악할 수 있는 대시보드와 관리 도구 개발
포컴퍼니는 Abib·NAMING.·BOLD FORMULA·VASOL 네 브랜드를 올리브영과 면세점, 자사몰, 아마존, 틱톡샵, 미국 코스트코까지 서로 다른 성격의 채널로 내보냅니다. 채널이 요구하는 잔여 사용기한과 최소 발주 수량이 제각각이라, 브랜드 하나가 아니라 브랜드 넷과 채널 열두 곳이 곱해지는 자리에서만 이 계산이 손에 부칩니다. 공고가 첫 업무로 적은 것도 데이터로 제품과 업무 현황을 파악하는 대시보드와 관리 도구 개발이고, CEO직속 테크팀이 마케팅·영업·운영의 반복 업무를 걷어 가는 자리입니다. 다만 이 포트폴리오는 기준표를 읽어 판정을 만드는 규칙 구현과 그 결과를 담당자가 읽을 화면으로 만드는 일을 보여줍니다. 화장품 유통 실무나 나라별 표시·통관 규정의 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
공고는 마케팅·영업·운영에서 반복되는 업무를 자동화하는 내부 도구 개발을 첫 업무로 적습니다. 바깥에 파는 제품이 아니라 브랜드를 굴리는 사람들이 매일 여는 화면이 산출물입니다.
여러 SaaS와 외부 API를 연결해 데이터 수집·처리·업무 자동화 시스템을 만든다고 적혀 있습니다. 채널마다 모양이 다른 자료를 한 규격으로 맞추는 일이 그대로 업무입니다.
데이터로 제품과 업무 현황을 파악하는 대시보드와 관리 도구 개발이 업무에 못박혀 있고, 데이터 기반 가설검증으로 문제를 푸는 사람을 찾습니다. LLM 과 AI Agent 활용 경험도 우대로 적혀 있습니다.
로트 목록과 채널 입고 기준표를 올리면 로트마다 오늘 기준 남은 개월을 세어 채널 하한과 맞춰 보고, 예정대로 내보낼 로트와 다른 채널로 돌릴 로트, 아예 못 내보낼 로트를 갈라 놓습니다. 어디로 갈지는 남은 개월과 최소 발주 수량이 정하고, 클로드는 그렇게 갈라진 로트를 창고에 넘길 출고 지시 한 줄로 풀어 씁니다.
Abib·NAMING.·BOLD FORMULA·VASOL 재고를 올리브영·면세점·아마존으로 내보내는 포컴퍼니 유통 담당자 — 채널마다 받아 주는 잔여 사용기한과 최소 발주 수량이 달라 로트별로 어디에 넣을 수 있는지 매번 손으로 맞춰 본다
로트를 버리게 되는 까닭은 기한이 짧아서가 아니라, 채널마다 다른 하한을 로트 하나하나에 대 보는 일이 손으로만 되기 때문입니다. 남은 개월을 세어 열두 채널 하한과 한꺼번에 맞춰 보고 같은 제품 로트를 합쳐 수량까지 재면, 아직 옮길 수 있을 때 옮길 곳이 정해집니다.
유통 담당자가 아침에 재고 파일을 올려 바로 쓰는 화면 하나를 냅니다. 로트 목록과 채널 기준표를 올리면 로트마다 남은 개월과 배정 채널이 나오고, 못 내보내는 로트는 무엇에 걸렸는지 근거 값이 함께 뜹니다. 두 자료는 담당자가 내려받은 파일을 올리는 것으로 시작하고, 사내 재고 시스템과 잇는 일은 3주차로 미룹니다.
유통 담당자가 손으로 배정한 40건과 화면 판정을 자동으로 맞춰 보고 어긋난 유형을 주간 리포트로 냅니다. 배정이 끝난 로트는 창고로 넘길 출고 지시서로 뽑아 내려받습니다.
담당자가 채널 하한과 최소 발주 수량을 화면에서 고치면 그날 판정이 다시 돌고, 주간 판매 수량으로 소진 예상 주수를 갱신해 기한 안에 다 못 파는 로트를 목록 맨 위에 세웁니다.
유통 담당자가 재고 파일과 채널 기준표를 올리면 로트마다 남은 개월과 갈 채널이 나오고, 못 내보내는 로트는 어느 하한에 걸렸는지 그 자리에서 읽습니다.
유통기한 칸이 비어 있거나 날짜 표기가 뒤섞이거나 채널 이름이 기준표에 없는 파일 30종을 올려도 목록이 사라지지 않고, 걸린 로트만 판정 보류로 내려갑니다.
같은 제품을 여러 로트로 나눠 받았을 때도 로트별이 아니라 합계로 최소 발주 수량을 재고, 합쳐서 넘으면 보류 대신 그 채널로 배정됩니다.
손으로 배정한 40건과 화면 판정을 맞춰 일치율을 냅니다. 단, 정답과 데이터를 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
위 수치는 더미데이터 자가채점이며 실제 배정 적중률은 포컴퍼니의 실제 로트 재고와 채널별 입고 기준이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아닙니다. 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 만들었으니 잘 맞는 것이 당연합니다. 결측·악성·경계 케이스를 더미에 일부러 섞어 쉬운 문제만 푸는 함정을 피합니다.
하한을 넘겼다는 판정이 곧 그 채널이 받아 준다는 뜻은 아닙니다. 선적과 통관에 걸리는 시간만큼 기한이 더 깎이므로 배정은 후보로 읽고 마지막은 담당자가 정합니다.
이 포트폴리오는 기준표를 읽어 판정을 만드는 규칙 구현을 보여줍니다. 화장품 유통 실무와 나라별 표시·통관 규정의 전문성은 주장하지 않습니다.
실제 도입에서는 채널 하한이 계약서마다 다르고 프로모션 기간에 한시로 풀리기도 합니다. 기준을 코드에서 빼 담당자가 고치는 화면으로 옮겨야 하는데, 그 일은 도입 단계에서 따로 잡습니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
브랜드 네 곳의 로트별 재고입니다. 유통기한이 코앞인 로트와, 주간 판매 수량이 아직 안 잡혀 weekly_sold 가 비어 있는 신규 로트를 일부러 넣었습니다.
| lot_id | brand | sku | qty | expires_on | current_channel | weekly_sold |
|---|---|---|---|---|---|---|
| L-2409 | Abib | 어성초 카밍 토너 200ml | 1,800 | 2027-09-30 | 면세점 | 140 |
| L-2503 | NAMING. | 글로우 쿠션 21호 15g | 4,800 | 2028-09-20 | 올리브영 | 620 |
| L-2312 | BOLD FORMULA | 딥클렌징 폼 150ml | 900 | 2027-02-15 | 자사몰 | 45 |
| L-2508 | VASOL | 이너 클렌징폼 200ml | 640 | 2028-03-31 | 아마존 | 30 |
| L-2601 | VASOL | 이너 클렌징폼 200ml | 210 | 2028-05-31 | 아마존 | — |
아래 JSON Schema 에 맞는 로트 재고 행을 더 만들어 주세요. {"type":"object","properties":{"lot_id":{"type":"string"},"brand":{"type":"string","enum":["Abib","NAMING.","BOLD FORMULA","VASOL"]},"sku":{"type":"string"},"qty":{"type":"integer"},"expires_on":{"type":"string"},"current_channel":{"type":"string"},"weekly_sold":{"type":["integer","null"]}},"required":["lot_id","brand","sku","qty","expires_on","current_channel"]} 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) weekly_sold 가 비어 있는 신규 입고 로트, (2) 같은 sku 를 나눠 가진 소량 로트 두세 개, (3) expires_on 이 오늘로부터 두세 달밖에 안 남은 로트, (4) qty 가 채널 최소 발주 수량 언저리에서 아슬아슬하게 갈리는 로트. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"lot_id":{"type":"string"},"brand":{"type":"string","enum":["Abib","NAMING.","BOLD FORMULA","VASOL"]},"sku":{"type":"string"},"qty":{"type":"integer"},"expires_on":{"type":"string"},"current_channel":{"type":"string"},"weekly_sold":{"type":["integer","null"]}},"required":["lot_id","brand","sku","qty","expires_on","current_channel"]}채널마다 받아 주는 잔여 사용기한 하한과 최소 발주 수량을 담은 기준표입니다. 배정을 가르는 잣대는 전부 이 표에서 옵니다.
| channel | country | min_remaining_months | min_order_qty |
|---|---|---|---|
| 올리브영 | KR | 10 | 300 |
| 면세점 | KR | 18 | 500 |
| 자사몰 | KR | 6 | 1 |
| 쿠팡 | KR | 7 | 200 |
| 무신사 뷰티 | KR | 6 | 200 |
아래 JSON Schema 에 맞는 채널 입고 기준 행을 더 만들어 주세요. {"type":"object","properties":{"channel":{"type":"string"},"country":{"type":"string","enum":["KR","US","JP","SG","MY","HK"]},"min_remaining_months":{"type":"integer"},"min_order_qty":{"type":"integer"}},"required":["channel","country","min_remaining_months","min_order_qty"]} 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) min_remaining_months 가 같은 채널 둘, (2) 하한은 낮은데 최소 발주 수량이 큰 채널, (3) 하한이 18개월 이상인 면세·대형 리테일 채널, (4) 같은 country 안에서 하한이 갈리는 채널 묶음. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"channel":{"type":"string"},"country":{"type":"string","enum":["KR","US","JP","SG","MY","HK"]},"min_remaining_months":{"type":"integer"},"min_order_qty":{"type":"integer"}},"required":["channel","country","min_remaining_months","min_order_qty"]}| TypeScript | 규칙 엔진과 화면이 같은 타입 정의를 나눠 쓰도록 프런트와 백엔드를 한 언어로 묶습니다. 로트와 채널 기준의 모양이 어긋나면 빌드에서 걸립니다. |
| React | 유통 담당자가 여는 배정판입니다. 판정 묶음을 왼쪽에 세우고 누른 로트의 근거를 오른쪽에 폅니다. |
| Node.js | 파일 업로드와 배정 실행, 출고 지시서 생성을 맡는 백엔드입니다. 규칙은 여기에만 두고 화면은 결과만 받습니다. |
| PostgreSQL | 로트 재고와 채널 기준표, 배정 이력을 담습니다. 기준표가 바뀐 날짜를 남겨 지난 판정을 그대로 되짚습니다. |
| 외부 API 연동 | 채널별 판매 수량을 SaaS 에서 받아 weekly_sold 를 채웁니다. 공고가 적은 여러 SaaS와 외부 API 연결이 여기에 해당합니다. |
| AI Coding Agent | 규칙 엔진의 단위 테스트와 채널별 경계 케이스를 에이전트로 먼저 뽑아 놓고 손으로 다듬습니다. |
| LLM | 배정이 끝난 로트를 창고 전달용 한 줄로 풀어 씁니다. 채널을 고르는 일에는 손대지 않습니다. |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우려면 담당자가 손으로 매긴 배정과 맞대 보는 단계로 넘어갑니다.
✓ pass → 여기까지도 완결입니다. 더 키우려면 채널 하한을 화면에서 고치고 소진 속도까지 같이 보는 단계로 확장합니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
verdict사유 라벨 · lot_id + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
예정 채널로 출고예정 채널 출고기한 맞는 채널로 돌림채널 변경어느 채널에도 못 넣음출고 불가묶음 수량 미달로 보류수량 보류로트 하나를 어느 채널로 내보낼지, 못 내보내면 무엇에 걸렸는지를 근거 값과 함께 남기는 형식입니다. 배정은 규칙이 정하고 출고 지시 문장만 모델이 씁니다.
{"type":"object","properties":{"lot_id":{"type":"string"},"brand":{"type":"string"},"verdict":{"type":"string","enum":["예정 채널로 출고","기한 맞는 채널로 돌림","어느 채널에도 못 넣음","묶음 수량 미달로 보류"]},"assigned_channel":{"type":["string","null"],"description":"배정된 채널. 하한을 넘는 채널 가운데 min_remaining_months 가 가장 큰 곳을 고르고, 넘는 채널이 없으면 비웁니다"},"remaining_months":{"type":"integer","description":"화면을 여는 날(데모는 2026-09-06)부터 expires_on 까지의 온전한 개월 수. 남은 날짜는 버립니다"},"sku_total_qty":{"type":["integer","null"],"description":"같은 sku 로트의 qty 합계. 수량으로 갈린 판정에만 채웁니다"},"weeks_to_sell_out":{"type":["number","null"],"description":"qty 를 weekly_sold 로 나눈 소진 예상 주수. 소수 첫째 자리에서 반올림하고, weekly_sold 가 비어 있으면 비웁니다"},"evidence":{"type":"array","items":{"type":"object","properties":{"source":{"type":"string","enum":["lot_stock","channel_intake_rules"]},"field":{"type":"string"},"agg":{"type":["string","null"],"enum":["count","sum","avg","min","max",null]},"value":{"type":["string","integer","null"]}},"required":["source","field","value"]}},"summary":{"type":"string"},"hedge":{"type":["string","null"]}},"required":["lot_id","brand","verdict","remaining_months","evidence","summary"]}[
{
"lot_id": "L-2503",
"brand": "NAMING.",
"verdict": "예정 채널로 출고",
"assigned_channel": "올리브영",
"remaining_months": 24,
"sku_total_qty": null,
"weeks_to_sell_out": 7.7,
"evidence": [
{
"source": "lot_stock",
"field": "expires_on",
"value": "2028-09-20"
},
{
"source": "channel_intake_rules",
"field": "min_remaining_months",
"value": 10
},
{
"source": "lot_stock",
"field": "qty",
"value": 4800
},
{
"source": "channel_intake_rules",
"field": "min_order_qty",
"value": 300
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": 620
}
],
"summary": "남은 24개월이 올리브영 하한 10개월을 넉넉히 넘어 예정대로 내보냅니다.",
"hedge": null
},
{
"lot_id": "L-2441",
"brand": "NAMING.",
"verdict": "예정 채널로 출고",
"assigned_channel": "왓슨스",
"remaining_months": 15,
"sku_total_qty": null,
"weeks_to_sell_out": 16.2,
"evidence": [
{
"source": "lot_stock",
"field": "expires_on",
"value": "2027-12-20"
},
{
"source": "channel_intake_rules",
"field": "min_remaining_months",
"value": 14
},
{
"source": "lot_stock",
"field": "qty",
"value": 2100
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": 130
}
],
"summary": "남은 15개월이 왓슨스 하한 14개월을 한 달 차이로 넘겨 예정대로 내보냅니다.",
"hedge": "소진 예상 16.2주는 지금 판매 속도가 그대로 이어진다고 본 합성 기준 계산입니다."
},
{
"lot_id": "L-2409",
"brand": "Abib",
"verdict": "기한 맞는 채널로 돌림",
"assigned_channel": "아마존",
"remaining_months": 12,
"sku_total_qty": null,
"weeks_to_sell_out": 12.9,
"evidence": [
{
"source": "lot_stock",
"field": "expires_on",
"value": "2027-09-30"
},
{
"source": "channel_intake_rules",
"field": "min_remaining_months",
"value": 18
},
{
"source": "channel_intake_rules",
"field": "min_order_qty",
"value": 1000
},
{
"source": "lot_stock",
"field": "qty",
"value": 1800
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": 140
}
],
"summary": "남은 12개월이 면세점 하한 18개월에 모자라, 하한이 12개월인 아마존으로 돌립니다.",
"hedge": null
},
{
"lot_id": "L-2377",
"brand": "Abib",
"verdict": "기한 맞는 채널로 돌림",
"assigned_channel": "틱톡샵",
"remaining_months": 9,
"sku_total_qty": null,
"weeks_to_sell_out": 14.4,
"evidence": [
{
"source": "lot_stock",
"field": "expires_on",
"value": "2027-06-30"
},
{
"source": "channel_intake_rules",
"field": "min_remaining_months",
"value": 15
},
{
"source": "channel_intake_rules",
"field": "min_order_qty",
"value": 600
},
{
"source": "lot_stock",
"field": "qty",
"value": 2600
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": 180
}
],
"summary": "남은 9개월이 코스트코 하한 15개월에 모자라, 하한이 9개월인 틱톡샵으로 돌립니다.",
"hedge": null
},
{
"lot_id": "L-2312",
"brand": "BOLD FORMULA",
"verdict": "어느 채널에도 못 넣음",
"assigned_channel": null,
"remaining_months": 5,
"sku_total_qty": null,
"weeks_to_sell_out": 20,
"evidence": [
{
"source": "lot_stock",
"field": "expires_on",
"value": "2027-02-15"
},
{
"source": "channel_intake_rules",
"field": "min_remaining_months",
"agg": "min",
"value": 6
},
{
"source": "lot_stock",
"field": "qty",
"value": 900
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": 45
}
],
"summary": "남은 5개월이 채널 열두 곳 가운데 가장 낮은 하한 6개월에도 닿지 못해 어디에도 넣지 못합니다.",
"hedge": null
},
{
"lot_id": "L-2508",
"brand": "VASOL",
"verdict": "묶음 수량 미달로 보류",
"assigned_channel": "아마존",
"remaining_months": 18,
"sku_total_qty": 850,
"weeks_to_sell_out": 21.3,
"evidence": [
{
"source": "lot_stock",
"field": "qty",
"value": 640
},
{
"source": "lot_stock",
"field": "qty",
"agg": "sum",
"value": 850
},
{
"source": "channel_intake_rules",
"field": "min_order_qty",
"value": 1000
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": 30
}
],
"summary": "640개가 아마존 최소 발주 1,000개에 모자라고 같은 제품의 다른 로트를 합쳐도 850개라 보류합니다.",
"hedge": null
},
{
"lot_id": "L-2601",
"brand": "VASOL",
"verdict": "묶음 수량 미달로 보류",
"assigned_channel": "아마존",
"remaining_months": 20,
"sku_total_qty": 850,
"weeks_to_sell_out": null,
"evidence": [
{
"source": "lot_stock",
"field": "qty",
"value": 210
},
{
"source": "lot_stock",
"field": "qty",
"agg": "sum",
"value": 850
},
{
"source": "channel_intake_rules",
"field": "min_order_qty",
"value": 1000
},
{
"source": "lot_stock",
"field": "weekly_sold",
"value": null
}
],
"summary": "210개를 앞 로트와 합쳐도 850개라 아마존 최소 발주에 닿지 못해 보류합니다.",
"hedge": "주간 판매 수량이 비어 있어 소진 예상 주수를 내지 못했습니다. 합성 기준 판정이라 판매가 시작되면 달라집니다."
}
][자동 검증 · 코드가 판정합니다] 1. verdict 가 예정 채널로 출고·기한 맞는 채널로 돌림·어느 채널에도 못 넣음·묶음 수량 미달로 보류 네 값 중 하나인지 확인합니다. 2. lot_id·brand·verdict·remaining_months·evidence·summary 여섯 필드가 모두 존재하는지 확인합니다. 3. remaining_months 가 기준일과 expires_on 사이의 온전한 개월 수와 같은지 다시 계산합니다. 4. sku_total_qty 가 같은 sku 로트 qty 의 합과 같은지 다시 계산하고, weeks_to_sell_out 이 qty 를 weekly_sold 로 나눈 값과 소수 첫째 자리까지 같은지 다시 계산합니다. 5. evidence 의 field 가 lot_stock·channel_intake_rules 의 컬럼에 실재하는 이름인지 대조합니다. 6. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 글자 그대로 같은지 확인합니다. 7. weekly_sold 가 비어 있으면 weeks_to_sell_out 도 비고 hedge 가 채워지는지 확인하며, summary 가 존댓말 한 문장으로 끝나는지 확인합니다. [판정 순서 · 규칙] 기한을 먼저 보고 수량을 나중에 봅니다. 남은 개월이 어느 채널 하한도 넘지 못하면 그 자리에서 어느 채널에도 못 넣음으로 끝나고, 넘는 채널이 있을 때만 그 채널의 최소 발주 수량과 같은 sku 합계를 견줍니다. 다만 예정 채널이 그대로 살아남으면 예정 채널로 출고이고, 다른 채널로 바뀌면 기한 맞는 채널로 돌림입니다. [평가 러너 · 2주차] 유통 담당자가 손으로 배정한 40건과 화면 판정을 맞춰 일치율과 판정별 적중률을 냅니다. [수동 검증 · 사람이 봅니다] 1. 하한을 한두 달 차이로 겨우 넘긴 로트 20건을 뽑아, 배송 기간까지 생각하면 그 채널이 정말 받는지 눈으로 확인합니다. 2. 같은 sku 를 여러 로트로 묶어 보낼 때 유통기한이 짧은 로트를 먼저 태울지 담당자와 맞춰 정합니다.