Building 86dfrom.com: Next.js E-Commerce + Google Apps Script Integration with AWS Infrastructure
What Was Done
Deployed a full-stack t-shirt e-commerce site for 86dfrom.com integrating Next.js 14 frontend, Stripe payments, Printful print-on-demand fulfillment, and Google Apps Script backend automation. The infrastructure spans Vercel (application hosting), AWS S3 + CloudFront (static assets and redirects), Route53 (DNS), and Google Apps Script (order webhook processing).
Architecture Overview
The project uses a hybrid deployment model:
- Application tier: Next.js 14 on Vercel with five compiled API routes handling product variants, Stripe webhooks, and order confirmation
- Payment processing: Stripe for card transactions with webhook validation at
/api/webhook - Print fulfillment: Printful API integration for variant retrieval and order creation via
scripts/get-printful-variants.js - Order persistence: Google Apps Script (GAS) deployed as web app, receiving POST requests from Vercel to log orders into Google Sheets
- Static hosting: Parallel S3 + CloudFront deployment for
86from.com(note: different domain spelling) with CloudFront Functions handling HTTP→HTTPS redirect
File Structure and Key Components
The project directory layout reflects this separation:
/Users/cb/Documents/repos/sites/86dfrom.com/
├── site/
│ ├── index.html (static redirect/marketing page)
│ └── success.html (order confirmation page)
├── gas/
│ ├── Code.gs (Google Apps Script backend)
│ ├── appsscript.json (GAS manifest with scopes)
│ └── .clasp.json (Clasp deployment config)
├── scripts/
│ └── deploy.sh (S3 + CloudFront deployment automation)
└── .env.local (environment variables—not committed)
The Next.js application (deployed separately to Vercel) contains:
app/
├── page.tsx (homepage with product grid)
├── api/
│ ├── variants/ (GET Printful variant IDs)
│ ├── create-checkout/ (POST initiate Stripe session)
│ ├── webhook/ (POST Stripe webhook handler)
│ └── success/ (POST order confirmation)
└── layout.tsx (shared metadata + fonts)
Technical Decisions and Rationale
Why Google Apps Script Instead of a Database
Orders are logged to Google Sheets via Apps Script rather than a dedicated database. This reduces operational overhead—no database provisioning, backups, or schema migrations. Google Sheets serves as both the data store and the audit log, accessible to non-technical team members. The GAS Code.gs file exposes an HTTP endpoint that validates incoming requests and appends rows to a spreadsheet.
Dual Domain Strategy (86dfrom.com vs 86from.com)
The production e-commerce site lives at 86dfrom.com (Vercel), while a static redirect site runs at 86from.com (S3 + CloudFront) to catch typos. The redirect uses CloudFront Functions—a lightweight compute layer that intercepts requests before they hit S3, eliminating the need for S3 website hosting or Lambda@Edge. This approach costs less and has lower latency than Lambda-based redirects.
Variant ID Population via Script
Rather than hardcoding Printful variant IDs in the codebase, scripts/get-printful-variants.js queries the Printful API at deploy time. The script fetches the product (Bella+Canvas 3001 Black t-shirt) and extracts variant IDs (sizes 4016–4020), writing them to a JSON file that the build process consumes. This decouples product catalog changes from code deployments.
AWS Infrastructure for Static Content
Static assets (site/index.html, site/success.html`) are deployed to S3 bucket 86from-com-static and served through CloudFront distribution. S3 bucket policies restrict all access to CloudFront's origin access identity (OAI), preventing direct bucket access. This pattern ensures:
- DDoS protection via CloudFront's edge locations
- HTTPS-only traffic with ACM certificates
- HTTP→HTTPS redirect via CloudFront Functions without additional servers
- Cache invalidation automation post-deploy
Infrastructure Details
S3 Bucket Configuration
Bucket name: 86from-com-static
Bucket policy grants only CloudFront's OAI read access:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity [OAI-ID]"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::86from-com-static/*"
}
]
}
This prevents accidental public access while allowing CloudFront to fetch objects.
CloudFront Distributions
Primary distribution (86from.com → S3):
- Origin: S3 bucket
86from-com-static(not website endpoint—bucket endpoint via OAI) - ACM certificate:
86from.comwith DNS validation via Route53 - Default root object:
index.html - Cache behaviors: Default TTL 86400s (1 day) for marketing pages
- Compress: Enabled for text assets (HTML, CSS)
Redirect distribution (86from.com HTTP→HTTPS):
- Origin: Custom origin (no S3 origin—headers would be ineffective)
- CloudFront Function: Evaluates request URI and returns 301/302 redirect to HTTPS
- Viewer protocol policy: HTTP and HTTPS allowed (function handles redirect)
Route53 DNS
Hosted zone for 86from.com contains:
86from.com A record→ CloudFront distribution alias (static content)www.86from.com CNAME→86from.com(optional, typically not used for redirects)- ACM validation CNAMEs (temporary, removed after certificate issuance)
Primary domain 86dfrom.com (production e-commerce) is configured separately with Vercel's nameservers or as a CNAME to Vercel's provided endpoint.
Google Apps Script Deployment
File gas/.clasp.json contains Clasp