Core 네트워크/권한 주석 보강

This commit is contained in:
JiWoong Sul
2025-09-29 17:46:16 +09:00
parent 89fc296765
commit 242e290722
5 changed files with 22 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide; import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide;
/// 사이드바/내비게이션용 페이지 정보.
class AppPageDescriptor { class AppPageDescriptor {
const AppPageDescriptor({ const AppPageDescriptor({
required this.path, required this.path,
@@ -15,6 +16,7 @@ class AppPageDescriptor {
final String summary; final String summary;
} }
/// 메뉴 섹션을 나타내는 데이터 클래스.
class AppSectionDescriptor { class AppSectionDescriptor {
const AppSectionDescriptor({required this.label, required this.pages}); const AppSectionDescriptor({required this.label, required this.pages});
@@ -22,9 +24,13 @@ class AppSectionDescriptor {
final List<AppPageDescriptor> pages; final List<AppPageDescriptor> pages;
} }
/// 로그인 라우트 경로.
const loginRoutePath = '/login'; const loginRoutePath = '/login';
/// 대시보드 라우트 경로.
const dashboardRoutePath = '/dashboard'; const dashboardRoutePath = '/dashboard';
/// 네비게이션 구성을 정의한 섹션 목록.
const appSections = <AppSectionDescriptor>[ const appSections = <AppSectionDescriptor>[
AppSectionDescriptor( AppSectionDescriptor(
label: '대시보드', label: '대시보드',

View File

@@ -1,5 +1,3 @@
// ignore_for_file: public_member_api_docs
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'api_error.dart'; import 'api_error.dart';
@@ -93,6 +91,7 @@ class ApiClient {
); );
} }
/// Dio 요청을 실행하고 `DioException`을 공통 예외 유형으로 변환한다.
Future<Response<T>> _wrap<T>(Future<Response<T>> Function() request) async { Future<Response<T>> _wrap<T>(Future<Response<T>> Function() request) async {
try { try {
return await request(); return await request();

View File

@@ -1,5 +1,6 @@
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
/// API 호출 실패 유형.
enum ApiErrorCode { enum ApiErrorCode {
badRequest, badRequest,
unauthorized, unauthorized,
@@ -12,6 +13,7 @@ enum ApiErrorCode {
unknown, unknown,
} }
/// API 호출 시 공통으로 던지는 예외 모델.
class ApiException implements Exception { class ApiException implements Exception {
const ApiException({ const ApiException({
required this.code, required this.code,
@@ -32,9 +34,11 @@ class ApiException implements Exception {
'ApiException(code: $code, statusCode: $statusCode, message: $message)'; 'ApiException(code: $code, statusCode: $statusCode, message: $message)';
} }
/// Dio 예외를 [ApiException]으로 변환하는 매퍼.
class ApiErrorMapper { class ApiErrorMapper {
const ApiErrorMapper(); const ApiErrorMapper();
/// Dio 예외 세부 정보를 분석해 적절한 [ApiException]을 생성한다.
ApiException map(DioException error) { ApiException map(DioException error) {
final status = error.response?.statusCode; final status = error.response?.statusCode;
final data = error.response?.data; final data = error.response?.data;
@@ -124,6 +128,7 @@ class ApiErrorMapper {
); );
} }
/// 응답 바디 혹은 Dio 예외 객체에서 사용자용 메시지를 추출한다.
String _resolveMessage(DioException error, dynamic data) { String _resolveMessage(DioException error, dynamic data) {
if (data is Map<String, dynamic>) { if (data is Map<String, dynamic>) {
final message = data['message'] ?? data['error']; final message = data['message'] ?? data['error'];
@@ -136,6 +141,7 @@ class ApiErrorMapper {
return error.message ?? '요청 처리 중 알 수 없는 오류가 발생했습니다.'; return error.message ?? '요청 처리 중 알 수 없는 오류가 발생했습니다.';
} }
/// 422/409 등에서 제공되는 필드별 오류 정보를 추출한다.
Map<String, dynamic>? _extractDetails(dynamic data) { Map<String, dynamic>? _extractDetails(dynamic data) {
if (data is Map<String, dynamic>) { if (data is Map<String, dynamic>) {
final errors = data['errors']; final errors = data['errors'];

View File

@@ -2,8 +2,10 @@ import 'package:flutter/widgets.dart';
import '../config/environment.dart'; import '../config/environment.dart';
/// 권한 체크를 위한 액션 종류.
enum PermissionAction { view, create, edit, delete, restore, approve } enum PermissionAction { view, create, edit, delete, restore, approve }
/// 기능별 권한을 확인하고 오버라이드를 지원하는 매니저.
class PermissionManager extends ChangeNotifier { class PermissionManager extends ChangeNotifier {
PermissionManager({Map<String, Set<PermissionAction>>? overrides}) { PermissionManager({Map<String, Set<PermissionAction>>? overrides}) {
if (overrides != null) { if (overrides != null) {
@@ -13,6 +15,7 @@ class PermissionManager extends ChangeNotifier {
final Map<String, Set<PermissionAction>> _overrides = {}; final Map<String, Set<PermissionAction>> _overrides = {};
/// 지정한 리소스/행동이 허용되는지 여부를 반환한다.
bool can(String resource, PermissionAction action) { bool can(String resource, PermissionAction action) {
final override = _overrides[resource]; final override = _overrides[resource];
if (override != null) { if (override != null) {
@@ -25,6 +28,7 @@ class PermissionManager extends ChangeNotifier {
return Environment.hasPermission(resource, action.name); return Environment.hasPermission(resource, action.name);
} }
/// 개발/테스트 환경에서 사용할 임시 오버라이드 값을 설정한다.
void updateOverrides(Map<String, Set<PermissionAction>> overrides) { void updateOverrides(Map<String, Set<PermissionAction>> overrides) {
_overrides _overrides
..clear() ..clear()
@@ -33,6 +37,7 @@ class PermissionManager extends ChangeNotifier {
} }
} }
/// 위젯 트리에 [PermissionManager]를 전달하는 Inherited 위젯.
class PermissionScope extends InheritedNotifier<PermissionManager> { class PermissionScope extends InheritedNotifier<PermissionManager> {
const PermissionScope({ const PermissionScope({
super.key, super.key,
@@ -50,6 +55,7 @@ class PermissionScope extends InheritedNotifier<PermissionManager> {
} }
} }
/// 권한에 따라 child/fallback을 노출하거나 숨기는 헬퍼 위젯.
class PermissionGate extends StatelessWidget { class PermissionGate extends StatelessWidget {
const PermissionGate({ const PermissionGate({
super.key, super.key,
@@ -83,5 +89,6 @@ class PermissionGate extends StatelessWidget {
} }
extension PermissionActionKey on PermissionAction { extension PermissionActionKey on PermissionAction {
/// GoRouter 등에서 사용할 문자열 키.
String get key => name; String get key => name;
} }

View File

@@ -23,8 +23,10 @@ import '../../features/util/postal_search/presentation/pages/postal_search_page.
import '../../widgets/app_shell.dart'; import '../../widgets/app_shell.dart';
import '../constants/app_sections.dart'; import '../constants/app_sections.dart';
/// 전역 네비게이터 키(로그인/셸 라우터 공용).
final _rootNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'root'); final _rootNavigatorKey = GlobalKey<NavigatorState>(debugLabel: 'root');
/// 애플리케이션 전체 라우팅 구성을 담당하는 GoRouter 인스턴스.
final appRouter = GoRouter( final appRouter = GoRouter(
navigatorKey: _rootNavigatorKey, navigatorKey: _rootNavigatorKey,
initialLocation: loginRoutePath, initialLocation: loginRoutePath,