diff --git a/docs/rp_activity_ux_expansion_flow.md b/docs/rp_activity_ux_expansion_flow.md new file mode 100644 index 00000000..c0dd717d --- /dev/null +++ b/docs/rp_activity_ux_expansion_flow.md @@ -0,0 +1,105 @@ +# RP 활동상황 UX 확장 기능 동작 흐름 + +이 문서는 UserFront의 '활동상황' UX 확장 기능(Scope 표시, Consent 이력, 과거 연동 앱 보기)이 어떤 파일과 로직을 통해 구현되었는지, 그리고 전체 데이터 흐름이 어떻게 동작하는지 설명합니다. + +## 1. 개요 + +이 기능의 목표는 사용자에게 자신이 동의한 권한(Scope) 내역을 명확히 보여주고, 과거의 동의 및 해지 이력을 제공하며, 더 이상 사용하지 않는 앱의 목록도 확인할 수 있도록 하는 것입니다. 이를 위해 백엔드에 동의 이력을 기록하는 로직이 추가되었고, 프런트엔드는 이 데이터를 활용하여 확장된 UX를 제공합니다. + +## 2. 전체 데이터 흐름 + +```mermaid +sequenceDiagram + participant User as 사용자 + participant UserFront + participant Backend + participant AuditDB as 감사 로그 (ClickHouse) + participant Hydra + + User->>UserFront: 대시보드 접속 + UserFront->>Backend: GET /api/v1/user/rp/linked (활성 앱 목록 요청) + Backend->>Hydra: ListConsentSessions (활성 세션 조회) + Hydra-->>Backend: 현재 유효한 동의 세션 목록 + Backend-->>UserFront: 활성 앱 목록 응답 (scopes 포함) + + UserFront->>Backend: GET /api/v1/user/rp/history (전체 이력 요청) + Backend->>AuditDB: FindByUserAndEvents("consent.granted", "consent.revoked") + AuditDB-->>Backend: 동의/해지 로그 목록 + Backend-->>UserFront: 가공된 앱별 최종 상태 목록 + + UserFront-->>User: 활성 앱과 과거 연동 앱 목록 표시 + + User->>UserFront: 특정 앱의 '상세정보' 클릭 + UserFront-->>UserFront: 다이얼로그 표시 (Scope 목록 + 필터링된 이력) +``` + +## 3. 백엔드 구현 상세 (`backend`) + +### 3.1. 동의/해지 이벤트 기록 + +**파일**: `internal/handler/auth_handler.go` + +- **동의 시 (`AcceptConsentRequest`)**: 사용자가 권한 동의를 수락하면, `consent.granted` 타입의 감사 로그를 생성합니다. + - **로직**: `h.AuditRepo.Create()`를 호출합니다. + - **저장 정보**: 로그의 `Details` 필드에 Client ID, Client 이름, 사용자가 동의한 **Scope 목록**을 JSON 형태로 저장합니다. +- **해지 시 (`RevokeLinkedRp`)**: 사용자가 연동 해지를 하면, `consent.revoked` 타입의 감사 로그를 생성합니다. + - **로직**: `h.AuditRepo.Create()`를 호출합니다. + - **저장 정보**: `Details` 필드에 Client ID를 저장합니다. + +### 3.2. 이력 조회 API 구현 + +**파일**: `internal/handler/auth_handler.go` + +- **신규 핸들러 (`ListRpHistory`)**: `GET /api/v1/user/rp/history` 요청을 처리합니다. + - **로직**: + 1. `h.resolveConsentSubject(c)`를 통해 요청한 사용자의 ID를 식별합니다. + 2. `h.AuditRepo.FindByUserAndEvents`를 호출하여 해당 사용자의 `consent.granted`, `consent.revoked` 로그를 모두 조회합니다. + 3. 조회된 로그를 시간순으로 처리하여 앱(Client ID)별로 그룹화하고, 각 앱의 최종 상태(`status`), 마지막 승인일(`last_approved_at`), 마지막 해지일(`last_revoked_at`) 등을 계산하여 응답을 구성합니다. + +### 3.3. 데이터베이스 인터페이스 확장 + +**파일**: `internal/domain/models.go`, `internal/repository/clickhouse_repo.go` + +- **인터페이스 변경**: `AuditRepository` 인터페이스에 `FindByUserAndEvents` 메서드를 추가하여 특정 사용자의 특정 이벤트 유형 로그를 조회할 수 있는 규약을 정의했습니다. +- **구현**: `ClickHouseRepository`에 `FindByUserAndEvents` 메서드를 실제 SQL 쿼리로 구현했습니다. `WHERE user_id = ? AND event_type IN (?)` 절을 사용하여 성능을 확보합니다. + +### 3.4. 라우팅 등록 + +**파일**: `cmd/server/main.go` + +- `user` API 그룹에 `user.Get("/rp/history", authHandler.ListRpHistory)` 라우팅 규칙을 추가하여 API를 외부로 노출시켰습니다. + +--- + +## 4. 프런트엔드 구현 상세 (`userfront`) + +**주요 파일**: `lib/features/dashboard/presentation/dashboard_screen.dart` + +### 4.1. 데이터 모델 추가 + +- **`RpHistoryItem`**: 백엔드의 `rp/history` API 응답을 파싱하기 위한 새로운 데이터 모델 클래스를 정의했습니다. +- **`_ActivityItem` 수정**: 기존 UI 모델에 `List scopes` 필드를 추가하여, 활성 앱의 Scope 정보를 위젯 내부에서 사용할 수 있도록 했습니다. + +### 4.2. API 호출 로직 + +- **`_fetchRpHistory()`**: `initState`에서 호출되며, 백엔드의 `GET /api/v1/user/rp/history` API를 호출하여 모든 연동 이력(활성/해지 포함)을 가져와 `_rpHistoryFuture` 상태에 저장합니다. +- **`_fetchLinkedRps()`**: 기존 로직을 유지하며, 현재 활성화된 앱 목록을 `GET /api/v1/user/rp/linked`를 통해 가져옵니다. + +### 4.3. UI 렌더링 로직 + +#### 4.3.1. 활성 앱 카드 (`_buildActivityCard`) + +- **"상세정보" 버튼 추가**: 기존의 '연동 해지' 버튼 옆에 '상세정보' 버튼을 추가했습니다. +- **`onPressed` 이벤트**: 이 버튼을 누르면 `_showRpDetails(item)` 함수가 호출됩니다. + +#### 4.3.2. 상세 정보 다이얼로그 (`_showRpDetails`) + +- **Scope 목록 표시**: `_ActivityItem`에 저장된 `scopes` 리스트를 `Wrap`과 `Chip` 위젯을 사용해 보기 좋게 표시합니다. +- **이력 표시**: `_rpHistoryFuture`에서 가져온 전체 이력 중, 현재 보고 있는 앱의 `clientId`와 일치하는 항목을 찾아 마지막 승인/해지 일시와 현재 상태를 표시합니다. + +#### 4.3.3. 과거 연동 앱 목록 (`_buildPastRps`) + +- **위치**: '활동상황' 섹션 아래, '접속이력' 섹션 위에 새로운 섹션으로 추가되었습니다. +- **데이터 소스**: `_rpHistoryFuture`를 사용합니다. +- **필터링 로직**: `status`가 `'active'`가 아닌 항목들(주로 'revoked')만 필터링하여 목록을 만듭니다. +- **UI 재사용**: 필터링된 데이터를 `_ActivityItem` 모델로 변환한 뒤, 기존의 `_buildActivityGrid`와 `_buildActivityCard` 위젯을 재사용하여 일관된 UI를 보여줍니다. '연동 해지' 버튼은 비활성화 처리됩니다.