@girardmedia/bootspring 3.3.2 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/assets/agents/accessibility-auditor.md +39 -0
  2. package/assets/agents/api-designer.md +40 -0
  3. package/assets/agents/auth-implementer.md +64 -0
  4. package/assets/agents/bug-hunter.md +42 -0
  5. package/assets/agents/bundle-analyzer.md +40 -0
  6. package/assets/agents/cache-optimizer.md +55 -0
  7. package/assets/agents/changelog-writer.md +55 -0
  8. package/assets/agents/ci-cd-builder.md +40 -0
  9. package/assets/agents/code-explainer.md +39 -0
  10. package/assets/agents/code-reviewer.md +39 -0
  11. package/assets/agents/cost-optimizer.md +57 -0
  12. package/assets/agents/cron-scheduler.md +51 -0
  13. package/assets/agents/data-seeder.md +56 -0
  14. package/assets/agents/database-architect.md +40 -0
  15. package/assets/agents/dependency-updater.md +40 -0
  16. package/assets/agents/deploy-checker.md +40 -0
  17. package/assets/agents/docker-optimizer.md +40 -0
  18. package/assets/agents/documentation-writer.md +40 -0
  19. package/assets/agents/email-builder.md +55 -0
  20. package/assets/agents/env-setup.md +40 -0
  21. package/assets/agents/error-handler.md +40 -0
  22. package/assets/agents/eslint-fixer.md +46 -0
  23. package/assets/agents/feature-flagger.md +69 -0
  24. package/assets/agents/git-detective.md +39 -0
  25. package/assets/agents/graphql-builder.md +60 -0
  26. package/assets/agents/incident-responder.md +59 -0
  27. package/assets/agents/log-analyzer.md +39 -0
  28. package/assets/agents/migration-planner.md +41 -0
  29. package/assets/agents/monorepo-navigator.md +39 -0
  30. package/assets/agents/nextjs-expert.md +57 -0
  31. package/assets/agents/notification-builder.md +56 -0
  32. package/assets/agents/onboarding-guide.md +39 -0
  33. package/assets/agents/performance-profiler.md +40 -0
  34. package/assets/agents/prisma-expert.md +57 -0
  35. package/assets/agents/rate-limiter.md +58 -0
  36. package/assets/agents/react-expert.md +58 -0
  37. package/assets/agents/refactorer.md +42 -0
  38. package/assets/agents/regex-builder.md +46 -0
  39. package/assets/agents/release-manager.md +40 -0
  40. package/assets/agents/s3-manager.md +58 -0
  41. package/assets/agents/schema-validator.md +40 -0
  42. package/assets/agents/search-builder.md +62 -0
  43. package/assets/agents/security-auditor.md +39 -0
  44. package/assets/agents/sitemap-generator.md +53 -0
  45. package/assets/agents/stripe-integrator.md +59 -0
  46. package/assets/agents/tailwind-expert.md +55 -0
  47. package/assets/agents/tech-debt-tracker.md +39 -0
  48. package/assets/agents/test-writer.md +42 -0
  49. package/assets/agents/type-fixer.md +45 -0
  50. package/assets/agents/webhook-builder.md +54 -0
  51. package/assets/rules/cpp.md +53 -0
  52. package/assets/rules/css.md +52 -0
  53. package/assets/rules/go.md +50 -0
  54. package/assets/rules/html.md +52 -0
  55. package/assets/rules/java.md +51 -0
  56. package/assets/rules/kotlin.md +50 -0
  57. package/assets/rules/php.md +51 -0
  58. package/assets/rules/python.md +51 -0
  59. package/assets/rules/ruby.md +51 -0
  60. package/assets/rules/rust.md +49 -0
  61. package/assets/rules/shell.md +52 -0
  62. package/assets/rules/sql.md +49 -0
  63. package/assets/rules/swift.md +50 -0
  64. package/assets/rules/typescript.md +52 -0
  65. package/assets/rules/yaml-json.md +51 -0
  66. package/assets/skills/accessibility.md +210 -0
  67. package/assets/skills/agent-patterns.md +387 -0
  68. package/assets/skills/ai-integration.md +263 -0
  69. package/assets/skills/animation-patterns.md +224 -0
  70. package/assets/skills/api-design.md +218 -0
  71. package/assets/skills/api-gateway.md +341 -0
  72. package/assets/skills/api-versioning.md +226 -0
  73. package/assets/skills/astro-patterns.md +233 -0
  74. package/assets/skills/auth-patterns.md +248 -0
  75. package/assets/skills/aws-patterns.md +171 -0
  76. package/assets/skills/background-jobs.md +162 -0
  77. package/assets/skills/browser-extensions.md +309 -0
  78. package/assets/skills/caching-patterns.md +253 -0
  79. package/assets/skills/ci-cd.md +251 -0
  80. package/assets/skills/cli-development.md +296 -0
  81. package/assets/skills/code-review.md +185 -0
  82. package/assets/skills/cron-patterns.md +327 -0
  83. package/assets/skills/data-fetching.md +231 -0
  84. package/assets/skills/database-migrations.md +346 -0
  85. package/assets/skills/database-patterns.md +219 -0
  86. package/assets/skills/debugging.md +281 -0
  87. package/assets/skills/design-system.md +289 -0
  88. package/assets/skills/django-patterns.md +182 -0
  89. package/assets/skills/docker-patterns.md +235 -0
  90. package/assets/skills/e2e-testing.md +287 -0
  91. package/assets/skills/edge-computing.md +268 -0
  92. package/assets/skills/electron-patterns.md +266 -0
  93. package/assets/skills/email-templates.md +206 -0
  94. package/assets/skills/error-handling.md +265 -0
  95. package/assets/skills/event-driven.md +232 -0
  96. package/assets/skills/express-patterns.md +239 -0
  97. package/assets/skills/fastapi-patterns.md +198 -0
  98. package/assets/skills/feature-flags.md +212 -0
  99. package/assets/skills/figma-to-code.md +298 -0
  100. package/assets/skills/file-upload.md +228 -0
  101. package/assets/skills/forms-patterns.md +264 -0
  102. package/assets/skills/gcp-patterns.md +189 -0
  103. package/assets/skills/git-workflow.md +187 -0
  104. package/assets/skills/golang-patterns.md +185 -0
  105. package/assets/skills/graphql-patterns.md +244 -0
  106. package/assets/skills/i18n-patterns.md +172 -0
  107. package/assets/skills/image-processing.md +350 -0
  108. package/assets/skills/java-springboot.md +226 -0
  109. package/assets/skills/kotlin-patterns.md +207 -0
  110. package/assets/skills/kubernetes-patterns.md +326 -0
  111. package/assets/skills/laravel-patterns.md +261 -0
  112. package/assets/skills/llm-fine-tuning.md +335 -0
  113. package/assets/skills/load-testing.md +303 -0
  114. package/assets/skills/logging-observability.md +228 -0
  115. package/assets/skills/markdown-processing.md +318 -0
  116. package/assets/skills/mcp-server-patterns.md +292 -0
  117. package/assets/skills/microservices.md +272 -0
  118. package/assets/skills/migration-patterns.md +239 -0
  119. package/assets/skills/mongodb-patterns.md +189 -0
  120. package/assets/skills/monorepo-patterns.md +287 -0
  121. package/assets/skills/nextjs-app-router.md +237 -0
  122. package/assets/skills/notification-patterns.md +348 -0
  123. package/assets/skills/oauth-patterns.md +246 -0
  124. package/assets/skills/payment-integration.md +222 -0
  125. package/assets/skills/pdf-generation.md +307 -0
  126. package/assets/skills/performance-optimization.md +277 -0
  127. package/assets/skills/php-patterns.md +210 -0
  128. package/assets/skills/prisma-patterns.md +241 -0
  129. package/assets/skills/prompt-engineering.md +193 -0
  130. package/assets/skills/pwa-patterns.md +247 -0
  131. package/assets/skills/python-patterns.md +158 -0
  132. package/assets/skills/python-testing.md +172 -0
  133. package/assets/skills/queue-patterns.md +295 -0
  134. package/assets/skills/rag-patterns.md +159 -0
  135. package/assets/skills/rate-limiting.md +319 -0
  136. package/assets/skills/react-components.md +201 -0
  137. package/assets/skills/react-native-patterns.md +299 -0
  138. package/assets/skills/real-time-patterns.md +181 -0
  139. package/assets/skills/redis-patterns.md +188 -0
  140. package/assets/skills/refactoring.md +218 -0
  141. package/assets/skills/regex-patterns.md +191 -0
  142. package/assets/skills/remix-patterns.md +262 -0
  143. package/assets/skills/responsive-design.md +199 -0
  144. package/assets/skills/ruby-rails-patterns.md +178 -0
  145. package/assets/skills/rust-patterns.md +211 -0
  146. package/assets/skills/search-patterns.md +227 -0
  147. package/assets/skills/security-hardening.md +237 -0
  148. package/assets/skills/seo-patterns.md +179 -0
  149. package/assets/skills/serverless-patterns.md +223 -0
  150. package/assets/skills/sql-optimization.md +154 -0
  151. package/assets/skills/state-management.md +254 -0
  152. package/assets/skills/storybook-patterns.md +330 -0
  153. package/assets/skills/svelte-patterns.md +258 -0
  154. package/assets/skills/swift-patterns.md +227 -0
  155. package/assets/skills/tailwind-patterns.md +272 -0
  156. package/assets/skills/tdd-workflow.md +199 -0
  157. package/assets/skills/terraform-patterns.md +270 -0
  158. package/assets/skills/testing-react.md +240 -0
  159. package/assets/skills/testing-vitest.md +232 -0
  160. package/assets/skills/typescript-strict.md +159 -0
  161. package/assets/skills/video-processing.md +340 -0
  162. package/assets/skills/vue-patterns.md +247 -0
  163. package/assets/skills/web-workers.md +327 -0
  164. package/assets/skills/webhooks-patterns.md +283 -0
  165. package/assets/skills/websocket-patterns.md +306 -0
  166. package/dist/cli/index.js +941 -958
  167. package/dist/core/index.d.ts +341 -11
  168. package/dist/core.js +58 -95
  169. package/dist/mcp/index.d.ts +33 -1
  170. package/dist/mcp-server.js +177 -255
  171. package/package.json +4 -1
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: python-patterns
3
+ description: Modern Python patterns including type hints, dataclasses, async/await, context managers, decorators, and pathlib.
4
+ ---
5
+
6
+ # Python Patterns
7
+
8
+ ## When to Use
9
+
10
+ Apply these patterns when writing Python 3.10+ code that needs to be maintainable,
11
+ type-safe, and idiomatic. Use this skill when building CLI tools, data pipelines,
12
+ API clients, or any Python project that benefits from modern language features.
13
+
14
+ ## How It Works
15
+
16
+ ### Type Hints and Generics
17
+
18
+ Use `from __future__ import annotations` at the top of every module. Prefer built-in
19
+ generic types (`list[str]`, `dict[str, int]`) over `typing.List`, `typing.Dict`.
20
+
21
+ ```python
22
+ from __future__ import annotations
23
+ from typing import TypeVar, Protocol
24
+
25
+ T = TypeVar("T")
26
+
27
+ class Comparable(Protocol):
28
+ def __lt__(self, other: Comparable) -> bool: ...
29
+
30
+ def top_n(items: list[T], n: int, key: Callable[[T], Comparable]) -> list[T]:
31
+ return sorted(items, key=key, reverse=True)[:n]
32
+ ```
33
+
34
+ ### Dataclasses and Slots
35
+
36
+ Use `@dataclass(frozen=True, slots=True)` for value objects. Use `field(default_factory=...)`
37
+ for mutable defaults. Never use mutable default arguments.
38
+
39
+ ```python
40
+ from dataclasses import dataclass, field
41
+
42
+ @dataclass(frozen=True, slots=True)
43
+ class Config:
44
+ host: str
45
+ port: int = 8080
46
+ tags: list[str] = field(default_factory=list)
47
+ ```
48
+
49
+ ### Async/Await
50
+
51
+ Use `asyncio.TaskGroup` (3.11+) instead of `asyncio.gather` for structured concurrency.
52
+ Always set timeouts on network calls. Use `async for` with async iterators.
53
+
54
+ ```python
55
+ async def fetch_all(urls: list[str]) -> list[Response]:
56
+ async with asyncio.TaskGroup() as tg:
57
+ tasks = [tg.create_task(fetch(url)) for url in urls]
58
+ return [t.result() for t in tasks]
59
+ ```
60
+
61
+ ### Context Managers
62
+
63
+ Use `@contextmanager` for resource cleanup. Pair every acquire with a release in a
64
+ try/finally block. Use `AsyncExitStack` when managing dynamic numbers of resources.
65
+
66
+ ```python
67
+ from contextlib import contextmanager
68
+
69
+ @contextmanager
70
+ def temp_directory(prefix: str = "tmp"):
71
+ path = Path(tempfile.mkdtemp(prefix=prefix))
72
+ try:
73
+ yield path
74
+ finally:
75
+ shutil.rmtree(path, ignore_errors=True)
76
+ ```
77
+
78
+ ### Decorators with Proper Signatures
79
+
80
+ Always use `@functools.wraps` to preserve the wrapped function's metadata.
81
+ Use `ParamSpec` for type-safe decorators that forward arguments.
82
+
83
+ ```python
84
+ from typing import ParamSpec, TypeVar
85
+ import functools
86
+
87
+ P = ParamSpec("P")
88
+ R = TypeVar("R")
89
+
90
+ def retry(max_attempts: int = 3):
91
+ def decorator(func: Callable[P, R]) -> Callable[P, R]:
92
+ @functools.wraps(func)
93
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
94
+ for attempt in range(max_attempts):
95
+ try:
96
+ return func(*args, **kwargs)
97
+ except Exception:
98
+ if attempt == max_attempts - 1:
99
+ raise
100
+ raise RuntimeError("unreachable")
101
+ return wrapper
102
+ return decorator
103
+ ```
104
+
105
+ ### Pathlib Over os.path
106
+
107
+ Use `Path` for all filesystem operations. Chain `/` for path construction.
108
+ Use `.read_text()` / `.write_text()` instead of `open()` for simple reads/writes.
109
+
110
+ ```python
111
+ from pathlib import Path
112
+
113
+ config_dir = Path.home() / ".config" / "myapp"
114
+ config_dir.mkdir(parents=True, exist_ok=True)
115
+ config = config_dir / "settings.toml"
116
+ content = config.read_text(encoding="utf-8")
117
+ ```
118
+
119
+ ## Examples
120
+
121
+ **Pattern: Structured enum with behavior**
122
+ ```python
123
+ from enum import Enum, auto
124
+
125
+ class Status(Enum):
126
+ PENDING = auto()
127
+ RUNNING = auto()
128
+ DONE = auto()
129
+
130
+ @property
131
+ def is_terminal(self) -> bool:
132
+ return self in (Status.DONE,)
133
+ ```
134
+
135
+ **Pattern: Named tuple for lightweight records**
136
+ ```python
137
+ from typing import NamedTuple
138
+
139
+ class Point(NamedTuple):
140
+ x: float
141
+ y: float
142
+
143
+ def distance_to(self, other: Point) -> float:
144
+ return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
145
+ ```
146
+
147
+ ## Checklist
148
+
149
+ - [ ] `from __future__ import annotations` at top of every module
150
+ - [ ] All function signatures have type hints, including return types
151
+ - [ ] Dataclasses use `frozen=True` and `slots=True` where possible
152
+ - [ ] No mutable default arguments (use `field(default_factory=...)`)
153
+ - [ ] `@functools.wraps` on every decorator
154
+ - [ ] `Path` instead of `os.path` for filesystem operations
155
+ - [ ] `asyncio.TaskGroup` instead of bare `gather` for structured concurrency
156
+ - [ ] Context managers for any resource that needs cleanup
157
+ - [ ] `match` statements (3.10+) instead of long if/elif chains where appropriate
158
+ - [ ] `__all__` defined in public-facing modules
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: python-testing
3
+ description: Python testing with pytest including fixtures, parametrize, mocking, coverage, and property-based testing.
4
+ ---
5
+
6
+ # Python Testing
7
+
8
+ ## When to Use
9
+
10
+ Apply this skill when writing or improving tests for Python code. Use pytest as the
11
+ default test runner. Reach for property-based testing (Hypothesis) when testing pure
12
+ functions with wide input domains. Use mocking sparingly and prefer dependency injection.
13
+
14
+ ## How It Works
15
+
16
+ ### Pytest Fixtures
17
+
18
+ Fixtures replace setup/teardown. Use `yield` fixtures for cleanup. Scope fixtures
19
+ (`session`, `module`, `function`) to control lifecycle. Keep fixtures close to the
20
+ tests that use them; use `conftest.py` for shared fixtures.
21
+
22
+ ```python
23
+ import pytest
24
+
25
+ @pytest.fixture
26
+ def db_conn():
27
+ conn = create_test_connection()
28
+ yield conn
29
+ conn.rollback()
30
+ conn.close()
31
+
32
+ @pytest.fixture(scope="session")
33
+ def app_config():
34
+ return load_config("test")
35
+ ```
36
+
37
+ ### Parametrize
38
+
39
+ Use `@pytest.mark.parametrize` for data-driven tests. Each tuple is a distinct test
40
+ case with its own pass/fail. Use `pytest.param(..., id="name")` for readable IDs.
41
+
42
+ ```python
43
+ @pytest.mark.parametrize("input_val,expected", [
44
+ pytest.param("hello", "HELLO", id="lowercase"),
45
+ pytest.param("Hello World", "HELLO WORLD", id="mixed-case"),
46
+ pytest.param("", "", id="empty-string"),
47
+ pytest.param("123", "123", id="digits-unchanged"),
48
+ ])
49
+ def test_uppercase(input_val: str, expected: str):
50
+ assert input_val.upper() == expected
51
+ ```
52
+
53
+ ### Mocking
54
+
55
+ Use `unittest.mock.patch` to replace external dependencies. Prefer patching where
56
+ the name is used, not where it is defined. Use `spec=True` to catch attribute errors.
57
+
58
+ ```python
59
+ from unittest.mock import patch, MagicMock
60
+
61
+ def test_send_email():
62
+ with patch("myapp.notifications.smtp_client", spec=True) as mock_smtp:
63
+ mock_smtp.send.return_value = {"status": "sent"}
64
+ result = send_notification("user@example.com", "Hello")
65
+ mock_smtp.send.assert_called_once()
66
+ assert result["status"] == "sent"
67
+ ```
68
+
69
+ ### Async Testing
70
+
71
+ Use `pytest-asyncio` with `@pytest.mark.asyncio` for async tests. Set
72
+ `asyncio_mode = "auto"` in `pyproject.toml` to avoid marking every test.
73
+
74
+ ```python
75
+ @pytest.mark.asyncio
76
+ async def test_fetch_user(mock_api):
77
+ user = await fetch_user(user_id=42)
78
+ assert user.name == "Alice"
79
+ assert user.active is True
80
+ ```
81
+
82
+ ### Property-Based Testing with Hypothesis
83
+
84
+ Use Hypothesis for pure functions. Define strategies that describe valid inputs.
85
+ Hypothesis will find edge cases you would never write by hand.
86
+
87
+ ```python
88
+ from hypothesis import given, strategies as st
89
+
90
+ @given(st.lists(st.integers()))
91
+ def test_sort_is_idempotent(xs: list[int]):
92
+ sorted_once = sorted(xs)
93
+ sorted_twice = sorted(sorted_once)
94
+ assert sorted_once == sorted_twice
95
+
96
+ @given(st.text(min_size=1))
97
+ def test_round_trip_encode_decode(s: str):
98
+ assert decode(encode(s)) == s
99
+ ```
100
+
101
+ ### Coverage
102
+
103
+ Run with `pytest --cov=myapp --cov-report=term-missing --cov-fail-under=80`.
104
+ Configure in `pyproject.toml`:
105
+
106
+ ```toml
107
+ [tool.coverage.run]
108
+ source = ["myapp"]
109
+ omit = ["*/tests/*", "*/migrations/*"]
110
+
111
+ [tool.coverage.report]
112
+ fail_under = 80
113
+ show_missing = true
114
+ ```
115
+
116
+ ### Markers and Filtering
117
+
118
+ Use custom markers to categorize tests. Run subsets with `-m`.
119
+
120
+ ```python
121
+ @pytest.mark.slow
122
+ def test_full_pipeline():
123
+ ...
124
+
125
+ @pytest.mark.integration
126
+ def test_database_roundtrip(db_conn):
127
+ ...
128
+ ```
129
+
130
+ ```bash
131
+ pytest -m "not slow" # skip slow tests
132
+ pytest -m integration # run only integration tests
133
+ pytest -k "test_parse" # run tests matching name pattern
134
+ ```
135
+
136
+ ## Examples
137
+
138
+ **Pattern: Factory fixture for flexible test data**
139
+ ```python
140
+ @pytest.fixture
141
+ def make_user():
142
+ def _make(name: str = "Alice", role: str = "user") -> User:
143
+ return User(id=uuid4(), name=name, role=role)
144
+ return _make
145
+
146
+ def test_admin_permissions(make_user):
147
+ admin = make_user(role="admin")
148
+ assert admin.can_delete_users() is True
149
+ ```
150
+
151
+ **Pattern: tmp_path for file tests (built-in fixture)**
152
+ ```python
153
+ def test_write_config(tmp_path):
154
+ config_file = tmp_path / "config.json"
155
+ write_config(config_file, {"debug": True})
156
+ assert config_file.exists()
157
+ data = json.loads(config_file.read_text())
158
+ assert data["debug"] is True
159
+ ```
160
+
161
+ ## Checklist
162
+
163
+ - [ ] Every test function starts with `test_` and has a descriptive name
164
+ - [ ] Fixtures use `yield` for cleanup, not `try/finally` in test bodies
165
+ - [ ] `@pytest.mark.parametrize` for any test with more than 2 similar cases
166
+ - [ ] Mocks use `spec=True` to catch incorrect attribute access
167
+ - [ ] Patch targets where the name is imported, not where it is defined
168
+ - [ ] Async tests use `@pytest.mark.asyncio` or `asyncio_mode = "auto"`
169
+ - [ ] Coverage threshold set in `pyproject.toml` (`fail_under = 80`)
170
+ - [ ] Hypothesis tests for pure functions with wide input domains
171
+ - [ ] Slow/integration tests marked so CI can run them separately
172
+ - [ ] No test depends on execution order (use `pytest-randomly` to verify)
@@ -0,0 +1,295 @@
1
+ ---
2
+ name: queue-patterns
3
+ description: Queue patterns for FIFO processing, priority queues, dead letter queues, delayed jobs, and exactly-once processing with BullMQ.
4
+ ---
5
+
6
+ # Queue Patterns
7
+
8
+ ## When to Use
9
+ Use job queues when you need to defer work, process tasks asynchronously, handle spikes in workload, or ensure reliable execution of operations that may fail. Queues decouple producers from consumers, enabling retry logic, priority ordering, rate-controlled processing, and distributed workloads. Apply these patterns for email sending, image processing, webhook delivery, report generation, and any task that should not block the request-response cycle.
10
+
11
+ ## How It Works
12
+
13
+ ### BullMQ Queue Setup
14
+
15
+ ```typescript
16
+ // src/queues/index.ts
17
+ import { Queue, Worker, QueueEvents } from 'bullmq';
18
+ import Redis from 'ioredis';
19
+
20
+ const connection = new Redis(process.env.REDIS_URL!, { maxRetriesPerRequest: null });
21
+
22
+ // Define typed job data
23
+ interface EmailJobData {
24
+ to: string;
25
+ subject: string;
26
+ template: string;
27
+ variables: Record<string, string>;
28
+ }
29
+
30
+ interface ImageJobData {
31
+ sourceUrl: string;
32
+ outputPath: string;
33
+ width: number;
34
+ height: number;
35
+ format: 'webp' | 'avif' | 'jpeg';
36
+ }
37
+
38
+ // Create queues
39
+ export const emailQueue = new Queue<EmailJobData>('email', {
40
+ connection,
41
+ defaultJobOptions: {
42
+ attempts: 3,
43
+ backoff: { type: 'exponential', delay: 5000 },
44
+ removeOnComplete: { age: 86400, count: 1000 },
45
+ removeOnFail: { age: 604800 },
46
+ },
47
+ });
48
+
49
+ export const imageQueue = new Queue<ImageJobData>('image-processing', {
50
+ connection,
51
+ defaultJobOptions: {
52
+ attempts: 2,
53
+ backoff: { type: 'fixed', delay: 10000 },
54
+ timeout: 120_000,
55
+ },
56
+ });
57
+ ```
58
+
59
+ ### Worker Definition
60
+
61
+ ```typescript
62
+ // src/workers/email.worker.ts
63
+ import { Worker, Job } from 'bullmq';
64
+ import { sendEmail } from '../services/email';
65
+
66
+ const emailWorker = new Worker<EmailJobData>(
67
+ 'email',
68
+ async (job: Job<EmailJobData>) => {
69
+ const { to, subject, template, variables } = job.data;
70
+
71
+ await job.updateProgress(10);
72
+
73
+ const html = await renderTemplate(template, variables);
74
+ await job.updateProgress(50);
75
+
76
+ const result = await sendEmail({ to, subject, html });
77
+ await job.updateProgress(100);
78
+
79
+ return { messageId: result.messageId, sentAt: new Date().toISOString() };
80
+ },
81
+ {
82
+ connection,
83
+ concurrency: 5, // process 5 jobs simultaneously
84
+ limiter: { max: 50, duration: 60_000 }, // max 50 per minute
85
+ }
86
+ );
87
+
88
+ emailWorker.on('completed', (job) => {
89
+ console.log(`Email sent: ${job.id} to ${job.data.to}`);
90
+ });
91
+
92
+ emailWorker.on('failed', (job, err) => {
93
+ console.error(`Email failed: ${job?.id}`, err.message);
94
+ if (job && job.attemptsMade >= (job.opts.attempts ?? 3)) {
95
+ // Move to dead letter queue after all retries exhausted
96
+ deadLetterQueue.add('email-failed', { originalJob: job.data, error: err.message });
97
+ }
98
+ });
99
+ ```
100
+
101
+ ### Priority Queue
102
+
103
+ ```typescript
104
+ // src/queues/priority.ts
105
+ export async function addJobWithPriority(data: EmailJobData, priority: 'high' | 'normal' | 'low') {
106
+ const priorityMap = { high: 1, normal: 5, low: 10 };
107
+
108
+ await emailQueue.add('send-email', data, {
109
+ priority: priorityMap[priority],
110
+ });
111
+ }
112
+
113
+ // High-priority transactional emails
114
+ await addJobWithPriority({
115
+ to: 'user@example.com',
116
+ subject: 'Password Reset',
117
+ template: 'password-reset',
118
+ variables: { resetLink: 'https://...' },
119
+ }, 'high');
120
+
121
+ // Low-priority marketing emails
122
+ await addJobWithPriority({
123
+ to: 'user@example.com',
124
+ subject: 'Weekly Digest',
125
+ template: 'weekly-digest',
126
+ variables: { userName: 'Alice' },
127
+ }, 'low');
128
+ ```
129
+
130
+ ### Delayed Jobs
131
+
132
+ ```typescript
133
+ // src/queues/scheduled.ts
134
+ // Send email 24 hours after signup
135
+ export async function scheduleWelcomeEmail(userId: string, email: string) {
136
+ await emailQueue.add('welcome-email', {
137
+ to: email,
138
+ subject: 'Getting started with MyApp',
139
+ template: 'welcome',
140
+ variables: { userId },
141
+ }, {
142
+ delay: 24 * 60 * 60 * 1000, // 24 hours
143
+ jobId: `welcome-${userId}`, // prevent duplicates
144
+ });
145
+ }
146
+
147
+ // Repeating jobs (cron-like)
148
+ export async function setupRecurringJobs() {
149
+ await emailQueue.add('daily-digest', {
150
+ to: 'admin@example.com',
151
+ subject: 'Daily Report',
152
+ template: 'daily-report',
153
+ variables: {},
154
+ }, {
155
+ repeat: {
156
+ pattern: '0 9 * * *', // every day at 9 AM
157
+ tz: 'America/New_York',
158
+ },
159
+ });
160
+ }
161
+ ```
162
+
163
+ ### Dead Letter Queue
164
+
165
+ ```typescript
166
+ // src/queues/dead-letter.ts
167
+ export const deadLetterQueue = new Queue('dead-letter', {
168
+ connection,
169
+ defaultJobOptions: {
170
+ removeOnComplete: false, // keep for inspection
171
+ },
172
+ });
173
+
174
+ // Worker to handle dead letter inspection
175
+ const dlqWorker = new Worker(
176
+ 'dead-letter',
177
+ async (job) => {
178
+ // Log to monitoring
179
+ await logToMonitoring({
180
+ type: 'dead-letter',
181
+ originalQueue: job.name,
182
+ data: job.data,
183
+ timestamp: new Date().toISOString(),
184
+ });
185
+
186
+ // Alert on critical failures
187
+ if (job.data.originalJob?.template === 'password-reset') {
188
+ await alertOncall('Critical email delivery failure', job.data);
189
+ }
190
+ },
191
+ { connection, concurrency: 1 }
192
+ );
193
+
194
+ // Admin API to retry dead-lettered jobs
195
+ export async function retryDeadLetter(jobId: string) {
196
+ const job = await deadLetterQueue.getJob(jobId);
197
+ if (!job) throw new Error(`Job ${jobId} not found`);
198
+
199
+ const { originalJob } = job.data;
200
+ await emailQueue.add('retry', originalJob, { attempts: 1 });
201
+ await job.remove();
202
+ }
203
+ ```
204
+
205
+ ### Exactly-Once Processing Pattern
206
+
207
+ ```typescript
208
+ // src/workers/idempotent.ts
209
+ import { Job } from 'bullmq';
210
+
211
+ async function processIdempotent(job: Job) {
212
+ const idempotencyKey = `processed:${job.id}`;
213
+
214
+ // Check if already processed
215
+ const alreadyProcessed = await redis.get(idempotencyKey);
216
+ if (alreadyProcessed) {
217
+ console.log(`Job ${job.id} already processed, skipping`);
218
+ return JSON.parse(alreadyProcessed);
219
+ }
220
+
221
+ // Process the job
222
+ const result = await doWork(job.data);
223
+
224
+ // Mark as processed with TTL
225
+ await redis.set(idempotencyKey, JSON.stringify(result), 'EX', 86400);
226
+
227
+ return result;
228
+ }
229
+ ```
230
+
231
+ ### Queue Monitoring Dashboard
232
+
233
+ ```typescript
234
+ // src/routes/admin/queues.ts
235
+ import { Queue } from 'bullmq';
236
+
237
+ export async function getQueueStats(queue: Queue) {
238
+ const [waiting, active, completed, failed, delayed] = await Promise.all([
239
+ queue.getWaitingCount(),
240
+ queue.getActiveCount(),
241
+ queue.getCompletedCount(),
242
+ queue.getFailedCount(),
243
+ queue.getDelayedCount(),
244
+ ]);
245
+
246
+ return {
247
+ name: queue.name,
248
+ counts: { waiting, active, completed, failed, delayed },
249
+ isPaused: await queue.isPaused(),
250
+ };
251
+ }
252
+
253
+ app.get('/admin/queues', async (_req, res) => {
254
+ const stats = await Promise.all([
255
+ getQueueStats(emailQueue),
256
+ getQueueStats(imageQueue),
257
+ getQueueStats(deadLetterQueue),
258
+ ]);
259
+ res.json({ queues: stats });
260
+ });
261
+
262
+ // Pause/resume for maintenance
263
+ app.post('/admin/queues/:name/pause', async (req, res) => {
264
+ const queue = getQueueByName(req.params.name);
265
+ await queue.pause();
266
+ res.json({ paused: true });
267
+ });
268
+
269
+ app.post('/admin/queues/:name/resume', async (req, res) => {
270
+ const queue = getQueueByName(req.params.name);
271
+ await queue.resume();
272
+ res.json({ paused: false });
273
+ });
274
+ ```
275
+
276
+ ## Examples
277
+
278
+ | Pattern | Use Case | Retry Strategy |
279
+ |---------|----------|----------------|
280
+ | FIFO | Order processing | Exponential backoff, 3 attempts |
281
+ | Priority | Transactional vs marketing email | Priority 1/5/10, same retry |
282
+ | Delayed | Welcome email after 24h | Single attempt, no retry |
283
+ | Repeating | Daily report generation | Cron pattern, skip on failure |
284
+ | Dead letter | Failed after all retries | Manual inspection and retry |
285
+ | Batch | Bulk CSV import | Chunk into sub-jobs, parallel |
286
+
287
+ ## Checklist
288
+ - [ ] Queues use `maxRetriesPerRequest: null` in Redis connection for BullMQ
289
+ - [ ] Default job options set for attempts, backoff, and TTL
290
+ - [ ] Workers have concurrency limits matching resource capacity
291
+ - [ ] Rate limiter configured for external API calls (email, SMS)
292
+ - [ ] Dead letter queue captures jobs that exhaust all retries
293
+ - [ ] Idempotency keys prevent duplicate processing on retry
294
+ - [ ] Queue monitoring endpoint exposes counts and pause state
295
+ - [ ] Delayed and repeating jobs use unique `jobId` to prevent duplicates