Clicking the free-guide card opens an accessible email popup. The email is
added to the Resend Free AI Guide segment. The optional updates checkbox is
the only action that opts the contact into the Practical AI Workflows topic;
unchecked guide requests remain globally unsubscribed from broadcasts.
After Resend accepts the contact, the server returns a five-minute GET-only URL
for the free PDF in Vercel Private Blob. The guide is downloaded directly from
that private link; submitting the form does not send a transactional email.
The free guide is not served from public/.
Resend configuration is managed through the official CLI. The deployed app
requires RESEND_API_KEY, RESEND_FREE_GUIDE_SEGMENT_ID,
RESEND_AI_WORKFLOWS_TOPIC_ID, and FREE_GUIDE_BLOB_PATHNAME. Resend is the
canonical mailing list and handles topic consent and unsubscribes. A verified
sending domain is not required for contact capture, but it is required before
sending broadcasts.
The contact list is portable. The export script follows Resend's pagination and writes every contact to standard output:
npm run --silent export:contacts > ~/Downloads/resend-contacts.csv
npm run --silent export:contacts -- --format=json > ~/Downloads/resend-contacts.jsonThe script reads RESEND_API_KEY from the shared private token file, the shell,
or .env.local. Keep exports outside the repository because they contain
personal data.
The paid playbook is stored in a private Vercel Blob store and is never copied
into public/.
Stripe redirects successful buyers to
/playbook/thank-you?session_id={CHECKOUT_SESSION_ID}. The server verifies that
the live Checkout Session is complete, paid, originated from the expected
Payment Link, and contains the exact playbook price. Only then does the download
route issue a five-minute, GET-only signed URL for the configured private Blob.
The page and download route are private/no-store, and web analytics are disabled
on the thank-you page because the Checkout Session ID is a bearer credential.
Required server variables are documented here. Vercel supplies the linked Blob
credentials; STRIPE_SECRET_KEY, BLOB_STORE_ID, and
PLAYBOOK_BLOB_PATHNAME must be configured for each deployment environment.
- Compute a content hash of the final PDF.
- Upload it to the private store under a new versioned pathname such as
products/seven-day-ai-workflow-pilot/v2-<hash>.pdf. - Change
PLAYBOOK_BLOB_PATHNAMEto the exact uploaded pathname for the target Vercel environment. - Deploy a new preview and run the entitlement checks before promoting it.
Do not overwrite an existing pathname or place a paid artifact under public/.
A fast personal brand hub with a small server-side boundary for secure digital delivery.
- 🎨 Light/Dark Theme - Auto-detects system preference + manual toggle
- 📱 Responsive Grid - Adapts to all screen sizes (3 → 4 → 6 columns)
- 🔐 Secure Delivery - Stripe-verified access to private digital products
- ♿ Accessible - WCAG 2.1 AA compliant, keyboard navigable
- 🎭 Confetti Easter Egg - Fun interactive element (respects reduced motion)
- 🧩 Easy Content Updates - Single
content.tsfile to manage everything - 🎯 Future-Proof - Newsletter placeholder ready for Beehiiv/ConvertKit
- Node.js 18+ (specified in
.nvmrc) - npm or yarn
# Install dependencies
npm install
# Run development server
npm run devVisit http://localhost:3000
# Build for production
npm run build
# Start production server
npm startDeploy to Vercel:
vercel- Framework: Next.js 14 (App Router)
- Styling: TailwindCSS
- Theme: next-themes
- Type: Next.js site with static pages and server-side entitlement routes
.
├── app/
│ ├── components/ # UI components
│ │ ├── HeroHeader.tsx # Header with title, tagline, theme toggle
│ │ ├── AboutCard.tsx # Large square profile photo tile
│ │ ├── AppIcon.tsx # App/social tile component (rounded square images)
│ │ ├── FeatureTile.tsx # Large feature banner tile
│ │ └── MainGrid.tsx # 2-column layout orchestrator
│ ├── providers/
│ │ └── ThemeProvider.tsx # Theme context provider
│ ├── utils/
│ │ └── imageDiscovery.ts # Auto-discovery helpers for icons/images
│ ├── content.ts # Single source of truth for all content
│ ├── layout.tsx # Root layout with metadata
│ ├── page.tsx # Main page assembling all components
│ └── globals.css # Global styles & theme variables
├── public/
│ ├── icons/ # App & social icons (PNG)
│ └── images/ # Profile & feature images (JPG/PNG)
├── package.json
└── README.md
- Drop your PNG file in
/public/icons/(e.g.,your-app.png) - Update
app/content.ts:- Add to
iconMapat the top:yourApp: "your-app" - Add the icon key type to
app/utils/imageDiscovery.tsIconKeytype - Add your item to either
personalItemsorsocialsarray with the newiconKey
- Add to
- Drop your JPG/PNG file in
/public/images/- Profile photo:
profile.jpgorprofile.png - Feature tile:
feature.jpgorfeature.png
- Profile photo:
- Update if needed: If using a different name, update the
ImageKeytype inapp/utils/imageDiscovery.ts
The system automatically discovers your assets - no manual path management!
- Light mode:
#E6E1DCbg,#111111text,#7CB3FFprimary - Dark mode:
#0C0C14bg,#FAFAFAtext,#4A8BFFprimary - System preference detection enabled
- Manual toggle via
useThemehook
Keep these values server-only; do not prefix them with NEXT_PUBLIC_:
STRIPE_SECRET_KEYBLOB_STORE_IDBLOB_READ_WRITE_TOKENPLAYBOOK_BLOB_PATHNAMERESEND_API_KEYRESEND_FREE_GUIDE_SEGMENT_IDRESEND_AI_WORKFLOWS_TOPIC_IDFREE_GUIDE_BLOB_PATHNAMEFREE_GUIDE_VERSION
✅ Completed:
- Project scaffold (T1-T3)
- All UI components (T4-T11)
- Light/dark theme system
- Responsive 2-column layout (mobile stacked)
- Accessibility features
- Auto-discovery system for images/icons
- Real profile photo and social icons
- Updated links (affiliate links for personal items, direct platform links for socials)
✅ Completed (T12):
- ✅ Theme system fixed (light/dark mode working)
- ✅ Deployed to Vercel: https://linktree.snackoverflowgeorge.com
- ✅ Production build successful
- ✅ Static generation enabled
- ✅ All pages working: /, /about, /playground
# Start dev server
npm run dev
# Build for production
npm run build
# Test production build
npm start- WCAG 2.1 AA compliant
- Full keyboard navigation with visible focus states
- Respects
prefers-reduced-motion - Semantic HTML throughout
- All images have alt text
- Color contrast ≥ 4.5:1 for body text
- Push to GitHub
- Import project on Vercel
- Auto-deploy on push
# Or use CLI
npm i -g vercel
vercelPrivate project