diff --git a/lib/core/constants/app_sections.dart b/lib/core/constants/app_sections.dart index 491f0a1..faa0022 100644 --- a/lib/core/constants/app_sections.dart +++ b/lib/core/constants/app_sections.dart @@ -1,6 +1,7 @@ import 'package:flutter/widgets.dart'; import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide; +/// 사이드바/내비게이션용 페이지 정보. class AppPageDescriptor { const AppPageDescriptor({ required this.path, @@ -15,6 +16,7 @@ class AppPageDescriptor { final String summary; } +/// 메뉴 섹션을 나타내는 데이터 클래스. class AppSectionDescriptor { const AppSectionDescriptor({required this.label, required this.pages}); @@ -22,9 +24,13 @@ class AppSectionDescriptor { final List pages; } +/// 로그인 라우트 경로. const loginRoutePath = '/login'; + +/// 대시보드 라우트 경로. const dashboardRoutePath = '/dashboard'; +/// 네비게이션 구성을 정의한 섹션 목록. const appSections = [ AppSectionDescriptor( label: '대시보드', diff --git a/lib/core/network/api_client.dart b/lib/core/network/api_client.dart index 900977e..9e569a2 100644 --- a/lib/core/network/api_client.dart +++ b/lib/core/network/api_client.dart @@ -1,5 +1,3 @@ -// ignore_for_file: public_member_api_docs - import 'package:dio/dio.dart'; import 'api_error.dart'; @@ -93,6 +91,7 @@ class ApiClient { ); } + /// Dio 요청을 실행하고 `DioException`을 공통 예외 유형으로 변환한다. Future> _wrap(Future> Function() request) async { try { return await request(); diff --git a/lib/core/network/api_error.dart b/lib/core/network/api_error.dart index 522ed6f..ad1d85f 100644 --- a/lib/core/network/api_error.dart +++ b/lib/core/network/api_error.dart @@ -1,5 +1,6 @@ import 'package:dio/dio.dart'; +/// API 호출 실패 유형. enum ApiErrorCode { badRequest, unauthorized, @@ -12,6 +13,7 @@ enum ApiErrorCode { unknown, } +/// API 호출 시 공통으로 던지는 예외 모델. class ApiException implements Exception { const ApiException({ required this.code, @@ -32,9 +34,11 @@ class ApiException implements Exception { 'ApiException(code: $code, statusCode: $statusCode, message: $message)'; } +/// Dio 예외를 [ApiException]으로 변환하는 매퍼. class ApiErrorMapper { const ApiErrorMapper(); + /// Dio 예외 세부 정보를 분석해 적절한 [ApiException]을 생성한다. ApiException map(DioException error) { final status = error.response?.statusCode; final data = error.response?.data; @@ -124,6 +128,7 @@ class ApiErrorMapper { ); } + /// 응답 바디 혹은 Dio 예외 객체에서 사용자용 메시지를 추출한다. String _resolveMessage(DioException error, dynamic data) { if (data is Map) { final message = data['message'] ?? data['error']; @@ -136,6 +141,7 @@ class ApiErrorMapper { return error.message ?? '요청 처리 중 알 수 없는 오류가 발생했습니다.'; } + /// 422/409 등에서 제공되는 필드별 오류 정보를 추출한다. Map? _extractDetails(dynamic data) { if (data is Map) { final errors = data['errors']; diff --git a/lib/core/permissions/permission_manager.dart b/lib/core/permissions/permission_manager.dart index e936c37..3ec0dba 100644 --- a/lib/core/permissions/permission_manager.dart +++ b/lib/core/permissions/permission_manager.dart @@ -2,8 +2,10 @@ import 'package:flutter/widgets.dart'; import '../config/environment.dart'; +/// 권한 체크를 위한 액션 종류. enum PermissionAction { view, create, edit, delete, restore, approve } +/// 기능별 권한을 확인하고 오버라이드를 지원하는 매니저. class PermissionManager extends ChangeNotifier { PermissionManager({Map>? overrides}) { if (overrides != null) { @@ -13,6 +15,7 @@ class PermissionManager extends ChangeNotifier { final Map> _overrides = {}; + /// 지정한 리소스/행동이 허용되는지 여부를 반환한다. bool can(String resource, PermissionAction action) { final override = _overrides[resource]; if (override != null) { @@ -25,6 +28,7 @@ class PermissionManager extends ChangeNotifier { return Environment.hasPermission(resource, action.name); } + /// 개발/테스트 환경에서 사용할 임시 오버라이드 값을 설정한다. void updateOverrides(Map> overrides) { _overrides ..clear() @@ -33,6 +37,7 @@ class PermissionManager extends ChangeNotifier { } } +/// 위젯 트리에 [PermissionManager]를 전달하는 Inherited 위젯. class PermissionScope extends InheritedNotifier { const PermissionScope({ super.key, @@ -50,6 +55,7 @@ class PermissionScope extends InheritedNotifier { } } +/// 권한에 따라 child/fallback을 노출하거나 숨기는 헬퍼 위젯. class PermissionGate extends StatelessWidget { const PermissionGate({ super.key, @@ -83,5 +89,6 @@ class PermissionGate extends StatelessWidget { } extension PermissionActionKey on PermissionAction { + /// GoRouter 등에서 사용할 문자열 키. String get key => name; } diff --git a/lib/core/routing/app_router.dart b/lib/core/routing/app_router.dart index e3ca599..3c074c4 100644 --- a/lib/core/routing/app_router.dart +++ b/lib/core/routing/app_router.dart @@ -23,8 +23,10 @@ import '../../features/util/postal_search/presentation/pages/postal_search_page. import '../../widgets/app_shell.dart'; import '../constants/app_sections.dart'; +/// 전역 네비게이터 키(로그인/셸 라우터 공용). final _rootNavigatorKey = GlobalKey(debugLabel: 'root'); +/// 애플리케이션 전체 라우팅 구성을 담당하는 GoRouter 인스턴스. final appRouter = GoRouter( navigatorKey: _rootNavigatorKey, initialLocation: loginRoutePath,