루쿠쿠
경력근거: 운영 효율을 높이기 위한 어드민, 대시보드 및 업무 자동화 도구를 개발
루쿠쿠는 살로몬과 FILA 같은 브랜드의 글로벌 커머스를 Shopify 와 Cafe24 와 Headless 스토어프론트로 만들면서 운영 효율을 높이는 어드민과 자동화 도구 개발을 주요업무에 함께 못박았고, 자격요건도 사용자의 구매 경험과 비즈니스 지표를 함께 보고 개선할 사람을 찾습니다. 이 화면은 지표를 늘어놓는 대시보드가 아니라 운영 담당이 직접 묻고 스스로 답을 받아 가는 어드민 도구로 잡았고, 우대사항의 GraphQL 은 확정된 조건을 질의로 조립하는 자리에 들어가며 GA4 와 A/B 테스트는 확정한 세그먼트를 실험 대상으로 내보내는 3주차에 붙습니다. 이 포트폴리오가 보여주는 것은 자연어를 구조화된 조건으로 바꾸고 사람이 화면에서 확정해야만 질의가 실행되는 흐름을 만드는 프론트엔드 기술이며, 글로벌 커머스 전환율 최적화나 브랜드 마케팅 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
공고가 스토어프론트 구축과 나란히 운영 효율을 높이는 어드민과 자동화 도구 개발을 주요업무로 적었습니다. 운영 담당이 직접 묻고 답을 받아 가는 화면이 그 일의 첫 조각입니다.
자격요건이 사용자의 구매 경험과 비즈니스 지표를 함께 보고 개선할 사람을 찾습니다. 퍼널 단계와 잔존을 조건으로 직접 물어 보는 도구가 그 두 가지를 한 화면에 놓습니다.
우대사항에 GraphQL 과 GA4 와 A/B 테스트 경험이 함께 걸려 있습니다. 확정된 조건을 GraphQL 질의로 조립하고 그 세그먼트를 실험 대상으로 내보내는 흐름이 그 셋을 한 줄로 잇습니다.
브랜드 커머스 운영 담당이 보고 싶은 방문자 묶음을 한국어 한 문장으로 적으면 그 문장이 기간과 브랜드와 퍼널 단계와 기기 조건 카드로 쪼개지는 어드민 화면입니다. 두 가지로 읽히는 구절은 미확정 칩으로 남아 사람이 후보를 고르거나 값을 직접 고쳐야 실행 버튼이 열리고, 확정한 조건은 GraphQL 질의로 조립되어 스토어프론트 이벤트 기록에 그대로 돌아 대상 세션 목록과 단계별 잔존 수를 냅니다. 조건마다 문장의 어느 구절에서 나왔는지가 붙어 있어 숫자를 보기 전에 무엇을 물었는지부터 확인합니다.
브랜드 커머스 운영을 맡아 지난주 모바일에서 장바구니까지 왔다가 결제로 가지 않은 첫 방문자가 몇 명인지 궁금할 때마다 프론트엔드 개발자에게 조건을 말로 설명하고 결과를 기다리던 담당자가, 문장을 그대로 적고 애매한 부분만 화면에서 골라 스스로 답을 얻고 싶은 사람입니다.
문장을 조건으로 옮기는 일은 모델에 맡기되 두 가지로 읽히는 구절을 사람이 화면에서 확정하게 만들면, 운영 담당이 개발자를 거치지 않고도 자기가 물은 것과 나온 숫자가 같은지 확인하며 세그먼트를 뽑게 된다는 가정입니다.
운영 담당이 보고 싶은 방문자 조건을 한국어 한 문장으로 적으면 기간과 브랜드와 퍼널 단계와 기기 조건 카드로 쪼개지고, 두 가지로 읽히는 구절은 미확정 칩으로 남아 사람이 후보를 고르기 전까지 실행 버튼이 잠긴 채로 있는 웹 화면이 배포까지 끝난 완결품입니다. 확정하면 조건이 GraphQL 질의로 조립되어 이벤트 기록에 돌고 대상 세션 목록과 단계별 잔존 수가 나오며, 조건마다 문장의 어느 구절에서 나왔는지가 함께 붙습니다. 실제 Shopify 와 Cafe24 연동 대신 같은 모양의 이벤트를 담은 로컬 GraphQL 서버를 가정해 시작합니다. 만드는 덩어리는 조건 확정 화면과 질의 실행 결과 둘이며 평일 5일에 혼자 끝나는 범위입니다.
확정 화면에서 사람이 고른 표현과 조건의 짝을 표현 사전에 쌓아 같은 말이 다음 문장부터 미확정 없이 확정되게 만들고, 요청 문장 40종을 정답 조건과 대조해 어긋난 필드와 후보 목록을 보정한 2차 판입니다.
확정된 세그먼트 두 개를 나란히 놓고 단계별 잔존 차이를 보는 비교 화면과, 세그먼트 조건을 GA4 탐색 조건과 GTM 트리거 초안으로 내보내 A/B 실험 대상 정의로 바로 쓰게 하는 확장판입니다.
요청 문장 한 줄을 적어 조건 카드가 뜨고 미확정 칩을 고른 뒤 대상 세션 목록과 단계별 잔존이 나오는 흐름을 처음부터 끝까지 시연합니다.
기간이 두 가지로 읽히는 문장과 브랜드 표기가 흔들리는 문장과 퍼널 단계가 빠진 문장을 심어 두고, 그 세 유형이 모두 미확정으로 잡혀 실행 버튼이 잠기는 것과 사람이 고른 값이 질의문에 그대로 반영되는 것을 보입니다. 다만 정답과 데이터를 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
오타와 이모지와 영문 혼용이 섞이고 조건이 하나도 없는 문장 30종을 넣어도 화면이 죽지 않고 해석하지 못한 구절로 남기는 것을 보입니다.
요청 문장 40종을 넣어 확정된 조건이 정답 조건과 필드와 연산자와 값이 일치하는 비율을 2주차에 보고합니다. 규칙으로 채점하며 합성 기준 추정이라 실제 요청과 다를 수 있습니다.
위 수치는 더미데이터 자가채점이며, 실제 운영 담당이 얼마나 스스로 답을 얻는지는 루쿠쿠가 운영하는 브랜드 스토어프론트의 실제 이벤트와 담당자의 실사용이 있어야 측정 가능합니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아닙니다. 면접에서는 데모가 도는 상태와 실검증 준비 상태로 솔직히 설명합니다.
정답 조건을 작성자가 만들었으니 잘 맞는 것이 당연합니다. 기간이 두 가지로 읽히는 문장과 브랜드 표기가 흔들리는 문장과 조건이 서로 충돌하는 문장과 조건이 하나도 없는 문장을 요청 더미에 일부러 섞어 두었습니다.
이 포트폴리오가 보여주는 것은 자연어를 구조화된 조건으로 바꾸고 사람이 확정해야만 질의가 실행되는 화면 흐름을 만드는 기술이며, 글로벌 커머스 전환율 최적화나 브랜드 마케팅 도메인 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
실제 도입에서는 이벤트 스키마가 Shopify 와 Cafe24 와 Headless 마다 다르고 운영 담당이 쓰는 표현도 브랜드마다 달라집니다. 이벤트 어댑터와 표현 사전을 실제 스토어프론트에 맞춰 다시 채우는 일을 도입 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
브랜드 운영 담당이 실제로 적을 법한 요청 문장과 그 문장에서 나와야 하는 정답 조건입니다. 변환기를 규칙으로 채점하고 어느 구절이 미확정으로 남아야 하는지를 정하는 기준입니다.
| req_id | brand_raw | text | gold_conditions | ambiguous_spans |
|---|---|---|---|---|
| R001 | Salomon | 지난주 모바일에서 장바구니까지 왔다가 결제로 안 간 첫 방문자 보여줘 | [{"field":"period","op":"between","value":"2026-07-20..2026-07-26"},{"field":"brand","op":"eq","value":"salomon"},{"field":"device","op":"eq","value":"mobile"},{"field":"step","op":"eq","value":"cart"},{"field":"behavior","op":"not","value":"purchase"},{"field":"first_visit","op":"eq","value":"true"}] | ["지난주"] |
| R002 | 살로몬 | 살로몬 상품상세에서 이탈한 사람들 | [{"field":"brand","op":"eq","value":"salomon"},{"field":"step","op":"eq","value":"pdp"},{"field":"behavior","op":"not","value":"cart"}] | ["이탈한"] |
| R003 | FILA | 어제 데스크탑으로 들어온 재방문자 중에 결제까지 간 세션 | [{"field":"period","op":"eq","value":"2026-07-31"},{"field":"brand","op":"eq","value":"fila"},{"field":"device","op":"eq","value":"desktop"},{"field":"first_visit","op":"eq","value":"false"},{"field":"step","op":"eq","value":"purchase"}] | [] |
| R004 | VERISH | 요즘 왜 이렇게 안 팔리지 | [] | ["요즘","안 팔리지"] |
| R005 | Nonfiction | 논픽션 최근 30일 체크아웃 진입한 모바일 세션 🙏 | [{"field":"brand","op":"eq","value":"nonfiction"},{"field":"period","op":"between","value":"2026-07-03..2026-08-01"},{"field":"step","op":"eq","value":"checkout"},{"field":"device","op":"eq","value":"mobile"}] | ["최근 30일"] |
아래 JSON Schema에 맞는 세그먼트 요청 문장 행을 40건 더 만들어 주세요. {"type":"object","properties":{"req_id":{"type":"string"},"brand_raw":{"type":"string"},"text":{"type":"string"},"gold_conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["period","brand","step","device","behavior","first_visit"]},"op":{"type":"string","enum":["eq","in","between","not"]},"value":{"type":"string"}},"required":["field","op","value"]}},"ambiguous_spans":{"type":"array","items":{"type":"string"}}},"required":["req_id","brand_raw","text","gold_conditions","ambiguous_spans"]} 쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라. 첫째 지난주와 지난달과 최근 30일처럼 기준을 두 가지로 읽을 수 있는 기간 표현이 든 문장, 둘째 같은 브랜드를 한글과 영문과 오타로 제각각 부르거나 별칭 목록에 없는 브랜드를 부르는 문장, 셋째 이탈했다처럼 어느 단계에서 멈춘 것인지 지정되지 않은 문장, 넷째 모바일만 빼고 모바일처럼 조건이 서로 충돌하는 문장, 다섯째 조건으로 옮길 구절이 하나도 없는 감상 문장, 여섯째 이모지와 영문이 섞이거나 문장 부호가 없는 문장. 각 행의 gold_conditions 에는 사람이 확정한 뒤의 정답 조건만 적고, 확정 없이는 값을 정할 수 없는 구절은 ambiguous_spans 에 원문 그대로 넣어 주세요.{"type":"object","properties":{"req_id":{"type":"string"},"brand_raw":{"type":"string"},"text":{"type":"string"},"gold_conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["period","brand","step","device","behavior","first_visit"]},"op":{"type":"string","enum":["eq","in","between","not"]},"value":{"type":"string"}},"required":["field","op","value"]}},"ambiguous_spans":{"type":"array","items":{"type":"string"}}},"required":["req_id","brand_raw","text","gold_conditions","ambiguous_spans"]}확정된 조건이 실제로 돌아가는 스토어프론트 세션 이벤트 기록입니다. 대상 세션 목록과 단계별 잔존 수를 계산하는 입력입니다.
| event_id | session_id | brand_id | occurred_at | step | device | is_first_visit | locale |
|---|---|---|---|---|---|---|---|
| E001 | S-1001 | salomon | 2026-07-22T10:12:00+09:00 | cart | mobile | true | ko-KR |
| E002 | S-1001 | salomon | 2026-07-22T10:14:00+09:00 | checkout | mobile | true | ko-KR |
| E003 | S-1002 | fila | 2026-07-31T23:58:00+09:00 | landing | desktop | false | en-US |
| E004 | S-1003 | — | 2026-07-25T14:03:00+09:00 | pdp | mobile | — | ko-KR |
| E005 | S-1004 | nonfiction | 2026-07-19T09:41:00+09:00 | landing | unknown | true | ja-JP |
아래 JSON Schema에 맞는 스토어프론트 세션 이벤트 행을 60건 더 만들어 주세요. {"type":"object","properties":{"event_id":{"type":"string"},"session_id":{"type":"string"},"brand_id":{"type":["string","null"]},"occurred_at":{"type":"string"},"step":{"type":"string","enum":["landing","pdp","cart","checkout","purchase"]},"device":{"type":"string","enum":["mobile","desktop","tablet","unknown"]},"is_first_visit":{"type":["boolean","null"]},"locale":{"type":"string"}},"required":["event_id","session_id","occurred_at","step","device"]} 쉬운 데이터만 만들지 말 것. 다음 하드 케이스를 의도적으로 섞어라. 첫째 brand_id 가 null 인 미등록 브랜드 행, 둘째 is_first_visit 가 null 인 쿠키 없는 세션, 셋째 device 가 unknown 인 행, 넷째 landing 에서 곧장 checkout 으로 뛰는 것처럼 단계를 건너뛴 세션, 다섯째 occurred_at 이 주 경계와 자정 직전 직후에 놓여 기간 해석에 따라 포함 여부가 갈리는 행, 여섯째 locale 이 빈 문자열이거나 처음 보는 값인 행. 한 session_id 에 여러 이벤트가 시간순으로 붙게 만들어 주세요.{"type":"object","properties":{"event_id":{"type":"string"},"session_id":{"type":"string"},"brand_id":{"type":["string","null"]},"occurred_at":{"type":"string"},"step":{"type":"string","enum":["landing","pdp","cart","checkout","purchase"]},"device":{"type":"string","enum":["mobile","desktop","tablet","unknown"]},"is_first_visit":{"type":["boolean","null"]},"locale":{"type":"string"}},"required":["event_id","session_id","occurred_at","step","device"]}| TypeScript | 조건 카드와 질의 빌더가 같은 타입을 공유하도록 조건 스키마를 한 곳에 두고 화면과 실행 양쪽에서 씁니다. |
| React | 조건 카드와 미확정 칩과 결과 표를 상태로 묶어 사람이 값을 고칠 때마다 대상 규모가 다시 계산되게 만듭니다. |
| Next.js | 운영 담당이 여는 세그먼트 화면과 문장을 조건 초안으로 바꾸는 서버 라우트를 한 앱에 담습니다. |
| Tailwind | 확정된 조건과 미확정 칩과 해석하지 못한 구절을 색과 여백만으로 나눠 어디를 손봐야 하는지 바로 보이게 합니다. |
| JavaScript | 조건을 고칠 때 결과 표와 단계별 잔존 막대가 다시 그려지는 동작을 처리합니다. |
| GraphQL | 확정된 조건을 이벤트 스키마의 질의로 조립해 실행하고, 화면에 그 질의문을 그대로 펼쳐 보여 무엇을 물었는지 확인하게 합니다. |
| Claude | 요청 문장을 조건 초안으로 바꾸고, 두 가지로 읽히는 구절은 값을 정하지 않고 후보만 달아 미확정으로 남깁니다. |
✓ pass → 여기서 멈춰도 운영 담당이 혼자 쓰는 도구로 완결됩니다. 더 키우려면 2주차에서 사람이 고른 매핑을 사전에 쌓아 같은 표현을 자동 확정합니다.
✓ pass → 변환이 안정되면 3주차에서 세그먼트 비교 화면과 실험 대상 내보내기로 넓힙니다.
요청 문장 한 건을 옮긴 조건 초안입니다. 조건마다 근거 구절과 확정 여부를 담고, 미확정이 남아 있으면 질의를 조립하지 않아 실행이 잠깁니다.
{"type":"object","properties":{"req_id":{"type":"string"},"conditions":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","enum":["period","brand","step","device","behavior","first_visit","unknown"]},"op":{"type":"string","enum":["eq","in","between","not"]},"value":{"type":"string"},"source_span":{"type":"string"},"status":{"type":"string","enum":["confirmed","needs_choice","unmapped"]},"choices":{"type":"array","items":{"type":"string"}}},"required":["field","op","value","source_span","status"]},"minItems":1},"blocking_count":{"type":"integer"},"query_preview":{"type":["string","null"]},"hedge":{"type":["string","null"]}},"required":["req_id","conditions","blocking_count"]}[
{
"req_id": "R001",
"conditions": [
{
"field": "period",
"op": "between",
"value": "",
"source_span": "지난주",
"status": "needs_choice",
"choices": [
"2026-07-20..2026-07-26 (월요일부터 일요일까지)",
"2026-07-25..2026-07-31 (오늘 기준 최근 7일)"
]
},
{
"field": "brand",
"op": "eq",
"value": "salomon",
"source_span": "Salomon",
"status": "confirmed",
"choices": []
},
{
"field": "device",
"op": "eq",
"value": "mobile",
"source_span": "모바일에서",
"status": "confirmed",
"choices": []
},
{
"field": "step",
"op": "eq",
"value": "cart",
"source_span": "장바구니까지 왔다가",
"status": "confirmed",
"choices": []
},
{
"field": "behavior",
"op": "not",
"value": "purchase",
"source_span": "결제로 안 간",
"status": "confirmed",
"choices": []
},
{
"field": "first_visit",
"op": "eq",
"value": "true",
"source_span": "첫 방문자",
"status": "confirmed",
"choices": []
}
],
"blocking_count": 1,
"query_preview": null,
"hedge": "기간 표현이 두 가지로 읽혀 사람이 고르기 전까지 실행을 잠급니다. 값과 정답은 합성 기준입니다."
},
{
"req_id": "R010",
"conditions": [
{
"field": "brand",
"op": "eq",
"value": "fila",
"source_span": "휠라",
"status": "confirmed",
"choices": []
},
{
"field": "period",
"op": "between",
"value": "2026-07-20..2026-07-26",
"source_span": "7월 20일부터 7월 26일까지",
"status": "confirmed",
"choices": []
},
{
"field": "step",
"op": "eq",
"value": "cart",
"source_span": "카트 담고",
"status": "confirmed",
"choices": []
},
{
"field": "behavior",
"op": "not",
"value": "purchase",
"source_span": "안 산",
"status": "confirmed",
"choices": []
}
],
"blocking_count": 0,
"query_preview": "query { sessions(brand: [\"fila\"], from: \"2026-07-20\", to: \"2026-07-26\", reachedStep: CART, notReachedStep: PURCHASE) { sessionId lastStep device firstVisit } }",
"hedge": "결과 수는 합성 이벤트 기준이라 실제 트래픽과 다릅니다."
},
{
"req_id": "R004",
"conditions": [
{
"field": "unknown",
"op": "eq",
"value": "",
"source_span": "요즘",
"status": "unmapped",
"choices": [
"최근 7일",
"최근 30일",
"직접 날짜 지정"
]
},
{
"field": "unknown",
"op": "eq",
"value": "",
"source_span": "안 팔리지",
"status": "unmapped",
"choices": [
"결제까지 가지 않은 세션",
"장바구니에서 멈춘 세션"
]
}
],
"blocking_count": 2,
"query_preview": null,
"hedge": "조건으로 옮길 구절이 없어 해석하지 못한 구절만 남기고 실행하지 않습니다. 합성 기준입니다."
}
]field 와 op 와 status 의 허용 값, conditions 최소 1건은 스키마로 자동 검증합니다. source_span 이 요청 문장의 실제 부분인지, blocking_count 가 confirmed 가 아닌 조건 수와 같은지, blocking_count 가 0 보다 크면 query_preview 가 비어 있는지는 규칙 검사기가 확인합니다. 확정된 조건이 정답 조건과 필드와 연산자와 값까지 일치하는지도 규칙으로 채점해 사람 판단 없이 점수가 나옵니다.