Skip to content

Operations & Configuration

Tasuku runs as a Cloudflare Worker with D1 and a Durable Object. Configuration and operational scripts live at the repo root; deployments are performed by the maintainer.

  • wrangler.jsonc — Worker config: the main entry (src/worker.ts, which re-exports the SyncInbox Durable Object), the durable_objects binding + migration, the D1 bindings, the send_email binding (SUPPORT_EMAIL, pinned to a verified destination — ADR-017) + the SUPPORT_RATE_LIMITER, the ATTACHMENTS R2 bucket for task file attachments (ADR-019), and the Cron Trigger ["* * * * *"] driving both the reminder scan (ADR-015) and the daily completed-task cleanup (spec 038 — see Scheduled jobs). All of these are repeated under env.staging (named envs are non-inheritable — the recurring footgun) (ADR-011/015/017/019).
  • Bindings are the only way Worker code reaches external resources (D1, the DO, email, rate limiter, the R2 bucket) — injected via env at request time (constitution §7.8).
  • Secrets & vars — secrets (CLERK_SECRET_KEY, VAPID_PRIVATE_KEY) are set with wrangler secret put per env; non-secret runtime vars (ENVIRONMENT, VAPID_PUBLIC_KEY, VAPID_SUBJECT, SENTRY_DSN, SUPPORT_FROM_ADDRESS) live in wrangler.jsonc. Client-baked PUBLIC_* (Clerk/VAPID/Sentry DSN) come from .env/.dev.vars at build time. .dev.vars* are never committed. The full compile-vs-deploy split is in Configuration & Secrets.
  • Migrations — forward-only D1 migrations in src/db/migrations (latest: 0016 push notifications, 0017 tags, 0018 attachments, 0019 completed-task auto-deletion), applied with db:migrate:*. A new R2 bucket (tasuku-attachments, and …-staging) must be created once per env before deploying spec 037 (ADR-019). Migration 0019 (spec 038) is additive — tasks.completed_at (+ index) and users.auto_delete_completed (default 1) — needs no new binding or secret.
  • Observability — production errors/traces/logs/metrics go to Sentry (ADR-018); no-ops without a DSN. See Observability.
  • Environments — production (tasuku-db) and an isolated tasuku-staging Worker + tasuku-db-staging (spec 020).

Key package.json scripts:

ScriptPurpose
devastro dev
buildastro build + service-worker patch (scripts/build-sw.mjs)
db:migrate:localapply D1 migrations locally (never --remote from the assistant)
test / test:e2eVitest unit/contract; Playwright E2E
ci:localthe full local mirror of the CI gates

npm run ci:local runs install → validate (typecheck/lint/format/test) → build → docs site (build + coverage, spec 022) → supply-chain (SBOM, osv-scanner incl. the docs-site lockfile, npm-audit, gitleaks). It is the single verification the project relies on locally.

The single Cron Trigger (["* * * * *"], fired every minute) runs the Worker’s scheduled() handler (src/worker.ts). Two independent jobs run from it, each in its own waitUntil/catch so one failing never affects the other:

  • Reminder scan (ADR-015 / spec 029) — every minute; sends closed-app Web Push for due reminders. No-ops when VAPID is unconfigured.
  • Completed-task cleanup (spec 038) — gated to run once per UTC day (at 03:00 UTC); soft-deletes Tasks completed more than 30 days ago for users with auto_delete_completed = 1, cascading to their Steps + My Day entries, then fans a SyncSignal to each affected user (owner ∪ active list members) so removals converge in seconds. Tasks only; never Steps on their own. Runs independently of Web Push (no VAPID requirement).

Operational notes for the cleanup job:

  • The 03:00 gate is stateless wall-clock logic (getUTCHours()/getUTCMinutes()), not a persisted “last run” marker — a missed tick (deploy/outage) simply waits until the next day, which is fine for a 30-day retention window.
  • The first run after first deploy sweeps 0 rows: pre-existing completed Tasks have completed_at = NULL (no backfill) and are never auto-swept. A large swept count on an early run would be a red flag.
  • Observability (counts only, no task content): cleanup.auto.run { swept } per gate-open run; cleanup.manual.run { userId, removed } for the user-triggered cleanup. Watch via wrangler tail.
  • To verify on a deployed env without waiting for 03:00, drive the manual cleanup (POST /v1/me/completed-tasks/cleanup) — it exercises the same delete → cascade → tombstone → fan-out path — or temporarily widen the gate in a staging-only build.
  • The app Worker is deployed with Wrangler by the maintainer (wrangler deploy; staging via npm run deploy:staging). D1 migrations are applied with db:migrate:*.
  • The documentation site (this site) is built with npm run build --prefix docs-site and deployed by the maintainer as a separate Cloudflare Pages project — independent of the app Worker (ADR-012).

The project runs on a hard compute cap. Assistant commits use [ci skip] and git push -o ci.skip, only to non-default, MR-free branches; the maintainer opens merge requests and performs all merges and deploys. ci:local is the only verification the assistant relies on (CONTRIBUTING → “CI cost discipline”).

Supporting tooling (not individual module guides)

Section titled “Supporting tooling (not individual module guides)”

Several knowledge-graph communities are tooling/governance rather than runtime modules and are summarized here rather than given their own guides: the GitLab CI pipeline (spec 006), supply-chain scanners (ADR-007), static analysis & code-health gates (opengrep SAST, gitleaks history scan, dependency-cruiser, jscpd, knip — shifted left into git hooks), spec-kit workflow/shell helpers, Renovate config, dependency sets, npm scripts, and the i18n message catalogs (en/de; ADR-008). The repository’s test suites (unit/contract/E2E) are likewise cross-cutting and documented alongside the subsystems they exercise.