화면과 개발이 함께 지키는 시각 기준

디자인 가이드

학교를 오가며 쓰는 업무라는 조건에서 색상·글꼴·그리드·반응형·컴포넌트 원칙을 정한 독립 문서입니다.

15,329자 · 시스템이 만든 그대로입니다

사람이 손댄 곳 3군데
  • · 3단계 ‘추론 확인’에서 두 곳을 고쳤습니다. 인터뷰에 서류 만료 알림을 첫 버전에 넣겠다고 적었는데, 정작 서류 관리 자체는 후속 버전이었습니다. 그대로 두면 없는 데이터를 읽어 알림을 보내는 문서가 되므로, 첫 버전 알림을 시간표 변경 하나로 줄이고 필수 화면 목록에 알림함을 넣었습니다.
  • · 4단계에서 확인할 사용 흐름 세 가지를 다시 묶었습니다. 처음 제안된 묶음은 화면 열한 개를 순서대로 셋으로 나눈 것이라 운영자 화면과 강사 화면이 한 흐름에 섞여 있었습니다. 흐름은 “이 순서로 막힘없이 이어지는가”를 보는 자리이므로 역할별로 다시 나누고 이름도 업체가 실제로 하는 일로 바꿨습니다.
  • · 문서 본문은 손대지 않았습니다. 위 두 가지는 모두 인터뷰 답변과 화면 목록을 고친 것이고, 그 뒤 문서는 고쳐진 답변으로 다시 만들어졌습니다.

DESIGN CONTRACT V1

방과후·늘봄 강사 배정 관리 서비스 디자인 가이드

운영자에게는 엑셀처럼 빠르게 훑고 수정할 수 있는 고밀도 업무 화면을 제공하고, 강사에게는 이동 중 최신 확정 시간표와 변경 알림을 빠르게 확인하는 모바일 중심 화면을 제공한다. 운영자 화면은 학교·학기·운영 기간의 맥락을 항상 유지하며, 시간 중복을 빨간색에만 의존하지 않고 충돌한 두 수업과 해결 행동을 함께 보여준다. 공개 전 편집본과 강사에게 보이는 공개본을 분리해 저장과 공개를 혼동하지 않게 한다.

정확한 시간표 · 충돌 우선 · 엑셀 친화적 · 학교별 실제 시간 · 행 단위 수정 · 공개본 분리 · 운영자 고밀도 · 강사 모바일 확인 · 차분한 교육 행정 · 명확한 상태 표시

레이아웃
Desktop first
기본 글꼴
Pretendard Variable
조사 출처
10곳

COLOR SYSTEM

컬러 시스템

각 토큰의 실제 색상과 사용 맥락의 본문 대비를 보여 줍니다. AA 기준은 4.5:1입니다.

#1D4ED8

Primary

2.65:1 · 큰 글자용

주요 버튼, 선택된 탐색 항목, 링크, 현재 단계와 포커스 보조 표시

#1E40AF

PrimaryHover

2.03:1 · 큰 글자용

주요 버튼과 링크의 hover 및 pressed 상태

#EFF6FF

PrimarySoft

16.31:1 · AA

선택된 행, 정보 배너, 공개 상태의 약한 배경

#101828

TextPrimary

16.70:1 · AA

제목, 본문, 표의 주요 값

#475467

TextSecondary

7.23:1 · AA

보조 설명, 메타 정보, 비활성에 가깝지만 읽어야 하는 텍스트

#F7F8FA

Canvas

16.70:1 · AA

운영자 화면의 전체 배경

#FFFFFF

Surface

17.75:1 · AA

카드, 표, 모달, 드로어와 입력 영역

#D0D5DD

Border

12.04:1 · AA

표 구분선, 입력 테두리, 카드 경계

#EAECF0

Disabled

15.00:1 · AA

비활성 입력과 버튼 배경

#067647

Success

3.12:1 · 큰 글자용

정상 검증, 저장 완료, 초대 연결 완료

#ECFDF3

SuccessSoft

16.83:1 · AA

정상 행과 완료 상태의 약한 배경

#B54708

Warning

3.27:1 · 큰 글자용

확인 필요, 교시명과 실제 시간 불일치, 공개 전 확인 항목

#FFFAEB

WarningSoft

17.01:1 · AA

경고 배너와 확인 필요 셀 배경

#B42318

Danger

2.70:1 · 큰 글자용

저장 차단, 시간 중복, 필수값 오류, 삭제 확인

#FEF3F2

DangerSoft

16.32:1 · AA

문제 셀, 충돌 카드와 오류 요약 배경

#5925DC

Exception

2.30:1 · 큰 글자용

같은 학교 시간 겹침의 예외 저장 상태와 이력

#F4F3FF

ExceptionSoft

16.15:1 · AA

예외 사유 영역과 예외 저장 배지 배경

TYPOGRAPHY

한글 타이포그래피

제목 · -0.025em

흙에서 완성까지, 한눈에

본문 · -0.01em

작품의 현재 단계와 선반 위치를 기록하고, 다음 가마에 넣을 작품을 빠르게 확인합니다.

가마 02 · 1,250°C · 8–11시간

SPACING & RADIUS

간격과 형태

4px
8px
12px
16px
20px
24px
32px
40px
48px
64px
80px
sm
6px
md
10px
lg
16px
full
9999px

RESPONSIVE LAYOUT

그리드와 화면 전략

운영자의 핵심 업무가 여러 학교·강사의 시간표를 고밀도 표와 주간 격자에서 비교하고, 충돌한 두 수업을 동시에 펼쳐 수정하는 작업이므로 desktop_first가 적합하다. 기본 운영 화면은 1280px 이상에서 사이드바, 작업 영역, 우측 비교 패널을 함께 사용한다. 1024px 미만에서는 비교 패널을 전체 화면 드로어로 전환하고, 768px 미만에서는 시간표 격자보다 문제 목록과 요일별 카드 목록을 우선 제공한다. 강사 화면은 같은 웹 서비스 안에서 별도로 모바일에 최적화한다.

모바일 · 4

데스크톱 · 12

sm
640px
md
768px
lg
1024px
xl
1280px
최대 폭
1440px

COMPONENTS

컴포넌트와 상태

계약 토큰을 적용한 버튼·입력·카드 견본과 구현 규칙입니다.

버튼

입력 상태

물레컵 3점

초벌 대기

2번 선반 · 1칸
예상 완료 9월 18일

AppShell

operator · instructor · default · sidebarCollapsed · mobileNavigationOpen

operator는 240px 좌측 사이드바, 상단 업체·학기 맥락 영역, 본문으로 구성한다. 1280px 이상에서 충돌 비교 패널이 열리면 본문과 나란히 배치한다. instructor는 모바일 하단 탐색에 시간표와 알림함만 노출하고 운영자 메뉴는 렌더링하지 않는다.

PageHeader

standard · withContext · withPrimaryAction · default · sticky

화면명 아래에 선택한 학교, 학기, 운영 기간을 표시한다. 저장·공개처럼 결과가 다른 행동은 같은 문구로 합치지 않는다. 고밀도 화면에서는 필터와 주요 행동을 스크롤 중에도 사용할 수 있도록 상단을 고정한다.

OperatorNavigation

expanded · collapsed · mobileDrawer · default · active · disabled

운영자 화면, 학교·강사, 학기·교시표, 수업 등록, 엑셀 업로드, 전체 시간표 순으로 배치한다. 첫 개발에서 제외된 서류, 대체강사, 정산, 민원, 결제 메뉴는 노출하지 않는다.

Button

primary · secondary · tertiary · danger · icon · default · hover · focus · pressed · loading · disabled

기본 높이는 데스크톱 40px, 모바일 44px 이상으로 한다. 버튼은 저장, 검증, 확정, 공개를 구분해 구체적인 동사를 사용한다. 비활성 버튼 주변에는 비활성 이유를 문장으로 제공한다.

Field

text · select · combobox · date · dateRange · time · textarea · default · hover · focus · filled · error · warning · disabled · readonly

모든 입력은 화면에 남는 라벨을 사용한다. 필수값은 라벨과 오류 문구로 안내한다. 시간 입력은 9, 0900, 09:00을 허용하되 포커스가 빠지면 HH:mm으로 정규화한다. 종료 시각이 시작 시각과 같거나 빠르면 해당 필드 아래에 즉시 오류를 표시한다.

EntityCombobox

school · instructor · term · subject · default · searching · noResult · ambiguous · selected · error

학교와 강사는 표시 이름이 아니라 고유 식별값을 저장한다. 동명이인 강사 선택 시 휴대폰번호 뒤 4자리와 내부 식별 정보를 함께 보여주되 전체 연락처는 노출하지 않는다. 엑셀 업로드의 모호한 이름은 운영자가 선택하기 전까지 확정하지 않는다.

StatusBadge

temporary · confirmed · published · unpublishedChange · normal · needsReview · blocked · exception · invited · connected · default

색상과 함께 임시 배정, 확정 시간표, 공개됨, 변경 미게시, 저장 차단, 예외 저장처럼 상태명을 항상 표시한다. 한 화면에서 같은 의미의 상태명과 색상을 일관되게 유지한다.

FilterBar

inline · responsiveDrawer · default · filtered · expanded

학교, 학기, 운영 기간, 강사, 요일, 상태 필터를 제공하고 적용 중인 조건을 칩으로 표시한다. 문제 해결 화면에서는 충돌만 보기와 예외 저장 보기의 우선순위를 높인다. 모바일에서는 필터를 드로어로 열고 적용된 조건 수를 버튼에 표시한다.

EditableDataGrid

standard · excelPreview · compact · loading · empty · normal · rowSelected · cellEditing · cellError · rowBlocked · rowRevalidating

헤더와 엑셀 행 번호 열을 고정하고 가로 스크롤을 허용한다. 오류는 행 전체가 아니라 문제 셀에 DangerSoft 배경, 테두리, 아이콘, 문구로 표시한다. Enter로 편집, Esc로 취소, Tab으로 다음 편집 셀 이동이 가능해야 한다. 수정한 행은 재검증 중 상태를 거쳐야 정상으로 바뀐다.

ValidationSummary

inline · sticky · dialog · allValid · hasWarnings · hasBlockingErrors · validating

정상, 확인 필요, 저장 차단 건수를 분리한다. 저장 차단 건수를 누르면 첫 문제 행 또는 충돌 수업으로 이동한다. 저장 버튼 문구에는 해결할 건수를 포함하고, 경고와 저장 차단의 차이를 설명한다.

Timetable

allSchoolsWeek · schoolWeek · instructorWeek · list · loading · empty · normal · conflict · exception · published · unpublishedChange

데스크톱 격자에는 요일과 실제 시간 축을 사용하고 카드 안에 학교, 교시명, 실제 시각, 과목, 강사를 일정한 순서로 표시한다. 충돌 카드를 선택하면 상대 카드도 강조한다. 모바일에서는 격자를 축소하지 말고 요일별 목록으로 바꾼다.

ClassCard

operator · instructor · comparison · normal · temporary · published · conflict · exception · changed

운영자용 카드는 학교, 요일·교시, 실제 시각, 과목, 강사를 표시한다. 강사용 카드는 강사명을 생략하고 학교, 요일·교시, 실제 시각, 과목을 우선한다. 충돌과 변경 상태는 아이콘, 상태명, 짧은 이유를 함께 표시한다.

ConflictComparePanel

sidePanel · fullScreenDrawer · blockedAcrossSchools · sameSchoolExceptionAvailable · editing · revalidating · resolved · newConflictFound

충돌한 두 수업을 동일한 필드 순서로 나란히 보여주고 실제 시간이 겹치는 구간을 시간 막대로 표시한다. 운영자는 수정할 수업을 선택해 강사, 요일, 교시, 실제 시간을 바꾼다. 서로 다른 학교의 시간 중복에는 예외 저장 행동을 절대 제공하지 않는다.

ExceptionReasonDialog

sameSchoolOverlap · default · invalid · submitting · saved

같은 강사의 같은 학교 시간 겹침에서만 연다. 겹친 두 수업, 예외 적용 범위, 필수 사유 입력란을 표시한다. 저장 후 예외 사유, 처리한 운영자, 처리 시각, 관련 수업 식별값이 남는다는 점을 확인 문구로 알린다.

AssignmentForm

create · edit · inlineConflictEdit · pristine · dirty · validating · blocked · valid · saving · saved

학교와 학기를 먼저 선택한 뒤 운영 기간, 요일, 교시 또는 실제 시간, 과목, 강사를 입력한다. 교시 선택 시 실제 시각을 읽기 전용으로 함께 보여주고 직접 시간을 선택하면 그 값을 충돌 검사 기준으로 사용한다. 유효한 신규 수업은 임시 배정으로 저장한다.

ExcelDropzone

empty · fileSelected · reading · idle · dragOver · uploading · unsupported · readFailed · complete

양식 다운로드를 파일 선택보다 먼저 제공한다. 지원 확장자와 최대 파일 크기는 개발 정책 확정 후 문구에 반영한다. 파일은 실제 시간표에 바로 저장하지 않고 임시 데이터로 읽는다고 명시한다.

ProcessStepper

excelImport · onboarding · upcoming · current · complete · error

엑셀 업로드는 파일 선택, 검토·수정, 확정의 단계로 표시한다. 지정 양식을 사용하므로 첫 개발에서는 임의 열 연결 단계를 만들지 않는다. 현재 단계와 완료된 단계를 색상 외에 숫자와 텍스트로 구분한다.

PublishDialog

initialPublish · publishChanges · blocked · ready · publishing · success · failed

최초 공개에서는 공개할 학교·학기, 강사 수, 수업 수, 초대 미연결 강사 수를 보여준다. 변경 게시에서는 변경된 수업, 변경 전후 값, 영향을 받는 강사 수를 보여준다. 저장 차단 시간 중복이 있으면 공개 버튼을 비활성화하고 문제 화면으로 이동하는 행동을 제공한다.

NotificationItem

initialPublish · scheduleChange · unread · read

제목에 학교와 변경 유형을 포함하고 본문에 요일, 교시명, 실제 시간, 과목, 변경 시각을 표시한다. 변경 알림 상세에서는 변경 전후 값 중 달라진 항목만 강조한다. 항목을 열면 읽음 처리하고 해당 개인 시간표 위치로 이동한다.

InlineAlert

info · success · warning · danger · default · dismissible

오류 코드 대신 무엇이 문제이고 어떻게 해결할지 문장으로 표시한다. 예: 김지민 강사는 월요일 14:00~15:20에 다른 학교 수업에 배정되어 있습니다. 강사 또는 시간을 변경하세요.

DialogAndDrawer

modal · sideDrawer · bottomSheet · fullScreen · opening · open · closing

데스크톱 비교·수정은 우측 드로어, 모바일은 전체 화면을 사용한다. 열릴 때 제목으로 포커스를 옮기고 닫힐 때 실행한 요소로 포커스를 돌려준다. 저장되지 않은 변경이 있으면 닫기 전에 확인한다.

EmptyState

firstUse · filtered · noPublishedSchedule · noNotifications · default

첫 사용 상태에는 다음 행동 하나를 제시한다. 필터 결과 없음은 필터 초기화, 공개 시간표 없음은 운영자가 공개한 뒤 표시된다는 설명을 제공한다. 서류, 정산, 대체강사 기능을 암시하는 문구는 사용하지 않는다.

Toast

success · error · info · visible · dismissed

단순 저장 완료는 토스트로 알리되 공개, 충돌, 업로드 확정처럼 중요한 결과는 화면 안의 지속 메시지도 함께 제공한다. 오류 토스트만으로 입력 오류 위치를 전달하지 않는다.

APPLICATION

업계 조사와 화면별 적용

· 운영자는 학기 시작 전 여러 학교와 강사의 배정을 한꺼번에 검토하므로 주간 시간표, 표 보기, 문제 목록을 오갈 수 있어야 한다.

· 학교마다 같은 교시명의 실제 시작·종료 시각이 다를 수 있으므로 모든 시간표 카드와 충돌 화면에 교시명과 실제 시각을 함께 표시해야 한다.

· 시간 중복은 같은 요일, 겹치는 운영 기간, 실제 시작·종료 시각을 함께 검사해야 하며 14:00~14:40과 14:40~15:20은 겹치지 않는 것으로 표시한다.

· 엑셀 업로드는 실패 안내로 끝내지 않고 원본 엑셀 행 번호, 문제 셀, 오류 이유, 바로 수정할 입력 요소를 같은 표 안에 제공해야 한다.

· 충돌 경고는 충돌한 두 수업의 학교, 운영 기간, 요일, 교시, 실제 시간, 과목, 강사를 나란히 보여줘야 해결 속도가 높아진다.

· 서로 다른 학교에서 발생한 동일 강사의 시간 중복은 예외 없이 저장을 막고, 같은 학교 안의 시간 겹침만 사유를 남긴 경우 예외 저장할 수 있어야 한다.

· 강사는 전체 시간표보다 자신의 최신 공개 시간표와 변경 알림을 우선 확인하므로 모바일에서는 요일별 목록과 알림함을 핵심 탐색 구조로 사용한다.

· 조사 자료에는 이동시간 부족, 서류 상태, 대체강사, 확인 응답 기능이 제안되어 있으나 첫 개발 범위에서는 화면과 상태에 포함하지 않는다.

· 시간표 저장과 강사 공개를 분리하고, 공개 후 수정은 변경 전후 값과 영향을 받는 강사를 확인한 뒤 게시해야 강사에게 미완성 편집 내용이 노출되지 않는다.

· 운영자 화면은 데스크톱에서 상시 사용하는 고밀도 표와 비교 패널이 핵심이지만, 좁은 화면에서도 문제 목록 조회와 수업 한 건 수정은 가능해야 한다.

operator

운영자용 시작 화면이다. 상단에서 현재 학기를 선택하고 학교 등록, 강사 등록, 교시표 설정, 수업 등록, 충돌 해결, 시간표 공개의 준비 상태를 순서대로 보여준다. 본문에는 등록 학교 수, 등록 강사 수, 미해결 시간 중복 수, 임시 배정 수, 마지막 공개 시각을 표시한다. 가장 위험한 미해결 시간 중복을 첫 번째 작업 카드로 두고 전체 시간표로 연결한다. 서류, 대체강사, 정산, 민원, 결제 현황은 첫 개발 화면에 넣지 않는다.

instructor

강사 역할의 모바일 셸이다. 로그인 후 강사 개인 시간표로 바로 이동하고 하단 탐색에는 시간표와 알림함만 제공한다. 읽지 않은 알림 수를 배지로 표시한다. 다른 강사의 시간표, 전체 시간표, 학교·강사 관리, 강사료·재료비·지급 예정액 메뉴는 노출하지 않는다.

admin-login-start

로그인과 업체 시작을 탭 또는 분리된 카드로 제공한다. 업체 시작은 운영자 로그인 정보와 위탁업체명을 필수로 받고, 계정과 위탁업체 생성이 함께 성공했을 때만 완료한다. 오류는 계정 존재 여부를 과도하게 드러내지 않는 문장으로 표시한다. 완료 후 학교·강사 목록 관리 화면으로 이동하며 첫 학교와 강사를 등록하라는 안내를 보여준다.

school-instructor-list

학교와 강사를 상단 탭으로 분리한다. 각 탭에는 검색, 등록 버튼, 목록, 수정 행동을 제공한다. 학교 행에는 학교명, 등록된 학기·교시 템플릿 상태, 연결된 수업 수를 표시하고 학기·교시표 설정으로 이동하는 버튼을 둔다. 강사 행에는 이름, 구분용 휴대폰번호 뒤 4자리, 초대 전·초대 발송·연결 완료 상태를 표시한다. 이름이 같은 강사를 합치지 않으며 고유 식별값으로 구분한다. 모바일에서는 표를 카드 목록으로 전환한다.

class-assignment

학교와 학기를 먼저 선택한 뒤 운영 기간, 요일, 교시 또는 시작·종료 시각, 과목, 담당 강사를 입력한다. 교시를 선택하면 실제 시간을 바로 아래에 표시한다. 입력값이 바뀔 때 화면에서 즉시 검증하고 저장 요청 시 서버에서 다시 검사한다. 서로 다른 학교의 동일 강사 시간 중복은 저장 버튼을 막고 충돌 비교 패널을 연다. 같은 학교 시간 겹침은 예외 사유 입력 행동을 제공한다. 정상 신규 수업은 임시 배정으로 저장하며, 공개된 수업 수정은 변경 미게시 상태로 두어 기존 공개본이 강사 화면에서 유지되게 한다.

excel-import-preview

상단에 양식 다운로드, 파일 선택, 검토·수정, 확정 단계를 표시한다. 업로드 파일은 임시 데이터로만 읽고 총 행, 정상, 확인 필요, 저장 차단 건수를 고정 요약 영역에 표시한다. 표에는 상태, 엑셀 행, 학교, 운영 기간, 요일, 교시명, 시작, 종료, 과목, 강사, 검증 결과를 배치한다. 등록되지 않은 학교, 모호한 강사, 비어 있는 시간, 잘못된 종료 시각과 시간 중복은 문제 셀에서 직접 수정한다. 동명이인은 후보를 직접 선택하게 하고 교시명으로 시간을 찾을 수 없으면 교시표 설정 또는 직접 시간 입력으로 연결한다. 수정 후 관련 행을 재검증하며 모든 저장 차단 오류가 해결되어야 전체 확정 버튼을 사용할 수 있다. 확정 직전 서버에서 다시 충돌을 검사하고 새 충돌이 생기면 해당 엑셀 행으로 되돌린다.

master-timetable

운영자의 핵심 작업 화면이다. 상단에 학기, 학교, 강사, 요일, 상태 필터와 주간 보기·표 보기·충돌만 보기 전환을 둔다. 데스크톱에서는 전체 시간표 왼쪽과 420~480px 우측 충돌 비교 패널을 함께 보여준다. 충돌 카드를 선택하면 상대 수업도 강조하고 두 수업의 학교, 운영 기간, 요일, 교시, 실제 시간, 과목, 강사를 나란히 표시한다. 한쪽 수업을 선택해 강사, 요일, 교시 또는 실제 시간을 수정한 뒤 즉시 재검증한다. 서로 다른 학교의 시간 중복은 해결 전 저장과 공개를 막는다. 같은 학교 예외 저장 건에는 사유와 처리 이력을 볼 수 있는 보라색 상태 배지를 표시한다. 공개 버튼을 누르면 공개 차단 오류, 공개 대상 학교·강사·수업 수, 초대 미연결 강사 수를 확인한다. 최초 공개와 변경 게시를 구분하고 성공 후 공개본 식별값과 공개 시각을 화면에 표시한다.

instructor-timetable

강사에게 최신 공개본만 보여준다. 모바일 기본은 요일별 목록이며 상단에 학기와 운영 기간을 표시한다. 각 수업은 요일, 교시명, 실제 시작·종료 시각, 학교, 과목 순으로 보여준다. 여러 학교의 수업을 학교 색상만으로 구분하지 말고 학교명을 반복 표시한다. 변경 알림에서 진입하면 해당 수업으로 스크롤하고 잠시 강조한다. 공개된 수업이 없으면 운영자가 시간표를 공개한 뒤 확인할 수 있다는 빈 상태를 제공한다. 임시 배정과 변경 미게시 내용은 노출하지 않는다.

instructor-notifications

읽지 않음과 전체 필터를 제공하고 최신 알림부터 정렬한다. 최초 공개 알림에는 공개된 학기, 수업 수, 공개 시각을 표시한다. 변경 알림에는 변경된 학교, 요일, 교시명, 실제 시간, 과목, 변경 시각을 포함한다. 상세를 열면 변경 전후 값 중 달라진 항목을 나란히 보여주고 읽음 처리한다. 시간표 보기 버튼은 해당 개인 시간표 위치로 이동한다. 첫 개발에는 확인했습니다, 진행이 어렵습니다, 카카오톡 발송 기능을 추가하지 않는다.

school-term-period-settings

왼쪽 또는 상단에서 학교와 학기를 선택하고 학기 운영 기간을 설정한다. 교시 템플릿 카드에는 템플릿명, 적용 기간, 요일을 표시하고 내부 교시표는 교시명, 시작 시각, 종료 시각을 편집 가능한 행으로 구성한다. 종료 시각이 시작 시각과 같거나 빠르면 해당 행 저장을 막는다. 동일한 학교·학기·요일·적용 범위에서 어떤 교시 템플릿을 써야 하는지 하나로 결정할 수 없으면 충돌한 템플릿을 함께 표시한다. 가정에 따라 첫 개발에서는 교시 템플릿을 수정해도 이미 저장된 수업의 실제 시간은 자동 변경하지 않는다. 저장 전에 기존 수업 수를 보여주고 기존 수업은 현재 실제 시간을 유지한다는 확인 문구를 제공한다.

instructor-login-invite

초대 링크의 위탁업체명과 연결 대상 강사 이름을 표시하고 계정 만들기 또는 기존 계정 로그인을 선택하게 한다. 개인정보는 필요한 범위만 마스킹해 보여준다. 연결 완료 전에는 개인 시간표와 알림함으로 진입할 수 없다. 만료, 이미 사용됨, 대상 정보 불일치, 권한 없음 상태를 각각 구분하고 운영자에게 새 초대를 요청하는 방법을 안내한다. 성공 시 연결된 위탁업체와 강사 정보를 확인한 뒤 강사 개인 시간표로 이동한다.

에셋 원칙
가정: 별도 브랜드 자산이 없으므로 첫 개발에서는 텍스트 워드마크 ‘방과후 운영 한눈에’를 사용한다. · 학교, 강사, 시간표, 엑셀, 충돌, 알림, 공개 상태를 표현하는 일관된 20px·24px SVG 선형 아이콘 세트 · 현재 지원 열 이름과 입력 예시가 포함된 시간표 엑셀 양식 파일 · 업로드 빈 상태, 공개 시간표 없음, 알림 없음에 사용할 단순한 단색 SVG 일러스트레이션 · 시간 중복 비교용 시간 막대와 겹침 구간 SVG · 로딩 중 표와 시간표에 사용할 스켈레톤 자산 · 민감한 서류 원본을 연상시키는 업로드 자산은 첫 개발 범위에서 제외한다. · 아이콘 라이브러리와 워드마크의 최종 라이선스는 구현 전 확인 필요

ACCESSIBILITY

접근성과 모션

  • · KWCAG 2.2와 WCAG 2.1 AA를 기준으로 본문과 배경은 4.5:1 이상, 큰 글자와 주요 UI 경계는 3:1 이상의 명도 대비를 확보한다.
  • · 시간 중복, 경고, 예외, 공개 상태는 색상만으로 구분하지 않고 아이콘, 상태명, 원인 문구를 함께 제공한다.
  • · 모든 상호작용 요소에는 키보드로 접근할 수 있어야 하며 보이는 2px 이상의 포커스 표시를 제공한다.
  • · 모바일 터치 대상은 최소 44px × 44px로 하고 인접한 아이콘 버튼 사이에 8px 이상의 간격을 둔다.
  • · 입력 오류는 필드 라벨, 오류 문구, aria-describedby로 연결하고 저장 시 첫 오류로 포커스를 이동한다.
  • · 엑셀 검토 표는 caption과 열 머리글을 제공하고, 오류 셀의 상태를 스크린 리더가 행 번호와 함께 읽을 수 있게 한다.
  • · 편집 가능한 표는 Enter로 편집 시작, Esc로 취소, Tab으로 다음 셀 이동을 지원하며 키보드 사용법을 표 앞에서 안내한다.
  • · 충돌 재검증, 저장 완료, 새 오류 발생 결과는 aria-live 영역으로 알리되 같은 메시지를 반복 낭독하지 않는다.
  • · 모달과 드로어는 포커스를 내부에 유지하고 제목과 설명을 연결하며 닫힌 뒤 원래 실행 요소로 포커스를 복원한다.
  • · 주간 시간표를 시각적 격자로만 제공하지 않고 동일 데이터를 표 보기 또는 요일별 목록으로도 제공한다.
  • · 200% 확대와 320px 너비에서도 핵심 조회와 수업 한 건 수정이 가능해야 하며, 화면 전체에 가로 스크롤을 만들지 않는다. 고밀도 표 내부의 가로 스크롤은 허용한다.
  • · 날짜와 시간은 한국 표준시 기준의 명확한 형식으로 표시하고 상대 날짜만 사용하지 않는다.
  • · 아이콘 버튼에는 접근 가능한 이름을 제공하고 닫기, 편집, 알림처럼 의미가 다른 아이콘을 모양만으로 구분하지 않는다.
  • · 동작 줄이기 설정이 켜지면 패널 이동과 상태 전환 애니메이션을 제거하고 즉시 상태를 변경한다.

기본 전환 180ms cubic-bezier(0.2, 0, 0, 1) · 모션 감소 설정 지원 · 다크모드 not_planned

EVIDENCE

조사 출처

기계 판독 디자인 계약 보기
{
  "version": 1,
  "direction": "운영자에게는 엑셀처럼 빠르게 훑고 수정할 수 있는 고밀도 업무 화면을 제공하고, 강사에게는 이동 중 최신 확정 시간표와 변경 알림을 빠르게 확인하는 모바일 중심 화면을 제공한다. 운영자 화면은 학교·학기·운영 기간의 맥락을 항상 유지하며, 시간 중복을 빨간색에만 의존하지 않고 충돌한 두 수업과 해결 행동을 함께 보여준다. 공개 전 편집본과 강사에게 보이는 공개본을 분리해 저장과 공개를 혼동하지 않게 한다.",
  "keywords": [
    "정확한 시간표",
    "충돌 우선",
    "엑셀 친화적",
    "학교별 실제 시간",
    "행 단위 수정",
    "공개본 분리",
    "운영자 고밀도",
    "강사 모바일 확인",
    "차분한 교육 행정",
    "명확한 상태 표시"
  ],
  "industryFindings": [
    "운영자는 학기 시작 전 여러 학교와 강사의 배정을 한꺼번에 검토하므로 주간 시간표, 표 보기, 문제 목록을 오갈 수 있어야 한다.",
    "학교마다 같은 교시명의 실제 시작·종료 시각이 다를 수 있으므로 모든 시간표 카드와 충돌 화면에 교시명과 실제 시각을 함께 표시해야 한다.",
    "시간 중복은 같은 요일, 겹치는 운영 기간, 실제 시작·종료 시각을 함께 검사해야 하며 14:00~14:40과 14:40~15:20은 겹치지 않는 것으로 표시한다.",
    "엑셀 업로드는 실패 안내로 끝내지 않고 원본 엑셀 행 번호, 문제 셀, 오류 이유, 바로 수정할 입력 요소를 같은 표 안에 제공해야 한다.",
    "충돌 경고는 충돌한 두 수업의 학교, 운영 기간, 요일, 교시, 실제 시간, 과목, 강사를 나란히 보여줘야 해결 속도가 높아진다.",
    "서로 다른 학교에서 발생한 동일 강사의 시간 중복은 예외 없이 저장을 막고, 같은 학교 안의 시간 겹침만 사유를 남긴 경우 예외 저장할 수 있어야 한다.",
    "강사는 전체 시간표보다 자신의 최신 공개 시간표와 변경 알림을 우선 확인하므로 모바일에서는 요일별 목록과 알림함을 핵심 탐색 구조로 사용한다.",
    "조사 자료에는 이동시간 부족, 서류 상태, 대체강사, 확인 응답 기능이 제안되어 있으나 첫 개발 범위에서는 화면과 상태에 포함하지 않는다.",
    "시간표 저장과 강사 공개를 분리하고, 공개 후 수정은 변경 전후 값과 영향을 받는 강사를 확인한 뒤 게시해야 강사에게 미완성 편집 내용이 노출되지 않는다.",
    "운영자 화면은 데스크톱에서 상시 사용하는 고밀도 표와 비교 패널이 핵심이지만, 좁은 화면에서도 문제 목록 조회와 수업 한 건 수정은 가능해야 한다."
  ],
  "layoutMode": "desktop_first",
  "layoutRationale": "운영자의 핵심 업무가 여러 학교·강사의 시간표를 고밀도 표와 주간 격자에서 비교하고, 충돌한 두 수업을 동시에 펼쳐 수정하는 작업이므로 desktop_first가 적합하다. 기본 운영 화면은 1280px 이상에서 사이드바, 작업 영역, 우측 비교 패널을 함께 사용한다. 1024px 미만에서는 비교 패널을 전체 화면 드로어로 전환하고, 768px 미만에서는 시간표 격자보다 문제 목록과 요일별 카드 목록을 우선 제공한다. 강사 화면은 같은 웹 서비스 안에서 별도로 모바일에 최적화한다.",
  "typography": {
    "koreanFont": "Pretendard Variable",
    "fallback": [
      "Pretendard",
      "-apple-system",
      "BlinkMacSystemFont",
      "Segoe UI",
      "Noto Sans KR",
      "sans-serif"
    ],
    "bodyLetterSpacing": "-0.01em",
    "headingLetterSpacing": "-0.025em",
    "bodyLineHeight": 1.5
  },
  "colors": [
    {
      "name": "Primary",
      "value": "#1D4ED8",
      "usage": "주요 버튼, 선택된 탐색 항목, 링크, 현재 단계와 포커스 보조 표시"
    },
    {
      "name": "PrimaryHover",
      "value": "#1E40AF",
      "usage": "주요 버튼과 링크의 hover 및 pressed 상태"
    },
    {
      "name": "PrimarySoft",
      "value": "#EFF6FF",
      "usage": "선택된 행, 정보 배너, 공개 상태의 약한 배경"
    },
    {
      "name": "TextPrimary",
      "value": "#101828",
      "usage": "제목, 본문, 표의 주요 값"
    },
    {
      "name": "TextSecondary",
      "value": "#475467",
      "usage": "보조 설명, 메타 정보, 비활성에 가깝지만 읽어야 하는 텍스트"
    },
    {
      "name": "Canvas",
      "value": "#F7F8FA",
      "usage": "운영자 화면의 전체 배경"
    },
    {
      "name": "Surface",
      "value": "#FFFFFF",
      "usage": "카드, 표, 모달, 드로어와 입력 영역"
    },
    {
      "name": "Border",
      "value": "#D0D5DD",
      "usage": "표 구분선, 입력 테두리, 카드 경계"
    },
    {
      "name": "Disabled",
      "value": "#EAECF0",
      "usage": "비활성 입력과 버튼 배경"
    },
    {
      "name": "Success",
      "value": "#067647",
      "usage": "정상 검증, 저장 완료, 초대 연결 완료"
    },
    {
      "name": "SuccessSoft",
      "value": "#ECFDF3",
      "usage": "정상 행과 완료 상태의 약한 배경"
    },
    {
      "name": "Warning",
      "value": "#B54708",
      "usage": "확인 필요, 교시명과 실제 시간 불일치, 공개 전 확인 항목"
    },
    {
      "name": "WarningSoft",
      "value": "#FFFAEB",
      "usage": "경고 배너와 확인 필요 셀 배경"
    },
    {
      "name": "Danger",
      "value": "#B42318",
      "usage": "저장 차단, 시간 중복, 필수값 오류, 삭제 확인"
    },
    {
      "name": "DangerSoft",
      "value": "#FEF3F2",
      "usage": "문제 셀, 충돌 카드와 오류 요약 배경"
    },
    {
      "name": "Exception",
      "value": "#5925DC",
      "usage": "같은 학교 시간 겹침의 예외 저장 상태와 이력"
    },
    {
      "name": "ExceptionSoft",
      "value": "#F4F3FF",
      "usage": "예외 사유 영역과 예외 저장 배지 배경"
    }
  ],
  "breakpoints": {
    "sm": 640,
    "md": 768,
    "lg": 1024,
    "xl": 1280
  },
  "grid": {
    "baseUnit": 4,
    "mobileColumns": 4,
    "desktopColumns": 12,
    "maxContentWidth": 1440
  },
  "spacing": [
    4,
    8,
    12,
    16,
    20,
    24,
    32,
    40,
    48,
    64,
    80
  ],
  "radius": {
    "sm": 6,
    "md": 10,
    "lg": 16,
    "full": 9999
  },
  "components": [
    {
      "name": "AppShell",
      "variants": [
        "operator",
        "instructor"
      ],
      "states": [
        "default",
        "sidebarCollapsed",
        "mobileNavigationOpen"
      ],
      "guidance": "operator는 240px 좌측 사이드바, 상단 업체·학기 맥락 영역, 본문으로 구성한다. 1280px 이상에서 충돌 비교 패널이 열리면 본문과 나란히 배치한다. instructor는 모바일 하단 탐색에 시간표와 알림함만 노출하고 운영자 메뉴는 렌더링하지 않는다."
    },
    {
      "name": "PageHeader",
      "variants": [
        "standard",
        "withContext",
        "withPrimaryAction"
      ],
      "states": [
        "default",
        "sticky"
      ],
      "guidance": "화면명 아래에 선택한 학교, 학기, 운영 기간을 표시한다. 저장·공개처럼 결과가 다른 행동은 같은 문구로 합치지 않는다. 고밀도 화면에서는 필터와 주요 행동을 스크롤 중에도 사용할 수 있도록 상단을 고정한다."
    },
    {
      "name": "OperatorNavigation",
      "variants": [
        "expanded",
        "collapsed",
        "mobileDrawer"
      ],
      "states": [
        "default",
        "active",
        "disabled"
      ],
      "guidance": "운영자 화면, 학교·강사, 학기·교시표, 수업 등록, 엑셀 업로드, 전체 시간표 순으로 배치한다. 첫 개발에서 제외된 서류, 대체강사, 정산, 민원, 결제 메뉴는 노출하지 않는다."
    },
    {
      "name": "Button",
      "variants": [
        "primary",
        "secondary",
        "tertiary",
        "danger",
        "icon"
      ],
      "states": [
        "default",
        "hover",
        "focus",
        "pressed",
        "loading",
        "disabled"
      ],
      "guidance": "기본 높이는 데스크톱 40px, 모바일 44px 이상으로 한다. 버튼은 저장, 검증, 확정, 공개를 구분해 구체적인 동사를 사용한다. 비활성 버튼 주변에는 비활성 이유를 문장으로 제공한다."
    },
    {
      "name": "Field",
      "variants": [
        "text",
        "select",
        "combobox",
        "date",
        "dateRange",
        "time",
        "textarea"
      ],
      "states": [
        "default",
        "hover",
        "focus",
        "filled",
        "error",
        "warning",
        "disabled",
        "readonly"
      ],
      "guidance": "모든 입력은 화면에 남는 라벨을 사용한다. 필수값은 라벨과 오류 문구로 안내한다. 시간 입력은 9, 0900, 09:00을 허용하되 포커스가 빠지면 HH:mm으로 정규화한다. 종료 시각이 시작 시각과 같거나 빠르면 해당 필드 아래에 즉시 오류를 표시한다."
    },
    {
      "name": "EntityCombobox",
      "variants": [
        "school",
        "instructor",
        "term",
        "subject"
      ],
      "states": [
        "default",
        "searching",
        "noResult",
        "ambiguous",
        "selected",
        "error"
      ],
      "guidance": "학교와 강사는 표시 이름이 아니라 고유 식별값을 저장한다. 동명이인 강사 선택 시 휴대폰번호 뒤 4자리와 내부 식별 정보를 함께 보여주되 전체 연락처는 노출하지 않는다. 엑셀 업로드의 모호한 이름은 운영자가 선택하기 전까지 확정하지 않는다."
    },
    {
      "name": "StatusBadge",
      "variants": [
        "temporary",
        "confirmed",
        "published",
        "unpublishedChange",
        "normal",
        "needsReview",
        "blocked",
        "exception",
        "invited",
        "connected"
      ],
      "states": [
        "default"
      ],
      "guidance": "색상과 함께 임시 배정, 확정 시간표, 공개됨, 변경 미게시, 저장 차단, 예외 저장처럼 상태명을 항상 표시한다. 한 화면에서 같은 의미의 상태명과 색상을 일관되게 유지한다."
    },
    {
      "name": "FilterBar",
      "variants": [
        "inline",
        "responsiveDrawer"
      ],
      "states": [
        "default",
        "filtered",
        "expanded"
      ],
      "guidance": "학교, 학기, 운영 기간, 강사, 요일, 상태 필터를 제공하고 적용 중인 조건을 칩으로 표시한다. 문제 해결 화면에서는 충돌만 보기와 예외 저장 보기의 우선순위를 높인다. 모바일에서는 필터를 드로어로 열고 적용된 조건 수를 버튼에 표시한다."
    },
    {
      "name": "EditableDataGrid",
      "variants": [
        "standard",
        "excelPreview",
        "compact"
      ],
      "states": [
        "loading",
        "empty",
        "normal",
        "rowSelected",
        "cellEditing",
        "cellError",
        "rowBlocked",
        "rowRevalidating"
      ],
      "guidance": "헤더와 엑셀 행 번호 열을 고정하고 가로 스크롤을 허용한다. 오류는 행 전체가 아니라 문제 셀에 DangerSoft 배경, 테두리, 아이콘, 문구로 표시한다. Enter로 편집, Esc로 취소, Tab으로 다음 편집 셀 이동이 가능해야 한다. 수정한 행은 재검증 중 상태를 거쳐야 정상으로 바뀐다."
    },
    {
      "name": "ValidationSummary",
      "variants": [
        "inline",
        "sticky",
        "dialog"
      ],
      "states": [
        "allValid",
        "hasWarnings",
        "hasBlockingErrors",
        "validating"
      ],
      "guidance": "정상, 확인 필요, 저장 차단 건수를 분리한다. 저장 차단 건수를 누르면 첫 문제 행 또는 충돌 수업으로 이동한다. 저장 버튼 문구에는 해결할 건수를 포함하고, 경고와 저장 차단의 차이를 설명한다."
    },
    {
      "name": "Timetable",
      "variants": [
        "allSchoolsWeek",
        "schoolWeek",
        "instructorWeek",
        "list"
      ],
      "states": [
        "loading",
        "empty",
        "normal",
        "conflict",
        "exception",
        "published",
        "unpublishedChange"
      ],
      "guidance": "데스크톱 격자에는 요일과 실제 시간 축을 사용하고 카드 안에 학교, 교시명, 실제 시각, 과목, 강사를 일정한 순서로 표시한다. 충돌 카드를 선택하면 상대 카드도 강조한다. 모바일에서는 격자를 축소하지 말고 요일별 목록으로 바꾼다."
    },
    {
      "name": "ClassCard",
      "variants": [
        "operator",
        "instructor",
        "comparison"
      ],
      "states": [
        "normal",
        "temporary",
        "published",
        "conflict",
        "exception",
        "changed"
      ],
      "guidance": "운영자용 카드는 학교, 요일·교시, 실제 시각, 과목, 강사를 표시한다. 강사용 카드는 강사명을 생략하고 학교, 요일·교시, 실제 시각, 과목을 우선한다. 충돌과 변경 상태는 아이콘, 상태명, 짧은 이유를 함께 표시한다."
    },
    {
      "name": "ConflictComparePanel",
      "variants": [
        "sidePanel",
        "fullScreenDrawer"
      ],
      "states": [
        "blockedAcrossSchools",
        "sameSchoolExceptionAvailable",
        "editing",
        "revalidating",
        "resolved",
        "newConflictFound"
      ],
      "guidance": "충돌한 두 수업을 동일한 필드 순서로 나란히 보여주고 실제 시간이 겹치는 구간을 시간 막대로 표시한다. 운영자는 수정할 수업을 선택해 강사, 요일, 교시, 실제 시간을 바꾼다. 서로 다른 학교의 시간 중복에는 예외 저장 행동을 절대 제공하지 않는다."
    },
    {
      "name": "ExceptionReasonDialog",
      "variants": [
        "sameSchoolOverlap"
      ],
      "states": [
        "default",
        "invalid",
        "submitting",
        "saved"
      ],
      "guidance": "같은 강사의 같은 학교 시간 겹침에서만 연다. 겹친 두 수업, 예외 적용 범위, 필수 사유 입력란을 표시한다. 저장 후 예외 사유, 처리한 운영자, 처리 시각, 관련 수업 식별값이 남는다는 점을 확인 문구로 알린다."
    },
    {
      "name": "AssignmentForm",
      "variants": [
        "create",
        "edit",
        "inlineConflictEdit"
      ],
      "states": [
        "pristine",
        "dirty",
        "validating",
        "blocked",
        "valid",
        "saving",
        "saved"
      ],
      "guidance": "학교와 학기를 먼저 선택한 뒤 운영 기간, 요일, 교시 또는 실제 시간, 과목, 강사를 입력한다. 교시 선택 시 실제 시각을 읽기 전용으로 함께 보여주고 직접 시간을 선택하면 그 값을 충돌 검사 기준으로 사용한다. 유효한 신규 수업은 임시 배정으로 저장한다."
    },
    {
      "name": "ExcelDropzone",
      "variants": [
        "empty",
        "fileSelected",
        "reading"
      ],
      "states": [
        "idle",
        "dragOver",
        "uploading",
        "unsupported",
        "readFailed",
        "complete"
      ],
      "guidance": "양식 다운로드를 파일 선택보다 먼저 제공한다. 지원 확장자와 최대 파일 크기는 개발 정책 확정 후 문구에 반영한다. 파일은 실제 시간표에 바로 저장하지 않고 임시 데이터로 읽는다고 명시한다."
    },
    {
      "name": "ProcessStepper",
      "variants": [
        "excelImport",
        "onboarding"
      ],
      "states": [
        "upcoming",
        "current",
        "complete",
        "error"
      ],
      "guidance": "엑셀 업로드는 파일 선택, 검토·수정, 확정의 단계로 표시한다. 지정 양식을 사용하므로 첫 개발에서는 임의 열 연결 단계를 만들지 않는다. 현재 단계와 완료된 단계를 색상 외에 숫자와 텍스트로 구분한다."
    },
    {
      "name": "PublishDialog",
      "variants": [
        "initialPublish",
        "publishChanges"
      ],
      "states": [
        "blocked",
        "ready",
        "publishing",
        "success",
        "failed"
      ],
      "guidance": "최초 공개에서는 공개할 학교·학기, 강사 수, 수업 수, 초대 미연결 강사 수를 보여준다. 변경 게시에서는 변경된 수업, 변경 전후 값, 영향을 받는 강사 수를 보여준다. 저장 차단 시간 중복이 있으면 공개 버튼을 비활성화하고 문제 화면으로 이동하는 행동을 제공한다."
    },
    {
      "name": "NotificationItem",
      "variants": [
        "initialPublish",
        "scheduleChange"
      ],
      "states": [
        "unread",
        "read"
      ],
      "guidance": "제목에 학교와 변경 유형을 포함하고 본문에 요일, 교시명, 실제 시간, 과목, 변경 시각을 표시한다. 변경 알림 상세에서는 변경 전후 값 중 달라진 항목만 강조한다. 항목을 열면 읽음 처리하고 해당 개인 시간표 위치로 이동한다."
    },
    {
      "name": "InlineAlert",
      "variants": [
        "info",
        "success",
        "warning",
        "danger"
      ],
      "states": [
        "default",
        "dismissible"
      ],
      "guidance": "오류 코드 대신 무엇이 문제이고 어떻게 해결할지 문장으로 표시한다. 예: 김지민 강사는 월요일 14:00~15:20에 다른 학교 수업에 배정되어 있습니다. 강사 또는 시간을 변경하세요."
    },
    {
      "name": "DialogAndDrawer",
      "variants": [
        "modal",
        "sideDrawer",
        "bottomSheet",
        "fullScreen"
      ],
      "states": [
        "opening",
        "open",
        "closing"
      ],
      "guidance": "데스크톱 비교·수정은 우측 드로어, 모바일은 전체 화면을 사용한다. 열릴 때 제목으로 포커스를 옮기고 닫힐 때 실행한 요소로 포커스를 돌려준다. 저장되지 않은 변경이 있으면 닫기 전에 확인한다."
    },
    {
      "name": "EmptyState",
      "variants": [
        "firstUse",
        "filtered",
        "noPublishedSchedule",
        "noNotifications"
      ],
      "states": [
        "default"
      ],
      "guidance": "첫 사용 상태에는 다음 행동 하나를 제시한다. 필터 결과 없음은 필터 초기화, 공개 시간표 없음은 운영자가 공개한 뒤 표시된다는 설명을 제공한다. 서류, 정산, 대체강사 기능을 암시하는 문구는 사용하지 않는다."
    },
    {
      "name": "Toast",
      "variants": [
        "success",
        "error",
        "info"
      ],
      "states": [
        "visible",
        "dismissed"
      ],
      "guidance": "단순 저장 완료는 토스트로 알리되 공개, 충돌, 업로드 확정처럼 중요한 결과는 화면 안의 지속 메시지도 함께 제공한다. 오류 토스트만으로 입력 오류 위치를 전달하지 않는다."
    }
  ],
  "accessibility": [
    "KWCAG 2.2와 WCAG 2.1 AA를 기준으로 본문과 배경은 4.5:1 이상, 큰 글자와 주요 UI 경계는 3:1 이상의 명도 대비를 확보한다.",
    "시간 중복, 경고, 예외, 공개 상태는 색상만으로 구분하지 않고 아이콘, 상태명, 원인 문구를 함께 제공한다.",
    "모든 상호작용 요소에는 키보드로 접근할 수 있어야 하며 보이는 2px 이상의 포커스 표시를 제공한다.",
    "모바일 터치 대상은 최소 44px × 44px로 하고 인접한 아이콘 버튼 사이에 8px 이상의 간격을 둔다.",
    "입력 오류는 필드 라벨, 오류 문구, aria-describedby로 연결하고 저장 시 첫 오류로 포커스를 이동한다.",
    "엑셀 검토 표는 caption과 열 머리글을 제공하고, 오류 셀의 상태를 스크린 리더가 행 번호와 함께 읽을 수 있게 한다.",
    "편집 가능한 표는 Enter로 편집 시작, Esc로 취소, Tab으로 다음 셀 이동을 지원하며 키보드 사용법을 표 앞에서 안내한다.",
    "충돌 재검증, 저장 완료, 새 오류 발생 결과는 aria-live 영역으로 알리되 같은 메시지를 반복 낭독하지 않는다.",
    "모달과 드로어는 포커스를 내부에 유지하고 제목과 설명을 연결하며 닫힌 뒤 원래 실행 요소로 포커스를 복원한다.",
    "주간 시간표를 시각적 격자로만 제공하지 않고 동일 데이터를 표 보기 또는 요일별 목록으로도 제공한다.",
    "200% 확대와 320px 너비에서도 핵심 조회와 수업 한 건 수정이 가능해야 하며, 화면 전체에 가로 스크롤을 만들지 않는다. 고밀도 표 내부의 가로 스크롤은 허용한다.",
    "날짜와 시간은 한국 표준시 기준의 명확한 형식으로 표시하고 상대 날짜만 사용하지 않는다.",
    "아이콘 버튼에는 접근 가능한 이름을 제공하고 닫기, 편집, 알림처럼 의미가 다른 아이콘을 모양만으로 구분하지 않는다.",
    "동작 줄이기 설정이 켜지면 패널 이동과 상태 전환 애니메이션을 제거하고 즉시 상태를 변경한다."
  ],
  "motion": {
    "durationMs": 180,
    "easing": "cubic-bezier(0.2, 0, 0, 1)",
    "reducedMotion": true
  },
  "darkMode": "not_planned",
  "screenGuidance": [
    {
      "screenId": "operator",
      "guidance": "운영자용 시작 화면이다. 상단에서 현재 학기를 선택하고 학교 등록, 강사 등록, 교시표 설정, 수업 등록, 충돌 해결, 시간표 공개의 준비 상태를 순서대로 보여준다. 본문에는 등록 학교 수, 등록 강사 수, 미해결 시간 중복 수, 임시 배정 수, 마지막 공개 시각을 표시한다. 가장 위험한 미해결 시간 중복을 첫 번째 작업 카드로 두고 전체 시간표로 연결한다. 서류, 대체강사, 정산, 민원, 결제 현황은 첫 개발 화면에 넣지 않는다."
    },
    {
      "screenId": "instructor",
      "guidance": "강사 역할의 모바일 셸이다. 로그인 후 강사 개인 시간표로 바로 이동하고 하단 탐색에는 시간표와 알림함만 제공한다. 읽지 않은 알림 수를 배지로 표시한다. 다른 강사의 시간표, 전체 시간표, 학교·강사 관리, 강사료·재료비·지급 예정액 메뉴는 노출하지 않는다."
    },
    {
      "screenId": "admin-login-start",
      "guidance": "로그인과 업체 시작을 탭 또는 분리된 카드로 제공한다. 업체 시작은 운영자 로그인 정보와 위탁업체명을 필수로 받고, 계정과 위탁업체 생성이 함께 성공했을 때만 완료한다. 오류는 계정 존재 여부를 과도하게 드러내지 않는 문장으로 표시한다. 완료 후 학교·강사 목록 관리 화면으로 이동하며 첫 학교와 강사를 등록하라는 안내를 보여준다."
    },
    {
      "screenId": "school-instructor-list",
      "guidance": "학교와 강사를 상단 탭으로 분리한다. 각 탭에는 검색, 등록 버튼, 목록, 수정 행동을 제공한다. 학교 행에는 학교명, 등록된 학기·교시 템플릿 상태, 연결된 수업 수를 표시하고 학기·교시표 설정으로 이동하는 버튼을 둔다. 강사 행에는 이름, 구분용 휴대폰번호 뒤 4자리, 초대 전·초대 발송·연결 완료 상태를 표시한다. 이름이 같은 강사를 합치지 않으며 고유 식별값으로 구분한다. 모바일에서는 표를 카드 목록으로 전환한다."
    },
    {
      "screenId": "class-assignment",
      "guidance": "학교와 학기를 먼저 선택한 뒤 운영 기간, 요일, 교시 또는 시작·종료 시각, 과목, 담당 강사를 입력한다. 교시를 선택하면 실제 시간을 바로 아래에 표시한다. 입력값이 바뀔 때 화면에서 즉시 검증하고 저장 요청 시 서버에서 다시 검사한다. 서로 다른 학교의 동일 강사 시간 중복은 저장 버튼을 막고 충돌 비교 패널을 연다. 같은 학교 시간 겹침은 예외 사유 입력 행동을 제공한다. 정상 신규 수업은 임시 배정으로 저장하며, 공개된 수업 수정은 변경 미게시 상태로 두어 기존 공개본이 강사 화면에서 유지되게 한다."
    },
    {
      "screenId": "excel-import-preview",
      "guidance": "상단에 양식 다운로드, 파일 선택, 검토·수정, 확정 단계를 표시한다. 업로드 파일은 임시 데이터로만 읽고 총 행, 정상, 확인 필요, 저장 차단 건수를 고정 요약 영역에 표시한다. 표에는 상태, 엑셀 행, 학교, 운영 기간, 요일, 교시명, 시작, 종료, 과목, 강사, 검증 결과를 배치한다. 등록되지 않은 학교, 모호한 강사, 비어 있는 시간, 잘못된 종료 시각과 시간 중복은 문제 셀에서 직접 수정한다. 동명이인은 후보를 직접 선택하게 하고 교시명으로 시간을 찾을 수 없으면 교시표 설정 또는 직접 시간 입력으로 연결한다. 수정 후 관련 행을 재검증하며 모든 저장 차단 오류가 해결되어야 전체 확정 버튼을 사용할 수 있다. 확정 직전 서버에서 다시 충돌을 검사하고 새 충돌이 생기면 해당 엑셀 행으로 되돌린다."
    },
    {
      "screenId": "master-timetable",
      "guidance": "운영자의 핵심 작업 화면이다. 상단에 학기, 학교, 강사, 요일, 상태 필터와 주간 보기·표 보기·충돌만 보기 전환을 둔다. 데스크톱에서는 전체 시간표 왼쪽과 420~480px 우측 충돌 비교 패널을 함께 보여준다. 충돌 카드를 선택하면 상대 수업도 강조하고 두 수업의 학교, 운영 기간, 요일, 교시, 실제 시간, 과목, 강사를 나란히 표시한다. 한쪽 수업을 선택해 강사, 요일, 교시 또는 실제 시간을 수정한 뒤 즉시 재검증한다. 서로 다른 학교의 시간 중복은 해결 전 저장과 공개를 막는다. 같은 학교 예외 저장 건에는 사유와 처리 이력을 볼 수 있는 보라색 상태 배지를 표시한다. 공개 버튼을 누르면 공개 차단 오류, 공개 대상 학교·강사·수업 수, 초대 미연결 강사 수를 확인한다. 최초 공개와 변경 게시를 구분하고 성공 후 공개본 식별값과 공개 시각을 화면에 표시한다."
    },
    {
      "screenId": "instructor-timetable",
      "guidance": "강사에게 최신 공개본만 보여준다. 모바일 기본은 요일별 목록이며 상단에 학기와 운영 기간을 표시한다. 각 수업은 요일, 교시명, 실제 시작·종료 시각, 학교, 과목 순으로 보여준다. 여러 학교의 수업을 학교 색상만으로 구분하지 말고 학교명을 반복 표시한다. 변경 알림에서 진입하면 해당 수업으로 스크롤하고 잠시 강조한다. 공개된 수업이 없으면 운영자가 시간표를 공개한 뒤 확인할 수 있다는 빈 상태를 제공한다. 임시 배정과 변경 미게시 내용은 노출하지 않는다."
    },
    {
      "screenId": "instructor-notifications",
      "guidance": "읽지 않음과 전체 필터를 제공하고 최신 알림부터 정렬한다. 최초 공개 알림에는 공개된 학기, 수업 수, 공개 시각을 표시한다. 변경 알림에는 변경된 학교, 요일, 교시명, 실제 시간, 과목, 변경 시각을 포함한다. 상세를 열면 변경 전후 값 중 달라진 항목을 나란히 보여주고 읽음 처리한다. 시간표 보기 버튼은 해당 개인 시간표 위치로 이동한다. 첫 개발에는 확인했습니다, 진행이 어렵습니다, 카카오톡 발송 기능을 추가하지 않는다."
    },
    {
      "screenId": "school-term-period-settings",
      "guidance": "왼쪽 또는 상단에서 학교와 학기를 선택하고 학기 운영 기간을 설정한다. 교시 템플릿 카드에는 템플릿명, 적용 기간, 요일을 표시하고 내부 교시표는 교시명, 시작 시각, 종료 시각을 편집 가능한 행으로 구성한다. 종료 시각이 시작 시각과 같거나 빠르면 해당 행 저장을 막는다. 동일한 학교·학기·요일·적용 범위에서 어떤 교시 템플릿을 써야 하는지 하나로 결정할 수 없으면 충돌한 템플릿을 함께 표시한다. 가정에 따라 첫 개발에서는 교시 템플릿을 수정해도 이미 저장된 수업의 실제 시간은 자동 변경하지 않는다. 저장 전에 기존 수업 수를 보여주고 기존 수업은 현재 실제 시간을 유지한다는 확인 문구를 제공한다."
    },
    {
      "screenId": "instructor-login-invite",
      "guidance": "초대 링크의 위탁업체명과 연결 대상 강사 이름을 표시하고 계정 만들기 또는 기존 계정 로그인을 선택하게 한다. 개인정보는 필요한 범위만 마스킹해 보여준다. 연결 완료 전에는 개인 시간표와 알림함으로 진입할 수 없다. 만료, 이미 사용됨, 대상 정보 불일치, 권한 없음 상태를 각각 구분하고 운영자에게 새 초대를 요청하는 방법을 안내한다. 성공 시 연결된 위탁업체와 강사 정보를 확인한 뒤 강사 개인 시간표로 이동한다."
    }
  ],
  "assets": [
    "가정: 별도 브랜드 자산이 없으므로 첫 개발에서는 텍스트 워드마크 ‘방과후 운영 한눈에’를 사용한다.",
    "학교, 강사, 시간표, 엑셀, 충돌, 알림, 공개 상태를 표현하는 일관된 20px·24px SVG 선형 아이콘 세트",
    "현재 지원 열 이름과 입력 예시가 포함된 시간표 엑셀 양식 파일",
    "업로드 빈 상태, 공개 시간표 없음, 알림 없음에 사용할 단순한 단색 SVG 일러스트레이션",
    "시간 중복 비교용 시간 막대와 겹침 구간 SVG",
    "로딩 중 표와 시간표에 사용할 스켈레톤 자산",
    "민감한 서류 원본을 연상시키는 업로드 자산은 첫 개발 범위에서 제외한다.",
    "아이콘 라이브러리와 워드마크의 최종 라이선스는 구현 전 확인 필요"
  ],
  "sources": [
    {
      "title": "교육부 > 정책 > 초·중·고 교육 > 초등돌봄·교육",
      "url": "https://www.moe.go.kr/boardCnts/viewRenew.do?boardID=72782&boardSeq=105180&lev=0&m=030215&opType=N&page=1&s=moe&statusYN=W&utm_source=openai",
      "note": "방과후·늘봄 운영 맥락과 학교 단위 업무 용어를 확인하는 근거로 사용했다."
    },
    {
      "title": "2026 방과후학교 업체위탁 실무 가이드북",
      "url": "https://www.goe.go.kr/resource/goe/na/bbs_2675/2025/09/29a0af61-3f89-4078-92b9-99b7befa8d7f.pdf?utm_source=openai",
      "note": "위탁업체가 학교별로 운영 조건과 시간표를 관리하는 업무 흐름의 근거로 사용했다."
    },
    {
      "title": "카카오톡 예약하기에서 그려 본 캘린더",
      "url": "https://tech.kakao.com/posts/820?utm_source=openai",
      "note": "시간 축 기반 일정 표현과 모바일·데스크톱 캘린더 상호작용을 참고했다."
    },
    {
      "title": "직원들에게 근무 스케줄 공유하기",
      "url": "https://mini-guide.flex.team/ko/articles/10632776-%EC%A7%81%EC%9B%90%EB%93%A4%EC%97%90%EA%B2%8C-%EA%B7%BC%EB%AC%B4-%EC%8A%A4%EC%BC%80%EC%A4%84-%EA%B3%B5%EC%9C%A0%ED%95%98%EA%B8%B0?utm_source=openai",
      "note": "운영자가 확정된 일정을 구성원에게 공개하는 흐름을 참고했다."
    },
    {
      "title": "모바일 환경에서도 완벽한 인력관리 | 시프티",
      "url": "https://shiftee.io/ko/mobile-app?utm_source=openai",
      "note": "강사가 이동 중 개인 일정과 알림을 확인하는 모바일 정보 우선순위를 참고했다."
    },
    {
      "title": "원클릭시간표 — 새 학기 준비, 반나절.",
      "url": "https://www.oneclicktimetable.com/?utm_source=openai",
      "note": "주간 시간표, 충돌 중심 검토, 새 학기 편성 화면의 업종 사례로 참고했다."
    },
    {
      "title": "PowerPoint 프레젠테이션",
      "url": "https://rtms.molit.go.kr/menualDownload/rtms/rtmsManualDownload.pdf?utm_source=openai",
      "note": "한국 행정형 서비스의 파일 업로드, 미리보기, 오류 확인 절차를 참고했다."
    },
    {
      "title": "건강보험심사평가원 업무 안내 자료",
      "url": "https://www.hira.or.kr/bbs/157/2025/05/BZ202505261650192.pdf?utm_source=openai",
      "note": "고밀도 표에서 행 상태와 오류를 구분하는 행정 업무 UI 사례로 참고했다."
    },
    {
      "title": "게시글 재알림 - 네이버웍스",
      "url": "https://help.worksmobile.com/ko/use-guides/board/check-post/send-notification/?utm_source=openai",
      "note": "알림 목록의 읽음 상태와 영향받는 사용자 중심 안내 구조를 참고했다."
    },
    {
      "title": "Web Content Accessibility Guidelines 2.1",
      "url": "https://www.w3.org/TR/WCAG21/",
      "note": "색상 대비, 키보드 접근, 포커스, 오류 안내 등 접근성 구현 기준으로 사용했다."
    }
  ]
}
디자인 가이드 원문 전체 보기

UI/UX 디자인 가이드

1. 디자인 방향

운영자에게는 엑셀처럼 빠르게 훑고 수정할 수 있는 고밀도 업무 화면을 제공하고, 강사에게는 이동 중 최신 확정 시간표와 변경 알림을 빠르게 확인하는 모바일 중심 화면을 제공한다. 운영자 화면은 학교·학기·운영 기간의 맥락을 항상 유지하며, 시간 중복을 빨간색에만 의존하지 않고 충돌한 두 수업과 해결 행동을 함께 보여준다. 공개 전 편집본과 강사에게 보이는 공개본을 분리해 저장과 공개를 혼동하지 않게 한다.

무드 키워드: 정확한 시간표 · 충돌 우선 · 엑셀 친화적 · 학교별 실제 시간 · 행 단위 수정 · 공개본 분리 · 운영자 고밀도 · 강사 모바일 확인 · 차분한 교육 행정 · 명확한 상태 표시

업계 조사에서 반영한 점

  • 운영자는 학기 시작 전 여러 학교와 강사의 배정을 한꺼번에 검토하므로 주간 시간표, 표 보기, 문제 목록을 오갈 수 있어야 한다.
  • 학교마다 같은 교시명의 실제 시작·종료 시각이 다를 수 있으므로 모든 시간표 카드와 충돌 화면에 교시명과 실제 시각을 함께 표시해야 한다.
  • 시간 중복은 같은 요일, 겹치는 운영 기간, 실제 시작·종료 시각을 함께 검사해야 하며 14:00~14:40과 14:40~15:20은 겹치지 않는 것으로 표시한다.
  • 엑셀 업로드는 실패 안내로 끝내지 않고 원본 엑셀 행 번호, 문제 셀, 오류 이유, 바로 수정할 입력 요소를 같은 표 안에 제공해야 한다.
  • 충돌 경고는 충돌한 두 수업의 학교, 운영 기간, 요일, 교시, 실제 시간, 과목, 강사를 나란히 보여줘야 해결 속도가 높아진다.
  • 서로 다른 학교에서 발생한 동일 강사의 시간 중복은 예외 없이 저장을 막고, 같은 학교 안의 시간 겹침만 사유를 남긴 경우 예외 저장할 수 있어야 한다.
  • 강사는 전체 시간표보다 자신의 최신 공개 시간표와 변경 알림을 우선 확인하므로 모바일에서는 요일별 목록과 알림함을 핵심 탐색 구조로 사용한다.
  • 조사 자료에는 이동시간 부족, 서류 상태, 대체강사, 확인 응답 기능이 제안되어 있으나 첫 개발 범위에서는 화면과 상태에 포함하지 않는다.
  • 시간표 저장과 강사 공개를 분리하고, 공개 후 수정은 변경 전후 값과 영향을 받는 강사를 확인한 뒤 게시해야 강사에게 미완성 편집 내용이 노출되지 않는다.
  • 운영자 화면은 데스크톱에서 상시 사용하는 고밀도 표와 비교 패널이 핵심이지만, 좁은 화면에서도 문제 목록 조회와 수업 한 건 수정은 가능해야 한다.

2. 레이아웃 전략

  • 방식: Desktop first
  • 근거: 운영자의 핵심 업무가 여러 학교·강사의 시간표를 고밀도 표와 주간 격자에서 비교하고, 충돌한 두 수업을 동시에 펼쳐 수정하는 작업이므로 desktop_first가 적합하다. 기본 운영 화면은 1280px 이상에서 사이드바, 작업 영역, 우측 비교 패널을 함께 사용한다. 1024px 미만에서는 비교 패널을 전체 화면 드로어로 전환하고, 768px 미만에서는 시간표 격자보다 문제 목록과 요일별 카드 목록을 우선 제공한다. 강사 화면은 같은 웹 서비스 안에서 별도로 모바일에 최적화한다.
  • 좁은 화면에서도 핵심 조회·입력·처리를 제거하지 않습니다.
  • 최대 콘텐츠 폭: 1440px
  • 그리드: 모바일 4열 / 데스크톱 12열 / 기본 단위 4px
  • Breakpoint: sm 640px, md 768px, lg 1024px, xl 1280px

3. 컬러 시스템

토큰용도
Primary#1D4ED8주요 버튼, 선택된 탐색 항목, 링크, 현재 단계와 포커스 보조 표시
PrimaryHover#1E40AF주요 버튼과 링크의 hover 및 pressed 상태
PrimarySoft#EFF6FF선택된 행, 정보 배너, 공개 상태의 약한 배경
TextPrimary#101828제목, 본문, 표의 주요 값
TextSecondary#475467보조 설명, 메타 정보, 비활성에 가깝지만 읽어야 하는 텍스트
Canvas#F7F8FA운영자 화면의 전체 배경
Surface#FFFFFF카드, 표, 모달, 드로어와 입력 영역
Border#D0D5DD표 구분선, 입력 테두리, 카드 경계
Disabled#EAECF0비활성 입력과 버튼 배경
Success#067647정상 검증, 저장 완료, 초대 연결 완료
SuccessSoft#ECFDF3정상 행과 완료 상태의 약한 배경
Warning#B54708확인 필요, 교시명과 실제 시간 불일치, 공개 전 확인 항목
WarningSoft#FFFAEB경고 배너와 확인 필요 셀 배경
Danger#B42318저장 차단, 시간 중복, 필수값 오류, 삭제 확인
DangerSoft#FEF3F2문제 셀, 충돌 카드와 오류 요약 배경
Exception#5925DC같은 학교 시간 겹침의 예외 저장 상태와 이력
ExceptionSoft#F4F3FF예외 사유 영역과 예외 저장 배지 배경

상태는 색상만으로 구분하지 않고 아이콘·문구·테두리를 함께 사용합니다.

4. 타이포그래피

  • 한글 기본: Pretendard Variable
  • 대체 글꼴: Pretendard, -apple-system, BlinkMacSystemFont, Segoe UI, Noto Sans KR, sans-serif
  • 본문 자간: -0.01em
  • 제목 자간: -0.025em
  • 본문 행간: 1.5

5. 간격·형태

  • 간격: 4px, 8px, 12px, 16px, 20px, 24px, 32px, 40px, 48px, 64px, 80px
  • 모서리: sm 6px, md 10px, lg 16px, full 9999px

6. 컴포넌트와 상태

AppShell

  • 변형: operator, instructor
  • 상태: default, sidebarCollapsed, mobileNavigationOpen
  • 적용: operator는 240px 좌측 사이드바, 상단 업체·학기 맥락 영역, 본문으로 구성한다. 1280px 이상에서 충돌 비교 패널이 열리면 본문과 나란히 배치한다. instructor는 모바일 하단 탐색에 시간표와 알림함만 노출하고 운영자 메뉴는 렌더링하지 않는다.

PageHeader

  • 변형: standard, withContext, withPrimaryAction
  • 상태: default, sticky
  • 적용: 화면명 아래에 선택한 학교, 학기, 운영 기간을 표시한다. 저장·공개처럼 결과가 다른 행동은 같은 문구로 합치지 않는다. 고밀도 화면에서는 필터와 주요 행동을 스크롤 중에도 사용할 수 있도록 상단을 고정한다.

OperatorNavigation

  • 변형: expanded, collapsed, mobileDrawer
  • 상태: default, active, disabled
  • 적용: 운영자 화면, 학교·강사, 학기·교시표, 수업 등록, 엑셀 업로드, 전체 시간표 순으로 배치한다. 첫 개발에서 제외된 서류, 대체강사, 정산, 민원, 결제 메뉴는 노출하지 않는다.

Button

  • 변형: primary, secondary, tertiary, danger, icon
  • 상태: default, hover, focus, pressed, loading, disabled
  • 적용: 기본 높이는 데스크톱 40px, 모바일 44px 이상으로 한다. 버튼은 저장, 검증, 확정, 공개를 구분해 구체적인 동사를 사용한다. 비활성 버튼 주변에는 비활성 이유를 문장으로 제공한다.

Field

  • 변형: text, select, combobox, date, dateRange, time, textarea
  • 상태: default, hover, focus, filled, error, warning, disabled, readonly
  • 적용: 모든 입력은 화면에 남는 라벨을 사용한다. 필수값은 라벨과 오류 문구로 안내한다. 시간 입력은 9, 0900, 09:00을 허용하되 포커스가 빠지면 HH:mm으로 정규화한다. 종료 시각이 시작 시각과 같거나 빠르면 해당 필드 아래에 즉시 오류를 표시한다.

EntityCombobox

  • 변형: school, instructor, term, subject
  • 상태: default, searching, noResult, ambiguous, selected, error
  • 적용: 학교와 강사는 표시 이름이 아니라 고유 식별값을 저장한다. 동명이인 강사 선택 시 휴대폰번호 뒤 4자리와 내부 식별 정보를 함께 보여주되 전체 연락처는 노출하지 않는다. 엑셀 업로드의 모호한 이름은 운영자가 선택하기 전까지 확정하지 않는다.

StatusBadge

  • 변형: temporary, confirmed, published, unpublishedChange, normal, needsReview, blocked, exception, invited, connected
  • 상태: default
  • 적용: 색상과 함께 임시 배정, 확정 시간표, 공개됨, 변경 미게시, 저장 차단, 예외 저장처럼 상태명을 항상 표시한다. 한 화면에서 같은 의미의 상태명과 색상을 일관되게 유지한다.

FilterBar

  • 변형: inline, responsiveDrawer
  • 상태: default, filtered, expanded
  • 적용: 학교, 학기, 운영 기간, 강사, 요일, 상태 필터를 제공하고 적용 중인 조건을 칩으로 표시한다. 문제 해결 화면에서는 충돌만 보기와 예외 저장 보기의 우선순위를 높인다. 모바일에서는 필터를 드로어로 열고 적용된 조건 수를 버튼에 표시한다.

EditableDataGrid

  • 변형: standard, excelPreview, compact
  • 상태: loading, empty, normal, rowSelected, cellEditing, cellError, rowBlocked, rowRevalidating
  • 적용: 헤더와 엑셀 행 번호 열을 고정하고 가로 스크롤을 허용한다. 오류는 행 전체가 아니라 문제 셀에 DangerSoft 배경, 테두리, 아이콘, 문구로 표시한다. Enter로 편집, Esc로 취소, Tab으로 다음 편집 셀 이동이 가능해야 한다. 수정한 행은 재검증 중 상태를 거쳐야 정상으로 바뀐다.

ValidationSummary

  • 변형: inline, sticky, dialog
  • 상태: allValid, hasWarnings, hasBlockingErrors, validating
  • 적용: 정상, 확인 필요, 저장 차단 건수를 분리한다. 저장 차단 건수를 누르면 첫 문제 행 또는 충돌 수업으로 이동한다. 저장 버튼 문구에는 해결할 건수를 포함하고, 경고와 저장 차단의 차이를 설명한다.

Timetable

  • 변형: allSchoolsWeek, schoolWeek, instructorWeek, list
  • 상태: loading, empty, normal, conflict, exception, published, unpublishedChange
  • 적용: 데스크톱 격자에는 요일과 실제 시간 축을 사용하고 카드 안에 학교, 교시명, 실제 시각, 과목, 강사를 일정한 순서로 표시한다. 충돌 카드를 선택하면 상대 카드도 강조한다. 모바일에서는 격자를 축소하지 말고 요일별 목록으로 바꾼다.

ClassCard

  • 변형: operator, instructor, comparison
  • 상태: normal, temporary, published, conflict, exception, changed
  • 적용: 운영자용 카드는 학교, 요일·교시, 실제 시각, 과목, 강사를 표시한다. 강사용 카드는 강사명을 생략하고 학교, 요일·교시, 실제 시각, 과목을 우선한다. 충돌과 변경 상태는 아이콘, 상태명, 짧은 이유를 함께 표시한다.

ConflictComparePanel

  • 변형: sidePanel, fullScreenDrawer
  • 상태: blockedAcrossSchools, sameSchoolExceptionAvailable, editing, revalidating, resolved, newConflictFound
  • 적용: 충돌한 두 수업을 동일한 필드 순서로 나란히 보여주고 실제 시간이 겹치는 구간을 시간 막대로 표시한다. 운영자는 수정할 수업을 선택해 강사, 요일, 교시, 실제 시간을 바꾼다. 서로 다른 학교의 시간 중복에는 예외 저장 행동을 절대 제공하지 않는다.

ExceptionReasonDialog

  • 변형: sameSchoolOverlap
  • 상태: default, invalid, submitting, saved
  • 적용: 같은 강사의 같은 학교 시간 겹침에서만 연다. 겹친 두 수업, 예외 적용 범위, 필수 사유 입력란을 표시한다. 저장 후 예외 사유, 처리한 운영자, 처리 시각, 관련 수업 식별값이 남는다는 점을 확인 문구로 알린다.

AssignmentForm

  • 변형: create, edit, inlineConflictEdit
  • 상태: pristine, dirty, validating, blocked, valid, saving, saved
  • 적용: 학교와 학기를 먼저 선택한 뒤 운영 기간, 요일, 교시 또는 실제 시간, 과목, 강사를 입력한다. 교시 선택 시 실제 시각을 읽기 전용으로 함께 보여주고 직접 시간을 선택하면 그 값을 충돌 검사 기준으로 사용한다. 유효한 신규 수업은 임시 배정으로 저장한다.

ExcelDropzone

  • 변형: empty, fileSelected, reading
  • 상태: idle, dragOver, uploading, unsupported, readFailed, complete
  • 적용: 양식 다운로드를 파일 선택보다 먼저 제공한다. 지원 확장자와 최대 파일 크기는 개발 정책 확정 후 문구에 반영한다. 파일은 실제 시간표에 바로 저장하지 않고 임시 데이터로 읽는다고 명시한다.

ProcessStepper

  • 변형: excelImport, onboarding
  • 상태: upcoming, current, complete, error
  • 적용: 엑셀 업로드는 파일 선택, 검토·수정, 확정의 단계로 표시한다. 지정 양식을 사용하므로 첫 개발에서는 임의 열 연결 단계를 만들지 않는다. 현재 단계와 완료된 단계를 색상 외에 숫자와 텍스트로 구분한다.

PublishDialog

  • 변형: initialPublish, publishChanges
  • 상태: blocked, ready, publishing, success, failed
  • 적용: 최초 공개에서는 공개할 학교·학기, 강사 수, 수업 수, 초대 미연결 강사 수를 보여준다. 변경 게시에서는 변경된 수업, 변경 전후 값, 영향을 받는 강사 수를 보여준다. 저장 차단 시간 중복이 있으면 공개 버튼을 비활성화하고 문제 화면으로 이동하는 행동을 제공한다.

NotificationItem

  • 변형: initialPublish, scheduleChange
  • 상태: unread, read
  • 적용: 제목에 학교와 변경 유형을 포함하고 본문에 요일, 교시명, 실제 시간, 과목, 변경 시각을 표시한다. 변경 알림 상세에서는 변경 전후 값 중 달라진 항목만 강조한다. 항목을 열면 읽음 처리하고 해당 개인 시간표 위치로 이동한다.

InlineAlert

  • 변형: info, success, warning, danger
  • 상태: default, dismissible
  • 적용: 오류 코드 대신 무엇이 문제이고 어떻게 해결할지 문장으로 표시한다. 예: 김지민 강사는 월요일 14:00~15:20에 다른 학교 수업에 배정되어 있습니다. 강사 또는 시간을 변경하세요.

DialogAndDrawer

  • 변형: modal, sideDrawer, bottomSheet, fullScreen
  • 상태: opening, open, closing
  • 적용: 데스크톱 비교·수정은 우측 드로어, 모바일은 전체 화면을 사용한다. 열릴 때 제목으로 포커스를 옮기고 닫힐 때 실행한 요소로 포커스를 돌려준다. 저장되지 않은 변경이 있으면 닫기 전에 확인한다.

EmptyState

  • 변형: firstUse, filtered, noPublishedSchedule, noNotifications
  • 상태: default
  • 적용: 첫 사용 상태에는 다음 행동 하나를 제시한다. 필터 결과 없음은 필터 초기화, 공개 시간표 없음은 운영자가 공개한 뒤 표시된다는 설명을 제공한다. 서류, 정산, 대체강사 기능을 암시하는 문구는 사용하지 않는다.

Toast

  • 변형: success, error, info
  • 상태: visible, dismissed
  • 적용: 단순 저장 완료는 토스트로 알리되 공개, 충돌, 업로드 확정처럼 중요한 결과는 화면 안의 지속 메시지도 함께 제공한다. 오류 토스트만으로 입력 오류 위치를 전달하지 않는다.

7. 화면별 적용

operator · 운영자 화면

운영자용 시작 화면이다. 상단에서 현재 학기를 선택하고 학교 등록, 강사 등록, 교시표 설정, 수업 등록, 충돌 해결, 시간표 공개의 준비 상태를 순서대로 보여준다. 본문에는 등록 학교 수, 등록 강사 수, 미해결 시간 중복 수, 임시 배정 수, 마지막 공개 시각을 표시한다. 가장 위험한 미해결 시간 중복을 첫 번째 작업 카드로 두고 전체 시간표로 연결한다. 서류, 대체강사, 정산, 민원, 결제 현황은 첫 개발 화면에 넣지 않는다.

instructor · 강사 개인 화면

강사 역할의 모바일 셸이다. 로그인 후 강사 개인 시간표로 바로 이동하고 하단 탐색에는 시간표와 알림함만 제공한다. 읽지 않은 알림 수를 배지로 표시한다. 다른 강사의 시간표, 전체 시간표, 학교·강사 관리, 강사료·재료비·지급 예정액 메뉴는 노출하지 않는다.

admin-login-start · 운영자 로그인 및 업체 시작 화면

로그인과 업체 시작을 탭 또는 분리된 카드로 제공한다. 업체 시작은 운영자 로그인 정보와 위탁업체명을 필수로 받고, 계정과 위탁업체 생성이 함께 성공했을 때만 완료한다. 오류는 계정 존재 여부를 과도하게 드러내지 않는 문장으로 표시한다. 완료 후 학교·강사 목록 관리 화면으로 이동하며 첫 학교와 강사를 등록하라는 안내를 보여준다.

school-instructor-list · 학교·강사 목록 관리 화면

학교와 강사를 상단 탭으로 분리한다. 각 탭에는 검색, 등록 버튼, 목록, 수정 행동을 제공한다. 학교 행에는 학교명, 등록된 학기·교시 템플릿 상태, 연결된 수업 수를 표시하고 학기·교시표 설정으로 이동하는 버튼을 둔다. 강사 행에는 이름, 구분용 휴대폰번호 뒤 4자리, 초대 전·초대 발송·연결 완료 상태를 표시한다. 이름이 같은 강사를 합치지 않으며 고유 식별값으로 구분한다. 모바일에서는 표를 카드 목록으로 전환한다.

class-assignment · 학교별 수업 및 강사 배정 등록 화면

학교와 학기를 먼저 선택한 뒤 운영 기간, 요일, 교시 또는 시작·종료 시각, 과목, 담당 강사를 입력한다. 교시를 선택하면 실제 시간을 바로 아래에 표시한다. 입력값이 바뀔 때 화면에서 즉시 검증하고 저장 요청 시 서버에서 다시 검사한다. 서로 다른 학교의 동일 강사 시간 중복은 저장 버튼을 막고 충돌 비교 패널을 연다. 같은 학교 시간 겹침은 예외 사유 입력 행동을 제공한다. 정상 신규 수업은 임시 배정으로 저장하며, 공개된 수업 수정은 변경 미게시 상태로 두어 기존 공개본이 강사 화면에서 유지되게 한다.

excel-import-preview · 엑셀 업로드 확인 및 수정 화면

상단에 양식 다운로드, 파일 선택, 검토·수정, 확정 단계를 표시한다. 업로드 파일은 임시 데이터로만 읽고 총 행, 정상, 확인 필요, 저장 차단 건수를 고정 요약 영역에 표시한다. 표에는 상태, 엑셀 행, 학교, 운영 기간, 요일, 교시명, 시작, 종료, 과목, 강사, 검증 결과를 배치한다. 등록되지 않은 학교, 모호한 강사, 비어 있는 시간, 잘못된 종료 시각과 시간 중복은 문제 셀에서 직접 수정한다. 동명이인은 후보를 직접 선택하게 하고 교시명으로 시간을 찾을 수 없으면 교시표 설정 또는 직접 시간 입력으로 연결한다. 수정 후 관련 행을 재검증하며 모든 저장 차단 오류가 해결되어야 전체 확정 버튼을 사용할 수 있다. 확정 직전 서버에서 다시 충돌을 검사하고 새 충돌이 생기면 해당 엑셀 행으로 되돌린다.

master-timetable · 전체 시간표와 중복 배정 경고 화면

운영자의 핵심 작업 화면이다. 상단에 학기, 학교, 강사, 요일, 상태 필터와 주간 보기·표 보기·충돌만 보기 전환을 둔다. 데스크톱에서는 전체 시간표 왼쪽과 420~480px 우측 충돌 비교 패널을 함께 보여준다. 충돌 카드를 선택하면 상대 수업도 강조하고 두 수업의 학교, 운영 기간, 요일, 교시, 실제 시간, 과목, 강사를 나란히 표시한다. 한쪽 수업을 선택해 강사, 요일, 교시 또는 실제 시간을 수정한 뒤 즉시 재검증한다. 서로 다른 학교의 시간 중복은 해결 전 저장과 공개를 막는다. 같은 학교 예외 저장 건에는 사유와 처리 이력을 볼 수 있는 보라색 상태 배지를 표시한다. 공개 버튼을 누르면 공개 차단 오류, 공개 대상 학교·강사·수업 수, 초대 미연결 강사 수를 확인한다. 최초 공개와 변경 게시를 구분하고 성공 후 공개본 식별값과 공개 시각을 화면에 표시한다.

instructor-timetable · 강사 개인 시간표 화면

강사에게 최신 공개본만 보여준다. 모바일 기본은 요일별 목록이며 상단에 학기와 운영 기간을 표시한다. 각 수업은 요일, 교시명, 실제 시작·종료 시각, 학교, 과목 순으로 보여준다. 여러 학교의 수업을 학교 색상만으로 구분하지 말고 학교명을 반복 표시한다. 변경 알림에서 진입하면 해당 수업으로 스크롤하고 잠시 강조한다. 공개된 수업이 없으면 운영자가 시간표를 공개한 뒤 확인할 수 있다는 빈 상태를 제공한다. 임시 배정과 변경 미게시 내용은 노출하지 않는다.

instructor-notifications · 강사 알림함 화면

읽지 않음과 전체 필터를 제공하고 최신 알림부터 정렬한다. 최초 공개 알림에는 공개된 학기, 수업 수, 공개 시각을 표시한다. 변경 알림에는 변경된 학교, 요일, 교시명, 실제 시간, 과목, 변경 시각을 포함한다. 상세를 열면 변경 전후 값 중 달라진 항목을 나란히 보여주고 읽음 처리한다. 시간표 보기 버튼은 해당 개인 시간표 위치로 이동한다. 첫 개발에는 확인했습니다, 진행이 어렵습니다, 카카오톡 발송 기능을 추가하지 않는다.

school-term-period-settings · 학교별 학기·교시표 설정 화면

왼쪽 또는 상단에서 학교와 학기를 선택하고 학기 운영 기간을 설정한다. 교시 템플릿 카드에는 템플릿명, 적용 기간, 요일을 표시하고 내부 교시표는 교시명, 시작 시각, 종료 시각을 편집 가능한 행으로 구성한다. 종료 시각이 시작 시각과 같거나 빠르면 해당 행 저장을 막는다. 동일한 학교·학기·요일·적용 범위에서 어떤 교시 템플릿을 써야 하는지 하나로 결정할 수 없으면 충돌한 템플릿을 함께 표시한다. 가정에 따라 첫 개발에서는 교시 템플릿을 수정해도 이미 저장된 수업의 실제 시간은 자동 변경하지 않는다. 저장 전에 기존 수업 수를 보여주고 기존 수업은 현재 실제 시간을 유지한다는 확인 문구를 제공한다.

instructor-login-invite · 강사 로그인 및 초대 연결 화면

초대 링크의 위탁업체명과 연결 대상 강사 이름을 표시하고 계정 만들기 또는 기존 계정 로그인을 선택하게 한다. 개인정보는 필요한 범위만 마스킹해 보여준다. 연결 완료 전에는 개인 시간표와 알림함으로 진입할 수 없다. 만료, 이미 사용됨, 대상 정보 불일치, 권한 없음 상태를 각각 구분하고 운영자에게 새 초대를 요청하는 방법을 안내한다. 성공 시 연결된 위탁업체와 강사 정보를 확인한 뒤 강사 개인 시간표로 이동한다.

8. 에셋과 모션

  • 가정: 별도 브랜드 자산이 없으므로 첫 개발에서는 텍스트 워드마크 ‘방과후 운영 한눈에’를 사용한다.
  • 학교, 강사, 시간표, 엑셀, 충돌, 알림, 공개 상태를 표현하는 일관된 20px·24px SVG 선형 아이콘 세트
  • 현재 지원 열 이름과 입력 예시가 포함된 시간표 엑셀 양식 파일
  • 업로드 빈 상태, 공개 시간표 없음, 알림 없음에 사용할 단순한 단색 SVG 일러스트레이션
  • 시간 중복 비교용 시간 막대와 겹침 구간 SVG
  • 로딩 중 표와 시간표에 사용할 스켈레톤 자산
  • 민감한 서류 원본을 연상시키는 업로드 자산은 첫 개발 범위에서 제외한다.
  • 아이콘 라이브러리와 워드마크의 최종 라이선스는 구현 전 확인 필요
  • 기본 전환: 180ms cubic-bezier(0.2, 0, 0, 1)
  • prefers-reduced-motion 사용자는 불필요한 움직임을 제거합니다.
  • 다크모드: 초기 범위에서 제외

9. 접근성

  • KWCAG 2.2와 WCAG 2.1 AA를 기준으로 본문과 배경은 4.5:1 이상, 큰 글자와 주요 UI 경계는 3:1 이상의 명도 대비를 확보한다.
  • 시간 중복, 경고, 예외, 공개 상태는 색상만으로 구분하지 않고 아이콘, 상태명, 원인 문구를 함께 제공한다.
  • 모든 상호작용 요소에는 키보드로 접근할 수 있어야 하며 보이는 2px 이상의 포커스 표시를 제공한다.
  • 모바일 터치 대상은 최소 44px × 44px로 하고 인접한 아이콘 버튼 사이에 8px 이상의 간격을 둔다.
  • 입력 오류는 필드 라벨, 오류 문구, aria-describedby로 연결하고 저장 시 첫 오류로 포커스를 이동한다.
  • 엑셀 검토 표는 caption과 열 머리글을 제공하고, 오류 셀의 상태를 스크린 리더가 행 번호와 함께 읽을 수 있게 한다.
  • 편집 가능한 표는 Enter로 편집 시작, Esc로 취소, Tab으로 다음 셀 이동을 지원하며 키보드 사용법을 표 앞에서 안내한다.
  • 충돌 재검증, 저장 완료, 새 오류 발생 결과는 aria-live 영역으로 알리되 같은 메시지를 반복 낭독하지 않는다.
  • 모달과 드로어는 포커스를 내부에 유지하고 제목과 설명을 연결하며 닫힌 뒤 원래 실행 요소로 포커스를 복원한다.
  • 주간 시간표를 시각적 격자로만 제공하지 않고 동일 데이터를 표 보기 또는 요일별 목록으로도 제공한다.
  • 200% 확대와 320px 너비에서도 핵심 조회와 수업 한 건 수정이 가능해야 하며, 화면 전체에 가로 스크롤을 만들지 않는다. 고밀도 표 내부의 가로 스크롤은 허용한다.
  • 날짜와 시간은 한국 표준시 기준의 명확한 형식으로 표시하고 상대 날짜만 사용하지 않는다.
  • 아이콘 버튼에는 접근 가능한 이름을 제공하고 닫기, 편집, 알림처럼 의미가 다른 아이콘을 모양만으로 구분하지 않는다.
  • 동작 줄이기 설정이 켜지면 패널 이동과 상태 전환 애니메이션을 제거하고 즉시 상태를 변경한다.

10. 구현 체크리스트

  • 디자인 토큰을 CSS 변수 또는 Tailwind theme에 한 번만 정의합니다.
  • Pretendard와 지정 자간이 모든 한글 화면에 적용되는지 확인합니다.
  • 선택한 레이아웃 전략과 breakpoint가 화면마다 달라지지 않게 합니다.
  • 버튼·입력·표·대화상자의 focus, disabled, error 상태를 확인합니다.
  • 모바일과 데스크톱에서 핵심 사용자 흐름을 각각 끝까지 확인합니다.

조사 출처

디자인 가이드 — 방과후·늘봄 강사 배정 관리 서비스 | Prometheon