# 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 5–10 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` (`Active`). Furthermore, expired passes remain in the active deck rather than being filtered or marked as expired. | **Action Item:**
1. Derive badge dynamically: if `is_paused` $\rightarrow$ `badge-warning Paused`; if `isExpired` $\rightarrow$ `badge-secondary Expired`; else `badge-success Active`.
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:
`[Date] · [Time] · [ Colored Urgency Badge ]`
• **Natural Date String:** `Today` (if $<24$h), `Tomorrow` (if $<48$h), `Sep 23` (same year), `Jan 15, 2027` (future year).
• **Exact Time:** `10:39 PM` (local time).
• **Floating Dot Separator:** Styled subtle `·` with muted opacity to preserve visual rhythm.
• **Multi-Tier Urgency Badge:**
- $<1$h: Amber `[ 45m left ]`
- $<24$h: Amber/Green `[ 2h 45m left ]`
- 1–60d: Green `[ 28d left ]`
- 2–12 mos: Green `[ 4.5 mos left ]` (no clunky `142d`)
- 1+ yrs: Green `[ 1.2 yrs left ]` (no clunky `420d`)
- Expired: Red `[ Expired ]`
• **Optional Prefix:** `showPrefix?: boolean` (defaults to `false` since headers/cards establish context).
• **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):**
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.
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'`.
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:**
• Update SQL in `events.ts:extend` to use `GREATEST(expires_at, NOW())`.
• In `EventCockpitDeck.tsx`, render expired passes in a collapsed `` / `[ 📁 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:**
1. Displaying raw minutes (`Joined 474m ago`) is unreadable math clutter.
2. Printing full redundant slugs (`guest_universal-sandbox-read-only_1`) on every seat creates massive visual noise.
3. Missing actionable guest telemetry (last action, ingress route, activity level). | **Action Item (Inverted Start-Time & Telemetry Pattern):**
• **Header:** Bold `Seat #[N]` + `🟢 Active / ⏸️ Paused` badge.
• **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.
• **Line 2 (Action Telemetry):** `Last Action: ForwardAuth Ingress (ed-droid) · 2m ago · 💻 Web` (pulling `last_activity_action` and `last_activity_at` from `sessions`).
• 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 `Event Passes
`, while `EventCockpitDeck.tsx:7` ALSO rendered `Event Passes
` alongside the view toggle, creating two stacked identical titles. | **Action Item:** Remove the redundant `Event Passes
` 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):**
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.
2. **Border Bleed:** Input boxes and Copy buttons blow past the right card border boundary.
3. **Buttons Pushed Outside Card:** `[ 👥 Guests (3) ]` and `[ ▸ Details ]` are pushed completely outside the blue card border onto the empty page background.
4. **Mock Code Regression:** The `[ ▸ Details ]` button executes an inline browser alert (`alert('Expand functionality for compact view to be implemented if needed')`).
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):
• **Row 1:** `[▸ Event Title (ellipsis, max-w 260px)]` · `[Date · Time · Urgency Badge]` · `[3/40 Seats]` · `[🟢 Status Badge]`.
• **Row 2:** `[ PIN: 241-881 (Copy) ]` `[ Link (Copy) ]` `[ CLI (Copy) ]` on the left, and `[ 👥 Guests (3) ]` + `[ 🔄 +1h ]` docked on the right.
• Remove mock `[ ▸ Details ]` alert completely since all handoffs are 1 click away on Row 2.
• Remove duplicate `Event Passes
` 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):**
• **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);`).
• **Inactive Option:** Muted translucent background (`color: var(--text-muted); opacity: 0.75;`).
• 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":**
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.
2. The bottom button says `"Dismiss"`, which sounds negative and confusing. | **Action Item:**
• Standardize all 3 copy buttons to uniform `btn-outline` (`Copy PIN`, `Copy URL`, `Copy 1-Liner`).
• 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:
• Reset `#eventCreateState` to `display: block` and `#eventHandoffState` to `display: none`.
• Clear form input values.
• 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):**
• Update `POST /api/events/:id/rotate-pin` to rotate **BOTH** the numeric PIN (`pin_code`) and the event slug suffix (`slug`).
• Return `{ success: true, pinCode, slug, link, cli }` and update all 3 fields in the UI simultaneously.
• 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.