Files
minhthu/APP_COMPLETE_SETUP_GUIDE.md
2025-10-28 00:09:46 +07:00

527 lines
15 KiB
Markdown

# 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": <data>,
"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.