auth-yes/tasks/ui-audit-3.md

56 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UI & UX Live Audit Log — Round 3 (`ui-audit-3.md`)
**Date:** 2026-08-26 (Session: 21:30)\
**Target Environments:** `https://auth.atyg.org` | `https://ed-droid.atyg.org`\
**Scope:** Verification of Phase 5 Deliverables (True Slide-Over Guest Drawer,
Multi-Event Compact Toggle, Standardized Countdown Pills, Mobile Density
Optimization, Backend Revocation).
---
## 1. Core Verification Focus Areas
| # | Feature / Flow | Target Behavior | Status |
| :---- | :------------------------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------- |
| **1** | **Slide-Over Guest Drawer** | Clicking `[ 👥 Manage Guests (N) ]` opens a fixed right-side panel on Desktop (`420px; 100vh`) and bottom sheet on Mobile (`100vw; 80vh`) with backdrop fade, `Escape` key close, and backdrop click dismissal. | ⏳ Pending Test |
| **2** | **Guest Drawer Information IA** | Pinned contextual header showing `[Event Name] Guests` + `N / Max Claimed Seats · ⏳ Xh Ym left · (Expires Time)`. Individual rows only display unique data (`Seat #[N]`, `Username`, `Joined relative time`, `🟢 Active / ⏸️ Paused`). | ⏳ Pending Test |
| **3** | **Backend Revocation Fix** | Event creator clicking `[ 🗑️ Revoke ]` inside the Guest Drawer immediately deletes the attendee session from Valkey cache and DB without 404 access-denied errors. | ⏳ Pending Test |
| **4** | **Multi-Event Compact Toggle** | `[ 🗂️ Grid ]` vs `[ 📋 Compact ]` toggle collapses 510 active event cards into sleek 1-row strips (`Title · 🟢 Active · ⏳ 2h 45m left · 12/50 Seats · PIN · [ 👥 Guests ]`). View mode persists in `localStorage`. | ⏳ Pending Test |
| **5** | **Dynamic Countdown Pills** | Countdown pills across all Event Pass cards, Guest Drawer, and Sessions list display `⏳ Xh Ym left · (Expires Time)` with dynamic colors (green $\rightarrow$ amber $<1$h $\rightarrow$ red expired) and tick down live every 30s. | Pending Test |
| **6** | **Mobile Session Density** | Remote personal device cards in `SessionDeck.tsx` have no dedicated full-width bottom row; compact `[ 🗑️ Revoke ]` sits inline in the header row next to the status badge. | Pending Test |
---
## 2. Live Observation & Findings Log
_Record observations, visual feedback, quirks, and confirmations here as we
execute._
| Timestamp | Scenario | Component / Flow | Observation / Finding | Resolution / Action Item |
| :-------- | :------------------------------ | :------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `21:30` | Setup | System | Opened `ui-audit-3.md` tracking log for Phase 5 live deployment testing. | Ready for live observation inputs. |
| `21:31` | State Consistency | `EventCockpitDeck.tsx` & Queries | **Contradictory Status (`⏳ Expired` + `Active` Badge):** An expired workshop pass shows the countdown pill as `⏳ Expired` (red) but right next to it the status badge remains hardcoded as green `Active` (`<span class="badge badge-success status-badge">Active</span>`). Furthermore, expired passes remain in the active deck rather than being filtered or marked as expired. | **Action Item:**<br>1. Derive badge dynamically: if `is_paused` $\rightarrow$ `badge-warning Paused`; if `isExpired` $\rightarrow$ `badge-secondary Expired`; else `badge-success Active`.<br>2. Filter out or separate expired passes in the database query (`WHERE expires_at > NOW()`) so the active cockpit deck only shows currently actionable passes. |
| `21:38` | Information Architecture | `ExpiryBadge` Component | **Finalized Natural Expiry & Lifespan Format (Option A+):** Standardize all session and pass expiration indicators to a clean, highly readable pattern:<br>`[Date] · [Time] · [ Colored Urgency Badge ]`<br><br>**Natural Date String:** `Today` (if $<24$h), `Tomorrow` (if $<48$h), `Sep 23` (same year), `Jan 15, 2027` (future year).<br>**Exact Time:** `10:39 PM` (local time).<br>**Floating Dot Separator:** Styled subtle `·` with muted opacity to preserve visual rhythm.<br>**Multi-Tier Urgency Badge:**<br>&nbsp;&nbsp;- $<1$h: Amber `[ 45m left ]`<br>&nbsp;&nbsp;- $<24$h: Amber/Green `[ 2h 45m left ]`<br>&nbsp;&nbsp;- 160d: Green `[ 28d left ]`<br>&nbsp;&nbsp;- 212 mos: Green `[ 4.5 mos left ]` (no clunky `142d`)<br>&nbsp;&nbsp;- 1+ yrs: Green `[ 1.2 yrs left ]` (no clunky `420d`)<br>&nbsp;&nbsp;- Expired: Red `[ Expired ]`<br>**Optional Prefix:** `showPrefix?: boolean` (defaults to `false` since headers/cards establish context).<br>**Full Precision Tooltip:** `title="Wednesday, August 26, 2026, 10:39:01 PM EDT"` on element for hover/long-press. | |
| `21:59` | Lifecycle & Business Logic | `server/routes/events.ts` & Deck | **Extending Expired Events (Re-activation vs Kill Switch):**<br>1. **Not an Anti-Pattern:** Allowing an event host to add time to a naturally expired event (where `is_active = TRUE`) is high-value for real workshops running overtime, saving the host from creating a new event and forcing 30 participants to re-join.<br>2. **Backend Math Bug:** Currently `SET expires_at = expires_at + interval '1 hour'` fails if the event expired hours ago. It must be `SET expires_at = GREATEST(expires_at, NOW()) + interval '${extendHours} hours'`.<br>3. **Distinction from Hard Kill Switch:** `[ End Event ]` sets `is_active = FALSE` (hard revocation, permanent archive). A naturally expired event remains `is_active = TRUE` and can be re-opened with `[ 🔄 Reopen (+1h) ]`. | **Action Item:**<br>• Update SQL in `events.ts:extend` to use `GREATEST(expires_at, NOW())`.<br>• In `EventCockpitDeck.tsx`, render expired passes in a collapsed `<details>` / `[ 📁 Expired Passes (N) ]` section or with a distinct `[ 🔄 Reopen (+1h) ]` button rather than deleting them immediately. |
| `22:13` | IA & Telemetry Design | `EventGuestsDrawer.tsx` & Script | **Clunky "Joined 474m ago" & Redundant Slug Overwhelm:**<br>1. Displaying raw minutes (`Joined 474m ago`) is unreadable math clutter.<br>2. Printing full redundant slugs (`guest_universal-sandbox-read-only_1`) on every seat creates massive visual noise.<br>3. Missing actionable guest telemetry (last action, ingress route, activity level). | **Action Item (Inverted Start-Time & Telemetry Pattern):**<br>**Header:** Bold `Seat #[N]` + `🟢 Active / ⏸️ Paused` badge.<br>**Line 1 (Inverted Start-Time):** `Joined Today · 2:15 PM · [ Active 7h 54m ]` (or `Joined Aug 25 · [ Active 2d ]`) using the symmetrical time-since formatter.<br>**Line 2 (Action Telemetry):** `Last Action: ForwardAuth Ingress (ed-droid) · 2m ago · 💻 Web` (pulling `last_activity_action` and `last_activity_at` from `sessions`).<br>• Drop the redundant full slug from the visual text (keep in hover tooltip only). |
| `22:18` | Visual Layout & Redundancy | `SessionsPage.tsx` vs `EventCockpitDeck.tsx` | **Duplicate "Event Passes" Heading:** `SessionsPage.tsx:60` rendered `<h2>Event Passes</h2>`, while `EventCockpitDeck.tsx:7` ALSO rendered `<h2>Event Passes</h2>` alongside the view toggle, creating two stacked identical titles. | **Action Item:** Remove the redundant `<h2>Event Passes</h2>` from `SessionsPage.tsx` so `EventCockpitDeck.tsx` exclusively owns its section header and attached view mode toggle. |
| `22:25` | Layout Density & Visual Bug | `EventCockpitDeck.tsx` (Compact View) | **Critical Compact Mode Breakdown (Verified via Screenshot):**<br>1. **Severe Text Collision:** The event title (`testing workshop event:...`) collides and overlaps directly on top of `Seats Claimed 3/40`, `⏳ Expired`, and the PIN input.<br>2. **Border Bleed:** Input boxes and Copy buttons blow past the right card border boundary.<br>3. **Buttons Pushed Outside Card:** `[ 👥 Guests (3) ]` and `[ ▸ Details ]` are pushed completely outside the blue card border onto the empty page background.<br>4. **Mock Code Regression:** The `[ ▸ Details ]` button executes an inline browser alert (`alert('Expand functionality for compact view to be implemented if needed')`).<br>5. **Double Heading & Arrow:** Double `Event Passes` headings and double `▶ ▸` disclosure arrows. | **Action Item (2-Row Compact Card Architecture):** Scrap the broken single-line CSS hack. Build a dedicated, strictly bounded **2-Row Compact Card** (~70px height):<br>**Row 1:** `[▸ Event Title (ellipsis, max-w 260px)]` · `[Date · Time · Urgency Badge]` · `[3/40 Seats]` · `[🟢 Status Badge]`.<br>**Row 2:** `[ PIN: 241-881 (Copy) ]` `[ Link (Copy) ]` `[ CLI (Copy) ]` on the left, and `[ 👥 Guests (3) ]` + `[ 🔄 +1h ]` docked on the right.<br>• Remove mock `[ ▸ Details ]` alert completely since all handoffs are 1 click away on Row 2.<br>• Remove duplicate `<h2>Event Passes</h2>` from `SessionsPage.tsx`. |
| `22:30` | Visual Affordance & Contrast | `EventCockpitDeck.tsx` (View Toggle) | **Ambiguous Active State on Grid/Compact Toggle:** The `[ 🗂️ Grid ]` vs `[ 📋 Compact ]` toggle lacks clear visual distinction between active and inactive states (both look almost flat with faint border outlines), making it hard to discern at a glance which mode is currently selected. | **Action Item (High-Contrast Segmented Pill Control):**<br>**Active Option:** High-contrast solid brand pill (`background: var(--primary); color: #ffffff; font-weight: 700; box-shadow: 0 1px 3px rgba(0,0,0,0.3);`).<br>**Inactive Option:** Muted translucent background (`color: var(--text-muted); opacity: 0.75;`).<br>• Include `aria-pressed="true/false"` for complete screen reader accessibility. |
| `22:54` | UX Polish & Action Clarity | `WorkshopDrawer.tsx` (Handoff State) | **Mismatched Blue Copy Button & Ambiguous "Dismiss":**<br>1. In the created event handoff screen, `Copy PIN` is styled as `btn-primary` (solid blue) while `Copy URL` and `Copy 1-Liner` are `btn-outline`, creating inconsistent button hierarchy.<br>2. The bottom button says `"Dismiss"`, which sounds negative and confusing. | **Action Item:**<br>• Standardize all 3 copy buttons to uniform `btn-outline` (`Copy PIN`, `Copy URL`, `Copy 1-Liner`).<br>• Replace `"Dismiss"` with a clean, minimal button **`[ OK ]`** that closes the drawer and ensures the newly created event appears in the deck. |
| `22:58` | State Machine Reset | `SessionsScript.tsx` (`openDelegateDrawer`) | **Stale Drawer State on Re-open:** When clicking `[ Delegate Session ]` after previously creating an event or session, the drawer opens directly to the stale handoff success screen rather than resetting back to the clean creation form. | **Action Item:** In `openDelegateDrawer()`, always reset the state machine:<br>• Reset `#eventCreateState` to `display: block` and `#eventHandoffState` to `display: none`.<br>• Clear form input values.<br>• Default back to `Single Session` tab. |
| `23:01` | Security & Ingress Invalidation | `server/routes/events.ts` (`rotate-pin`) | **Incomplete Ingress Rotation (PIN rotated but Link & CLI stayed open):** Currently, clicking rotate only generates a new 6-digit PIN, leaving the static slug active. If the direct link or CLI command was leaked to bad actors, rotating the PIN fails to lock them out! | **Action Item (Universal Ingress Rotation):**<br>• Update `POST /api/events/:id/rotate-pin` to rotate **BOTH** the numeric PIN (`pin_code`) and the event slug suffix (`slug`).<br>• Return `{ success: true, pinCode, slug, link, cli }` and update all 3 fields in the UI simultaneously.<br>• Existing active attendees remain completely unaffected, while any new join attempt using the old PIN, old Link, or old CLI command is immediately blocked. |
---
## 3. Retained Security & Architecture Roadmap
- [ ] **🛡️ Peer-to-Peer Vouching (High-Security Web of Trust):** Attendee PIN
join $\rightarrow$ `quarantined: true` $\rightarrow$ Local peer/host
1-time QR code/emoji approval $\rightarrow$ Activated (with hierarchical
branch revocation).
- [ ] **⚡ Transparent Client Proof-of-Work (PoW):** Background ~50ms
`crypto.subtle` SHA-256 hash collision on PIN submission to defeat
distributed botnets.
- [ ] **📌 Sticky / Persistent Delegation Action Bar:** Floating/sticky trigger
for `[ Delegate Session ]` on deep scrolling pages.