← Custom Builds Dashboard Workflows Custom Builds Community Billing
✦   Custom Build 01   ✦

The Client Portal
& Gallery Delivery System

The exact system running inside Moonlight and Lace Boudoir. Not a template. Not a mockup. The real build, handed to you with every file, every feature, and every line of code.

Difficulty: Advanced
Requires: Cloudflare · Netlify · VS Code · Claude or ChatGPT
Time to build: 2 days to 2 weeks depending on experience
Third party costs: ~$0–$9/mo
Overview

What This System Actually Does

This is a complete, password-protected client portal that lives on its own domain. Your client gets a login. She logs in, lands on her personal dashboard, and from there she has access to everything related to her session... her prep materials, her paperwork, her gallery, and her collection details.

The gallery is connected to Cloudflare R2 cloud storage. You upload her images from a photographer dashboard. The moment images are in her folder, her gallery comes alive. She can view, heart her favorites, watch a cinematic slideshow with music, see her images as wall art in a real room, and send her selections directly to you via pre-filled text message.

This is not a link to a Google Drive folder. This is not Pic-Time or Shootproof. This is your own branded system, on your domain, under your full control, for a fraction of the ongoing cost of any gallery delivery platform.

The portal has two sides. The client-facing side is what she sees when she logs in. The photographer dashboard is what you use to upload images, manage galleries, and send notifications to your clients.

Her gallery experience includes watermark protection on preview images, a favorites system that saves to the cloud in real time, a cinematic fullscreen slideshow with music, a wall art mockup viewer where she can place her image inside a real room, and a post-selection flow that walks her into your upgrade calculator and routes her directly into your ordering experience.

This is the full system. Nothing is hidden. Nothing is watered down. You get every file, every feature, every line of code, with placeholder content already in place so you know exactly what to swap.

Feature Breakdown

Every Feature, Explained

Here is exactly what this build does, broken down so you understand what you are building and what your client experiences at every step.

🔒

Login and Authentication

Built on Netlify Identity. Clients receive an invitation email and create their own password. You control access from your Netlify dashboard. No client can view the portal without your approval. Sessions persist so she does not have to log in every visit, but expire after a set period for security. Login is handled entirely by Netlify at no extra cost.

Personal Client Dashboard

Her home base after login. Shows her name, session information, quick-access buttons to every section of the portal, and a progress indicator showing where she is in the client journey. All content is pulled dynamically from her gallery record stored in Cloudflare R2, so each client sees their own personalized experience.

🖼

Gallery with Justified Layout

A cinema-quality masonry-style gallery that automatically adjusts row heights based on each image's aspect ratio. Portrait and landscape images flow together cleanly without awkward cropping. Works perfectly on both mobile and desktop. Images load lazily as she scrolls so even large galleries of 100+ images load without slowing down her device.

Favorites System (Cloud-Saved)

She taps the heart on any image to favorite it. Her favorites save to Cloudflare R2 in real time. If she closes her browser and comes back a week later, her hearts are still there exactly as she left them. A floating selection bar at the bottom shows her count in real time and lets her send selections when she is ready. No account, no app download, no extra steps for her.

Cinematic Slideshow with Music

A fullscreen experience that plays through her gallery with a slow Ken Burns zoom effect and gentle crossfades between images. Background music starts automatically at a soft volume. She can toggle music on or off, pause, skip forward or back, and use arrow keys on desktop. The slideshow ends gracefully. You choose your own royalty-free track from Pixabay and upload it to your R2 bucket.

🎬

Cinematic Reveal Player

A separate reveal experience (reveal.html) designed for in-person reveal appointments or a self-guided reveal she watches from home. Features per-image duration controls you set before sending, drag-and-drop image sequencing, and a cinematic full-bleed presentation mode. This is the experience she watches when she sees her images for the very first time.

💧

Watermark Protection

The watermark is controlled per gallery. Turn it on for preview galleries (unpurchased images), turn it off for delivered galleries. When on, a tiled semi-transparent watermark overlay covers every image in the grid, the lightbox, and the slideshow. Right-click to save, drag-to-desktop, and keyboard shortcuts are all blocked. An agreement gate appears before she can even enter the gallery requiring her to acknowledge your terms before viewing.

🔍

Lightbox Image Viewer

Clicking any image opens a full-resolution lightbox with smooth animation. She navigates with arrow keys or swipes on mobile. A counter shows her position in the gallery. On clean (purchased) galleries, a Download button appears for individual saves. A heart button lets her favorite directly from the lightbox. A "See it on your wall" button opens the wall art viewer for that specific image.

🖼

Wall Art Mockup Viewer

Her image placed inside a real room photo. She can drag the print, rotate it, and tilt it to see it at an angle on the wall. Multiple room backgrounds (bedroom, nightstand vignette, gallery wall) and multiple product sizes (8x10 bedside metal, 16x24, 20x30, 24x36, 40x60, and a wall gallery trio set) let her visualize exactly what a piece looks like before she commits. A CTA at the bottom of the viewer routes her directly into the ordering experience.

💰

Stop Moment and Upgrade Calculator

After she taps Send My Selections, the system checks whether she has favorited every image. If she has not, a Stop Moment screen appears showing her the images she is about to leave behind and offering her the option to keep them all before proceeding. After the stop moment, she enters an upgrade calculator where she can add wall art, albums, acrylic blocks, a USB, or upgrade her package. PA sales tax calculates automatically by ZIP code. Everything routes to your GHL order webhook.

📋

Ordering Experience

The ordering.html file is a full appointment-based ordering experience. It walks her through selecting her package, reviewing her selections, customizing physical products, choosing a payment structure, and submitting her order. The order data sends to your GHL webhook and triggers your fulfillment workflow. This file is large and has multiple routing sections for different package tiers.

📱

Push Notifications

When she saves the portal to her phone's home screen and enables notifications, she receives push alerts directly from you. You send notifications from your photographer dashboard... gallery ready, paperwork reminder, selection deadline reminder, order confirmation. A notification bell in her sidebar shows an unread badge. Full push delivery to the home screen requires VAPID key setup. In-portal notification delivery works without it. Instructions in Section 17.

📬

Notifications Inbox

A dedicated Notifications page inside her portal shows every message you have sent in reverse chronological order. Unread messages are marked. The sidebar bell badge updates automatically when she has unread messages and clears when she visits the page. She can see the full communication history from you without searching through texts or emails.

📦

Download All (Delivered Galleries)

On galleries with watermark turned off (purchased, delivered images), a Download All button appears. It bundles all images into a single ZIP file using JSZip, named with her first name and your studio name, and downloads directly to her device. Falls back to individual downloads automatically if the ZIP fails. Individual image download is also available inside the lightbox on clean galleries.

📸

Photographer Upload Dashboard

A password-protected drag-and-drop upload interface only you access. You select a client folder, drag in her images, set the gallery type (preview or clean delivery), add an expiry date, include a personal note, and publish. The gallery goes live immediately. No FTP client. No backend system. No third party gallery platform. Everything writes directly to your Cloudflare R2 bucket.

📊

Photographer Activity Dashboard

A separate dashboard showing you client activity across all galleries. Which clients have viewed their gallery, which images they opened, how many times, whether they sent selections, and whether they submitted an upgrade request. Activity logs write to R2 in real time. You always know exactly where each client is in the process without having to follow up manually.

Client Closet Browser

A filterable inventory of your studio wardrobe. Clients browse by category, view item details, see size ranges and descriptions, and note what is available before their session. You replace the placeholder product images and descriptions with your actual closet inventory. Full closet setup instructions in Section 18.

Full Prep Hub

Basics, Prep, and Arrival pages give your client everything she needs before her session. These pages contain your studio-specific prep instructions, what to bring, what to expect on session day, and how to arrive. You replace all placeholder content with your own. These are the pages that eliminate your prep emails and get clients showing up camera-ready.

📺

TV Welcome Page

A full-screen welcome display designed to run on a TV or monitor in your studio lobby or shooting area when a client arrives. Shows her name, a welcome message, and your studio branding. Update this page for each client from your dashboard before she arrives. Creates an immediate luxury first impression the moment she walks in the door.

💌

Branded Email Templates

Two fully built HTML email templates are included. One for gallery delivery (images-ready-email.html) and one for download delivery (images-downloadable-email.html). These are formatted HTML emails that render beautifully in any email client, match your portal branding exactly, and include your logo, buttons, and studio information. Copy them into your GHL email builder as custom HTML.

📝

Questionnaire and Survey Pages

A post-session questionnaire (questionnaire.html) and a post-delivery feedback survey (post-session-survey.html) are included in the portal. These are browsable pages within her client portal. Customize the questions and link them to your GHL forms or internal tracking system.

📖

Album Designer

An interactive album layout designer (album-designer.html) where clients can arrange their selected images into album spreads before their order is finalized. Helps clients visualize their album and gives you a clear direction for the album layout without a back-and-forth approval process.

Before You Begin

Read This Before You Start

This build will take days. Not hours.

This is not a template where you swap a logo and publish in 20 minutes. This is a real, functioning, custom-coded portal system with cloud storage, an image delivery pipeline, a login system, push notifications, a cinematic reveal experience, an ordering flow, and more than two dozen interconnected files. The real version runs live inside an active boudoir studio. Getting YOUR version running requires real time and real effort.

Realistic timelines

Already comfortable with Netlify, Cloudflare, and editing HTML: → 2 to 4 days of focused work sessions Some experience with web tools, new to code editing: → 4 to 7 days working with AI assistance throughout No prior experience with any of these tools: → 1 to 2 weeks, working methodically one section at a time This is not a reflection of your intelligence. It is a reflection of how complex this system actually is.

What will make this go smoothly

Work in phases. Do not try to do everything at once. The build walkthrough in Sections 9 through 13 breaks this into five distinct phases. Finish one phase, test it, and move to the next.

Test after every single change. Do not make 10 changes and then deploy. Make one change, deploy, check that it works, and then move on. This is how you avoid ending up with a broken system and no idea which change caused it.

Use Claude or ChatGPT for every question. No question is too small. If you do not understand something, ask. If something looks wrong, paste the code and ask. Section 14 shows you exactly how to do this effectively.

The photographers who succeed with this build all have one thing in common

They do not try to rush it. They block out real time on their calendar, they work through one step at a time, and they treat every stuck moment as a question to ask AI rather than a reason to give up. Every piece of this system is solvable. None of it requires a computer science degree. It requires patience and a willingness to paste code into a chat box and read the response.

What You Need to Set Up

Accounts You Will Need to Create

All of these are free to create. Some have optional paid tiers. Here is exactly what each one is for, how to sign up, and what you will need from each one during the build.

Real Talk on Costs

Third Party Costs, Honestly

These costs have nothing to do with Boudoir Automations

These are third party services you sign up for directly. The prices below are accurate as of the time this lesson was written. Always verify current pricing on each platform's website before signing up.

Cloudflare R2

Free for the first 10GB of storage and 10 million read operations per month. After that, storage costs $0.015 per GB. For context... 500 full-resolution boudoir images at an average of 8MB each is about 4GB total. One typical client gallery is well under 1GB. You would need a very high volume of active galleries simultaneously to exceed the free tier.

Most studios using this system pay $0 to $3 per month on Cloudflare R2. Even at full studio capacity with 10 to 15 active client galleries at once, you are unlikely to exceed $5/month.

Netlify

Free tier gives you 300 build minutes per month and 100GB of bandwidth. Each time you deploy a change (drag a new folder), it uses build minutes. For a stable live studio portal where you are making occasional updates, free works perfectly.

If you are actively developing and redeploying many times per day during setup, you may approach the monthly limit. The $9/month Pro plan removes this concern. Start free and upgrade only if you need to. Once the portal is live and stable, redeployments become infrequent.

Most studios pay $0 to $9 per month on Netlify depending on whether they are actively developing.

Total ongoing cost: $0 to $12 per month

Compare this to a dedicated gallery delivery platform like Shootproof ($10 to $45/month) or Pic-Time ($10 to $20/month plus storage fees), and this system pays for itself with a single month of use. You own it. There are no per-client fees. No storage caps that force you to delete client work. No branding you cannot remove. This is your system, permanently.

Your Computer Setup

Tools to Install Before You Start

Install these before you open a single file. Having the right tools set up from the beginning saves you from frustrating moments mid-build.

01

Visual Studio Code (required)

Go to code.visualstudio.com. Download the version for your OS (Mac or Windows). Install it. This is your code editor for the entire build. When you open your portal folder in VS Code, you will see all files in the left sidebar and can click any one to open and edit it.

02

A modern browser with developer tools (required)

Chrome or Edge are both excellent for this. Firefox also works. Safari works but its developer tools are slightly different. During the build, you will use the browser's developer console (press F12) to see error messages when something breaks. This is your diagnostic tool throughout the build.

03

A credentials document (required)

Before you create a single account, open a Google Doc, Notes file, or any text document and title it "Portal Build Credentials." Every URL, key, password, and token you generate goes in here immediately. You will create credentials across Cloudflare and Netlify. If you lose a key mid-build, you usually have to revoke it and generate a new one, which can break things already in place.

Example of what to track: Cloudflare R2 Public URL: https://pub-xxxx.r2.dev Cloudflare R2 Endpoint: https://xxxx.r2.cloudflarestorage.com Cloudflare Account ID: [found in right sidebar of CF dashboard] Cloudflare R2 Access Key ID: [from R2 API token creation] Cloudflare R2 Secret Access Key: [from R2 API token creation — copy immediately] Netlify Site URL: [your-portal.netlify.app] Netlify Custom Domain: [vip.yourstudio.com] Portal Admin Password: [what you set in dashboard.html]
04

AI tool open in a browser tab (required)

Before you start Phase 1, open claude.ai or chat.openai.com and keep it in a tab for the entire build. Every question goes here. Every error goes here. Every placeholder you are unsure about goes here. This is your co-developer for the entire project.

The Code Files

What Is in Every File

Here is every file in the portal package and exactly what it does. Do not be overwhelmed by the list. You will only need to actively edit a handful of them to make this yours. The rest either work automatically or contain content you customize at your own pace.

portal/ ├── index.html ← root redirect — sends visitors to login.html automatically ├── login.html ← client login page powered by Netlify Identity — do not edit heavily ├── dashboard.html ← client home base after login — shows her name, session info, quick links ├── gallery.html ← THE MAIN GALLERY — justified grid, hearts, lightbox, slideshow, wall viewer, watermark, SMS pre-fill, upgrade calculator (largest file, most credentials) ├── reveal.html ← cinematic reveal player — per-image duration, drag-and-drop sequencing, full-bleed presentation mode ├── ordering.html ← full ordering experience — package selection, product customization, payment routing to GHL webhook (very large file) ├── collection.html ← her investment and collection summary — your package names, pricing, payment link URLs ├── notifications.html ← her notification inbox — messages you send from the photographer dashboard ├── basics.html ← session basics prep page — what to know, what to expect ├── prep.html ← full session prep guide — skin care, what to bring, what to avoid ├── arrival.html ← day-of arrival instructions — parking, schedule, what happens when she arrives ├── closet.html ← client closet browser — filterable wardrobe inventory with your actual items ├── bonus.html ← bonus sets page — additional set options or complimentary add-ons ├── body-love-workbook.html ← body love confidence workbook — pre-session mindset resource for clients ├── questionnaire.html ← post-session client questionnaire — links to your GHL form ├── post-session-survey.html ← post-delivery feedback survey — review and testimonial capture ├── album-designer.html ← interactive album layout designer — she arranges images into spreads ├── ipa-system.html ← investment presentation system — in-person or self-guided ordering presentation ├── welcome.html ← TV welcome display — full-screen for studio lobby or shooting area on arrival day ├── go.html ← redirect utility — used for short links and routing ├── images-ready-email.html ← branded HTML email template for gallery delivery notification ├── images-downloadable-email.html ← branded HTML email template for download delivery notification ├── portal-nav.js ← shared navigation — UPDATE THIS FIRST, your logo and studio name applies to every page ├── push-client.js ← push notification client script — handles browser subscription registration ├── cloudflare-worker-push.js ← Cloudflare Worker script — deploy this to Cloudflare Workers (not Netlify), handles push delivery ├── sw-push.js ← service worker — handles push notifications in the background on her phone └── _headers ← Netlify security headers — leave this alone unless you know what you are changing

The files you MUST edit for the system to function

portal-nav.js ... edit this FIRST. Your logo URL and studio name go here. It drives the navigation on every single page.

gallery.html ... your R2 public URL, R2 endpoint, R2 access key, R2 secret key, your watermark URL, your music URL, your phone number for SMS pre-fill, and your studio name. Nothing in the gallery works without correct R2 credentials.

reveal.html ... your R2 credentials and studio branding. Must match gallery.html credentials exactly.

ordering.html ... your GHL order webhook URL, your collection package names, prices, and your studio branding. Large file with multiple routing sections.

collection.html ... your pricing, package names, and GHL payment link URLs for each package.

Files you can customize at your own pace

closet.html, basics.html, prep.html, arrival.html, bonus.html, body-love-workbook.html, questionnaire.html, post-session-survey.html, and welcome.html all contain placeholder content that you can replace gradually as you have time. The portal functions without them being fully customized. Get the gallery working first, then come back to these.

Your Customization Checklist

Everything You Need to Replace

Every placeholder in the code is labeled clearly inside brackets. Use Ctrl+Shift+F in VS Code to search for the bracket character [ and see every placeholder across all files at once. Here is what each one means and where to find the value it needs.

[YOUR STUDIO NAME]

Your full studio name as you want it displayed to clients. Appears in page titles, footers, SMS pre-fill messages, and email templates. Found in almost every file.

[YOUR LOGO URL]

The direct URL to your logo image. Must be a publicly accessible image URL ending in .png or .jpg. Host it on your GHL CDN, Cloudflare R2, or any image hosting service. Found in portal-nav.js and multiple pages.

[YOUR PHONE]

Your studio phone number in plain digits (no dashes or spaces needed in the SMS link format). Appears in SMS pre-fill buttons throughout the gallery. When she taps Send My Selections, a text to this number pre-fills automatically.

[YOUR EMAIL]

Your studio email address for footer contact links and any contact forms.

[YOUR ADDRESS]

Your studio address displayed in footer areas of gallery and dashboard pages.

[YOUR DOMAIN]

Your portal domain once connected. Example: vip.yourstudio.com or yourstudio.netlify.app. Used in redirect logic and internal links.

[YOUR R2 PUBLIC URL]

Your Cloudflare R2 bucket public URL. Starts with https://pub- and ends with .r2.dev. Found in Cloudflare → R2 → your bucket → Settings → Public URL. Goes in gallery.html, reveal.html, and dashboard.html as the variable R2_PUB.

[YOUR R2 ENDPOINT]

Your Cloudflare R2 storage endpoint for authenticated uploads. Found in R2 → your bucket → Settings → Bucket Details. Looks like https://accountid.r2.cloudflarestorage.com. Goes in gallery.html and the upload dashboard as the variable R2_EP.

[YOUR R2 ACCESS KEY]

Your Cloudflare R2 API Access Key ID. Generated under R2 → Manage API Tokens. Goes in gallery.html as the variable R2_KEY. This is not your Cloudflare account login password.

[YOUR R2 SECRET KEY]

Your Cloudflare R2 API Secret Access Key. Copy it immediately when generated because Cloudflare only shows it once. Goes in gallery.html as the variable R2_SEC. Keep this private.

[YOUR WATERMARK URL]

Direct URL to your watermark PNG file uploaded to Cloudflare R2. The file should be a PNG with a transparent background. Upload it to the root of your galleries bucket, then copy its public URL. Goes in gallery.html as the variable WM_URL.

[YOUR MUSIC URL]

Direct URL to your royalty-free MP3 file uploaded to Cloudflare R2. Upload your Pixabay MP3 to the root of your galleries bucket, then copy its public URL. Replaces the audio src tag inside gallery.html.

[YOUR GHL WEBHOOK URL]

Your GoHighLevel order webhook URL. Used in ordering.html to receive order submissions. Found in GHL under Automation → Webhooks. If you do not have a GHL webhook set up yet, you can temporarily use a free webhook testing service like webhook.site while building, and swap in your real URL when your GHL workflow is ready.

[YOUR PACKAGE NAMES]

Your collection package names as you want them to appear to clients. Found in collection.html and ordering.html. Replace every instance of the placeholder package names with your actual studio collection names.

[YOUR PAYMENT LINKS]

Your GHL payment link URLs for each package. These are the links that send clients to your payment page after they select a package. Found in collection.html and ordering.html. Generate these in GHL under Payments → Payment Links.

Keep Your R2 Keys Private

Your R2 Access Key and Secret Key give write access to your storage bucket. Do not paste them into social posts, do not share them in group chats, and do not commit them to a public GitHub repository. They live inside your HTML files on your deployed Netlify site. Since the site is deployed (not a public repo), the keys are not exposed as raw source to visitors. Be mindful of who you share your code files with.

Phase 1 of 5

Set Up Cloudflare

Do not touch a code file yet. Set up your cloud storage first. Everything depends on this being correct before you deploy anything.

Have your credentials document open. You will copy values into it throughout this phase. Do not skip this step or you will lose keys.

1.1

Create your Cloudflare account

Go to cloudflare.com. Click Sign Up. Enter your email and a password. Verify your email. You do not need to add a domain or website. Just create the account and log in.

1.2

Create your R2 bucket

In your Cloudflare dashboard, find R2 Object Storage in the left sidebar. If you don't see it, look for Storage or click the hamburger menu. Click Create Bucket. Name it exactly: galleries (lowercase, no spaces, no hyphens). Choose your region as closest to you. Click Create Bucket.

1.3

Enable public access and copy your public URL

Inside your galleries bucket, click the Settings tab. Scroll to Public Access. Click Allow Access. A public URL will appear that starts with pub-. Copy it and paste it into your credentials document as "R2 Public URL." This URL is how every image in the portal is served to clients.

1.4

Copy your R2 endpoint URL

Still in the Settings tab of your bucket, find Bucket Details. There will be an S3-compatible endpoint URL. It looks like https://accountid.r2.cloudflarestorage.com. Copy it to your credentials document as "R2 Endpoint."

1.5

Create your R2 API token

Go back to the main R2 page (click R2 in the left sidebar, not your bucket). Click Manage API Tokens in the top right. Click Create API Token. Name it "Portal." Under Permissions, select Object Read and Write. Under Specify Bucket, select your galleries bucket only. Click Create API Token.

On the next screen, you will see your Access Key ID and your Secret Access Key. Copy both of these immediately. The secret key is never shown again after you leave this screen. Paste both into your credentials document.

1.6

Upload your watermark and music to R2

Go into your galleries bucket and click Upload. First, upload your watermark PNG file (see Section 15 for how to make one). Then upload your Pixabay music MP3 (see Section 16 for how to find one). Both files should sit in the root of the bucket, not inside any folder. After uploading each file, click it and copy its public URL. Add both to your credentials document as "Watermark URL" and "Music URL."

Phase 1 complete when you have all of these:

✓ R2 Public URL (starts with pub-) ✓ R2 Endpoint URL (contains r2.cloudflarestorage.com) ✓ R2 Access Key ID ✓ R2 Secret Access Key ✓ Watermark URL (public link to your PNG in the bucket) ✓ Music URL (public link to your MP3 in the bucket)
Phase 2 of 5

Set Up Your Code Files

Now you open your portal files and put your credentials and information in. Work through these in the order listed. Do not skip files and circle back later.

2.1

Open the portal folder in VS Code

Open Visual Studio Code. Go to File → Open Folder. Navigate to and select the portal folder you downloaded from this page. All your HTML files appear in the Explorer panel on the left.

2.2

Edit portal-nav.js first

Click portal-nav.js in the left sidebar. This file controls the navigation that appears on every single page. Find and replace:

Your logo URL → the direct image URL to your studio logo Your studio name → your studio name as it appears in the nav

Save the file with Ctrl+S or Cmd+S. Updating this file once applies your branding to the entire portal navigation automatically.

2.3

Edit gallery.html — credentials block

Open gallery.html. Press Ctrl+F or Cmd+F and search for R2_PUB. You will find a variable block near the top of the script section. Replace each value with the credentials from your credentials document:

// Find this block and replace every placeholder: var R2_PUB = '[YOUR R2 PUBLIC URL]'; var R2_EP = '[YOUR R2 ENDPOINT]'; var R2_KEY = '[YOUR R2 ACCESS KEY]'; var R2_SEC = '[YOUR R2 SECRET KEY]'; var R2_BKT = 'galleries'; var WM_URL = '[YOUR WATERMARK URL]';

Then find the audio tag and replace the music URL:

<audio id="ss-audio" src="[YOUR MUSIC URL]" loop preload="auto"></audio>

Then find and replace your phone number (search for the SMS link format), your studio name, your logo URL, and your address. Save the file.

2.4

Edit reveal.html — credentials block

Open reveal.html. Search for R2_PUB and replace the same credential block with the same values you used in gallery.html. The credentials must match exactly. Also replace your studio name and logo URL. Save.

2.5

Edit ordering.html — webhook and packages

Open ordering.html. This is a large file. Search for GHL_WEBHOOK or ORDER_WEBHOOK and replace the placeholder with your GHL order webhook URL. Then search for your package name placeholders and replace with your actual collection names and prices. Search for payment link placeholders and replace with your GHL payment link URLs. Save.

If you do not have your GHL webhook set up yet, use webhook.site (a free temporary URL) as a placeholder so you can test the rest of the system. Swap in your real GHL webhook when your workflow is ready.

2.6

Edit collection.html — pricing and packages

Open collection.html. Replace your package names, prices, and payment link URLs. This is the page where she reviews her investment options. Make sure the package names here match exactly what appears in ordering.html.

2.7

Do a global search for remaining placeholders

In VS Code, press Ctrl+Shift+F (Windows) or Cmd+Shift+F (Mac) to open the global search. Search for the [ character. This will show you every remaining placeholder across all files. Work through each one. Some are in prep pages and closet.html, which you can fill in later. But make sure gallery.html, reveal.html, ordering.html, and collection.html have zero remaining placeholders.

Phase 3 of 5

Deploy to Netlify

3.1

Create your Netlify account

Go to netlify.com. Click Sign Up. You can sign up with email or connect via Google. Once inside, you land on the Teams dashboard.

3.2

Deploy your portal folder

Click Add New Site → Deploy Manually. A drag-and-drop zone appears. Open your file explorer or Finder, navigate to your portal folder, and drag the entire folder into the Netlify drop zone. Do not zip it. Drag the folder itself. Netlify will upload all files and deploy them. Within 30 to 60 seconds, it gives you a live URL like random-words.netlify.app. Click the URL to see your portal live.

3.3

Enable Netlify Identity

In your Netlify dashboard, click your site name. Click Site Settings at the top. Find Identity in the left sidebar. Click Enable Identity. Under Registration preferences, set to Invite Only. This activates the client login system. Without this step, no one can log in to the portal.

3.4

Test the login system with your own email

In Netlify, go to Identity. Click Invite Users. Enter your own email address and click Send. Check your email for the invitation. Click the link in the email, set a password, and you will be logged in to your portal. Navigate through each page to make sure everything loads correctly. If something shows a blank page or an error, press F12, check the Console tab for red errors, and bring them to Claude or ChatGPT.

3.5

Connect your custom domain

In Site Settings → Domain Management → Add Custom Domain, enter the subdomain you want (like vip.yourstudio.com). Netlify shows you the DNS records to add in your domain registrar. Log in to wherever you bought your domain (GoDaddy, Namecheap, Cloudflare, etc.) and add the CNAME or A record exactly as Netlify instructs. DNS propagation takes anywhere from 5 minutes to 48 hours. Netlify automatically provisions your free SSL certificate once the domain resolves. Until then, use the netlify.app URL.

3.6

How to redeploy after making changes

Every time you make a change to any file in VS Code and want to see it live, save the file, then go back to Netlify. Under Deploys, click the Deploy Manually option and drag your updated folder in again. Wait 30 to 60 seconds, then hard refresh your browser with Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac). Do not use a regular refresh. Hard refresh clears the cached version so you see the actual updated page.

Phase 4 of 5

Customize Every Page

Now that the core system is live and tested, go through each page and make it fully yours. Work through these in whatever order makes sense for your studio's priorities.

4.1

dashboard.html — client home base

Replace all placeholder studio name, logo URL, and welcome messaging with your own. This is the first page she sees after login. It should feel immediately like YOUR studio. Replace any generic language with your voice and your brand.

4.2

basics.html, prep.html, arrival.html — prep hub

Open each of these and replace all placeholder studio information and prep content with your own. Your specific prep instructions, what you tell clients about skin care, what to bring, how to find the studio, where to park, and what to expect when they arrive. These pages eliminate your prep emails. Make them complete and detailed.

4.3

closet.html — client wardrobe

Replace every placeholder product image URL and product description with your actual closet inventory. Photograph your pieces, upload the images to your R2 bucket inside a folder called closet, copy each image URL, and paste it into the corresponding item block. Full closet setup instructions are in Section 18.

4.4

welcome.html — TV display

Customize the welcome page with your logo, branding colors, and the welcome message you want displayed when a client arrives at your studio. This page is designed to run on a TV or monitor. Update it before each client's arrival day to show her name.

4.5

images-ready-email.html and images-downloadable-email.html

Open each email template, replace the placeholder logo URL, studio name, and any messaging with your own. Then copy the full HTML from each file and paste it into GHL as a custom HTML email template. These are the emails your clients receive when their gallery is ready.

Phase 5 of 5

Test Everything

Do not send a client to this portal until you have tested every step of the experience yourself, from login through selection submission. Use a test gallery with your own images before going live with a real client.

5.1

Create a test client gallery

From your photographer upload dashboard (your portal URL /gallery or however the dashboard is routed), create a folder for a test client. Name it something like "test-client." Upload 10 to 15 test images into that folder. Set the gallery type to Preview and turn watermark on. Note the exact folder name because you will need it to access the test gallery.

5.2

Test the full client experience

Log in to the portal as your test client account. Navigate to gallery.html with the test client folder. Verify the watermark appears on every image. Open the lightbox. Navigate between images with arrow keys. Open the slideshow and confirm music plays. Open the wall art viewer and try moving the image in a room. Heart several images. Click Send My Selections and go through the stop moment, upgrade calculator, and ordering flow. Verify the order submission reaches your GHL webhook (or webhook.site if you are using a temp URL).

5.3

Test on your phone

Open the portal on your phone using Safari (iOS) or Chrome (Android). Navigate through every page. Check that the gallery layout looks correct, images are full-width, and buttons are tappable. Add the portal to your home screen (Share → Add to Home Screen on iOS) and verify it opens like an app. If a push notification prompt appears, allow it and send yourself a test notification from the photographer dashboard.

5.4

Test the clean delivery experience

Go back to the photographer dashboard and change the test gallery to clean delivery with watermark off. Reload the gallery as the client and verify the watermark is gone, the agreement gate does not appear, and the Download All button appears. Test the download to confirm it bundles images into a ZIP correctly.

5.5

Invite a real test client

Before going live with a paying client, invite a friend or colleague via Netlify Identity and have them go through the full experience on their own device without any guidance from you. Note anything confusing, anything that breaks, or anything that does not match what you intended. Fix those things, redeploy, and test again. Only go live with paying clients once you are fully satisfied with the experience end to end.

Working With AI

How to Use Claude or ChatGPT Throughout This Build

This build will take days. Not hours.

This is not a 20-minute implementation. This is a real, functioning, custom-coded system with cloud storage, login, push notifications, a cinematic reveal player, and a full ordering experience. Getting YOUR version live can take anywhere from 2 days to 2 weeks depending on your starting point. That is completely normal. That is how this system was built.

Keep Claude or ChatGPT open the entire time. Work through one step at a time. Test after every change. Use AI for every question, no matter how small it seems.

01

Which AI to use and what plan you need

Claude (claude.ai) is recommended. The paid Claude Pro plan ($20/month) gives you a large context window so you can paste entire files like gallery.html without hitting a character limit. Free tier has smaller limits and may cut off large files mid-paste.

ChatGPT (chat.openai.com) Plus ($20/month) with GPT-4o also works well. Either will get you through this build.

Set up your workspace like this:

Tab 1 → Claude or ChatGPT (open the entire time) Tab 2 → Your live Netlify portal (for testing) Tab 3 → Netlify dashboard (for redeploying) Tab 4 → Cloudflare dashboard (for R2 management) Desktop → VS Code with your portal folder open
02

How to paste code into Claude or ChatGPT

For sections of code (a few lines to a few hundred lines), copy and paste directly into the chat. For large files like gallery.html or ordering.html, you have two options.

Option A: Copy the entire file contents and paste into the chat, then ask your question. Most paid AI plans handle files this size without issue.

Option B (Claude only): Drag and drop the file directly into the Claude chat window. It reads the whole file without you having to copy it.

Example prompt when pasting a full file: "Here is my gallery.html file. I need to find where to replace my Cloudflare R2 credentials. Can you show me the exact variable names, tell me where they appear in the file, and confirm what format each value should be in?" [paste the entire file contents below]

More context is always better. Pasting the whole file is almost always better than pasting a small piece, because the AI understands how everything connects.

03

When something breaks after deploying

Open your browser. Press F12. Click the Console tab. Any red text is an error. Copy all of it.

Prompt for browser console errors: "I deployed my client portal to Netlify and something is not working. Here is the error in my browser console (F12 → Console tab): [paste every red error message] Here is the section of code that seems related (or the full file): [paste the relevant section or full file] What is causing this and what exactly do I need to change to fix it?"

After getting the fix: make the change in VS Code, save, drag the updated folder to Netlify, wait 30 to 60 seconds, then hard refresh with Ctrl+Shift+R or Cmd+Shift+R.

04

When you want to change how something looks

All visual styling is in the CSS section of each file, between the <style> and </style> tags near the top. You do not need to understand CSS to change it with AI help. Describe what you want and paste the CSS section.

Prompt for visual changes: "I want to change the gallery sidebar button color from gold to a deep burgundy. Here is the full CSS section from my gallery.html: [paste the contents between the style tags] Which rule controls the sidebar button color, what is the current value, and what should I change it to for a deep burgundy (#6B1A2A)?"
05

When you don't understand a placeholder

Prompt for placeholder clarification: "I found this in my gallery.html file: var R2_EP = '[YOUR R2 ENDPOINT]'; I have a Cloudflare R2 account and I created a bucket called galleries. I am not sure what the R2 Endpoint is or exactly where to find it in the Cloudflare dashboard. Can you walk me through finding it step by step?"
06

When you want to add or remove something from a page

Prompt for adding or removing features: "Here is my closet.html file. I currently have 12 product items. I want to add 3 more items in a category called Robes. Can you show me one example of the code block for a single item, and write out the 3 new Robe items using these details: Item 1: Ivory Silk Robe, sizes S-XL, available in studio Item 2: Blush Lace Robe, sizes S-L, limited availability Item 3: Black Satin Robe, sizes S-2XL, available in studio"
07

When you get a response you don't fully understand

Ask for clarification. You do not need to pretend you understand the answer. Say exactly what you are confused about.

Prompt when an AI answer is unclear: "You said to 'replace the var block in the script tag.' I am not sure exactly where the script tag starts and ends in my file. Can you show me a screenshot-style example of exactly what line I should be looking at and what the before and after version of that specific section should look like?"
08

Keeping your work safe as you go

Every time you make a significant set of changes that works correctly, make a backup copy of those files before making more changes. Name backups something like gallery-working-v1.html so you can always go back. When you are deep in a change and something breaks, having a working backup saves you from having to redo all your previous work.

And when you get truly stuck and cannot figure out what is wrong even with AI help: take a break, come back fresh, and start over from your last working backup. Fresh eyes catch things that exhausted eyes miss every time.

Starting Your Build With AI

Everything to Give Claude or ChatGPT Before You Start

Before you touch a single file, start your AI conversation with this exact setup message. The more context you give upfront, the fewer back-and-forth clarifications you need later. This list covers every piece of information the AI will need to help you swap placeholders, fix errors, and customize this system end to end.

How to start the conversation

Open Claude or ChatGPT. Start a new conversation. Upload the ZIP file you downloaded from this page (drag it directly into the chat window on Claude, or use the paperclip attachment button on ChatGPT). Then paste the message below, filling in every blank with your actual information. Send it all at once before asking anything else. This becomes the AI's reference document for your entire build.

Your opening message to Claude or ChatGPT — copy this, fill in every blank, send it first
I am building a custom client portal and gallery delivery system for my boudoir photography studio. I have downloaded the code files from Boudoir Automations Custom Build 01 and I need your help customizing every placeholder with my studio's real information, fixing errors as they come up, and getting this fully deployed to Netlify. I will be sharing files with you throughout this build. Here is everything about my studio. Use this as your reference for the entire conversation. ━━━ STUDIO IDENTITY ━━━ Studio name (full): [e.g. Luxe and Lace Boudoir] Studio name (short/casual): [e.g. Luxe and Lace] Studio LLC name (legal): [e.g. Luxe and Lace Boudoir LLC] My first name: [e.g. Sarah] My full name (legal): [e.g. Sarah M. Johnson] Studio website domain: [e.g. luxeandlaceboudoir.com] Portal subdomain I want: [e.g. vip.luxeandlaceboudoir.com OR luxelace.netlify.app] ━━━ CONTACT INFORMATION ━━━ Studio phone (10 digits, no spaces): [e.g. 8005550100] Studio phone (formatted display): [e.g. 800-555-0100] Studio email: [e.g. hello@luxeandlaceboudoir.com] Studio street address: [e.g. 123 Main Street, Suite 4] Studio city: [e.g. Nashville] Studio state: [e.g. TN] Studio ZIP code: [e.g. 37201] Studio city + state: [e.g. Nashville, TN] Studio city + state + ZIP: [e.g. Nashville, TN 37201] Studio full address (one line): [e.g. 123 Main Street, Suite 4, Nashville, TN 37201] ━━━ LOGO ━━━ Logo image URL (direct link ending in .png or .jpg): [e.g. https://assets.cdn.filesafe.space/YOURID/media/YOURFILEID.png] How to get this: In GHL go to Settings → Media Storage, find your logo file, click it, and copy the direct URL. OR upload your logo to your Cloudflare R2 bucket and copy the public URL. ━━━ CLOUDFLARE R2 ━━━ R2 public URL (starts with pub-): [e.g. https://pub-abc123.r2.dev] R2 endpoint (for uploads): [e.g. https://abc123def456.r2.cloudflarestorage.com] R2 Access Key ID: [e.g. abc123...] R2 Secret Access Key: [e.g. abc123... — copy it immediately when generated, Cloudflare only shows it once] R2 bucket name: galleries (leave this as "galleries" — the system is built expecting this exact name) Watermark file URL (your PNG uploaded to R2 root): [e.g. https://pub-abc123.r2.dev/your-watermark.png] Music file URL (your MP3 uploaded to R2 root): [e.g. https://pub-abc123.r2.dev/your-slideshow-music.mp3] ━━━ NETLIFY ━━━ My Netlify site URL (given after first deploy): [e.g. https://lush-rose-abc123.netlify.app] Custom domain I am connecting (if any): [e.g. vip.luxeandlaceboudoir.com] ━━━ GOHIGHLEVEL ━━━ GHL Location ID (your unique GHL account ID): [e.g. aBc123XyZ — found in GHL under Settings → Business Profile → Location ID] GHL Order Webhook URL: [e.g. https://services.leadconnectorhq.com/hooks/YOURID/webhook-trigger/YOURTRIGGERID] How to get this: In GHL go to Automation → New Workflow → Trigger: Inbound Webhook. GHL generates the URL. Copy it. GHL form embed URL for paperwork/contracts (if you use GHL forms in the portal): [e.g. https://api.leadconnectorhq.com/widget/form/YOURFORMID] How to get this: In GHL go to Sites → Forms → your form → Embed → copy the iframe src URL. ━━━ MY COLLECTION PACKAGES AND PRICING ━━━ Replace the example packages below with your EXACT package names and prices. If you have different packages than this list, tell me and we will rewrite the package array together. Package 1 name: [e.g. 3 Image Digital Collection] Price: [e.g. $1,400] Images included: [e.g. 3] Package 2 name: [e.g. 20 Image Digital Collection] Price: [e.g. $2,400] Images included: [e.g. 20] Package 3 name: [e.g. 40 Image Digital Collection] Price: [e.g. $3,600] Images included: [e.g. 40] Package 4 name: [e.g. Full Gallery] Price: [e.g. $4,200] Images included: [all] Package 5 name: [e.g. Crave Collection] Price: [e.g. $2,800] Includes: [e.g. 4 images + 2 acrylic blocks] Package 6 name: [e.g. Mesmerize Collection] Price: [e.g. $5,400] Includes: [e.g. album + metal print + all digitals] Payment plan threshold (minimum order price to qualify for a payment plan): [e.g. $1,500 — orders below this must pay in full] Deposit percentage for payment plans: [e.g. 25% deposit, remainder split into monthly payments] ━━━ WALL ART PRODUCTS AND PRICING ━━━ These appear in the wall art upgrade calculator and ordering flow. List every physical product you offer and its price. [e.g.] 16x24 metal print: $1,400 20x30 metal print: $1,600 24x36 metal print: $1,900 40x60 metal print: $2,800 8x10 bedside metal: $600 Acrylic block: $400 Signature album: $1,800 USB drive (all images): $300 Wall gallery trio (3): $2,200 ━━━ GHL PAYMENT LINKS ━━━ These are the direct payment link URLs for each package (generated in GHL under Payments → Payment Links). Clients are sent here after selecting their package in the ordering flow. Package 1 payment link: [paste full URL] Package 2 payment link: [paste full URL] Package 3 payment link: [paste full URL] Package 4 payment link: [paste full URL] Package 5 payment link: [paste full URL] Package 6 payment link: [paste full URL] Payment plan link (if separate): [paste full URL] ━━━ GALLERY DELIVERY TIMELINE ━━━ How many days after the session are images typically delivered? [e.g. 7] (used in messaging throughout the portal) ━━━ SALES TAX ━━━ Do you charge sales tax on physical products? [Yes / No] If yes, what is your state and tax rate? [e.g. Tennessee, 9.75%] Note: The original code has Pennsylvania ZIP-code-based tax detection built in. If you are NOT in Pennsylvania, tell me and I will rewrite the tax logic for your state. If you do NOT charge sales tax, tell me and I will remove the tax calculation entirely. ━━━ PUSH NOTIFICATIONS (optional — advanced) ━━━ Do you want to set up push notifications to your client's phone home screen? [Yes / No] If yes, you will need VAPID keys. I will walk you through generating them when we get to that step. If no, I will disable the push subscription prompt so clients are not asked to allow notifications. ━━━ CLOUDFLARE WORKER (optional — for push and order routing) ━━━ Do you want to deploy the Cloudflare Worker for order processing and push delivery? [Yes / No — if unsure, say No for now and we can add it later] If yes, your Worker subdomain (chosen when you deploy to Cloudflare Workers): [e.g. my-portal-push.myname.workers.dev] ━━━ YOUR CLIENT CLOSET ━━━ The closet page currently contains placeholder inventory from the original studio. Do you want to replace it with your own inventory now, or come back to it later? [Now / Later] If now, I will need: - A list of every item in your closet with: item name, sizes available, color/style, and your image URL for each piece - Your closet category names (e.g. Lingerie, Robes, Bodysuits, Dresses, Accessories) ━━━ YOUR PREP PAGES ━━━ The basics, prep, and arrival pages contain studio-specific prep instructions. Do you want to customize these now or later? [Now / Later] If now, tell me: - Your session prep instructions (what you tell clients about skin care, spray tan, what to bring) - Your arrival instructions (parking, how to find you, what happens when they arrive) - Any studio-specific policies or hard rules clients need to know before their session ━━━ YOUR HAIR AND MAKEUP ARTIST (optional) ━━━ Do you have an in-house or partner HMU artist? [Yes / No] If yes: HMU artist name: [e.g. Jessica] HMU artist email: [e.g. jessica@studiohair.com] HMU social handle: [e.g. @jessicadoeshair] ━━━ YOUR ROOM BACKGROUND IMAGES FOR WALL ART VIEWER ━━━ The wall art mockup viewer shows clients their image placed in a room photo. You can use the placeholder room images already in the code, or replace them with your own. [Keep placeholders for now / I want to replace them] If replacing, provide 3 direct image URLs of room interior photos (bedroom, living room, etc.): Room image 1: [URL] Room image 2: [URL] Room image 3: [URL] ━━━ BRANDING COLORS (optional — only if you want to change the visual style) ━━━ The portal currently uses a dark luxury color palette. Do you want to keep the existing black/gold/pink palette or switch to your own? [Keep existing / Use my colors] If using your own colors: Background dark color: [hex code, e.g. #0a0a0a] Primary accent color: [hex code, e.g. #C9A96E] Highlight/pop color: [hex code, e.g. #FF3D6E] Light text/cream color: [hex code, e.g. #faf8f5] ━━━ BRANDING FONTS (optional) ━━━ Do you want to keep the existing fonts (Cinzel headers, Cormorant Garamond accents, Jost body) or switch to your own? [Keep existing / Use my fonts] If using your own, list the Google Fonts names: Header font: [e.g. Playfair Display] Accent font: [e.g. Cormorant Garamond] Body font: [e.g. Lato] ━━━ WHAT I NEED HELP WITH FIRST ━━━ [Tell the AI what you want to tackle first — e.g.:] "Start by helping me replace all the placeholder credentials in gallery.html with my R2 values. Show me exactly what the variable block should look like with my real information filled in." OR "Start by replacing all studio name, phone, email, and logo placeholders across all files. Use Ctrl+Shift+F instructions so I can find and replace globally in VS Code." OR "I already replaced the basics. I am getting this error in my browser console: [paste your error] Help me fix it."

You do not need all of this on Day 1

The credentials block (Cloudflare R2, studio name, phone, logo) is what you need to make the gallery functional. Everything else can be filled in as you go. If you paste this message with the top half completed and the bottom half left as placeholders, the AI can still help you with the technical setup first and circle back to content and customization later.

What matters is that the AI has your real information in front of it from the start, so it never gives you instructions using placeholder values. When you paste your actual credentials, it fills them in for you instead of just telling you where they go.

Keep this message somewhere safe

Save this filled-in version somewhere you can find it again. If your AI conversation gets too long and you need to start a new one, paste it again at the top of the fresh conversation. This is your studio data document. It also doubles as a reference for every credential and URL you will need throughout the build.

Watermark Setup

Creating and Uploading Your Watermark

Your watermark tiles repeatedly across every image in the gallery when watermark protection is turned on. It appears in the grid, the lightbox, and the slideshow. It cannot be removed by right-clicking, screenshotting shortcuts, or dragging.

Design guidelines

Your watermark should be a PNG file with a transparent background. It will tile at roughly 38% size, meaning it repeats in a grid pattern across the full image. Make it semi-transparent (50 to 70% opacity works well). Your studio name, logo mark, or a combination works best. Avoid anything too detailed at small sizes.

Make it in Canva: Create a new design with a transparent background (PNG export). Place your studio name or logo mark in the center. Keep the text or mark large enough to be readable when tiled at reduced size. Export as PNG with transparent background.

Make it in Photoshop or Illustrator: Same principle. Export as PNG-24 with transparency.

How to upload and connect it

Go to Cloudflare → R2 → your galleries bucket. Click Upload. Select your watermark PNG. Upload it to the root of the bucket (not inside any folder). After upload, click the file and copy its public URL. It will look like: https://pub-xxxx.r2.dev/your-watermark.png

Open gallery.html in VS Code. Find the variable WM_URL and replace the placeholder with your watermark URL. Save and redeploy.

var WM_URL = 'https://pub-xxxx.r2.dev/your-watermark.png';

Test it by visiting your gallery in preview mode (watermark on). If the watermark is too dark, too large, or not tiling correctly, ask Claude or ChatGPT to adjust the opacity or tiling density. Paste the watermark CSS section from gallery.html and describe exactly what you want changed.

Music Setup

Finding and Uploading Your Slideshow Music

The slideshow plays background music automatically when a client opens the cinematic view. You choose the track. It must be royalty-free so there are no copyright issues.

Where to find it

Go to pixabay.com/music and search for any of these terms:

cinematic romantic soft piano ambient luxury editorial ethereal feminine slow emotional piano intimate acoustic

Longer tracks (3+ minutes) feel more natural before the loop. The slideshow loops the audio so any length technically works. Listen before downloading to confirm the mood fits the experience you want clients to have.

How to upload and connect it

Download the MP3 from Pixabay. Go to Cloudflare → R2 → your galleries bucket. Click Upload. Upload the MP3 to the root of the bucket. After upload, click the file and copy its public URL.

Open gallery.html. Find the audio tag and replace the src value with your music URL:

<audio id="ss-audio" src="https://pub-xxxx.r2.dev/your-track.mp3" loop preload="auto"></audio>

Save and redeploy. Test by opening the slideshow in your portal.

The music button in the slideshow shows MUSIC ON by default and lets the client toggle it off. The volume fades in gently when the slideshow starts so it is never jarring.

Push Notifications

How the Notification System Works

What the client experiences

When your client visits the portal on her phone, her browser may prompt her to allow notifications. If she taps Allow, her browser registers for push delivery. If she saves the portal to her home screen (Add to Home Screen on iOS or Android), she gets a full app-like experience and push alerts arrive even when the browser is not open.

A Notifications page inside her portal shows every message you have sent in reverse chronological order. The bell icon in her sidebar shows a badge with unread count. When she visits the page, messages mark as read and the badge clears.

What you do as the photographer

From your photographer dashboard, you can send a notification to any client gallery. Type your message, select the client's folder name, and send. The notification writes to their gallery folder in R2 as a JSON record. Her portal reads this and surfaces it in the Notifications page.

Common uses: gallery ready alert, paperwork reminder, selection deadline reminder, order placed confirmation, reveal appointment reminder.

Full push delivery to the home screen requires VAPID key setup

The cloudflare-worker-push.js and push-client.js and sw-push.js files handle push delivery. To enable full home-screen push notifications, you need to generate VAPID keys (a pair of public/private keys that authorize your push server) and deploy the Cloudflare Worker. This is an advanced step. If you want to set it up, paste the contents of cloudflare-worker-push.js and sw-push.js into Claude or ChatGPT and ask it to walk you through generating your VAPID keys, deploying the Worker to Cloudflare, and adding the keys to the service worker file. For in-portal notification delivery only (no home-screen push), no VAPID setup is needed and the system works out of the box.

Client Closet

Setting Up Your Client Closet

The closet page is a filterable, browsable inventory of everything available for clients to wear at your studio. It includes category filters, item images, descriptions, size ranges, and availability notes.

The placeholder images in closet.html are not your actual inventory

closet.html contains stock placeholder product images and generic descriptions. You replace every image URL and every product description with your own studio's actual wardrobe. This can be done gradually after the rest of the portal is live.

Photograph or gather images of your closet items

Clean flat-lay photos on a neutral background work best. Product-on-hanger shots also work. Keep them consistent in framing and lighting so the closet page looks cohesive.

Upload your images to Cloudflare R2

Create a folder inside your galleries bucket called closet. Upload all product images into that folder. After uploading, click each image and copy its public URL. It will look like: https://pub-xxxx.r2.dev/closet/item-name.jpg

Open closet.html and replace each item block

Each item has an image URL, a name, a category tag (used for filtering), a size range, and notes. Replace each placeholder with your actual item details. To add or remove items from the list, paste the current closet.html into Claude or ChatGPT and ask it to add new items or remove existing ones for you. Describe what you want in plain language.

The Vault: Custom Builds
Build 01 of 04  ·  Client Portal and Gallery Delivery System
Screenshots and screen recording of this content are strictly prohibited.
For member use only. All sales final. © Boudoir Automations