fix: API 응답 파싱 오류 수정 및 에러 처리 개선

주요 변경사항:
- 창고 관리 API 응답 구조와 DTO 불일치 수정
  - WarehouseLocationDto에 code, manager_phone 필드 추가
  - RemoteDataSource에서 API 응답을 DTO 구조에 맞게 변환
- 회사 관리 API 응답 파싱 오류 수정
  - CompanyResponse의 필수 필드를 nullable로 변경
  - PaginatedResponse 구조 매핑 로직 개선
- 에러 처리 및 로깅 개선
  - Service Layer에 상세 에러 로깅 추가
  - Controller에서 에러 타입별 처리
- 새로운 유틸리티 추가
  - ResponseInterceptor: API 응답 정규화
  - DebugLogger: 디버깅 도구
  - HealthCheckService: 서버 상태 확인
- 문서화
  - API 통합 테스트 가이드
  - 에러 분석 보고서
  - 리팩토링 계획서
This commit is contained in:
JiWoong Sul
2025-07-31 19:15:39 +09:00
parent ad2c699ff7
commit f08b7fec79
89 changed files with 10521 additions and 892 deletions

View File

@@ -7,19 +7,19 @@ part 'equipment_list_dto.g.dart';
class EquipmentListDto with _$EquipmentListDto {
const factory EquipmentListDto({
required int id,
required String equipmentNumber,
@JsonKey(name: 'equipment_number') required String equipmentNumber,
required String manufacturer,
String? modelName,
String? serialNumber,
@JsonKey(name: 'model_name') String? modelName,
@JsonKey(name: 'serial_number') String? serialNumber,
required String status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
required DateTime createdAt,
@JsonKey(name: 'current_company_id') int? currentCompanyId,
@JsonKey(name: 'current_branch_id') int? currentBranchId,
@JsonKey(name: 'warehouse_location_id') int? warehouseLocationId,
@JsonKey(name: 'created_at') required DateTime createdAt,
// 추가 필드 (조인된 데이터)
String? companyName,
String? branchName,
String? warehouseName,
@JsonKey(name: 'company_name') String? companyName,
@JsonKey(name: 'branch_name') String? branchName,
@JsonKey(name: 'warehouse_name') String? warehouseName,
}) = _EquipmentListDto;
factory EquipmentListDto.fromJson(Map<String, dynamic> json) =>

View File

@@ -21,18 +21,28 @@ EquipmentListDto _$EquipmentListDtoFromJson(Map<String, dynamic> json) {
/// @nodoc
mixin _$EquipmentListDto {
int get id => throw _privateConstructorUsedError;
@JsonKey(name: 'equipment_number')
String get equipmentNumber => throw _privateConstructorUsedError;
String get manufacturer => throw _privateConstructorUsedError;
@JsonKey(name: 'model_name')
String? get modelName => throw _privateConstructorUsedError;
@JsonKey(name: 'serial_number')
String? get serialNumber => throw _privateConstructorUsedError;
String get status => throw _privateConstructorUsedError;
@JsonKey(name: 'current_company_id')
int? get currentCompanyId => throw _privateConstructorUsedError;
@JsonKey(name: 'current_branch_id')
int? get currentBranchId => throw _privateConstructorUsedError;
@JsonKey(name: 'warehouse_location_id')
int? get warehouseLocationId => throw _privateConstructorUsedError;
@JsonKey(name: 'created_at')
DateTime get createdAt =>
throw _privateConstructorUsedError; // 추가 필드 (조인된 데이터)
@JsonKey(name: 'company_name')
String? get companyName => throw _privateConstructorUsedError;
@JsonKey(name: 'branch_name')
String? get branchName => throw _privateConstructorUsedError;
@JsonKey(name: 'warehouse_name')
String? get warehouseName => throw _privateConstructorUsedError;
/// Serializes this EquipmentListDto to a JSON map.
@@ -53,18 +63,18 @@ abstract class $EquipmentListDtoCopyWith<$Res> {
@useResult
$Res call(
{int id,
String equipmentNumber,
@JsonKey(name: 'equipment_number') String equipmentNumber,
String manufacturer,
String? modelName,
String? serialNumber,
@JsonKey(name: 'model_name') String? modelName,
@JsonKey(name: 'serial_number') String? serialNumber,
String status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
DateTime createdAt,
String? companyName,
String? branchName,
String? warehouseName});
@JsonKey(name: 'current_company_id') int? currentCompanyId,
@JsonKey(name: 'current_branch_id') int? currentBranchId,
@JsonKey(name: 'warehouse_location_id') int? warehouseLocationId,
@JsonKey(name: 'created_at') DateTime createdAt,
@JsonKey(name: 'company_name') String? companyName,
@JsonKey(name: 'branch_name') String? branchName,
@JsonKey(name: 'warehouse_name') String? warehouseName});
}
/// @nodoc
@@ -163,18 +173,18 @@ abstract class _$$EquipmentListDtoImplCopyWith<$Res>
@useResult
$Res call(
{int id,
String equipmentNumber,
@JsonKey(name: 'equipment_number') String equipmentNumber,
String manufacturer,
String? modelName,
String? serialNumber,
@JsonKey(name: 'model_name') String? modelName,
@JsonKey(name: 'serial_number') String? serialNumber,
String status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
DateTime createdAt,
String? companyName,
String? branchName,
String? warehouseName});
@JsonKey(name: 'current_company_id') int? currentCompanyId,
@JsonKey(name: 'current_branch_id') int? currentBranchId,
@JsonKey(name: 'warehouse_location_id') int? warehouseLocationId,
@JsonKey(name: 'created_at') DateTime createdAt,
@JsonKey(name: 'company_name') String? companyName,
@JsonKey(name: 'branch_name') String? branchName,
@JsonKey(name: 'warehouse_name') String? warehouseName});
}
/// @nodoc
@@ -266,18 +276,18 @@ class __$$EquipmentListDtoImplCopyWithImpl<$Res>
class _$EquipmentListDtoImpl implements _EquipmentListDto {
const _$EquipmentListDtoImpl(
{required this.id,
required this.equipmentNumber,
@JsonKey(name: 'equipment_number') required this.equipmentNumber,
required this.manufacturer,
this.modelName,
this.serialNumber,
@JsonKey(name: 'model_name') this.modelName,
@JsonKey(name: 'serial_number') this.serialNumber,
required this.status,
this.currentCompanyId,
this.currentBranchId,
this.warehouseLocationId,
required this.createdAt,
this.companyName,
this.branchName,
this.warehouseName});
@JsonKey(name: 'current_company_id') this.currentCompanyId,
@JsonKey(name: 'current_branch_id') this.currentBranchId,
@JsonKey(name: 'warehouse_location_id') this.warehouseLocationId,
@JsonKey(name: 'created_at') required this.createdAt,
@JsonKey(name: 'company_name') this.companyName,
@JsonKey(name: 'branch_name') this.branchName,
@JsonKey(name: 'warehouse_name') this.warehouseName});
factory _$EquipmentListDtoImpl.fromJson(Map<String, dynamic> json) =>
_$$EquipmentListDtoImplFromJson(json);
@@ -285,29 +295,39 @@ class _$EquipmentListDtoImpl implements _EquipmentListDto {
@override
final int id;
@override
@JsonKey(name: 'equipment_number')
final String equipmentNumber;
@override
final String manufacturer;
@override
@JsonKey(name: 'model_name')
final String? modelName;
@override
@JsonKey(name: 'serial_number')
final String? serialNumber;
@override
final String status;
@override
@JsonKey(name: 'current_company_id')
final int? currentCompanyId;
@override
@JsonKey(name: 'current_branch_id')
final int? currentBranchId;
@override
@JsonKey(name: 'warehouse_location_id')
final int? warehouseLocationId;
@override
@JsonKey(name: 'created_at')
final DateTime createdAt;
// 추가 필드 (조인된 데이터)
@override
@JsonKey(name: 'company_name')
final String? companyName;
@override
@JsonKey(name: 'branch_name')
final String? branchName;
@override
@JsonKey(name: 'warehouse_name')
final String? warehouseName;
@override
@@ -384,17 +404,18 @@ class _$EquipmentListDtoImpl implements _EquipmentListDto {
abstract class _EquipmentListDto implements EquipmentListDto {
const factory _EquipmentListDto(
{required final int id,
required final String equipmentNumber,
@JsonKey(name: 'equipment_number') required final String equipmentNumber,
required final String manufacturer,
final String? modelName,
final String? serialNumber,
@JsonKey(name: 'model_name') final String? modelName,
@JsonKey(name: 'serial_number') final String? serialNumber,
required final String status,
final int? currentCompanyId,
final int? currentBranchId,
final int? warehouseLocationId,
required final DateTime createdAt,
final String? companyName,
final String? branchName,
@JsonKey(name: 'current_company_id') final int? currentCompanyId,
@JsonKey(name: 'current_branch_id') final int? currentBranchId,
@JsonKey(name: 'warehouse_location_id') final int? warehouseLocationId,
@JsonKey(name: 'created_at') required final DateTime createdAt,
@JsonKey(name: 'company_name') final String? companyName,
@JsonKey(name: 'branch_name') final String? branchName,
@JsonKey(name: 'warehouse_name')
final String? warehouseName}) = _$EquipmentListDtoImpl;
factory _EquipmentListDto.fromJson(Map<String, dynamic> json) =
@@ -403,28 +424,38 @@ abstract class _EquipmentListDto implements EquipmentListDto {
@override
int get id;
@override
@JsonKey(name: 'equipment_number')
String get equipmentNumber;
@override
String get manufacturer;
@override
@JsonKey(name: 'model_name')
String? get modelName;
@override
@JsonKey(name: 'serial_number')
String? get serialNumber;
@override
String get status;
@override
@JsonKey(name: 'current_company_id')
int? get currentCompanyId;
@override
@JsonKey(name: 'current_branch_id')
int? get currentBranchId;
@override
@JsonKey(name: 'warehouse_location_id')
int? get warehouseLocationId;
@override
@JsonKey(name: 'created_at')
DateTime get createdAt; // 추가 필드 (조인된 데이터)
@override
@JsonKey(name: 'company_name')
String? get companyName;
@override
@JsonKey(name: 'branch_name')
String? get branchName;
@override
@JsonKey(name: 'warehouse_name')
String? get warehouseName;
/// Create a copy of EquipmentListDto

View File

@@ -10,34 +10,34 @@ _$EquipmentListDtoImpl _$$EquipmentListDtoImplFromJson(
Map<String, dynamic> json) =>
_$EquipmentListDtoImpl(
id: (json['id'] as num).toInt(),
equipmentNumber: json['equipmentNumber'] as String,
equipmentNumber: json['equipment_number'] as String,
manufacturer: json['manufacturer'] as String,
modelName: json['modelName'] as String?,
serialNumber: json['serialNumber'] as String?,
modelName: json['model_name'] as String?,
serialNumber: json['serial_number'] as String?,
status: json['status'] as String,
currentCompanyId: (json['currentCompanyId'] as num?)?.toInt(),
currentBranchId: (json['currentBranchId'] as num?)?.toInt(),
warehouseLocationId: (json['warehouseLocationId'] as num?)?.toInt(),
createdAt: DateTime.parse(json['createdAt'] as String),
companyName: json['companyName'] as String?,
branchName: json['branchName'] as String?,
warehouseName: json['warehouseName'] as String?,
currentCompanyId: (json['current_company_id'] as num?)?.toInt(),
currentBranchId: (json['current_branch_id'] as num?)?.toInt(),
warehouseLocationId: (json['warehouse_location_id'] as num?)?.toInt(),
createdAt: DateTime.parse(json['created_at'] as String),
companyName: json['company_name'] as String?,
branchName: json['branch_name'] as String?,
warehouseName: json['warehouse_name'] as String?,
);
Map<String, dynamic> _$$EquipmentListDtoImplToJson(
_$EquipmentListDtoImpl instance) =>
<String, dynamic>{
'id': instance.id,
'equipmentNumber': instance.equipmentNumber,
'equipment_number': instance.equipmentNumber,
'manufacturer': instance.manufacturer,
'modelName': instance.modelName,
'serialNumber': instance.serialNumber,
'model_name': instance.modelName,
'serial_number': instance.serialNumber,
'status': instance.status,
'currentCompanyId': instance.currentCompanyId,
'currentBranchId': instance.currentBranchId,
'warehouseLocationId': instance.warehouseLocationId,
'createdAt': instance.createdAt.toIso8601String(),
'companyName': instance.companyName,
'branchName': instance.branchName,
'warehouseName': instance.warehouseName,
'current_company_id': instance.currentCompanyId,
'current_branch_id': instance.currentBranchId,
'warehouse_location_id': instance.warehouseLocationId,
'created_at': instance.createdAt.toIso8601String(),
'company_name': instance.companyName,
'branch_name': instance.branchName,
'warehouse_name': instance.warehouseName,
};

View File

@@ -1,4 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:superport/core/utils/equipment_status_converter.dart';
part 'equipment_request.freezed.dart';
part 'equipment_request.g.dart';
@@ -34,7 +35,7 @@ class UpdateEquipmentRequest with _$UpdateEquipmentRequest {
String? barcode,
DateTime? purchaseDate,
double? purchasePrice,
String? status,
@EquipmentStatusJsonConverter() String? status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,

View File

@@ -389,6 +389,7 @@ mixin _$UpdateEquipmentRequest {
String? get barcode => throw _privateConstructorUsedError;
DateTime? get purchaseDate => throw _privateConstructorUsedError;
double? get purchasePrice => throw _privateConstructorUsedError;
@EquipmentStatusJsonConverter()
String? get status => throw _privateConstructorUsedError;
int? get currentCompanyId => throw _privateConstructorUsedError;
int? get currentBranchId => throw _privateConstructorUsedError;
@@ -423,7 +424,7 @@ abstract class $UpdateEquipmentRequestCopyWith<$Res> {
String? barcode,
DateTime? purchaseDate,
double? purchasePrice,
String? status,
@EquipmentStatusJsonConverter() String? status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
@@ -553,7 +554,7 @@ abstract class _$$UpdateEquipmentRequestImplCopyWith<$Res>
String? barcode,
DateTime? purchaseDate,
double? purchasePrice,
String? status,
@EquipmentStatusJsonConverter() String? status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
@@ -676,7 +677,7 @@ class _$UpdateEquipmentRequestImpl implements _UpdateEquipmentRequest {
this.barcode,
this.purchaseDate,
this.purchasePrice,
this.status,
@EquipmentStatusJsonConverter() this.status,
this.currentCompanyId,
this.currentBranchId,
this.warehouseLocationId,
@@ -706,6 +707,7 @@ class _$UpdateEquipmentRequestImpl implements _UpdateEquipmentRequest {
@override
final double? purchasePrice;
@override
@EquipmentStatusJsonConverter()
final String? status;
@override
final int? currentCompanyId;
@@ -810,7 +812,7 @@ abstract class _UpdateEquipmentRequest implements UpdateEquipmentRequest {
final String? barcode,
final DateTime? purchaseDate,
final double? purchasePrice,
final String? status,
@EquipmentStatusJsonConverter() final String? status,
final int? currentCompanyId,
final int? currentBranchId,
final int? warehouseLocationId,
@@ -840,6 +842,7 @@ abstract class _UpdateEquipmentRequest implements UpdateEquipmentRequest {
@override
double? get purchasePrice;
@override
@EquipmentStatusJsonConverter()
String? get status;
@override
int? get currentCompanyId;

View File

@@ -52,7 +52,8 @@ _$UpdateEquipmentRequestImpl _$$UpdateEquipmentRequestImplFromJson(
? null
: DateTime.parse(json['purchaseDate'] as String),
purchasePrice: (json['purchasePrice'] as num?)?.toDouble(),
status: json['status'] as String?,
status: _$JsonConverterFromJson<String, String>(
json['status'], const EquipmentStatusJsonConverter().fromJson),
currentCompanyId: (json['currentCompanyId'] as num?)?.toInt(),
currentBranchId: (json['currentBranchId'] as num?)?.toInt(),
warehouseLocationId: (json['warehouseLocationId'] as num?)?.toInt(),
@@ -77,7 +78,8 @@ Map<String, dynamic> _$$UpdateEquipmentRequestImplToJson(
'barcode': instance.barcode,
'purchaseDate': instance.purchaseDate?.toIso8601String(),
'purchasePrice': instance.purchasePrice,
'status': instance.status,
'status': _$JsonConverterToJson<String, String>(
instance.status, const EquipmentStatusJsonConverter().toJson),
'currentCompanyId': instance.currentCompanyId,
'currentBranchId': instance.currentBranchId,
'warehouseLocationId': instance.warehouseLocationId,
@@ -85,3 +87,15 @@ Map<String, dynamic> _$$UpdateEquipmentRequestImplToJson(
'nextInspectionDate': instance.nextInspectionDate?.toIso8601String(),
'remark': instance.remark,
};
Value? _$JsonConverterFromJson<Json, Value>(
Object? json,
Value? Function(Json json) fromJson,
) =>
json == null ? null : fromJson(json as Json);
Json? _$JsonConverterToJson<Json, Value>(
Value? value,
Json? Function(Value value) toJson,
) =>
value == null ? null : toJson(value);

View File

@@ -1,4 +1,5 @@
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:superport/core/utils/equipment_status_converter.dart';
part 'equipment_response.freezed.dart';
part 'equipment_response.g.dart';
@@ -17,7 +18,7 @@ class EquipmentResponse with _$EquipmentResponse {
String? barcode,
DateTime? purchaseDate,
double? purchasePrice,
required String status,
@EquipmentStatusJsonConverter() required String status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,

View File

@@ -31,6 +31,7 @@ mixin _$EquipmentResponse {
String? get barcode => throw _privateConstructorUsedError;
DateTime? get purchaseDate => throw _privateConstructorUsedError;
double? get purchasePrice => throw _privateConstructorUsedError;
@EquipmentStatusJsonConverter()
String get status => throw _privateConstructorUsedError;
int? get currentCompanyId => throw _privateConstructorUsedError;
int? get currentBranchId => throw _privateConstructorUsedError;
@@ -73,7 +74,7 @@ abstract class $EquipmentResponseCopyWith<$Res> {
String? barcode,
DateTime? purchaseDate,
double? purchasePrice,
String status,
@EquipmentStatusJsonConverter() String status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
@@ -243,7 +244,7 @@ abstract class _$$EquipmentResponseImplCopyWith<$Res>
String? barcode,
DateTime? purchaseDate,
double? purchasePrice,
String status,
@EquipmentStatusJsonConverter() String status,
int? currentCompanyId,
int? currentBranchId,
int? warehouseLocationId,
@@ -406,7 +407,7 @@ class _$EquipmentResponseImpl implements _EquipmentResponse {
this.barcode,
this.purchaseDate,
this.purchasePrice,
required this.status,
@EquipmentStatusJsonConverter() required this.status,
this.currentCompanyId,
this.currentBranchId,
this.warehouseLocationId,
@@ -445,6 +446,7 @@ class _$EquipmentResponseImpl implements _EquipmentResponse {
@override
final double? purchasePrice;
@override
@EquipmentStatusJsonConverter()
final String status;
@override
final int? currentCompanyId;
@@ -583,7 +585,7 @@ abstract class _EquipmentResponse implements EquipmentResponse {
final String? barcode,
final DateTime? purchaseDate,
final double? purchasePrice,
required final String status,
@EquipmentStatusJsonConverter() required final String status,
final int? currentCompanyId,
final int? currentBranchId,
final int? warehouseLocationId,
@@ -622,6 +624,7 @@ abstract class _EquipmentResponse implements EquipmentResponse {
@override
double? get purchasePrice;
@override
@EquipmentStatusJsonConverter()
String get status;
@override
int? get currentCompanyId;

View File

@@ -22,7 +22,8 @@ _$EquipmentResponseImpl _$$EquipmentResponseImplFromJson(
? null
: DateTime.parse(json['purchaseDate'] as String),
purchasePrice: (json['purchasePrice'] as num?)?.toDouble(),
status: json['status'] as String,
status: const EquipmentStatusJsonConverter()
.fromJson(json['status'] as String),
currentCompanyId: (json['currentCompanyId'] as num?)?.toInt(),
currentBranchId: (json['currentBranchId'] as num?)?.toInt(),
warehouseLocationId: (json['warehouseLocationId'] as num?)?.toInt(),
@@ -54,7 +55,7 @@ Map<String, dynamic> _$$EquipmentResponseImplToJson(
'barcode': instance.barcode,
'purchaseDate': instance.purchaseDate?.toIso8601String(),
'purchasePrice': instance.purchasePrice,
'status': instance.status,
'status': const EquipmentStatusJsonConverter().toJson(instance.status),
'currentCompanyId': instance.currentCompanyId,
'currentBranchId': instance.currentBranchId,
'warehouseLocationId': instance.warehouseLocationId,