refactor: 사용하지 않는 파일 9개 정리
- 코드베이스 분석을 통해 사용되지 않는 파일 식별 및 삭제 - migration, utils, models, screens 등 미사용 파일 제거 - flutter analyze 결과: 63개 → 48개 오류로 개선 - 전체 .dart 파일 수: 365개로 정리 완료 삭제된 파일: - lib/core/migrations/execute_migration.dart - lib/core/utils/login_diagnostics.dart - lib/utils/equipment_display_helper.dart - lib/utils/formatters/business_number_formatter.dart - lib/utils/user_utils.dart - lib/models/user_phone_field.dart - lib/screens/rent/rent_list_screen_simple.dart - lib/screens/common/widgets/category_autocomplete_field.dart - lib/screens/common/widgets/company_branch_dropdown.dart ✅ 빌드 검증 완료: flutter pub get, build_runner 성공 ✅ Phase 10 이후 추가 코드베이스 정리 완료
This commit is contained in:
@@ -1,326 +0,0 @@
|
||||
/// License → Maintenance 마이그레이션 실행 스크립트
|
||||
///
|
||||
/// 사용법:
|
||||
/// dart run lib/core/migrations/execute_migration.dart
|
||||
///
|
||||
/// 옵션:
|
||||
/// --dry-run: 실제 데이터 변경 없이 시뮬레이션만 수행
|
||||
/// --rollback: 이전 백업에서 롤백 실행
|
||||
/// --validate: 마이그레이션 후 데이터 검증만 수행
|
||||
library;
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'license_to_maintenance_migration.dart';
|
||||
import 'maintenance_data_validator.dart';
|
||||
|
||||
class MigrationExecutor {
|
||||
static const String apiBaseUrl = 'http://43.201.34.104:8080/api/v1';
|
||||
static const String backupPath = './migration_backup.json';
|
||||
|
||||
final Dio _dio;
|
||||
String? _authToken;
|
||||
|
||||
MigrationExecutor() : _dio = Dio(BaseOptions(
|
||||
baseUrl: apiBaseUrl,
|
||||
connectTimeout: const Duration(seconds: 30),
|
||||
receiveTimeout: const Duration(seconds: 30),
|
||||
));
|
||||
|
||||
/// 마이그레이션 실행
|
||||
Future<void> execute({bool isDryRun = false}) async {
|
||||
print('=' * 60);
|
||||
print('License → Maintenance 마이그레이션 시작');
|
||||
print('=' * 60);
|
||||
print('모드: ${isDryRun ? "DRY RUN (시뮬레이션)" : "실제 실행"}');
|
||||
print('시작 시간: ${DateTime.now()}');
|
||||
print('-' * 60);
|
||||
|
||||
try {
|
||||
// 1. 인증
|
||||
print('\n[1/7] API 인증 중...');
|
||||
await _authenticate();
|
||||
|
||||
// 2. 기존 License 데이터 가져오기
|
||||
print('\n[2/7] License 데이터 로딩 중...');
|
||||
final licenseData = await _fetchLicenseData();
|
||||
print(' → ${licenseData.length}개 License 발견');
|
||||
|
||||
// 3. Equipment 및 Equipment History 데이터 가져오기
|
||||
print('\n[3/7] Equipment 관련 데이터 로딩 중...');
|
||||
final equipmentData = await _fetchEquipmentData();
|
||||
final equipmentHistoryData = await _fetchEquipmentHistoryData();
|
||||
print(' → ${equipmentData.length}개 Equipment 발견');
|
||||
print(' → ${equipmentHistoryData.length}개 Equipment History 발견');
|
||||
|
||||
// 4. 마이그레이션 실행
|
||||
print('\n[4/7] 데이터 변환 중...');
|
||||
final result = await LicenseToMaintenanceMigration.migrate(
|
||||
licenseData: licenseData,
|
||||
equipmentData: equipmentData,
|
||||
equipmentHistoryData: equipmentHistoryData,
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
throw Exception('마이그레이션 실패: ${result.error}');
|
||||
}
|
||||
|
||||
// 5. 백업 저장
|
||||
print('\n[5/7] 백업 저장 중...');
|
||||
if (!isDryRun) {
|
||||
await _saveBackup(result.backup!);
|
||||
print(' → 백업 저장 완료: $backupPath');
|
||||
} else {
|
||||
print(' → [DRY RUN] 백업 저장 건너뜀');
|
||||
}
|
||||
|
||||
// 6. Maintenance 데이터 저장
|
||||
print('\n[6/7] Maintenance 데이터 저장 중...');
|
||||
if (!isDryRun) {
|
||||
await _saveMaintenanceData(result.maintenanceData!);
|
||||
print(' → ${result.maintenanceData!.length}개 Maintenance 저장 완료');
|
||||
} else {
|
||||
print(' → [DRY RUN] 실제 저장 건너뜀');
|
||||
_printSampleData(result.maintenanceData!);
|
||||
}
|
||||
|
||||
// 7. 검증
|
||||
print('\n[7/7] 데이터 검증 중...');
|
||||
final validationReport = await MaintenanceDataValidator.validate(
|
||||
maintenanceData: result.maintenanceData!,
|
||||
equipmentHistoryData: [], // TODO: 실제 equipment history 데이터 로드
|
||||
);
|
||||
|
||||
_printValidationReport(validationReport);
|
||||
|
||||
// 완료
|
||||
print('\n${'=' * 60}');
|
||||
print('마이그레이션 ${isDryRun ? "시뮬레이션" : "실행"} 완료!');
|
||||
print('=' * 60);
|
||||
print('통계:');
|
||||
print(' - 총 License: ${result.statistics!.totalCount}개');
|
||||
print(' - 활성: ${result.statistics!.activeCount}개');
|
||||
print(' - 만료 예정: ${result.statistics!.upcomingCount}개');
|
||||
print(' - 만료됨: ${result.statistics!.expiredCount}개');
|
||||
print('종료 시간: ${DateTime.now()}');
|
||||
|
||||
} catch (e) {
|
||||
print('\n❌ 마이그레이션 실패!');
|
||||
print('오류: $e');
|
||||
print('\n롤백이 필요한 경우 다음 명령을 실행하세요:');
|
||||
print('dart run lib/core/migrations/execute_migration.dart --rollback');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// 롤백 실행
|
||||
Future<void> rollback() async {
|
||||
print('=' * 60);
|
||||
print('License → Maintenance 롤백 시작');
|
||||
print('=' * 60);
|
||||
|
||||
try {
|
||||
// 백업 파일 로드
|
||||
final backupFile = File(backupPath);
|
||||
if (!await backupFile.exists()) {
|
||||
throw Exception('백업 파일을 찾을 수 없습니다: $backupPath');
|
||||
}
|
||||
|
||||
final backupContent = await backupFile.readAsString();
|
||||
final backup = jsonDecode(backupContent) as Map<String, dynamic>;
|
||||
|
||||
print('백업 정보:');
|
||||
print(' - 생성 시간: ${backup['timestamp']}');
|
||||
print(' - 버전: ${backup['version']}');
|
||||
print(' - 데이터 수: ${(backup['data'] as List).length}개');
|
||||
|
||||
// 롤백 확인
|
||||
print('\n정말로 롤백하시겠습니까? (y/n)');
|
||||
final confirm = stdin.readLineSync();
|
||||
if (confirm?.toLowerCase() != 'y') {
|
||||
print('롤백 취소됨');
|
||||
return;
|
||||
}
|
||||
|
||||
// 롤백 실행
|
||||
print('\n롤백 실행 중...');
|
||||
final success = await LicenseToMaintenanceMigration.rollback(backup);
|
||||
|
||||
if (success) {
|
||||
print('✅ 롤백 완료!');
|
||||
|
||||
// Maintenance 데이터 삭제
|
||||
print('Maintenance 데이터 정리 중...');
|
||||
await _deleteMaintenanceData();
|
||||
|
||||
// License 데이터 복원
|
||||
print('License 데이터 복원 중...');
|
||||
await _restoreLicenseData(backup['data'] as List);
|
||||
|
||||
print('\n롤백이 성공적으로 완료되었습니다.');
|
||||
} else {
|
||||
throw Exception('롤백 실패');
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
print('\n❌ 롤백 실패!');
|
||||
print('오류: $e');
|
||||
print('\n수동 복구가 필요할 수 있습니다.');
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/// API 인증
|
||||
Future<void> _authenticate() async {
|
||||
try {
|
||||
final response = await _dio.post('/auth/login', data: {
|
||||
'email': 'admin@example.com',
|
||||
'password': 'password123',
|
||||
});
|
||||
|
||||
_authToken = response.data['token'];
|
||||
_dio.options.headers['Authorization'] = 'Bearer $_authToken';
|
||||
} catch (e) {
|
||||
throw Exception('인증 실패: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// License 데이터 가져오기
|
||||
Future<List<Map<String, dynamic>>> _fetchLicenseData() async {
|
||||
try {
|
||||
// 실제 환경에서는 API 호출
|
||||
// 여기서는 더미 데이터 반환 (실제 구현 시 수정 필요)
|
||||
return [
|
||||
{
|
||||
'id': 1,
|
||||
'equipment_id': 1,
|
||||
'license_type': 'O',
|
||||
'period_months': 12,
|
||||
'cost': 1000000,
|
||||
'vendor_name': '삼성전자서비스',
|
||||
'vendor_contact': '1588-3366',
|
||||
'start_date': '2024-01-01T00:00:00Z',
|
||||
'expiry_date': '2024-12-31T23:59:59Z',
|
||||
'created_at': '2024-01-01T00:00:00Z',
|
||||
},
|
||||
// 추가 데이터...
|
||||
];
|
||||
} catch (e) {
|
||||
throw Exception('License 데이터 로딩 실패: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Equipment 데이터 가져오기
|
||||
Future<List<Map<String, dynamic>>> _fetchEquipmentData() async {
|
||||
try {
|
||||
final response = await _dio.get('/equipments');
|
||||
return (response.data['data'] as List)
|
||||
.map((e) => e as Map<String, dynamic>)
|
||||
.toList();
|
||||
} catch (e) {
|
||||
throw Exception('Equipment 데이터 로딩 실패: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Equipment History 데이터 가져오기
|
||||
Future<List<Map<String, dynamic>>> _fetchEquipmentHistoryData() async {
|
||||
try {
|
||||
final response = await _dio.get('/equipment_history');
|
||||
return (response.data['data'] as List)
|
||||
.map((e) => e as Map<String, dynamic>)
|
||||
.toList();
|
||||
} catch (e) {
|
||||
// Equipment History가 아직 구현되지 않았을 수 있음
|
||||
print(' ⚠️ Equipment History API 미구현, 빈 데이터 사용');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// 백업 저장
|
||||
Future<void> _saveBackup(Map<String, dynamic> backup) async {
|
||||
final file = File(backupPath);
|
||||
await file.writeAsString(jsonEncode(backup));
|
||||
}
|
||||
|
||||
/// Maintenance 데이터 저장
|
||||
Future<void> _saveMaintenanceData(List<Map<String, dynamic>> data) async {
|
||||
for (final maintenance in data) {
|
||||
try {
|
||||
await _dio.post('/maintenances', data: maintenance);
|
||||
} catch (e) {
|
||||
print(' ⚠️ Maintenance #${maintenance['id']} 저장 실패: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Maintenance 데이터 삭제
|
||||
Future<void> _deleteMaintenanceData() async {
|
||||
try {
|
||||
// 모든 Maintenance 데이터 삭제
|
||||
await _dio.delete('/maintenances/all');
|
||||
} catch (e) {
|
||||
print(' ⚠️ Maintenance 데이터 삭제 실패: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// License 데이터 복원
|
||||
Future<void> _restoreLicenseData(List<dynamic> data) async {
|
||||
for (final license in data) {
|
||||
try {
|
||||
await _dio.post('/licenses', data: license);
|
||||
} catch (e) {
|
||||
print(' ⚠️ License #${license['id']} 복원 실패: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 샘플 데이터 출력 (DRY RUN용)
|
||||
void _printSampleData(List<Map<String, dynamic>> data) {
|
||||
print('\n 샘플 변환 데이터 (처음 3개):');
|
||||
for (var i = 0; i < (data.length > 3 ? 3 : data.length); i++) {
|
||||
final item = data[i];
|
||||
print(' ${i + 1}. Maintenance #${item['id']}');
|
||||
print(' - Equipment History ID: ${item['equipment_history_id']}');
|
||||
print(' - Type: ${item['maintenance_type']}');
|
||||
print(' - Period: ${item['period_months']} months');
|
||||
print(' - Status: ${item['status']}');
|
||||
print(' - Next Date: ${item['next_date']}');
|
||||
}
|
||||
}
|
||||
|
||||
/// 검증 보고서 출력
|
||||
void _printValidationReport(ValidationReport report) {
|
||||
print('\n 검증 결과:');
|
||||
print(' - 전체 검증: ${report.isValid ? "✅ 통과" : "❌ 실패"}');
|
||||
print(' - 데이터 무결성: ${report.dataIntegrity ? "✅" : "❌"}');
|
||||
print(' - FK 관계: ${report.foreignKeyIntegrity ? "✅" : "❌"}');
|
||||
print(' - 비즈니스 규칙: ${report.businessRulesValid ? "✅" : "❌"}');
|
||||
|
||||
if (report.warnings.isNotEmpty) {
|
||||
print('\n 경고:');
|
||||
for (final warning in report.warnings) {
|
||||
print(' ⚠️ $warning');
|
||||
}
|
||||
}
|
||||
|
||||
if (report.errors.isNotEmpty) {
|
||||
print('\n 오류:');
|
||||
for (final error in report.errors) {
|
||||
print(' ❌ $error');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 메인 실행 함수
|
||||
Future<void> main(List<String> args) async {
|
||||
final executor = MigrationExecutor();
|
||||
|
||||
if (args.contains('--rollback')) {
|
||||
await executor.rollback();
|
||||
} else {
|
||||
final isDryRun = args.contains('--dry-run');
|
||||
await executor.execute(isDryRun: isDryRun);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user