Portal app (frontend/portal_app/)

Orchestration shell: public front page + module-level access to all five Notechondria modules. One of three standalone Flutter apps that share the same backend.

Related: editor_app, planner_app, server/backend.md.

Role

  • Public-facing landing page (no login required): recommended/public courses carousel, contribution heatmap, recent-notes discovery list. Powered by the backend's FrontPageApiView at GET /api/v1/ (anonymous-friendly).
  • Full five-module sidebar since 0.1.18: Front page, Learner, Course, Activity, Settings. Unlike editor/planner (which limit visibleIndices), the portal surfaces all five so a signed-in user can reach any feature without swapping apps.
  • Pages project-site root redirects here: https://trance-0.github.io/Notechondria//Notechondria/portal/ via the meta-refresh index shipped by .github/workflows/frontend-pages.yml.

Shape

Self-contained Flutter workspace with its own pubspec.yaml, lib/, web/, windows/, test/, Dockerfile, docker-compose.yml, and nginx template.

Library layout

Same part of notechondria_frontend pattern as the other two apps:

FileResponsibility
main.dartLaunches NotechondriaApp with visibleIndices: [0,1,2,3,4] — all five modules on.
app_shell.dartRoot widget + state. Same Settings-save flow + handshake guard as the other apps, plus a compact AppBar title that mirrors the current module's _titles entry.
core/client.dartHttpNotechondriaClient with verifyHandshake.
core/helpers.dartCompile-time API base default.
core/local_store.dartSame SharedPreferences shape.
components/splash_screen.dartKrebs-cycle splash with widget.appTitle overlay.
modules/front.dartPublic front page: carousel of public courses, heatmap (if logged in), recent public notes.
modules/learner.dartLearner view (embeds editor's shape).
modules/course.dartCourse view (embeds planner's shape).
modules/activity.dartActivity view (embeds planner's shape).
modules/settings.dartPortal Settings (partial parity with editor — see "Known drift").

Smoke test

test/smoke_test.dart boots app.main() and asserts find.text('Front page') is present (matches both the compact AppBar title and the navigation destination label after the 0.1.18 rewrite).

API client contract

Same HttpNotechondriaClient contract as the other two apps — see editor_app.md#api-client-contract. Portal-specific calls:

  • getFrontPage() → the combined payload served by the backend FrontPageApiView: {default_course, carousel_courses, recent_notes, recommended_notes, collections, heatmap?, upcoming_events?}.
  • Auth flow is shared (login, register, OAuth, verify, rotate key, change email/password).

Build and deploy

  • Local: flutter run -d chrome from frontend/portal_app/.
  • Smoke test: flutter test test/smoke_test.dart -r compact.
  • GitHub Pages: same frontend-pages.yml workflow, base-href /Notechondria/portal/. Root /Notechondria/ meta-refreshes here.
  • Self-hosted Docker: app-local compose routes location = / through the gateway nginx return 302 /portal/.

Known drift

See index.md §6. Portal-specific: