0.1.105 — four user-reported bug fixes

Four small, orthogonal fixes from a user-bug report. Each lands as a separate change inside this round; nothing here is destructive or schema-changing.

1. Casdoor probe log surfaces the probed URL

Symptom (user-reported):

00:10:42 Warning Editor.Auth/casdoor.config.probe:
  Casdoor SSO surface unavailable:
  Editor.Auth/casdoor.config.probe — API route not found.

The bare "API route not found" string didn't tell the operator which backend host was missing the route. Same string appeared whether the SPA was hitting prod, a stale Render deploy, or localhost with the wrong port — useless for triage.

Fix in editor_app/lib/core/initial_data.dart, portal_app/lib/core/initial_data.dart, and planner_app/lib/core/initial_data.dart: the getCasdoorConfig catch block now resolves _httpClient?.baseUrl ?? '<unresolved>' and appends (probed <full URL>) to the warning. The new line shape:

Casdoor SSO surface unavailable:
  Editor.Auth/casdoor.config.probe —
  API route not found
  (probed https://notechondria.trance-0.com/api/v1/auth/casdoor/config/).

So the operator can immediately tell which deploy is stale.

2. "Local drafts only" filter no longer fetches public notes for anonymous users

Symptom: signed-out users picking "Local drafts only" from the all-notes scope dropdown still saw public notes underneath.

Root cause in editor_app/lib/core/note_loading.dart:

// Anonymous users always see public notes (scope=all).
final effectiveScope =
    isAuthenticated ? (scope ?? _learnerSearchScope) : 'all';

This silently rewrote 'local''all' for anonymous users, then listNotes happily returned public-feed rows. Fixed: anonymous users now respect 'local' (clears _learnerNotes + skips the backend call) and fall back to 'all' only for the other three scopes (personal / private / public — none of which apply signed-out anyway):

final pickedScope = scope ?? _learnerSearchScope;
final effectiveScope = isAuthenticated
    ? pickedScope
    : (pickedScope == 'local' ? 'local' : 'all');

The widget side (learner.dart) already routed effectiveScope == 'local' to showCloudNotes = false, so once the loader respects the choice, the page updates immediately and the public-notes block disappears even when local drafts are empty.

3. Default Inbox pinning + sidebar diagnostic breadcrumb

Symptom (user-reported): "Default index folder on side bar is still not rendered on web interface."

Root cause: the sidebar's pinned filter in editor_app/lib/core/build_helpers.dart only matched courses with is_default == true. Older builds and some sync paths (manual _createCategory while offline, archive restore, an older seeder version that wrote is_default: false, a backend payload that dropped the flag during a renamed-but-still-Inbox column rewrite) could leave a row titled "Inbox" with the flag off. The pinned filter came up empty → category vanished from the top of the sidebar → user saw an unpinned, draggable Inbox or no Inbox at all until tapping "Restore default Inbox" in Settings.

Fix:

  • New isCategoryPinned(Map<String, dynamic> course) helper on _AppShellBuildHelpersX. Pins when is_default == true OR when the title casefolds to "inbox". Both compact + wide layouts in build_helpers.dart route through it.
  • New emitSidebarPinDiagnostics({required total, required pinned}) helper on the same extension. Emits a debug-log line per sidebar rebuild with total=... and pinned=... counters. Goes to warning when pinned == 0 && total > 0 — that case is the symptom, recorded the moment it happens.
  • Filter the Debug Log card by source Editor.UI/sidebar.pin_diagnostics to see the breadcrumbs in flight.

How to debug from here: open the editor → Settings → Debug log → filter by sidebar.pin_diagnostics. Healthy state shows total=N pinned=1 at debug level. If you see pinned=0 warnings with total>0, the seed flag got stripped somewhere — tap "Restore default Inbox" in Settings to reseed; if that doesn't help, the cloud Course row's is_default is wrong on the backend and needs a fix on the server side (run a one-shot Course.objects .filter(creator_id=..., title__iexact='inbox').update(is_default=True)).

4. Portal Settings: Debug log card rendered inline

Symptom (user-reported): "On portal app settings page, the debug is not listed as independent widget as the editor settings does."

Editor's settings page rendered DebugLogCard inline as a card on the main scroll (level filter + terminal + copy + ping). Portal's hid it behind a "Debug" ListTile that pushed _DebugPage — fine for focused work but bad for at-a-glance ops.

Fix in portal_app/lib/modules/settings.dart:

  • New _buildInlineDebugCard(BuildContext) method matching the editor's _buildDebugSection shape exactly: when widget.debugLogController != null, render the shared DebugLogCard; otherwise fall back to a minimal "uiLogs" card.
  • Mounted on the main settings scroll between _buildSettingsMenu and _buildLogoutCard.
  • The existing "Debug" ListTile_DebugPage push is kept so the focused subpage still works.

Verification

  • flutter analyze clean across editor_app, portal_app, planner_app. No new errors / warnings from the four fixes.
  • The Casdoor-probe URL change is a pure log-shape upgrade, so no test surface needed.
  • The all-notes filter fix is an inverted condition; the existing rendering branches in learner.dart already cover the effectiveScope == 'local' path with the empty-state Card.
  • The Inbox pin fix is purely additive — the is_default == true check still works; we just OR in the title fallback. Existing flow unchanged for healthy data.
  • The portal debug card mirrors the editor's already-tested code path; no new logic.