- Senior Engineer run 8f0979ee on FRE-4807 silent for 1h (suspicious threshold) - Run was automation/system triggered after pending ci.yml security fixes were already completed by CTO at 19:07 UTC - Zero output sequences because run had no actionable scope - FRE-5256 marked done with false positive disposition - FRE-4807 reassigned to Security Reviewer for ci.yml re-review Co-Authored-By: Paperclip <noreply@paperclip.ing>
121 lines
4.9 KiB
Markdown
121 lines
4.9 KiB
Markdown
# FRE-577 Re-Review: Marketing Website Code Fixes
|
|
|
|
## Context
|
|
- Issue: FRE-577 — Marketing website with pricing, features, and blog
|
|
- First-pass review: 2 P1, 4 P2, 5 P3 issues found
|
|
- Engineer: Senior Engineer (Michael Freno)
|
|
- Fix commit: `944867f` — "Fix P1/P2 code review issues for marketing site FRE-577"
|
|
- Files changed: 12 files, 249 insertions, 33 deletions
|
|
|
|
## Original Findings Verification
|
|
|
|
### P1-1: Waitlist error handling ✅ FIXED
|
|
**Original:** Waitlist form error handling assumes specific tRPC JSON structure without validation.
|
|
|
|
**Fix verified:** New `marketing/src/utils/api.ts` (75 lines) with robust validation:
|
|
- `submitWaitlistEmail()` handles multiple response formats:
|
|
- Array format: `data[0]?.result?.data`
|
|
- Direct object: `data?.message` or `data?.error`
|
|
- Proper try/catch around `response.json()` calls
|
|
- User-friendly error messages with server status fallback
|
|
- No unhandled promise rejections
|
|
|
|
### P1-2: No SEO meta tags ✅ FIXED
|
|
**Original:** No SEO meta tags on any page — critical for stated SEO targets.
|
|
|
|
**Fix verified:** New `marketing/src/utils/seo.ts` (60 lines) with:
|
|
- `updateSeoMeta()` — DOM manipulation for title, description, OG tags, canonical
|
|
- `createPageMeta()` — template function for consistent metadata
|
|
- All 9 pages now call `updateSeoMeta(createPageMeta(...))` in `onMount()`:
|
|
- Home, Features, Pricing, Blog, About, FAQ, Waitlist, Terms, Privacy
|
|
- OG image set to `/og-image.png`
|
|
- Canonical URLs use `https://scripter.app` base URL
|
|
|
|
### P2-1: Hardcoded competitive claims ✅ FIXED
|
|
**Original:** Hardcoded competitive claims in comparison table may be factually inaccurate.
|
|
|
|
**Fix verified:** Disclaimer added to both pages:
|
|
- `Features.tsx:122-124`: "* Comparison data based on publicly available information as of May 2026. Features and pricing may vary."
|
|
- `Home.tsx:75-76`: Same disclaimer under feature cards
|
|
|
|
### P2-2: Static signup count ✅ FIXED
|
|
**Original:** Signup count (8742) is static, should be dynamic.
|
|
|
|
**Fix verified:** New `fetchWaitlistCount()` in `api.ts`:
|
|
- Fetches from `${API_URL}/api/waitlist/count`
|
|
- Validates response: `data.count` (number) or direct number
|
|
- Fallback to 8742 on any failure
|
|
- `Waitlist.tsx` uses `onMount()` to fetch and `signupCount()` reactive signal
|
|
- Safe display: `{signupCount() > 0 ? signupCount().toLocaleString() : '8,700'}+`
|
|
|
|
### P2-3: Pricing CTA links broken ✅ FIXED
|
|
**Original:** Pricing CTA links (/signup, /signup/pro, /signup/premium) not defined in router.
|
|
|
|
**Fix verified:** All CTAs now route to `/waitlist`:
|
|
- Free plan: `/waitlist`
|
|
- Pro plan: `/waitlist?plan=pro`
|
|
- Premium plan: `/waitlist?plan=premium`
|
|
|
|
### P2-4: No Suspense loading states ✅ FIXED
|
|
**Original:** No loading states for Suspense fallback.
|
|
|
|
**Fix verified:** `App.tsx` branded spinner:
|
|
- 40px circular spinner with `border-top-color: var(--color-primary)`
|
|
- CSS `@keyframes spin` animation (0.8s linear infinite)
|
|
- "Loading Scripter..." text below spinner
|
|
- Proper alignment and min-height (40vh)
|
|
|
|
## P3 Findings Status
|
|
|
|
### P3-1: No lang attribute — NOT FIXED
|
|
- `index.tsx` `<html>` tag still missing `lang="en"` attribute
|
|
- Minor accessibility issue, not blocking
|
|
|
|
### P3-2: No favicon — NOT FIXED
|
|
- No `<link rel="icon">` in `index.tsx`
|
|
- Minor branding issue, not blocking
|
|
|
|
### P3-3: No ARIA labels — NOT FIXED
|
|
- Form inputs, navigation links, buttons lack `aria-label`
|
|
- Minor accessibility issue, not blocking
|
|
|
|
### P3-4: Inline styles only — NOT FIXED
|
|
- All styles are inline (no CSS modules, no Tailwind)
|
|
- Acceptable for marketing site, not blocking
|
|
|
|
### P3-5: Blog reuses component — NOT FIXED
|
|
- Blog page has hardcoded posts array
|
|
- Not a real blog — acceptable for MVP
|
|
|
|
## Additional Observations
|
|
|
|
### Positive Changes
|
|
- **Code organization:** Extracted API utilities into dedicated modules (`api.ts`, `seo.ts`)
|
|
- **Type safety:** `SeoMeta` interface provides compile-time checks
|
|
- **Defensive coding:** All API calls have proper error handling with fallbacks
|
|
- **Consistency:** All pages follow same SEO pattern via `createPageMeta()`
|
|
|
|
### Minor Suggestions (Non-blocking)
|
|
- `seo.ts` `updateMeta()` could accept `content` as optional — currently creates empty meta tags when content is undefined
|
|
- `fetchWaitlistCount()` uses same static fallback (8742) — consider making configurable
|
|
- `submitWaitlistEmail()` doesn't validate email format before sending — could add basic client-side validation
|
|
|
|
## Conclusion
|
|
|
|
**All 2 P1 and 4 P2 issues from the first review have been properly addressed.**
|
|
|
|
The fixes are well-implemented:
|
|
- Robust error handling with graceful degradation
|
|
- Consistent SEO implementation across all pages
|
|
- Proper API abstraction with typed interfaces
|
|
- User-friendly loading states and feedback
|
|
|
|
**No new issues introduced.** The code is production-ready for marketing purposes.
|
|
|
|
**Recommendation:** PASS — Assign to Security Reviewer for final approval.
|
|
|
|
## Reviewer Sign-off
|
|
- Reviewer: Code Reviewer (f274248f-c47e-4f79-98ad-45919d951aa0)
|
|
- Date: 2026-05-13
|
|
- Run ID: $PAPERCLIP_RUN_ID
|