From bb349e42f5abba0aedb78c27cdb90a80e73d4fc8 Mon Sep 17 00:00:00 2001 From: Nora Date: Fri, 26 Jun 2026 17:08:08 -0600 Subject: [PATCH] docs(qa): remove 4 high-risk unsupported marketing/security promises Per docs/qa/audit-2026-06-26/FINAL-REPORT.md. Audited 32 customer-facing promises across marketing, docs, and public UI; 22 lacked code backing. This commit removes the four highest-risk items: - Fabricated landing stats (500+ farms, 98% on-time, 50K+ orders, 2M+ lbs) and 4.9/12 JSON-LD rating on src/app/page.tsx + HeroSection.tsx. - Fake named testimonials (Marcus / Sandra / James with numeric claims) replaced with honest 'Early access' copy + contact CTA. - Pricing source-of-truth mismatch: Farm annual 152280 -> 134100, Enterprise annual 0 -> 359100 (25% off, matching pricing.ts). - Security claims (SOC 2 Type II, 99.9% uptime SLA, quarterly pentests, 2FA via Supabase Auth) re-scoped to providers we actually use (Vercel, Neon Postgres, Stripe). Provider cards updated. - Plus LOW-risk cleanups: OG image refs (-> .svg), SMS Campaigns + Route Optimization reclassified as shipped on roadmap, /roadmap/suggestion form replaced with mailto:, wholesale login Google error string fix. Note: src/app/wholesale/login/page.tsx and src/app/pricing/PricingClientPage.tsx were also touched by an unrelated useState->useReducer refactor in the same session. Those changes are bundled here because git add -p per-hunk separation would be brittle. Follow-up commits should isolate the remaining 81 modified files if they belong to a coherent change. Remaining 10 unsupported items documented in PROPOSE section of FINAL-REPORT.md need separate decisions (see that file). --- docs/qa/audit-2026-06-26/FINAL-REPORT.md | 141 ++ docs/qa/audit-2026-06-26/PROMISE-AUDIT.md | 337 ++++ src/app/blog/page.tsx | 3 +- src/app/contact/page.tsx | 5 +- src/app/page.tsx | 11 +- src/app/pricing/PricingClientPage.tsx | 834 ++++---- src/app/pricing/page.tsx | 5 +- src/app/roadmap/page.tsx | 73 +- src/app/security/page.tsx | 60 +- src/app/wholesale/login/page.tsx | 185 +- src/components/landing/HeroSection.tsx | 2138 +++++++++++---------- src/lib/stripe-billing.ts | 4 +- 12 files changed, 2327 insertions(+), 1469 deletions(-) create mode 100644 docs/qa/audit-2026-06-26/FINAL-REPORT.md create mode 100644 docs/qa/audit-2026-06-26/PROMISE-AUDIT.md diff --git a/docs/qa/audit-2026-06-26/FINAL-REPORT.md b/docs/qa/audit-2026-06-26/FINAL-REPORT.md new file mode 100644 index 0000000..95a1787 --- /dev/null +++ b/docs/qa/audit-2026-06-26/FINAL-REPORT.md @@ -0,0 +1,141 @@ +# Promise-Audit Final Report — 2026-06-26 + +**Companion to:** [`PROMISE-AUDIT.md`](./PROMISE-AUDIT.md) (full inventory). + +## TL;DR + +The audit found **32 distinct customer-facing promises** across marketing, docs, +and public UI. **22 of them did not survive contact with the code**. After +applying the user-approved fixes, the four highest-risk unsupported promises +are now removed from public copy and replaced with defensible language. The +remaining 10 medium/low-risk items are documented in PROPOSE section below +and need a separate decision. + +| Risk | Before | After | +|---|---|---| +| **HIGH** — fabricated landing stats | 4 fake stats + 4.9/12 JSON-LD rating | Removed; section hidden; rating block deleted | +| **HIGH** — fake named testimonials | Marcus / Sandra / James with numeric claims | Replaced with honest "Early access" copy + contact CTA | +| **HIGH** — pricing source-of-truth mismatch | `$1,341` vs `$1,522.80`; `$3,591` vs `$0` | Aligned to `pricing.ts`: Farm $1,341, Enterprise $3,591 | +| **HIGH** — security claims (SOC 2, 99.9% uptime, pentests, 2FA) | All four on the security page | Re-scoped to providers we actually use (Vercel, Neon, Stripe) | +| **LOW** — broken OG image references | `og-default.jpg` referenced, only `.svg` ships | All three pages now point to `.svg` | +| **LOW** — roadmap "Mobile App iOS & Android" misclassified | In Progress (no native code) | Left in place — only a PWA spec exists; **needs separate decision** | +| **LOW** — roadmap "SMS Campaigns" / "Route Optimization" already shipped | Listed as Planned | Reclassified as Shipped | +| **LOW** — `/roadmap/suggestion` form with no handler | Button goes nowhere | Replaced with `mailto:` link | + +## Files changed + +| File | What changed | +|---|---| +| `src/components/landing/HeroSection.tsx` | Replaced fabricated `HERO_STATS` and `STAT_COUNTERS` with empty arrays; `StatsSection` returns `null` while empty; HERO_STATS render guarded by `length > 0`. | +| `src/app/page.tsx` | Removed `aggregateRating` block from JSON-LD; changed Enterprise price spec to "Custom pricing" with no fixed `price`. | +| `src/lib/stripe-billing.ts` | Farm annual 152280 → 134100; Enterprise annual 0 → 359100. Both now 25% off, matching `pricing.ts`. | +| `src/app/pricing/PricingClientPage.tsx` | Emptied `TESTIMONIALS`; `Testimonials` component falls back to honest "Early access" copy + `/contact` CTA when array is empty. | +| `src/app/security/page.tsx` | Replaced `SECURITY_FEATURES` with provider-scoped versions; replaced `TRUST_BADGES` (no more SOC 2 / PCI badges); metadata description + keywords updated; "Supabase" provider card → "Neon Postgres". | +| `src/app/pricing/page.tsx`, `src/app/blog/page.tsx`, `src/app/contact/page.tsx` | OG image URLs changed `/og-default.jpg` → `/og-default.svg`. | +| `src/app/roadmap/page.tsx` | SMS Campaigns + Route Optimization moved from `planned` → `shipped`; `id="suggest"` section replaced with `mailto:hello@routecommerce.com` link. | +| `src/app/wholesale/login/page.tsx` | Error string "the wholesale portal is not yet wired up to it" → "Google sign-in failed. Please use email and password." | + +## Verification + +| Check | Result | +|---|---| +| `npx tsc --noEmit` | ✅ passes | +| `npm run lint` | ✅ no new errors in changed files (3 pre-existing errors in `wholesale/portal/page.tsx`, `water/admin/login/page.tsx` — out of scope) | +| `npm run build` | ✅ builds clean | +| `grep "500+\|98%\|50K+\|2M+" src/components/landing/HeroSection.tsx src/app/page.tsx` | ✅ only audit-comment references remain | +| `grep "Marcus T\|Sandra K\|James R" src/app/pricing/PricingClientPage.tsx` | ✅ only audit-comment reference remains | +| `grep "SOC 2\|99.9%\|quarterly penetration" src/app/security/page.tsx` | ✅ only audit-comment references remain | +| `grep "134100\|359100" src/lib/stripe-billing.ts` and `grep "1341\|3591" src/lib/pricing.ts` | ✅ aligned to 25% off | + +## Remaining unsupported / outdated promises (NOT touched — need decisions) + +These were in the audit and either out of scope for this pass or need a +human decision before changing: + +1. **Changelog v1.9.0 "Two-Factor Authentication"** — claim exists, code does + not. Two paths: implement Better Auth's `twoFactor` plugin, **or** delete + the v1.9.0 entry. **Recommend:** delete the entry; queue 2FA as a real + ticket. + +2. **README "Time Tracking" section** — actions are stubs + (`src/actions/time-tracking/field.ts:7`). README still documents + workers, tasks, PINs as if working. **Recommend:** replace README + section with "Time Tracking — coming back in v0.5" and link to a real + ticket. + +3. **`LAUNCH_CHECKLIST.md` "Referral Program ✓ Complete"** — + `src/app/api/referrals/route.ts` uses an in-memory `Map`. **Recommend:** + either remove the "✓ Complete" line from `LAUNCH_CHECKLIST.md`, or wire + the API to Postgres. + +4. **`LAUNCH_CHECKLIST.md` "OnboardingFlow.tsx", "TestimonialsAndCTA.tsx", + "FeaturesAndStats.tsx"** — components don't exist. **Recommend:** remove + the references; the launch checklist is now an internal doc and is + misleading. + +5. **Roadmap "Mobile App (iOS & Android)" — In Progress** — only a PWA spec + exists. **Recommend:** rename to "Admin mobile (PWA)" with link to + `docs/superpowers/plans/2026-06-17-admin-mobile-pwa.md`. + +6. **Roadmap "Multi-location Support" — In Progress** — no schema. **Recommend:** + move to Planned. + +7. **"On-Time Delivery 98%" / "500+ Farm Brands"** — already removed from + Hero. **Recommend:** when you ship the first production brand, capture + real metrics and re-add them via a `get_platform_stats` RPC (would need + to be created and gated). + +8. **Add-on tile "wholesale_portal: Contact us" vs pricing card `$99/mo`** — + mismatch between `feature-flags.ts:59` and `pricing.ts`. **Recommend:** + pick one narrative — either show prices in the add-on tile or move + wholesale portal to enterprise-only. + +9. **FAQ: "Every new account starts on the Starter plan" vs waitlist + "30 days free on any plan"** — these contradict each other and neither + is true. **Recommend:** consolidate into one onboarding FAQ once the + signup flow is real. + +10. **Changelog staleness** — last entry 2025-01-15; today 2026-06-26. Add + a "Recent" block at top with the most recent 3–5 releases. Needs an + editorial pass. + +## Decisions the user should still make + +- **Changelog v1.9.0** — implement 2FA or delete the entry? (Recommend: + delete + queue.) +- **README Time Tracking section** — mark coming-soon or rebuild the + schema? (Recommend: mark coming-soon; rebuild is multi-week.) +- **`LAUNCH_CHECKLIST.md`** — refresh or retire? (Recommend: refresh; it's + cited in QA runs.) +- **Roadmap Mobile App entry** — rename to "(PWA)" or remove until native + work starts? +- **Pricing assessment doc** (`docs/pricing-assessment.md`) — recommendations + there (2.5–3× lift, Starter $99, Farm $349, Enterprise Custom) are not + applied to the marketing copy yet. That's a separate business decision. + +## Proven promises (no action needed) + +The following were audited and held up. Listed for completeness: + +- Harvest Reach (templates, scheduling, analytics). +- Square Inventory Sync (bidirectional mode exists; cron wired in + `vercel.json`). +- Water Log module (`/admin/water-log`, `/water`). +- Wholesale Portal (`/wholesale/portal`). +- 8 AI endpoints (`/api/ai/*` — gated on `getAIClient(brandId)` returning a + client). +- Email automation crons (per `vercel.json`). +- Stripe-scoped PCI / 256-bit SSL / fraud detection / tokenization. +- Vercel-scoped edge DDoS / global CDN. +- Tuxedo brand FAQ (real numbers, real phone 970-323-6874). +- Indian River Direct testimonials (real customer quotes). +- `dev_session` cookie bypass (well-controlled; NODE_ENV guard at + `src/lib/auth.ts:55`). + +## Next step + +A copy of this report and the inventory are committed to +`docs/qa/audit-2026-06-26/`. The audit fixes are uncommitted on the working +tree — review with `git diff src/` before staging. The remaining 10 +unsupported / outdated items above are queued for a follow-up session; none +require code changes without sign-off. \ No newline at end of file diff --git a/docs/qa/audit-2026-06-26/PROMISE-AUDIT.md b/docs/qa/audit-2026-06-26/PROMISE-AUDIT.md new file mode 100644 index 0000000..7e5c679 --- /dev/null +++ b/docs/qa/audit-2026-06-26/PROMISE-AUDIT.md @@ -0,0 +1,337 @@ +# Customer-Facing Promise Audit — Route Commerce + +**Date:** 2026-06-26 +**Scope:** Every promise the product makes to customers across marketing, +documentation, public UI, and "AI answers" (admin copy that talks to the user +in product voice). Includes pricing, security, changelog, roadmap, landing +hero/stats, FAQ copy, product descriptions, and `LAUNCH_CHECKLIST.md`. + +**Method:** Walked every customer-touching surface in the repo. For each +distinct promise, captured (a) the exact copy, (b) the file/line, and +(c) the strongest evidence — code, schema, docs, or absence of evidence — +underneath. Then assigned one label per the user contract. + +**Labels used** + +| Label | Meaning | +|---|---| +| **PROVEN** | Code/schema/docs substantiate the claim today. | +| **PARTLY PROVEN** | Substantially true but with caveats; copy overstates one detail. | +| **MISLEADING** | The headline reads true but the fine print is materially wrong, or the framing suggests a stronger guarantee than reality. | +| **UNSUPPORTED** | No code, schema, audit, contract, or credential backs the claim. | +| **OUTDATED** | Was true at one point, no longer true. | +| **MISSING EVIDENCE** | Need a human or system to confirm before we can label. | + +--- + +## 1. Landing & marketing surfaces + +### 1.1 Landing hero stats — `src/components/landing/HeroSection.tsx:48` + +``` +{ stat: "500+", label: "Farm Brands" } +{ stat: "98%", label: "On-Time" } +{ stat: "50K+", label: "Deliveries" } +``` + +Plus `STAT_COUNTERS` (HeroSection.tsx:84): +``` +500 "Produce Brands" +50K "Orders Delivered" +98% "On-Time Delivery" +$2M+ "Weekly Sales" +``` + +**Evidence:** None. No customers in tree, no DB row count, no integration +that surfaces live numbers. The pricing-assessment doc (docs/pricing-assessment.md:79) +already flags this: *"Landing-page stats are aspirational, not real. The +working tree has no customers; this is a marketing claim that could trip up +B2B buyers doing due diligence. Either back it with real numbers or remove it."* + +**Label:** **UNSUPPORTED** (high-risk: B2B due-diligence exposure). +**Fix rank:** #1. + +### 1.2 Landing feature copy — HeroSection.tsx:53–98 + +| Promise | Evidence | Label | +|---|---|---| +| "Showcase seasonal produce with rich media galleries and **real-time availability** updates" | No realtime subscriptions on storefront. `supabase` is mentioned in `indian-river-direct/page.tsx` for brand lookup, but product availability is a fresh fetch. | **MISLEADING** | +| "Optimize delivery routes with **intelligent mapping** and real-time scheduling" | `src/app/api/ai/route-optimizer/route.ts` exists but is gated on admin user + AI provider key. No live routing on the storefront. | **PARTLY PROVEN** (admin-only) | +| "Track orders from placement through delivery with **automated status** updates" | No delivery tracking. Order status is admin-set. | **UNSUPPORTED** | +| "Give buyers a dedicated space to browse pricing and place bulk orders" | Wholesale portal exists. | **PROVEN** | +| "Send email and SMS campaigns about seasonal availability and new harvests" | Harvest Reach exists for admin. | **PROVEN** (admin surface) | +| "Uncover sales trends and operational insights with **real-time dashboards**" | Reports dashboard exists; not realtime. | **PARTLY PROVEN** | + +### 1.3 Pricing page — `src/app/pricing/PricingClientPage.tsx` + +| Promise | Evidence | Label | +|---|---|---| +| AggregateRating in JSON-LD `4.9 / 12 reviews` (`src/app/page.tsx:55`) | Inline comment: `// Placeholder — replace with real review data once collected.` | **UNSUPPORTED** (fabricated rating published as structured data; Google could surface it). | +| "Marcus T., Fresh Fields Farm" / "Sandra K., Pacific Produce Co-op" / "James R., Gulf Coast Distribution" testimonials (PricingClientPage.tsx:54–58) | No source. Names are made up. | **MISLEADING** (named-person testimonials with no consent) | +| "Harvest Reach alone paid for the subscription. Our pickup rate went from 70% to 94% in two months." | No source. | **UNSUPPORTED** (specific metric, no customer) | +| "Every new account starts on the Starter plan. … No credit card required to start." (FAQ line 24) | Waitlist page (line 103) contradicts: *"Early access members get 30 days free on any plan."* No self-serve signup exists; brands are seeded by `scripts/provision-admin.ts`. | **MISLEADING** (conflicting free-trial claims) | +| "Enterprise customers can pay by invoice" (FAQ line 32) | `pricing.ts` prices Enterprise at $399/mo; `stripe-billing.ts` has annual=0 (Custom); the FAQ says invoice. None of these match the public pricing card. | **MISLEADING** (internal pricing model is inconsistent with public copy) | +| "Add-ons are available on any plan. … billed proportionally when added mid-cycle." | No proportional-billing code path in `src/actions/billing/`. Stripe proration is on but the proportional UI copy implies a feature we haven't built. | **PARTLY PROVEN** | +| Save 25% with annual (line 160) | `pricing.ts` shows: Starter annual 441 = 49×12×0.75 ✓; Farm 1341 = 149×12×0.75 ✓; Enterprise 3591 = 399×12×0.75 ✓. But `stripe-billing.ts:34` shows Farm annual = $1,522.80 (15% off). **Two sources of truth disagree.** | **MISLEADING** (internal inconsistency; one of the two is wrong) | +| "Dedicated SLA" (Enterprise feature) | No SLA document, no `sla_*` table or RPC, no uptime monitoring integration. | **UNSUPPORTED** | +| "Priority support" (Farm) | No support tier system, no SLA, no escalation path. | **UNSUPPORTED** | +| Compare table "AI Intelligence Pack" Enterprise-only | Roadmap / pricing says Farm has Harvest Reach but not AI. Pricing page mirrors that. | **PROVEN** (consistent) | +| Compare table "Multi-location Support" — *not actually in the table* (referenced on roadmap only) | n/a | n/a | + +### 1.4 Pricing JSON-LD — `src/app/page.tsx` + +``` +offers: { lowPrice: 49, highPrice: 399, ... } +priceSpecification: [ {Starter 49}, {Farm 149}, {Enterprise 399} ] +``` + +**CLAUDE.md (the canonical reference) says Enterprise is "Custom" pricing.** +**Label:** **MISLEADING**. The structured-data layer is publishing a price +that the platform says is custom. This is the kind of thing that surfaces +in Google search snippets and creates procurement friction. + +### 1.5 Waitlist — `src/app/waitlist/page.tsx` + +| Promise | Evidence | Label | +|---|---|---| +| "Join **500+** farms on the waitlist" / "**12+** States Covered" / "Q2 Launch Target" | Hard-coded copy. No waitlist row count. | **UNSUPPORTED** (three different numbers, all made up) | +| "I've been waiting for a platform like this. The wholesale portal alone will save us hours every week." — Maria S., Sunny Acres Farm | No source. | **UNSUPPORTED** | +| "Yes! Early access members get **30 days free on any plan**." | No billing code grants this. | **UNSUPPORTED** | +| "Full access to all features including products, orders, stops management, and communications." | Waitlist → /api/waitlist writes a row. Does NOT auto-create a tenant. | **MISLEADING** | + +### 1.6 Indian River Direct landing — `src/app/indian-river-direct/page.tsx` + +``` +TESTIMONIALS = [ + { name: "Linda Hurlbut", text: "I finally got my grapefruit from you today..." }, + { name: "Phil Myers", text: "I just wanted to comment on the citrus I received..." }, + { name: "Bill Prue", text: "I would just like to say how pleased we are..." } +] +``` + +**Evidence:** These are real customer quotes from the brand owner's email +archive (different file than the pricing page). **Label:** **PROVEN** for +IRD-specific surface; isolated risk. + +--- + +## 2. Pricing & billing internal consistency + +### 2.1 Two pricing sources of truth + +`src/lib/pricing.ts` (marketing UI): +``` +Farm annual = $1,341 (25% off) +Enterprise annual = $3,591 (25% off) +``` + +`src/lib/stripe-billing.ts` (Stripe checkout logic): +``` +Farm annual = $1,522.80 (15% off) ← src/lib/stripe-billing.ts:67 +Enterprise annual = $0 (Custom) ← src/lib/stripe-billing.ts:82 +``` + +**Label:** **MISLEADING** — the marketing UI cannot be trusted to match +what the checkout will charge. +**Fix rank:** #2 (after landing stats, since this can cost real money). + +### 2.2 Feature flags display + +`src/lib/feature-flags.ts:59` shows `wholesale_portal: "Contact us"` and +`ai_tools: "OpenAI API required"`, but `pricing.ts` prices them at $99 and $59. + +**Label:** **MISLEADING** (the add-on tile says "Contact us" while the +pricing card says "$99/mo"). Same item, two prices. + +### 2.3 Add-on Stripe env-var mismatch + +`src/actions/billing/stripe-checkout.ts:19` reads `STRIPE_PRICE_WATER_LOG`. +`pricing.ts` and `stripe-billing.ts` agree on price. **But** +`stripe-billing.ts:154` also defines `_annual` price IDs that are never used. + +**Label:** **PARTLY PROVEN** (works for monthly, but annual is +not actually wired in any Stripe price env var the docs mention). +**Fix rank:** lower. + +--- + +## 3. Security page — `src/app/security/page.tsx` + +| Promise | Evidence | Label | +|---|---|---| +| "**SOC 2 Compliant** — Our infrastructure meets SOC 2 Type II standards for security, availability, and confidentiality." | No SOC 2 report, no auditor name, no compliance-trust URL. | **UNSUPPORTED** (high-risk; this is a regulatory/compliance claim). | +| "We conduct **quarterly penetration tests** and annual security audits with certified third parties." | No pentest repo, no audit report, no scheduled task. | **UNSUPPORTED** | +| "**99.9% Uptime SLA** — Enterprise plan customers receive a 99.9% uptime guarantee with 24/7 monitoring." | No SLA doc, no `sla_*` table, no monitoring integration beyond Vercel's defaults. | **UNSUPPORTED** | +| "**GDPR & CCPA Compliant**" | `src/app/privacy-policy/page.tsx` exists but does not include DPA, SCCs, or data-residency clauses. | **PARTLY PROVEN** (privacy page exists; compliance posture unverified) | +| "Supabase Auth provides secure, compliant authentication with 2FA support." (line 69) | Auth was migrated to **Neon Auth** (`src/lib/auth.ts`), and 2FA is **not enabled** in the Better Auth config. | **OUTDATED + UNSUPPORTED** (both — wrong product AND no 2FA) | +| "SSL Secured" / "SOC 2 Compliant" / "GDPR Ready" / "PCI Compliant" trust badges (line 47) | Same SOC 2 / PCI issue. | **UNSUPPORTED** | +| "Stripe — PCI-compliant payment processing" (line 178) | Stripe IS PCI DSS Level 1; we inherit it. **PROVEN** for Stripe's posture. | **PROVEN** (when scoped to Stripe's posture, not our own) | +| "Vercel — Edge network with automatic DDoS protection and global CDN" (line 168) | Vercel does provide this. | **PROVEN** (when scoped to Vercel's posture) | +| "Supabase — PostgreSQL database with built-in encryption and real-time capabilities" (line 173) | DB is now **Neon Postgres direct via `pg`**, not Supabase. | **OUTDATED** | +| "256-bit SSL encryption" / "PCI DSS Level 1 compliant" / "Advanced fraud detection" / "Secure card tokenization" | All Stripe attributes, true when scoped to Stripe. | **PROVEN** (Stripe-scoped) | +| `mailto:security@routecommerce.com` for vulnerability reports | Inbox unverifiable from repo. | **MISSING EVIDENCE** (need to confirm mailbox monitored) | + +--- + +## 4. Changelog — `src/app/changelog/page.tsx` + +| Version | Promise | Evidence | Label | +|---|---|---|---| +| 2.4.0 (2025-01-15) "Harvest Reach Email Campaigns — …templates, scheduling, and analytics" | Templates, scheduling, analytics all in code. | **PROVEN** | +| 2.3.0 "Square Inventory Sync" | Settings UI + `square_to_rc` / `rc_to_square` / `bidirectional` modes in `SquareSyncSettingsClient.tsx:443`. | **PROVEN** (UI exists; cron at `/api/square/process-queue` is wired in `vercel.json`). | +| 2.2.2 "Dashboard now loads 40% faster" | No benchmark in tree. | **UNSUPPORTED** (specific perf claim with no measurement) | +| 2.2.1 "Order Export Fix" | Generic bug-fix entry. | **MISSING EVIDENCE** (cannot verify without git blame) | +| 2.2.0 "**AI Intelligence Pack** — Campaign Writer, Pricing Advisor, Demand Forecasting. Available on Enterprise plan." | All 8 AI endpoints exist (`/api/ai/*`); all gated on `getAIClient(brandId)` returning a client. Requires brand to have an AI provider key configured. | **PARTLY PROVEN** (works only when brand has configured an API key — defaults to OpenAI which is BYO key, not "included in Enterprise") | +| 2.1.0 "Water Log Module" | Module exists at `/admin/water-log` and `/water`; schema documented in `docs/water-log.md`. | **PROVEN** | +| 2.0.0 "New Admin Dashboard" | v2 routes under `/admin/v2/*`. | **PROVEN** | +| 1.9.0 (2024-10-30) "Two-Factor Authentication" | **No TOTP/2FA in `src/lib/auth.ts` or `src/auth.config.ts`.** Better Auth supports a `twoFactor` plugin but it is not registered. | **UNSUPPORTED** (high-risk; this is the headline 1.9.0 feature and it doesn't exist) | + +**Changelog metadata issue:** the changelog's most-recent entry is dated +2025-01-15. We're in June 2026. **Label:** **OUTDATED** as a whole +(this page silently went stale). + +--- + +## 5. Roadmap — `src/app/roadmap/page.tsx` + +### 5.1 "Shipped" column (page.tsx:35) + +| Item | Promise | Evidence | Label | +|---|---|---|---| +| Harvest Reach Email Campaigns | Code lives under `/admin/communications`. | **PROVEN** | +| Square Inventory Sync | Code + queue cron. | **PROVEN** | +| AI Intelligence Pack | 8 endpoints, brand-gated. | **PROVEN** (with the same caveat as 2.2.0 above) | +| Water Log Module | Module lives at `/admin/water-log`. | **PROVEN** | + +### 5.2 "In Progress" (page.tsx:43) + +| Item | Promise | Evidence | Label | +|---|---|---|---| +| Mobile App (iOS & Android) | No `ios/`, `android/`, or React Native config. The "admin mobile PWA" spec (`docs/superpowers/plans/2026-06-17-admin-mobile-pwa.md`) is a PWA plan, **not a native app**. | **UNSUPPORTED** (a public claim of a native mobile app; reality is a PWA spec). | +| Advanced Reporting & Analytics | Reports page exists; advanced exports not all wired. | **PARTLY PROVEN** | +| Multi-location Support | No schema for `locations` table; `brands` has no `location_id`. | **UNSUPPORTED** | + +### 5.3 "Planned" (page.tsx:51) + +| Item | Evidence | Label | +|---|---|---| +| SMS Campaigns | Module already implemented at `/api/ai/stop-blast-advisor` and gated by `sms_campaigns` add-on. | **OUTDATED** (should be "Shipped", not "Planned") | +| Route Optimization | Endpoint at `/api/ai/route-optimizer` exists. | **OUTDATED** (should be "Shipped") | +| POS Integration (Clover, Toast) | No Clover/Toast integration in tree. | **PROVEN** (still planned) | +| Customer Loyalty Program | No code. | **PROVEN** (still planned) | + +### 5.4 Roadmap affordances that don't work + +`docs/qa/audit-2026-06-25/ACCEPTANCE-CRITERIA.md:668` already flagged: +`/roadmap/suggestion` form and upvotes have no handlers. + +**Label:** **MISLEADING** (the page implies a working vote/suggest system). + +--- + +## 6. Public docs (`README.md`, `LAUNCH_CHECKLIST.md`, `docs/`) + +### 6.1 README.md + +| Promise | Evidence | Label | +|---|---|---| +| "Time Tracking" with PINs, Workers, Tasks (lines "Adding Workers / Adding Tasks / Notification Alerts") | `src/actions/time-tracking/field.ts:7` is **stub code** that returns `{ success: false, error: "Time tracking is not configured" }`. The TODO comment (line 7) explicitly says: *"the time-tracking feature was built on Supabase RPCs … that don't exist in the SaaS rebuild schema. The functions below are stubs … the field UI degrades gracefully (no PIN login, no entry submit)."* | **UNSUPPORTED** (high-risk; README documents a feature that does not work) | +| "**Supabase** (Postgres + Auth + RLS)" (Tech Stack) | README still says Supabase; CLAUDE.md says we're on direct Postgres + Neon Auth. | **OUTDATED** | +| `npm run migrate` / `supabase link --project-ref` | `supabase/push-migrations.js` exists but CLAUDE.md says only the direct `pg` path is used; Supabase CLI branch is legacy. | **OUTDATED** | +| `dev_session` cookie bypass — described as dev-only | CLAUDE.md reinforces this. Code guard at `src/lib/auth.ts:55` returns early in production unless `PERF_TEST_AUTH=1`. | **PROVEN** (well-controlled) | +| Email automation cron endpoints (`/api/email-automation/abandoned-cart`, `/api/email-automation/welcome-sequence`) | Endpoints + Vercel cron config in `vercel.json`. | **PROVEN** | + +### 6.2 `LAUNCH_CHECKLIST.md` + +| Claim | Evidence | Label | +|---|---|---| +| "**Social Proof** ✓ Complete — FeaturesAndStats.tsx" | `FeaturesAndStats.tsx` does not exist in `src/components/landing/`. | **OUTDATED** | +| "**Testimonials** ✓ Complete — TestimonialsAndCTA.tsx" | `TestimonialsAndCTA.tsx` does not exist. | **OUTDATED** | +| "**Guided Product Tour** ✓ Complete — OnboardingFlow.tsx" | `OnboardingFlow.tsx` does not exist. | **OUTDATED** | +| "**Referral Program** ✓ Complete — src/app/api/referrals/route.ts, ReferralSystem.tsx" | `src/app/api/referrals/route.ts` uses **in-memory `Map`** that does not persist across serverless invocations. `ReferralSystem.tsx` does not exist. | **OUTDATED + UNSUPPORTED** | +| "**Email Capture** ✓ Complete — Newsletter form in blog page" | `src/app/blog/page.tsx` does not have a working newsletter form (static post list). | **OUTDATED** | + +### 6.3 `docs/ADMIN_FUNCTIONALITY_CHECKLIST.md` + +Lists time-tracking admin features as testable. Combined with the stub +status above, this is **OUTDATED + UNSUPPORTED**. + +--- + +## 7. Public storefront / AI answers in product voice + +### 7.1 Wholesale portal login — `src/app/wholesale/login/page.tsx:156` + +> "Google sign-in is available, but the wholesale portal is not yet wired up to it. Please use email + password for now." + +**Label:** **PARTLY PROVEN** (honest about the limitation, but a customer-facing string saying "not yet wired up" is itself a smell — production copy should not contain TODO-like caveats). + +### 7.2 Brand-specific FAQs — `src/app/tuxedo/faq/FAQClientPage.tsx` + +Mostly verifiable (corn minimum 4 dozen, real phone number 970-323-6874). +**Label:** **PROVEN** for Tuxedo-specific FAQ. + +### 7.3 `CLAUDE.md` "AI answers" surfaced in admin copy + +The product has 8 AI endpoints (`/api/ai/{campaign-writer, customer-insights, +demand-forecast, pricing-advisor, product-writer, report-explainer, +route-optimizer, stop-blast-advisor}`). Each returns a typed response. The +admin UI at `/admin/settings/ai` describes them in product voice: + +> "Configure AI providers, keys, and preferences used by **campaign writer, +> pricing advisor, report explainer**, and other tools." + +**Evidence:** All endpoints exist, but they require: +1. Brand has `get_ai_provider_settings` row (BYO API key). +2. The configured provider must be reachable from the server. +3. The `minimax` provider is hard-coded into `AIProviderPanel.tsx` with model names like `MiniMax-M3`, `MiniMax-M2.7`, `MiniMax-M2.1` — these are **not real public model IDs** and look like leftover copy from a model-bake-off. + +**Label for "AI Intelligence Pack" as advertised on pricing page:** +**PARTLY PROVEN** (works with config; "Available on Enterprise plan" copy +implies it's bundled, but the feature requires BYO OpenAI/Anthropic key — +the add-on has no included inference credits). + +**Label for `minimax` provider card:** **UNSUPPORTED** (placeholder model +names published to admin UI). + +--- + +## 8. Risk-ranked list of fixes the user must approve + +Top items, ranked by legal/customer-trust exposure × likelihood a real +buyer will notice. **Production copy changes require sign-off** per the +user contract. + +| Rank | Fix | Surface | Risk if unchanged | Effort | +|---|---|---|---|---| +| 1 | Replace fabricated landing stats ("500+ Farm Brands / 98% On-Time / 50K+ Deliveries / $2M+ Weekly Sales") with neutral copy OR real numbers once available. Remove from JSON-LD `aggregateRating` placeholder. | `src/components/landing/HeroSection.tsx`, `src/app/page.tsx` | **HIGH** — B2B procurement teams check public stats. | XS | +| 2 | Pick one pricing source of truth. Reconcile `src/lib/pricing.ts` and `src/lib/stripe-billing.ts`. Update FAQ "Enterprise customers can pay by invoice" if pricing stays Custom. | `src/lib/pricing.ts`, `src/lib/stripe-billing.ts`, FAQ copy | **HIGH** — checkout may charge a different price than the marketing card. | S | +| 3 | Remove "Two-Factor Authentication" from `Changelog v1.9.0` and the security page feature list, or implement TOTP via Better Auth's `twoFactor` plugin and verify it works. | `src/app/changelog/page.tsx`, `src/app/security/page.tsx` | **HIGH** — customers rely on advertised features; missing 2FA after promised = trust loss. | M | +| 4 | Strip SOC 2 / 99.9% uptime / quarterly pentest claims from `security/page.tsx`, or replace with neutral, scoped language ("Vercel provides edge DDoS protection; Stripe is PCI DSS Level 1"). | `src/app/security/page.tsx` | **HIGH** — regulatory/compliance exposure. | S | +| 5 | Remove or label-as-example the three fabricated testimonials on pricing page (Marcus / Sandra / James). Keep the IRD ones (real quotes). | `src/app/pricing/PricingClientPage.tsx` | **HIGH** — fake named-person testimonials can violate FTC guidelines. | XS | +| 6 | Reconcile Enterprise pricing: structured-data JSON-LD `$399`, marketing card `$399`, CLAUDE.md "Custom". Pick one. | `src/app/page.tsx`, `src/app/pricing/PricingClientPage.tsx`, FAQ copy | **MEDIUM** — Google snippets, sales-call confusion. | S | +| 7 | Remove or implement `dev_session`/`dev_login` claims that promise features not built (e.g., "Not yet wired up to Google" line in wholesale login). | `src/app/wholesale/login/page.tsx` | **MEDIUM** — production copy with TODO language. | XS | +| 8 | Replace `MiniMax-M3` etc. in `AIProviderPanel.tsx` with the real `minimax` model catalog or remove the provider until shipped. | `src/components/admin/AIProviderPanel.tsx` | **MEDIUM** — admin sets a non-existent model; calls will 404. | XS | +| 9 | Mark Time Tracking as "coming soon" in README + checklist, or rebuild the schema. | `README.md`, `docs/ADMIN_FUNCTIONALITY_CHECKLIST.md`, `src/actions/time-tracking/field.ts` | **MEDIUM** — docs promise a feature whose actions are stubs. | L | +| 10 | Refresh changelog & roadmap dates (most recent changelog entry is 2025-01-15; today is 2026-06-26). Reclassify SMS Campaigns and Route Optimization as Shipped. | `src/app/changelog/page.tsx`, `src/app/roadmap/page.tsx` | **LOW** — perception of staleness. | S | +| 11 | Wire the `/api/referrals` in-memory `Map` to Postgres OR remove the "Referral Program ✓ Complete" claim from `LAUNCH_CHECKLIST.md`. | `src/app/api/referrals/route.ts`, `LAUNCH_CHECKLIST.md` | **LOW** — feature currently advertised but non-functional. | M | +| 12 | OG image: `/og-default.jpg` referenced by pricing/blog/contact but only `/og-default.svg` exists in `public/`. | `src/app/{pricing,blog,contact}/page.tsx`, `public/` | **LOW** — broken preview cards in social shares. | XS | +| 13 | Replace Supabase-era auth claim ("Supabase Auth provides 2FA") and DB claim ("Supabase Postgres") on security page. | `src/app/security/page.tsx` | **LOW–MEDIUM** — outdated reference, but page is informational. | XS | +| 14 | Resolve `/roadmap/suggestion` form & upvotes (no handlers) — either disable or wire up. | `src/app/roadmap/page.tsx` | **LOW** — UI affordance leads nowhere. | S | + +--- + +## 9. Decisions needed from the user + +1. **Replace or keep** the landing hero stats? If keep, commit to a data source. +2. **Choose pricing source of truth** — `pricing.ts` (25% annual) or `stripe-billing.ts` (15% annual, Enterprise=Custom). Recommend: align on `pricing.ts` for marketing parity, set `stripe-billing.ts` annual prices accordingly, and decide Enterprise = Custom (no card on site). +3. **Implement 2FA now** via Better Auth's `twoFactor` plugin, **or remove** from changelog + security page. Recommend: remove from copy; queue 2FA as a real ticket. +4. **Strip SOC 2 / uptime / pentest claims** from security page **or** scope them to providers (Vercel, Stripe). Recommend: scope to providers; queue real compliance work. +5. **Strip fabricated named testimonials** from pricing page. Recommend: yes, replace with either no testimonials or real ones once collected. +6. **Time Tracking**: docs claim it works, actions are stubs. Recommend: mark "coming soon" in README/checklist, file a real ticket to bring back the schema. +7. **Roadmap & changelog**: reclassify SMS Campaigns and Route Optimization as Shipped; refresh dates. +8. **OG image fix**: rename `og-default.svg` to `og-default.jpg`, or generate a JPG. Recommend: rename references in metadata to `/og-default.svg`. +9. **Permission to apply any subset of the above** in this session? If yes, which? + +(Defaults below assume "yes, apply the safe ones; ask on anything that +touches an invoice number.") \ No newline at end of file diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx index 5ac8400..31e6688 100644 --- a/src/app/blog/page.tsx +++ b/src/app/blog/page.tsx @@ -19,7 +19,8 @@ export const metadata: Metadata = { type: "website", images: [ { - url: "/og-default.jpg", + // Audit 2026-06-26: only og-default.svg exists in /public. + url: "/og-default.svg", width: 1200, height: 630, alt: "Route Commerce Blog", diff --git a/src/app/contact/page.tsx b/src/app/contact/page.tsx index 34b6ada..f0ebfad 100644 --- a/src/app/contact/page.tsx +++ b/src/app/contact/page.tsx @@ -19,7 +19,8 @@ export const metadata: Metadata = { type: "website", images: [ { - url: "/og-default.jpg", + // Audit 2026-06-26: only og-default.svg exists in /public. + url: "/og-default.svg", width: 1200, height: 630, alt: "Contact Route Commerce", @@ -32,7 +33,7 @@ export const metadata: Metadata = { description: "Get in touch with Route Commerce.", site: "@RouteCommerce", creator: "@RouteCommerce", - images: ["/og-default.jpg"], + images: ["/og-default.svg"], }, alternates: { canonical: `${BASE_URL}/contact`, diff --git a/src/app/page.tsx b/src/app/page.tsx index 61296c1..0847383 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -40,15 +40,12 @@ const structuredData = { priceSpecification: [ { "@type": "UnitPriceSpecification", name: "Starter", price: 49, priceCurrency: "USD", description: "$49/month" }, { "@type": "UnitPriceSpecification", name: "Farm", price: 149, priceCurrency: "USD", description: "$149/month" }, - { "@type": "UnitPriceSpecification", name: "Enterprise", price: 399, priceCurrency: "USD", description: "Custom pricing" }, + // Enterprise pricing is custom — see CLAUDE.md / pricing.ts. No fixed price published. + { "@type": "UnitPriceSpecification", name: "Enterprise", priceCurrency: "USD", description: "Custom pricing" }, ], }, - aggregateRating: { - "@type": "AggregateRating", - // Placeholder — replace with real review data once collected. - ratingValue: 4.9, - reviewCount: 12, - }, + // Audit 2026-06-26: removed placeholder aggregateRating (4.9/12). + // Re-add only when there is real, attributed review data. }, { "@type": "WebSite", diff --git a/src/app/pricing/PricingClientPage.tsx b/src/app/pricing/PricingClientPage.tsx index 461bed4..212b24d 100644 --- a/src/app/pricing/PricingClientPage.tsx +++ b/src/app/pricing/PricingClientPage.tsx @@ -50,6 +50,40 @@ const FAQ_ITEMS = [ }, ]; +// Audit 2026-06-26: previously had three fabricated named testimonials +// (Marcus T., Sandra K., James R.) with specific numeric claims. Replaced +// with an honest line until real, attributed customer quotes are collected. +const TESTIMONIALS: Array<{ quote: string; name: string; location: string }> = []; + +type CompareTier = "starter" | "farm" | "enterprise"; + +type CompareRow = { + feature: string; + starter: boolean | string; + farm: boolean | string; + enterprise: boolean | string; +}; + +const COMPARE_ROWS: CompareRow[] = [ + { feature: "Products catalog", starter: true, farm: true, enterprise: true }, + { feature: "Stop / route management", starter: "10/mo", farm: "Unlimited", enterprise: "Unlimited" }, + { feature: "Orders processing", starter: true, farm: true, enterprise: true }, + { feature: "Pickup & fulfillment", starter: true, farm: true, enterprise: true }, + { feature: "Admin users", starter: "1", farm: "5", enterprise: "Unlimited" }, + { feature: "Products limit", starter: "25", farm: "Unlimited", enterprise: "Unlimited" }, + { feature: "Reporting", starter: "Standard", farm: "Advanced", enterprise: "Advanced + AI" }, + { feature: "Email support", starter: true, farm: true, enterprise: "Dedicated" }, + { feature: "Wholesale Portal", starter: false, farm: true, enterprise: true }, + { feature: "Harvest Reach (Email & SMS)", starter: false, farm: true, enterprise: true }, + { feature: "AI Intelligence Pack", starter: false, farm: false, enterprise: true }, + { feature: "SMS Campaigns", starter: false, farm: false, enterprise: true }, + { feature: "Square Inventory Sync", starter: false, farm: false, enterprise: true }, + { feature: "Water Log", starter: false, farm: false, enterprise: true }, + { feature: "Unlimited brands", starter: false, farm: false, enterprise: true }, + { feature: "Custom development", starter: false, farm: false, enterprise: true }, + { feature: "SLA guarantee", starter: false, farm: false, enterprise: true }, +]; + export default function PricingClientPage() { const [billingCycle, setBillingCycle] = useState("annual"); const [compareOpen, setCompareOpen] = useState(false); @@ -61,336 +95,490 @@ export default function PricingClientPage() { return (
- {/* ── Nav bar ─────────────────────────────────────────────────────────── */} -
-
-
- - Route Commerce -
- -
-
- - {/* ── Hero ────────────────────────────────────────────────────────────── */} -
-
-
- - Built for produce wholesale operations -
-

- Pricing that scales
with your operation -

-

- From small farms to enterprise distributors — everything you need to manage orders, stops, communications, and billing in one platform. -

-
- - Save 25% with annual -
-
-
- - {/* ── Plan cards ───────────────────────────────────────────────────────── */} -
-

Available Plans

-
- {(Object.entries(PLAN_TIERS) as [keyof typeof PLAN_TIERS, typeof PLAN_TIERS[keyof typeof PLAN_TIERS]][]).map(([key, plan]) => { - const price = billingCycle === "annual" ? plan.annualPrice : plan.monthlyPrice; - const monthlyEquivalent = billingCycle === "annual" && plan.annualPrice ? Math.round(plan.annualPrice / 12) : null; - const isMostPopular = plan.highlighted; - - return ( -
- {isMostPopular && ( -
- Most Popular -
- )} -
-

{plan.label}

-

{plan.description}

-
-
- ${price} - /{billingCycle === "annual" ? "yr" : "mo"} -
- {monthlyEquivalent !== null && ( -

${monthlyEquivalent}/mo equivalent

- )} - - {key === "enterprise" ? "Contact Sales" : "Get Started"} - -
    - {(plan.features as readonly string[]).map((f) => ( -
  • - - {f} -
  • - ))} -
-
- ); - })} -
- -
- -
- - {/* Compare table */} - {compareOpen && ( -
-
-

Full Feature Comparison

- -
-
- - - - - {(["starter", "farm", "enterprise"] as const).map((tier) => { - const p = PLAN_TIERS[tier]; - return ( - - ); - })} - - - - {[ - ["Products catalog", { starter: true, farm: true, enterprise: true }], - ["Stop / route management", { starter: "10/mo", farm: "Unlimited", enterprise: "Unlimited" }], - ["Orders processing", { starter: true, farm: true, enterprise: true }], - ["Pickup & fulfillment", { starter: true, farm: true, enterprise: true }], - ["Admin users", { starter: "1", farm: "5", enterprise: "Unlimited" }], - ["Products limit", { starter: "25", farm: "Unlimited", enterprise: "Unlimited" }], - ["Reporting", { starter: "Standard", farm: "Advanced", enterprise: "Advanced + AI" }], - ["Email support", { starter: true, farm: true, enterprise: "Dedicated" }], - ["Wholesale Portal", { starter: false, farm: true, enterprise: true }], - ["Harvest Reach (Email & SMS)", { starter: false, farm: true, enterprise: true }], - ["AI Intelligence Pack", { starter: false, farm: false, enterprise: true }], - ["SMS Campaigns", { starter: false, farm: false, enterprise: true }], - ["Square Inventory Sync", { starter: false, farm: false, enterprise: true }], - ["Water Log", { starter: false, farm: false, enterprise: true }], - ["Unlimited brands", { starter: false, farm: false, enterprise: true }], - ["Custom development", { starter: false, farm: false, enterprise: true }], - ["SLA guarantee", { starter: false, farm: false, enterprise: true }], - ].map(([feature, tiers], rowIndex) => { - const t = tiers as Record; - return ( - - - {(["starter", "farm", "enterprise"] as const).map((tier) => { - const val = t[tier]; - return ( - - ); - })} - - ); - })} - -
Feature - {p.label} -
{feature as string} - {val === true ? ( - - - - ) : val === false ? ( - - ) : ( - {val} - )} -
-
-
- )} -
- - {/* ── Add-ons ───────────────────────────────────────────────────────────── */} -
-
-

Power-Up with Add-ons

-

Add capabilities à la carte on any plan. No bundles required.

-
- {ADDON_LIST.map(({ key, label, icon, description }) => { - const addon = ADDONS[key as keyof typeof ADDONS]; - if (!addon) return null; - const price = billingCycle === "annual" ? addon.annualPrice : addon.monthlyPrice; - const monthlyEquiv = billingCycle === "annual" ? Math.round(addon.annualPrice / 12) : null; - return ( -
- -
-

{label}

-

{description}

-
- ${price} - /{billingCycle === "annual" ? "yr" : "mo"} - {monthlyEquiv !== null && ( - (${monthlyEquiv}/mo equiv.) - )} -
-
-
- ); - })} -
-
-
- - {/* ── Social proof ─────────────────────────────────────────────────────── */} -
-
-

Trusted by produce operations across the US

-
- {[ - { quote: "We went from managing 12 spreadsheets to one platform. Route Commerce cut our order chaos by 80%.", name: "Marcus T., Fresh Fields Farm", location: "California" }, - { quote: "Harvest Reach alone paid for the subscription. Our pickup rate went from 70% to 94% in two months.", name: "Sandra K., Pacific Produce Co-op", location: "Oregon" }, - { quote: "The wholesale portal saved us 6 hours a week on order entry. Buyers love the self-service.", name: "James R., Gulf Coast Distribution", location: "Florida" }, - ].map((item, i) => ( -
-
- {["★", "★", "★", "★", "★"].map((s, j) => ( - - ))} -
-
-

“{item.quote}”

-
-

{item.name}

-

{item.location}

-
- ))} -
-
-
- - {/* ── FAQ ─────────────────────────────────────────────────────────────── */} -
-
-

Frequently Asked Questions

-
- {FAQ_ITEMS.map((item, i) => ( -
- - {openFaq === i && ( -
-

{item.a}

-
- )} -
- ))} -
-
-
- - {/* ── CTA ──────────────────────────────────────────────────────────────── */} -
-
-

Ready to grow your operation?

-

Start free on Starter. No credit card required. Upgrade when you're ready.

-
- - Start for Free → - - - Talk to Us - -
-

- Invoiced by Cielo Hermosa, LLC · billing@routecommerce.com -

-
-
- - {/* ── Footer ──────────────────────────────────────────────────────────── */} -
-
-
- - Route Commerce -
- -
-
+ + + setCompareOpen((v) => !v)} + onCloseCompare={() => setCompareOpen(false)} + /> + + + + +
); } +function NavBar() { + return ( +
+
+
+ + Route Commerce +
+ +
+
+ ); +} + +function Hero({ billingCycle, onCycleChange }: { billingCycle: BillingCycle; onCycleChange: (c: BillingCycle) => void }) { + return ( +
+
+
+ + Built for produce wholesale operations +
+

+ Pricing that scales
with your operation +

+

+ From small farms to enterprise distributors — everything you need to manage orders, stops, communications, and billing in one platform. +

+
+ + Save 25% with annual +
+
+
+ ); +} + +function PlansSection({ + billingCycle, + compareOpen, + onToggleCompare, + onCloseCompare, +}: { + billingCycle: BillingCycle; + compareOpen: boolean; + onToggleCompare: () => void; + onCloseCompare: () => void; +}) { + return ( +
+

Available Plans

+
+ {(Object.entries(PLAN_TIERS) as [keyof typeof PLAN_TIERS, typeof PLAN_TIERS[keyof typeof PLAN_TIERS]][]).map(([key, plan]) => ( + + ))} +
+ +
+ +
+ + {compareOpen && } +
+ ); +} + +function PlanCard({ + planKey, + plan, + billingCycle, +}: { + planKey: keyof typeof PLAN_TIERS; + plan: typeof PLAN_TIERS[keyof typeof PLAN_TIERS]; + billingCycle: BillingCycle; +}) { + const price = billingCycle === "annual" ? plan.annualPrice : plan.monthlyPrice; + const monthlyEquivalent = billingCycle === "annual" && plan.annualPrice ? Math.round(plan.annualPrice / 12) : null; + const isMostPopular = plan.highlighted; + const isEnterprise = planKey === "enterprise"; + + return ( +
+ {isMostPopular && ( +
+ Most Popular +
+ )} +
+

{plan.label}

+

{plan.description}

+
+
+ ${price} + /{billingCycle === "annual" ? "yr" : "mo"} +
+ {monthlyEquivalent !== null && ( +

${monthlyEquivalent}/mo equivalent

+ )} + + {isEnterprise ? "Contact Sales" : "Get Started"} + +
    + {(plan.features as readonly string[]).map((f) => ( + + ))} +
+
+ ); +} + +function PlanFeature({ feature }: { feature: string }) { + return ( +
  • + + {feature} +
  • + ); +} + +function CompareTable({ onClose }: { onClose: () => void }) { + return ( +
    +
    +

    Full Feature Comparison

    + +
    +
    + + + + + {(["starter", "farm", "enterprise"] as const).map((tier) => ( + + ))} + + + + {COMPARE_ROWS.map((row, rowIndex) => ( + + ))} + +
    Feature
    +
    +
    + ); +} + +function CompareHeaderCell({ tier }: { tier: CompareTier }) { + const p = PLAN_TIERS[tier]; + return ( + + {p.label} + + ); +} + +function CompareRow({ row, rowIndex }: { row: CompareRow; rowIndex: number }) { + return ( + + {row.feature} + {(["starter", "farm", "enterprise"] as const).map((tier) => ( + + ))} + + ); +} + +function CompareCell({ value }: { value: boolean | string }) { + if (value === true) { + return ( + + + + + + ); + } + if (value === false) { + return ( + + + + ); + } + return ( + + {value} + + ); +} + +function AddOnsSection({ billingCycle }: { billingCycle: BillingCycle }) { + return ( +
    +
    +

    Power-Up with Add-ons

    +

    Add capabilities à la carte on any plan. No bundles required.

    +
    + {ADDON_LIST.map(({ key, label, icon, description }) => ( + + ))} +
    +
    +
    + ); +} + +function AddOnCard({ + addonKey, + label, + icon, + description, + billingCycle, +}: { + addonKey: keyof typeof ADDONS; + label: string; + icon: string; + description: string; + billingCycle: BillingCycle; +}) { + const addon = ADDONS[addonKey]; + if (!addon) return null; + const price = billingCycle === "annual" ? addon.annualPrice : addon.monthlyPrice; + const monthlyEquiv = billingCycle === "annual" ? Math.round(addon.annualPrice / 12) : null; + return ( +
    + +
    +

    {label}

    +

    {description}

    +
    + ${price} + /{billingCycle === "annual" ? "yr" : "mo"} + {monthlyEquiv !== null && ( + (${monthlyEquiv}/mo equiv.) + )} +
    +
    +
    + ); +} + +function Testimonials() { + // Audit 2026-06-26: previously rendered fabricated named testimonials. + // Replaced with a single honest line until real, attributed customer + // quotes are collected and consented. + if (TESTIMONIALS.length === 0) { + return ( +
    +
    +

    + Early access +

    +

    + We're in early access with produce brands across the country. Customer stories coming soon —  + + talk to us + +  if you'd like to be a reference customer. +

    +
    +
    + ); + } + return ( +
    +
    +

    Trusted by produce operations across the US

    +
    + {TESTIMONIALS.map((item, i) => ( + + ))} +
    +
    +
    + ); +} + +function TestimonialCard({ item, index }: { item: { quote: string; name: string; location: string }; index: number }) { + return ( +
    +
    + {["★", "★", "★", "★", "★"].map((s, j) => ( + + ))} +
    +
    +

    “{item.quote}”

    +
    +

    {item.name}

    +

    {item.location}

    +
    + ); +} + +function FAQSection({ + openFaq, + onToggle, +}: { + openFaq: number | null; + onToggle: (index: number) => void; +}) { + return ( +
    +
    +

    Frequently Asked Questions

    +
    + {FAQ_ITEMS.map((item, i) => ( + onToggle(i)} + index={i} + /> + ))} +
    +
    +
    + ); +} + +function FAQItem({ + question, + answer, + isOpen, + onToggle, + index, +}: { + question: string; + answer: string; + isOpen: boolean; + onToggle: () => void; + index: number; +}) { + return ( +
    + + {isOpen && ( +
    +

    {answer}

    +
    + )} +
    + ); +} + +function CTA() { + return ( +
    +
    +

    Ready to grow your operation?

    +

    Start free on Starter. No credit card required. Upgrade when you're ready.

    +
    + + Start for Free → + + + Talk to Us + +
    +

    + Invoiced by Cielo Hermosa, LLC · billing@routecommerce.com +

    +
    +
    + ); +} + +function SiteFooter() { + return ( +
    +
    +
    + + Route Commerce +
    + +
    +
    + ); +} + function BillingToggle({ cycle, onChange }: { cycle: BillingCycle; onChange: (c: BillingCycle) => void }) { return (
    ); -} \ No newline at end of file +} diff --git a/src/app/pricing/page.tsx b/src/app/pricing/page.tsx index 590fa84..dcc02a5 100644 --- a/src/app/pricing/page.tsx +++ b/src/app/pricing/page.tsx @@ -19,7 +19,8 @@ export const metadata: Metadata = { type: "website", images: [ { - url: "/og-default.jpg", + // Audit 2026-06-26: only og-default.svg exists in /public. + url: "/og-default.svg", width: 1200, height: 630, alt: "Route Commerce Pricing", @@ -32,7 +33,7 @@ export const metadata: Metadata = { description: "Simple, transparent pricing for produce wholesale operations.", site: "@RouteCommerce", creator: "@RouteCommerce", - images: ["/og-default.jpg"], + images: ["/og-default.svg"], }, alternates: { canonical: `${BASE_URL}/pricing`, diff --git a/src/app/roadmap/page.tsx b/src/app/roadmap/page.tsx index 96d7d9a..58b2edf 100644 --- a/src/app/roadmap/page.tsx +++ b/src/app/roadmap/page.tsx @@ -45,6 +45,10 @@ const ROADMAP_ITEMS = { { id: 2, title: "Square Inventory Sync", description: "Two-way sync with Square POS", category: "Integrations", upvotes: 89 }, { id: 3, title: "AI Intelligence Pack", description: "Campaign writer, pricing advisor, demand forecasting", category: "AI", upvotes: 156 }, { id: 4, title: "Water Log Module", description: "Track irrigation and water usage", category: "Operations", upvotes: 67 }, + // Audit 2026-06-26: reclassified from "Planned" — both have code in tree + // (sms_campaigns feature flag + /api/ai/stop-blast-advisor; route-optimizer at /api/ai/route-optimizer). + { id: 12, title: "SMS Campaigns", description: "Text message marketing and transactional SMS via Twilio", category: "Communication", upvotes: 98 }, + { id: 13, title: "Route Optimization", description: "AI-assisted route planning for delivery stops", category: "Logistics", upvotes: 167 }, ], inProgress: [ { id: 5, title: "Mobile App (iOS & Android)", description: "Native apps for field workers and delivery drivers", category: "Mobile", upvotes: 234 }, @@ -52,8 +56,6 @@ const ROADMAP_ITEMS = { { id: 7, title: "Multi-location Support", description: "Manage multiple farms or warehouses from one account", category: "Operations", upvotes: 145 }, ], planned: [ - { id: 8, title: "SMS Campaigns", description: "Text message marketing and notifications", category: "Communication", upvotes: 98 }, - { id: 9, title: "Route Optimization", description: "AI-powered route planning for deliveries", category: "Logistics", upvotes: 167 }, { id: 10, title: "POS Integration ( Clover, Toast)", description: "Additional POS system integrations", category: "Integrations", upvotes: 76 }, { id: 11, title: "Customer Loyalty Program", description: "Points, rewards, and referral tracking", category: "Marketing", upvotes: 112 }, ], @@ -190,64 +192,29 @@ export default function RoadmapPage() { - {/* Suggest Feature */} + {/* Suggest Feature + Audit 2026-06-26: form previously had no submit handler — replaced + with a mailto: link to avoid a non-functional affordance. Re-implement + with a real API once the suggestion queue is ready. */}

    Suggest a Feature

    -

    Have an idea? We'd love to hear it. Share your suggestion and vote on others.

    +

    Have an idea? Email us and we'll add it to the list.

    +
    +
    + + Suggest a Feature + +

    + Opens your email client to hello@routecommerce.com +

    -
    -
    -
    - - -
    -
    - -