S3 (a1): affiliate + partner plumbing
Zero out-of-pocket; everything config-flip-ready but DISABLED/organic. - BOOK IT deep links: web/src/lib/bookLinks.js + affiliateConfig.js (all books enabled:false, Impact/Partnerize param shapes documented, empty params skipped). Wired into StatStrip BookItTeaser (real anchor now) + scan hand-off links. Every book anchor renders rel="sponsored noopener noreferrer" (BOOK_LINK_REL). - Best-price marker: slateAdapter.detectBestBook (only when >=2 books post the SAME line and prices differ — absent beats wrong) + subtle signal-green dot in StatStrip. Slate.groupByGame threads the grouped per-book rows (books[]) onto PropRowProp instead of discarding them. - Partner refs: ?ref=CODE -> vyndr_ref cookie (90d, first-touch, PartnerRefCapture in layout) -> signup metadata partner_ref -> internal GET /api/partners/report/:code (requireInternalAuth; honest zeros + note until the TODO migration in docs/PARTNERS.md adds user_profiles.partner_ref — NOT run). Stripe promo-code convention: partner code == promotion code, verbatim. - Tests: +41 (2398 -> 2439, 209 suites); bookItTeaser + vyndrCoreScreens invariants updated to the new (stronger) rel contract. Web build exit 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -150,8 +150,12 @@ describe('Phase D — scan + landing wiring', () => {
|
||||
expect(src).toContain('mapScanToGradeResult');
|
||||
expect(src).not.toContain("from '@/components/GradeCard'");
|
||||
});
|
||||
it('scan keeps sportsbook deep-links safe (noopener noreferrer)', () => {
|
||||
expect(read('app/scan/page.tsx')).toContain('noopener noreferrer');
|
||||
it('scan keeps sportsbook deep-links safe (A1 S3: BOOK_LINK_REL = sponsored noopener noreferrer)', () => {
|
||||
const src = read('app/scan/page.tsx');
|
||||
expect(src).toContain('rel={BOOK_LINK_REL}');
|
||||
// the constant itself carries noopener noreferrer (+ sponsored)
|
||||
const { BOOK_LINK_REL } = require('../../web/src/lib/bookLinks');
|
||||
expect(BOOK_LINK_REL).toContain('noopener noreferrer');
|
||||
});
|
||||
it('landing mounts the ClaimMeter', () => {
|
||||
expect(read('app/page.tsx')).toContain('ClaimMeter');
|
||||
|
||||
Reference in New Issue
Block a user