Product pages get og:type=product, og:url, og:image (hero image), and
twitter:card=summary_large_image. All other shop pages get og:type=website
and twitter:card=summary. og:title and og:description mirror the existing
page title and meta description.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Product pages: first 155 chars of description, stripped of HTML, truncated on word boundary.
Collections: contextual description based on collection type.
Content pages (about, delivery, privacy, terms): from hero_description text.
Contact: static description.
Home falls through to site_description from settings (already in layout).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Event call sites (product_view, add_to_cart, checkout_start, purchase)
were only passing visitor_hash and pathname, leaving browser, OS, screen
size and country nil. Add AnalyticsHook.attrs/1 helper to extract common
analytics fields from socket assigns, and use it in all LiveView event
call sites. Checkout controller reads the same fields from the session.
Also fix plug analytics test to clear stale events before assertions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-layer pipeline: Plug for all HTTP requests (no JS needed), LiveView
hook for SPA navigations, JS hook for screen width. ETS-backed buffer
batches writes to SQLite every 10s. Daily-rotating salt for visitor hashing.
Includes admin dashboard with date ranges, visitor trends, top pages,
sources, devices, and e-commerce conversion funnel. Oban cron for 12-month
data retention.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Coming soon page was unstyled after Tailwind removal — replaced
utility classes with proper component CSS. Also removed dead h-full
classes from shop_root layout, adding height: 100% to the shop reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>