auditandfix-sales-page.md
1 --- 2 title: 'Audit&Fix Sales Page + Report Generation System' 3 category: plans/implemented 4 status: implemented 5 implemented_date: '2026-02-19' 6 commit: 'a01f5a0b' 7 related_files: 8 - auditandfix.com/ 9 - workers/auditandfix-api/ 10 - src/reports/ 11 - src/cron/poll-purchases.js 12 - src/cron/process-purchases.js 13 - src/api/pricing-export.js 14 - src/cli/purchases.js 15 - src/payment/paypal.js 16 - db/migrations/060-create-purchases-table.sql 17 - tests/purchases*.test.js 18 tags: [auditandfix, sales, payments, reports, paypal, cloudflare] 19 --- 20 21 # ✅ IMPLEMENTED (2026-02-19, commit a01f5a0b) 22 23 ## Implementation Summary 24 25 All 9 phases implemented. 45 files changed (38 new), 6,585 lines added. 26 12 test suites, 80 tests, 0 failures, 0 regressions. 27 28 **Deliverables:** 29 30 - PHP sales page (auditandfix.com) with PayPal Smart Buttons, multi-currency pricing, geo-detection 31 - Cloudflare Worker (auditandfix-api) — KV-backed purchase queue + pricing endpoint 32 - Purchase polling cron (5-min) — ingests from CF Worker, sends confirmation emails 33 - Report generation — full-page capture → LLM score refresh → problem area cropping → 9-page PDF 34 - Report delivery cron (twice-daily) — emails PDF attachment via Resend 35 - PayPal refund support added to paypal.js 36 - Purchase CLI (`npm run purchases:list`, `purchases:process`, `purchases:refund`) 37 - Dashboard precomputation for purchase metrics 38 39 --- 40 41 # Audit&Fix Sales Page + Report Generation System 42 43 ## Overview 44 45 A direct sales channel where website owners can purchase a premium CRO audit report. 46 Creates a second revenue stream alongside automated outreach. 47 48 **Flow:** 49 50 1. Visitor lands on auditandfix.com 51 2. Enters URL + email, pays via PayPal 52 3. Purchase queued in Cloudflare Worker KV store 53 4. 333Method polls CF Worker every 5 min, ingests purchase, sends confirmation email 54 5. Processing cron runs twice daily: captures full-page screenshot, refreshes LLM score, crops problem areas, generates 9-page PDF report 55 6. Delivery cron emails PDF to customer 56 57 --- 58 59 ## Phase 1 — Database 60 61 **File:** `db/migrations/060-create-purchases-table.sql` 62 63 ```sql 64 CREATE TABLE purchases ( 65 id INTEGER PRIMARY KEY AUTOINCREMENT, 66 email TEXT NOT NULL, 67 landing_page_url TEXT NOT NULL, 68 phone TEXT, 69 paypal_order_id TEXT UNIQUE NOT NULL, 70 paypal_payer_id TEXT, 71 paypal_capture_id TEXT, 72 amount REAL NOT NULL, -- local currency amount 73 currency TEXT NOT NULL, -- ISO 4217 74 amount_usd REAL NOT NULL, 75 country_code TEXT, 76 ip_address TEXT, 77 user_agent TEXT, 78 status TEXT NOT NULL DEFAULT 'paid' 79 CHECK (status IN ('paid','processing','report_generated','delivered','failed','refunded')), 80 report_path TEXT, 81 delivered_at TEXT, 82 retry_count INTEGER DEFAULT 0, 83 error_message TEXT, 84 created_at TEXT DEFAULT (datetime('now')), 85 updated_at TEXT DEFAULT (datetime('now')) 86 ); 87 ``` 88 89 Status flow: `paid → processing → report_generated → delivered` 90 91 --- 92 93 ## Phase 2 — Cloudflare Worker 94 95 **Files:** `workers/auditandfix-api/` 96 97 **Endpoints:** 98 99 - `GET /health` — health check 100 - `GET /pricing` — returns pricing JSON from KV (populated by `npm run pricing:export`) 101 - `POST /purchases` — stores new purchase in KV queue (called by PHP after PayPal capture) 102 - `GET /purchases` — returns queued purchases (polled by 333Method cron) 103 - `DELETE /purchases/:id` — removes processed purchase from queue 104 105 **Auth:** `X-Auth-Secret` header on all non-public endpoints. 106 107 **KV Namespaces:** `PURCHASES` (queue), `PRICING` (pricing data) 108 109 **Deploy:** 110 111 ```bash 112 cd workers/auditandfix-api 113 npm install --ignore-scripts 114 npx wrangler login --no-browser 115 npx wrangler kv:namespace create PURCHASES 116 npx wrangler kv:namespace create PRICING 117 # Update wrangler.toml with KV namespace IDs 118 npx wrangler secret put AUTH_SECRET 119 npx wrangler deploy 120 ``` 121 122 --- 123 124 ## Phase 3 — Purchase Polling 125 126 **File:** `src/cron/poll-purchases.js` 127 128 - Polls `GET /purchases` from CF Worker every 5 minutes (registered in cron.js) 129 - Inserts new purchases into `purchases` table (INSERT OR IGNORE for idempotency) 130 - Sends confirmation email via Resend 131 - Removes processed purchases from CF Worker queue via `DELETE /purchases/:id` 132 133 **Env vars required:** `AUDITANDFIX_WORKER_URL`, `AUDITANDFIX_WORKER_SECRET` 134 135 --- 136 137 ## Phase 4 — Report Generation 138 139 **Files:** `src/reports/` 140 141 | Module | Purpose | 142 | --------------------------- | ----------------------------------------------------------------------------- | 143 | `full-page-capture.js` | Full-page screenshot via Playwright (above + below fold) | 144 | `score-refresh.js` | Re-scores site using fresh screenshot + current prompt | 145 | `problem-area-cropper.js` | Crops 5 worst-scoring areas using sharp | 146 | `audit-report-generator.js` | 9-page PDF with pdfkit — cover, exec summary, 6 factor pages, recommendations | 147 | `report-orchestrator.js` | Orchestrates all 4 steps for a single purchase | 148 149 **Scoring prompt:** `prompts/AUDIT-REPORT-SCORING.md` 150 151 --- 152 153 ## Phase 5 — Report Processing Cron 154 155 **File:** `src/cron/process-purchases.js` 156 157 - Runs twice daily (8am + 8pm) 158 - Picks up `status='paid'` purchases 159 - Calls `generateAuditReportForPurchase(purchase)` 160 - On success: updates `status='report_generated'`, stores `report_path` 161 - On failure: increments `retry_count`; after 3 retries marks `status='failed'` and adds to human review queue 162 163 --- 164 165 ## Phase 6 — PHP Sales Page 166 167 **Files:** `auditandfix.com/` 168 169 | File | Purpose | 170 | ---------------------- | --------------------------------------------------------------------- | 171 | `index.php` | Main landing page — geo detection, pricing, PayPal buttons | 172 | `api.php` | Backend — creates PayPal order, captures payment, queues to CF Worker | 173 | `thank-you.php` | Post-payment confirmation page | 174 | `includes/config.php` | PayPal credentials, CF Worker URL/secret | 175 | `includes/pricing.php` | Fetches pricing from CF Worker | 176 | `includes/geo.php` | IP-based country detection | 177 | `assets/css/style.css` | Landing page styles | 178 | `assets/js/main.js` | Currency switching, form validation, PayPal Smart Buttons | 179 | `.htaccess` | HTTPS redirect, security headers | 180 181 **config.php values to fill in:** 182 183 ```php 184 define('PAYPAL_CLIENT_ID', '...'); 185 define('PAYPAL_CLIENT_SECRET', '...'); 186 define('PAYPAL_MODE', 'sandbox'); // → 'live' for production 187 define('CF_WORKER_URL', 'https://auditandfix-api.xxx.workers.dev'); 188 define('CF_WORKER_SECRET', '...'); // same as AUDITANDFIX_WORKER_SECRET 189 ``` 190 191 --- 192 193 ## Phase 7 — Sample Report 194 195 **File:** `scripts/generate-sample-report.js` 196 197 Generates a fuzzed/watermarked sample PDF from a real scored site: 198 199 ```bash 200 npm run report:sample 201 # Output: reports/sample-audit-report.pdf 202 ``` 203 204 Used on the landing page as a preview/lead magnet. 205 206 --- 207 208 ## Phase 8 — npm Scripts 209 210 Added to `package.json`: 211 212 ``` 213 npm run report:audit — generate audit report for a purchase 214 npm run report:sample — generate fuzzed sample report 215 npm run purchases:list — list all purchases 216 npm run purchases:process — run report processing cron manually 217 npm run purchases:refund — refund a purchase 218 ``` 219 220 Also added `pricing:export` to push pricing to CF Worker KV. 221 222 --- 223 224 ## Phase 9 — Tests 225 226 12 test files, 80 tests: 227 228 | Test File | Coverage | 229 | -------------------------------- | ------------------------------------------------------ | 230 | `purchases.test.js` | Schema, constraints, status flow, indexes | 231 | `paypal-refund.test.js` | refundPayment() with mocked PayPal API | 232 | `purchase-confirmation.test.js` | sendConfirmationEmail() with mocked Resend | 233 | `pricing-export.test.js` | exportPricing() — CF Worker + local file | 234 | `poll-purchases.test.js` | pollPurchases() — ingest, dedup, confirmation, delete | 235 | `problem-area-cropper.test.js` | cropProblemAreas() with real sharp | 236 | `full-page-capture.test.js` | captureFullPage() with mocked Playwright | 237 | `score-refresh.test.js` | refreshScore() — LLM call, JSON extraction, truncation | 238 | `audit-report-generator.test.js` | generateAuditReport() — real pdfkit PDF output | 239 | `report-delivery.test.js` | deliverReport() — PDF email attachment | 240 | `purchases.integration.test.js` | Full purchase flow with real DB | 241 | `purchases-e2e.test.js` | End-to-end: poll → process → PDF → deliver | 242 243 --- 244 245 ## Phase 10 — Multilanguage Support (Planned, Post-Launch) 246 247 Build English first. Add language support as a second iteration once the English page is live and validated. 248 249 **Approach:** Language selector widget at the top of the page — similar to the currency selector already implemented. The selector sets a cookie/URL param that controls: 250 251 1. **Sales page text** — All copy (headlines, body, CTAs, FAQ, testimonials) translated to the user's language. Separate translated PHP template per language, or a translation key/value system loaded at render time. 252 253 2. **Report screenshots on the page** — The "Here's What You Actually Get" montage images (report cover, factor analysis, etc.) should be generated from a sample report in the same language. Generate one set of sample report PNGs per supported language. 254 255 3. **The audit reports themselves** — The PDF reports are generated in English initially. Add LLM translation of the report narrative (factor descriptions, recommendations) as a follow-on step. The site content screenshots in the report remain as-is (they're from the customer's site). 256 257 **Priority languages** (based on existing pricing markets): English (default), German (DE), French (FR), Spanish (ES), Japanese (JP), Portuguese (BR). 258 259 **Implementation order:** 260 261 1. Refactor `index.php` to use a translation layer (PHP array-based, one file per language) 262 2. Add language selector widget to nav (alongside currency selector) 263 3. Translate copy for priority languages 264 4. Generate localised sample report screenshot sets per language 265 5. (Later) LLM report translation for factor narrative and recommendations 266 267 **Note:** Currency and language are independent selectors — a French-speaking Canadian might want CAD + French, or a Swiss user might want CHF + German. Don't couple them. 268 269 --- 270 271 ## Deployment Checklist 272 273 - [ ] Run migration: `sqlite3 db/sites.db < db/migrations/060-create-purchases-table.sql` 274 - [ ] Add `.env` vars: `AUDITANDFIX_WORKER_URL`, `AUDITANDFIX_WORKER_SECRET` 275 - [ ] Deploy CF Worker (see Phase 2 above) 276 - [ ] Push pricing to KV: `npm run pricing:export` (after worker is live) 277 - [ ] Restart pipeline: `systemctl --user restart 333method-pipeline` 278 - [ ] Create PayPal app at developer.paypal.com 279 - [ ] Fill in `auditandfix.com/includes/config.php` 280 - [ ] Upload PHP files to web host 281 - [ ] Configure DNS + HTTPS for auditandfix.com 282 - [ ] End-to-end sandbox test (PayPal sandbox → poll → process → deliver) 283 - [ ] Switch PayPal mode to `live` in config.php 284 - [ ] Generate sample report: `npm run report:sample` 285 - [ ] Link sample PDF from landing page