4개 전문 감사관(프론트·백엔드·일관성·UX) 병렬 검증 결과 반영.
버그/깨짐(HIGH·MED):
- HtmlCssPage: 존재하지 않는 /learn/computer → /learn/hardware(깨진 링크, 대시보드로 튕김)
- MentorAnalyticsService: 체크리스트 활동(Progress.checkedAt)이 '마지막 활동'에 누락돼
체크리스트만 한 학생이 '관심 필요'로 오분류되던 버그 수정(+회귀 테스트)
- 퀴즈 핫스팟 평균 정수절삭 → Math.round로 통일
접근성/UX(MED):
- CodeEditor: 코드 입력창에 aria-label 추가(WCAG 4.1.2, 스크린리더 이름 부여)
- 멘토 제출물 표: tr role=button → 셀 안 button으로(표 의미구조 보존 + 키보드)
- 대시보드 체크박스 토글 실패 시 무피드백 → try/catch + 에러 안내
콘텐츠/문서 드리프트:
- 초급 미니프로젝트 JS 예제 var→let(let/const 가르치며 var 쓰던 자기모순)
- README 강좌 수(71→83+48), BACKUP.md 복원검증 카운트(퀴즈655·문서19·코딩25)
- 브랜드/코스수 주석 정리(수습 플랫폼→학습 플랫폼, 72개→비수치화), 퀴즈 결과 '점'→'%'
테스트 백엔드 51→52, 프론트 30 유지. 운영 배포·스모크 11/11.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backup-gitea.sh: gitea dump(저장소+SQLite+설정을 일관된 시점으로) | S3 업로드
볼륨 tar 대신 gitea dump를 쓴 이유를 주석에 명시 (실행 중 tar는 시점이 어긋날 수 있음)
- zip 무결성(unzip -t)·크기 검증 후에만 업로드
- systemd timer 매일 03:10 KST (DB 백업 10분 뒤 — 겹치지 않게)
- IAM 정책에 gitea/ 경로 추가 + 복원용 GetObject (여전히 해당 버킷 두 경로로만 제한)
- S3 수명주기에 gitea/ 30일 규칙 추가
- BACKUP.md: Gitea 복원 절차·검증법·'무엇이 이 서버에만 있는가' 관점 정리
검증: 백업 2.8MB, zip 무결성 OK, 백업 속 저장소에서 clone → HEAD·커밋20·파일269 운영과 일치
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backup-db.sh: pg_dump | gzip | S3 업로드 + 로컬 7일 보관, 덤프 크기 검증
- restore-db.sh: 목록 조회·복원(확인 프롬프트·복원 전 자동 스냅샷)
- systemd timer로 매일 03:00 KST 실행 (AL2023에 cron 없음, 이력이 journalctl에 남음)
- S3 버킷: 퍼블릭 차단 + AES256 암호화 + 30일 수명주기
- IAM 역할(mirim-backup-role): 해당 버킷 postgres/ 에 PutObject만 — 최소 권한, 액세스 키 없음
- BACKUP.md: 구성·설계 이유·복원 리허설 절차
검증: 백업 성공(8.5MB→102KB), S3 업로드 확인, 임시 DB 복원 후 운영본과 건수 완전 일치
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>