@hivehub/rulebook 2.1.0 → 3.0.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.
- package/README.md +779 -661
- package/dist/cli/commands.d.ts +22 -0
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +291 -8
- package/dist/cli/commands.js.map +1 -1
- package/dist/core/claude-mcp.d.ts +32 -0
- package/dist/core/claude-mcp.d.ts.map +1 -0
- package/dist/core/claude-mcp.js +92 -0
- package/dist/core/claude-mcp.js.map +1 -0
- package/dist/core/config-manager.d.ts.map +1 -1
- package/dist/core/config-manager.js +27 -6
- package/dist/core/config-manager.js.map +1 -1
- package/dist/core/generator.d.ts.map +1 -1
- package/dist/core/generator.js +98 -49
- package/dist/core/generator.js.map +1 -1
- package/dist/core/migrator.d.ts +13 -0
- package/dist/core/migrator.d.ts.map +1 -1
- package/dist/core/migrator.js +76 -9
- package/dist/core/migrator.js.map +1 -1
- package/dist/core/openspec-migrator.d.ts +1 -1
- package/dist/core/openspec-migrator.d.ts.map +1 -1
- package/dist/core/openspec-migrator.js +14 -7
- package/dist/core/openspec-migrator.js.map +1 -1
- package/dist/core/workflow-generator.js +297 -261
- package/dist/core/workflow-generator.js.map +1 -1
- package/dist/index.js +40 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/rulebook-server.d.ts.map +1 -1
- package/dist/mcp/rulebook-server.js +255 -74
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/dist/memory/hnsw-index.d.ts +63 -0
- package/dist/memory/hnsw-index.d.ts.map +1 -0
- package/dist/memory/hnsw-index.js +421 -0
- package/dist/memory/hnsw-index.js.map +1 -0
- package/dist/memory/memory-cache.d.ts +33 -0
- package/dist/memory/memory-cache.d.ts.map +1 -0
- package/dist/memory/memory-cache.js +85 -0
- package/dist/memory/memory-cache.js.map +1 -0
- package/dist/memory/memory-hooks.d.ts +42 -0
- package/dist/memory/memory-hooks.d.ts.map +1 -0
- package/dist/memory/memory-hooks.js +193 -0
- package/dist/memory/memory-hooks.js.map +1 -0
- package/dist/memory/memory-manager.d.ts +55 -0
- package/dist/memory/memory-manager.d.ts.map +1 -0
- package/dist/memory/memory-manager.js +209 -0
- package/dist/memory/memory-manager.js.map +1 -0
- package/dist/memory/memory-search.d.ts +42 -0
- package/dist/memory/memory-search.d.ts.map +1 -0
- package/dist/memory/memory-search.js +166 -0
- package/dist/memory/memory-search.js.map +1 -0
- package/dist/memory/memory-store.d.ts +59 -0
- package/dist/memory/memory-store.d.ts.map +1 -0
- package/dist/memory/memory-store.js +394 -0
- package/dist/memory/memory-store.js.map +1 -0
- package/dist/memory/memory-types.d.ts +69 -0
- package/dist/memory/memory-types.d.ts.map +1 -0
- package/dist/memory/memory-types.js +7 -0
- package/dist/memory/memory-types.js.map +1 -0
- package/dist/memory/memory-vectorizer.d.ts +29 -0
- package/dist/memory/memory-vectorizer.d.ts.map +1 -0
- package/dist/memory/memory-vectorizer.js +104 -0
- package/dist/memory/memory-vectorizer.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +107 -106
- package/templates/commands/rulebook-memory-save.md +48 -0
- package/templates/commands/rulebook-memory-search.md +47 -0
- package/templates/commands/rulebook-task-apply.md +2 -2
- package/templates/commands/rulebook-task-archive.md +2 -2
- package/templates/commands/rulebook-task-create.md +2 -2
- package/templates/commands/rulebook-task-list.md +2 -2
- package/templates/commands/rulebook-task-show.md +2 -2
- package/templates/commands/rulebook-task-validate.md +2 -2
- package/templates/git/CI_CD_PATTERNS.md +4 -4
- package/templates/git/GITHUB_ACTIONS.md +3 -3
- package/templates/git/GITLAB_CI.md +4 -4
- package/templates/git/SECRETS_MANAGEMENT.md +4 -4
- package/templates/hooks/COMMIT_MSG.md +4 -4
- package/templates/hooks/POST_CHECKOUT.md +3 -3
- package/templates/hooks/PREPARE_COMMIT_MSG.md +3 -3
- package/templates/hooks/PRE_COMMIT.md +4 -4
- package/templates/hooks/PRE_PUSH.md +4 -4
- package/templates/modules/MEMORY.md +63 -0
- package/templates/skills/cli/aider/SKILL.md +59 -0
- package/templates/skills/cli/amazon-q/SKILL.md +35 -0
- package/templates/skills/cli/auggie/SKILL.md +42 -0
- package/templates/skills/cli/claude/SKILL.md +42 -0
- package/templates/skills/cli/claude-code/SKILL.md +146 -0
- package/templates/skills/cli/cline/SKILL.md +42 -0
- package/templates/skills/cli/codebuddy/SKILL.md +30 -0
- package/templates/skills/cli/codeium/SKILL.md +30 -0
- package/templates/skills/cli/codex/SKILL.md +31 -0
- package/templates/skills/cli/continue/SKILL.md +44 -0
- package/templates/skills/cli/cursor-cli/SKILL.md +38 -0
- package/templates/skills/cli/factory/SKILL.md +28 -0
- package/templates/skills/cli/gemini/SKILL.md +45 -0
- package/templates/skills/cli/kilocode/SKILL.md +28 -0
- package/templates/skills/cli/opencode/SKILL.md +28 -0
- package/templates/skills/core/agent-automation/SKILL.md +194 -0
- package/templates/skills/core/dag/SKILL.md +314 -0
- package/templates/skills/core/documentation-rules/SKILL.md +47 -0
- package/templates/skills/core/quality-enforcement/SKILL.md +78 -0
- package/templates/skills/frameworks/angular/SKILL.md +46 -0
- package/templates/skills/frameworks/django/SKILL.md +93 -0
- package/templates/skills/frameworks/electron/SKILL.md +157 -0
- package/templates/skills/frameworks/flask/SKILL.md +48 -0
- package/templates/skills/frameworks/flutter/SKILL.md +65 -0
- package/templates/skills/frameworks/jquery/SKILL.md +42 -0
- package/templates/skills/frameworks/laravel/SKILL.md +48 -0
- package/templates/skills/frameworks/nestjs/SKILL.md +53 -0
- package/templates/skills/frameworks/nextjs/SKILL.md +137 -0
- package/templates/skills/frameworks/nuxt/SKILL.md +50 -0
- package/templates/skills/frameworks/rails/SKILL.md +76 -0
- package/templates/skills/frameworks/react/SKILL.md +48 -0
- package/templates/skills/frameworks/react-native/SKILL.md +57 -0
- package/templates/skills/frameworks/spring/SKILL.md +49 -0
- package/templates/skills/frameworks/symfony/SKILL.md +46 -0
- package/templates/skills/frameworks/vue/SKILL.md +46 -0
- package/templates/skills/frameworks/zend/SKILL.md +45 -0
- package/templates/skills/ides/copilot/SKILL.md +47 -0
- package/templates/skills/ides/cursor/SKILL.md +53 -0
- package/templates/skills/ides/jetbrains-ai/SKILL.md +45 -0
- package/templates/skills/ides/replit/SKILL.md +46 -0
- package/templates/skills/ides/tabnine/SKILL.md +39 -0
- package/templates/skills/ides/vscode/SKILL.md +50 -0
- package/templates/skills/ides/windsurf/SKILL.md +46 -0
- package/templates/skills/ides/zed/SKILL.md +42 -0
- package/templates/skills/languages/ada/SKILL.md +68 -0
- package/templates/skills/languages/c/SKILL.md +343 -0
- package/templates/skills/languages/cpp/SKILL.md +753 -0
- package/templates/skills/languages/csharp/SKILL.md +427 -0
- package/templates/skills/languages/dart/SKILL.md +342 -0
- package/templates/skills/languages/elixir/SKILL.md +464 -0
- package/templates/skills/languages/erlang/SKILL.md +371 -0
- package/templates/skills/languages/go/SKILL.md +655 -0
- package/templates/skills/languages/haskell/SKILL.md +187 -0
- package/templates/skills/languages/java/SKILL.md +617 -0
- package/templates/skills/languages/javascript/SKILL.md +641 -0
- package/templates/skills/languages/julia/SKILL.md +107 -0
- package/templates/skills/languages/kotlin/SKILL.md +521 -0
- package/templates/skills/languages/lisp/SKILL.md +110 -0
- package/templates/skills/languages/lua/SKILL.md +84 -0
- package/templates/skills/languages/objectivec/SKILL.md +100 -0
- package/templates/skills/languages/php/SKILL.md +426 -0
- package/templates/skills/languages/python/SKILL.md +692 -0
- package/templates/skills/languages/r/SKILL.md +360 -0
- package/templates/skills/languages/ruby/SKILL.md +431 -0
- package/templates/skills/languages/rust/SKILL.md +487 -0
- package/templates/skills/languages/sas/SKILL.md +83 -0
- package/templates/skills/languages/scala/SKILL.md +358 -0
- package/templates/skills/languages/solidity/SKILL.md +590 -0
- package/templates/skills/languages/sql/SKILL.md +147 -0
- package/templates/skills/languages/swift/SKILL.md +476 -0
- package/templates/skills/languages/zig/SKILL.md +275 -0
- package/templates/skills/modules/atlassian/SKILL.md +265 -0
- package/templates/skills/modules/context7/SKILL.md +64 -0
- package/templates/skills/modules/figma/SKILL.md +277 -0
- package/templates/skills/modules/github-mcp/SKILL.md +74 -0
- package/templates/skills/modules/grafana/SKILL.md +338 -0
- package/templates/skills/modules/memory/SKILL.md +73 -0
- package/templates/skills/modules/notion/SKILL.md +257 -0
- package/templates/skills/modules/playwright/SKILL.md +100 -0
- package/templates/skills/modules/rulebook-mcp/SKILL.md +166 -0
- package/templates/skills/modules/serena/SKILL.md +347 -0
- package/templates/skills/modules/supabase/SKILL.md +233 -0
- package/templates/skills/modules/synap/SKILL.md +79 -0
- package/templates/skills/modules/vectorizer/SKILL.md +73 -0
- package/templates/skills/services/azure-blob/SKILL.md +194 -0
- package/templates/skills/services/cassandra/SKILL.md +249 -0
- package/templates/skills/services/dynamodb/SKILL.md +318 -0
- package/templates/skills/services/elasticsearch/SKILL.md +357 -0
- package/templates/skills/services/gcs/SKILL.md +188 -0
- package/templates/skills/services/influxdb/SKILL.md +275 -0
- package/templates/skills/services/kafka/SKILL.md +351 -0
- package/templates/skills/services/mariadb/SKILL.md +193 -0
- package/templates/skills/services/memcached/SKILL.md +252 -0
- package/templates/skills/services/minio/SKILL.md +211 -0
- package/templates/skills/services/mongodb/SKILL.md +278 -0
- package/templates/skills/services/mysql/SKILL.md +368 -0
- package/templates/skills/services/neo4j/SKILL.md +257 -0
- package/templates/skills/services/oracle/SKILL.md +300 -0
- package/templates/skills/services/postgresql/SKILL.md +336 -0
- package/templates/skills/services/rabbitmq/SKILL.md +296 -0
- package/templates/skills/services/redis/SKILL.md +302 -0
- package/templates/skills/services/s3/SKILL.md +308 -0
- package/templates/skills/services/sqlite/SKILL.md +304 -0
- package/templates/skills/services/sqlserver/SKILL.md +304 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "Kafka"
|
|
3
|
+
description: "Use Kafka for high-throughput event streaming, real-time data pipelines, and distributed messaging with fault tolerance."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
category: "services"
|
|
6
|
+
author: "Rulebook"
|
|
7
|
+
tags: ["services", "messaging"]
|
|
8
|
+
dependencies: []
|
|
9
|
+
conflicts: []
|
|
10
|
+
---
|
|
11
|
+
<!-- KAFKA:START -->
|
|
12
|
+
# Apache Kafka Message Streaming Instructions
|
|
13
|
+
|
|
14
|
+
**CRITICAL**: Use Kafka for high-throughput event streaming, real-time data pipelines, and distributed messaging with fault tolerance.
|
|
15
|
+
|
|
16
|
+
## Core Features
|
|
17
|
+
|
|
18
|
+
### Connection
|
|
19
|
+
```typescript
|
|
20
|
+
// Using kafkajs
|
|
21
|
+
import { Kafka } from 'kafkajs'
|
|
22
|
+
|
|
23
|
+
const kafka = new Kafka({
|
|
24
|
+
clientId: 'my-app',
|
|
25
|
+
brokers: (process.env.KAFKA_BROKERS || 'localhost:9092').split(','),
|
|
26
|
+
ssl: process.env.KAFKA_SSL === 'true',
|
|
27
|
+
sasl: process.env.KAFKA_USERNAME ? {
|
|
28
|
+
mechanism: 'plain',
|
|
29
|
+
username: process.env.KAFKA_USERNAME,
|
|
30
|
+
password: process.env.KAFKA_PASSWORD,
|
|
31
|
+
} : undefined,
|
|
32
|
+
retry: {
|
|
33
|
+
initialRetryTime: 100,
|
|
34
|
+
retries: 8,
|
|
35
|
+
},
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const producer = kafka.producer()
|
|
39
|
+
const consumer = kafka.consumer({ groupId: 'my-group' })
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Producing Messages
|
|
43
|
+
```typescript
|
|
44
|
+
await producer.connect()
|
|
45
|
+
|
|
46
|
+
// Send single message
|
|
47
|
+
await producer.send({
|
|
48
|
+
topic: 'users',
|
|
49
|
+
messages: [{
|
|
50
|
+
key: 'user-1',
|
|
51
|
+
value: JSON.stringify({ id: '1', name: 'John', email: 'john@example.com' }),
|
|
52
|
+
headers: {
|
|
53
|
+
'content-type': 'application/json',
|
|
54
|
+
},
|
|
55
|
+
}],
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// Send multiple messages
|
|
59
|
+
await producer.send({
|
|
60
|
+
topic: 'events',
|
|
61
|
+
messages: [
|
|
62
|
+
{ key: 'event-1', value: JSON.stringify({ type: 'created', id: '1' }) },
|
|
63
|
+
{ key: 'event-2', value: JSON.stringify({ type: 'updated', id: '2' }) },
|
|
64
|
+
],
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// Send with partition
|
|
68
|
+
await producer.send({
|
|
69
|
+
topic: 'orders',
|
|
70
|
+
messages: [{
|
|
71
|
+
key: 'order-1',
|
|
72
|
+
value: JSON.stringify({ orderId: '1', amount: 100 }),
|
|
73
|
+
partition: 0, // Specific partition
|
|
74
|
+
}],
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
await producer.disconnect()
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Consuming Messages
|
|
81
|
+
```typescript
|
|
82
|
+
await consumer.connect()
|
|
83
|
+
await consumer.subscribe({ topic: 'users', fromBeginning: false })
|
|
84
|
+
|
|
85
|
+
await consumer.run({
|
|
86
|
+
eachMessage: async ({ topic, partition, message }) => {
|
|
87
|
+
const key = message.key?.toString()
|
|
88
|
+
const value = JSON.parse(message.value?.toString() || '{}')
|
|
89
|
+
|
|
90
|
+
console.log({
|
|
91
|
+
topic,
|
|
92
|
+
partition,
|
|
93
|
+
offset: message.offset,
|
|
94
|
+
key,
|
|
95
|
+
value,
|
|
96
|
+
headers: message.headers,
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// Process message
|
|
100
|
+
await processMessage(value)
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
// Consume from specific partition
|
|
105
|
+
await consumer.subscribe({ topic: 'events' })
|
|
106
|
+
await consumer.run({
|
|
107
|
+
partitionsConsumedConcurrently: 1, // Process one partition at a time
|
|
108
|
+
eachMessage: async ({ topic, partition, message }) => {
|
|
109
|
+
// Process message
|
|
110
|
+
},
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Advanced Features
|
|
115
|
+
```typescript
|
|
116
|
+
// Transactional producer
|
|
117
|
+
const transactionalProducer = kafka.producer({
|
|
118
|
+
transactionalId: 'my-transactional-producer',
|
|
119
|
+
maxInFlightRequests: 1,
|
|
120
|
+
idempotent: true,
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
await transactionalProducer.connect()
|
|
124
|
+
|
|
125
|
+
await transactionalProducer.send({
|
|
126
|
+
topic: 'users',
|
|
127
|
+
messages: [{ key: 'user-1', value: JSON.stringify(userData) }],
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
await transactionalProducer.sendOffsets({
|
|
131
|
+
consumerGroupId: 'my-group',
|
|
132
|
+
topics: [{
|
|
133
|
+
topic: 'users',
|
|
134
|
+
partitions: [{ partition: 0, offset: '100' }],
|
|
135
|
+
}],
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
await transactionalProducer.commitTransaction()
|
|
139
|
+
|
|
140
|
+
// Admin operations
|
|
141
|
+
const admin = kafka.admin()
|
|
142
|
+
await admin.connect()
|
|
143
|
+
|
|
144
|
+
// Create topic
|
|
145
|
+
await admin.createTopics({
|
|
146
|
+
topics: [{
|
|
147
|
+
topic: 'new-topic',
|
|
148
|
+
numPartitions: 3,
|
|
149
|
+
replicationFactor: 1,
|
|
150
|
+
configEntries: [
|
|
151
|
+
{ name: 'retention.ms', value: '604800000' }, // 7 days
|
|
152
|
+
],
|
|
153
|
+
}],
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
// List topics
|
|
157
|
+
const topics = await admin.listTopics()
|
|
158
|
+
|
|
159
|
+
// Delete topic
|
|
160
|
+
await admin.deleteTopics({
|
|
161
|
+
topics: ['old-topic'],
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
await admin.disconnect()
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Common Patterns
|
|
168
|
+
|
|
169
|
+
### Event Sourcing
|
|
170
|
+
```typescript
|
|
171
|
+
async function publishEvent(eventType: string, aggregateId: string, data: any) {
|
|
172
|
+
await producer.send({
|
|
173
|
+
topic: 'events',
|
|
174
|
+
messages: [{
|
|
175
|
+
key: aggregateId,
|
|
176
|
+
value: JSON.stringify({
|
|
177
|
+
eventType,
|
|
178
|
+
aggregateId,
|
|
179
|
+
data,
|
|
180
|
+
timestamp: new Date().toISOString(),
|
|
181
|
+
version: 1,
|
|
182
|
+
}),
|
|
183
|
+
headers: {
|
|
184
|
+
'event-type': eventType,
|
|
185
|
+
},
|
|
186
|
+
}],
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Replay events
|
|
191
|
+
await consumer.subscribe({ topic: 'events', fromBeginning: true })
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### CQRS Pattern
|
|
195
|
+
```typescript
|
|
196
|
+
// Command side (write)
|
|
197
|
+
async function handleCommand(command: any) {
|
|
198
|
+
// Process command
|
|
199
|
+
const result = await processCommand(command)
|
|
200
|
+
|
|
201
|
+
// Publish event
|
|
202
|
+
await producer.send({
|
|
203
|
+
topic: 'commands',
|
|
204
|
+
messages: [{
|
|
205
|
+
key: command.aggregateId,
|
|
206
|
+
value: JSON.stringify({
|
|
207
|
+
commandType: command.type,
|
|
208
|
+
aggregateId: command.aggregateId,
|
|
209
|
+
data: result,
|
|
210
|
+
}),
|
|
211
|
+
}],
|
|
212
|
+
})
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Query side (read)
|
|
216
|
+
await consumer.subscribe({ topic: 'commands' })
|
|
217
|
+
await consumer.run({
|
|
218
|
+
eachMessage: async ({ message }) => {
|
|
219
|
+
const command = JSON.parse(message.value?.toString() || '{}')
|
|
220
|
+
await updateReadModel(command)
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Stream Processing
|
|
226
|
+
```typescript
|
|
227
|
+
// Process stream with state
|
|
228
|
+
const stateStore = new Map<string, any>()
|
|
229
|
+
|
|
230
|
+
await consumer.subscribe({ topic: 'events' })
|
|
231
|
+
await consumer.run({
|
|
232
|
+
eachMessage: async ({ message }) => {
|
|
233
|
+
const event = JSON.parse(message.value?.toString() || '{}')
|
|
234
|
+
const key = event.aggregateId
|
|
235
|
+
|
|
236
|
+
// Update state
|
|
237
|
+
const currentState = stateStore.get(key) || {}
|
|
238
|
+
const newState = { ...currentState, ...event.data }
|
|
239
|
+
stateStore.set(key, newState)
|
|
240
|
+
|
|
241
|
+
// Emit aggregated result
|
|
242
|
+
await producer.send({
|
|
243
|
+
topic: 'aggregated-events',
|
|
244
|
+
messages: [{
|
|
245
|
+
key,
|
|
246
|
+
value: JSON.stringify(newState),
|
|
247
|
+
}],
|
|
248
|
+
})
|
|
249
|
+
},
|
|
250
|
+
})
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Best Practices
|
|
254
|
+
|
|
255
|
+
✅ **DO:**
|
|
256
|
+
- Use appropriate partition keys for message ordering
|
|
257
|
+
- Implement idempotent consumers
|
|
258
|
+
- Use consumer groups for load balancing
|
|
259
|
+
- Monitor consumer lag
|
|
260
|
+
- Use transactions for exactly-once semantics
|
|
261
|
+
- Set appropriate retention policies
|
|
262
|
+
- Use compression for large messages
|
|
263
|
+
- Implement proper error handling
|
|
264
|
+
- Use schema registry for message validation
|
|
265
|
+
- Monitor topic sizes and partitions
|
|
266
|
+
|
|
267
|
+
❌ **DON'T:**
|
|
268
|
+
- Store large messages (> 1MB, use external storage)
|
|
269
|
+
- Skip error handling
|
|
270
|
+
- Ignore consumer lag
|
|
271
|
+
- Hardcode broker addresses
|
|
272
|
+
- Use too many partitions (affects performance)
|
|
273
|
+
- Skip idempotency checks
|
|
274
|
+
- Ignore message ordering requirements
|
|
275
|
+
- Store sensitive data without encryption
|
|
276
|
+
- Skip monitoring
|
|
277
|
+
- Use synchronous operations
|
|
278
|
+
|
|
279
|
+
## Configuration
|
|
280
|
+
|
|
281
|
+
### Environment Variables
|
|
282
|
+
```bash
|
|
283
|
+
KAFKA_BROKERS=localhost:9092
|
|
284
|
+
KAFKA_BROKERS=broker1:9092,broker2:9092,broker3:9092
|
|
285
|
+
KAFKA_SSL=false
|
|
286
|
+
KAFKA_USERNAME=
|
|
287
|
+
KAFKA_PASSWORD=
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Docker Compose
|
|
291
|
+
```yaml
|
|
292
|
+
services:
|
|
293
|
+
zookeeper:
|
|
294
|
+
image: confluentinc/cp-zookeeper:latest
|
|
295
|
+
environment:
|
|
296
|
+
ZOOKEEPER_CLIENT_PORT: 2181
|
|
297
|
+
ZOOKEEPER_TICK_TIME: 2000
|
|
298
|
+
ports:
|
|
299
|
+
- "2181:2181"
|
|
300
|
+
|
|
301
|
+
kafka:
|
|
302
|
+
image: confluentinc/cp-kafka:latest
|
|
303
|
+
depends_on:
|
|
304
|
+
- zookeeper
|
|
305
|
+
ports:
|
|
306
|
+
- "9092:9092"
|
|
307
|
+
environment:
|
|
308
|
+
KAFKA_BROKER_ID: 1
|
|
309
|
+
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
|
|
310
|
+
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
|
|
311
|
+
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
|
|
312
|
+
healthcheck:
|
|
313
|
+
test: ["CMD", "kafka-broker-api-versions", "--bootstrap-server", "localhost:9092"]
|
|
314
|
+
interval: 10s
|
|
315
|
+
timeout: 5s
|
|
316
|
+
retries: 5
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
## Integration with Development
|
|
320
|
+
|
|
321
|
+
### Testing
|
|
322
|
+
```typescript
|
|
323
|
+
// Use test Kafka instance
|
|
324
|
+
const testKafka = new Kafka({
|
|
325
|
+
clientId: 'test-app',
|
|
326
|
+
brokers: ['localhost:9093'], // Different port
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
// Clean up after tests
|
|
330
|
+
afterEach(async () => {
|
|
331
|
+
// Delete test topics or use separate test cluster
|
|
332
|
+
})
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Health Checks
|
|
336
|
+
```typescript
|
|
337
|
+
async function checkKafkaHealth(): Promise<boolean> {
|
|
338
|
+
try {
|
|
339
|
+
const admin = kafka.admin()
|
|
340
|
+
await admin.connect()
|
|
341
|
+
await admin.listTopics()
|
|
342
|
+
await admin.disconnect()
|
|
343
|
+
return true
|
|
344
|
+
} catch {
|
|
345
|
+
return false
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
<!-- KAFKA:END -->
|
|
351
|
+
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "MariaDB"
|
|
3
|
+
description: "Use MariaDB for MySQL-compatible relational database with enhanced features, performance improvements, and open-source licensing."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
category: "services"
|
|
6
|
+
author: "Rulebook"
|
|
7
|
+
tags: ["services", "database"]
|
|
8
|
+
dependencies: []
|
|
9
|
+
conflicts: []
|
|
10
|
+
---
|
|
11
|
+
<!-- MARIADB:START -->
|
|
12
|
+
# MariaDB Database Instructions
|
|
13
|
+
|
|
14
|
+
**CRITICAL**: Use MariaDB for MySQL-compatible relational database with enhanced features, performance improvements, and open-source licensing.
|
|
15
|
+
|
|
16
|
+
## Core Features
|
|
17
|
+
|
|
18
|
+
### Connection
|
|
19
|
+
```typescript
|
|
20
|
+
// Using mysql2 (compatible with MySQL)
|
|
21
|
+
import mysql from 'mysql2/promise'
|
|
22
|
+
|
|
23
|
+
const pool = mysql.createPool({
|
|
24
|
+
host: process.env.DB_HOST || 'localhost',
|
|
25
|
+
port: parseInt(process.env.DB_PORT || '3306'),
|
|
26
|
+
database: process.env.DB_NAME || 'myapp',
|
|
27
|
+
user: process.env.DB_USER,
|
|
28
|
+
password: process.env.DB_PASSWORD,
|
|
29
|
+
waitForConnections: true,
|
|
30
|
+
connectionLimit: 10,
|
|
31
|
+
queueLimit: 0,
|
|
32
|
+
enableKeepAlive: true,
|
|
33
|
+
keepAliveInitialDelay: 0,
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
// Using Prisma
|
|
37
|
+
import { PrismaClient } from '@prisma/client'
|
|
38
|
+
const prisma = new PrismaClient()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Basic Queries
|
|
42
|
+
```typescript
|
|
43
|
+
// SELECT
|
|
44
|
+
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ?', [userId])
|
|
45
|
+
const users = rows as User[]
|
|
46
|
+
|
|
47
|
+
// INSERT
|
|
48
|
+
const [result] = await pool.execute(
|
|
49
|
+
'INSERT INTO users (name, email) VALUES (?, ?)',
|
|
50
|
+
['John Doe', 'john@example.com']
|
|
51
|
+
)
|
|
52
|
+
const insertId = (result as any).insertId
|
|
53
|
+
|
|
54
|
+
// UPDATE
|
|
55
|
+
const [result] = await pool.execute(
|
|
56
|
+
'UPDATE users SET name = ? WHERE id = ?',
|
|
57
|
+
['Jane Doe', userId]
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
// DELETE
|
|
61
|
+
await pool.execute('DELETE FROM users WHERE id = ?', [userId])
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Advanced Features
|
|
65
|
+
```typescript
|
|
66
|
+
// JSON operations (MariaDB 10.2.7+)
|
|
67
|
+
const [rows] = await pool.execute(
|
|
68
|
+
"SELECT * FROM products WHERE JSON_EXTRACT(metadata, '$.category') = ?",
|
|
69
|
+
['electronics']
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
// Window functions (MariaDB 10.2+)
|
|
73
|
+
const [rows] = await pool.execute(`
|
|
74
|
+
SELECT
|
|
75
|
+
name,
|
|
76
|
+
salary,
|
|
77
|
+
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank
|
|
78
|
+
FROM employees
|
|
79
|
+
`)
|
|
80
|
+
|
|
81
|
+
// Common Table Expressions (CTE) (MariaDB 10.2+)
|
|
82
|
+
const [rows] = await pool.execute(`
|
|
83
|
+
WITH RECURSIVE cte AS (
|
|
84
|
+
SELECT id, name, parent_id FROM categories WHERE parent_id IS NULL
|
|
85
|
+
UNION ALL
|
|
86
|
+
SELECT c.id, c.name, c.parent_id FROM categories c
|
|
87
|
+
INNER JOIN cte ON c.parent_id = cte.id
|
|
88
|
+
)
|
|
89
|
+
SELECT * FROM cte
|
|
90
|
+
`)
|
|
91
|
+
|
|
92
|
+
// Sequences (MariaDB 10.3+)
|
|
93
|
+
await pool.execute('CREATE SEQUENCE user_id_seq START WITH 1 INCREMENT BY 1')
|
|
94
|
+
const [result] = await pool.execute('SELECT NEXT VALUE FOR user_id_seq')
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Common Patterns
|
|
98
|
+
|
|
99
|
+
### Connection Pooling
|
|
100
|
+
```typescript
|
|
101
|
+
let pool: mysql.Pool | null = null
|
|
102
|
+
|
|
103
|
+
export function getPool(): mysql.Pool {
|
|
104
|
+
if (!pool) {
|
|
105
|
+
pool = mysql.createPool({
|
|
106
|
+
// ... config
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
return pool
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Graceful shutdown
|
|
113
|
+
process.on('SIGINT', async () => {
|
|
114
|
+
if (pool) {
|
|
115
|
+
await pool.end()
|
|
116
|
+
}
|
|
117
|
+
process.exit(0)
|
|
118
|
+
})
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Error Handling
|
|
122
|
+
```typescript
|
|
123
|
+
try {
|
|
124
|
+
const [rows] = await pool.execute('SELECT * FROM users WHERE id = ?', [userId])
|
|
125
|
+
if ((rows as any[]).length === 0) {
|
|
126
|
+
throw new Error('User not found')
|
|
127
|
+
}
|
|
128
|
+
return rows[0]
|
|
129
|
+
} catch (error: any) {
|
|
130
|
+
if (error.code === 'ER_DUP_ENTRY') {
|
|
131
|
+
throw new Error('Duplicate entry')
|
|
132
|
+
}
|
|
133
|
+
throw error
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Best Practices
|
|
138
|
+
|
|
139
|
+
✅ **DO:**
|
|
140
|
+
- Use connection pooling (10-20 connections)
|
|
141
|
+
- Always use parameterized queries (?)
|
|
142
|
+
- Use transactions for multi-step operations
|
|
143
|
+
- Create indexes on frequently queried columns
|
|
144
|
+
- Use InnoDB engine (ACID compliance)
|
|
145
|
+
- Set appropriate charset (utf8mb4)
|
|
146
|
+
- Monitor slow query log
|
|
147
|
+
- Use prepared statements
|
|
148
|
+
|
|
149
|
+
❌ **DON'T:**
|
|
150
|
+
- Use string concatenation for queries
|
|
151
|
+
- Create too many connections
|
|
152
|
+
- Skip error handling
|
|
153
|
+
- Use MyISAM engine
|
|
154
|
+
- Hardcode connection strings
|
|
155
|
+
- Ignore query performance
|
|
156
|
+
|
|
157
|
+
## Configuration
|
|
158
|
+
|
|
159
|
+
### Environment Variables
|
|
160
|
+
```bash
|
|
161
|
+
DB_HOST=localhost
|
|
162
|
+
DB_PORT=3306
|
|
163
|
+
DB_NAME=myapp
|
|
164
|
+
DB_USER=myuser
|
|
165
|
+
DB_PASSWORD=securepassword
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Docker Compose
|
|
169
|
+
```yaml
|
|
170
|
+
services:
|
|
171
|
+
mariadb:
|
|
172
|
+
image: mariadb:11
|
|
173
|
+
environment:
|
|
174
|
+
MYSQL_DATABASE: myapp
|
|
175
|
+
MYSQL_USER: myuser
|
|
176
|
+
MYSQL_PASSWORD: securepassword
|
|
177
|
+
MYSQL_ROOT_PASSWORD: rootpassword
|
|
178
|
+
ports:
|
|
179
|
+
- "3306:3306"
|
|
180
|
+
volumes:
|
|
181
|
+
- mariadb_data:/var/lib/mysql
|
|
182
|
+
healthcheck:
|
|
183
|
+
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
|
184
|
+
interval: 10s
|
|
185
|
+
timeout: 5s
|
|
186
|
+
retries: 5
|
|
187
|
+
|
|
188
|
+
volumes:
|
|
189
|
+
mariadb_data:
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
<!-- MARIADB:END -->
|
|
193
|
+
|