Harden admin telemetry and deployment safeguards
TaxBaik CI/CD / build-and-deploy (push) Successful in 4m30s

This commit is contained in:
2026-07-02 16:10:15 +09:00
parent b1601b0305
commit d780fecf8c
53 changed files with 1590 additions and 656 deletions
+11
View File
@@ -14,6 +14,7 @@
| Deploy | Gitea Actions CI/CD만 배포 경로 | 수동 SSH/복사로 운영 반영 |
| Evidence | 빌드, 테스트, E2E, API smoke 로그 | "확인함", "될 것" 같은 진술 |
| Admin Render | `InteractiveWebAssemblyRenderMode(prerender: false)` | 어드민에 `InteractiveServerRenderMode` 또는 `prerender: true` 존재 |
| KST Timestamp | CI/배포/백업 폴더명과 추적 일시는 `TZ=Asia/Seoul` | `date`가 기본 UTC 또는 서버 로캘에 종속 |
## Architecture Guardrails
@@ -26,6 +27,13 @@
- 어드민 렌더 모드는 `InteractiveWebAssemblyRenderMode(prerender: false)`를 기본값으로 둔다. `InteractiveServerRenderMode``prerender: true`는 어드민에서 허용하지 않는다.
- JavaScript는 최소화한다. 브라우저 API, 인증 토큰 저장, 서드파티 편집기처럼 Blazor/MudBlazor만으로 해결하기 부적절한 경우에만 JS module로 격리한다.
- 상속은 프레임워크 요구 또는 명확한 다형성 모델에만 사용한다. 폼/테이블/CRUD 재사용은 기본적으로 컴포넌트 합성과 작은 service/client로 처리한다.
- 과유불급을 지킨다. 실제 재사용이 2곳 미만이면 새 추상화를 만들지 말고 기존 컴포넌트를 직접 조합한다.
- CI, 배포 폴더명, 백업명, 버전 추적에 쓰는 시간 문자열은 `TZ=Asia/Seoul`을 기본으로 한다.
- 클라이언트 오류 수집은 서버/브라우저를 보호하는 목적의 제한형 수집으로만 운영한다. 건당 비동기 전송, 중복 억제, 분당 상한, 서버 rate limit, 실패 시 조용히 폐기, 재시도 폭주 금지.
- 브라우저에서 발생한 JS 오류는 운영 장애 탐지를 위한 샘플 데이터로만 취급하고, 전체 이벤트 스트림을 보존하려는 설계는 금지한다.
- 텔레그램 알림은 운영자의 주의 채널이지 이벤트 버스가 아니다. 같은 원인/같은 기간의 중복 알림은 억제하고, 리포트/오류/문의/시작 장애는 종류별 시간창을 분리한다.
- 오류 알림에는 재현성 6요소를 포함한다: 화면, 기능, 액션, 단계, 데이터 식별자, 현재 라우트. 이 정보가 없으면 운영 대응이 끝나지 않은 것으로 본다.
- 재현 맥락은 페이지별 수동 JS 호출이 아니라 `AdminTelemetryContext` 같은 공통 컴포넌트가 담당한다. 새 어드민 화면은 레이아웃 경유 기본값을 자동 상속해야 하며, 예외만 명시적으로 덮어쓴다.
## Code Quality Harness
@@ -54,6 +62,9 @@
- 상태 전이는 허용 목록을 둔다. 임의 문자열 저장을 금지한다.
- 삭제는 운영 데이터 손실 위험이 있으면 soft delete 또는 archive를 우선 검토한다.
- 콤보 값은 [COMMON_CODE_POLICY.md](./COMMON_CODE_POLICY.md)를 1차 기준으로 삼는다.
- 클라이언트 로그와 장애 진단 로그는 운영 데이터가 아니라 관측 데이터로 본다. 저장 실패는 사용자 흐름을 막지 않으며, 수집 실패 자체를 재시도 루프로 증폭하지 않는다.
- 동일 오류의 텔레그램 재알림은 일정 기간 1회로 제한하고, 재전송 목적의 루프는 금지한다.
- 데이터가 오류 재현에 필요하면 `entity`, `entityId`, `dataKey` 같은 최소 식별자만 남기고, 원문 데이터 전체를 로그에 싣지 않는다.
## API-First Admin Pattern
+20
View File
@@ -22,6 +22,25 @@
| Public API | `/taxbaik/api/*` | JWT 인증, ProblemDetails 오류, DTO 입출력 |
| CI/CD | `.gitea/workflows/deploy.yml`, `.gitea/workflows/browser-e2e.yml` | 수동 배포 금지, 배포본 E2E 통과 후 완료 |
## Shared Component Map
| 컴포넌트 | 용도 | 대표 사용처 |
| --- | --- | --- |
| `AdminShell` | 관리자 상단바/드로워/버전/알림 공통 shell | `Components/Admin/Layout/MainLayout.razor` |
| `AdminLoginForm` | 관리자 로그인 입력/제출 UI | `Components/Admin/Pages/Login.razor` |
| `AdminPageHeader` | 페이지 타이틀/보조설명/주요 액션 | Blog, Inquiry, Client, FAQ 목록 |
| `AdminDataPanel` | 목록/표면/로딩 스켈레톤 공통 래퍼 | Blog, Inquiry, CommonCode, Dashboard |
| `AdminEditorPanel` | 편집형 스켈레톤 래퍼 | BlogEdit, InquiryEdit, ClientEdit, CompanyEdit, FAQEdit |
| `AdminSkeletonRows` | 반복 로딩 골격 | AdminDataPanel, AdminEditorPanel, Dashboard |
| `AdminMetricCard` | 대시보드 KPI 카드 | `Components/Admin/Pages/Dashboard.razor` |
| `AdminEmptyState` | empty/empty-filter 상태 | ClientList 등 목록 화면 |
| `AdminFormSection` | 폼 입력 섹션 구획 | BlogForm, InquiryForm |
| `AdminFormActions` | 제출/취소 버튼 묶음 | BlogForm, InquiryForm |
| `AdminDetailSection` | 상세 정보 카드 | InquiryDetail |
| `AdminCrudPageShell` | create/edit 페이지 공통 헤더+취소+편집 래퍼 | BlogCreate/Edit, InquiryCreate/Edit |
| `CommonCodeGroupPanel` | 공통코드 그룹 선택/추가 패널 | CommonCodes |
| `CommonCodeListPanel` | 공통코드 목록/편집 패널 | CommonCodes |
## Document Rules
- 문서는 짧게 유지한다. 새 문서를 만들기 전에 이 인덱스에 추가할 가치가 있는지 판단한다.
@@ -30,3 +49,4 @@
- WBS 완료 여부는 체크박스가 아니라 수치와 실행 로그로 판단한다.
- 코드 변경 시 관련 WBS ID를 커밋/PR 설명 또는 작업 메모에 남긴다.
- 공통코드 관련 규칙은 [COMMON_CODE_POLICY.md](./COMMON_CODE_POLICY.md)만 1차 기준으로 사용한다.
- 공유 컴포넌트는 `INDEX.md`의 Shared Component Map을 먼저 확인한다.