SsuperslateDocs
Build with the boilerplate

Decide background work

Choose a queue or worker design only when a product requirement justifies it.

Decide a background-work request

When to use

Use this path whenever a PRD asks for a worker, queue, scheduled job, async AI processing, retries, webhook fan-out, long-running task, or cleanup outside the supported request/response path.

The v1 foundation deliberately has no generic worker or queue. This runbook produces a supported, deferred, rejected, or product-specific architecture decision. It does not authorize silently restoring the historical Cloudflare/Gemini worker.

Files and boundaries

  • docs/decisions/0001-exclude-background-worker-from-v1.md: accepted exclusion and re-entry bar.
  • AGENTS.md: current background-work prohibitions and architecture requirements.
  • the product PRD and product contract: whether delayed work is truly required.
  • apps/server/src/domains/<domain>/: synchronous bounded work and persisted domain state.
  • packages/contracts: typed job input/output only if a product-specific mechanism is approved.
  • deployment, environment, cost, retention, and incident docs for any approved executor.

A provider SDK or scheduler does not own application authorization, job identity, data ownership, idempotency, or product state. Those remain server/domain responsibilities.

Procedure

  1. Rewrite the request as a concrete job: trigger, authenticated owner, input, output, maximum runtime, frequency, concurrency, latency target, retryability, terminal failure, data retention, provider cost, and user-visible states.
  2. Decide whether the work is actually background work:
    • bounded, fast, and safe to retry with the request may remain synchronous;
    • optional post-response convenience work may be deferred from the PRD;
    • work whose correctness depends on surviving process exit needs durable execution and may not be hidden in an unawaited promise or in-memory timer.
  3. Test the request against all re-entry criteria in Decision 0001: Better Auth authorization; server-owned job/object ownership; idempotency, retry, terminal failure, and deletion; abuse and provider-cost limits; typed MIME-correct contracts; zero-key local behavior; retention and observable paginated cleanup; deployed end-to-end proof; and a proportional support/removal path.
  4. Produce one explicit result:
    • supported synchronous: bounded request/response work with tests and timeouts;
    • defer/re-scope: not required for the validated user outcome;
    • unsupported in v1: PRD depends on durable background infrastructure but evidence and re-entry criteria are absent;
    • approve product-specific design investigation: a real product job and evidence justify designing the smallest executor, subject to a new ADR and full proof.
  5. For unsupported/deferred outcomes, update the PRD and Linear scope. Do not add packages or code.
  6. For an approved investigation, write an ADR before implementation. Name authorization handoff, persisted state machine, idempotency key, retry/backoff/dead-letter behavior, rate/cost limits, retention, local disabled path, deployment owner, observability, rollback, and removal.
  7. Re-run the product contract and support-cost review. One validated job does not automatically justify advertising a generic queue.

Verification

For a decision-only result:

rg -n -i "worker|queue|background|cron|scheduled|job" \
  AGENTS.md README.md docs package.json pnpm-workspace.yaml apps packages
vp check

Verify no worker package, shared worker JWT, queue environment key, deployment trigger, or product claim was introduced. For supported synchronous work, add timeout, duplicate-request, process-error, authorization, and database integration proof. For an approved executor, Decision 0001 requires a deployed API-to-executor smoke in addition to all repository checks.

Security constraints

  • Never pass a Better Auth session cookie or a long-lived shared JWT to a separate executor.
  • Every job needs purpose, audience, subject/owner, short authorization lifetime or server-side claim, and replay behavior.
  • Persist ownership and status before external work. Provider metadata is not authorization.
  • Bound input size/type, concurrency, retries, provider spend, retention, and cleanup.
  • Do not put secrets or full customer payloads into queue names, logs, job IDs, or evidence.
  • Cleanup must be paginated, observable, retryable, and ownership-safe.
  • Unawaited promises and in-memory timers are not durable background infrastructure.

Failure modes

  • “Add BullMQ/Trigger/Cloudflare Queues” appears before a job contract: solution-first expansion.
  • An HTTP handler returns before an unpersisted promise: process exit silently loses required work.
  • A provider task ID becomes the application job ID: ownership and retries are outsourced.
  • A shared secret authenticates every user/job: compromise has unbounded scope.
  • Retry creates duplicate charges or objects: no domain idempotency key/state transition exists.
  • Cleanup is periodic but unpaginated or silent: retention claims are false.
  • Local setup requires queue/AI/storage credentials: zero-key product setup regressed.
  • A sample is shipped but unsupported in docs/incidents: distributed code became hidden support liability.

Rollback and diagnosis

For a decision-only path, revert the PRD scope change if evidence later satisfies the re-entry bar. For an implementation, stop new job creation before disabling consumers, preserve persisted state, drain or explicitly fail owned jobs, revoke scoped credentials, and follow the ADR rollback.

Diagnose by job ID, application owner, state transition, attempt, idempotency key, and redacted provider request ID. Never use a queue purge as the first recovery action.

Acceptance criteria

  • The job is defined by outcome, ownership, lifecycle, limits, and failure behavior before tooling.
  • Every Decision 0001 re-entry criterion is answered with evidence or an explicit gap.
  • The result is one of supported synchronous, defer/re-scope, unsupported v1, or approved product-specific investigation.
  • Unsupported/deferred decisions add no runtime dependency, environment key, deployment resource, auth mechanism, or commercial claim.
  • Approved work has a new ADR and complete authorization/state/idempotency/cost/retention/local/ deployment/support contract before implementation.
  • vp check passes and current docs remain consistent with the worker exclusion.

Agent prohibitions

  • Do not restore the deleted Cloudflare/Gemini worker from git history.
  • Do not add a generic queue because a PRD contains the word background.
  • Do not implement required work with an unawaited promise, timer, or process-local map.
  • Do not mint a parallel shared-secret auth system.
  • Do not call provider task state the application source of truth.
  • Do not advertise background work from an ADR, mock, local-only example, or package installation.
  • Do not treat this runbook as approval; it is a decision gate.

On this page