Push → PDF Chain

Developer guide — traced 2026-06-03 · ahmedbouchefra2

What the chain looks like

There are 4 pieces that need to talk to each other for a user to subscribe and unlock PDFs.

🌐 Browser JS
push_subscribe.js
☁️ CF Worker
push-gate
🗄️ KV Store
PUSH_SUBS
🖥️ CLI
ab push stats

Each piece runs in a different runtime — browser, Cloudflare edge, Cloudflare KV, and Node.js. They are connected only through HTTP calls and a shared KV namespace. No tool currently traces the full chain automatically.

BUG Subscribe button in PDF modal did nothing

ELI5: Imagine a vending machine with a "pay here" button, but the payment reader is turned off. You press the button, nothing happens. That's what was happening — the subscribe button called window.PushSubscribe.subscribe(), but PushSubscribe was never loaded because push was disabled.

Root cause: pushNotify: { enabled: false } in bookpost's AppCoreConfig. When push is disabled, app-core.js never loads push_subscribe.js, so window.PushSubscribe is undefined. handlePdfSubscribeClick() detects this, silently closes the modal, and exits.

FIXED Enable pushNotify in bookpost AppCoreConfig

// _layouts/bookpost.html:98 — AppCoreConfig block window.AppCoreConfig = { iabEscape: { enabled: true }, emailGate: { enabled: false }, - pushNotify: { enabled: false }, // ← was disabled + pushNotify: { enabled: true }, // ← fixed pwaInstall: { enabled: true }, };
Now app-core.js loads push_subscribe.jswindow.PushSubscribe exists → modal subscribe button calls ps.subscribe() → permission prompt fires → sub sent to worker → localStorage push_subscribed=1 set → PDF unlocks.

What happens when a user clicks the PDF button

  1. 1
    PDF button clicked
    User taps the little printer icon in the toolbar.
    onclick="handlePrintClick()"
  2. 2
    Access check
    The code asks: "Does this person have a VIP pass?" It checks localStorage for the key push_subscribed=1. If yes → go straight to PDF. If no → show the modal.
    _hasPdfAccess() → checks localStorage.getItem('push_subscribed') === '1'
  3. 3
    Modal opens (no access)
    If no VIP pass, a popup appears saying "subscribe to push notifications to get the PDF."
    _onPdfProtected('push-required')_showPdfPrompt()
  4. 4
    User clicks subscribe in modal
    The big button in the popup. Calls window.PushSubscribe.subscribe() — this is the function from push_subscribe.js. If that script isn't loaded (old bug), nothing happens.
    handlePdfSubscribeClick()window.PushSubscribe.subscribe()
  5. 5
    Browser asks for notification permission
    The browser shows its own system dialog: "Allow notifications from this site?" If user says yes, the browser gives us a unique subscription token.
    Notification.requestPermission()reg.pushManager.subscribe(...)
  6. 6
    Subscription token sent to Cloudflare Worker
    We POST the token to our Cloudflare Worker. Think of it like mailing your address to a magazine — so they know where to deliver.
    _sendToBackend(sub)POST https://push-gate.techiediaries.workers.dev/subscribe
  7. 7
    Worker saves subscriber to KV
    The Worker writes the subscription + your country, city, timezone into a Cloudflare KV database. It's like a notebook with entries per subscriber.
    Stores: endpoint, keys, country, city, timezone, ua, timestamp
  8. 8
    localStorage key set + PDF unlocks
    Back in the browser, we stamp push_subscribed=1 in localStorage (the "VIP pass"). Then handlePrintClick() runs again — this time _hasPdfAccess() returns true and the PDF opens.
    localStorage.setItem('push_subscribed', '1')document.dispatchEvent('pushSubscribed')handlePrintClick() retries

Checking subscribers from the terminal

The CLI reads the same KV via the Worker's /stats endpoint. Run:

node cli/hub.js push stats # table: date · country · city · timezone · UA node cli/hub.js push send # send payloadless push to all subscribers node cli/hub.js push send-one # interactive picker — send to one subscriber

Things not done yet

TODO Per-site tracking — subscribers from ahmedbouchefra.com and techiediaries.com share the same KV with no way to tell them apart. The worker doesn't save which site the subscription came from.


TODO Per-app subpath subscriptions — users can't subscribe to just one app (e.g. /techquiz). It's all-or-nothing.


TODO Cross-runtime chain tracing — no tool currently maps the full browser → worker → KV → CLI chain as a navigable graph. Options: explicit chains.json, extend codeknow with HTTP contract edges, or an architecture doc.