임의로 20% 축소하던 방식 대신, 1x1 타일 목표 크기(184px, 계정 프로필
카드와 비슷한 크기)를 기준으로 그리드 폭을 계산하도록 변경. 화면이
목표 크기보다 넓으면 가운데로 모아 여백을 주고, 좁으면(폰) 화면 폭에
그대로 맞춘다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 화면이 넓어져도 열 개수를 6개까지 늘리지 않고 4열에서 고정
- 그리드 캔버스 자체 너비를 700px로 제한하고 20% 더 줄여서, 타일이
화면을 꽉 채우는 느낌 대신 가운데에 여백을 두고 정갈하게 보이게 함
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 화면 전체를 차지하던 색상 배너를 작은 둥근 프로필 카드로 교체하고 가운데에 배치
- 앱바는 ">" 메뉴 버튼만 올라가는 투명한 얇은 바로 변경
- 균일한 그리드 대신 flutter_staggered_grid_view로 타일마다 크기가 다른
매이슨리 레이아웃 적용 (NFC 태그는 세로로 길게, 실시간 출석/서버 DB 제어는
가로로 넓게) - 화면 폭에 따라 열 개수가 자동으로 바뀌어 폰에서도 안 깨짐
- 가로로 넓지만 낮은 타일에서 내용이 넘치지 않도록 카드 배율 계산을
가로/세로 중 작은 쪽 기준으로 변경
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 좌우 슬라이드 대신 맥북 런치패드처럼 확대+페이드로 나타나고 전환 중 뒤 화면이
블러 처리되는 LaunchpadPageRoute 추가, 대시보드의 모든 기능 타일 이동에 적용
- 오른쪽 위 설정 아이콘 + 로그아웃 아이콘 2개를 ">" 버튼 1개로 통합하고,
누르면 로그아웃/설정 메뉴가 런치패드 스타일 오버레이(배경 블러 유지)로 뜨게 변경
- 기능 타일을 누를 때 뜨는 안내 메시지를 스낵바 대신 알약(pill) 모양 알림으로 교체
(AppNotice) - 웹에서는 왼쪽 위, 앱에서는 기존처럼 아래쪽에 표시. 푸시 알림과는 무관.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 폰처럼 작은 화면에서 6칸 고정 격자 때문에 레이아웃이 깨지는 문제로,
타일 드래그 이동/크기조절 기능을 kTileEditingEnabled 플래그로 임시 비활성화
(관련 코드는 그대로 유지 - 작은 화면 대응 방안 마련 후 플래그만 켜면 재사용 가능)
- 비활성화 상태에서는 화면 폭에 따라 열이 자동으로 줄어드는 기본 그리드 사용
- 설정 화면의 "UI 편집" 항목은 비활성화 표시로 안내
- 로그인 화면에 "로그인 상태 유지" 체크박스 추가 (기본 체크됨, 해제 시 세션 저장 안 함)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 이름/부제, "스마트 관리 시스템 메뉴" 제목을 중앙 정렬
- 타일을 1x1~4x4 크기로 자유 배치할 수 있는 편집 모드 추가 (6x4 캔버스, 삼성 One UI 위젯 편집 방식)
- 타일 배치는 계정별로 서버에 저장/복원 (dashboard_layout_controller.dart)
- 설정 화면(톱니바퀴 아이콘) > "UI 편집" 진입점 추가
- shared_preferences로 로그인 유지 기능 추가 (비밀번호는 저장하지 않음)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
앱 전체 MaterialApp의 ThemeData가 여전히 primarySwatch: Colors.indigo
였던 게 진짜 원인이었음 — 개별 화면 색은 고쳤지만, 기본 위젯 스타일
(포커스 안 된 텍스트필드 밑줄, FilterChip 선택 색 등)은 전부 이
전역 테마를 그대로 따라가고 있어서 여전히 예전 색으로 보였음.
ColorScheme을 AppPalette 기준으로 재구성해 해결.
추가로 팔레트 작업에서 빠졌던 화면들도 마무리:
- teacher_register_screen.dart (교사 회원가입)
- nfc_tag_writer_screen.dart (NFC 태그 쓰기)
- change_password_screen.dart (미사용이지만 일관성을 위해 정리)
- teacher_attendance_page.dart의 주머니 번호 칩 색상
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
화면 타이틀, 스낵바/다이얼로그 메시지, 백그라운드 알림 문구 등
사용자에게 노출되는 텍스트에서 이모티콘을 전부 제거 (코드 주석은
대상 아님). 아이콘 위젯은 그대로 유지.
main_dashboard.dart의 "계정 강제 삭제" 타일 아이콘 색상도 빨간색
대신 다른 타일과 동일한 검정(AppPalette.ink)으로 통일.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
coolors.co 무채색 팔레트(1c1c1c-daddd8-ecebe4-eef0f2-fafaff)를
lib/theme/app_palette.dart에 정의하고, 로그인/대시보드/출석 확인/
학생 계정 관리/스마트기기 반출(신청·대장)/관리자 화면 전반의
배너·배경·카드·기본 버튼 색을 이 팔레트로 교체.
기능적으로 의미 있는 색(위반/미출석/삭제/거절 등 경고성 빨간색,
승인 대기 등 상태 표시)은 그대로 유지 — 구조적/장식적 색상만
무채색으로 통일해 위험한 동작이 시각적으로 더 도드라지게 함.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
원본 파비콘이 1024x1024(610KB)라 매 접속마다 불필요하게 큰 파일을
받아오던 문제를 32x32로 리사이즈해 해결. PWA 홈화면 아이콘
(192/512, maskable 포함)도 같은 새 이미지로 통일.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
StudentDashboard, TeacherDashboard, AdminDashboard(진입 라우팅)를
MainDashboard 하나로 합치고, 역할(role)에 따라 배너 색상/문구와
보이는 타일만 달라지게 함. 그리드 레이아웃/카드 디자인은 이제
한 곳에서만 관리되어, 앞으로 UI를 고치면 모든 역할에 자동 적용됨.
- 2061(개발자) 계정에 기존에 빠져있던 "스마트기기 반출 대장" 타일 추가
- role=='admin' 실 계정도 이제 학생 계정 관리/출석 확인 등 교사 기능에
접근 가능 (관리자는 교사 권한을 포함하는 것으로 정리)
- 작은 DB 초기화 전용 화면(admin_dashboard.dart)은 "서버 DB 제어"
타일의 목적지로만 유지, 로그인 직후 랜딩 화면 역할은 제거
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
자동 감지 하드웨어가 아직 없어서, 승인된(APPROVED) 요청에 선생님이
기기를 실제로 돌려받았을 때 누르는 "기기 반납 확인" 버튼을 추가.
누르면 상태가 반납완료로 바뀌어 10분 후 미반납 알림이 더 이상
가지 않는다 (백엔드는 별도 저장소에서 이미 배포 완료).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
계획 변경에 따라 저울/아두이노 기반 픽업·반납·무단반출 감지를 없애고
순수 시간 기반 알림만 남김 (백엔드는 별도 저장소에서 이미 배포 완료).
- 승인 시 현재 로그인한 선생님의 teacherId/teacherName을 서버에 함께
전송하여 저장하고, 대장에 "OOO 선생님이 허용했습니다" 표시
- 반납 시간 초과 알림은 승인한 선생님에게만 전송 (서버가 해당 선생님의
등록된 기기를 못 찾으면 전체 선생님에게 대체 발송)
- 대장 카드의 상태 표시에서 IN_USE/RETURNED(픽업 대기) 문구 제거
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
학생 타일의 이름/상태/학년칩 폰트와 아이콘 크기를 키워 가독성을
높이고, 계정 추가/엑셀 등록 정사각형 칸의 크기를 학생 목록 타일과
동일한 크기(tileSize)로 통일했다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
계정 추가/엑셀 등록 정사각형 칸은 기존 크기의 25%로 축소하고,
학생 목록 타일은 기존보다 50% 더 큰 정사각형으로 확대. 목록 폭은
더 이상 위 두 칸 폭에 종속되지 않고 전체 폭을 사용하도록 변경.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
웹 넓은 화면에서 계정 추가/엑셀 일괄 등록을 정사각형 2칸으로
나란히 배치(왼쪽 계정 추가, 오른쪽 엑셀 등록)하고, 그 아래 학생
목록을 두 칸 합친 폭에 맞춘 타일 그리드로 변경. 각 타일은 아이콘/
이름/상태/액션 버튼을 모두 중앙 정렬. 폰 화면은 기존처럼 세로 스택
유지.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
웹(넓은 화면)에서 항상 2개씩 줄바꿈되던 버그 수정. 학생 대시보드와
동일하게 LayoutBuilder로 폭이 800 이상이면 한 줄에 5개, 좁으면
기존처럼 2개씩 보이도록 함.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
패드는 NFC를 못 쓰므로 학생이 사용 시간/목적을 신청하면 선생님이
대시보드의 반출 대장에서 승인/거절하는 흐름을 추가. 저울-아두이노
연동(무게 기반 픽업/반납 감지)은 백엔드에 구현되어 있으나 실기기
연동은 추후 진행.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 두 화면이 서로 다른 기능만 갖고 있던 문제 해결: 선생님 화면(엑셀 일괄등록,
학년 지정, 커스텀 초기비번)에 마스터 화면에만 있던 실시간 학생 목록 조회 +
기기 리셋(학생이 폰 바꿨을 때 재등록용) 기능을 합침
- 학번을 직접 타이핑하던 블라인드 학년변경/삭제 다이얼로그를 목록의
행별 액션(학년 칩, 기기 리셋 버튼, 삭제 버튼)으로 교체
- 계정 생성/삭제/학년변경 성공 시 목록 자동 새로고침
- 마스터(2061) 계정의 "학생 계정 관리" 카드도 이 통합 화면으로 연결하고,
중복되던 student_management_screen.dart / student_management_controller.dart 삭제
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 학생 계정 관리 화면에 드래그앤드롭/클릭 업로드 영역 추가
(excel, desktop_drop, file_picker 패키지 도입)
- .xlsx 파싱 → 미리보기 팝업 → 확인 후 한 명씩 순서대로 계정 생성,
결과(성공/실패)를 요약해서 보여줌. 초기 비밀번호는 1234 고정
- file_picker의 웹 구현체가 pickFile(s)를 아직 구현하지 않아서
(UnimplementedError) 웹에서는 package:web으로 직접 <input type=file>을
다뤄서 우회 (lib/function/excel_file_picker_web.dart), 다른 플랫폼은
기존 file_picker 사용 (excel_file_picker_io.dart)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 학생 계정 관리 화면에 학번으로 학년을 지정/변경하는 카드+다이얼로그 추가
- 계정 생성 성공 판정을 HTTP 상태코드가 아닌 응답 status 필드로 정확히 확인하도록 수정
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 실시간 출석 현황을 학년별 섹션으로 묶어서 표시 (백엔드에 grade 필드 추가)
- 학생 계정 추가 폼에 학년 선택 드롭다운 추가
- 학생 계정 생성/삭제가 실제로는 존재하지 않는 엔드포인트를 호출하던
버그 수정 (/api/users/register-student, /api/users/delete/{id} →
/api/users/create, /api/users/delete)
- 학생 대시보드(개발자 모드) 카드 그리드가 넓은 화면에서 과도하게
커지던 레이아웃 버그 수정, 웹은 5열/폰은 2열로 반응형 처리
- 버전 1.2.0+6
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- iOS는 조도 센서/백그라운드 서비스가 불가능해서 근접센서(UIDevice
proximityMonitoring) + 가이드 접근 안내로 대체 구현 (Core NFC와 마찬가지로
네이티브 플러그인 필요해서 ProximityMonitorPlugin.swift 추가)
- 교사 대시보드 실시간 출석 현황: 모바일 리스트/데스크톱 표를 타일 그리드로
통일해서 한눈에 보기 쉽게 변경
- 서버를 학교 자체 서버(Cloudflare Tunnel, api.backsanhi.shop)로 이전하면서
기본 BASE_URL 갱신
- Firebase CLI 로컬 캐시(.firebase/)는 소스가 아니라 gitignore 처리
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- config.dart의 baseUrl/webVapidKey와 학교 이름을 String.fromEnvironment로 전환
- 기본값은 기존 백산고 값 그대로라 인자 없이 빌드하면 지금과 동일하게 동작
- 다른 학교는 --dart-define=BASE_URL=...=SCHOOL_NAME=...=WEB_VAPID_KEY=...로 빌드
하교 버튼을 누르면 반출 허용뿐 아니라, 그 시각을 기준선으로 삼아 대시보드의
"출석 완료" 표시도 미제출로 초기화되도록 함. 실제 출석 기록(attendance 테이블)은
삭제하지 않고, 대시보드가 "오늘 출석"으로 인정하는 기준 시각만 옮기는 방식이라
데이터 손실 없이 표시만 리셋된다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 선생님 대시보드에 "하교" 버튼 추가: 시간 입력 없이 바로 전체 학생 반출 허용
(실수 클릭 방지를 위해 확인 다이얼로그 한 번 거침)
- 무단반출이 감지되면 클라이언트의 감시 상태를 해제해서, 다음 태깅이
체크아웃이 아니라 새 출석으로 처리되도록 수정
- 주머니 감시 화면에 있던 "폰 회수하고 감시 종료 (테스트용)" 버튼 제거
(정식 플로우는 재태깅으로만 체크아웃/재출석 처리)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- TeacherAttendancePage 앱바에 수동 새로고침 버튼 추가
- Firebase Hosting에서 index.html/flutter_service_worker.js/version.json을
no-cache로 설정해서, 재배포 후 브라우저가 예전 버전을 계속 들고 있는 문제 방지
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 실시간 출석 현황 화면(TeacherAttendancePage)에 데스크톱(웹 브라우저 800px+) 전용
레이아웃 추가: 통계 타일 3개 + 정식 DataTable. 교사 대시보드 메뉴 그리드도
데스크톱에서 카드가 지나치게 커지지 않도록 최대 너비 제한
- Firebase Hosting에 웹 빌드 배포 설정 추가 (firebase.json hosting 섹션),
https://school-display-ff28f.web.app 로 선생님이 브라우저에서 바로 접속 가능
- 무단 반출(/api/violations/active) 감지 시 대시보드에 빨간 표시 + "반출 허용" 버튼 추가
- 선생님이 개별 학생에게 N분간 반출 허용(/api/violations/allow), 또는 전체 학생에게
한 번에 반출 허용 시간대 설정(/api/permissions/window, 쉬는시간 등) 가능하도록 연동
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
## 릴리즈 빌드 준비
- android/app/build.gradle.kts: 디버그 키로 서명하던 release 빌드 타입을
android/key.properties 기반 정식 릴리즈 키스토어(upload-keystore.jks) 서명으로 변경
- applicationId를 com.example.school_attendance → com.backsanhighschool.app 로 변경
(com.example.* 패키지는 구글 플레이 업로드 자체가 거부되기 때문)
## Firebase 재등록
- 새 패키지명(com.backsanhighschool.app)으로 Firebase Android 앱을 새로 등록
- google-services.json, lib/firebase_options.dart, firebase.json을 새 앱 ID 기준으로 재생성
## HTTPS 전환
- lib/config.dart: baseUrl을 http:// → https:// 로 변경
(서버에 이미 발급되어 있었지만 프록시에 연결이 안 되어 있던 Let's Encrypt
인증서를 nginx-proxy-manager에 연결하고 HTTP→HTTPS 강제 리다이렉트 설정)
- AndroidManifest.xml: 더 이상 필요 없는 usesCleartextTraffic="true" 제거
## NFC 태그 쓰기 기능 (신규)
- lib/screens/nfc_tag_writer_screen.dart 추가: 관리자가 빈 NFC 스티커에
"POCKET_번호" 텍스트를 쓰고, 태그 하드웨어 UID를 서버(/api/pockets/register)에
등록해서 태그 복제(내용만 베낀 위조 태그)를 방지
- lib/nfc_poccket_checkin_screen.dart: 체크인 시 태그 UID를 함께 서버로 전송해서
등록된 진짜 주머니 번호로 검증하도록 변경
- lib/screens/student_dashboard.dart: 개발자 메뉴에 "NFC 태그 쓰기" 카드 추가,
기존 "가상 NFC 태깅" 카드는 "NFC 태그"로 이름 변경
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>