오픈서베이
경력근거: 설문 설계부터 응답·수집·정제·검증·분석·보고서까지
오픈서베이 Dataspace 는 설문 설계부터 응답·수집·정제·검증·분석·보고서까지를 한 환경에서 자동화하는 플랫폼이라, 첫 칸인 설문 설계에서 새는 문항 결함이 뒤의 수집과 분석과 보고서를 그대로 오염시킵니다. 뒤쪽에서 나쁜 응답을 걸러내는 도구 대신 결함이 설계 단계를 넘어가지 못하게 막는 화면을 골랐습니다. 공고가 사용자인 리서처와 기획자와 분석가의 문제를 직접 정의하고 구현과 배포까지 이어갈 사람을 찾는다고 적었기 때문에, 기능 목록의 나열보다 화면과 API 와 저장과 배포를 혼자 끝낸 작은 제품 하나가 증거가 됩니다. 코딩과 반복 업무는 에이전트에 맡기고 사람은 결과를 검증한다는 일하는 방식은, 판정은 규칙이 하고 LLM 은 수정 문구만 제안하며 채택은 사람이 화면에서 결정하는 구조로 제품 안에 옮겼습니다. 이 포트폴리오가 보여주는 것은 화면과 API 와 상태 관리를 혼자 끝내는 웹 풀스택 기술과 결정론적 규칙 검사 설계이며, 시장조사 방법론과 합성 패널 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
설문 설계부터 보고서까지를 한 환경에서 자동화하는 플랫폼이라 설계 화면이 뒤의 모든 단계의 입력을 결정합니다. 그래서 그 첫 칸 하나를 편집과 검사와 내보내기까지 닫는 것이 가장 직접적인 증거가 됩니다.
반복 작업은 에이전트에 맡기고 사람은 무엇을 만들지 정하고 결과를 검증한다는 방식이라, 결함 판정은 규칙이 하고 LLM 은 수정 문구만 제안하며 채택은 사람이 화면에서 결정하도록 역할을 나눴습니다.
분업과 핸드오프를 줄이고 리서처의 문제를 직접 정의해 구현과 배포까지 잇는 자리라, 잘게 쪼갠 기능 목록 대신 화면과 API 와 저장과 배포를 혼자 끝낸 작은 제품 하나로 그 역량을 보입니다.
리서처가 문서에 써 둔 설문 초안을 그대로 붙여넣으면 문항 카드로 쪼개지고, 파서가 유형을 정하지 못한 문항과 유도질문·이중질문·보기 겹침·보기 누락·척도 라벨 비대칭 같은 결함이 카드마다 표시되는 설문 편집 화면입니다. 유형 미정 문항은 사람이 화면에서 유형을 골라야 카드가 완성되고, 차단 등급 결함은 제안 문구를 채택하거나 직접 고치거나 사유를 적어 닫아야 사라집니다. 남은 것이 하나라도 있으면 내보내기 버튼이 잠겨 있고, 모두 닫혔을 때에만 배포용 설문 정의 파일이 나옵니다.
설문지 초안을 문서에 써 두고 동료 검토 의견을 받아 손으로 반영하다가, 유도질문이나 보기 겹침을 배포 직전에 발견해 문항 번호와 분기를 다시 맞추던 리서처입니다. 초안을 붙여넣기만 하면 고쳐야 할 곳이 문항마다 표시되고 그것을 다 닫기 전에는 내보내지지 않는 화면을 쓰고 싶은 사람입니다.
초안을 문항 카드로 쪼개고 결함을 차단 등급으로 표시한 뒤 사람이 닫아야만 내보내기가 열리게 하면, 배포 이후에나 드러나던 문항 결함이 설계 단계에서 걸린다는 가정입니다.
설문 초안을 붙여넣으면 문항 카드로 쪼개지고, 유형 미정 문항과 차단 등급 결함이 카드마다 표시되며, 사람이 유형을 고르고 결함을 채택이나 직접 수정이나 사유 기록으로 닫아야 내보내기 잠금이 풀려 배포용 설문 정의 파일이 나오는 화면이 배포까지 끝난 완결품입니다. 만드는 덩어리는 문항 파서와 유형 지정 화면, 결함 검사와 내보내기 관문 둘이며 평일 5일에 혼자 끝나는 범위입니다.
문항 카드를 끌어 분기 조건을 연결하면 도달할 수 없는 문항과 되돌아 도는 순환을 그래프 검사가 잡아 차단 결함으로 올리는 기능입니다. 이 주차부터 서비스를 AWS 에 올려 실제 주소로 운영합니다.
확정한 설문에 더미 응답자를 분기 규칙대로 흘려 문항별 도달률과 응답자가 어느 보기에도 걸리지 않는 지점을 보여주는 사전 점검 화면입니다.
결함 12종을 심어 둔 설문 초안 30문항을 붙여넣으면 유형 미정 문항과 차단 결함이 카드마다 표시되고 내보내기 버튼이 잠긴 상태에서 시작해, 제안을 채택하거나 직접 고치거나 사유를 적어 모두 닫으면 잠금이 풀리고 배포용 정의 파일이 나오는 흐름을 처음부터 끝까지 시연합니다.
같은 초안을 열 번 넣어도 결함 목록과 차단 여부가 매번 똑같이 나오는 것을 보입니다. 판정은 규칙이 하고 LLM 은 수정 문구 제안만 맡기 때문입니다.
제안 문구를 채택해도 원문의 평가 대상 단어가 그대로 남아 있는지 규칙이 다시 검사하고, 어긋나면 채택이 막히는 것을 보입니다.
2주차에서 도달 불가 문항이나 순환을 심어 둔 분기 설계 20건 중 몇 건을 그래프 검사가 잡아내는지 작성자가 만든 정답과 대조합니다. 다만 정답과 데이터를 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
위 수치는 더미데이터 자가채점이며, 이 검사가 리서처의 재작업을 실제로 줄이는지는 오픈서베이의 실제 설문 초안과 리서처의 실사용이 있어야 측정 가능합니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아닙니다. 면접에서는 데모가 도는 상태와 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 만들었으니 잘 맞는 것이 당연합니다. 유도 표현이 섞인 문항과 이중질문과 구간이 겹치는 보기와 빠진 구간과 대상이 없는 분기 지시와 거의 같은 문구의 중복 문항을 초안 더미에 일부러 섞어 두었습니다.
좋은 문항의 기준은 조사 목적마다 달라서 규칙을 제품에 못 박으면 리서처의 의도를 막습니다. 규칙 목록을 설정으로 외부화하고, 애매한 유형은 차단이 아니라 경고로 두며, 차단 결함도 사유를 적으면 닫히게 하고 그 사유를 이력에 남깁니다.
이 포트폴리오가 보여주는 것은 편집 화면과 규칙 검사와 내보내기 관문을 혼자 끝내는 웹 풀스택 기술이며, 설문 방법론과 합성 패널 같은 리서치 도메인 전문성은 주장하지 않습니다. 검사 규칙은 공개된 설문 작성 통념을 옮긴 수준이라 실제 도입에서는 리서처의 기준으로 다시 맞춰야 하고, 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
리서처가 문서에 써 둔 설문 초안을 붙여넣은 상태를 흉내 낸 더미입니다. 파서가 유형을 정하지 못하는 문항과 규칙 검사가 잡아야 할 결함 문항을 일부러 섞어 두었습니다.
| item_id | raw_text | parsed_type | options | branch_note | source_note |
|---|---|---|---|---|---|
| i_01 | 1. 최근 3개월 안에 이 서비스를 사용한 적이 있으신가요? | single | ["있다","없다"] | 없다를 고르면 12번으로 | — |
| i_02 | 2. 가격과 배송 속도는 만족스러우셨나요? | scale | ["매우 불만","불만","보통","만족","매우 만족"] | — | 한 문항이 가격과 배송 속도 두 가지를 함께 묻습니다 |
| i_03 | 3. 훌륭하다는 평가를 받는 이번 신제품에 얼마나 만족하시나요? | scale | ["매우 불만","보통","만족","매우 만족"] | — | 유도 표현과 척도 라벨 비대칭이 함께 있습니다 |
| i_04 | 4. 연령대를 골라 주세요. | single | ["20~29세","25~34세","35~49세","50~59세"] | — | 20대 후반 구간이 겹치고 60세 이상 구간이 없습니다 |
| i_05 | 5. 이 서비스를 알게 된 경로를 모두 골라 주세요. | multi | ["지인 추천","온라인 광고","검색","해당 없음"] | — | 해당 없음과 다른 보기를 동시에 고를 수 있습니다 |
아래 Zod 스키마에 맞는 설문 초안 문항 60행을 JSON 배열로 생성해 주세요.
{"type":"object","properties":{"item_id":{"type":"string"},"raw_text":{"type":"string"},"parsed_type":{"type":"string","enum":["single","multi","scale","open","unknown"]},"options":{"type":"array","items":{"type":"string"}},"branch_note":{"type":["string","null"]},"source_note":{"type":["string","null"]}},"required":["item_id","raw_text","parsed_type","options","branch_note","source_note"]}
쉬운 문항만 만들지 마세요. 하드 케이스를 의도적으로 섞습니다. (1) 한 문항이 두 대상을 함께 묻는 이중질문 3건, (2) 훌륭한·인기 있는 같은 유도 표현이 들어간 문항 3건, (3) 연령이나 금액 보기 구간이 서로 겹치는 문항 2건, (4) 구간이 빠져 어느 보기에도 해당하지 않는 응답자가 생기는 문항 2건, (5) 척도 라벨이 부정과 긍정 개수로 비대칭인 문항 2건, (6) 해당 없음과 다른 보기를 함께 고를 수 있는 복수선택 1건, (7) 빈 문자열 보기 1건, (8) branch_note 가 존재하지 않는 문항 번호를 가리키는 경우 2건, (9) parsed_type 이 unknown 인 문항 3건, (10) 거의 같은 문구의 중복 문항 2건. JSON 배열만 출력합니다.{"type":"object","properties":{"item_id":{"type":"string"},"raw_text":{"type":"string"},"parsed_type":{"type":"string","enum":["single","multi","scale","open","unknown"]},"options":{"type":"array","items":{"type":"string"}},"branch_note":{"type":["string","null"]},"source_note":{"type":["string","null"]}},"required":["item_id","raw_text","parsed_type","options","branch_note","source_note"]}확정한 설문에 흘려 문항별 도달률을 미리 보기 위한 더미 응답자입니다. 보기 구간이 빠진 문항에서 어느 보기에도 걸리지 않는 사람과 분기 때문에 일찍 끝나는 사람을 섞어 두었습니다.
| respondent_id | age | gender | usage | answers |
|---|---|---|---|---|
| p_01 | 31 | 여성 | 사용중 | {"i_01":"있다","i_04":"25~34세","i_08":"예"} |
| p_02 | 27 | 남성 | 사용중 | {"i_01":"있다","i_04":"20~29세","i_08":"예"} |
| p_03 | 62 | 여성 | 사용경험있음 | {"i_01":"있다","i_04":null,"i_08":"아니오"} |
| p_04 | 45 | 남성 | 사용경험없음 | {"i_01":"없다"} |
| p_05 | 23 | 무응답 | 사용중 | {"i_01":"있다","i_04":"20~29세","i_08":"아니오"} |
아래 Zod 스키마에 맞는 더미 응답자 120행을 JSON 배열로 생성해 주세요.
{"type":"object","properties":{"respondent_id":{"type":"string"},"age":{"type":"number"},"gender":{"type":"string","enum":["여성","남성","무응답"]},"usage":{"type":"string","enum":["사용중","사용경험있음","사용경험없음"]},"answers":{"type":"object","additionalProperties":{"type":["string","null"]}}},"required":["respondent_id","age","gender","usage","answers"]}
하드 케이스를 의도적으로 섞습니다. (1) 연령이 60세 이상이라 연령 보기 어디에도 해당하지 않아 answers 의 해당 문항이 null 인 사람 12명, (2) 20대 후반이라 겹치는 두 보기 모두에 해당하는 사람 10명, (3) 1번에서 없다를 골라 뒤 문항을 건너뛰고 answers 가 한 칸만 있는 사람 20명, (4) 중간 문항을 비워 null 로 둔 사람 8명, (5) gender 가 무응답인 사람 10명. 나머지는 정상 응답으로 채웁니다. JSON 배열만 출력합니다.{"type":"object","properties":{"respondent_id":{"type":"string"},"age":{"type":"number"},"gender":{"type":"string","enum":["여성","남성","무응답"]},"usage":{"type":"string","enum":["사용중","사용경험있음","사용경험없음"]},"answers":{"type":"object","additionalProperties":{"type":["string","null"]}}},"required":["respondent_id","age","gender","usage","answers"]}| React | 문항 카드와 결함 배지와 수정 제안 채택과 잠긴 내보내기 버튼까지 편집 화면 전체를 만듭니다. |
| TypeScript | 문항과 결함과 처리 상태의 타입을 화면과 API 가 함께 쓰고 Zod 로 런타임 검증까지 겁니다. |
| Python (FastAPI) | 초안 파서와 결함 규칙 검사기와 내보내기 관문을 API 로 구현합니다. |
| MySQL | 설문 초안과 문항별 결함 처리 이력을 저장해 누가 무엇을 어떤 사유로 닫았는지 남깁니다. |
| AWS | 2주차부터 서비스를 AWS 에 올려 실제 주소로 운영하고 3주차 사전 점검까지 같은 환경에서 돌립니다. |
| Anthropic Claude | 결함 문항의 수정 문구와 보기 라벨 정리를 제안하며 결함 판정과 차단 여부에는 관여하지 않습니다. |
| Claude Code | 규칙 추가와 화면 작업을 에이전트에 맡기고 그 결과는 같은 초안을 반복 투입하는 규칙 재현 테스트로 검증하는 작업 방식을 저장소에 남깁니다. |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우려면 2주차에서 분기 연결과 도달성 검사를 붙입니다.
✓ pass → 여기까지도 완결입니다. 더 키우려면 3주차에서 더미 응답자를 흘려 문항별 도달률을 미리 보는 화면을 붙입니다.
문항별 결함 판정과 사람이 화면에서 그것을 어떻게 닫았는지를 함께 담습니다. 내보내기 잠금 여부가 이 값들로 결정됩니다.
{"type":"object","properties":{"item_id":{"type":"string"},"issue_code":{"type":"string","enum":["leading","double_barreled","option_overlap","option_gap","scale_asymmetry","option_empty","branch_target_missing","duplicate_item","type_unresolved","none"]},"severity":{"type":"string","enum":["block","warn","none"]},"rule_evidence":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"quote":{"type":"string"}},"required":["field","quote"]},"minItems":1},"suggested_fix":{"type":["string","null"]},"resolution":{"type":"string","enum":["adopted","edited","waived","open"]},"waiver_reason":{"type":["string","null"]},"blocks_export":{"type":"boolean"}},"required":["item_id","issue_code","severity","rule_evidence","suggested_fix","resolution","waiver_reason","blocks_export"]}[
{
"item_id": "i_02",
"issue_code": "double_barreled",
"severity": "block",
"rule_evidence": [
{
"field": "raw_text",
"quote": "가격과 배송 속도는 만족스러우셨나요?"
}
],
"suggested_fix": "가격은 만족스러우셨나요? 와 배송 속도는 만족스러우셨나요? 두 문항으로 나눕니다.",
"resolution": "adopted",
"waiver_reason": null,
"blocks_export": true
},
{
"item_id": "i_04",
"issue_code": "option_overlap",
"severity": "block",
"rule_evidence": [
{
"field": "options",
"quote": "20~29세"
},
{
"field": "options",
"quote": "25~34세"
}
],
"suggested_fix": "20~29세와 30~34세로 경계를 나누고 60세 이상 보기를 더합니다.",
"resolution": "edited",
"waiver_reason": null,
"blocks_export": true
},
{
"item_id": "i_09",
"issue_code": "type_unresolved",
"severity": "block",
"rule_evidence": [
{
"field": "parsed_type",
"quote": "unknown"
}
],
"suggested_fix": null,
"resolution": "open",
"waiver_reason": null,
"blocks_export": true
},
{
"item_id": "i_05",
"issue_code": "option_overlap",
"severity": "warn",
"rule_evidence": [
{
"field": "options",
"quote": "해당 없음"
}
],
"suggested_fix": "해당 없음을 고르면 다른 보기가 꺼지도록 배타 설정을 겁니다.",
"resolution": "waived",
"waiver_reason": "이번 조사에서는 복수 응답을 그대로 받기로 리서처가 정했습니다.",
"blocks_export": false
}
]자동으로 거는 규칙입니다. (1) Zod parse 통과, (2) rule_evidence[].quote 가 입력 문항의 raw_text 나 options 안에 글자 그대로 있는지, (3) blocks_export 가 true 인 항목이 하나라도 resolution 이 open 이면 내보내기 잠금이 유지되는지, (4) resolution 이 waived 인데 waiver_reason 이 비어 있지 않은지, (5) option_overlap 과 option_gap 은 보기 구간의 교집합과 여집합 계산으로 같은 결과가 재현되는지. LLM 이 만든 suggested_fix 는 판정에 쓰지 않고, 원문의 평가 대상 단어가 유지됐는지만 규칙으로 검사한 뒤 화면에 올립니다.