From 6475ea39f9a56b41cab94b2b87b016a077b2e4ce Mon Sep 17 00:00:00 2001 From: User Date: Sat, 22 Aug 2026 17:44:45 +0200 Subject: [PATCH] docs: define local-only logout visibility --- ...-22-local-only-logout-visibility-design.md | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 docs/superpowers/specs/2026-08-22-local-only-logout-visibility-design.md diff --git a/docs/superpowers/specs/2026-08-22-local-only-logout-visibility-design.md b/docs/superpowers/specs/2026-08-22-local-only-logout-visibility-design.md new file mode 100644 index 00000000..83a62469 --- /dev/null +++ b/docs/superpowers/specs/2026-08-22-local-only-logout-visibility-design.md @@ -0,0 +1,124 @@ +# Local-Only Logout Visibility Design + +**Date:** 2026-08-22 +**Status:** approved +**Scope:** frontend visibility of the authenticated-shell logout control +**Source baseline:** `912bab9` + +## 1. Purpose + +ThothII has two distinct authentication journeys: + +- standalone Mac and Windows installations authenticate directly in ThothII with local accounts; +- the Aritmolab server installation authenticates the user in the surrounding portal and exposes + that trusted identity to ThothII. + +The current authenticated shell always renders a `Log out` button. That action is meaningful for +the standalone local-authentication journey, where ThothII owns the browser session. It is +misleading in the server journey because leaving the authenticated environment is a portal-level +operation, not a ThothII operation. + +The frontend must therefore render the logout control only when the public authentication mode is +exactly `local`. + +## 2. Behavioral contract + +The existing `GET /auth/config` response is the sole authority for logout visibility. The frontend +applies this closed rule: + +| Public authentication mode | Show `Log out` | +| --- | --- | +| `local` | yes | +| `upstream` | no | +| `oidc` | no | +| `none` | no | +| `mock` | no | + +This deliberately hides the control for every current and future server-oriented non-local mode. +It does not infer deployment type from the operating system, hostname, URL, user issuer, nullable +session data, or build-time variables. + +The authenticated user's display name remains visible in every mode. Only the `Log out` button is +conditional. + +## 3. Frontend design + +`AuthGate` already loads and validates the public authentication configuration before it requests +`GET /me`. It will derive a boolean logout capability from the retained configuration: + +```text +canLogout = config.mode === "local" +``` + +`AuthGate` passes this capability through `AuthenticatedContent` to `AppShell`. `AppShell` uses it +only to decide whether to render the existing button. The current click handler, logout API +coordinator, authentication-state cleanup, and query/session isolation behavior remain unchanged. + +The capability is passed explicitly instead of being recomputed from `AuthenticatedUser` because +legacy and upstream user representations may have nullable session data. It is also preferable to +a new environment variable because `/auth/config` already represents the backend's effective +authentication mode at runtime. + +## 4. Backend and deployment impact + +No backend route, authentication configuration, Compose descriptor, native `tht` command, or +packaging logic changes. + +`POST /auth/logout` remains available for the local standalone flow and for existing internal +authentication behavior. Hiding a control is not treated as an authorization boundary; backend +authentication and CSRF protections remain authoritative. + +Mac and Windows packages require no platform detection. Their existing local authentication +configuration produces `mode: "local"`, so they retain the button automatically. The Aritmolab +server's trusted-upstream configuration produces `mode: "upstream"`, so it loses the button +automatically. + +## 5. Failure behavior + +`AuthGate` continues to fail closed when `/auth/config` is unavailable or malformed; the +authenticated shell is not rendered in that state. Once the configuration has been accepted, an +unrecognized mode is already rejected by the existing parser and therefore cannot accidentally +enable logout. + +The visibility change introduces no new request, fallback, or error message. In non-local modes +the button is absent and no user-initiated `POST /auth/logout` can originate from this shell +control. + +## 6. Verification + +Frontend component tests will prove: + +1. `AuthGate` propagates logout capability for `mode: "local"` and disables it for + `mode: "upstream"`. +2. `AppShell` renders `Log out` when logout capability is enabled and preserves the existing + request-and-state-clear behavior. +3. `AppShell` keeps the authenticated identity visible but does not render `Log out` when logout + capability is disabled. +4. The focused frontend tests, the complete frontend Vitest suite, TypeScript build-mode + type-check, and production frontend build pass. + +No live server mutation is required to validate this source change. A later manual server smoke +test may confirm that the deployed Aritmolab journey shows the user identity without a ThothII +logout control, while a standalone local-authentication smoke test confirms the control remains. + +## 7. Non-goals + +This change does not: + +- implement portal or global Aritmolab logout; +- redirect users to an Aritmolab logout URL; +- remove or weaken `POST /auth/logout`; +- change login, expiry, session revocation, OIDC, or trusted-upstream behavior; +- detect Mac, Windows, or server packaging in browser code; +- alter any other authenticated-shell control or layout. + +## 8. Acceptance criteria + +The design is complete when: + +- `Log out` is present only for public authentication mode `local`; +- the Aritmolab trusted-upstream server shell has no ThothII logout button; +- standalone Mac and Windows local-authentication behavior is unchanged; +- the username or display name remains visible in all authenticated modes; +- no backend or deployment configuration is added solely for this visibility decision; +- automated frontend tests prevent regression in both local and upstream modes.