파이인스티튜트오브디자인
경력근거: 학습자가 수업과 관련된 모든 것을 한 곳에서 확인하는 시스템을 만듭니다
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고가 인터널 학습 제품을 두고 '학습자가 수업과 관련된 모든 것을 한 곳에서 확인하는 시스템을 만듭니다' 라고 적었고, 앞에서는 '커리큘럼, 운영 구조, 학습자가 경험하는 모든 것이 처음 설계되는 중' 이라고 밝혔습니다. 처음 짜는 시간표는 겹침과 정원이 개강 직전에 드러나고, 이 포트폴리오는 그 확인을 커리큘럼 규칙표로 옮깁니다. '프로덕트 오너, 프로덕트 디자이너, 교육 설계팀(LD)과 긴밀히 협업합니다' 라 규칙을 표로 두면 그 협업이 데이터로 남습니다. 이 포트폴리오가 보여주는 것은 커리큘럼 규칙을 데이터로 두고 신청과 맞춰 확정 여부를 가르는 기술이며, 교육 과정 설계나 디자인 교수법 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
'학습자가 수업과 관련된 모든 것을 한 곳에서 확인하는 시스템을 만듭니다'. 그 한 곳이 서려면 일정이 먼저 맞아야 합니다.
'커리큘럼, 운영 구조, 학습자가 경험하는 모든 것이 처음 설계되는 중'. 규칙이 아직 데이터가 아니라 사람 머릿속에 있습니다.
'프로덕트 오너, 프로덕트 디자이너, 교육 설계팀(LD)과 긴밀히 협업합니다'. 규칙을 표로 두면 그 협업이 문서가 아니라 데이터로 남습니다.
들어온 수강 신청을 그대로 확정해도 되는지 신청마다 가려 화면에 사유별로 묶어 보여줍니다. 과목별 커리큘럼 규칙에 선수 과목과 강의실 정원, 수업 사이 최소 간격을 두고 신청과 회차 시각을 맞춰, 다 맞으면 확정으로 넘기고 그렇지 않으면 시간 겹침·정원 초과·선수 과목 미이수 중 어느 쪽인지 사유로 남깁니다. 회차 시각이 아직 안 정해진 신청은 겹치는지 볼 수 없다고 표시하고, 규칙에 없는 과목은 미선언으로 남겨 정원과 선수 과목을 먼저 정하게 합니다. 신청 기록은 실 학사 자료 대신 지원자가 공개 학사 일정 양식으로 만든 것을 가정합니다.
첫 기수를 준비하는 교육 기관의 학습 운영 담당자입니다. 터미널을 쓰지 않고 하루에도 몇 번씩 신청 현황을 열어 보는 사람이라, 교육 설계팀이 그린 시간표와 들어온 신청을 눈으로 맞춰 보다가 개강 직전에 겹침을 발견하곤 했습니다.
과목마다 선수 과목과 정원, 수업 사이 최소 간격을 규칙으로 두고 신청과 회차 시각을 맞추면, 확정할 신청과 되물을 신청이 갈리고 되묻는 이유가 근거로 남는다는 가정입니다. 규칙에 없는 과목은 미선언으로 빠지므로 아직 정하지 않은 과목이 그대로 드러납니다.
신청 기록과 커리큘럼 규칙을 넣으면 신청마다 확정·보류를 판정하고, 보류면 시간 겹침·정원 초과·선수 과목 미이수·회차 미정·미선언 중 어느 쪽인지 붙여 사유별로 묶어 보여주는 화면이 도는 완결품입니다. 카드를 펼치면 그 판단의 근거 값이 나옵니다.
공개 양식으로 만든 신청 600건에 손으로 붙인 정답 판정과 대조해 일치율을 내고, 미선언이 몰리는 과목을 모아 규칙이 없는 자리를 목록으로 냅니다.
겹치거나 자리가 찬 신청에 같은 과목의 다른 회차를 후보로 붙여 내고, 대안이 없는 신청을 학습 운영에 넘기는 목록으로 갈라 내는 단계입니다.
학습 운영 담당자가 신청 기록과 규칙표를 넣으면 신청마다 확정 여부와 보류 사유가 사유별로 묶여 화면에 뜨는 과정을 시연합니다.
공개 양식으로 만든 신청 600건과 손으로 붙인 정답 판정을 대조해 일치율을 냅니다. 단, 정답과 신청 기록을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
회차 시각이 비었거나 과목 표기가 흔들리거나 규칙에 없는 과목이 섞인 입력 30종을 넣어도 화면이 안 깨지고 사유별로 빠지는 비율을 보여줍니다.
정원과 최소 간격을 바꿨을 때 옛 판정이 어떻게 뒤집히는지 회귀로 확인합니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 작성자가 만든 신청 기록의 자가채점이며, 실제 확정 정확도는 첫 기수의 실 커리큘럼과 실 신청이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아니므로, 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
정답을 작성자가 붙였으니 잘 맞는 게 당연하므로, 회차 미정과 정원 초과, 규칙에 없는 과목을 일부러 섞어 쉬운 신청만 푸는 함정을 피합니다.
이 포트폴리오가 보여주는 것은 커리큘럼 규칙을 데이터로 두고 신청과 맞춰 확정 여부를 가르는 기술이며, 교육 과정 설계나 디자인 교수법 전문성은 주장하지 않습니다. 판정은 시각 겹침과 정원 비교가 하고 LLM 은 담당자가 읽을 사유 문장만 맡습니다.
선수 과목을 들었는지는 신청 기록으로만 보므로, 다른 경로로 익힌 학습자는 사람이 예외를 두게 남깁니다.
실제 도입 때는 커리큘럼이 기수마다 바뀌므로, 규칙표를 교육 설계팀과 함께 고치는 일을 운영 과제로 둡니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
학습자가 넣은 수강 신청과 그 회차 정보를 한 줄로 편 것입니다. 신청 번호와 학습자, 과목 이름, 회차 번호, 시작·끝 시각, 강의실, 지금까지 찬 자리 수, 신청한 날을 한 행에 둡니다. 같은 학습자가 같은 날 두 수업을 넣어 시각이 겹치는 행, 정원이 다 찬 행, 회차 시각이 아직 안 정해진 행, 찬 자리 수가 빈 행, 규칙표에 없는 과목을 일부러 섞어 두어 사유가 갈리게 둡니다.
| enroll_no | learner_no | course_raw | session_no | starts_at | ends_at | room_raw | seat_taken | applied_at |
|---|---|---|---|---|---|---|---|---|
| EN-001 | L-101 | 타이포그래피 기초 | S-11 | 2026-09-07T10:00:00 | 2026-09-07T13:00:00 | A홀 | 18 | 2026-08-20 |
| EN-002 | L-101 | 인터랙션 설계 | S-21 | 2026-09-07T12:00:00 | 2026-09-07T15:00:00 | B실 | 12 | 2026-08-20 |
| EN-003 | L-102 | 타이포그래피 기초 | S-11 | 2026-09-07T10:00:00 | 2026-09-07T13:00:00 | A홀 | 24 | 2026-08-21 |
| EN-004 | L-102 | 인터랙션 심화 | S-31 | 2026-09-08T10:00:00 | 2026-09-08T13:00:00 | B실 | 9 | 2026-08-21 |
| EN-005 | L-103 | 타이포그래피 기초 | S-12 | 2026-09-14T10:00:00 | 2026-09-14T13:00:00 | A홀 | 20 | 2026-08-21 |
아래 JSON Schema 를 그대로 만족하는 수강 신청 행을 600개 더 만들어 주세요. 학습자를 백 명 두고 과목을 예닐곱 종, 과목마다 회차를 두셋 둡니다. 한 학습자가 같은 날 두 수업을 넣어 시각이 겹치거나 십 분 만에 이어지는 경우를 몇 쌍 만들고, 2할은 회차 시각이나 찬 자리 수를 비우며, 몇 행은 찬 자리 수를 정원과 같게 두세요. 규칙표에 없는 과목도 몇 행 넣습니다. 판정 결과는 넣지 마세요.
{"type": "object", "properties": {"enroll_no": {"type": "string"}, "learner_no": {"type": "string"}, "course_raw": {"type": "string"}, "session_no": {"type": "string"}, "starts_at": {"type": ["string", "null"]}, "ends_at": {"type": ["string", "null"]}, "room_raw": {"type": ["string", "null"]}, "seat_taken": {"type": ["integer", "null"]}, "applied_at": {"type": "string"}}, "required": ["enroll_no", "learner_no", "course_raw", "session_no", "starts_at", "ends_at", "room_raw", "seat_taken", "applied_at"]}{"type": "object", "properties": {"enroll_no": {"type": "string"}, "learner_no": {"type": "string"}, "course_raw": {"type": "string"}, "session_no": {"type": "string"}, "starts_at": {"type": ["string", "null"]}, "ends_at": {"type": ["string", "null"]}, "room_raw": {"type": ["string", "null"]}, "seat_taken": {"type": ["integer", "null"]}, "applied_at": {"type": "string"}}, "required": ["enroll_no", "learner_no", "course_raw", "session_no", "starts_at", "ends_at", "room_raw", "seat_taken", "applied_at"]}과목별 커리큘럼 규칙표입니다. 규칙 번호와 과목, 선수 과목, 강의실 정원, 수업 사이 최소 간격, 담당을 한 행에 둡니다. 과목마다 정원과 선수 과목이 달라, 같은 학습자라도 어느 과목을 넣느냐로 결과가 갈립니다. 신청에 나오는 과목 중 일부는 일부러 넣지 않아 미선언이 도출되게 둡니다.
| rule_no | course_raw | prereq_raw | room_capacity | min_gap_min | owner_name |
|---|---|---|---|---|---|
| CR-01 | 타이포그래피 기초 | — | 24 | 30 | 학습설계 |
| CR-02 | 인터랙션 설계 | — | 16 | 30 | 학습설계 |
| CR-03 | 인터랙션 심화 | 인터랙션 설계 | 12 | 30 | 학습설계 |
| CR-04 | 브랜딩 워크숍 | 타이포그래피 기초 | 18 | 30 | 학습설계 |
| CR-05 | 리서치 방법 | — | 20 | 30 | 학습설계 |
아래 JSON Schema 를 그대로 만족하는 커리큘럼 규칙 행을 20개 더 만들어 주세요. 기초 과목은 선수 과목을 비우고 심화 과목에는 앞 과목을 적습니다. 정원은 12 에서 24 사이로, 수업 사이 최소 간격은 30 분이나 60 분으로 둡니다. 신청에 나오는 과목 중 일부는 일부러 넣지 마세요 — 미선언이 있어야 규칙표의 구멍이 드러납니다. 판정 결과는 넣지 마세요.
{"type": "object", "properties": {"rule_no": {"type": "string"}, "course_raw": {"type": "string"}, "prereq_raw": {"type": ["string", "null"]}, "room_capacity": {"type": "integer"}, "min_gap_min": {"type": "integer"}, "owner_name": {"type": "string"}}, "required": ["rule_no", "course_raw", "prereq_raw", "room_capacity", "min_gap_min", "owner_name"]}{"type": "object", "properties": {"rule_no": {"type": "string"}, "course_raw": {"type": "string"}, "prereq_raw": {"type": ["string", "null"]}, "room_capacity": {"type": "integer"}, "min_gap_min": {"type": "integer"}, "owner_name": {"type": "string"}}, "required": ["rule_no", "course_raw", "prereq_raw", "room_capacity", "min_gap_min", "owner_name"]}| TypeScript | 신청과 커리큘럼 규칙을 맞춰 시각과 정원을 견주는 판정기를 맡습니다. |
| React | 사유별로 묶은 신청 카드와 근거 값을 보여주는 화면을 맡습니다. |
| PostgreSQL | 신청 기록과 회차, 규칙, 판정 결과를 담습니다. |
| Next.js | 학습 운영 담당자가 여는 관리자 페이지를 맡습니다. |
✗ fail → 미선언이 절반을 넘으면 규칙표를 먼저 채웁니다.
✓ pass → 2주차 정답 대조로 넘어갑니다.
✗ fail → 어긋난 과목을 모아 최소 간격과 선수 과목 정의를 다시 봅니다.
✓ pass → 3주차 대안 회차로 넘어갑니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
schedule_code사유 라벨 · enroll_no + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
confirmed확정time_conflict시간 겹침capacity_over정원 초과prereq_missing선수 과목 미이수slot_missing회차 미정course_undeclared과목 미선언신청 하나와 커리큘럼 규칙이 만나는 자리마다 그대로 확정해도 되는지 정합니다. 못 하면 시간 겹침·정원 초과·선수 과목 미이수·회차 미정·미선언 중 어느 쪽인지 싣습니다. 리포트는 이 사유 코드로 묶습니다.
{"type": "object", "properties": {"verdict_no": {"type": "string"}, "enroll_no": {"type": "string"}, "learner_no": {"type": "string"}, "course_raw": {"type": "string"}, "rule_no": {"type": ["string", "null"]}, "schedule_code": {"type": "string", "enum": ["confirmed", "time_conflict", "capacity_over", "prereq_missing", "slot_missing", "course_undeclared"]}, "seats_left": {"type": ["integer", "null"], "description": "그 과목 규칙의 room_capacity 에서 seat_taken 을 뺀 남은 자리 수입니다. 자리 수가 적힌 신청에만 채웁니다."}, "room_capacity": {"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", "enroll_no", "learner_no", "course_raw", "schedule_code", "evidence", "summary"]}[
{
"verdict_no": "SC-001",
"enroll_no": "EN-001",
"learner_no": "L-101",
"course_raw": "타이포그래피 기초",
"rule_no": "CR-01",
"schedule_code": "confirmed",
"seats_left": 6,
"room_capacity": 24,
"owner_name": "학습설계",
"evidence": [
{
"field": "seat_taken",
"agg": null,
"value": 18
},
{
"field": "room_capacity",
"agg": null,
"value": 24
}
],
"summary": "자리도 남고 겹치는 수업도 없어 그대로 확정합니다.",
"hedge": null
},
{
"verdict_no": "SC-002",
"enroll_no": "EN-002",
"learner_no": "L-101",
"course_raw": "인터랙션 설계",
"rule_no": "CR-02",
"schedule_code": "time_conflict",
"seats_left": 4,
"room_capacity": 16,
"owner_name": "학습설계",
"evidence": [
{
"field": "starts_at",
"agg": null,
"value": "2026-09-07T12:00:00"
},
{
"field": "min_gap_min",
"agg": null,
"value": 30
}
],
"summary": "같은 날 앞 수업이 한 시에 끝나는데 열두 시에 시작해 한 시간이 겹칩니다.",
"hedge": null
},
{
"verdict_no": "SC-003",
"enroll_no": "EN-003",
"learner_no": "L-102",
"course_raw": "타이포그래피 기초",
"rule_no": "CR-01",
"schedule_code": "capacity_over",
"seats_left": 0,
"room_capacity": 24,
"owner_name": "학습설계",
"evidence": [
{
"field": "seat_taken",
"agg": null,
"value": 24
},
{
"field": "room_capacity",
"agg": null,
"value": 24
}
],
"summary": "강의실 정원이 다 차 이 신청은 대기로 돌립니다.",
"hedge": null
},
{
"verdict_no": "SC-004",
"enroll_no": "EN-004",
"learner_no": "L-102",
"course_raw": "인터랙션 심화",
"rule_no": "CR-03",
"schedule_code": "prereq_missing",
"seats_left": 3,
"room_capacity": 12,
"owner_name": "학습설계",
"evidence": [
{
"field": "prereq_raw",
"agg": null,
"value": "인터랙션 설계"
},
{
"field": "seat_taken",
"agg": null,
"value": 9
}
],
"summary": "앞 과목을 아직 듣지 않아 이 회차부터 따라가기 어렵습니다.",
"hedge": null
},
{
"verdict_no": "SC-005",
"enroll_no": "EN-006",
"learner_no": "L-103",
"course_raw": "브랜딩 워크숍",
"rule_no": "CR-04",
"schedule_code": "confirmed",
"seats_left": 3,
"room_capacity": 18,
"owner_name": "학습설계",
"evidence": [
{
"field": "starts_at",
"agg": null,
"value": "2026-09-14T14:00:00"
},
{
"field": "min_gap_min",
"agg": null,
"value": 30
}
],
"summary": "앞 수업이 한 시에 끝나고 두 시에 시작해 쉬는 시간이 규칙을 채웁니다.",
"hedge": null
},
{
"verdict_no": "SC-006",
"enroll_no": "EN-010",
"learner_no": "L-105",
"course_raw": "브랜딩 워크숍",
"rule_no": "CR-04",
"schedule_code": "time_conflict",
"seats_left": 4,
"room_capacity": 18,
"owner_name": "학습설계",
"evidence": [
{
"field": "starts_at",
"agg": null,
"value": "2026-09-16T13:10:00"
},
{
"field": "min_gap_min",
"agg": null,
"value": 30
}
],
"summary": "앞 수업이 끝나고 십 분 만에 시작해 이동할 여유가 없습니다.",
"hedge": null
},
{
"verdict_no": "SC-007",
"enroll_no": "EN-008",
"learner_no": "L-104",
"course_raw": "타이포그래피 기초",
"rule_no": "CR-01",
"schedule_code": "slot_missing",
"seats_left": 16,
"room_capacity": 24,
"owner_name": "학습설계",
"evidence": [
{
"field": "starts_at",
"agg": null,
"value": null
},
{
"field": "session_no",
"agg": null,
"value": "S-13"
}
],
"summary": "회차 시각이 아직 안 정해져 겹치는지 볼 수 없습니다.",
"hedge": null
},
{
"verdict_no": "SC-008",
"enroll_no": "EN-013",
"learner_no": "L-105",
"course_raw": "모션 그래픽",
"rule_no": null,
"schedule_code": "course_undeclared",
"seats_left": null,
"room_capacity": null,
"owner_name": null,
"evidence": [
{
"field": "course_raw",
"agg": null,
"value": "모션 그래픽"
},
{
"field": "rule_no",
"agg": "count",
"value": 12
}
],
"summary": "커리큘럼 열두 행에 없는 과목이라 정원과 선수 과목을 정해 두지 않았습니다.",
"hedge": null
}
][자동 검증 · 코드가 판정합니다] 1. schedule_code 가 enum 여섯 값 중 하나인지 확인합니다. 2. verdict_no·enroll_no·learner_no·course_raw·schedule_code·evidence·summary 가 모두 채워졌는지 확인합니다. 3. enroll_no 가 신청 기록에 실재하는 번호인지 대조합니다. 4. rule_no 가 있으면 규칙표에 실재하는 행 번호인지 대조합니다. 5. rule_no 가 있으면 room_capacity·owner_name 이 그 규칙 행의 값과 같은지 대조합니다. 6. course_raw 를 띄어쓰기를 접어 규칙표와 맞추고, 맞는 행이 없으면 schedule_code 가 course_undeclared 인지 확인합니다. 7. seats_left 를 room_capacity 에서 seat_taken 을 빼 다시 계산합니다. 8. starts_at 이나 ends_at 이 비어 있으면 schedule_code 가 slot_missing 인지 확인합니다. 9. seat_taken 이 room_capacity 이상이면 schedule_code 가 capacity_over 인지 다시 계산합니다. 10. 같은 learner_no 의 앞서 확정된 신청과 시각이 겹치거나 사이 간격이 min_gap_min 에 못 미치면 schedule_code 가 time_conflict 인지 다시 계산합니다. 11. prereq_raw 가 있는데 같은 학습자의 그 과목 신청이 없으면 schedule_code 가 prereq_missing 인지 확인합니다. 12. schedule_code 가 confirmed 이면 위 검사를 모두 통과하는지 다시 확인합니다. 13. evidence 의 field 이름이 신청 기록과 규칙표에 실재하는 컬럼인지 대조합니다. 14. agg 가 없는 evidence 의 value 가 그 컬럼에 수록된 행 값과 같은지 확인합니다. 15. summary 가 존댓말로 끝나는지 확인합니다. [평가 러너 · 2주차] 공개 양식으로 만든 신청 600건에 손으로 붙인 정답 판정과 대조해 일치율과 사유 코드별 분포를 내고, 미선언이 몰리는 과목을 목록으로 냅니다. [수동 검증 · 사람이 봅니다] 1. 규칙에 없는 과목의 정원과 선수 과목을 교육 설계팀이 정합니다. 2. 선수 과목을 다른 경로로 익힌 학습자에게 예외를 둘지 학습 운영이 정합니다.