GreenVault eCommerce
The Complete eCommerce Data Lifecycle — From Cart to Signed Download URL
Complete eCommerce platform with the full digital goods delivery lifecycle: PayFast ITN → idempotent webhook handler → signed Supabase Storage URL (48-hour expiry) → Resend confirmation email. The earth-toned design system became the Mirembe Muse brand palette.
Serving
SA sustainable commerce market
Market
Complete eCommerce data model deployed
Problem
Digital goods delivery must be idempotent
Result
Earth-toned design system became Mirembe Muse's brand palette
What needed solving
SA sustainable products are scattered across informal sellers and Instagram pages. But GreenVault's real problem was engineering: digital goods delivery must be idempotent — PayFast can send the same ITN multiple times.
How I built it
Idempotency check on payment reference before processing. Signed Supabase Storage URLs with 48-hour expiry for digital download delivery. Earth-toned design system (forest green, terracotta, cream, warm amber) built for the SA sustainable market.
GreenVault was the most technically comprehensive foundation project: it implemented the complete eCommerce data lifecycle that now runs the Mirembe Muse Store. The hardest problem was digital goods delivery. When a customer pays for a digital product, the flow has to be: PayFast sends ITN → verify signature → mark order confirmed → generate a signed Supabase Storage URL with 48-hour expiry → send email via Resend. The entire chain must be atomic and idempotent — PayFast can send the same ITN multiple times, so the webhook handler must be safe to run repeatedly without creating duplicate orders or sending multiple emails. The earth-toned design system (forest green, terracotta, cream, warm amber) built for GreenVault became the Mirembe Muse brand palette.
// PayFast ITN webhook — idempotent handler
// Safe to run multiple times for the same payment reference
export async function POST(request: Request) {
const body = await request.formData();
const params = Object.fromEntries(body.entries()) as Record<string, string>;
// 1. Verify ITN signature (field order must match POST body order)
const { payment_status, pf_payment_id } = params;
const isValid = await verifyPayFastSignature(params);
if (!isValid) return new Response('Invalid signature', { status: 403 });
// 2. Idempotency check — skip if already processed
const { data: existingOrder } = await supabase
.from('orders')
.select('id, status')
.eq('payfast_payment_id', pf_payment_id)
.single();
if (existingOrder?.status === 'confirmed') {
return new Response('Already processed', { status: 200 }); // PayFast needs 200
}
if (payment_status === 'COMPLETE') {
// 3. Generate signed URL with 48hr expiry
const { data: signedUrl } = await supabase.storage
.from('products')
.createSignedUrl(order.file_path, 48 * 60 * 60);
// 4. Update order + send confirmation email
await supabase.from('orders').update({
status: 'confirmed',
download_url: signedUrl.signedUrl,
}).eq('id', existingOrder.id);
await resend.emails.send({ /* confirmation email */ });
}
return new Response('OK', { status: 200 });
}What This Taught Me
- 1
PayFast ITN handlers must be idempotent — the same notification can arrive 2-3 times
- 2
Signed Supabase Storage URLs are the correct pattern for digital goods delivery — not public URLs
- 3
The eCommerce order state machine (pending → confirmed → fulfilled → refunded) belongs in the database as a CHECK constraint, not application logic
- 4
Earth-toned design systems (forest green, terracotta, cream) are inherently brand-appropriate for African wellness/sustainable commerce
Next.js 14
Performance + SEO for eCommerce, API routes for PayFast ITN
TypeScript
Reliable payment and inventory logic
Supabase
Product database + Storage for signed download URLs
PayFast
Native SA payment gateway — ITN webhook
Resend
Order confirmation + download link emails
Tailwind CSS
Earth-toned design system
# GreenVault eCommerce > The Complete eCommerce Data Lifecycle — From Cart to Signed Download URL ## Project Context **Category:** eCommerce · Full-Stack **Status:** Live · 2025 **Author:** Nandawula Regine Kabali-Kagwa — East London, South Africa **Company:** Mirembe Muse (Pty) Ltd · Reg: 2026-005658 ## Stack ``` Next.js 14 # Performance + SEO for eCommerce, API routes for PayFast ITN TypeScript # Reliable payment and inventory logic Supabase # Product database + Storage for signed download URLs PayFast # Native SA payment gateway — ITN webhook Resend # Order confirmation + download link emails Tailwind CSS # Earth-toned design system ``` ## Architecture Notes - All data mutations validated server-side via Next.js API routes - Row-Level Security enforced at database level (Supabase) - Mobile-first, PWA-ready, offline-tolerant where connectivity is unreliable - PayFast integration for ZAR-native payments (no USD conversion) - SEO-optimised: metadata, JSON-LD, canonical URLs, sitemap - POPIA compliant — data minimisation + user consent by design ## Environment Variables ```env NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY= ANTHROPIC_API_KEY= NEXT_PUBLIC_PAYFAST_MERCHANT_ID= NEXT_PUBLIC_PAYFAST_MERCHANT_KEY= PAYFAST_PASSPHRASE= RESEND_API_KEY= ``` ## Links - Live: https://green-valut-e-commerce-store-demo.vercel.app - GitHub: https://github.com/Nanda-Regine/GreenValut-eCommerce-store-demo - Portfolio: https://creativelynanda.co.za/projects/green-vault --- Built from East London, South Africa · Nine months · Zero to production
More Projects
Interested in similar work?
Let's discuss how I can build something like this for your business.
Let's Talk