Adds a public funnel landing at `/` and moves the login to `/login`, rebuilt around the panel's own colors instead of an invented palette. Landing (`src/components/landing/`, one section per file, no props): - Seven funnel sections composed by `LandingPage`. The hero's eight swatches are literally `PIE_COLORS` from `DashboardPage`, the same hex values the seed hands to avatars and services, so "your colors become your numbers" is literal. - `BrandMark` becomes the single source for the logo, replicating `public/favicon.svg`. Blue is the action surface, orange only ever marks. - `NotebookVisual` is the one deliberate exception to the palette: it is what the product replaces. - Copy drops all system vocabulary; motion comes from `src/lib/motion.ts` with a single easing, and reduced-motion resolves `initial` to the final state so a never-firing `whileInView` cannot leave a section invisible forever. Routing and bundle: - `homePathFor` is the single definition of each role's destination. - Landing, login, dashboard and calendar load lazily. Eager, the login dragged framer-motion (~40 KB gz) into every panel load and the landing downloaded recharts + FullCalendar (~187 KB gz) without charting anything. `clsx` is pinned to the `react` chunk because Rollup otherwise assigns it to `charts`, making the entry import 111 KB gz for a 200-byte utility. Responsiveness (iPhone/iPad), verified with `npm run audit:responsive`: - No touch form field below 16px, `dvh` height utilities, safe-area insets, and 40px touch targets keyed off `pointer: coarse` rather than `sm:`. - New `.ld-gutter`: `.safe-x` lives outside `@layer` and beats Tailwind's `px-*`, so it left the login's side padding at 0 on anything but an iPhone in landscape. No overflow check could see it — there was no overflow, just zero margin. The audit now guards it with a `gutter` check. - `shell-height` no longer fires on pages that legitimately scroll; the static `raw-viewport-unit` scan covers those instead. Production build: - The Dockerfile now sets `VITE_DEMO_UI=1` as a build arg. `DEMO` is a build-time constant, so without it Vite eliminated the magic login and the "Ver como…" switcher: the deployed landing promised "no registration" and led to an empty form. Verified by building both ways and diffing the bundle. - Service worker cache bumped to v2 so the orphaned pre-landing chunks get purged from returning visitors' caches. Verified: typecheck clean; unit 39/39, e2e 33/33, admin 17/17, booking 12/12, landing 13/13 (WebKit), PWA passed against the real production build. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
5.9 KiB
5.9 KiB
Task 4 Report
Files
- Added
pwa-e2e.mjswith production endpoint, manifest, SPA fallback, Chromium install prompt, iOS instructions, standalone/unsupported states, service-worker readiness/source checks, and real browser/api/healthrequest verification. - Updated
README.mdwith local production validation, Android/Chrome installation, iOS Safari instructions, standalone behavior, connectivity expectations, and Coolify HTTPS validation guidance.
Verification
node --check pwa-e2e.mjs: passed.npm.cmd run typecheck: passed.npm.cmd run build: passed; Vite produced the production bundle indist/.npm.cmd run test:pwa: passed; outputPWA checks passedagainst the built production server on port 3000.npm.cmd run audit:visual: passed; 58 screens/visits, 0 failed loads, 0 horizontal overflow issues. The audit reported 8 console 404 messages while still exiting 0.git diff --check: passed with no whitespace errors. Git emitted existing LF-to-CRLF working-copy warnings for tracked files.
The first PWA run exposed a test-harness race where the synthetic event could fire before React registered its listener. The harness was corrected to dispatch 100 ms after load; the subsequent production run passed.
Self-review
- Endpoint checks use the configured
PWA_BASE_URL, defaulting tohttp://localhost:3000. - Manifest assertions cover standalone display, root start URL/scope, and both required icon sizes.
- Browser contexts are isolated for Chromium prompt, iOS Safari instructions, standalone mode, and unsupported/no-event mode.
- Service-worker readiness has a five-second bound, and the source guard checks cover
/api/and non-GET requests. - The browser API check observes a real request and validates its JSON response rather than using a fixture.
- No app authentication, tenant data, API route, database schema, or runtime behavior was changed.
Concerns
- The visual audit continues to record eight pre-existing 404 console messages on some authenticated/admin visits. They were not introduced by Task 4 and were not changed because the task explicitly limits scope to PWA verification and production documentation.
- The report itself and pre-existing
.superpowers/sdd/*andgraphify-out/*changes remain outside the Task 4 commit staging set.
Review Fixes
- Added
fetchWithTimeout()usingAbortControllerfor every direct endpoint/source fetch. The in-page/api/healthrequest now uses its own boundedAbortControlleras well. - Added exact-one accessible-action coverage for the login page, authenticated business shell, and authenticated admin shell. Business/admin flows use the existing demo credentials and a mobile viewport so their compact install controls are visible and accessible.
- Replaced fixed sleeps in standalone/unsupported checks with bounded DOM-state polling for zero matching install actions.
- Replaced iOS body-text checks with visible exact-text locators for
CompartirandAñadir a pantalla de inicio. - Relaxed service-worker source checks to tolerate whitespace and quote style while still requiring the pathname
/api/bypass and non-GET guard. - Tracked all browser contexts and closes them explicitly before closing the browser in
finally; default UI/navigation timeouts are bounded.
Review-Fix Verification
node --check pwa-e2e.mjs: passed.npm.cmd run typecheck: passed.npm.cmd run build: passed; Vite produced the production bundle indist/.npm.cmd run test:pwa: passed; outputPWA checks passedagainst the built production server on port 3000.npm.cmd run audit:visual: passed; 58 screens/visits, 0 failed loads, 0 horizontal overflow issues. The audit still reports 8 pre-existing console 404 messages.git diff --check: passed with no whitespace errors; Git only emitted existing LF-to-CRLF working-copy warnings.
Review-Fix Self-review
- Direct network operations now have bounded completion, including response-body reads for endpoint/source assertions and the browser-side API response.
- Login, business, and admin each assert one and only one accessible
Instalar AgendaMaxaction; the two shell checks exercise the authenticated UI path rather than assuming route markup. - Negative install-state checks wait on the DOM condition with a timeout and fail non-zero if the condition never becomes true.
- All changes remain in the PWA test harness and this report; application behavior and unrelated tests are unchanged.
Remaining Concerns
- The visual audit's 8 pre-existing 404 console messages remain outside Task 4 scope. They do not cause failed loads, overflow failures, or a non-zero audit exit.
Service-worker Behavioral Fix
- Added a reload and
navigator.serviceWorker.controllergate before behavioral API checks, ensuring requests run through an active, controlling worker. - While online, the browser now verifies
GET /api/healthreturns200and a safe invalidPOST /api/auth/loginreturns401. - With the Playwright context offline, both API requests must produce bounded network errors rather than cached responses. Connectivity is restored in a
finallyblock.
Service-worker Behavioral Verification
npm.cmd run typecheck: passed.npm.cmd run build: passed; Vite produced the production bundle indist/.npm.cmd run test:pwa: passed; outputPWA checks passedagainst the built production server on port 3000.git diff --check: passed with no whitespace errors; Git only emitted existing LF-to-CRLF working-copy warnings.
Service-worker Behavioral Self-review
- The online assertions validate real statuses (
200and401) before offline mode is enabled, so a cached fixture cannot satisfy the positive path. - Offline assertions require both requests to reject with a network-error result and do not accept a response status or body.
- The offline state is always reverted in
finally, and the existing bounded request, navigation, worker-readiness, UI, install-surface, and cleanup checks remain intact.