Let’s lock it in clean.

Quick verify (now)

Health check

curl -s http://localhost:5000/health/bp-templates | jq


✅ Expect ok: true, mode: "public" (after you publish rules) or "signed" (fallback), and 200s for docx/preview/thumb.

Public API

curl -s http://localhost:5000/api/bp-templates-firebase/list | jq '.[0].slug,.isMaster'
curl -s http://localhost:5000/api/bp-templates-firebase/master | jq '.slug,.isMaster'
curl -I  http://localhost:5000/api/bp-templates-firebase/business-plan-general-blank-template/download


✅ 302 to public URL (or signed if rules not published).

Go-live checklist

Link the new page in your navbar:

/business-templates → “Free Business Plan Templates”

Keep auto-fallback in place (public → signed) so downloads never break.

After you click Publish in Firebase Storage rules, confirm health shows mode: "public".

Nice polish (fast)

Add structured data (better SEO for the gallery page):

<script type="application/ld+json">
{
  "@context":"https://schema.org",
  "@type":"CollectionPage",
  "name":"Free Business Plan Templates",
  "isAccessibleForFree": true,
  "about":"Download lender-ready business plan templates.",
  "hasPart": [{
    "@type":"CreativeWork",
    "name":"Business Plan General Blank Template",
    "url": "/api/bp-templates-firebase/business-plan-general-blank-template",
    "thumbnailUrl":"https://firebasestorage.googleapis.com/v0/b/ibrandbiz-bcfbe.firebasestorage.app/o/templates%2Fbusiness-plan%2Fthumbs%2Fbusiness-plan-general-blank-template%2Fbusiness-plan-general-blank-template-v1-thumb.webp?alt=media",
    "isBasedOn":"DOCX",
    "license":"https://ibrandbiz.com/terms"
  }]
}
</script>


Track downloads (server-side, lightweight):

In the download route (before redirect), log an event {slug, ts, ipHash, mode} to Firestore (e.g., analytics/downloads).

Optional: add a GA/Segment client event when the user clicks Download.

Pagination (when list grows):

Add ?limit=24&cursor=<id> to the list endpoint; your page can request more on scroll.

Cache

Keep Cache-Control: public, max-age=60 on public endpoints.

Storage URLs are versioned by path, so they cache nicely.

Admin notes (future versions)

Upload v2 → run the Promote button → your transaction demotes v1, promotes v2, updates pointer doc atomically.

Health endpoint will immediately reflect the current master and file status.