/ docs / plans / implemented / auditandfix-sales-page.md
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