# code_20260708_b01_dashboard.md ## 목적 이번 대화 세션에서는 `.agent/plan_register_split.md`와 `.agent/plan_register_split_validation.md` 기준으로 B01 페이지를 역할별 대시보드와 계정관리 기능을 함께 포함하는 단일 페이지로 구현했다. ## 주요 구현 ### 1. B01 단일 폴더 정리 - `B01_Dashboard/`를 B01의 단일 구현 폴더로 사용한다. - 기존 `B01_AccountDetail/`의 계정관리 성격은 `B01_Dashboard` 안으로 흡수했다. - 기존 `B01_AccountDetail_UI_Page.ts`, `B01_AccountDetail_UI_Style.css`는 삭제했다. - `B01_AccountDetail` 문자열 참조는 주석까지 정리했다. ### 2. 백엔드 API 신규 파일: - `B01_Dashboard/B01_Dashboard_Router.py` - `B01_Dashboard/B01_Dashboard_Repository.py` - `B01_Dashboard/B01_Dashboard_Schema.py` 구현된 API 범위: - 공통 사용자 정보 조회/수정 - USER 프로젝트/회사 조회, 회사 검색, 회사 생성, 회사 가입 신청 - ADMIN 팀원 조회/추가/제거, 가입 요청 승인/거절, 회사 프로젝트 조회 - SYSTEM_ADMIN 회사/사용자/가입 요청/감사 로그/리소스 조회 라우터 등록: - `main.py`에 `B01_Dashboard_Router`를 등록했다. ### 3. 프론트엔드 신규/수정 파일: - `B01_Dashboard/B01_Dashboard_UI_Page.ts` - `B01_Dashboard/B01_Dashboard_Api_Fetch.ts` - `B01_Dashboard/B01_Dashboard_UI_Style.css` - `A00_Common/router.ts` - `ui_template/ui_template_locale.ts` 구현된 UI 범위: - 역할별 대시보드 섹션 조건부 렌더링 - 프로젝트 테이블 및 B03~B09 워크플로우 단계 버튼 - 회사 미연결/가입 대기/활성 상태 표시 - 회사 생성 및 회사 검색/가입 신청 모달 - ADMIN 팀원 관리 및 가입 요청 처리 - SYSTEM_ADMIN 리소스/회사/사용자/가입 요청/로그 섹션 - 기본정보 수정 - 비밀번호 변경 주의: - 색상은 직접 하드코딩하지 않고 `ui_template_theme.css` 변수 기반 CSS를 사용했다. - UI 문구는 `ui_template_locale.ts`에 등록해 참조했다. ### 4. 인증/세션 관련 최소 수정 로그인 인증 이슈 재발을 피하기 위해 수정 범위를 좁혔다. 수정 파일: - `common_util/common_util_auth.py` - `common_util/common_util_auth_repository.py` - `A06_Login/A06_Login_Router.py` - `A07_Register/A07_Register_Router.py` 변경 내용: - `PENDING` 상태 사용자도 B01 대시보드에 접근할 수 있도록 세션 검증 허용 상태에 포함했다. - 신규 가입 기본 역할을 기존 `MEMBER`가 아니라 계획 기준인 `USER`로 맞췄다. - 이메일 인증 완료 시 `auth_expires_at`을 3개월 뒤로 설정했다. - 로그인 완료 시 `last_login`, `auth_expires_at`을 갱신한다. - 회사 생성/연결 안내 주석을 `B01_Dashboard` 기준으로 갱신했다. ### 5. DB 마이그레이션 신규 파일: - `db_management/004_dashboard.sql` 적용 내용: - `users.role`을 `SYSTEM_ADMIN`, `ADMIN`, `USER` 기준으로 정규화 - 기존 `MASTER -> ADMIN`, `MEMBER -> USER` 데이터 변환 - `users.status`에 `NO_COMPANY` 포함 - `users.department`, `last_login`, `auth_expires_at` 추가 - `system_audit_logs`, `system_resources` 생성 - `join_requests.review_comment` 추가 실행 결과: - 원격 MariaDB에 `004_dashboard.sql` 실행 완료 - 10개 SQL statement 실행 및 커밋 완료 - information_schema 조회로 다음 항목 확인 완료: - `users.role = enum('SYSTEM_ADMIN','ADMIN','USER')` - `users.status = enum('PENDING_EMAIL','NO_COMPANY','PENDING','ACTIVE','INACTIVE','REJECTED')` - `department`, `last_login`, `auth_expires_at` - `system_audit_logs`, `system_resources` - `join_requests.review_comment` ## 검증 실행한 검증: - `npx.cmd tsc --noEmit` - `ruff check --fix --no-cache ...` - venv 기준 Python import 확인 - DB information_schema 확인 결과: - TypeScript 검사 통과 - Ruff 검사 통과 - DB 마이그레이션 적용 확인 참고: - 서버 실행은 프로젝트 지침에 따라 수행하지 않았다. - 의존성은 venv에서 `pymysql`, `aiomysql`, `fastapi` import가 정상이라 추가 설치하지 않았다. ## 후속 수정 (리소스 현황 실측) - `get_system_resources`에서 `None`으로 하드코딩되어 화면에 `-`로만 표시되던 CPU/메모리 값을 `psutil`로 실측하도록 변경했다. - CPU: `psutil.cpu_percent(interval=0.1)` - 메모리: `psutil.virtual_memory().percent` - 디스크: 기존 `shutil.disk_usage()` 유지 - 이력 조회 기간을 24시간 → 기본 30일로 변경했다. (`days` 파라미터, 1~90일) - API 파라미터 불일치 수정: 프론트가 보내던 `period=24h`(문자열)를 백엔드 `days`(정수)와 일치하도록 `fetchSystemResources(days = 30)`로 변경했다. - `psutil`은 이미 `requirements.txt`(`psutil>=6.1,<7`) 및 venv에 존재하여 추가 설치 불필요. ## 후속 수정 (리소스 그래프 + 계측 로그) ### 프론트엔드 그래프 - `ui_template_elements.ts`에 공통 라인 차트 컴포넌트 `createLineChart` 추가 (외부 라이브러리 없이 인라인 SVG). - null 값 구간은 선을 끊고 다음 유효점에서 재시작. - 색상은 `ui_template_theme.css`에 추가한 `--color-chart-0~3` 변수 참조 (하드코딩 없음). - `B01_Dashboard_UI_Page.ts`의 리소스 섹션을 `buildResourcePanel`로 교체하여 지표(metrics) + 30일 추이 그래프(CPU/메모리/디스크)를 함께 표시. - `ResourceData.history`를 `unknown[]` → `ResourceHistoryPoint[]`로 타입 구체화. - locale에 `B01_Dashboard_Resources_ChartCaption`, `B01_Dashboard_Resources_ChartAria` 추가. ### 계측 백그라운드 태스크 + 로그 파일 - `common_util/common_util_resource_monitor.py` 신규: 2분 주기로 CPU/메모리/디스크 계측. - DB `system_resources` 테이블 INSERT (그래프 조회 소스) + 30일 경과 행 DELETE. - 루트 `log/system_resources.log` 단일 파일에 탭 구분 1줄 append, 30일 경과 줄 제거(오래된 줄 삭제 + 신규 줄 추가). - `main.py` lifespan에 `sample_resources_loop` 태스크 등록/취소 (기존 cleanup 태스크 패턴). - `config_system.py`에 `LOG_BASE_DIR`, `RESOURCE_LOG_PATH`, `RESOURCE_SAMPLE_INTERVAL_SEC=120`, `RESOURCE_LOG_RETENTION_DAYS=30` 추가. - `.gitignore`에 `log/` 추가. ### 검증 - `npx tsc --noEmit` 통과, `ruff format`/`ruff check` 통과, `prettier --write` 변경 없음. - 계측/로그 트림 로직은 스크립트로 실측 확인 (샘플 기록·30일 경과 줄 제거 동작 확인 후 테스트 로그 삭제). ## 후속 수정 (그래프 다운샘플링 + 스플라인 + 범례/X축) ### 조회 다운샘플링 (백엔드) - `get_system_resources`의 history 조회를 시간버킷 평균으로 축소. - `bucket = max(120초, days*86400 / 300)` → 최대 약 300점. - `GROUP BY FLOOR(UNIX_TIMESTAMP(timestamp)/bucket)` + `AVG(...)`. - 30일 조회 페이로드 ~4MB → ~55KB 수준으로 감소. 하루 이하 조회 시 원본 해상도 유지. - DB 실측: 5행 → 1버킷 평균 집계 확인 후 테스트 데이터 삭제. ### 차트 컴포넌트 개선 (`ui_template_elements.ts`) - 직선 → **스플라인**(Catmull-Rom → 3차 베지어). null 구간은 세그먼트로 분리해 각각 곡선 처리. - **범례를 그래프 우상단 오버레이**로 이동 (`.ui-chart__plot` position:relative + `.ui-chart__legend` absolute, 반투명 배경). - **X축 라벨** 지원: `opts.xLabels`, 양끝 포함 5개 균등 표기 (`.ui-chart__tick--x`). - `B01_Dashboard_UI_Page.ts`에 `formatChartTime`(MM/DD HH:mm) 추가 후 `xLabels` 전달. ### 리소스 지표 레이아웃 (`B01_Dashboard_UI_Style.css`) - metric-grid를 5열 1행, 각 항목은 라벨·값 가로 1줄(`space-between`)로 컴팩트화. 값 폰트 축소. ### 검증 - `npx tsc --noEmit` 통과 (el() children 타입 이슈는 svg를 append로 분리해 해결). - `ruff format/check` 통과, `prettier` 변경 없음. ## 후속 수정 (그래프 X축 레이블 - 데이터 기반 고정) ### 백엔드 timestamp 직렬화 (B01_Dashboard_Repository.py) - 기존: `FROM_UNIXTIME()` → Python datetime 객체로 JSON 직렬화 불가 - 변경: `DATE_FORMAT(..., '%%Y-%%m-%%dT%%H:%%i:%%s')` → ISO 문자열로 명시적 변환 - SQL에 `date_fmt` 변수 도입해 ruff 100자 줄 제한 준수 ### 프론트엔드 X축 라벨 고정 (ui_template_elements.ts, B01_Dashboard_UI_Page.ts) - 기존: `X_TICK_COUNT=5` 고정으로 균등 선택 (데이터 개수와 무관) - 변경: `X_TICK_STEP=3` — 데이터 포인트마다 3개씩 건너뛰며 표시 (실제 데이터량 기반) - X축 라벨 루프를 `for (let idx = 0; idx < pointCount; idx += X_TICK_STEP)` 로 변경 - `formatChartTime`에 try-catch 추가로 예외 안전성 강화 ### 검증 - ✅ `npx tsc --noEmit` 통과 - ✅ `ruff format/check` 통과 (100자 줄 제한 준수) - ✅ `prettier` 변경 없음 ## 남은 주의점 - B01 화면은 구현됐지만 실제 브라우저 검증은 수행하지 않았다. - 그래프는 `system_resources` 이력이 쌓여야 선이 그려진다 (앱 최초 구동 직후에는 데이터 2점 미만이면 `—` 빈 상태 표시, 2분 주기로 누적). - 그래프 갱신은 페이지 로드/새로고침 시점 1회 (자동 폴링 없음). - 로그인/회사 상태별 실제 시나리오 검증은 별도 검증 AI 또는 사용자가 수행해야 한다. - `B01_Dashboard_UI_Page.ts`는 645줄로 700줄 제한 이내지만, 향후 기능 추가 시 컴포넌트 분리를 고려해야 한다. - 이전 import 검증 중 기존 B04 계열 Pydantic `model_*` 필드 경고가 출력됐으나, 이번 B01 구현에서 발생한 경고는 아니다.