Skip to content

Changelog

Chronological log of what's shipped. Most recent first.

2026-04-24 (evening) — SEO baseline + JWT plumbing

SEO (PWA)

  • 🎉 SEO_SITE_URL + SEO_INDEXABLE env switches. Dev defaults to noindex/Disallow; production flips one env var to go live. Canonicals and metadataBase always point at fruitplug.co.uk regardless of where the bytes are served from.
  • 🎉 app/robots.ts — dynamic robots gated on SEO_INDEXABLE. When on, allows crawling and advertises the sitemap; blocks /api/, /cart, /checkout, /account.
  • 🎉 app/sitemap.ts — dynamic sitemap pulling products + categories from the Woo Store API, plus static pages and box-builder templates. 1h revalidate. Empty when SEO_INDEXABLE is off.
  • 🎉 JSON-LD structured dataOrganization + WebSite on home; Product (with Offer + AggregateRating) + BreadcrumbList on PDPs; BreadcrumbList + CollectionPage on category pages. Builders in lib/seo/structured-data.ts, rendered via <JsonLd /> component (HTML-escaped).
  • 🎉 Canonicals + OG on every SSR page. PDPs carry their primary product image as og:image.

Auth foundation (plugin + PWA, not yet deployed)

  • 🎉 HS256 JWT helper in fruitplug-api (Fruitplug\Auth\Jwt) — no third-party deps. Signing key derived from wp_salt('auth') so regenerating salts invalidates every issued token.
  • 🎉 POST /fruitplug/v1/auth/token — username/email + password → JWT. 14-day TTL. Returns safe user payload (id, username, email, display_name, roles).
  • 🎉 GET /fruitplug/v1/auth/meAuthorization: Bearer <jwt> → user identity.
  • 🎉 Bearer-auth filter — hooks determine_current_user so any REST request carrying a valid Bearer auto-becomes that user before permission_callback runs. Every existing is_user_logged_in() gate just works, no endpoint changes needed.
  • 🎉 PWA auth proxy/api/auth/login stores the JWT in an httpOnly cookie (fp_auth), so the browser never touches the token directly. /api/auth/logout clears it. /api/auth/me proxies through.
  • 🎉 lib/fruitplug-api.ts updated to forward Authorization: Bearer from the cookie when forwardAuth: true.
  • 🎉 lib/woo-admin.ts server helper for admin-authenticated Woo REST v3 reads (uses WC_CONSUMER_KEY / WC_CONSUMER_SECRET). Used for fetching order history by customer ID.

Deferred (this session)

  • /login + /account UI pages — paused pending UX/design direction.
  • Yoast metadata passthrough — depends on whether Yoast WooCommerce SEO is active on A2.
  • Plugin deploy — SEO changes are PWA-only; plugin JWT additions stay on disk until explicit go-ahead.

2026-04-24 (later) — Phase 1 Week 5 server wiring

Backend (fruitplug-api)

  • 🎉 Authoritative box templates on the server. New Fruitplug\BoxTemplates class mirrors apps/web/lib/box-templates.ts. Any endpoint that prices or validates a box now routes through BoxTemplates::validate_composition(), so the server, cart hook, and PWA agree on what's legal and what it costs.
  • 🎉 GET /fruitplug/v1/box/templates — public endpoint returning the full template list. Will become the single source of truth once the TS side switches to fetching it.
  • 🎉 POST /fruitplug/v1/box/price tightened. Body is now { template_slug, items } (was just items). Server validates eligibility, section caps, credit budget, and returns the canonical anchor price. Illegal compositions return HTTP 422 with a descriptive code.
  • 🎉 POST /fruitplug/v1/box/save validated. Saved-box payload stores { template_slug, price_gbp, lines } so future loads are replayable even if templates change.
  • 🎉 CustomBoxPricing bug fixed. The cart hook previously summed fruit component prices and set the line price to that sum — contradicting the anchor-price model. It now pins the line to the template's anchor price, so a tampered client can't under-pay.
  • 🎉 Fruit Costs admin page. wp-admin → WooCommerce → Fruit Costs lists every published product with an inline editable _fruitplug_cost_gbp meta. Margin is computed and shown per-row. Replaces the third-party Cost of Goods plugin removed in Phase 0.

Frontend (Next.js PWA)

  • 🎉 lib/fruitplug-api.ts — server-side proxy helper for the plugin (forwards WP login cookies to endpoints that need them).
  • 🎉 /api/box/price + /api/box/save routes — Next.js proxies so the browser never talks to WP directly.
  • 🎉 Box builder live validation. Every composition change debounces a /api/box/price call; the server-returned price drives the CTA, and validation errors are surfaced inline.
  • 🎉 "Save this box" wired to /api/box/save. Login-gated: shows "Sign in to save boxes — coming soon" on 401 (expected until JWT auth ships in Week 4), otherwise reports Saved · /b/{slug}.

Deferred

  • A2 plugin deploy — held back pending explicit auth (no production push without a green-light).
  • Cart-item composition metadata via Woo Store API extension — simpler path is deferred until Stripe checkout lands in Week 3.5.

2026-04-24 — Phase 0 complete · Phase 1 ~60%

Backend (A2 Hosting)

  • 🎉 PHP 7.4.33 → 8.2.30. Enabled mysqli, sodium, imagick in cPanel → Select PHP Version → Extensions.
  • 🎉 Plugin cleanup shipped. Removed 18 frontend-only plugins in 5 verified batches; 38 → 21 active.
  • 🎉 Revisions cleaned. 578 wp_posts revision rows deleted.
  • 🎉 Categories rebalanced. Uncategorised: 6 → 0. New Rare & Special category (5 products). Signature Box duplicate removed from Fruits.
  • 🎉 fruitplug-api installed + activated. 7 wp_fruitplug_* tables created, seasonal calendar seeded.
  • 🎉 Full DB + plugin + theme backup in backups/a2-20260424-205535/ locally. Uploads tarball kept server-side.
  • ⏳ HPOS still needs a one-click toggle in wp-admin (deferred — Woo sync-first migration).

Frontend (Next.js PWA at dev.fruitplug.co.uk)

  • 🎉 Home — hero, wordmark, tagline, social proof, feature cards.
  • 🎉 Shop — all 46 products rendering from Woo Store API.
  • 🎉 Category pages — Fruits, Boxes, Subscription, Merchandise, Rare & Special.
  • 🎉 Product detail pages — variation selector, rating, related, Add to Cart.
  • 🎉 Cart — full Woo cart with Cart-Token + Nonce session, quantity updates, remove, totals.
  • 🎉 Custom Box Builder/build-your-box + /build-your-box/[slug]. 3-tier section model (Premium 20cr / Tropical 12cr / Everyday 8cr), sticky credit budget bar, section min/max enforcement, adds to Woo cart.
  • 🎉 PWA install banner — device-aware (iOS Share-sheet instructions vs Android/Chrome native), 14-day cool-off on dismiss.
  • 🎉 Animated splash screen — dragon-fruit mascot with magenta glow + bounce-in, session-scoped, ?splash=1 override for preview.
  • 🎉 PWA icons regenerated — full wordmark on magenta for launchers, glyph-only for 32px favicon, maskable variants with 20% safe zone.
  • 🎉 Clean mascot PNG — flood-fill chroma-key on white background produces a truly transparent glyph. Saved as public/brand/mascot.png.

Brand & typography

  • 🎉 Display font: Caveat Brush (bolder, marker-pen feel). Closest free match to the Butcher theme's Hugtophia and the user-nominated "Grit".
  • 🎉 Grit hot-swap — layout auto-detects public/fonts/grit.woff2 and uses it over Caveat Brush when present.
  • 🎉 Brand tokens--fp-magenta #be006a, --fp-black, --fp-pith, --fp-leaf, --fp-sticker exposed as CSS vars AND Tailwind utilities.
  • 🎉 Lucide outline icons throughout — 1.75 stroke weight, no emoji in UI.

Infrastructure

  • 🎉 Caddy site blocks for dev.fruitplug.co.uk and docs.fruitplug.co.uk. Auto Let's Encrypt certs.
  • 🎉 Docker dev container with webpack polling for reliable HMR through WSL2 bind mounts.
  • 🎉 MkDocs Material docs site with hot reload and brand theming.
  • 🎉 A2 SSH tooling at infra/a2/ — inventory, backup, plugin cleanup, plugin rsync.
  • 🎉 Paramiko-based automation — encrypted-key support, SFTP, wp-cli pass-through.

Deferred / planned

See the Roadmap — it supersedes this list going forward.

2026-04-23 — Scaffold + plan

  • 📝 Strategic plan written at .claude/plans/hazy-soaring-hedgehog.md and user-approved.
  • 🎉 Next.js 16.2.4 + React 19.2.4 monorepo scaffolded with pnpm workspaces.
  • 🎉 Multi-stage Dockerfile + output: 'standalone' for slim production images.
  • 🎉 CI workflow (GitHub Actions, not yet pushed) — build → GHCR → SSH deploy → smoke test.
  • 🎉 WP custom plugin skeleton at wp-plugin/fruitplug-api/ with 11 PHP files covering 6 REST controllers + DB migrations + cron skeletons.
  • 🎉 Site audit baseline — 13 screenshots, 46 products exported, 38 plugins audited, 151M IG plays cataloged.
  • 🎉 Instagram asset library — 349 videos (2 GB), 53 images, thumbnails, manifest with captions + engagement.