Files
konstruct/.planning/phases/08-mobile-pwa/08-VERIFICATION.md
Adolfo Delorenzo a9077e3559 docs(phase-8): complete Mobile + PWA phase execution
Fixed uuid() recursion bug, updated MOB-02 requirement text.
All 8 phases complete.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 21:39:04 -06:00

20 KiB
Raw Blame History

phase, verified, status, score, gaps, human_verification
phase verified status score gaps human_verification
08-mobile-pwa 2026-03-26T03:35:51Z gaps_found 11/13 must-haves verified
truth status reason artifacts missing
Streaming responses (word-by-word tokens) work on mobile failed uuid() in chat-window.tsx line 18 calls itself recursively instead of crypto.randomUUID() — infinite recursion and stack overflow on every HTTPS/localhost chat message send where crypto.randomUUID is available
path issue
packages/portal/components/chat-window.tsx Line 18: return uuid() should be return crypto.randomUUID() — calls itself instead of the native function
Fix line 18: change `return uuid()` to `return crypto.randomUUID()`
truth status reason artifacts missing
MOB-02 requirement text satisfied — sidebar collapses to bottom tab bar (requirement text says hamburger menu) partial REQUIREMENTS.md MOB-02 specifies 'hamburger menu' but implementation uses a bottom tab bar. The PLAN, SUMMARY, and codebase all consistently implement a tab bar which is a superior mobile UX pattern. The REQUIREMENTS.md description is outdated. This is a documentation mismatch, not a code gap — the implemented UX exceeds the requirement intent.
path issue
.planning/REQUIREMENTS.md MOB-02 text says 'hamburger menu' but codebase implements bottom tab bar per PLAN. REQUIREMENTS.md should be updated to reflect the actual design.
Update REQUIREMENTS.md MOB-02 description to say 'bottom tab bar' instead of 'hamburger menu'
test expected why_human
Navigate all portal pages at 320px and 768px viewports No horizontal scroll, no overlapping elements, readable text at both widths Visual layout correctness on real or emulated viewports cannot be verified by grep
test expected why_human
Tap each bottom tab bar item at 320px width, then open More sheet Active indicator shows, correct page loads, More sheet slides up with RBAC-filtered items Touch tap target size (44px minimum), animation smoothness, and RBAC filtering require real device or browser DevTools interaction
test expected why_human
Open chat, tap a conversation, send a message and wait for streaming response on mobile Full-screen chat with back arrow, tokens appear word-by-word, back arrow returns to list Streaming animation and touch navigation flow require browser runtime
test expected why_human
Open Chrome DevTools > Application > Manifest Manifest loads with name=Konstruct, icons at 192/512/maskable, start_url=/dashboard PWA installability requires browser DevTools or Lighthouse audit
test expected why_human
Enable push notifications via More sheet > bell icon, then close browser tab Push notification appears when AI Employee responds; tapping it opens the correct conversation Push notification delivery requires a running server, VAPID keys, and a real browser push subscription

Phase 8: Mobile PWA Verification Report

Phase Goal: The portal is fully responsive on mobile/tablet devices and installable as a Progressive Web App — operators and customers can manage their AI workforce and chat with employees from any device Verified: 2026-03-26T03:35:51Z Status: gaps_found Re-verification: No — initial verification

Goal Achievement

Observable Truths

# Truth Status Evidence
1 Desktop sidebar is hidden on screens < 768px; bottom tab bar appears instead VERIFIED layout.tsx:44 hidden md:flex wraps Nav; MobileNav has md:hidden class
2 Bottom tab bar has 5 items: Dashboard, Employees, Chat, Usage, More VERIFIED mobile-nav.tsx:28-33 TAB_ITEMS array + More button at line 78
3 More sheet opens with Billing, API Keys, Users, Platform, Settings, Sign Out (RBAC) VERIFIED mobile-more-sheet.tsx:32-38 SHEET_ITEMS with allowedRoles + signOut button at line 107
4 Main content has bottom padding on mobile to clear the tab bar VERIFIED layout.tsx:50 pb-20 md:pb-8 applied to max-w container
5 Portal is installable as a PWA with manifest, icons, and service worker VERIFIED manifest.ts exports valid manifest; sw.ts uses Serwist; all 5 icon PNGs exist
6 Offline banner appears when network is lost VERIFIED offline-banner.tsx returns amber banner when useOnlineStatus() is false
7 All existing pages remain functional on desktop (no regression) HUMAN NEEDED Sidebar visible at md+ in hidden md:flex div — automated check passes; visual needs human
8 On mobile, tapping a conversation shows full-screen chat with back arrow header VERIFIED chat/page.tsx:271-276 MobileChatHeader rendered when mobileShowChat is true
9 Back arrow returns to conversation list on mobile VERIFIED mobile-chat-header.tsx:24-29 onBack callback; chat/page.tsx:275 sets mobileShowChat=false
10 Desktop two-column chat layout is unchanged VERIFIED chat/page.tsx:244-262 md:w-72 md:block classes preserved on sidebar panel
11 Chat input stays visible when iOS virtual keyboard opens VERIFIED chat-window.tsx:266-269 keyboardOffset from useVisualViewport applied to input paddingBottom
12 Streaming responses (word-by-word tokens) work on mobile FAILED chat-window.tsx:17-18 uuid() calls itself recursively — infinite recursion on send
13 User can grant push notification permission from the portal VERIFIED push-permission.tsx full state machine; embedded in MobileMoreSheet

Score: 11/13 truths verified (1 failed, 1 human-needed)


Required Artifacts

Artifact Provides Exists Substantive Wired Status
packages/portal/components/mobile-nav.tsx Bottom tab bar for mobile YES YES YES VERIFIED
packages/portal/components/mobile-more-sheet.tsx Bottom sheet secondary nav with RBAC YES YES YES VERIFIED
packages/portal/app/manifest.ts PWA manifest with K monogram icons YES YES YES VERIFIED
packages/portal/app/sw.ts Serwist SW + push + notificationclick handlers YES YES YES VERIFIED
packages/portal/components/sw-register.tsx Service worker registration YES YES YES VERIFIED
packages/portal/components/offline-banner.tsx Offline status indicator YES YES YES VERIFIED
packages/portal/components/mobile-chat-header.tsx Back arrow + agent name for mobile chat YES YES YES VERIFIED
packages/portal/lib/use-visual-viewport.ts Visual Viewport hook for iOS keyboard offset YES YES YES VERIFIED
packages/portal/components/install-prompt.tsx Second-visit PWA install banner (Android + iOS) YES YES YES VERIFIED
packages/portal/components/push-permission.tsx Push opt-in with permission state machine YES YES YES VERIFIED
packages/portal/lib/message-queue.ts IndexedDB offline message queue YES YES YES VERIFIED
packages/portal/app/actions/push.ts Server actions for push (planned artifact) NO MISSING
packages/gateway/routers/push.py Push API endpoints (planned path) NO* MISSING*
packages/shared/shared/api/push.py Push API (actual path — different from plan) YES YES YES VERIFIED
migrations/versions/012_push_subscriptions.py push_subscriptions table migration YES YES YES VERIFIED
packages/portal/public/icon-192.png PWA icon 192x192 YES YES VERIFIED
packages/portal/public/icon-512.png PWA icon 512x512 YES YES VERIFIED
packages/portal/public/icon-maskable-192.png Maskable PWA icon YES YES VERIFIED
packages/portal/public/apple-touch-icon.png Apple touch icon YES YES VERIFIED
packages/portal/public/badge-72.png Notification badge icon YES YES VERIFIED

NOTE: app/actions/push.ts and gateway/routers/push.py are listed in the plan frontmatter but were deliberately implemented differently. Push subscription management is handled via direct fetch in push-permission.tsx to /api/portal/push/subscribe, which is served by shared/api/push.py (consistent with all other API routers in this project). The plan's artifact list is outdated; no functional gap exists for push subscription flow. These are documentation mismatches, not code gaps.


From To Via Status Details
app/(dashboard)/layout.tsx components/mobile-nav.tsx hidden md:flex / md:hidden pattern WIRED Line 44: hidden md:flex on Nav div; MobileNav at line 57 is always rendered (md:hidden internally)
next.config.ts app/sw.ts withSerwist wrapper WIRED Lines 7-11: withSerwistInit configured with swSrc/swDest
app/layout.tsx components/sw-register.tsx Mounted in body WIRED Line 47: <ServiceWorkerRegistration /> in body
app/(dashboard)/chat/page.tsx components/mobile-chat-header.tsx Rendered when mobileShowChat is true WIRED Lines 271-276: MobileChatHeader rendered inside mobileShowChat block
components/chat-window.tsx lib/use-visual-viewport.ts keyboardOffset applied to input WIRED Line 32: import; line 77: const keyboardOffset = useVisualViewport(); line 268: applied as style
app/(dashboard)/chat/page.tsx mobileShowChat state State toggle on conversation select WIRED Line 154: useState; lines 173-181: handleSelectConversation sets true
app/sw.ts push event handler self.addEventListener('push', ...) WIRED Line 24: push event listener; lines 35-46: showNotification call
app/sw.ts notificationclick handler self.addEventListener('notificationclick', ...) WIRED Line 48: notificationclick listener; deep-link to /chat?id=
gateway/channels/web.py shared/api/push.py asyncio.create_task(_send_push_notification) WIRED Line 462: asyncio.create_task; line 115: imports _send_push
lib/use-chat-socket.ts lib/message-queue.ts enqueue when offline, drain on reconnect WIRED Line 17: imports; line 105: drainQueue in ws.onopen; line 208: enqueueMessage in send

Requirements Coverage

Requirement Source Plan Description Status Evidence
MOB-01 08-01 All portal pages render correctly on mobile (320px480px) and tablet HUMAN NEEDED Layout wiring verified; visual correctness requires browser test
MOB-02 08-01 Sidebar collapses (spec: hamburger menu, impl: bottom tab bar) VERIFIED* Tab bar implemented — superior to spec'd hamburger; REQUIREMENTS.md text is stale
MOB-03 08-02 Chat interface fully functional on mobile — send, stream, scroll history FAILED mobileShowChat toggle wired; MobileChatHeader present; BUT uuid() recursive bug in chat-window.tsx blocks message send in secure contexts
MOB-04 08-01 Portal installable as PWA with icon, splash, service worker VERIFIED manifest.ts, sw.ts, all icons, next.config.ts withSerwist all confirmed
MOB-05 08-03 Push notifications for new messages when PWA installed VERIFIED Full pipeline: PushPermission -> push.py -> 012 migration -> web.py trigger -> sw.ts handler
MOB-06 08-02 All touch interactions feel native — no hover-dependent UI on touch devices HUMAN NEEDED active:bg-accent classes present on all interactive items; 44px tap targets in all components; needs real device confirmation

*MOB-02: REQUIREMENTS.md says "hamburger menu" — implementation delivers a bottom tab bar per the PLAN design. The tab bar is the intended and superior design; requirement text is stale documentation.


Anti-Patterns Found

File Line Pattern Severity Impact
packages/portal/components/chat-window.tsx 18 return uuid() — recursive call BLOCKER Infinite recursion when crypto.randomUUID is available (all HTTPS + localhost). Chat messages never send; browser tab crashes or hangs.

Human Verification Required

1. Responsive Layout at Multiple Viewports (MOB-01)

Test: Open Chrome DevTools, toggle device toolbar, test at 320px (iPhone SE), 768px (iPad), 1024px (iPad landscape). Navigate to Dashboard, Employees, Chat, Usage, and Billing pages. Expected: No horizontal scrolling, no overlapping elements, readable text at all widths. Sidebar visible at 768px+, tab bar visible at 320px. Why human: Visual layout correctness (overflow, overlap, text truncation) requires rendered browser output.

2. Bottom Tab Bar Navigation and More Sheet (MOB-02)

Test: At 320px, tap each tab (Dashboard, Employees, Chat, Usage). Tap More — verify sheet slides up. Check with customer_operator role that Billing/API Keys/Users are hidden in the sheet. Expected: Active indicator on tapped tab; correct page loads; More sheet shows RBAC-filtered items; LanguageSwitcher and push permission toggle visible. Why human: Touch tap feedback, animation smoothness, and RBAC filtering in the rendered session context cannot be verified by static analysis.

3. Mobile Chat Full-Screen Flow (MOB-03)

Test: At 320px, navigate to Chat. Tap a conversation — verify full-screen mode with back arrow header and agent name. After fixing the uuid() bug (see Gaps), send a message and verify streaming tokens appear word-by-word. Tap back arrow — verify return to list. Expected: WhatsApp-style navigation; streaming tokens render incrementally; back arrow works. Why human: Streaming animation and back navigation flow require browser runtime. The uuid() bug MUST be fixed first.

4. PWA Installability (MOB-04)

Test: Open Chrome DevTools > Application > Manifest. Verify manifest loads with name=Konstruct, icons at 192/512/maskable, start_url=/dashboard, display=standalone. Check Application > Service Workers for registration. Expected: Manifest loads without errors; service worker registered and active; Lighthouse PWA audit score >= 90. Why human: PWA install flow requires a browser with HTTPS or localhost, Lighthouse, or Android device.

5. Push Notifications (MOB-05)

Test: Open More sheet, tap bell icon, grant notification permission. Close the browser tab. Trigger an AI Employee response (via API or second browser window). Tap the push notification. Expected: Notification appears on device; tapping notification opens the portal at the correct conversation URL. Why human: Push notification delivery requires running backend services, VAPID keys, and a real browser push subscription. Cannot simulate with grep.

6. Touch Interaction Native Feel (MOB-06)

Test: At 320px, tap all buttons, links, and interactive elements throughout the portal. Test tab bar items, More sheet links, chat send button, conversation list items. Expected: Immediate visual feedback on tap (active state); no hover-stuck states; all targets reachable with a finger (>= 44px). Why human: Touch interaction feel, hover-stuck detection, and tap target perception require a real touch device or touch simulation in DevTools.


Gaps Summary

One blocker gap, one documentation gap.

Blocker: Infinite recursion in uuid() (chat-window.tsx line 18)

The uuid() helper function in chat-window.tsx was written to fall back to a manual UUID generator when crypto.randomUUID is unavailable (e.g., HTTP non-secure context). However, the branch that should call crypto.randomUUID() calls uuid() itself recursively. In any secure context (HTTPS, localhost), crypto.randomUUID is always available, so every call to uuid() immediately recurses infinitely — causing a stack overflow. Chat messages in the portal require uuid() to generate stable IDs for optimistic UI updates (lines 100, 148, 158, 198). The fix is one character: change return uuid() to return crypto.randomUUID() on line 18.

Documentation gap: REQUIREMENTS.md MOB-02 text is stale

The REQUIREMENTS.md describes MOB-02 as "hamburger menu" but the design (defined in the PLAN and implemented in the codebase) uses a bottom tab bar — a more native mobile pattern. This is a documentation-only mismatch; the codebase correctly implements the intended design. Updating REQUIREMENTS.md to say "bottom tab bar" would bring the documentation in sync with the actual implementation.


Verified: 2026-03-26T03:35:51Z Verifier: Claude (gsd-verifier)