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

15 KiB

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

cd /Users/phuocnguyen/Projects/minhthu
flutter pub get

2. Configure API Base URL

Edit /Users/phuocnguyen/Projects/minhthu/lib/core/constants/app_constants.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

flutter run

API Integration

API Response Format

All APIs follow this response format:

{
  "Value": <data>,
  "IsSuccess": true,
  "IsFailure": false,
  "Errors": [],
  "ErrorCodes": []
}

Available APIs

1. Login

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

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

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

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

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

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

// 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

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

flutter test

Run Analysis

flutter analyze

Test Coverage

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

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.