Notechondria
Version: 0.1.63 Build Date: 2026-04-23T00:00
What's Changed
Bug — fresh OAuth sign-in rejected with "Invalid token"
-
The log was showing "Session established" followed milliseconds
later by "Session rejected: Backend.Auth/GET /api/v1/front-page/ —
Invalid token." on the very next request. Root cause: the token
minted by
GoogleOAuthApiView/GitHubOAuthApiViewis validated by DRF'sTokenAuthentication, which raisesAuthenticationFailedon any unknown token — even againstpermissions.AllowAnyviews — so a token that was issued but never persisted (DB reset between OAuth mint and first use, migration rollback, LB split-brain, etc.) produces a 401 on every subsequent call instead of a clear error. -
Fix:
applyAuthPayloadinfrontend/editor_app/lib/app_shell.dartnow verifies the fresh token withwidget.client.checkSession(token)before persisting it or triggering_loadInitialData. If the backend rejects the token (401, invalid-token message), we clear_token/_profile/_settings, log a named error atEditor.Auth/applyAuthPayloadexplaining the backend-state mismatch, and show a user-visible SnackBar: "Fresh token rejected by backend. Please sign in again." Non-401 errors (network blip, 5xx) are logged at warning and we continue so_loadInitialDatacan surface them with more context. No more confusing "offline fallback" immediately after a successful OAuth callback.
UX — Cancel the login dialog mid-submit
-
Previously the Close button on
EmailPasswordDialogdisabled itself during_submitting, so a slow OAuth / cold-start backend would strand the user staring at a "Working..." spinner with no way out. The left button is now always enabled; it readsClosewhen idle andCancelwhen a submit is in flight. Popping the dialog makes the in-flightonSubmitFuture's result a no-op because_submitguards onmountedafter the await.
UX — API base URL field guidance
-
The shared
AppPreferencesCard(app_preferences_card.dart) now has informative defaulthintText/helperTextso the user is told what to type before they try:hintText:https://your-backend.example.com/api/v1helperText: "Include the/api/v1suffix. The app will auto-append it if missing, but pasting the full URL is safer."- Callers can still override via the existing
apiBaseHintText/apiBaseHelperTextprops.
Splash — uniform particle size
-
Background particles in the Krebs-cycle splash no longer vary
in size (previously
0.75 + rng.nextDouble() * 0.75, giving a 2× spread). Per request, all particles render at the same scale (1.0); visual variation comes entirely from the existing per-particle alpha pulse and the ring-proximity fade. Cycle-step byproduct formulas (CO₂, NADH, FADH₂, GTP) already render at a fixed scale and were not touched — they're in a different draw class from the roaming background particles.
Files Changed
VERSION— bumped 0.1.62 → 0.1.63.frontend/editor_app/lib/app_shell.dart—applyAuthPayloadpre-validates the fresh token viacheckSessionand bails with a clear error if the backend rejects it.frontend/notechondria_shared/lib/src/components/auth_dialogs.dart—EmailPasswordDialogleft action always enabled; label switchesClose↔Cancelbased on_submitting.frontend/notechondria_shared/lib/src/settings/app_preferences_card.dart— default API basehintText+helperTextadded.frontend/notechondria_shared/lib/src/components/splash_screen.dart—SplashParticle.sizefixed at1.0instead of a random0.75..1.5range.
Notes / follow-ups
- The OAuth
checkSessionpre-validation is editor_app only this round. Planner and portal follow the sameapplyAuthPayloadpattern but live in their ownapp_shell.dartcopies; tracked indocs/TODO.mdunder Bugs. - If the fresh-token-rejected flow keeps firing, the backend is
truly losing Token rows between mint and next use. Check the
Render / Northflank DB state and the Django
authtoken_tokentable. The frontend fix above surfaces the error clearly; it doesn't paper over a genuine backend problem. - "Cancel" during an in-flight login lets the backend finish the
request in background. True request cancellation would need the
httppackage'scancelablefork ordart:asyncfutures with an abort token. Low priority since the session result is discarded by themountedguard.