208 lines
9.5 KiB
Markdown
208 lines
9.5 KiB
Markdown
# 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 구현에서 발생한 경고는 아니다.
|