# Complete App Setup Guide - Warehouse Management App ## Overview This guide provides a complete overview of the rewritten warehouse management app following clean architecture principles as specified in CLAUDE.md. ## App Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ Presentation Layer │ │ (UI, Widgets, State Management with Riverpod) │ ├─────────────────────────────────────────────────────────┤ │ Domain Layer │ │ (Business Logic, Use Cases, Entities, Interfaces) │ ├─────────────────────────────────────────────────────────┤ │ Data Layer │ │ (API Client, Models, Data Sources, Repositories) │ ├─────────────────────────────────────────────────────────┤ │ Core Layer │ │ (Network, Storage, Theme, Constants, Utilities) │ └─────────────────────────────────────────────────────────┘ ``` ## Project Structure ``` lib/ ├── core/ # Core infrastructure │ ├── constants/ │ │ ├── api_endpoints.dart # API endpoint constants │ │ └── app_constants.dart # App-wide constants │ ├── di/ │ │ └── providers.dart # Riverpod dependency injection │ ├── errors/ │ │ ├── exceptions.dart # Exception classes │ │ └── failures.dart # Failure classes for Either │ ├── network/ │ │ ├── api_client.dart # Dio HTTP client with interceptors │ │ └── api_response.dart # Generic API response wrapper │ ├── router/ │ │ └── app_router.dart # GoRouter configuration │ ├── storage/ │ │ └── secure_storage.dart # Secure token storage │ ├── theme/ │ │ └── app_theme.dart # Material 3 theme │ └── widgets/ │ ├── custom_button.dart # Reusable button widgets │ └── loading_indicator.dart # Loading indicators │ ├── features/ # Feature-first organization │ ├── auth/ # Authentication feature │ │ ├── data/ │ │ │ ├── datasources/ │ │ │ │ └── auth_remote_datasource.dart │ │ │ ├── models/ │ │ │ │ ├── login_request_model.dart │ │ │ │ └── user_model.dart │ │ │ └── repositories/ │ │ │ └── auth_repository_impl.dart │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ │ └── user_entity.dart │ │ │ ├── repositories/ │ │ │ │ └── auth_repository.dart │ │ │ └── usecases/ │ │ │ └── login_usecase.dart │ │ └── presentation/ │ │ ├── pages/ │ │ │ └── login_page.dart │ │ ├── providers/ │ │ │ └── auth_provider.dart │ │ └── widgets/ │ │ └── login_form.dart │ │ │ ├── warehouse/ # Warehouse feature │ │ ├── data/ │ │ │ ├── datasources/ │ │ │ │ └── warehouse_remote_datasource.dart │ │ │ ├── models/ │ │ │ │ └── warehouse_model.dart │ │ │ └── repositories/ │ │ │ └── warehouse_repository_impl.dart │ │ ├── domain/ │ │ │ ├── entities/ │ │ │ │ └── warehouse_entity.dart │ │ │ ├── repositories/ │ │ │ │ └── warehouse_repository.dart │ │ │ └── usecases/ │ │ │ └── get_warehouses_usecase.dart │ │ └── presentation/ │ │ ├── pages/ │ │ │ └── warehouse_selection_page.dart │ │ ├── providers/ │ │ │ └── warehouse_provider.dart │ │ └── widgets/ │ │ └── warehouse_card.dart │ │ │ ├── operation/ # Operation selection feature │ │ └── presentation/ │ │ ├── pages/ │ │ │ └── operation_selection_page.dart │ │ └── widgets/ │ │ └── operation_card.dart │ │ │ └── products/ # Products feature │ ├── data/ │ │ ├── datasources/ │ │ │ └── products_remote_datasource.dart │ │ ├── models/ │ │ │ └── product_model.dart │ │ └── repositories/ │ │ └── products_repository_impl.dart │ ├── domain/ │ │ ├── entities/ │ │ │ └── product_entity.dart │ │ ├── repositories/ │ │ │ └── products_repository.dart │ │ └── usecases/ │ │ └── get_products_usecase.dart │ └── presentation/ │ ├── pages/ │ │ └── products_page.dart │ ├── providers/ │ │ └── products_provider.dart │ └── widgets/ │ └── product_list_item.dart │ └── main.dart # App entry point ``` ## App Flow ``` 1. App Start ↓ 2. Check Authentication (via SecureStorage) ↓ ├── Not Authenticated → Login Screen │ ↓ │ Enter credentials │ ↓ │ API: POST /auth/login │ ↓ │ Store access token │ ↓ └── Authenticated → Warehouse Selection Screen ↓ API: GET /warehouses ↓ Select warehouse ↓ Operation Selection Screen ↓ Choose Import or Export ↓ Products List Screen ↓ API: GET /products?warehouseId={id}&type={type} ↓ Display products ``` ## Key Technologies - **Flutter SDK**: >=3.0.0 <4.0.0 - **State Management**: Riverpod (flutter_riverpod ^2.4.9) - **Navigation**: GoRouter (go_router ^13.2.0) - **HTTP Client**: Dio (dio ^5.3.2) - **Secure Storage**: FlutterSecureStorage (flutter_secure_storage ^9.0.0) - **Functional Programming**: Dartz (dartz ^0.10.1) - **Value Equality**: Equatable (equatable ^2.0.5) ## Setup Instructions ### 1. Install Dependencies ```bash cd /Users/phuocnguyen/Projects/minhthu flutter pub get ``` ### 2. Configure API Base URL Edit `/Users/phuocnguyen/Projects/minhthu/lib/core/constants/app_constants.dart`: ```dart static const String apiBaseUrl = 'https://your-api-domain.com'; ``` ### 3. Configure API Endpoints (if needed) Edit `/Users/phuocnguyen/Projects/minhthu/lib/core/constants/api_endpoints.dart` to match your backend API paths. ### 4. Run the App ```bash flutter run ``` ## API Integration ### API Response Format All APIs follow this response format: ```json { "Value": , "IsSuccess": true, "IsFailure": false, "Errors": [], "ErrorCodes": [] } ``` ### Available APIs #### 1. Login ```bash POST /auth/login Content-Type: application/json { "username": "string", "password": "string" } Response: { "Value": { "userId": "string", "username": "string", "accessToken": "string", "refreshToken": "string" }, "IsSuccess": true, "IsFailure": false, "Errors": [], "ErrorCodes": [] } ``` #### 2. Get Warehouses ```bash GET /warehouses Authorization: Bearer {access_token} Response: { "Value": [ { "Id": 1, "Name": "Kho nguyên vật liệu", "Code": "001", "Description": null, "IsNGWareHouse": false, "TotalCount": 8 } ], "IsSuccess": true, "IsFailure": false, "Errors": [], "ErrorCodes": [] } ``` #### 3. Get Products ```bash GET /products?warehouseId={id}&type={import/export} Authorization: Bearer {access_token} Response: { "Value": [ { "Id": 11, "Name": "Thép 435", "Code": "SCM435", "FullName": "SCM435 | Thép 435", "Weight": 120.00, "Pieces": 1320, "ConversionRate": 11.00, ... (43 total fields) } ], "IsSuccess": true, "IsFailure": false, "Errors": [], "ErrorCodes": [] } ``` ## Usage Examples ### Using Auth Provider ```dart import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:minhthu/core/di/providers.dart'; class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // Watch auth state final isAuthenticated = ref.watch(isAuthenticatedProvider); final currentUser = ref.watch(currentUserProvider); final isLoading = ref.watch(authProvider.select((s) => s.isLoading)); // Login onLoginPressed() async { await ref.read(authProvider.notifier).login(username, password); } // Logout onLogoutPressed() async { await ref.read(authProvider.notifier).logout(); } return Container(); } } ``` ### Using Warehouse Provider ```dart class WarehousePage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // Watch warehouses final warehouses = ref.watch(warehousesListProvider); final selectedWarehouse = ref.watch(selectedWarehouseProvider); final isLoading = ref.watch(warehouseProvider.select((s) => s.isLoading)); // Load warehouses useEffect(() { Future.microtask(() => ref.read(warehouseProvider.notifier).loadWarehouses() ); return null; }, []); // Select warehouse onWarehouseTap(warehouse) { ref.read(warehouseProvider.notifier).selectWarehouse(warehouse); context.go('/operations', extra: warehouse); } return ListView.builder(...); } } ``` ### Using Products Provider ```dart class ProductsPage extends ConsumerWidget { final int warehouseId; final String warehouseName; final String operationType; @override Widget build(BuildContext context, WidgetRef ref) { // Watch products final products = ref.watch(productsListProvider); final isLoading = ref.watch(productsProvider.select((s) => s.isLoading)); // Load products useEffect(() { Future.microtask(() => ref.read(productsProvider.notifier) .loadProducts(warehouseId, warehouseName, operationType) ); return null; }, [warehouseId, operationType]); return ListView.builder(...); } } ``` ### Navigation ```dart // Navigate to login context.go('/login'); // Navigate to warehouses context.go('/warehouses'); // Navigate to operations context.go('/operations', extra: warehouseEntity); // Navigate to products context.go('/products', extra: { 'warehouse': warehouseEntity, 'warehouseName': 'Kho nguyên vật liệu', 'operationType': 'import', // or 'export' }); // Or use extension methods context.goToOperations(warehouse); context.goToProducts(warehouse: warehouse, operationType: 'import'); ``` ## Error Handling ### Using Either for Error Handling ```dart final result = await ref.read(authProvider.notifier).login(username, password); result.fold( (failure) { // Handle error print('Error: ${failure.message}'); }, (user) { // Handle success print('Logged in as: ${user.username}'); }, ); ``` ### Error Types - **ServerFailure**: API returned an error - **NetworkFailure**: Network connectivity issues - **AuthenticationFailure**: Authentication/authorization errors ## Testing ### Run Tests ```bash flutter test ``` ### Run Analysis ```bash flutter analyze ``` ### Test Coverage ```bash flutter test --coverage ``` ## Security Best Practices 1. **Token Storage**: Access tokens are stored securely using `flutter_secure_storage` with platform-specific encryption: - Android: EncryptedSharedPreferences - iOS: Keychain 2. **API Security**: - All authenticated requests include Bearer token - 401 errors automatically clear tokens and redirect to login - Sensitive data redacted in logs 3. **HTTPS**: All API calls should use HTTPS in production ## Performance Optimizations 1. **Riverpod**: Minimal rebuilds with fine-grained reactivity 2. **Lazy Loading**: Providers are created only when needed 3. **Caching**: SecureStorage caches auth tokens 4. **Error Boundaries**: Proper error handling prevents crashes ## Troubleshooting ### Issue: Login fails with 401 - Check API base URL in `app_constants.dart` - Verify credentials - Check network connectivity ### Issue: White screen after login - Check if router redirect logic is working - Verify `SecureStorage.isAuthenticated()` returns true - Check console for errors ### Issue: Products not loading - Verify warehouse is selected - Check API endpoint configuration - Verify access token is valid ### Issue: Build errors ```bash flutter clean flutter pub get flutter run ``` ## Documentation References - **Core Architecture**: `/lib/core/di/README.md` - **Auth Feature**: `/lib/features/auth/README.md` - **Warehouse Feature**: `/lib/features/warehouse/README.md` - **Products Feature**: Inline documentation in code - **API Client**: `/lib/core/network/README.md` - **Router**: `/lib/core/router/README.md` ## Next Steps 1. ✅ Core architecture set up 2. ✅ Auth feature implemented 3. ✅ Warehouse feature implemented 4. ✅ Operation selection implemented 5. ✅ Products feature implemented 6. ✅ Routing configured 7. ✅ Dependency injection set up 8. ⏳ Configure production API URL 9. ⏳ Test with real API 10. ⏳ Add additional features as needed ## Support For issues or questions: 1. Check inline documentation in code files 2. Review README files in each module 3. Check CLAUDE.md for specifications ## License This project follows the specifications in CLAUDE.md and is built with clean architecture principles.