All Projects
Live2025Web App · Personal Brand · Full-Stack

CreativelyNanda.co.za

Portfolio & Digital HQ — The Website That Builds Itself

My personal portfolio, digital headquarters, and product platform — a magazine-inspired, AI-integrated website with a Notion template shop, poetry collection, blog, and AI assistant. Built with Next.js, Supabase, and PayFast.

Serving

African creative technologists

Market

Monthly recurring revenue

Problem

Generic portfolio problem

Result

72+ commits, 6 Notion templates live

The Problem

What needed solving

Generic developer portfolios fail to capture multidimensional creatives. A platform was needed that simultaneously showcases technical excellence, creative identity, and functions as a revenue-generating business.

The Solution

How I built it

A full-stack personal brand platform with editorial design aesthetics, a functional Notion template shop (PayFast integrated), published poetry collection, AI sales assistant, blog CMS, and PWA capabilities.

Build Journey

The goal from day one: not a static brochure. A cultural destination — the professional credibility of LinkedIn, the seamless commerce of a digital storefront, the literary community of a poetry platform, the editorial authority of a long-form publication, all in one. Every architecture decision was written with a rationale. PayFast over Stripe: Stripe doesn't process ZAR-denominated cards directly for SA merchants without complex setup. PayFast has ~60% market share in SA, supports EFT and instant EFT (dominant payment methods in ZA), and processes in Rand natively. For a site targeting SA students and entrepreneurs, Stripe adds friction and currency confusion. PayFast was always the correct choice for this market. Supabase over Firebase: Firestore's document model would require denormalising the product-order relationship that Postgres handles naturally with foreign keys and indexes. Supabase provides full PostgreSQL, Row Level Security at the database layer (orders readable by buyer, not other users), and signed Storage URLs for digital delivery — all without custom code. Zustand for the cart: the cart must persist across App Router navigations and survive browser refreshes. The critical pattern is skipHydration: true on the store, with rehydrate() called after mount — this prevents the 'cart flicker' where server HTML shows an empty cart but client state has items. TypeScript caught the PayFast signature bug before production: the PayfastPaymentData interface ensures every field passed to the signature generator is accounted for. A type error in the PayFast signature function would cause silent revenue loss. TypeScript strict mode on payment code costs nothing at build time; the same error in production costs revenue.

Cart skipHydration + PayFast field-order signature — production bugs caught
typescript
// Cart store — skipHydration pattern prevents SSR/client mismatch
// Without this: server renders empty cart, client rehydrates with items → layout shift

export const useCartStore = create<CartStore>()(
  persist(
    (set, get) => ({
      items: [],
      addItem: (item) => set((s) => {
        if (s.items.find(i => i.id === item.id)) return s; // No duplicates
        return { items: [...s.items, { ...item, quantity: 1 }] };
      }),
      removeItem: (id) => set((s) => ({ items: s.items.filter(i => i.id !== id) })),
      clearCart: () => set({ items: [] }),
      get total() { return get().items.reduce((sum, i) => sum + (i.price * i.quantity), 0); },
    }),
    {
      name: 'mirembe-cart',
      storage: createJSONStorage(() => localStorage),
      skipHydration: true, // Critical — prevents SSR/client cart flicker
    }
  )
);

// Call rehydrate() after mount — never on the server
useEffect(() => { useCartStore.persist.rehydrate(); }, []);

// PayFast signature — field ORDER matters; alphabetical sort BREAKS it
// This bug caused silent payment failures before the fix
export function generateSignature(data: PayfastPaymentData, passphrase: string): string {
  const params = Object.entries(data) // Insertion order — DO NOT .sort()
    .filter(([, v]) => v !== '' && v !== null)
    .map(([k, v]) => `${k}=${encodeURIComponent(String(v)).replace(/%20/g, '+')}`)
    .join('&');
  return md5(`${params}&passphrase=${encodeURIComponent(passphrase)}`);
}

What This Taught Me

  1. 1

    skipHydration: true on Zustand persist + rehydrate() after mount prevents the cart flicker in SSR/App Router applications

  2. 2

    PayFast signature is field-ORDER sensitive — alphabetical sort breaks it silently; this is not documented prominently in PayFast docs

  3. 3

    Supabase over Firebase: PostgreSQL + RLS + signed Storage URLs solves product-order-delivery in one platform

  4. 4

    PayFast over Stripe: ZAR native, EFT support, 60% SA market share — the correct payment gateway for the SA market

  5. 5

    TypeScript strict mode on payment code: the type error that catches a PayFast bug costs nothing at build time

  6. 6

    Arcjet composable middleware: bot detection + rate limiting in one API — less custom code, more security coverage

Tech Stack & Decision Rationale
01

Next.js 14

App Router, SEO, PWA

02

TypeScript

Type safety across all features

03

Supabase

Products, orders, blog, poetry database

04

Claude API

AI assistant for visitor engagement

05

PayFast

South African payment gateway for template sales

06

Resend

Transactional email delivery

07

Framer Motion

Editorial animation system

README.md — creativelynanda
📄 README.md
# CreativelyNanda.co.za
> Portfolio & Digital HQ — The Website That Builds Itself

## Project Context
**Category:** Web App · Personal Brand · 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                     # App Router, SEO, PWA
TypeScript                     # Type safety across all features
Supabase                       # Products, orders, blog, poetry database
Claude API                     # AI assistant for visitor engagement
PayFast                        # South African payment gateway for template sales
Resend                         # Transactional email delivery
Framer Motion                  # Editorial animation 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://creativelynanda.co.za
- GitHub: https://github.com/Nanda-Regine/CreativelyNanda.co.za
- Portfolio: https://creativelynanda.co.za/projects/creativelynanda

---
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