Files
minhthu/lib/features/auth/INTEGRATION_GUIDE.md
2025-10-28 00:09:46 +07:00

385 lines
9.5 KiB
Markdown

# Authentication Feature Integration Guide
Quick guide to integrate the authentication feature into the warehouse management app.
## Prerequisites
Ensure these dependencies are in `pubspec.yaml`:
```yaml
dependencies:
flutter_riverpod: ^2.4.9
dartz: ^0.10.1
flutter_secure_storage: ^9.0.0
dio: ^5.3.2
equatable: ^2.0.5
go_router: ^12.1.3
```
## Step 1: Update Main App
### Update `lib/main.dart`
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'core/routing/app_router.dart';
import 'core/theme/app_theme.dart';
void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Warehouse Manager',
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
routerConfig: appRouter,
debugShowCheckedModeBanner: false,
);
}
}
```
## Step 2: Update Router Configuration
### Update `lib/core/routing/app_router.dart`
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../features/auth/auth.dart';
import '../../features/auth/di/auth_dependency_injection.dart';
// Create a global key for navigator
final navigatorKey = GlobalKey<NavigatorState>();
// Router provider
final appRouterProvider = Provider<GoRouter>((ref) {
return GoRouter(
navigatorKey: navigatorKey,
initialLocation: '/login',
routes: [
// Login route
GoRoute(
path: '/login',
name: 'login',
builder: (context, state) => const LoginPage(),
),
// Warehouses route (protected)
GoRoute(
path: '/warehouses',
name: 'warehouses',
builder: (context, state) => const WarehouseSelectionPage(), // TODO: Create this
),
// Add more routes as needed...
],
// Redirect logic for authentication
redirect: (context, state) {
// Get auth state from provider container
final container = ProviderScope.containerOf(context);
final authState = container.read(authProvider);
final isAuthenticated = authState.isAuthenticated;
final isLoggingIn = state.matchedLocation == '/login';
// If not authenticated and not on login page, redirect to login
if (!isAuthenticated && !isLoggingIn) {
return '/login';
}
// If authenticated and on login page, redirect to warehouses
if (isAuthenticated && isLoggingIn) {
return '/warehouses';
}
// No redirect needed
return null;
},
);
});
// Export the router instance
final appRouter = GoRouter(
navigatorKey: navigatorKey,
initialLocation: '/login',
routes: [
GoRoute(
path: '/login',
name: 'login',
builder: (context, state) => const LoginPage(),
),
GoRoute(
path: '/warehouses',
name: 'warehouses',
builder: (context, state) => const Scaffold(
body: Center(child: Text('Warehouses Page - TODO')),
),
),
],
);
```
## Step 3: Configure API Base URL
### Update `lib/core/constants/app_constants.dart`
```dart
class AppConstants {
// API Configuration
static const String apiBaseUrl = 'https://your-api-url.com';
static const int connectionTimeout = 30000;
static const int receiveTimeout = 30000;
static const int sendTimeout = 30000;
// Other constants...
}
```
## Step 4: Create Protected Route Wrapper (Optional)
### Create `lib/core/widgets/protected_route.dart`
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../features/auth/di/auth_dependency_injection.dart';
class ProtectedRoute extends ConsumerWidget {
final Widget child;
const ProtectedRoute({
super.key,
required this.child,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final authState = ref.watch(authProvider);
// Show loading while checking auth
if (authState.isLoading) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}
// Redirect to login if not authenticated
if (!authState.isAuthenticated) {
WidgetsBinding.instance.addPostFrameCallback((_) {
context.go('/login');
});
return const SizedBox.shrink();
}
// Show protected content
return child;
}
}
```
## Step 5: Add Logout Button (Optional)
### Example usage in any page:
```dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:minhthu/features/auth/di/auth_dependency_injection.dart';
class SettingsPage extends ConsumerWidget {
const SettingsPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
appBar: AppBar(
title: const Text('Settings'),
actions: [
IconButton(
icon: const Icon(Icons.logout),
onPressed: () {
// Show confirmation dialog
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Logout'),
content: const Text('Are you sure you want to logout?'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
ref.read(authProvider.notifier).logout();
},
child: const Text('Logout'),
),
],
),
);
},
),
],
),
body: const Center(
child: Text('Settings'),
),
);
}
}
```
## Step 6: Handle API Client Setup
### Update `lib/core/di/core_providers.dart` (create if needed)
```dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../network/api_client.dart';
import '../storage/secure_storage.dart';
/// Provider for SecureStorage singleton
final secureStorageProvider = Provider<SecureStorage>((ref) {
return SecureStorage();
});
/// Provider for ApiClient
final apiClientProvider = Provider<ApiClient>((ref) {
final secureStorage = ref.watch(secureStorageProvider);
final apiClient = ApiClient(secureStorage);
// Set up unauthorized callback to handle 401 errors
apiClient.onUnauthorized = () {
// Navigate to login when unauthorized
// This can be enhanced with proper navigation context
};
return apiClient;
});
```
## Step 7: Test the Integration
### Manual Testing Checklist
1. **Login Flow**
- [ ] App starts on login page
- [ ] Form validation works
- [ ] Login with valid credentials succeeds
- [ ] Navigate to warehouses page after login
- [ ] Tokens saved in secure storage
2. **Error Handling**
- [ ] Invalid credentials show error message
- [ ] Network errors display properly
- [ ] Error messages are user-friendly
3. **Persistence**
- [ ] Close and reopen app stays logged in
- [ ] Tokens persisted in secure storage
- [ ] Auto-redirect to warehouses if authenticated
4. **Logout**
- [ ] Logout clears tokens
- [ ] Redirect to login page after logout
- [ ] Cannot access protected routes after logout
5. **Loading States**
- [ ] Loading indicator shows during login
- [ ] Form disabled during loading
- [ ] No double submissions
## Step 8: Environment Configuration (Optional)
### Create `lib/core/config/environment.dart`
```dart
enum Environment {
development,
staging,
production,
}
class EnvironmentConfig {
static Environment current = Environment.development;
static String get apiBaseUrl {
switch (current) {
case Environment.development:
return 'https://dev-api.example.com';
case Environment.staging:
return 'https://staging-api.example.com';
case Environment.production:
return 'https://api.example.com';
}
}
}
```
## Troubleshooting
### Issue: "Provider not found"
**Solution**: Ensure `ProviderScope` wraps your app in `main.dart`
### Issue: "Navigation doesn't work"
**Solution**: Verify router configuration and route names match
### Issue: "Secure storage error"
**Solution**:
- Add platform-specific configurations
- Check app permissions
- Clear app data and reinstall
### Issue: "API calls fail"
**Solution**:
- Verify API base URL in `app_constants.dart`
- Check network connectivity
- Verify API endpoint paths in `api_endpoints.dart`
## Next Steps
1. **Create Warehouse Feature** - Follow similar pattern
2. **Add Token Refresh** - Implement auto token refresh
3. **Add Remember Me** - Optional persistent login
4. **Add Biometric Auth** - Face ID / Touch ID
5. **Add Unit Tests** - Test use cases and repositories
6. **Add Widget Tests** - Test UI components
## Additional Resources
- [Riverpod Documentation](https://riverpod.dev/)
- [Go Router Documentation](https://pub.dev/packages/go_router)
- [Clean Architecture Guide](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
- [Flutter Secure Storage](https://pub.dev/packages/flutter_secure_storage)
## Support
For issues or questions:
1. Check the main README in `lib/features/auth/README.md`
2. Review the CLAUDE.md for project guidelines
3. Check existing code examples in the codebase