- UserRemoteDataSource: API v0.2.1 스펙 완전 대응 • 응답 형식 통일 (success: true 구조) • 페이지네이션 처리 개선 • 에러 핸들링 강화 • 불필요한 파라미터 제거 (includeInactive 등) - UserDto 모델 현대화: • 서버 응답 구조와 100% 일치 • 도메인 모델 변환 메서드 추가 • Freezed 불변성 패턴 완성 - User 도메인 모델 신규 구현: • Clean Architecture 원칙 준수 • UserRole enum 타입 안전성 강화 • 비즈니스 로직 캡슐화 - 사용자 관련 UseCase 리팩토링: • Repository 패턴 완전 적용 • Either<Failure, Success> 에러 처리 • 의존성 주입 최적화 - UI 컨트롤러 및 화면 개선: • API 응답 변경사항 반영 • 사용자 권한 표시 정확성 향상 • 폼 검증 로직 강화 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
199 lines
5.2 KiB
Dart
199 lines
5.2 KiB
Dart
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
import '../../../models/user_model.dart';
|
|
|
|
part 'user_dto.freezed.dart';
|
|
part 'user_dto.g.dart';
|
|
|
|
/// 사용자 데이터 전송 객체 (서버 API v0.2.1 대응)
|
|
/// GET /api/v1/users/{id} 응답 형태
|
|
@freezed
|
|
class UserDto with _$UserDto {
|
|
const UserDto._();
|
|
|
|
const factory UserDto({
|
|
/// 사용자 ID (자동 생성)
|
|
required int id,
|
|
|
|
/// 사용자명 (유니크, 필수)
|
|
required String username,
|
|
|
|
/// 이름 (필수)
|
|
required String name,
|
|
|
|
/// 이메일 (유니크, 필수)
|
|
required String email,
|
|
|
|
/// 전화번호 (선택)
|
|
String? phone,
|
|
|
|
/// 권한 (admin, manager, staff)
|
|
required String role,
|
|
|
|
/// 활성화 상태 (기본값: true)
|
|
@JsonKey(name: 'is_active') required bool isActive,
|
|
|
|
/// 생성일시 (자동 입력)
|
|
@JsonKey(name: 'created_at') required DateTime createdAt,
|
|
|
|
/// 수정일시 (자동 갱신, 선택적)
|
|
@JsonKey(name: 'updated_at') DateTime? updatedAt,
|
|
}) = _UserDto;
|
|
|
|
factory UserDto.fromJson(Map<String, dynamic> json) =>
|
|
_$UserDtoFromJson(json);
|
|
|
|
/// DTO를 도메인 모델로 변환
|
|
User toDomainModel() {
|
|
return User(
|
|
id: id,
|
|
username: username,
|
|
email: email,
|
|
name: name,
|
|
phone: phone,
|
|
role: UserRole.fromString(role),
|
|
isActive: isActive,
|
|
createdAt: createdAt,
|
|
updatedAt: updatedAt,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 사용자 생성 요청 DTO (POST /api/v1/users)
|
|
@freezed
|
|
class CreateUserRequest with _$CreateUserRequest {
|
|
const factory CreateUserRequest({
|
|
/// 사용자명 (필수, 유니크, 3자 이상)
|
|
required String username,
|
|
|
|
/// 이메일 (필수, 유니크, 이메일 형식)
|
|
required String email,
|
|
|
|
/// 비밀번호 (필수, 6자 이상)
|
|
required String password,
|
|
|
|
/// 이름 (필수)
|
|
required String name,
|
|
|
|
/// 전화번호 (선택, "010-1234-5678" 형태)
|
|
String? phone,
|
|
|
|
/// 권한 (필수: admin, manager, staff)
|
|
required String role,
|
|
}) = _CreateUserRequest;
|
|
|
|
factory CreateUserRequest.fromJson(Map<String, dynamic> json) =>
|
|
_$CreateUserRequestFromJson(json);
|
|
|
|
/// 도메인 모델에서 생성 요청 DTO로 변환
|
|
factory CreateUserRequest.fromDomain(User user, String password) {
|
|
return CreateUserRequest(
|
|
username: user.username,
|
|
email: user.email,
|
|
password: password,
|
|
name: user.name,
|
|
phone: user.phone,
|
|
role: user.role.name,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 사용자 수정 요청 DTO (PUT /api/v1/users/{id})
|
|
@freezed
|
|
class UpdateUserRequest with _$UpdateUserRequest {
|
|
const factory UpdateUserRequest({
|
|
/// 이름 (선택)
|
|
String? name,
|
|
|
|
/// 이메일 (선택, 유니크, 이메일 형식)
|
|
String? email,
|
|
|
|
/// 비밀번호 (선택, 6자 이상)
|
|
String? password,
|
|
|
|
/// 전화번호 (선택)
|
|
String? phone,
|
|
|
|
/// 권한 (선택: admin, manager, staff)
|
|
String? role,
|
|
}) = _UpdateUserRequest;
|
|
|
|
factory UpdateUserRequest.fromJson(Map<String, dynamic> json) =>
|
|
_$UpdateUserRequestFromJson(json);
|
|
|
|
/// 도메인 모델에서 수정 요청 DTO로 변환
|
|
factory UpdateUserRequest.fromDomain(User user, {String? newPassword}) {
|
|
return UpdateUserRequest(
|
|
name: user.name,
|
|
email: user.email,
|
|
password: newPassword,
|
|
phone: user.phone,
|
|
role: user.role.name,
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 사용자명 중복 확인 응답 DTO
|
|
@freezed
|
|
class CheckUsernameResponse with _$CheckUsernameResponse {
|
|
const factory CheckUsernameResponse({
|
|
required bool available,
|
|
String? message,
|
|
}) = _CheckUsernameResponse;
|
|
|
|
factory CheckUsernameResponse.fromJson(Map<String, dynamic> json) =>
|
|
_$CheckUsernameResponseFromJson(json);
|
|
}
|
|
|
|
/// 사용자 목록 응답 DTO (기존 PaginatedResponse 형태 유지)
|
|
@freezed
|
|
class UserListDto with _$UserListDto {
|
|
const UserListDto._();
|
|
|
|
const factory UserListDto({
|
|
required List<UserDto> users,
|
|
required int total,
|
|
required int page,
|
|
@JsonKey(name: 'per_page') required int perPage,
|
|
@JsonKey(name: 'total_pages') required int totalPages,
|
|
}) = _UserListDto;
|
|
|
|
// 페이지네이션 응답과 호환성을 위한 getter들
|
|
List<UserDto> get items => users;
|
|
int get size => perPage;
|
|
int get totalElements => total;
|
|
bool get first => page <= 1;
|
|
bool get last => page >= totalPages;
|
|
|
|
factory UserListDto.fromJson(Map<String, dynamic> json) =>
|
|
_$UserListDtoFromJson(json);
|
|
|
|
/// DTO 목록을 도메인 모델 목록으로 변환
|
|
List<User> toDomainModels() {
|
|
return users.map((dto) => dto.toDomainModel()).toList();
|
|
}
|
|
}
|
|
|
|
/// 사용자 상세 응답 DTO
|
|
@freezed
|
|
class UserDetailDto with _$UserDetailDto {
|
|
const factory UserDetailDto({
|
|
required UserDto user,
|
|
}) = _UserDetailDto;
|
|
|
|
factory UserDetailDto.fromJson(Map<String, dynamic> json) =>
|
|
_$UserDetailDtoFromJson(json);
|
|
}
|
|
|
|
/// 일반적인 사용자 API 응답 DTO
|
|
@freezed
|
|
class UserResponse with _$UserResponse {
|
|
const factory UserResponse({
|
|
required UserDto user,
|
|
String? message,
|
|
}) = _UserResponse;
|
|
|
|
factory UserResponse.fromJson(Map<String, dynamic> json) =>
|
|
_$UserResponseFromJson(json);
|
|
}
|
|
|