Skip to content

QBTime Manager — Operations

Internal / restricted. This site is for DevOps and operators who deploy and run QBTime Manager. It is access-controlled (Cloudflare Access) and separate from the public product documentation at docs.qbtime.r2d2dev.com.

These guides cover installing, publishing, backing up, and recovering the QBTime Manager application and this documentation.

Pick your guide

  • Deploying the App

    From-zero, assume-nothing guide to installing the tools and publishing the QBTime Manager application to staging and production (incl. the scheduled-reports cron Worker).

  • Deploying the Docs Site

    Publishing the documentation sites (public + this ops site) to Cloudflare Pages.

  • Deploying the Sales Page

    Publishing the marketing/landing page (get.qbtime.r2d2dev.com) as its own Cloudflare Pages project, independent of the app and docs.

  • Backup & Restore

    Backing up and restoring the D1 database — exports, cadence, restore steps, and verifying a backup is good.

  • Incident Runbook

    First-response playbook: token expiry, failed report sends, cron not firing, lockouts, suspected tampering, and rollback.

Architecture at a glance

QBTime Manager is several independent Cloudflare deployments — each can be deployed and rolled back without touching the others:

  • App — Cloudflare Pages project qbtime (React client + Pages Functions API). Two environments: preview (staging) and production. Secrets are set per-environment in the dashboard, not via the CLI.
  • Database — Cloudflare D1 (SQLite), one per environment (qbtime_db_staging, qbtime_db_prod). Source of truth; back it up.
  • Cache & sessions — Cloudflare KV (disposable; not backed up).
  • Scheduled reports — a separate cron Worker (qbtime-cron-staging / qbtime-cron-prod) that fires every 15 minutes and POSTs the app's internal runner. Pages itself can't run cron.
  • Email — Microsoft Graph sendMail (or SendGrid), from one platform mailbox. Per-company QBT secrets are encrypted in D1, never in env vars.
  • Public docs — Pages project qbtime-docsdocs.qbtime.r2d2dev.com.
  • Ops docs (this site) — Pages project qbtime-docs-opsops.qbtime.r2d2dev.com, behind Cloudflare Access.
  • Sales page — Pages project for the static marketing page → get.qbtime.r2d2dev.com.

Operator quick reference

Environments. Two, fully isolated — production is not promoted from staging; both deploy the same source separately. Domains: staging.qbtime.r2d2dev.com (Pages preview) and qbtime.r2d2dev.com (Pages production).

Routine release (full steps in Deploying the App):

npm run build
npm run db:migrate:staging   # only when there are new migrations
npm run deploy:staging
# verify on staging, then:
npm run db:migrate:prod
npm run deploy:prod

Verify before deploying: npm run typecheck; npm run lint; npm test.

Cron health: npx wrangler tail qbtime-cron-prod — expect "*/15 * * * *" @ ... - Ok. A 403 means the Worker's INTERNAL_TASK_SECRET doesn't match the app's for that environment.

When something breaks: start at the Incident Runbook — it has the notice → confirm → fix → verify steps for the common failures.

Conventions. Screen paths are shown as routes (e.g. /platform/health, /app/companies). PowerShell examples assume you run from the repo root C:\MSP\CowboyMSP\Dev\CCC-QBTime.