This FRD ships @dmwd-io/jobs as an optional package that re-exports bullmq and ioredis as the platform standard for background job queues. Per ADR-014 (Open Source First), the value is standards enforcement and drift prevention — not a custom abstraction on top of the library. Platform conventions (env var names, queue naming) are documented alongside the re-export.
Introduction
Overview
ADR-065 mandates that webhook handlers acknowledge fast and process work asynchronously on a job queue. Each app currently wires its own BullMQ or database-backed queue with ad-hoc retry logic and no shared conventions. Per ADR-014 (Open Source First), we designate bullmq and ioredis as the community libraries for background job processing and re-export them through @dmwd-io/jobs. The platform contribution is documenting REDIS_URL as the standard env var and {domain}.{action} as the queue naming convention — no custom QueueProvider interface is built on top.
Goals
Designate bullmq / ioredis as the platform standard for background job queues per ADR-014.
Ship @dmwd-io/jobs as a thin re-export package so all apps import from a single pinned source.
Document REDIS_URL as the canonical env var for the Redis/Valkey connection string.
Document {domain}.{action} as the platform queue naming convention per ADR-065.
Define dead-letter and retry conventions that apps should adopt (using BullMQ’s native configuration).
Serve as the async processing backbone referenced by ADR-065 webhook handlers.
Non-Goals
Building a custom provider interface or adapter layer — the library’s own API is the interface (per ADR-014).
SQS or database-polling adapters (non-default; use BullMQ per ADR-027).
Implementing a job dashboard or monitoring UI.
FIFO ordering guarantees (jobs are at-least-once, not exactly-once ordered).
Priority queues — all jobs in a queue share the same priority.
Workflow orchestration or job chaining (DAG execution).
Scope
In Scope
Area
Description
@dmwd-io/jobs package
Re-exports bullmq and ioredis; pins to platform-approved versions
Env var conventions
REDIS_URL as the standard connection string env var
Queue naming conventions
{domain}.{action} convention documented and enforced by example
Platform recommendation for BullMQ failedJobsHistoryLength and DLQ patterns
Scheduled jobs
Documentation of BullMQ’s native delay and repeat options
Out of Scope
Area
Reason
Custom QueueProvider interface or adapters
ADR-014: library API is the interface
SQS or database-polling adapters
Non-default alternatives; BullMQ is the ADR-027-designated adapter
Job dashboard / admin UI
Operational tooling, not a library contract
Exactly-once delivery
At-least-once is sufficient; idempotency is the handler’s responsibility
Job priority levels
Future extension; initial scope is FIFO-ish within a queue
Workflow / DAG orchestration
Complex job chains are a separate concern
Users and Pain Points
User Groups
User
Description
Needs
App developers
Engineers building async processing pipelines
A single pinned import for BullMQ / ioredis with documented platform conventions
QA engineers
Testers validating async workflows
BullMQ’s built-in sandbox worker or a lightweight in-memory approach for deterministic tests
Design system maintainers
Library contributors
A clear re-export surface that webhook handlers can depend on per ADR-065
Pain Points
User
Pain Point
Impact
App developers
Each app wires its own BullMQ/SQS setup with different retry logic
Inconsistent failure handling; some apps retry forever, others drop silently
App developers
No shared env var convention — each app names the Redis connection differently
Config drift across services; ops burden at deploy time
App developers
No dead-letter convention — failed jobs disappear
No visibility into permanent failures; no recovery path
Definitions
Term
Definition
Job
A unit of async work with a type, payload, and retry policy
Queue
A named channel for jobs of a specific type
Retry policy
Configuration for how many times and at what intervals a failed job retries
Dead-letter queue (DLQ)
A holding area for jobs that exhausted all retry attempts
Scheduled job
A job that should not be processed until a specific time
At-least-once delivery
Each job is delivered to a processor at least once; duplicates are possible
Backoff
Increasing delay between retry attempts (exponential with jitter)
Current State
Existing Behavior
There is no shared queue abstraction. ADR-065 references async job processing but does not implement it. Apps that need background processing wire BullMQ or database polling directly.
Current Limitations
No shared TypeScript types for jobs, retry policies, or dead-letter entries.
No shared env var convention — each app names its Redis connection string differently.
No dead-letter conventions — failed jobs are logged and lost.
No scheduled job support — apps use setTimeout or cron for deferred work.
Webhook handlers (per ADR-065) have no standard queue to hand off work to.
Existing Workarounds
Apps create ad-hoc BullMQ queues with hard-coded retry counts.
Some apps use database rows as a poor-man’s queue with polling.
Failed jobs are logged to console with no recovery mechanism.
Proposed Solution
Summary
Create a packages/jobs/ directory containing @dmwd-io/jobs. The package re-exports bullmq and ioredis as peer dependencies so all platform apps import from a single pinned source. No custom interface is built — the library’s API is the interface. Platform conventions (env var names, queue naming, recommended retry defaults) are documented in the package README and Storybook docs page.
The env var REDIS_URL is the canonical connection string used by all services. Queue names follow {domain}.{action} convention per ADR-065. No custom adapter or factory is required.
Key Conventions
REDIS_URL — platform env var for the Redis/Valkey connection string.
Dead-letter: use BullMQ’s failedJobsHistoryLength and a dedicated {queue}.dlq queue for manual replay.
User Experience
End users are not directly affected. The queue package powers async processing behind API routes and webhook handlers.
Developer Experience
Developers import directly from @dmwd-io/jobs using BullMQ’s native API. Platform conventions (env var name, queue naming, retry defaults) are documented in one place. No adapter or factory wrapper is needed.
Requirements
ID
Requirement
Priority
Notes
FR-001
@dmwd-io/jobs package re-exports bullmq and ioredis
Must
Per ADR-014: thin re-export, no custom interface
FR-002
Package documents REDIS_URL as the platform env var
Conservative defaults that handle transient failures without long waits
David Holmes
2026-05-26
BullMQ designated as the TypeScript queue adapter
ADR-027 §2 explicitly names BullMQ (TS) and River (Go) as the default job queue implementations
David Holmes
2026-06-02
Reframed per ADR-014 (Open Source First): adopt bullmq / ioredis as thin re-export rather than building a custom provider interface. Library API is the interface.
ADR-014 mandates designating a community library over building a custom abstraction when the library already solves the problem
David Holmes
Document History
Date
Author
Change
2026-05-26
David Holmes
Initial draft
2026-06-02
David Holmes
Reframed per ADR-014: ship as thin re-export of bullmq / ioredis, drop custom interface.