10 - Debugging Guide
Tools, techniques, and checklists for diagnosing issues in the Flutter frontend.
Flutter DevTools
DevTools is Flutter's built-in debugger / profiler / inspector. It launches automatically when you run flutter run.
BashLaunch DevTools
# Start the app
C:\flutter\bin\flutter run -d chrome --web-port 8080
# Look for this line in the console:
# A Dart VM Service ... is available at: http://127.0.0.1:xxxxx
# Flutter DevTools debugger and profiler is available at: http://127.0.0.1:9100
# Open the DevTools URL in your browser
What you get in DevTools
- Flutter Inspector: widget tree inspector. Click any widget to highlight it on screen.
- Performance: frame timeline, raster time, skipped frames. Useful for jank diagnosis.
- Memory: heap snapshot, allocation tracking.
- Network: HTTP request log with headers, body, response, timing.
- Logging: all
debugPrintoutput with filterable log levels.
Breakpoints in VS Code
VS Code with the Flutter extension is the recommended IDE.
- Open the Flutter app folder in VS Code
- Click the left gutter next to a line number to set a breakpoint (red dot appears)
- Press F5 to start debugging (or click "Run and Debug")
- Select a device (Chrome, Android emulator, etc.)
- When the breakpoint is hit, use F10 (step over), F11 (step into), F5 (continue)
Set breakpoints in ApiService._post and ApiService._get to inspect every network call in one place. Set one in Stage0ArrivalScreen._initJourney to trace session startup.
debugPrint and print
Use debugPrint instead of print in Flutter code - it's rate-limited and works better on web.
DartLogging patterns
import 'package:flutter/foundation.dart';
debugPrint('Registration: mobile=$mobile, name=$name');
debugPrint('API response: success=${result.success}, data=${result.data}');
// For large objects, use debugPrint with JSON encoding
debugPrint('Full response: ${jsonEncode(result.data)}');
All debug logs show up in your terminal (flutter run) or VS Code Debug Console.
Network Inspection
Web (Chrome)
- Press F12 to open Chrome DevTools
- Go to the Network tab
- Filter by "XHR" or "Fetch" to see just API calls
- Click any request to inspect headers, payload, response, timing
If you see a CORS error in the Network tab, check backend/src/MO.Ekyc.Api/appsettings.json → Cors.AllowedOrigins. It must include your Flutter web origin (e.g., http://localhost:8080).
Android / iOS
Use Charles Proxy or Proxyman with a self-signed CA installed on the device/emulator. Flutter DevTools Network tab also shows HTTP traffic for mobile.
Inspecting Storage (SharedPreferences)
The StorageService wraps SharedPreferences. To see what's stored:
DartDump storage contents
final storage = await StorageService.getInstance();
debugPrint('leadId: ${storage.leadId}');
debugPrint('sessionId: ${storage.sessionId}');
debugPrint('token: ${storage.token}');
debugPrint('currentStage: ${storage.currentStage}');
debugPrint('lastActivity: ${storage.lastActivity}');
To clear storage and start fresh (useful when testing resume logic):
DartClear all storage
await (await StorageService.getInstance()).clearAll();
// Now restart the app - it will go through Stage 0 fresh
Web - Application tab
In Chrome DevTools, go to Application → Storage → Local Storage. SharedPreferences on web maps to localStorage. You can see and delete keys directly.
Common Issues Checklists
"White screen on startup"
- Check the browser/terminal console for Dart errors
- Run
flutter clean && flutter pub getand retry - Check if
main.dartthrows beforerunApp(e.g., StorageService init fails) - Make sure
assets/images/is registered inpubspec.yaml- missing assets can crash startup
"Stuck at Stage 0 loading spinner"
- Open browser Network tab - is
GET /api/v1/journey/initreturning 200? - Is the backend running? Test:
curl http://localhost:5000/api/v1/journey/init - Is
ApiConfig.baseUrlpointing to the correct backend for your env? - CORS error? Add your origin to
backend/appsettings.jsonCors.AllowedOrigins - Is PostgreSQL running? The backend fails on startup if DB is unreachable
"API always returns 401"
- Check
StorageService.tokenis set (see storage dump above) - Check the token isn't expired (default TTL is 15 min per
appsettings.jsonJwt.TokenExpiryMinutes) - Run a fresh journey - clearAll + restart. If it works, your saved token was stale.
- On the backend, check Serilog output for "JWT validation failed" messages
"OTP 1234 is rejected"
- Check
backend/src/MO.Ekyc.Api/appsettings.Development.json:Sms.Modemust be"FIXED_OTP" - Restart the backend after changing appsettings
- Make sure you are running with the Development profile:
dotnet run(notdotnet run --environment Production) - See 02 - Mock Mode
"Lottie animation doesn't play"
- Verify the asset path: should be
assets/images/ic_loader.jsonetc. - Check it's registered in
pubspec.yamlunderflutter.assets - Run
flutter pub getafter adding any asset - Web browser cache can serve old assets - hard refresh with Ctrl+Shift+R
"Navigation back button takes me out of the app"
- Make sure
BackButtonHandlerwraps the Scaffold (see 08 - Widgets) - On web, browser back is different from Android back - the
PopScopeintercept only applies to Flutter Navigator pops
"Mock URL opens real WebView in dev"
- Check
ApiConfig.isDevreturnstrue:debugPrint(ApiConfig.isDev) - Make sure you're not passing
--dart-define=ENV=prodaccidentally - Check the mock URL detection regex in the stage file matches what the backend is returning
"Session timed out immediately"
SessionTimerreadsStorageService.lastActivity- make sure API calls update it via_storage.updateActivity()- Verify the timeout values in
ApiConfig:sessionTimeout = 15 min,sessionWarningAt = 13 min
Backend-side debugging
When the backend is the problem, inspect it via Swagger and Hangfire.
| URL | Purpose |
|---|---|
http://localhost:5000/swagger | Interactive API explorer. Test endpoints without the Flutter app. |
http://localhost:5000/hangfire | Background job dashboard. See queued, running, completed, failed jobs (analytics events, downstream publishers). |
backend/src/MO.Ekyc.Api/appsettings.json- Serilog config- Console output when running
dotnet run - Backend debugging docs (pending) - placeholder