Address PR re-review findings:
- Only a 401 on the replay falls through to logout; other DioExceptions
(timeout, connection drop, 5xx) now propagate so a flaky network can't
wipe a valid session and callers see the real error.
- Skip the refresh when the failed request's bearer no longer matches the
stored one (a concurrent refresh already rotated it) and replay directly.
- Guard _logout() with a _loggingOut flag so the auth-failed callback fires
once per burst rather than once per concurrent caller.
Add unit tests (fake Dio adapter + mocked prefs) covering the retry guard,
single-flight refresh, and non-401 replay propagation paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses PR review on the auth interceptor:
- Guard against unbounded retry recursion: tag the replayed request with
extra['auth_retried'] and skip the refresh/replay path on a second 401 so
it can't recurse refresh -> replay indefinitely. Drop the redundant manual
Authorization header on the replay (onRequest re-injects it).
- Fix the concurrent-refresh race: coalesce concurrent 401s onto a single
in-flight refresh future so the rotating refresh token is only consumed
once, instead of later refreshes posting an already-consumed token and
spuriously logging out. (Chose the shared-future approach over
QueuedInterceptor, which deadlocks with the replay-via-same-Dio pattern.)
- Centralise the 'bearer' / 'refresh_token' / 'customer_data' pref keys in
a PrefKeys constants class used by the interceptor, network manager, auth
service and router so they can't silently diverge.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Introduced new board-related assets in AssetsManager.
- Updated NetworkManager to increase connection and receive timeouts to 20 seconds.
- Added BoardRouteData for navigation to the BoardScreen.
- Updated app routes to include the new board route.
- Modified DesktopNavigationWidget to include a navigation item for the board.
- Added a new string constant for the board label in TendersStrings.