mattrguerra/meridian-ops-boardmainPrivate on GitHub, published here in full

wrangler.jsonc

Language JSON5.9 KB132 lines

apps/worker/wrangler.jsonc

  1. {
  2. "$schema": "node_modules/wrangler/config-schema.json",
  3. "name": "meridian-dashboard",
  4. "main": "src/index.ts",
  5. "compatibility_date": "2026-08-24",
  6. // Served on <name>.<account-subdomain>.workers.dev. Cloudflare Access
  7. // protects workers.dev URLs, so no custom domain and no DNS change to
  8. // meridiandisplay.example is required. That matters: the public site's zone is
  9. // managed separately, and repointing it to serve an internal board would be
  10. // real risk for no benefit.
  11. //
  12. // Preview URLs default to matching this setting. They are a second door to
  13. // the same client data, so cover them in the same Access application or turn
  14. // them off. Do not leave one protected and the other open.
  15. "workers_dev": true,
  16. // Cron: 11:00 UTC = 06:00 America/Chicago in CDT, 05:00 in CST.
  17. //
  18. // Cloudflare crons are UTC only, so this shifts by an hour twice a year. The
  19. // page shows `syncedAt` in Meridian time, so a drifted run is visible rather than
  20. // silent. If the winter hour matters, add a second trigger and let the
  21. // duplicate run overwrite: it is idempotent.
  22. "triggers": {
  23. // Three crons; the Worker branches on which fired.
  24. //
  25. // The morning and 15-minute crons both run the full sync: statuses move
  26. // all day, and a board showing the 6am numbers at 3pm is one people learn
  27. // to distrust.
  28. //
  29. // The difference is history: only the 11:00 run records the day's row, so
  30. // the day-over-day arrows keep comparing mornings instead of quarter-hours.
  31. // See sync() in src/index.ts.
  32. //
  33. // What this costs: a couple of dozen upstream requests per sync (the Bitrix
  34. // lead pages, a few Plinth pages, Ninety, the tracker tabs) plus the Gmail
  35. // reads for the inbox. It costs no model spend: the written briefings come from a
  36. // laptop, not from here.
  37. //
  38. // At 11:00 both patterns fire and Cloudflare invokes twice. That is
  39. // harmless: every write here is idempotent, and the two runs compute the
  40. // same numbers.
  41. //
  42. // The every-minute cron is the Sync now button's runner. ctx.waitUntil() in
  43. // a fetch handler does not get the budget a scheduled one does, and a
  44. // two-minute sync does not fit in it: run from the route, it is cut off
  45. // with nothing written. So the button records a request and this cron runs
  46. // it, in the context that can. It does nothing at all on the minutes there
  47. // is no request pending, which is almost all of them.
  48. "crons": ["0 11 * * 1-5", "*/15 * * * *", "* * * * *"]
  49. },
  50. "kv_namespaces": [
  51. {
  52. "binding": "DASHBOARD",
  53. // Replace with the id printed by:
  54. // wrangler kv namespace create DASHBOARD
  55. "id": "00000000000000000000000000000000",
  56. // A separate namespace for `wrangler dev --remote`, which refuses to start
  57. // without one. That refusal is doing something useful: --remote runs on
  58. // Cloudflare's edge with the real secrets, so without this a test sync
  59. // would write real pages and a real inbox read into production KV and the
  60. // team would be served whatever a half-finished experiment produced.
  61. //
  62. // With it, a remote dev run is fully live against Google, Bitrix, Plinth and
  63. // Ninety (which is the point, since Worker secrets are the only copy of
  64. // the Gmail key) while writing somewhere nobody is reading.
  65. //
  66. // wrangler kv namespace create DASHBOARD --preview
  67. "preview_id": "11111111111111111111111111111111"
  68. }
  69. ],
  70. // D1: the end-of-day note and the private list, and the only SQL on this
  71. // board. Everything else the board owns is a JSON blob in KV; a note is a
  72. // row a day per person, read back as a date range that must include the days
  73. // with nothing in them, and that is a table (rule 14). See
  74. // apps/worker/migrations/ for the reasoning in full.
  75. //
  76. // If `wrangler d1 create` is refused with "Authentication error [code:
  77. // 10000]" while the printed OAuth scopes include d1:write, re-mint with
  78. // `wrangler login`: the cached scope list is wrangler's own record, not
  79. // Cloudflare's, and the two can disagree.
  80. //
  81. // The binding is optional in Env, and stays that way. A Worker that lacks
  82. // this binding says the note store is not set up, in those words. It
  83. // does not say "no notes written". An unconfigured store and an empty one are
  84. // different facts and the board never renders them the same way.
  85. "d1_databases": [
  86. {
  87. "binding": "CHECKINS",
  88. "database_name": "meridian-checkins",
  89. // Replace with the id printed by `wrangler d1 create meridian-checkins`.
  90. "database_id": "00000000-0000-0000-0000-000000000000",
  91. "migrations_dir": "migrations"
  92. }
  93. ],
  94. "vars": {
  95. // Widen if orders routinely run longer than this. Each extra day is more
  96. // Plinth paging, and Plinth caps at 10 requests / 10 seconds.
  97. "PLINTH_WINDOW_DAYS": "60",
  98. // Who the Worker trusts to say who you are. Both come from the Access
  99. // application; neither is a secret. The team domain is in every login URL
  100. // and the AUD tag identifies an app, it does not authorise anything.
  101. //
  102. // Until both are set the Worker refuses every request. That is the intended
  103. // order: it cannot verify an assertion it has no keys for, and a board
  104. // carrying client names must not fall open while Access is half-configured.
  105. //
  106. // team domain Zero Trust > Settings > Custom Pages, or any login URL
  107. // AUD tag Zero Trust > Access > Applications > (this app) > Overview
  108. "ACCESS_TEAM_DOMAIN": "your-team.cloudflareaccess.com",
  109. "ACCESS_AUD": "REPLACE_WITH_ACCESS_AUD_TAG",
  110. "DEBUG": "false"
  111. },
  112. // Secrets are not in this file and must never be. Set them with:
  113. // wrangler secret put NINETY_TOKEN
  114. // wrangler secret put BITRIX_WEBHOOK_URL
  115. // wrangler secret put PLINTH_API_KEY
  116. //
  117. // NINETY_TOKEN must belong to a company Owner or Admin. GET /todos/company
  118. // returns 403 for every other role.
  119. "observability": {
  120. "enabled": true
  121. }
  122. }