Download Markdown · Print this page to save a PDF.
Implementation and operating notes
What was built
- A dedicated Vercel project named bayline-offers in the Bayline Growth team.
- The offers.baylinegrowth.com custom domain, with only a new offers DNS record required.
- A hosted studio at /studio with first-use password creation, server-side password hashing, signed 12-hour HttpOnly sessions, same-origin mutation checks, and rate-limited sign-in.
- Private Vercel Blob storage for offer settings, reusable templates, administrator credentials, published snapshots, and publication history.
- Separate shop/offer addresses, creating drafts, copying offers, importing/exporting settings, and finding saved shops.
- Editable copy, all six brand colours, optional sections, image fields, confirmation-page copy, and per-offer custom CSS. Shared-placeholder inputs resolve repeated details such as GST terms once. Helvetica remains the landing-page font.
- Client image uploads, browser resizing, server-side WebP conversion, and immutable image URLs.
- Per-offer GHL embeds, success-redirect URLs, tracking activation, optional pixel override, consent control, and UTM link building.
- Reconstructed form iframe embeds plus the official GHL resizing script. Extra arbitrary script snippets in pasted embeds are not published; configure the studio’s tracking controls instead.
- A shared master pixel setting and Meta verification-token field. No existing pixel was reused or new Meta dataset invented.
- Studio-owned PageView and guarded confirmation-page Lead events, or GHL-only Lead mode; no CTA-click Lead event.
- Disabled scripts/forms in the design preview and seven-day signed read-only preview links.
- Login-protected working test pages with real form/tracking execution.
- Launch readiness checks, explicit publishing, frozen published HTML, draft/live separation, rollback, and taking an offer offline.
- Optimistic concurrency using Blob ETags so stale edits cannot silently overwrite another saved version.
- A reusable generic master with curly placeholders and the existing Luxotic offer imported as a private draft.
- An online help centre, full builder guide, and Meta website-lead SOP.
- The original editable local template, master, Luxotic version, and local editor are retained.
URLs
- Studio: https://offers.baylinegrowth.com/studio
- Help: https://offers.baylinegrowth.com/guide/index.html
- Luxotic’s intended public address: https://offers.baylinegrowth.com/luxotic-customs/ceramic-coating
- Standard success address: https://offers.baylinegrowth.com/SHOP/OFFER/thank-you?submitted=1
- Working test: https://offers.baylinegrowth.com/test/SHOP/OFFER
- Prelaunch test success: https://offers.baylinegrowth.com/test/SHOP/OFFER/thank-you?submitted=1
An unpublished offer returns an unavailable response. Having an intended URL is not evidence that the client’s page is launch-ready or live.
What still depends on shop and agency inputs
Luxotic remains a draft until its GHL embed, approved privacy/terms URLs, GST wording, turnaround, warranty service cost/maintenance conditions, and aftercare copy are completed. Its rating/review count should be rechecked before launch. The initial offer cap is 25 appointments; no live availability feed is connected.
The agency master pixel ID must be supplied. Creating/sharing a Meta dataset, configuring the GHL form/workflows, and verifying actual events require the corresponding assets and an approved controlled test contact. The platform is ready to accept those settings, but absent assets are not claimed as connected. No Meta ad campaign or spend was launched as part of the platform setup.
Delivery and caching
Publishing creates pre-rendered landing and confirmation HTML and stores an immutable version. Each public URL reads only its selected published snapshot and uses a Vercel CDN cache for 60 seconds. No admin editor or framework is loaded into the landing page. Uploaded image URLs use a one-year immutable cache. Bundled static images have a one-day cache.
This design allows publishing without a new code deployment. It is not a separate Vercel build/project for every shop. A cache miss invokes the server function to read the published record; subsequent cache hits can serve the HTML at the edge. CDN latency, the GHL iframe, and the Meta script are external performance factors. Do not promise a measured speed score without running a real test on the final integrated page.
Shop updates are isolated by record. Code deployments and hosting incidents affect the shared platform; keep that distinction clear. Master-template changes affect a page on its next publication, while its current published snapshot stays fixed. The implementation records a template version; it does not expose a template-version upgrade picker. For an old publication, the frozen HTML and rollback snapshot remain available.
Storage, secrets, and authentication
STUDIO_SESSION_SECRET signs sessions and preview/setup links. BLOB_READ_WRITE_TOKEN remains server-side. Vercel environment variables store both; .env.local is ignored and excluded from deployments. Private JSON records and authentication data are never included in the public output folder.
Offer data is persisted under offers/SHOP/OFFER.json. Immutable publication versions are under versions/SHOP/OFFER/UUID.json. Templates are under templates/NAME.json. Agency settings and authentication are stored in private records. Images are stored privately at media/HASH.webp and exposed through a narrow public image route.
This release uses one agency administrator password. It has no individual team accounts, role permissions, client portal, edit audit by named user, or automatic email password reset. Add those if staffing/client access grows. An exported JSON backup does not contain media bytes or all historic version bodies. Keep the Blob store available and add a full scheduled storage backup before promising disaster recovery.
To reset a forgotten password, an administrator can use the Blob SDK with project credentials to remove only auth/admin.json, then run scripts/provision.mjs to issue another private setup link. This is a deliberate recovery operation: never remove the offers or versions prefixes. Rotate the session secret and redeploy if compromised or if old sessions need immediate invalidation. Do not delete the Blob store when redeploying code.
Local commands
- npm start — original local editor and pages at 127.0.0.1:4173.
- npm run build — rebuild the original local master/Luxotic static output.
- npm run check — verify original template/client separation and assets.
- npm run test — run platform isolation, authentication, publishing, and tracking tests.
- npm run build:cloud — package the hosted studio/help and public assets.
- vercel deploy --prod --scope bayline-growth — deploy reviewed code changes to the linked offers project.
Use the existing .vercel/project.json linkage. Verify the project is bayline-offers before deployment. Page-content publishing inside the studio does not require this command. A deployment uploads reviewed application source and reads server credentials from Vercel; it does not upload HANDOFF-ACCESS.md or .env.local.
Ongoing costs and maintenance
The studio uses the agency’s existing Vercel account and metered private Blob storage. No paid-plan upgrade or domain purchase is required by the code setup. Review the account’s actual plan, transfer/storage/function usage, and spend controls in Vercel; high-volume GHL/Meta traffic is not cost-free merely because pages are static in structure.
Recheck integrations when GHL embed behavior or Meta controls change. Keep dependencies patched and review source changes locally before deploying. Preserve existing Bayline DNS records; this project needs only the offers host.