All Projects
Live2025eCommerce · Full-Stack

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.

Demo Recording

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

The Problem

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.

The Solution

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.

Build Journey

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 handler — idempotent webhook pattern
typescript
// 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. 1

    PayFast ITN handlers must be idempotent — the same notification can arrive 2-3 times

  2. 2

    Signed Supabase Storage URLs are the correct pattern for digital goods delivery — not public URLs

  3. 3

    The eCommerce order state machine (pending → confirmed → fulfilled → refunded) belongs in the database as a CHECK constraint, not application logic

  4. 4

    Earth-toned design systems (forest green, terracotta, cream) are inherently brand-appropriate for African wellness/sustainable commerce

Tech Stack & Decision Rationale
01

Next.js 14

Performance + SEO for eCommerce, API routes for PayFast ITN

02

TypeScript

Reliable payment and inventory logic

03

Supabase

Product database + Storage for signed download URLs

04

PayFast

Native SA payment gateway — ITN webhook

05

Resend

Order confirmation + download link emails

06

Tailwind CSS

Earth-toned design system

README.md — green-vault
📄 README.md
# 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

Interested in similar work?

Let's discuss how I can build something like this for your business.

Let's Talk