report-worker Isolate Profile
Engineering specification for the Hoox PDF report worker: BROWSER.quickAction pdf, cron at 08:00 and 18:00 UTC, and R2.
This page
The report-worker is the automated document compiler of the Hoox trading platform. Deployed as a scheduled cron isolate, this worker runs twice daily (at 08:00 and 18:00 UTC) to pull D1 transactional stats, construct a highly styled HTML5 portfolio report, call the BROWSER binding (quickAction("pdf")) to compile the page into a PDF buffer, offload the file to R2, and push a private download link to your Telegram.
⚡ 1. Declared Wrangler Configurations & Bindings
The report-worker mounts storage buckets, notification bindings, and is triggered by Cloudflare®'s background cron engine:
{
"name": "report-worker",
"main": "src/index.ts",
"compatibility_date": "2026-06-08",
"compatibility_flags": ["nodejs_compat"],
"account_id": "<CLOUDFLARE_ACCOUNT_ID>",
"placement": {
"mode": "smart",
},
"triggers": {
"crons": ["0 8 * * *", "0 18 * * *"],
},
"browser": {
"binding": "BROWSER",
},
"r2_buckets": [
{
"binding": "REPORTS_BUCKET",
"bucket_name": "trade-reports",
},
],
"kv_namespaces": [
{
"binding": "CONFIG_KV",
"id": "<KV_NAMESPACE_ID>",
},
],
"services": [
{ "binding": "D1_SERVICE", "service": "d1-worker" },
{ "binding": "TELEGRAM_SERVICE", "service": "telegram-worker" },
],
}
INTERNAL_KEY_BINDING is set with wrangler secret put. PDF uses the BROWSER binding (quickAction("pdf")).
🔑 2. Environmental Variables & Encrypted Secrets
BROWSER: Wranglerbrowserbinding.generatePdfcallsenv.BROWSER.quickAction("pdf", { html, options }). No Browser Rendering REST token.INTERNAL_KEY_BINDING: Shared key used to validate calls from other V8 isolates.
🌐 3. Browser Rendering & PDF Print Pipeline
When the Cron schedule triggers, report-worker runs the following programmatic pipeline:
Step 1: Data Aggregation & HTML Compilation
The worker pings D1_SERVICE to retrieve P&L, win rate, and total daily fees, inserting the metrics into a styled HTML5 template utilizing Tailwind CSS and CSS Grid styling:
<div class="card">
<h2>Daily P&L</h2>
<p class="pnl-green">+$1,234.50</p>
</div>
Step 2: Cloudflare® Chrome Isolate Print
Calls the Browser Rendering binding. This is not a REST request:
const pdf = await env.BROWSER.quickAction("pdf", {
html: htmlContent,
options: {
format: "A4",
printBackground: true,
margin: { top: "1cm", right: "1cm", bottom: "1cm", left: "1cm" },
},
});
Step 3: R2 Storage & Expiration
- The Browser Rendering binding (
BROWSER.quickAction("pdf", …)) compiles the page and returns a raw PDF binary stream. - The worker uploads the stream to the
REPORTS_BUCKETR2 storage bucket using a path-safe key:reports/daily-pnl-YYYY-MM-DD-{timestamp}.pdfKeys are validated (assertSafeReportKey) so.., absolute paths, and non-PDF names are rejected. - A lifecycle rule on the R2 bucket automatically purges reports older than 30 days to maintain storage cleanliness.
Step 4: Dispatch Telegram Alert
Calls TELEGRAM_SERVICE /alert with fail-closed internal auth (TELEGRAM_ALERT_AUTH_KEY_FIELDS). Download URLs encode path segments and only use a validated host from REPORT_WORKER_URL.
Security notes
- Auth:
GET /reportrequiresX-Internal-Auth-Key(fail-closed). Cron uses the scheduled handler (no public HTTP). - HTML escape: All D1-sourced strings (e.g.
topAsset) are escaped before interpolation into the PDF HTML template. - R2 path safety: Object keys must match
^reports/[A-Za-z0-9._-]+\.pdf$.
Tip
If the BROWSER binding (or R2) is not configured / PDF generation fails, the
worker gracefully falls back to a text-only P&L summary via Telegram so
ops still receive daily metrics without a hard crash.
🔗 Next Steps
- telegram-worker Profile — Review push alert configurations and webhook tunnels.
- D1 Database Operations — Apply schema.sql and query the ledger.