production: reminder cron, dashboard overhaul, shadcn components, setup wizard

- /api/cron/reminders: processes pending reminders every 15min, sends WhatsApp with email fallback
- /api/cron/overdue: marks overdue pledges daily (7d deferred, 14d immediate)
- /api/pledges: GET handler with filtering, search, pagination, sort by dueDate
- Dashboard overview: stats, collection progress bar, needs attention, upcoming payments
- Dashboard pledges: proper table with status tabs, search, actions, pagination
- New shadcn components: Table, Tabs, DropdownMenu, Progress
- Setup wizard: 4-step onboarding (org → bank → event → QR code)
- Settings API: PUT handler for org create/update
- Org resolver: single-tenant fallback to first org
- Cron jobs installed: reminders every 15min, overdue check at 6am
- Auto-generates installment dates when not provided
- HOSTNAME=0.0.0.0 in compose for multi-network binding
This commit is contained in:
2026-03-03 05:11:17 +08:00
parent 250221b530
commit c79b9bcabc
61 changed files with 3547 additions and 534 deletions

210
AUDIT.md Normal file
View File

@@ -0,0 +1,210 @@
# JustVitamin Proposal Site — Conversion Audit
**Audited:** justvitamin.quikcue.com (/, /proposal, /offer, /dashboard)
**Data source:** PostgreSQL DB — 728,018 validated orders, Nov 2005 Jan 2026
**Auditor:** Ruthless QA pass — every claim verified against raw data
---
## Start-Today Score: 3/10
**The demos are genuinely impressive but the two CTAs that matter — "Approve & Start Build" and "Let's Go" — are both broken `mailto:` links with NO email address. A client literally cannot say yes.**
---
## Top 10 Fixes (Highest Leverage First)
### Fix #1: BROKEN CTAs — Both conversion buttons are dead links
- **Problem:** `/offer` "Approve & Start Build →" and `/proposal` "Let's Go →" both link to `mailto:` with no email address. They do nothing.
- **Why it kills conversions:** The client reaches the end of the best pitch you'll ever make — and the door is locked. 100% of decision-ready traffic dies here.
- **Exact change:** Replace both with `mailto:omair@quikcue.com?subject=JustVitamin%20—%20Approved%20to%20Start%20Build&body=Hi%20Omair%2C%0A%0AApproved%20to%20proceed.%20Let%27s%20schedule%20the%20kickoff.` AND add a Calendly/Cal.com booking link as primary CTA.
- **Where:** `/offer` line 552, `/proposal` line 1013
- **Effort:** S | **Impact:** CRITICAL
### Fix #2: "97.4% Channel Dependency" claim is WRONG
- **Problem:** The offer page headline claims "Organic + Google Ads = 97.4% of all orders." Actual data shows **85.4% in 2025** (Organic 56.6% + Google Ads 28.8%) or **81.7% all-time**.
- **Why it kills conversions:** If the client checks this against their own Shopify analytics, your entire credibility collapses. One wrong number invalidates all numbers.
- **Exact change:** Replace "97.4%" with "85%" and reframe: "85% of your orders come from just two Google-dependent channels. Facebook is 0.1%. TikTok is 0%. You have almost zero social discovery." — the story is still devastating at 85%.
- **Where:** `/offer` hero stat box, section heading "97% Channel Dependency", channel donut chart, board summary bullet. 4 occurrences.
- **Effort:** S | **Impact:** HIGH
### Fix #3: "37.3% repeat rate" is UNVERIFIED — wrong metric used
- **Problem:** The revenue model uses "Repeat rate = 37.3% (your actual)" but this number cannot be derived from the data. The actual returning-order rate is 68.1% all-time / 86.8% in 2025. The cohort 12-month return rate averages 57.6%.
- **Why it kills conversions:** If 37.3% is wrong, the entire ROI calculator is wrong. The interactive model is the strongest close on the page — it must be bulletproof.
- **Exact change:** Use a verifiable metric: either cohort-based "57.6% of customers return within 12 months" or returning-order-share "68% of all orders are repeat purchases." Then recalculate the ROI model with the correct figure.
- **Where:** `/offer` interactive revenue model, assumptions text
- **Effort:** M | **Impact:** HIGH
### Fix #4: No person, no face, no credibility
- **Problem:** Zero information about who built this. "QuikCue" and "Omair" appear in tiny footer text. No bio, no photo, no LinkedIn, no portfolio, no "why me."
- **Why it kills conversions:** The client is being asked to pay £4,000 to someone with no visible identity. At this price point, they Google you. If they find nothing, they don't buy.
- **Exact change:** Add a "Built by" section with: headshot, name, 2-line bio ("I've built AI systems for X, Y, Z"), LinkedIn link, and 1-2 sentence personal note to the client. Place it before the CTA on `/offer`.
- **Where:** `/offer` before the "Decide" section, `/` above footer
- **Effort:** S | **Impact:** HIGH
### Fix #5: Two competing proposal pages — pick one
- **Problem:** `/proposal` and `/offer` are separate pages covering the same content. `/proposal` is weaker (no data story, no calculator, no de-risk section). A confused client reads both and trusts neither.
- **Why it kills conversions:** Split attention = no action. The client doesn't know which is the "real" proposal.
- **Exact change:** Kill `/proposal`. Redirect to `/offer`. The offer page is the complete pitch. Remove "Proposal" from nav, rename nav link to "The Proposal" pointing at `/offer`.
- **Where:** Navigation bar, `/proposal` route
- **Effort:** S | **Impact:** HIGH
### Fix #6: No pre-generated demo output — visitor must wait 90+ seconds
- **Problem:** All 3 demos start with "Waiting." The visitor must click, then wait 70-90s for AI generation. Most visitors won't wait.
- **Why it kills conversions:** The demo is the proof. If the proof requires patience, it's not proof — it's a promise.
- **Exact change:** Pre-generate one demo output (the D3+K2 product) and display it as the default state. Add a "Try another product" toggle that runs the live demo. The pre-loaded output proves it works; the live toggle proves it's real.
- **Where:** `/` Demo A section
- **Effort:** M | **Impact:** HIGH
### Fix #7: Homepage hero talks to us, not to the client
- **Problem:** "Your content engine is real and running" is about us proving our tech works. It says nothing about the client's problem, pain, or gain.
- **Why it kills conversions:** The client's first 5 seconds should be "they understand my problem." Instead, they get "look what I built."
- **Exact change:** Hero headline: **"JustVitamins has lost 84% of its new customers since 2020. This AI engine gets them back."** Sub: "We analysed your 728,018 orders. The product isn't the problem — discovery is. See the data, see the engine, decide today."
- **Where:** `/` hero section (h1 + subtitle)
- **Effort:** S | **Impact:** HIGH
### Fix #8: No "cost of doing nothing" visualisation
- **Problem:** The "£5,000£10,000 per month" cost-of-waiting claim is an ASSUMPTION with no derivation shown. It's presented as data but is actually a guess.
- **Why it kills conversions:** Savvy buyers spot unsubstantiated urgency and distrust the rest.
- **Exact change:** Replace with a verifiable projection: "In 2020, you acquired 24,666 new customers. In 2025, just 3,941. At your current AOV of £35.02, that's **£726,000 in lost first-purchase revenue per year** — before repeat purchases." Show the math inline. This is SOURCE-LINKED and devastating.
- **Where:** `/offer` cost-of-waiting callout
- **Effort:** S | **Impact:** MED
### Fix #9: No before/after proof of AI quality
- **Problem:** The demos generate output live, but there's no screenshot or example showing "Here's what your PDP looks like now → Here's what it looks like after AI." The client can't visualise the transformation without running the demo.
- **Why it kills conversions:** Before/after is the #1 conversion mechanic in any transformation pitch. It's completely absent.
- **Exact change:** Add a 2-column "Before → After" screenshot block below Demo A. Left: actual justvitamins.co.uk PDP (screenshotted). Right: AI-generated PDP output (screenshotted from the demo). Static images, instant load.
- **Where:** `/` between Demo A and Demo B
- **Effort:** M | **Impact:** MED
### Fix #10: Revenue model "payback period" math is wrong
- **Problem:** The calculator shows "2.6 mo" payback at 100 new customers/month, but the actual math gives 3.5 months (£12,400 / £3,502 per month). The 2.6 figure seems to include repeat revenue in month 1, which hasn't happened yet.
- **Why it kills conversions:** If the client runs the numbers themselves and gets a different answer, trust dies.
- **Exact change:** Use first-purchase-only for payback: 3.5 months at 100/mo, 7 months at 50/mo. Show the formula visibly. Add a note: "Repeat purchases improve ROI further in months 4-12 but are excluded from payback calculation."
- **Where:** `/offer` interactive revenue model
- **Effort:** S | **Impact:** MED
---
## Trust & Data Audit Report
### Hard Claims Table
| # | Claim | Page | Actual Value | Status | Action |
|---|-------|------|-------------|--------|--------|
| 1 | £19.4M lifetime revenue | / hero | £19,417,899 | ✅ SOURCE-LINKED | Keep |
| 2 | 728K orders processed | / hero | 728,018 | ✅ SOURCE-LINKED | Keep |
| 3 | 230K unique customers | / hero | 230,651 | ✅ SOURCE-LINKED | Keep |
| 4 | 20 years trading history | / hero | Nov 2005 Jan 2026 (20.2 yrs) | ✅ SOURCE-LINKED | Keep |
| 5 | -84% new customer decline | /offer hero | -84.0% (24,666→3,941, 2020→2025) | ✅ SOURCE-LINKED | Keep |
| 6 | -42% revenue from peak | /offer hero | -42.5% (£1.82M→£1.05M) | ✅ SOURCE-LINKED | Keep |
| 7 | 97.4% channel dependency (Google+Organic) | /offer hero + 3 more | 85.4% (2025) / 81.7% (all-time) | ❌ WRONG | **Fix to 85%** |
| 8 | AOV climbed from £26→£35 | /offer data | £26.46 (2018)→£35.02 (2025) | ✅ SOURCE-LINKED | Keep, add years |
| 9 | Repeat rate 37% / 37.3% | /offer model | Cannot verify. Returning rate=68.1%, cohort=57.6% | ⚠️ UNVERIFIED | **Fix: use verifiable metric** |
| 10 | 24,600/year in 2020 new customers | /offer data | 24,666 | ✅ SOURCE-LINKED | Keep |
| 11 | Under 4,000 in 2025 new customers | /offer data | 3,941 | ✅ SOURCE-LINKED | Keep |
| 12 | Facebook: 0.1% | /offer channel | 694/728,018 = 0.10% (all-time), 34/29,919 = 0.11% (2025) | ✅ SOURCE-LINKED | Keep |
| 13 | TikTok: 0%, Instagram: 0% | /offer channel | Not present in channel data | ✅ DERIVED (absence=0) | Keep |
| 14 | £5,000£10,000/month cost of waiting | /offer callout | Requires 143-286 new social customers/month. No basis for this range. | ❌ UNVERIFIED | **Replace with verifiable calc** |
| 15 | AOV = £35.02 (2025 actual) | /offer model | £35.02 | ✅ SOURCE-LINKED | Keep |
| 16 | "Competitors producing 10x content" | /offer | No source or evidence | ❌ UNVERIFIED | **Remove or soften** |
| 17 | Year 1 cost = £12,400 | /offer model | £4,000 + £500×12 + £200×12 = £12,400 | ✅ DERIVED (arithmetic) | Keep |
| 18 | 5.9x Year 1 ROI at 100 custs/mo | /offer model | Depends on 37.3% repeat rate being correct | ⚠️ CONDITIONAL | **Recalculate with verified rate** |
| 19 | 2.6 month payback | /offer model | Actual: 3.5 months (first-purchase only) | ❌ WRONG | **Fix math** |
| 20 | Revenue peak £1.82M | /offer board summary | £1,820,963 | ✅ SOURCE-LINKED | Keep |
| 21 | Revenue 2025 £1.05M | /offer board summary | £1,047,850 | ✅ SOURCE-LINKED | Keep |
| 22 | 3,900/year new customers 2025 | /offer board summary | 3,941 | ✅ SOURCE-LINKED | Keep (round to 3,900 is fair) |
| 23 | 728,018 validated orders | /offer footer | 728,018 | ✅ SOURCE-LINKED | Keep |
**Summary: 15/23 claims verified, 4 wrong/unverified, 4 conditional.**
---
## Rewritten "Start Today" Block
### Current (broken):
```
Ready to Build?
If approved, access is provided and build starts immediately.
[Approve & Start Build →] ← links to mailto: (empty!)
Build begins within 48 hours of approval.
```
### Rewritten:
```
──────────────────────────────────────
YOU'VE SEEN THE DATA. YOU'VE SEEN THE ENGINE.
Every month without social discovery costs you
£60,000+ in lost new-customer revenue.
(20,700 fewer new customers × £35.02 AOV = £726K/year lost since 2020)
THE OFFER:
✦ £4,000 one-time build — all 4 pillars
✦ £500/month infrastructure — cancel with 30 days' notice
✦ Week 4 gate — full review before any ongoing commitment
✦ You own everything — server, code, content, data
RISK REVERSAL:
→ If you're not satisfied at Week 4, walk away. No ongoing fees.
→ The £4,000 build cost delivers real infrastructure you keep regardless.
→ 30-day monthly exit clause. No lock-in. No agency dependency.
TO START:
□ 1. Reply to this email confirming approval
□ 2. We'll send Shopify collaborator access request
□ 3. 15-min kickoff call within 48 hours
□ 4. Infrastructure live by end of Week 1
[ Book 15-Min Kickoff Call → ] ← Calendly link
[ Reply: Approved to Start → ] ← mailto:omair@quikcue.com?subject=...
Built by Omair @ QuikCue
──────────────────────────────────────
```
**Key changes:**
1. Opens with data-backed cost of inaction (verifiable)
2. Offer summarised in 4 bullets (not buried in sections)
3. Risk reversal is explicit and bold
4. Two CTA options: low-friction (Calendly) + decisive (email)
5. Steps are numbered and tiny (3 things, nothing scary)
6. Person identified by name
---
## Detailed Verification Notes
### The 97.4% problem
The site claims "Organic + Google Ads = 97.4% of all orders." The actual channel breakdown:
**2025:**
| Channel | Orders | Share |
|---------|--------|-------|
| Organic | 16,942 | 56.6% |
| Google Adwords | 8,620 | 28.8% |
| Webgains | 2,768 | 9.3% |
| Email Newsletter | 1,402 | 4.7% |
| Bing | 153 | 0.5% |
| Facebook | 34 | 0.1% |
| **Total** | **29,919** | **100%** |
Google + Organic = **85.4%**, not 97.4%. Even adding Bing = 85.9%. Even adding Webgains = 95.2%. None of these groupings produce 97.4%.
**Recommended reframe:** "85% of orders depend on Google channels. 0.1% come from social. You have zero TikTok, zero Instagram, zero YouTube presence." — This is true AND just as alarming.
### The 37.3% repeat rate problem
No combination of available data produces 37.3%:
- Returning orders / total orders = 68.1% (all-time)
- Returning orders / total orders = 86.0% (2025)
- Average 12-month cohort retention = 57.6%
- New customer share = 33.5% (all-time)
37.3% might have come from a different analysis of the raw jv_data.json before aggregation, but it's not reproducible from the deployed database. The revenue model should use the cohort-verified 57.6% or explain its source.
### The payback period problem
At 100 new customers/month, monthly first-purchase revenue = £3,502.
Year 1 cost = £12,400.
Payback on first-purchase revenue alone = 12,400 / 3,502 = **3.54 months**, not 2.6.
The 2.6 month figure likely includes repeat revenue from the first cohorts, which is optimistic for a payback calculation. Standard practice uses first-purchase only.