# Superport API Migration Guide > **최종 업데이트**: 2025-08-13 > **분석 대상**: `/Users/maximilian.j.sul/Documents/flutter/superport_api/` > **프론트엔드 영향**: Flutter Clean Architecture 기반 ## 📋 목차 - [주요 변경사항 요약](#주요-변경사항-요약) - [Breaking Changes](#breaking-changes) - [신규 기능](#신규-기능) - [프론트엔드 마이그레이션](#프론트엔드-마이그레이션) - [API 엔드포인트 변경사항](#api-엔드포인트-변경사항) - [데이터베이스 스키마 변경](#데이터베이스-스키마-변경) - [실행 계획](#실행-계획) --- ## 🚨 주요 변경사항 요약 ### ✅ 완료된 주요 기능 1. **소프트 딜리트 시스템 전면 구현** 2. **권한 기반 접근 제어 강화** 3. **API 엔드포인트 표준화** 4. **페이지네이션 최적화** 5. **에러 처리 개선** ### 🔄 변경 영향도 매트릭스 | 영역 | 변경 수준 | 영향도 | 대응 필요도 | |------|-----------|--------|-------------| | **Authentication** | 중간 | 🟡 Medium | 토큰 구조 업데이트 | | **Companies API** | 높음 | 🔴 High | DTO 모델 전면 수정 | | **Equipment API** | 높음 | 🔴 High | 상태 관리 로직 수정 | | **Users API** | 중간 | 🟡 Medium | 권한 처리 로직 수정 | | **Licenses API** | 낮음 | 🟢 Low | 소프트 딜리트 대응 | | **Overview API** | 신규 | 🔵 New | 새로운 통합 필요 | --- ## ⚠️ Breaking Changes ### 1. 소프트 딜리트 도입 **변경 내용**: 모든 주요 엔티티에서 물리 삭제 → 논리 삭제로 변경 **영향을 받는 API**: ``` DELETE /companies/{id} → is_active = false DELETE /equipment/{id} → is_active = false DELETE /licenses/{id} → is_active = false DELETE /warehouse-locations/{id} → is_active = false ``` **프론트엔드 수정 필요사항**: ```dart // Before (기존) class CompanyListRequest { final int? page; final int? perPage; } // After (수정 필요) class CompanyListRequest { final int? page; final int? perPage; final bool? isActive; // 추가 필요 } ``` ### 2. 응답 형식 표준화 **변경 내용**: 모든 API 응답이 표준 형식으로 통일 **Before**: ```json { "data": [...], "total": 100 } ``` **After**: ```json { "status": "success", "message": "Operation completed successfully", "data": [...], "meta": { "pagination": { "current_page": 1, "per_page": 20, "total": 100, "total_pages": 5 } } } ``` ### 3. 권한 시스템 변경 **변경 내용**: JWT 클레임 구조 및 권한 체크 로직 강화 **새로운 JWT 구조**: ```json { "sub": 1, // user_id "username": "admin", "role": "admin", // admin|manager|staff "exp": 1700000000, "iat": 1699999000 } ``` **권한별 접근 제한**: - `staff`: 조회 권한만, 삭제 권한 없음 - `manager`: 모든 권한, 단 사용자 관리 제외 - `admin`: 모든 권한 --- ## 🆕 신규 기능 ### 1. Overview API (대시보드용) **새로운 엔드포인트**: ``` GET /overview/stats # 대시보드 통계 GET /overview/recent-activities # 최근 활동 GET /overview/equipment-status # 장비 상태 분포 GET /overview/license-expiry # 라이선스 만료 요약 ``` **통합 예시**: ```dart // 새로 추가할 UseCase class GetDashboardStatsUseCase { Future> call(int? companyId) async { return await overviewRepository.getDashboardStats(companyId); } } ``` ### 2. Lookups API (마스터 데이터) **새로운 엔드포인트**: ``` GET /lookups # 전체 마스터 데이터 GET /lookups/type # 타입별 마스터 데이터 ``` **활용 방안**: - 드롭다운 옵션 동적 로딩 - 캐싱을 통한 성능 최적화 ### 3. Health Check API **새로운 엔드포인트**: ``` GET /health # 서버 상태 체크 ``` **프론트엔드 활용**: - 앱 시작 시 서버 연결 상태 확인 - 주기적 헬스체크 구현 --- ## 🎯 프론트엔드 마이그레이션 ### Phase 1: DTO 모델 업데이트 #### 1.1 Company DTO 수정 ```dart // 기존 CreateCompanyRequest에 추가 @JsonSerializable() class CreateCompanyRequest { // 기존 필드들... final List? companyTypes; // 추가 final bool? isPartner; // 추가 final bool? isCustomer; // 추가 } // 새로운 필터링 옵션 @JsonSerializable() class CompanyListRequest { final int? page; final int? perPage; final bool? isActive; // 추가 (소프트 딜리트) } ``` #### 1.2 Equipment DTO 수정 ```dart // Equipment 상태 Enum 확장 enum EquipmentStatus { @JsonValue('available') available, @JsonValue('inuse') inuse, @JsonValue('maintenance') maintenance, @JsonValue('disposed') disposed, // 새로 추가 } // 페이지네이션 쿼리 확장 @JsonSerializable() class EquipmentListRequest { final int? page; final int? perPage; final String? status; final int? companyId; final int? warehouseLocationId; final bool? isActive; // 추가 } ``` ### Phase 2: Repository 인터페이스 수정 #### 2.1 소프트 딜리트 지원 ```dart abstract class CompanyRepository { // 기존 메서드 시그니처 수정 Future>> getCompanies({ int? page, int? perPage, bool? isActive, // 추가 }); // 삭제 메서드 동작 변경 (소프트 딜리트) Future> deleteCompany(int id); // 복구 메서드 추가 Future> restoreCompany(int id); // 신규 } ``` #### 2.2 새로운 Repository 추가 ```dart // 새로 추가할 Repository abstract class OverviewRepository { Future> getDashboardStats(int? companyId); Future>> getRecentActivities({ int? page, int? perPage, String? entityType, int? companyId, }); Future> getEquipmentStatusDistribution(int? companyId); Future> getLicenseExpirySummary(int? companyId); } abstract class LookupRepository { Future>>> getAllLookups(); Future>> getLookupsByType(String type); } ``` ### Phase 3: API 클라이언트 수정 #### 3.1 Retrofit 인터페이스 업데이트 ```dart @RestApi() abstract class SuperportApiClient { // Overview API 추가 @GET('/overview/stats') Future> getDashboardStats( @Query('company_id') int? companyId, ); @GET('/overview/license-expiry') Future> getLicenseExpirySummary( @Query('company_id') int? companyId, ); // Lookups API 추가 @GET('/lookups') Future>>> getAllLookups(); // 기존 API 파라미터 추가 @GET('/companies') Future>> getCompanies( @Query('page') int? page, @Query('per_page') int? perPage, @Query('is_active') bool? isActive, // 추가 ); } ``` #### 3.2 응답 형식 변경 대응 ```dart // 기존 ApiResponse 클래스 수정 @JsonSerializable() class ApiResponse { final String status; // 추가 final String? message; // 추가 final T data; final ResponseMeta? meta; // 변경 (기존 meta와 구조 다름) } @JsonSerializable() class ResponseMeta { final PaginationMeta? pagination; // 중첩 구조로 변경 } ``` ### Phase 4: 상태 관리 업데이트 #### 4.1 Controller 수정 ```dart class CompanyController extends ChangeNotifier { // 소프트 딜리트 상태 관리 bool _showDeleted = false; bool get showDeleted => _showDeleted; void toggleShowDeleted() { _showDeleted = !_showDeleted; _loadCompanies(); // 목록 다시 로드 notifyListeners(); } // 복구 기능 추가 Future restoreCompany(int id) async { final result = await _restoreCompanyUseCase(id); result.fold( (failure) => _handleError(failure), (company) { _companies[id] = company; notifyListeners(); }, ); } } ``` #### 4.2 새로운 Controller 추가 ```dart class DashboardController extends ChangeNotifier { DashboardStats? _stats; List _recentActivities = []; bool _isLoading = false; // Getters... Future loadDashboardData() async { _isLoading = true; notifyListeners(); // 병렬로 데이터 로드 await Future.wait([ _loadStats(), _loadRecentActivities(), ]); _isLoading = false; notifyListeners(); } } ``` --- ## 📡 API 엔드포인트 변경사항 ### 새로 추가된 엔드포인트 | Method | Endpoint | 설명 | 우선순위 | |--------|----------|------|----------| | `GET` | `/overview/stats` | 대시보드 통계 | 🔴 높음 | | `GET` | `/overview/license-expiry` | 라이선스 만료 요약 | 🟡 중간 | | `GET` | `/overview/equipment-status` | 장비 상태 분포 | 🟡 중간 | | `GET` | `/overview/recent-activities` | 최근 활동 내역 | 🟢 낮음 | | `GET` | `/lookups` | 전체 마스터 데이터 | 🟡 중간 | | `GET` | `/lookups/type` | 타입별 마스터 데이터 | 🟢 낮음 | | `GET` | `/health` | 서버 상태 체크 | 🟢 낮음 | ### 기존 엔드포인트 변경사항 | Endpoint | 변경 내용 | 마이그레이션 필요도 | |----------|-----------|---------------------| | `GET /companies` | `is_active` 파라미터 추가 | 🔴 필수 | | `GET /equipment` | `is_active` 파라미터 추가 | 🔴 필수 | | `DELETE /companies/{id}` | 소프트 딜리트로 변경 | 🔴 필수 | | `DELETE /equipment/{id}` | 권한 체크 강화 | 🟡 권장 | | 모든 응답 | 표준 형식으로 통일 | 🔴 필수 | --- ## 🗄️ 데이터베이스 스키마 변경 ### 새로 추가된 컬럼 | 테이블 | 컬럼 | 타입 | 설명 | |--------|------|------|------| | `companies` | `is_active` | `BOOLEAN` | 소프트 딜리트 플래그 | | `companies` | `is_partner` | `BOOLEAN` | 파트너사 여부 | | `companies` | `is_customer` | `BOOLEAN` | 고객사 여부 | | `companies` | `company_types` | `TEXT[]` | 회사 유형 배열 | | `equipment` | `is_active` | `BOOLEAN` | 소프트 딜리트 플래그 | | `licenses` | `is_active` | `BOOLEAN` | 소프트 딜리트 플래그 | | `warehouse_locations` | `is_active` | `BOOLEAN` | 소프트 딜리트 플래그 | | `addresses` | `is_active` | `BOOLEAN` | 소프트 딜리트 플래그 | | `users` | `is_active` | `BOOLEAN` | 소프트 딜리트 플래그 | ### 새로 추가된 인덱스 ```sql -- 소프트 딜리트 최적화용 인덱스 CREATE INDEX idx_companies_is_active ON companies(is_active); CREATE INDEX idx_equipment_is_active ON equipment(is_active); CREATE INDEX idx_licenses_is_active ON licenses(is_active); -- 복합 인덱스 (성능 최적화) CREATE INDEX idx_equipment_company_id_is_active ON equipment(company_id, is_active); CREATE INDEX idx_licenses_company_id_is_active ON licenses(company_id, is_active); ``` --- ## 🛠️ 실행 계획 ### Phase 1: 백엔드 API 통합 (1주차) - [ ] Overview API 통합 (`/overview/license-expiry` 우선) - [ ] 소프트 딜리트 대응 (필터링 로직) - [ ] 응답 형식 변경 대응 ### Phase 2: 프론트엔드 모델 업데이트 (2주차) - [ ] DTO 클래스 수정 (Freezed 재생성) - [ ] Repository 인터페이스 확장 - [ ] API 클라이언트 업데이트 ### Phase 3: UI/UX 개선 (3주차) - [ ] 소프트 딜리트 UI 구현 (복구 버튼, 필터링) - [ ] 대시보드 통계 위젯 구현 - [ ] 권한별 UI 제어 강화 ### Phase 4: 성능 최적화 (4주차) - [ ] Lookups API 캐싱 구현 - [ ] 페이지네이션 최적화 - [ ] 에러 처리 개선 ### Phase 5: 테스트 및 배포 (5주차) - [ ] 단위 테스트 업데이트 - [ ] 통합 테스트 실행 - [ ] 프로덕션 배포 --- ## 🧪 테스트 업데이트 가이드 ### 1. 단위 테스트 수정 ```dart // Repository 테스트 수정 예시 group('CompanyRepository', () { test('should return active companies when isActive is true', () async { // Given when(mockApiClient.getCompanies( page: 1, perPage: 20, isActive: true, // 추가된 파라미터 테스트 )).thenAnswer((_) async => mockActiveCompaniesResponse); // When final result = await repository.getCompanies( page: 1, perPage: 20, isActive: true, ); // Then expect(result.isRight(), true); }); }); ``` ### 2. Widget 테스트 수정 ```dart testWidgets('should show restore button for deleted companies', (tester) async { // Given final deletedCompany = Company(id: 1, name: 'Test', isActive: false); // When await tester.pumpWidget(CompanyListItem(company: deletedCompany)); // Then expect(find.text('복구'), findsOneWidget); expect(find.byIcon(Icons.restore), findsOneWidget); }); ``` ### 3. 통합 테스트 수정 ```dart group('Company CRUD Integration', () { test('soft delete should set is_active to false', () async { // Create company final company = await createTestCompany(); // Delete (soft delete) await apiClient.deleteCompany(company.id); // Verify soft delete final companies = await apiClient.getCompanies(isActive: false); expect(companies.data.any((c) => c.id == company.id), true); }); }); ``` --- ## 🚨 주의사항 ### 1. 데이터 마이그레이션 - 기존 삭제된 데이터는 복구 불가능 - 소프트 딜리트 전환 후에만 복구 가능 ### 2. 성능 영향 - `is_active` 필터링으로 인한 쿼리 복잡도 증가 - 인덱스 활용으로 성능 최적화 필요 ### 3. 권한 관리 - 새로운 권한 체크 로직 확인 필요 - Staff 권한 사용자의 기능 제한 확인 ### 4. 캐싱 전략 - Lookups API 응답 캐싱 구현 권장 - 대시보드 통계 캐싱으로 성능 개선 --- ## 📞 지원 및 문의 ### 개발팀 연락처 - **백엔드 API**: `superport_api` 레포지토리 이슈 생성 - **프론트엔드**: 현재 레포지토리 이슈 생성 - **데이터베이스**: DBA 팀 문의 ### 유용한 리소스 - [API_SCHEMA.md](./API_SCHEMA.md) - 완전한 API 명세서 - [ENTITY_MAPPING.md](./ENTITY_MAPPING.md) - 데이터베이스 구조 - 백엔드 소스: `/Users/maximilian.j.sul/Documents/flutter/superport_api/` --- **마이그레이션 가이드 버전**: 1.0 **최종 검토**: 2025-08-13 **담당자**: Full-Stack Development Team