# Feature Specification: New-Update Indicator for Guests **Feature**: `016-guest-notifications` **Created**: 2026-03-06 **Status**: Draft **Source**: Migrated from spec/userstories.md ## User Scenarios & Testing ### User Story 1 - Unread update indicator (Priority: P1) A guest opens the event page and sees a visual indicator (badge or highlighted section) drawing attention to update messages that were posted since their last visit. The read state is tracked entirely in localStorage — no server involvement. **Why this priority**: Core purpose of this feature. Without this, guests miss new organizer announcements unless they manually read through all messages. **Independent Test**: Can be tested by opening an event page after new update messages have been posted, verifying that a badge or visual highlight appears on the update messages section. **Acceptance Scenarios**: 1. **Given** a guest has previously visited the event page and `updates_last_seen_at` is stored in localStorage, **When** they return and the event has updates newer than `updates_last_seen_at`, **Then** a visual indicator is shown drawing attention to the unread messages. 2. **Given** the event page is rendered with unread updates shown, **When** the page finishes loading, **Then** `updates_last_seen_at` in localStorage is updated to the timestamp of the most recent update, so the indicator does not appear on the next visit. 3. **Given** a guest opens the event page and all updates are older than the stored `updates_last_seen_at`, **When** the page loads, **Then** no "new update" indicator is shown. --- ### User Story 2 - First visit: no indicator (Priority: P2) A guest who has never visited the event page before (no `updates_last_seen_at` in localStorage) sees the update messages without any "new" badge or indicator. **Why this priority**: A first-time visitor has not established a baseline; labeling existing updates as "new" would be misleading since they have never seen the event before. **Independent Test**: Can be tested by opening an event page on a device with no prior localStorage state for that event token, verifying that no unread indicator is shown even if update messages are present. **Acceptance Scenarios**: 1. **Given** a guest opens an event page for the first time (no `updates_last_seen_at` in localStorage for this event token), **When** the page loads and update messages are present, **Then** no "new update" indicator is shown and `updates_last_seen_at` is initialized to the most recent update timestamp. --- ### User Story 3 - No server read-tracking (Priority: P1) No server request is made to record that a guest viewed the updates. The read state is purely client-side. **Why this priority**: Fundamental privacy requirement — tracking which guests have read which updates would be a form of user surveillance, violating the project's privacy statutes. **Independent Test**: Can be tested by inspecting network traffic when a guest opens the event page, verifying that no "mark as read" or analytics request is sent. **Acceptance Scenarios**: 1. **Given** a guest opens the event page with unread updates, **When** the page loads and `updates_last_seen_at` is updated in localStorage, **Then** no additional server request is made to record the read event. --- ### Edge Cases - What happens when all update messages are deleted (US-10a) and a guest reopens the page? The stored `updates_last_seen_at` should remain in localStorage; no indicator is shown since there are no updates to compare against. - What happens if localStorage is unavailable (private browsing, storage quota exceeded)? The indicator is not shown (degrades gracefully); no error is displayed to the user. - The `updates_last_seen_at` key is separate from the `last_seen_at` key used in US-9 (field-change highlights). The two mechanisms operate independently. ## Requirements ### Functional Requirements - **FR-001**: System MUST display a visual indicator (badge or highlighted section) on the event page when the guest has unread update messages, determined by comparing the newest update's timestamp against `updates_last_seen_at` stored in localStorage. - **FR-002**: System MUST store the `updates_last_seen_at` timestamp in localStorage per event token after each page render, so the indicator clears on subsequent visits. - **FR-003**: System MUST NOT show a "new update" indicator on a guest's first visit to an event page (when no `updates_last_seen_at` exists in localStorage for that event token). - **FR-004**: System MUST initialize `updates_last_seen_at` in localStorage on first visit, set to the timestamp of the most recent update (or a sentinel value if no updates exist), to prevent spurious indicators on subsequent visits. - **FR-005**: System MUST NOT transmit any data to the server when a guest views or is marked as having read update messages — read tracking is purely client-side. - **FR-006**: System MUST use a localStorage key distinct from the `last_seen_at` key used in US-9 to avoid conflicts between the two read-state mechanisms. - **FR-007**: System MUST degrade gracefully if localStorage is unavailable: no indicator is shown, and no error is surfaced to the user. ### Key Entities - **UpdateReadState** (client-side only): Stored in localStorage, keyed by event token. Contains `updates_last_seen_at` (timestamp of the most recent update at last visit). Never transmitted to the server. ## Success Criteria ### Measurable Outcomes - **SC-001**: A guest who has not visited an event page since a new update was posted sees a visual indicator on their next visit, without any server request being made to track readership. - **SC-002**: After the event page is rendered, the same guest sees no indicator on their next visit (indicator clears after viewing). - **SC-003**: A first-time visitor to an event page with existing updates sees no "new" indicator. - **SC-004**: No network request is sent to the server when the read state transitions from unread to read. - **SC-005**: The read-state mechanism is independent of US-9's field-change highlight mechanism — toggling one does not affect the other.