V1 Web PWA · Surface walkthrough

Legal · Terms of Service

A per-surface walkthrough of the V1 Web PWA customer surface: layout, states, interactions, data, and cross-references.

walked
9sections3 minread

On this page

Context. surface customer · domain onboarding-public · route /legal/terms · auth anon · source apps/oshun/web/src/app/legal/terms/page.tsx

Last walked. 2026-05-29 automated runtime walk (Playwright headless) — render, /v1 data (2xx), console/page-errors, expected content, screenshot verified; manual screen-reader and real telemetry-delivery checks pending. Evidence: WALKTHROUGH/results/runtime-sweep-2026-05-29.md; 2026-06-28 public-legal-pages Playwright pass covered anonymous routing, exact section inventory, legal nav matrix/active states, TOC/back-to-top/print shell controls, 390 px no-overflow, 44 px touch targets, offline-after-load stability, no telemetry hooks, and axe. Manual AT pass and real telemetry delivery remain pending.

Purpose#

OSHUN's Terms of Service. Thirteen titled sections rendered through the shared LegalPageShell (cream paper, terracotta accent, Cormorant Garamond serif) with sticky cross-legal nav and in-page TOC.

Entry points#

  • Footer link "Terms of Service" on /welcome and /landing
  • Sidebar nav inside any other /legal/* page
  • Linked from sign-up "By creating an account, you agree to…" copy
  • Direct URL / bookmark — yes (anon)

Layout regions#

page.tsx defines SECTIONS (13 entries) and renders the article inside <LegalPageShell sections={SECTIONS}>. Section ids: acceptance, description, account-registration, acceptable-use, intellectual-property, user-content, subscription, disclaimer, limitation, termination, governing-law, changes, contact.

  • Header (shell): minimal brand + back link
  • Skip link: jumps to main
  • Sticky sidebar: cross-legal nav (7 entries) + in-page TOC
  • Main article: h1 "Terms of Service", data-legal-date "Last updated: February 21, 2026", then 13 numbered <section> blocks
  • Floating control: back-to-top button

States#

  • Loading — N/A; static server component
  • Default — all sections render
  • TOC click / active section — clicking a TOC button scrolls to that section and marks it data-active="true"; passive scroll-spy remains IntersectionObserver-driven
  • Back-to-top visible — the shared 44 px control appears after scrolling and returns the user near the document start
  • Narrow viewport (≤ 768px) — sidebar collapses; TOC hidden
  • Print — shell @media print rules hide sidebar/header/back-to-top and append anchor hrefs after each link
  • Offline after load — once loaded, the URL, heading, section inventory, and active legal nav state remain stable when the browser context goes offline
  • Gated — N/A; anonymous-readable

Interactions#

  • Each LEGAL_NAV link (link) — navigates to sibling legal page; active when pathname === href; hover applies paper background; mobile target is at least 44 px square

On-this-page TOC (13 buttons)#

  • Each TOC button (button)
    • Function: scrollIntoView for that section id
    • Active styling: terracotta + 2px left border after click and via IntersectionObserver
    • Hidden on ≤ 768px viewport

Back-to-top#

  • "↑" (button, aria-label="Back to top")
    • Function: smooth-scroll to top
    • Visible only when scrollY > 300

Body content#

The Description-of-Service section enumerates the six domain pillars (Tara, Veritas, Nyx, Arete, Nisaba, Metis) but as plain <strong> text, not links. Verify whether these should deep-link into /welcome/domains#*.

Data & contracts#

  • Reads: none — static text
  • Writes: none
  • Caching: SSR static; loaded-route offline stability is asserted. Cold offline navigation / per-legal SW path caching is not asserted, and current sw.js does not path-cache /legal/*.
  • Auth: anon (in middleware PUBLIC_PREFIXES)
  • Metadata: title: 'Terms of Service'

Cross-references#

E2E coverage#

  • Backed by apps/oshun/web/e2e/public-legal-pages.spec.ts — covers anonymous access, exact 13-section inventory, legal nav inventory/active state, shared TOC/back-to-top/print shell behavior, 390 px no-overflow, 44 px touch targets, offline-after-load stability, no telemetry hooks, and axe.

Open questions / known gaps#

  • Cold offline navigation / per-legal SW cache is not asserted and current sw.js does not path-cache /legal/*; PWA shell cache coverage remains in the offline-first / PWA walkthroughs.
  • Domain names listed in description section are not hyperlinked — confirm intent
  • No "I accept" tracking on this page; confirm acceptance is captured at sign-up rather than via inline checkbox
  • LAST_UPDATED is hard-coded — document the change-control flow
  • Hard-coded en-US copy; no localisation hook