All work

Full-stack web application · 2026

Huuman Beats

A self-hosted e-commerce platform to sell beats, instrumentals, and sound kits.

Huuman Beats

Huuman Beats

A full-stack e-commerce platform for independent music producers to sell beats, instrumentals, and sound kits directly to artists.

Live: huumanbeats.com

Built with: Next.js 15 | React 19 | TypeScript | Prisma | PostgreSQL | Stripe | Cloudflare R2 | NextAuth.js | Zustand | Tailwind CSS


Overview

Huuman Beats is a self-hosted digital storefront that gives music producers full ownership of their sales pipeline. Buyers can preview beats with an in-browser audio player, choose from multiple license tiers, check out as a guest or registered user, and instantly receive their files and a legally binding license contract. The admin studio gives the producer complete control over products, pricing, orders, content, and branding without touching code.

The Problem

Most independent producers sell through third-party marketplaces like BeatStars or Airbit. While convenient, these platforms take a cut of every sale, limit branding options, and place your catalog alongside competitors. Producers who want to build a recognizable brand need their own storefront, but building one from scratch requires handling audio streaming, license management, digital delivery, payment processing, and a content management system – a significant engineering effort.

The Solution

A purpose-built e-commerce platform tailored specifically for beat sales. Rather than adapting a generic e-commerce template, every feature is designed around the workflows that producers and their customers actually need: auditioning beats by ear, selecting license tiers with different usage rights, receiving downloads in multiple formats, and getting a PDF contract attached to the purchase confirmation.

Tech Stack

Layer Technology Why
Framework Next.js 15 (App Router, RSC) Server components for fast initial loads; API routes co-located with the app
Language TypeScript, React 19 End-to-end type safety across client and server
Database PostgreSQL (Neon) + Prisma ORM 25+ models with complex relations; Prisma provides type-safe queries and migrations
Payments Stripe (Checkout, Subscriptions, Webhooks) PCI-compliant checkout, subscription billing, webhook-driven fulfillment
File Storage Cloudflare R2 (S3-compatible) Cost-effective object storage for audio files and deliverables; presigned URLs for secure access
Auth NextAuth.js v5 Credentials + Google OAuth, JWT sessions, role-based access control
State Zustand Lightweight client stores for cart (localStorage-persisted) and audio player (ephemeral)
Email Resend + Mailchimp Transactional emails (receipts, contracts, password resets) + newsletter capture
Styling Tailwind CSS Utility-first CSS with dark mode throughout
Validation Zod Runtime schema validation for all API inputs
PDF Generation pdf-lib Auto-generated license contracts embedded in purchase emails

Key Features

Storefront

  • Audio Preview Player – Global persistent player with play/pause, seek, volume, queue management, and loop mode. Streams tagged previews from R2 via signed URLs without exposing the untagged masters.
  • Multi-License Checkout – Each beat offers multiple license tiers (MP3 Lease, WAV Lease, Exclusive, etc.) with different prices and usage rights. Buyers pick a license before adding to cart.
  • Digital Delivery – Purchases unlock per-format download buttons (MP3, WAV, Stems/ZIP). Files are served through time-limited presigned URLs that expire after one hour.
  • PDF License Contracts – On purchase, a legally binding contract is auto-generated as a PDF with the buyer’s name, the beat title, the license terms, and a unique order reference. It’s attached to the confirmation email and available in the account dashboard.
  • Guest Checkout – Buyers can purchase without creating an account. A unique download token is generated and emailed, giving access to a dedicated download page. The confirmation email also includes a link to set a password and claim the account.
  • Subscription Memberships – Monthly or yearly membership plans powered by Stripe Subscriptions, with configurable download allowances.
  • Coupon Codes and Bulk Discounts – Percentage or fixed-amount coupons with usage limits and expiration dates. Configurable bulk discount rules (e.g., buy 2 get 1 free).
  • Exclusive License Clarity – Exclusive licenses display “Full ownership · Beat removed from store after purchase” across license selectors, beat cards, and the homepage comparison table. A tooltip on the comparison table explains the removal policy on hover.
  • Responsive Catalog UX – List/grid view toggle (defaulting to list on mobile, grid on desktop). Compact mobile beat rows show title, BPM, key, and tags in a dense two-line layout. Filter tags scroll horizontally on mobile instead of wrapping. Sort direction toggles between ascending and descending by re-clicking the active sort button, with a visual arrow indicator.
  • Blog – Built-in CMS for SEO content, producer tips, and announcements. Supports featured images, scheduled publishing, and per-post SEO metadata.

Admin Studio

  • Product Management – Full CRUD for beats and kits with multi-file asset uploads (artwork, tagged previews, untagged masters, WAV deliverables, stems), per-product license configuration, tag management, and drag-and-drop sort ordering.
  • Order Dashboard – View all orders with payment status, line items, and customer details.
  • Customer Management – Browse all customers with order history and CSV export.
  • License Templates – Global license templates with customizable terms stored as structured JSON. Each template defines which file formats are included.
  • Lead Capture – Configurable newsletter popup with trigger options (exit intent, scroll depth, time delay) and Mailchimp integration.
  • Upload Progress – File uploads (audio previews, masters, stems, artwork) display real-time progress bars using XHR-based tracking, essential for larger deliverables like stem archives.
  • Store Settings – Branding (logo, colors, fonts), hero section, navigation links, announcement bar, analytics IDs (GA4, Meta Pixel, TikTok), and bulk discount rules. All editable without redeployment.

Analytics & Conversion Tracking

  • GA4 Ecommerce Events – Full GA4 ecommerce funnel implemented via gtag: view_item on beat detail page load, add_to_cart on license selection, begin_checkout before Stripe redirect, and purchase on the verified success page. All events include standard ecommerce parameters (item ID, name, price, license category, transaction ID, order value). The purchase event only fires after the verify API confirms payment, preventing double-counting on refresh.
  • Google Ads Conversion Tracking – GA4 is linked to Google Ads and the purchase event is imported as a primary conversion. begin_checkout and add_to_cart are imported as secondary (observe-only) conversions. No additional tag code was required — the existing gtag setup handles both GA4 and Google Ads via the shared measurement ID.
  • Dynamic Landing Pages for Paid Search – Genre-specific ad groups target /beats?tag=trap, /beats?tag=hip-hop, etc. The beats page dynamically sets the <h1>, <title>, and meta description based on the active tag, so keyword → ad → landing page relevance is consistent and Google’s Quality Score reflects the actual page content.

SEO

  • Dynamic Sitemap – Auto-generated /sitemap.xml includes all published beats and blog posts with lastModified timestamps and priority values.
  • Robots.txt – Properly configured to allow public pages and block admin, API, and account routes.
  • Rich PDP Title Tags – Title tags are dynamically built from beat attributes: title, BPM, genre tags, and key (e.g., “Blackmail - 85 BPM Hip Hop, R&B Beat in F# Minor”). Genres go in the title; moods, hook availability, and custom descriptions go in the meta description to avoid duplication.
  • Keywords Meta Tag – Automatically populated from the beat’s tag names (genres, moods, instruments).
  • Open Graph and Twitter Cards – Product artwork and enriched titles/descriptions rendered as OG/Twitter meta tags for rich link previews when shared on social media.
  • JSON-LD Structured Data – Organization, Product (with pricing, BPM, key, hook availability as additionalProperty entries, and keywords), and Article schemas for Google rich results.

Architecture Highlights

Middleware-Based RBAC with Defense in Depth

Authentication is enforced at two layers. Next.js middleware intercepts requests to /admin/* and /account/* routes, redirecting unauthenticated users before the page even renders. API routes add a second check via a requireAdmin() helper that verifies the JWT session and role, ensuring that even direct API calls are protected. Three roles (BUYER, STAFF, PRODUCER_ADMIN) control access granularity.

Presigned URL Pattern for Secure File Operations

All file uploads and downloads flow through S3-compatible presigned URLs rather than proxying through the application server. For uploads, the admin client requests a presigned PUT URL from the API, then uploads directly to R2. For downloads, the API generates a time-limited GET URL (1 hour) and returns it to the client. This keeps large binary files off the serverless function and avoids Vercel’s 4.5 MB response body limit.

Client State with Zustand

Two Zustand stores handle client-side state without the boilerplate of Redux. The cart store persists to localStorage so items survive page reloads and browser sessions. The player store is ephemeral – it tracks the current track, queue, playback state, and volume, resetting on page refresh. Both stores expose simple hooks that components consume directly.

Webhook-Driven Order Fulfillment

Stripe webhooks drive the entire post-payment flow. When a checkout.session.completed event arrives, the webhook handler writes the order record and payment to the database, then immediately returns a 200 to Stripe. The heavy post-payment work — PDF contract generation, R2 upload, and confirmation email — runs in a Next.js after() callback, which executes after the response is finalized without blocking it. This keeps the webhook response time well within Stripe’s timeout window while still guaranteeing fulfillment. A fallback verify endpoint handles the rare case where the webhook races with the buyer’s success page redirect.

Challenges and Solutions

Audio Streaming on Vercel’s Serverless Platform

Problem: The original implementation proxied audio files through a Next.js API route so the stream URL wouldn’t expose the S3 key. On Vercel, serverless functions have a 4.5 MB response body limit, which silently truncated audio files mid-stream.

Solution: Replaced the proxy with a two-step flow. The API route generates a time-limited presigned R2 URL and returns it as JSON. The client-side audio player fetches this URL, then sets it directly as the <audio> element source. The browser loads audio straight from R2, bypassing the serverless function entirely. An additional fix was needed in the AWS SDK configuration to suppress x-amz-checksum-mode=ENABLED query parameters that Cloudflare R2 rejects on presigned URLs.

Prisma Decimal Serialization Breaking Cart Arithmetic

Problem: License prices stored as Decimal in PostgreSQL were serialized as strings when passed to client components via React Server Components. JavaScript’s + operator concatenated them instead of adding, producing NaN subtotals in the cart.

Solution: Applied explicit Number() coercion at every boundary where price values enter client-side arithmetic – in the Zustand cart store’s addItem, updateItemLicense, and getTotal methods, in the bulk discount calculator, and in the formatCurrency utility. This is a one-line fix per call site, but it required tracing every code path where a Prisma Decimal could reach a math operation.

www vs. Non-www Origin Mismatch in Production

Problem: The audio stream route included a referrer/origin check to prevent hotlinking. In production, Vercel served the site at www.huumanbeats.com, but the environment variables were set to huumanbeats.com (without www). The startsWith check failed, returning 403 Forbidden for every audio stream request. The debug instrumentation logs confirmed the mismatch immediately.

Solution: Updated the origin checker to automatically generate both www and non-www variants of every allowed origin, so the check passes regardless of which subdomain the browser uses. This is more robust than requiring exact env var configuration.

Stripe Webhook Failures in Production

Problem: After going live, Stripe reported repeated webhook delivery failures with “other errors” for all 11 attempts over several days. Three root causes compounded each other. First, the webhook endpoint was registered in Stripe as https://huumanbeats.com/api/webhooks/stripe (no www), but the production domain redirects non-www to www.huumanbeats.com. Stripe does not follow redirects — a 307 response counts as a failure. Second, the STRIPE_WEBHOOK_SECRET environment variable had never been added to Vercel (only to the local .env.local), so the signature verification step was throwing for every request. Third, even once those were fixed, the webhook handler was performing PDF generation, R2 uploads, and email sending synchronously before returning a response. The cumulative time caused the Prisma database connection to drop with Error { kind: Closed }, resulting in 500 responses.

Solution: Applied three targeted fixes. Updated the Stripe webhook endpoint URL to the canonical www domain. Added STRIPE_WEBHOOK_SECRET as a Production environment variable in Vercel. Refactored the handler to return 200 immediately after the essential database writes, moving PDF generation, R2 upload, and email sending into a Next.js after() callback that runs in the background. A fourth issue emerged when retrying the backlogged events: the verify endpoint had already created orders (as a fallback while the webhook was broken), so the webhook retry was hitting a unique constraint on stripeSessionId. An idempotency check at the top of the guest checkout handler resolves this gracefully.

Results

Huuman Beats is live at huumanbeats.com, providing a fully self-owned sales channel for an independent producer. The platform handles the complete lifecycle from discovery to delivery: browse and preview beats, select a license, check out via Stripe, receive files and a PDF contract by email, and download in the format you need. The admin studio gives the producer full control over catalog, pricing, content, and branding without any code changes or redeployment.

Screenshots