···44TBD - created by archiving change bootstrap-finance-app. Update Purpose after archive.
55## Requirements
66### Requirement: ATProto OAuth login
77-The system SHALL authenticate users via AT Protocol OAuth using handle-based login. The user enters their handle (or DID); the system resolves it, performs the OAuth authorization flow (PAR, PKCE, DPoP) against the user's authorization server, and establishes an application session on success. The system SHALL request only the `atproto` scope and SHALL NOT access the user's PDS data after authentication.
77+The system SHALL authenticate users via AT Protocol OAuth using handle-based login. The user enters their handle (or DID); the system resolves it, performs the OAuth authorization flow (PAR, PKCE, DPoP) against the user's authorization server, and establishes an application session on success. The system SHALL request only the `atproto` scope and SHALL NOT make authenticated requests to the user's PDS after authentication. Resolving and rendering profile pictures from public ATProto profile data — without using the OAuth session or any application credential — is permitted.
8899#### Scenario: Successful login with allowlisted handle
1010- **WHEN** a user whose DID is in the allowlist completes the OAuth flow
···5353- **WHEN** the server process restarts and a user presents a previously issued valid session cookie
5454- **THEN** the session is honored because it is persisted in SQLite
55555656+### Requirement: Profile picture display
5757+The system SHALL display user profile pictures resolved from public ATProto profile data, keyed by the user's current handle and fetched by the browser without application credentials. Avatars SHALL appear in the navigation user chip alongside the handle, and in categorization provenance displays in place of the handle text, where the handle SHALL be revealed in a popover on hover or keyboard focus and the DID SHALL remain available via an accessible label. When an avatar cannot be loaded or does not exist, the UI SHALL fall back to the textual handle presentation.
5858+5959+#### Scenario: Nav chip shows avatar
6060+- **WHEN** an authenticated user views any app page
6161+- **THEN** the navigation user chip shows their avatar together with their handle
6262+6363+#### Scenario: Provenance avatar with popover
6464+- **WHEN** a user hovers over or keyboard-focuses the actor avatar in a transaction's categorization history
6565+- **THEN** a popover reveals the actor's handle, and the DID is exposed via an accessible label
6666+6767+#### Scenario: Avatar unavailable
6868+- **WHEN** an avatar image fails to load or the actor has no profile picture
6969+- **THEN** the UI renders the actor's handle as text, and no provenance information is lost
7070+7171+#### Scenario: Server fetches no profile data
7272+- **WHEN** pages containing avatars are rendered
7373+- **THEN** all profile-image requests originate from the browser against public endpoints, and the application server performs no profile-data requests
7474+