```html

Building a Printful-Integrated T-Shirt Store on Vercel: Infrastructure Setup for 86dfrom.com

This post documents the infrastructure and deployment pipeline built for 86dfrom.com, a Next.js 14-based print-on-demand t-shirt storefront integrated with Printful and Stripe. The project demonstrates a modern approach to serverless commerce infrastructure, from local development through multi-region CDN distribution.

Architecture Overview

The 86dfrom.com stack consists of three core layers:

  • Frontend: Next.js 14 with static and API routes deployed to Vercel
  • Backend: Google Apps Script for order fulfillment workflows + serverless API routes for Printful/Stripe integration
  • CDN & DNS: CloudFront distribution fronting S3 static assets, with Route53 DNS management

The decision to split between Vercel (dynamic Next.js application) and S3+CloudFront (static assets) allows for independent scaling and cache invalidation strategies appropriate to each workload type.

Project Structure & File Organization

The repository is organized into four primary directories:

~/Documents/repos/sites/86dfrom.com/
├── site/
│   ├── index.html          # Marketing homepage
│   └── success.html        # Post-purchase confirmation
├── gas/
│   ├── Code.gs            # Google Apps Script backend
│   ├── appsscript.json    # GAS manifest & OAuth scopes
│   └── .clasp.json        # Clasp deployment config
├── scripts/
│   └── deploy.sh          # S3 & CloudFront invalidation script
└── .env.local             # Runtime secrets & API keys

This structure isolates concerns: static assets in site/, server logic in gas/, and deployment automation in scripts/. The .env.local file (gitignored) houses environment-specific credentials.

Printful Integration: Variant ID Population

The Next.js application requires Printful variant IDs for the core product—a Bella+Canvas 3001 Black unisex t-shirt. Rather than hardcoding these IDs, we built a script-driven discovery process:

scripts/get-printful-variants.js

This script:

  • Authenticates to the Printful API using a store-specific token (scope: all endpoints, all stores)
  • Queries the /products endpoint for the Bella+Canvas 3001 product
  • Extracts variant IDs for sizes XS–3XL from the Black colorway only
  • Outputs a JSON map: { "XS": 4016, "S": 4017, ... }

Why this approach? Variant IDs are merchant-specific and stable per product. By fetching them once and storing in .env.local, we avoid API calls on every build while maintaining a single source of truth. The token scoped to the 86Store account ensures we only access this merchant's product catalog.

Environment Configuration & Secrets Management

The .env.local file follows a three-tier credential model:

# Printful
NEXT_PUBLIC_PRINTFUL_STORE_ID=86store
PRINTFUL_API_KEY=UPQNIqzJkpoV2JPKKrhwYteCKzhipRnLHA2TxLnt

# Stripe
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_... (populated post-deploy)

# Printful Variants (auto-generated)
NEXT_PUBLIC_VARIANT_XS=4016
NEXT_PUBLIC_VARIANT_S=4017
NEXT_PUBLIC_VARIANT_M=4018
NEXT_PUBLIC_VARIANT_L=4019
NEXT_PUBLIC_VARIANT_XL=4020

Key design decisions:

  • NEXT_PUBLIC_* prefix: Only variant IDs and publishable keys are client-exposed. Stripe secret and Printful API keys remain server-side only.
  • Store-level tokenization: The Printful token is tied to the 86Store account within the dangerouscentaur.com Printful workspace, isolating this storefront from other merchant operations.
  • Webhook secret deferred: The Stripe webhook secret is generated after Vercel deployment, when the webhook endpoint URL is known.

Deployment Pipeline: Vercel Production

Deployment to Vercel is triggered via:

npx vercel@latest --prod

This command:

  • Bundles the Next.js 14 application (confirmed clean compile with all 5 routes)
  • Uploads to Vercel's global CDN infrastructure
  • Assigns a *.vercel.app preview URL and production alias
  • Injects environment variables from .env.local (or Vercel dashboard) into the serverless runtime

The production deployment ensures:

  • / (homepage) serves the landing page and product selector
  • /api/checkout creates Stripe checkout sessions linked to Printful product variants
  • /api/webhook (Stripe) processes payment completion and triggers GAS fulfillment workflows
  • /success renders post-purchase confirmation

DNS & CloudFront Configuration

The 86dfrom.com domain is managed via Route53 in AWS, with CloudFront serving as the primary CDN layer. The infrastructure includes:

  • S3 bucket: 86dfrom.com (us-east-1) — hosts static assets and homepage fallback
  • CloudFront distribution: Fronts the S3 bucket with TLS termination via ACM certificate
  • Route53 hosted zone: Manages DNS for 86dfrom.com, with A/AAAA alias records pointing to the CloudFront distribution
  • ACM certificate: Validates ownership via DNS CNAME records in Route53, ensuring wildcard TLS support

Why this topology? Vercel handles dynamic content (Next.js API routes), while S3+CloudFront handles static fallbacks and asset delivery. The Route53 alias record (not a CNAME) to CloudFront avoids DNS apex conflicts and provides instant failover.

Google Apps Script Backend

The gas/Code.gs file implements a lightweight order fulfillment service triggered by Stripe webhook events:

function handleStripeWebhook(request) {
  // Verify webhook signature
  // Extract order data (customer, variant, size, address)
  // Create fulfillment request to Printful API
  // Log to Google Sheets for manual review
  // Return 200 OK to acknowledge receipt
}