<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Requirements on Heimdall</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/</link><description>Recent content in Requirements on Heimdall</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/index.xml" rel="self" type="application/rss+xml"/><item><title>Vision Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/vision-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/vision-document/</guid><description>&lt;h1 id="vision-document--heimdall-ui"&gt;Vision Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-introduction"&gt;1. Introduction&lt;/h2&gt;&#10;&lt;h3 id="11-purpose"&gt;1.1 Purpose&lt;/h3&gt;&#10;&lt;p&gt;This document establishes the vision for &lt;strong&gt;Heimdall UI&lt;/strong&gt;, the Flutter front-end for the&#10;&lt;a href="https://github.com/artur-rios/heimdall-api"&gt;Heimdall API&lt;/a&gt;&#10; — a centralized identity-management API&#10;with scope-based multi-tenancy.&lt;/p&gt;&#10;&lt;h3 id="12-scope"&gt;1.2 Scope&lt;/h3&gt;&#10;&lt;p&gt;Heimdall UI covers every use case the API exposes: the end-user flows (sign in, second factor,&#10;Google sign-in, password recovery, email verification, own profile and security settings) and the&#10;administrative console (scopes, persons, applications, scope permissions, and Google users), with&#10;what each person sees determined by their role.&lt;/p&gt;</description></item><item><title>System Requirements Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/system-requirements-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/system-requirements-document/</guid><description>&lt;h1 id="system-requirements-document--heimdall-ui"&gt;System Requirements Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-introduction"&gt;1. Introduction&lt;/h2&gt;&#10;&lt;h3 id="11-purpose"&gt;1.1 Purpose&lt;/h3&gt;&#10;&lt;p&gt;This document states &lt;strong&gt;what Heimdall UI must do&lt;/strong&gt;, as numbered requirements, and &lt;strong&gt;what qualities it&#10;must have&lt;/strong&gt; while doing it. The &lt;a href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/use-case-specification-document/"&gt;Use Case Specification Document&lt;/a&gt;&#10;&#10;describes the flows that satisfy these requirements; the&#10;&lt;a href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/technology-stack-document/"&gt;Technology Stack Document&lt;/a&gt;&#10; records what they are built with.&lt;/p&gt;&#10;&lt;h3 id="12-requirement-identifiers"&gt;1.2 Requirement identifiers&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Prefix&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Area&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-AU&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Authentication, session, and account recovery&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-SC&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Scope management&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-PE&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Person management&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-AP&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Application management&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-PM&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Scope permission management&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-GU&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Google user management&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-AL&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Audit trail&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;FR-UX&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Shell, navigation, responsiveness, and theming&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;NFR&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Non-functional&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="2-functional-requirements"&gt;2. Functional requirements&lt;/h2&gt;&#10;&lt;h3 id="21-authentication-session-and-recovery-fr-au"&gt;2.1 Authentication, session, and recovery (&lt;code&gt;FR-AU&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall authenticate a person by email and password through &lt;code&gt;POST /api/auth/login&lt;/code&gt;, sending the configured scope as Google sign-in does.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-01&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall detect a two-factor challenge in the login response and continue into the challenge flow instead of establishing a session.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-01, UI-02&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall send a challenge token to &lt;code&gt;POST /api/auth/2fa/verify&lt;/code&gt; and to no other endpoint, and shall never persist it.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-02&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall accept a generated code or a recovery code as the second factor, and shall let the user choose among the methods the API reports as available. Every field that takes a recovery code (sign-in, disabling, regenerating, an own email change) accepts the sixteen-character &lt;code&gt;XXXX-XXXX-XXXX-XXXX&lt;/code&gt; form and the older &lt;code&gt;XXXX-XXXX&lt;/code&gt; one, in any case and with or without hyphens or spaces, sets no length limit, and sends the code as typed, trimmed; the keyboard neither corrects nor completes it.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-02, UI-08, UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall store the bearer token and its expiry in the platform&amp;rsquo;s secure storage, and shall restore the session from it at start-up. On the web the session is restored only in the tab that signed in: across a reload of that tab, and wherever the browser restores that tab&amp;rsquo;s session storage.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-01, UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-06&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall discard a stored token whose expiry has passed without contacting the API.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-07&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall attach the bearer token to every authenticated request as an &lt;code&gt;Authorization: Bearer&lt;/code&gt; header. The token attached is the one held by the session the client is showing, never one read back from storage, so a request always acts as the identity on screen.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-08&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall clear the session and route to sign-in whenever the API answers &lt;code&gt;401&lt;/code&gt; to a request made under the session, except a &lt;code&gt;401&lt;/code&gt; refusing a password or code typed into that request, which the screen shows instead. Such a refusal is recognised by its message: &amp;ldquo;The password or code is incorrect.&amp;rdquo; (every re-authentication under a token, including a paused one and &lt;code&gt;POST /api/auth/2fa/confirm&lt;/code&gt;), and, from older APIs, &amp;ldquo;The current password is incorrect.&amp;rdquo;, &amp;ldquo;The code or recovery code is missing, incorrect, or already used.&amp;rdquo; and &amp;ldquo;The credential presented was not accepted.&amp;rdquo;. A &lt;code&gt;401&lt;/code&gt; to a request made under an earlier session, one that has since ended or been replaced, leaves the current session alone.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-09&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall offer Google sign-in when a Google client id is configured, exchange the resulting ID token at &lt;code&gt;POST /api/auth/google&lt;/code&gt;, and sign out through &lt;code&gt;POST /api/auth/google/sign-out&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-06&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-10&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall request a password reset through &lt;code&gt;POST /api/auth/password-recovery&lt;/code&gt; and shall show the same confirmation whether or not the address is registered.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-03&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-11&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall accept a reset token from a link and complete the reset through &lt;code&gt;POST /api/auth/password-reset&lt;/code&gt;. On the web it shall remove the token from the address once read.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-04&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-12&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall accept a verification token from a link and complete verification through &lt;code&gt;POST /api/auth/verify-email&lt;/code&gt;. On the web it shall remove the token from the address once read.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-05&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-13&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall offer to resend a verification email through &lt;code&gt;POST /api/auth/resend-verification&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-05&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-14&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show an authenticated user with an unverified address a dismissible prompt offering to resend the verification email.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-05&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-15&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show the signed-in person their own profile, read through &lt;code&gt;GET /api/persons/{id}&lt;/code&gt; — or, for a Google User, through &lt;code&gt;GET /api/scopes/{scopeId}/google-users/{id}&lt;/code&gt;, read-only.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-08&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-16&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall let the signed-in person update their own name and email through &lt;code&gt;PUT /api/persons/{id}&lt;/code&gt;. A change of email address (the trimmed values compared exactly, so case counts) shall be confirmed with &lt;code&gt;currentPassword&lt;/code&gt;, and with &lt;code&gt;twoFactorCode&lt;/code&gt; — an authenticator code or a recovery code — when the person&amp;rsquo;s two-factor authentication is on; a name-only change sends neither.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-08&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-17&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall enable two-factor authentication through &lt;code&gt;POST /api/auth/2fa/enable&lt;/code&gt;, sending the person&amp;rsquo;s &lt;code&gt;currentPassword&lt;/code&gt;, and confirm it through &lt;code&gt;POST /api/auth/2fa/confirm&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-18&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall render an &lt;code&gt;otpAuthUri&lt;/code&gt; as a scannable code and shall also present the secret as selectable text.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-19&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall display recovery codes exactly once, offer to copy or download them, and require acknowledgement before navigating away — a browser Back, Forward or typed address included — and ask the browser to confirm closing or reloading the tab while they wait.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-19a&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A copied credential secret, setup key or set of recovery codes shall, where the platform allows, be removed from the clipboard after 60 seconds, unless the clipboard has since changed. Where the platform does not let the application read the clipboard at that moment (an application in the background), the check stays pending and runs again each time the application returns to the foreground past the 60 seconds, until the clipboard can be read; it is never attempted on the web, and not done if the application is closed first. On Android the window shall be excluded from screenshots and the recents thumbnail while one is on screen.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-09, UI-37&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-20&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall disable two-factor authentication through &lt;code&gt;POST /api/auth/2fa/disable&lt;/code&gt; and regenerate recovery codes through &lt;code&gt;POST /api/auth/2fa/recovery-codes/regenerate&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-21&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall recognise a subject-rights-only session — one whose processing is restricted — from &lt;code&gt;processingRestricted&lt;/code&gt; in the answers of &lt;code&gt;POST /api/auth/login&lt;/code&gt;, &lt;code&gt;POST /api/auth/2fa/verify&lt;/code&gt; and &lt;code&gt;POST /api/auth/google&lt;/code&gt;, and from the token&amp;rsquo;s &lt;code&gt;subjectRightsOnly&lt;/code&gt; claim when a session is restored.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-22&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall confine a subject-rights-only session, whatever its role, to the restricted session screen and the privacy notice.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07, UI-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-23&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall lift the caller&amp;rsquo;s own restriction on processing through &lt;code&gt;POST /api/auth/processing-restriction/lift&lt;/code&gt;, then end the session, since the token that lifted it stays confined to the rights endpoints.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-24&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall obtain the caller&amp;rsquo;s own data through &lt;code&gt;POST /api/auth/data-export&lt;/code&gt; and save it as a JSON file: a browser download on the web, the downloads folder on every other target.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-25&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall request erasure of the caller&amp;rsquo;s own identity through &lt;code&gt;POST /api/auth/erasure-request&lt;/code&gt;, confirmed with the password for a person and with a freshly issued Google ID token for a Google User.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-26&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall request a new second-factor email code through &lt;code&gt;POST /api/auth/2fa/challenge/resend&lt;/code&gt; while a challenge answered by email is outstanding, waiting 30 seconds between sends and offering at most three per challenge, after which it offers to start the sign-in again.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-02&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-27&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall let a signed-in person restrict processing of their own identity through &lt;code&gt;POST /api/auth/processing-restriction&lt;/code&gt;, sending one of the four GDPR Art. 18(1) grounds the person chose (none preselected) after a confirmation that says the account is suspended until the restriction is lifted, and shall then end the session and say on the sign-in screen that signing in again opens the restricted session.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-33&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AU-28&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;After the signed-in person changes their own email address, confirms or disables two-factor authentication, or regenerates their recovery codes, the client shall send nothing more under the session&amp;rsquo;s token and shall end the session — after the recovery codes have been shown, when there are any — saying on the sign-in screen &amp;ldquo;Your sign-in details changed. Sign in again.&amp;rdquo;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-08, UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="22-scope-management-fr-sc"&gt;2.2 Scope management (&lt;code&gt;FR-SC&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list scopes through &lt;code&gt;GET /api/scopes&lt;/code&gt;, paginated by the API.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall filter the scope listing by name and shall let the user include logically deleted scopes.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall create a scope through &lt;code&gt;POST /api/scopes&lt;/code&gt;, with a name, a description, and at least one owner.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show a scope through &lt;code&gt;GET /api/scopes/{id}&lt;/code&gt;, including its owners, and a summary of its sign-in and sign-up settings.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall update a scope&amp;rsquo;s name and description through &lt;code&gt;PUT /api/scopes/{id}&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-12&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-06&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall logically delete a scope through &lt;code&gt;DELETE /api/scopes/{id}&lt;/code&gt; after confirmation.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-07&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall permanently delete a scope through &lt;code&gt;DELETE /api/scopes/{id}/hard&lt;/code&gt; after a confirmation requiring the scope&amp;rsquo;s name to be typed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-08&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list a scope&amp;rsquo;s owners through &lt;code&gt;GET /api/scopes/{scopeId}/owners&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-09&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall add an existing Scope Admin as a co-owner through &lt;code&gt;POST /api/scopes/{scopeId}/owners/{personId}&lt;/code&gt;, and shall say &amp;ldquo;Invitation sent&amp;rdquo; and list the person as pending when the answer says the API invited them.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-10&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall create a new Scope Admin as a co-owner through &lt;code&gt;POST /api/scopes/{scopeId}/owners&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-11&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall promote a user of the scope to owner through &lt;code&gt;POST /api/scopes/{scopeId}/users/{personId}/promote&lt;/code&gt;, and shall remove an owner through &lt;code&gt;DELETE /api/scopes/{scopeId}/owners/{personId}&lt;/code&gt;, each after confirmation. The lists of owners and of promotable users shall be paged, and the users searched, so that every owner and user is reachable.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-12&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall toggle a scope&amp;rsquo;s Google Sign-In through &lt;code&gt;PUT /api/scopes/{id}/google-signin&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-15, UI-31&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-13&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show and toggle a scope&amp;rsquo;s self-registration through &lt;code&gt;PUT /api/scopes/{id}/self-registration&lt;/code&gt;, asking before opening it while the scope has no verification link and before closing it.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-31&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-14&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall set or clear a scope&amp;rsquo;s verification and password-reset links through &lt;code&gt;PUT /api/scopes/{id}/email-links&lt;/code&gt;, sending both on every save, trimmed, with an empty link sent as &lt;code&gt;null&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-31&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-15&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A System Admin or an owning Scope Admin can list a scope&amp;rsquo;s pending self-registrations, newest first and paginated, with name, address, sign-up and expiry instants, attempts left and whether each has expired. No secret is shown.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-35&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-16&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;They can discard one after confirming. A registration already gone is reported as such and the list refreshed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-35&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-17&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list a scope&amp;rsquo;s pending owner invitations through &lt;code&gt;GET /api/scopes/{scopeId}/owner-invitations&lt;/code&gt;, with each invitee&amp;rsquo;s name, address and expiry, and shall withdraw one through &lt;code&gt;DELETE /api/scopes/{scopeId}/owner-invitations/{invitationId}&lt;/code&gt; after confirmation, reading the lists again when the API answers &lt;code&gt;404&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-18&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall tell an invitation from an added owner by the &lt;code&gt;invited&lt;/code&gt; field of the answer to &lt;code&gt;POST /api/scopes/{scopeId}/owners/{personId}&lt;/code&gt;, not by its status code.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-SC-19&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show the signed-in administrator&amp;rsquo;s open invitations on Home through &lt;code&gt;GET /api/persons/me/scope-invitations&lt;/code&gt;, and accept or decline one through &lt;code&gt;POST /api/scope-invitations/{invitationId}/accept&lt;/code&gt; or &lt;code&gt;…/decline&lt;/code&gt; after confirmation; after accepting it shall refresh the scopes it shows, and on a &lt;code&gt;404&lt;/code&gt; it shall read the invitations again and show the API&amp;rsquo;s message.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-39&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="23-person-management-fr-pe"&gt;2.3 Person management (&lt;code&gt;FR-PE&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list the persons of a scope through &lt;code&gt;GET /api/scopes/{scopeId}/persons&lt;/code&gt;, paginated by the API.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall filter the person listing and shall let the user include logically deleted persons.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall create a person within a scope through &lt;code&gt;POST /api/scopes/{scopeId}/persons&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall let a System Admin create a person belonging to no scope through &lt;code&gt;POST /api/persons&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show a person through &lt;code&gt;GET /api/persons/{id}&lt;/code&gt;, including role, scope membership, owned scopes, verification state, and whether a second factor is configured.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-18&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-06&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall update a person&amp;rsquo;s name and email through &lt;code&gt;PUT /api/persons/{id}&lt;/code&gt;, asking for no password. On the signed-in person&amp;rsquo;s own record the email address is read-only, since it is changed from the profile (FR-AU-16).&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-18&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-07&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall logically delete a person through &lt;code&gt;DELETE /api/persons/{id}&lt;/code&gt; after confirmation.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-08&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall permanently delete a person through &lt;code&gt;DELETE /api/persons/{id}/hard&lt;/code&gt; after a confirmation requiring the person&amp;rsquo;s email to be typed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-09&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall offer the owners a scope may be given from &lt;code&gt;GET /api/persons/scope-admins&lt;/code&gt;, leaving out the persons who already own the scope being managed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-11, UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-10&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A System Admin, or a Scope Admin viewing a User of a scope they own, can have a fresh verification link sent to a person whose address is unverified, after confirming.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-36&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-11&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;They can have a password reset link sent, after confirming. Neither action shows a link or code; the API&amp;rsquo;s refusals — including its cooldown — are shown as returned.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-36&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PE-12&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A System Admin can list the system&amp;rsquo;s System Admins, filtered by name or email and paged, through &lt;code&gt;GET /api/persons/system-admins&lt;/code&gt;, and open each one&amp;rsquo;s person page.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-38&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="24-application-management-fr-ap"&gt;2.4 Application management (&lt;code&gt;FR-AP&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list a scope&amp;rsquo;s applications through &lt;code&gt;GET /api/scopes/{scopeId}/applications&lt;/code&gt;, paginated by the API.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-20&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall filter the application listing and shall let the user include logically deleted applications.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-20&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall create an application through &lt;code&gt;POST /api/scopes/{scopeId}/applications&lt;/code&gt;, with a name and an owner drawn from the persons of that scope.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-21&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show an application through &lt;code&gt;GET /api/scopes/{scopeId}/applications/{id}&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-22&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall update an application&amp;rsquo;s name and owner through &lt;code&gt;PUT /api/scopes/{scopeId}/applications/{id}&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-22&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-06&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall logically delete an application through &lt;code&gt;DELETE /api/scopes/{scopeId}/applications/{id}&lt;/code&gt; after confirmation.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-23&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-07&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall permanently delete an application through &lt;code&gt;DELETE /api/scopes/{scopeId}/applications/{id}/hard&lt;/code&gt; after a confirmation requiring the application&amp;rsquo;s name to be typed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-23&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-08&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall resolve each application&amp;rsquo;s owner to a person, and shall fall back to the identifier when it cannot.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-20, UI-22&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-09&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A System Admin or the owning Scope Admin can list an application&amp;rsquo;s credentials, newest first, with status, issue, expiry and last-use instants. No secret or hash is shown.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-37&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-10&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;They can issue a credential with an optional expiry date; its secret is shown once, in a dialog that only closes when the user says it is stored. Issuing is not offered while two credentials are live.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-37&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AP-11&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;They can revoke a credential after confirming.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-37&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="25-scope-permission-management-fr-pm"&gt;2.5 Scope permission management (&lt;code&gt;FR-PM&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list a scope&amp;rsquo;s permissions through &lt;code&gt;GET /api/scopes/{scopeId}/permissions&lt;/code&gt;, paginated by the API.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall filter the permission listing and shall let the user include logically deleted permissions.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall create a permission through &lt;code&gt;POST /api/scopes/{scopeId}/permissions&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-25&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall state, where the claim flag is set, that the permission is issued in the scope&amp;rsquo;s tokens.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-25, UI-26&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show a permission through &lt;code&gt;GET /api/scopes/{scopeId}/permissions/{id}&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-26&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-06&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall update a permission&amp;rsquo;s name, description, and claim flag through &lt;code&gt;PUT /api/scopes/{scopeId}/permissions/{id}&lt;/code&gt;.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-26&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-07&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall logically delete a permission through &lt;code&gt;DELETE /api/scopes/{scopeId}/permissions/{id}&lt;/code&gt; after confirmation.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-27&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-PM-08&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall permanently delete a permission through &lt;code&gt;DELETE /api/scopes/{scopeId}/permissions/{id}/hard&lt;/code&gt; after a confirmation requiring the permission&amp;rsquo;s name to be typed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-27&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="26-google-user-management-fr-gu"&gt;2.6 Google user management (&lt;code&gt;FR-GU&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-GU-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list a scope&amp;rsquo;s Google users through &lt;code&gt;GET /api/scopes/{scopeId}/google-users&lt;/code&gt;, paginated by the API.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-GU-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show a Google user through &lt;code&gt;GET /api/scopes/{scopeId}/google-users/{id}&lt;/code&gt;, read-only.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-GU-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall fall back to an initials avatar when a profile picture is missing or unreachable.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-GU-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall logically delete a Google user through &lt;code&gt;DELETE /api/scopes/{scopeId}/google-users/{id}&lt;/code&gt; after confirmation.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-29&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-GU-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall permanently delete a Google user through &lt;code&gt;DELETE /api/scopes/{scopeId}/google-users/{id}/hard&lt;/code&gt; after a confirmation requiring the Google user&amp;rsquo;s email to be typed.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-29&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="27-shell-navigation-and-presentation-fr-ux"&gt;2.7 Shell, navigation, and presentation (&lt;code&gt;FR-UX&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall present navigation appropriate to the window&amp;rsquo;s breakpoint: a bottom bar when compact, a rail when medium, and an extended rail when expanded. A rail scrolls when the window, or what a soft keyboard leaves of it, is too short for its destinations, so every destination stays reachable.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show only the destinations the signed-in role can use.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall support light, dark, and system theme modes, and shall remember the choice between launches.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;—&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-04&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall render collections as cards when compact and as a paginated table when expanded, from one declaration per collection.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-10, UI-16, UI-20, UI-24, UI-28, UI-32, UI-34, UI-35, UI-38&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-05&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall render the API&amp;rsquo;s &lt;code&gt;errors&lt;/code&gt; array as returned, against the offending field where the error names one and in a banner otherwise.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;All&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-06&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall distinguish an empty collection from a filtered collection with no matches, and shall offer the appropriate next action for each.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-10, UI-16, UI-20, UI-24, UI-28, UI-32, UI-34, UI-35, UI-38&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-07&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall show a retryable error state when a request fails for transport reasons, preserving the user&amp;rsquo;s filters and input. Wherever a transport failure is shown, it reads &amp;ldquo;Could not reach the API. Check your connection and try again.&amp;rdquo;, never the HTTP library&amp;rsquo;s own text. An answer the client cannot read, such as a success response whose body is not the expected shape, shows &amp;ldquo;The API returned an unexpected response.&amp;rdquo; with Retry, never an endless placeholder.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;All&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-08&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall address every screen by a URL, so that a link opens the screen directly on the web target.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-09&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A &lt;code&gt;429&lt;/code&gt; shows the API&amp;rsquo;s message, and never ends the session. When the response carries &lt;code&gt;Retry-After&lt;/code&gt;, it adds &amp;ldquo;Try again in N seconds.&amp;rdquo;, in minutes from a minute and in hours from an hour, rounded up; a control that would send the same email again (the verification resend, the second-factor code resend, starting the email method) stays disabled for that long. &lt;code&gt;Retry-After&lt;/code&gt; is read as whole non-negative seconds and held to a day (86400); zero, a sign, a fraction, an HTTP-date or anything else unreadable pauses nothing and adds no hint.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-01, UI-02, UI-03, UI-04, UI-05, UI-06, UI-09, UI-30, UI-36&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-UX-10&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A record&amp;rsquo;s screen sits on the list it is opened from, a scope&amp;rsquo;s own screens on the scope, Security on the profile and the System Admins list on Home, so the system Back and the browser&amp;rsquo;s Back return there, a link to a record arrives with its list beneath, and a list, a scope, the profile or Home returned to is read again; on Home and the main lists the system Back leaves the app. Leaving an unsaved edit of a record, a new record&amp;rsquo;s form, the profile or a scope&amp;rsquo;s sign-in settings — by the navigation, the back control, the system Back or the browser&amp;rsquo;s Back — asks first, and so does signing out while any open screen holds one.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="28-data-subject-administration-fr-da"&gt;2.8 Data subject administration (&lt;code&gt;FR-DA&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-DA-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall list outstanding erasure requests through &lt;code&gt;GET /api/auth/erasure-requests&lt;/code&gt;, paginated by the API, soonest deadline first, with an overdue-only filter, showing no name or email address.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-32&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-DA-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The client shall re-apply erasures after a restore through &lt;code&gt;POST /api/auth/erasure-reconciliation&lt;/code&gt;, sending only a non-empty, de-duplicated list of identifiers after confirmation, and shall show how many were anonymised, already anonymised and not found.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-32&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="29-audit-trail-fr-al"&gt;2.9 Audit trail (&lt;code&gt;FR-AL&lt;/code&gt;)&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;ID&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Requirement&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AL-01&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;A System Admin can list the audit trail, newest first and paginated, filtered by an inclusive range of local days, by exact action, actor identifier, target identifier and outcome.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-34&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AL-02&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Each entry shows the instant in local date and time, the action, the outcome with its reason, and the actor (identifier and role) and target identifiers as returned. An entry with no actor — an anonymous action, or an attribution cleared after the attribution period or once the person was erased — reads &amp;ldquo;None&amp;rdquo;; nothing is resolved to a name.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-34&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;FR-AL-03&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Actor and target filters accept only identifiers, trimmed and lowercased before they are sent.&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-34&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="3-screen-inventory"&gt;3. Screen inventory&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Route&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Screen&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Use case&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/login&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Sign in&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-01, UI-06&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/login/two-factor&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Second-factor challenge&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-02&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/password-recovery&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Request password reset&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-03&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/password-reset&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Set a new password&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-04&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/verify-email&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Verify an email address&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-05&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/restricted&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Restricted session — lift the restriction, download one&amp;rsquo;s data, request erasure&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-30&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Home&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/profile&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Own profile; restrict processing of one&amp;rsquo;s own account&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-08, UI-33&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/profile/security&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Two-factor and recovery codes&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-09&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Scope listing&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-10&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/new&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Create a scope&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-11&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Scope detail&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-12, UI-13&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/owners&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Scope owners&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-14&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/sign-in-settings&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Sign-in &amp;amp; sign-up&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-31, UI-15&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/pending-registrations&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Pending registrations — list and discard&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-35&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/persons&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Person listing&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-16&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/persons/new&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Create a person&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-17&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/persons/:personId&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Person detail, with the account emails card&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-18, UI-19, UI-36&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/applications&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Application listing&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-20&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/applications/new&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Create an application&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-21&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/applications/:applicationId&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Application detail, with the credentials card&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-22, UI-23, UI-37&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/permissions&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Permission listing&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-24&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/permissions/new&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Create a permission&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-25&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/permissions/:permissionId&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Permission detail&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-26, UI-27&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/google-users&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Google user listing&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-28&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/scopes/:scopeId/google-users/:googleUserId&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Google user detail&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-29&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/system-admins&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;System Admins — list, search and page; rows open the person page&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-38&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/system-admins/:personId&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Person detail without a scope, opened from the System Admins list; back returns to it. &lt;code&gt;/persons/:personId&lt;/code&gt;, its earlier address, redirects here&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-38, UI-18, UI-19&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/erasure-requests&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Outstanding erasure requests; re-apply erasures after a restore&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-32&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/audit-log&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Audit trail — filter by dates, action, actor, target and outcome&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-34&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/health&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;API health and diagnostics&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;P-04&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/privacy&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Privacy notice — the Heimdall API&amp;rsquo;s own, shown verbatim; the privacy policy link on Google&amp;rsquo;s consent screen&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/artur-rios/heimdall-ui/issues/73"&gt;#73&lt;/a&gt;&#10;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;/not-found&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Not found — where a route whose id is not a &lt;code&gt;PublicId&lt;/code&gt; lands&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;UI-07&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="4-authorization-matrix"&gt;4. Authorization matrix&lt;/h2&gt;&#10;&lt;p&gt;What each role is offered. The API remains the authority: this table describes what the interface&#10;shows, and a request the API refuses is refused regardless of what appears here.&lt;/p&gt;</description></item><item><title>Use Case Specification Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/use-case-specification-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/use-case-specification-document/</guid><description>&lt;h1 id="use-case-specification-document--heimdall-ui"&gt;Use Case Specification Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-introduction"&gt;1. Introduction&lt;/h2&gt;&#10;&lt;h3 id="11-purpose"&gt;1.1 Purpose&lt;/h3&gt;&#10;&lt;p&gt;This document specifies &lt;strong&gt;what the Heimdall UI does&lt;/strong&gt;, use case by use case. Each use case describes&#10;one coherent piece of work a user performs through the interface, with its main flow and every&#10;alternative flow the implementation must handle.&lt;/p&gt;&#10;&lt;p&gt;The UI is a client of the &lt;a href="https://github.com/artur-rios/heimdall-api"&gt;Heimdall API&lt;/a&gt;&#10;. Each use case&#10;carries a &lt;strong&gt;Traces to&lt;/strong&gt; line naming the API use cases it consumes, so a change on either side can be&#10;followed to the other. The mapping is deliberately not one-to-one: an API use case that only makes&#10;sense alongside another (viewing and updating a record, for instance) becomes a single screen here,&#10;and one API use case can serve several screens.&lt;/p&gt;</description></item><item><title>Technology Stack Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/technology-stack-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/technology-stack-document/</guid><description>&lt;h1 id="technology-stack-document--heimdall-ui"&gt;Technology Stack Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-purpose"&gt;1. Purpose&lt;/h2&gt;&#10;&lt;p&gt;This document is the &lt;strong&gt;single source of truth for the technologies used to build Heimdall UI&lt;/strong&gt; — the&#10;framework, language, state management, routing, networking, storage, code generation, and testing&#10;tools, together with the version each is pinned to and the role it plays.&lt;/p&gt;&#10;&lt;p&gt;Every other document references this one for technical choices instead of restating them, so that&#10;versions and roles are maintained in exactly one place.&lt;/p&gt;</description></item><item><title>Testing Specification Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/testing-specification-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/testing-specification-document/</guid><description>&lt;h1 id="testing-specification-document--heimdall-ui"&gt;Testing Specification Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-purpose"&gt;1. Purpose&lt;/h2&gt;&#10;&lt;p&gt;This document defines &lt;strong&gt;how tests are written&lt;/strong&gt; for Heimdall UI, so that every use case receives the&#10;same shape of testing with the same tools, naming, and structure. The&#10;&lt;a href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/development-workflow-document/"&gt;Development Workflow Document&lt;/a&gt;&#10; defines &lt;em&gt;when&lt;/em&gt; testing happens&#10;in the delivery flow; the &lt;a href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/technology-stack-document/"&gt;Technology Stack Document&lt;/a&gt;&#10; records the&#10;tools themselves.&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="2-levels"&gt;2. Levels&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Level&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;What it covers&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;Where it lives&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Unit&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Controllers and notifiers, repository implementations, envelope unwrapping, guards, mappers, and any pure function&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;test/&lt;/code&gt;, mirroring &lt;code&gt;lib/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Widget&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Screens and shared widgets: what renders, what the user can do, and how the layout responds to the breakpoint&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;test/&lt;/code&gt;, mirroring &lt;code&gt;lib/&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;strong&gt;Flow&lt;/strong&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Whole flows across several screens, driven through the real router against fakes — a widget test that calls &lt;code&gt;pumpApp(router: ...)&lt;/code&gt; or &lt;code&gt;routerFor:&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;The feature&amp;rsquo;s &lt;code&gt;presentation/&lt;/code&gt; tests, e.g. &lt;code&gt;test/features/scopes/presentation/scope_list_screen_test.dart&lt;/code&gt;. &lt;code&gt;test/app/&lt;/code&gt; holds the app and router tests, which pump &lt;code&gt;HeimdallApp&lt;/code&gt; directly&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;code&gt;test/&lt;/code&gt; mirrors &lt;code&gt;lib/&lt;/code&gt; one directory at a time: &lt;code&gt;lib/features/auth/presentation/session_controller.dart&lt;/code&gt;&#10;is tested by &lt;code&gt;test/features/auth/presentation/session_controller_test.dart&lt;/code&gt;. A test file that does&#10;not correspond to a source file is a sign the source is in the wrong place.&lt;/p&gt;</description></item><item><title>Development Workflow Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/development-workflow-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/development-workflow-document/</guid><description>&lt;h1 id="development-workflow-document--heimdall-ui"&gt;Development Workflow Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-purpose"&gt;1. Purpose&lt;/h2&gt;&#10;&lt;p&gt;This document defines &lt;strong&gt;how a use case moves from backlog to merged&lt;/strong&gt; — the branch, the issue status&#10;transitions, the testing gate, and the pull request. It is the standard every contributor, human or&#10;agent, follows so that each use case (UI-01 … UI-39 in the&#10;&lt;a href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/use-case-specification-document/"&gt;Use Case Specification Document&lt;/a&gt;&#10;, plus the platform items&#10;P-01 … P-04) is delivered the same way.&lt;/p&gt;</description></item><item><title>Operations &amp; Infrastructure Document</title><link>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/operations--infrastructure-document/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/operations--infrastructure-document/</guid><description>&lt;h1 id="operations--infrastructure-document--heimdall-ui"&gt;Operations &amp;amp; Infrastructure Document — Heimdall UI&lt;/h1&gt;&#10;&lt;h2 id="1-purpose"&gt;1. Purpose&lt;/h2&gt;&#10;&lt;p&gt;This document covers everything between a checkout and a running application: how the client is&#10;configured, how it is built for each target, what each build produces, what the host needs, and what&#10;continuous integration does. The technologies themselves are recorded in the&#10;&lt;a href="https://docs.artur-rios.tech/heimdall-docs/docs/application/requirements/documents/technology-stack-document/"&gt;Technology Stack Document&lt;/a&gt;&#10;.&lt;/p&gt;&#10;&lt;p&gt;Heimdall UI has &lt;strong&gt;no server-side component of its own&lt;/strong&gt;. It is a client; the&#10;&lt;a href="https://github.com/artur-rios/heimdall-api"&gt;Heimdall API&lt;/a&gt;&#10; is the only backend, and every operational&#10;concern about data, tokens, and email belongs there.&lt;/p&gt;</description></item></channel></rss>