@nano-step/skill-manager 5.6.0 → 5.6.2
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/dist/utils.d.ts +1 -1
- package/dist/utils.js +1 -1
- package/package.json +1 -1
- package/private-catalog.json +5 -0
- package/skills/deep-design/SKILL.md +402 -0
- package/skills/deep-design/evals/evals.json +23 -0
- package/skills/deep-design/skill.json +7 -0
- package/skills/feature-analysis/SKILL.md +290 -0
- package/skills/feature-analysis/skill.json +15 -0
- package/skills/nano-brain/AGENTS_SNIPPET.md +0 -9
- package/skills/nano-brain/skill.json +7 -0
- package/skills/pr-code-reviewer/CHANGELOG.md +287 -0
- package/skills/pr-code-reviewer/RESEARCH.md +60 -0
- package/skills/pr-code-reviewer/SKILL.md +530 -0
- package/skills/pr-code-reviewer/assets/config.json +47 -0
- package/skills/pr-code-reviewer/checklists/backend-express.md +357 -0
- package/skills/pr-code-reviewer/checklists/ci-cd.md +428 -0
- package/skills/pr-code-reviewer/checklists/consumer-search-matrix.md +339 -0
- package/skills/pr-code-reviewer/checklists/database.md +382 -0
- package/skills/pr-code-reviewer/checklists/frontend-vue-nuxt.md +426 -0
- package/skills/pr-code-reviewer/checklists/review-checklist.md +116 -0
- package/skills/pr-code-reviewer/references/framework-rules/express.md +39 -0
- package/skills/pr-code-reviewer/references/framework-rules/nestjs.md +41 -0
- package/skills/pr-code-reviewer/references/framework-rules/typeorm.md +52 -0
- package/skills/pr-code-reviewer/references/framework-rules/typescript.md +50 -0
- package/skills/pr-code-reviewer/references/framework-rules/vue-nuxt.md +53 -0
- package/skills/pr-code-reviewer/references/nano-brain-integration.md +61 -0
- package/skills/pr-code-reviewer/references/performance-patterns.md +26 -0
- package/skills/pr-code-reviewer/references/quality-patterns.md +25 -0
- package/skills/pr-code-reviewer/references/report-template.md +167 -0
- package/skills/pr-code-reviewer/references/security-patterns.md +31 -0
- package/skills/pr-code-reviewer/references/subagent-prompts.md +323 -0
- package/skills/pr-code-reviewer/skill.json +15 -0
- package/skills/rri-t-testing/SKILL.md +224 -0
- package/skills/rri-t-testing/assets/rri-t-coverage-dashboard.md +138 -0
- package/skills/rri-t-testing/assets/rri-t-memory-protocol.md +271 -0
- package/skills/rri-t-testing/assets/rri-t-persona-interview.md +249 -0
- package/skills/rri-t-testing/assets/rri-t-quality-scorecard.md +122 -0
- package/skills/rri-t-testing/assets/rri-t-risk-matrix.md +87 -0
- package/skills/rri-t-testing/assets/rri-t-stress-matrix.md +100 -0
- package/skills/rri-t-testing/assets/rri-t-test-case.md +181 -0
- package/skills/rri-t-testing/assets/rri-t-testability-gate.md +131 -0
- package/skills/rri-t-testing/assets/rri-t-traceability-matrix.md +105 -0
- package/skills/rri-t-testing/skill.json +9 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# Consumer Search Matrix
|
|
2
|
+
|
|
3
|
+
When reviewing PRs, use this matrix to determine WHAT to search and WHERE.
|
|
4
|
+
|
|
5
|
+
## Quick Reference
|
|
6
|
+
|
|
7
|
+
| Change Type | Search Repos | Search Patterns | Severity |
|
|
8
|
+
|-------------|--------------|-----------------|----------|
|
|
9
|
+
| API response field removed/renamed | tradeit, tradeit-admin, tradeit-extension | `.{fieldName}`, `{fieldName}:`, `data.{fieldName}` | 🔴 CRITICAL |
|
|
10
|
+
| API endpoint path changed | All frontend repos | `/api/v2/{path}`, network/*.js | 🔴 CRITICAL |
|
|
11
|
+
| Database column removed | From by-database.md readers | `{column_name}`, `{camelCaseName}` | 🔴 CRITICAL |
|
|
12
|
+
| Redis key pattern changed | tradeit-backend, tradeit-socket-server | Exact key string, key prefix | 🟡 WARNING |
|
|
13
|
+
| External URL pattern changed | tradeit, tradeit-admin | Field name holding URL | 🔴 CRITICAL |
|
|
14
|
+
| Middleware removed | Same repo | `httpContext.get()`, middleware name | 🟡 WARNING |
|
|
15
|
+
| Socket event changed | tradeit-socket-server, tradeit | `socket.on()`, `socket.emit()` | 🔴 CRITICAL |
|
|
16
|
+
| Enum/constant changed | All repos importing enums | Enum name, literal value | 🟡 WARNING |
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. API Response Field Changes
|
|
21
|
+
|
|
22
|
+
### Detection
|
|
23
|
+
- Diff shows field removed/renamed in `res.success()` or return statement
|
|
24
|
+
- Controller response shape changed
|
|
25
|
+
- Service return value modified
|
|
26
|
+
|
|
27
|
+
### Search Scope
|
|
28
|
+
|
|
29
|
+
**tradeit-backend changes → Search:**
|
|
30
|
+
| Repo | Location | Pattern |
|
|
31
|
+
|------|----------|---------|
|
|
32
|
+
| tradeit | `network/*.js` | Response destructuring |
|
|
33
|
+
| tradeit | `composables/*.js` | Data field access |
|
|
34
|
+
| tradeit | `components/**/*.vue` | Template bindings |
|
|
35
|
+
| tradeit-admin | `api/*.js`, `services/*.js` | API consumers |
|
|
36
|
+
| tradeit-extension | `src/background/*.js` | Extension API calls |
|
|
37
|
+
|
|
38
|
+
### Search Patterns
|
|
39
|
+
```bash
|
|
40
|
+
# Field removed: "imgURL"
|
|
41
|
+
grep -rn "\.imgURL" tradeit/
|
|
42
|
+
grep -rn "imgURL:" tradeit/
|
|
43
|
+
grep -rn "item\.imgURL" tradeit/
|
|
44
|
+
grep -rn "data\.imgURL" tradeit/
|
|
45
|
+
|
|
46
|
+
# Destructuring pattern
|
|
47
|
+
grep -rn "{ imgURL" tradeit/
|
|
48
|
+
grep -rn "{ .*imgURL.*}" tradeit/
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Critical Fields (NEVER remove without migration)
|
|
52
|
+
|
|
53
|
+
**User Data** (`/api/v2/user/data`):
|
|
54
|
+
- `balance`, `storeBalance`, `steamId`, `email`
|
|
55
|
+
- `firstTradeBonus`, `stripeAccountId`
|
|
56
|
+
- `likedItemMap`, `likedAssetMap`
|
|
57
|
+
- `currencyPreference`, `tickets`
|
|
58
|
+
|
|
59
|
+
**Inventory** (`/api/v2/inventory/*`):
|
|
60
|
+
- `items[]`, `reserveAssetIds`, `tradeAwayAssetIds`
|
|
61
|
+
- `assetId`, `imgURL`, `price`, `name`
|
|
62
|
+
- `chartData`, `appId`, `groupId`
|
|
63
|
+
|
|
64
|
+
**Trade** (`/api/v2/trade/*`):
|
|
65
|
+
- `success`, `message`, `tradesInfo`
|
|
66
|
+
- `trades[]`, `tradeId`, `status`
|
|
67
|
+
|
|
68
|
+
**Insight** (`/api/v2/insight/*`):
|
|
69
|
+
- `chartData`, `stockData`, `marketContent`
|
|
70
|
+
- `sections`, `stats`
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 2. API Endpoint Path Changes
|
|
75
|
+
|
|
76
|
+
### Detection
|
|
77
|
+
- Route definition changed in `routes/*.js`
|
|
78
|
+
- HTTP method changed (GET→POST)
|
|
79
|
+
- Path parameter renamed
|
|
80
|
+
|
|
81
|
+
### Search Scope
|
|
82
|
+
```bash
|
|
83
|
+
# Search all frontend repos for API path
|
|
84
|
+
grep -rn "/api/v2/insight" tradeit/network/
|
|
85
|
+
grep -rn "/api/v2/insight" tradeit-admin/
|
|
86
|
+
grep -rn "insight" tradeit/network/*.js
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Network File Mapping
|
|
90
|
+
|
|
91
|
+
| Backend Route File | Frontend Network File |
|
|
92
|
+
|-------------------|----------------------|
|
|
93
|
+
| `routes/user.js` | `network/userNetwork.js` |
|
|
94
|
+
| `routes/inventory.js` | `network/inventoryNetwork.js` |
|
|
95
|
+
| `routes/trade.js` | `network/tradeNetwork.js` |
|
|
96
|
+
| `routes/sell.js` | `network/sellNetwork.js` |
|
|
97
|
+
| `routes/insight.js` | `network/insightNetwork.js` |
|
|
98
|
+
| `routes/meta.js` | `network/metaNetwork.js` |
|
|
99
|
+
| `routes/steam.js` | `network/steamNetwork.js` |
|
|
100
|
+
| `routes/stripe.js` | `network/paymentNetwork.js` |
|
|
101
|
+
| `routes/giveaway.js` | `network/giveawayNetwork.js` |
|
|
102
|
+
| `routes/skinCollection.js` | `network/skinCollectionNetwork.js` |
|
|
103
|
+
| `routes/coupons.js` | `network/couponNetwork.js` |
|
|
104
|
+
| `routes/oauth2.js` | `network/oauth2Network.js` |
|
|
105
|
+
| `routes/guessGame.js` | `network/guessGameNetwork.js` |
|
|
106
|
+
| `routes/invest.js` | `network/investNetwork.js` |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 3. Database Schema Changes
|
|
111
|
+
|
|
112
|
+
### Detection
|
|
113
|
+
- SQL query column list changed
|
|
114
|
+
- Migration file added
|
|
115
|
+
- Repository method modified
|
|
116
|
+
|
|
117
|
+
### Search Scope (from by-database.md)
|
|
118
|
+
|
|
119
|
+
| Table | Owner (Write) | Readers (Search These) |
|
|
120
|
+
|-------|---------------|------------------------|
|
|
121
|
+
| `item_prices` | pricing-manager | tradeit-backend, tradeit-service |
|
|
122
|
+
| `trades` | tradeit-backend | tradeit-service, tradeit-admin-backend |
|
|
123
|
+
| `users` | tradeit-backend | ALL services |
|
|
124
|
+
| `items_meta` | bymykel-scraper | tradeit-backend, pricing-manager |
|
|
125
|
+
| `pro_players` | pro-settings-scraper | tradeit-backend |
|
|
126
|
+
|
|
127
|
+
### Search Patterns
|
|
128
|
+
```bash
|
|
129
|
+
# Column "stable_price" removed
|
|
130
|
+
grep -rn "stable_price" tradeit-backend/server/repository/
|
|
131
|
+
grep -rn "stablePrice" tradeit-backend/server/ # camelCase version
|
|
132
|
+
grep -rn "stablePrice" tradeit/ # frontend usage
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## 4. Redis Key Changes
|
|
138
|
+
|
|
139
|
+
### Detection
|
|
140
|
+
- Redis key pattern changed in `redis/*.js`
|
|
141
|
+
- Key prefix modified
|
|
142
|
+
- TTL changed significantly
|
|
143
|
+
|
|
144
|
+
### Search Scope
|
|
145
|
+
| Repo | Redis Usage |
|
|
146
|
+
|------|-------------|
|
|
147
|
+
| tradeit-backend | Session, cache, pubsub, queue |
|
|
148
|
+
| tradeit-socket-server | Pubsub, real-time state |
|
|
149
|
+
| pricing-manager | Price cache |
|
|
150
|
+
| tradeit-inventory-server | Inventory cache |
|
|
151
|
+
|
|
152
|
+
### Common Key Patterns
|
|
153
|
+
```javascript
|
|
154
|
+
// Inventory cache
|
|
155
|
+
`cinv:${steamId}:${gameId}:compressed`
|
|
156
|
+
`sinv:${steamId}:${gameId}`
|
|
157
|
+
|
|
158
|
+
// User data
|
|
159
|
+
`ud:${steamId}`
|
|
160
|
+
`steamLevel:${steamId}`
|
|
161
|
+
|
|
162
|
+
// Insight cache
|
|
163
|
+
`insight_chart:${gameId}:${slug}`
|
|
164
|
+
`insight_chart_item_details:${gameId}:${itemId}`
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 5. External URL Pattern Changes
|
|
170
|
+
|
|
171
|
+
### Detection
|
|
172
|
+
- URL template changed (CDN, Steam, etc.)
|
|
173
|
+
- Conditional URL logic removed
|
|
174
|
+
- Domain changed
|
|
175
|
+
|
|
176
|
+
### Example: imgURL Change (PR #1101)
|
|
177
|
+
```javascript
|
|
178
|
+
// BEFORE (conditional)
|
|
179
|
+
imgURL: iconUrl
|
|
180
|
+
? `https://steamcommunity-a.akamaihd.net/economy/image/${iconUrl}/140fx140f`
|
|
181
|
+
: `${process.env.TRADEIT_API_URL}static/img/items-webp-256/${groupId}.webp`
|
|
182
|
+
|
|
183
|
+
// AFTER (always Steam CDN)
|
|
184
|
+
imgURL: `https://steamcommunity-a.akamaihd.net/economy/image/${iconUrl}/256fx256f`
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Search for URL consumers
|
|
188
|
+
```bash
|
|
189
|
+
# Find all imgURL usages
|
|
190
|
+
grep -rn "imgURL" tradeit/composables/
|
|
191
|
+
grep -rn "imgURL" tradeit/components/
|
|
192
|
+
grep -rn "\.imgURL" tradeit/
|
|
193
|
+
|
|
194
|
+
# Found 30+ usages in PR #1101 review
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 6. Middleware/Context Changes
|
|
200
|
+
|
|
201
|
+
### Detection
|
|
202
|
+
- Middleware removed from `index.js`
|
|
203
|
+
- `httpContext.set()` removed
|
|
204
|
+
- Request context field removed
|
|
205
|
+
|
|
206
|
+
### Search Scope (same repo)
|
|
207
|
+
```bash
|
|
208
|
+
# Analytics middleware removed
|
|
209
|
+
grep -rn "httpContext.get('analytics')" server/
|
|
210
|
+
grep -rn "analyticsService" server/
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Common Context Keys
|
|
214
|
+
- `analytics` - Analytics instance
|
|
215
|
+
- `mysqlConnection` - DB connection
|
|
216
|
+
- `requestId` - Request tracking
|
|
217
|
+
- `logger` - Request-scoped logger
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 7. Socket Event Changes
|
|
222
|
+
|
|
223
|
+
### Detection
|
|
224
|
+
- Event name changed in emit/on calls
|
|
225
|
+
- Event payload structure changed
|
|
226
|
+
- Channel/room changed
|
|
227
|
+
|
|
228
|
+
### Search Scope
|
|
229
|
+
| Change In | Search |
|
|
230
|
+
|-----------|--------|
|
|
231
|
+
| tradeit-backend | tradeit-socket-server, tradeit |
|
|
232
|
+
| tradeit-socket-server | tradeit, tradeit-admin |
|
|
233
|
+
|
|
234
|
+
### Common Events
|
|
235
|
+
```javascript
|
|
236
|
+
// Trade events
|
|
237
|
+
'trade:created', 'trade:updated', 'trade:completed'
|
|
238
|
+
|
|
239
|
+
// Inventory events
|
|
240
|
+
'inventory:updated', 'inventory:reserved'
|
|
241
|
+
|
|
242
|
+
// User events
|
|
243
|
+
'user:balance', 'user:notification'
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 8. Enum/Constant Changes
|
|
249
|
+
|
|
250
|
+
### Detection
|
|
251
|
+
- Value changed in `config/enums.js`
|
|
252
|
+
- Constant renamed
|
|
253
|
+
- New enum value added (usually safe)
|
|
254
|
+
|
|
255
|
+
### Search Scope
|
|
256
|
+
```bash
|
|
257
|
+
# CSGO_GAME_ID changed
|
|
258
|
+
grep -rn "CSGO_GAME_ID" tradeit-backend/
|
|
259
|
+
grep -rn "730" tradeit-backend/ # literal value
|
|
260
|
+
grep -rn "CSGO_GAME_ID" tradeit/
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Critical Enums
|
|
264
|
+
- `CSGO_GAME_ID`, `RUST_GAME_ID`, `DOTA2_GAME_ID`
|
|
265
|
+
- `TradeStatus`, `BotTradeItemStatus`
|
|
266
|
+
- `configurationKeys`
|
|
267
|
+
- `CsgoSlugType`, `InsightRootSlug`
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Automated Search Commands
|
|
272
|
+
|
|
273
|
+
### For PR Review
|
|
274
|
+
```bash
|
|
275
|
+
# 1. Get changed files
|
|
276
|
+
git diff --name-only base..head
|
|
277
|
+
|
|
278
|
+
# 2. For each changed controller, find response fields
|
|
279
|
+
grep -A5 "res.success" server/controllers/{file}.js
|
|
280
|
+
|
|
281
|
+
# 3. Search frontend for field usage
|
|
282
|
+
for field in $(extract_fields); do
|
|
283
|
+
grep -rn "\.${field}" ../tradeit/
|
|
284
|
+
grep -rn "${field}:" ../tradeit/
|
|
285
|
+
done
|
|
286
|
+
|
|
287
|
+
# 4. Search other backend repos
|
|
288
|
+
for repo in tradeit-service tradeit-admin-backend; do
|
|
289
|
+
grep -rn "{pattern}" ../${repo}/
|
|
290
|
+
done
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### GitHub Search (for remote repos)
|
|
294
|
+
```bash
|
|
295
|
+
# Search across organization
|
|
296
|
+
gh search code "imgURL" --owner zengamingx --language javascript
|
|
297
|
+
|
|
298
|
+
# Search specific repo
|
|
299
|
+
gh search code "imgURL" --repo zengamingx/tradeit
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## Severity Guide
|
|
305
|
+
|
|
306
|
+
| Severity | Meaning | Action |
|
|
307
|
+
|----------|---------|--------|
|
|
308
|
+
| 🔴 CRITICAL | Will crash/break functionality | Block PR, require fix |
|
|
309
|
+
| 🟡 WARNING | May cause issues, needs verification | Request changes, verify |
|
|
310
|
+
| 🟢 SAFE | Low risk, informational | Note in review |
|
|
311
|
+
|
|
312
|
+
### Auto-Block Triggers
|
|
313
|
+
- Response field removed without frontend update
|
|
314
|
+
- API path changed without network file update
|
|
315
|
+
- Database column removed with active readers
|
|
316
|
+
- Middleware removed with active consumers
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Cross-Repo Search Checklist
|
|
321
|
+
|
|
322
|
+
When reviewing a PR, check these boxes:
|
|
323
|
+
|
|
324
|
+
```markdown
|
|
325
|
+
## Consumer Search Completed
|
|
326
|
+
|
|
327
|
+
- [ ] Searched tradeit frontend for API field usage
|
|
328
|
+
- [ ] Searched tradeit-admin for admin API usage
|
|
329
|
+
- [ ] Searched tradeit-extension for extension usage
|
|
330
|
+
- [ ] Checked by-database.md for DB table readers
|
|
331
|
+
- [ ] Searched Redis key consumers (if applicable)
|
|
332
|
+
- [ ] Searched socket event subscribers (if applicable)
|
|
333
|
+
- [ ] Verified enum/constant consumers (if applicable)
|
|
334
|
+
|
|
335
|
+
## Findings
|
|
336
|
+
| Consumer | File | Impact |
|
|
337
|
+
|----------|------|--------|
|
|
338
|
+
| ... | ... | ... |
|
|
339
|
+
```
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# Database Checklist
|
|
2
|
+
|
|
3
|
+
Comprehensive review checklist for database-related changes (MySQL, Redis, migrations).
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. MySQL Query Safety
|
|
8
|
+
|
|
9
|
+
### CRITICAL - Must Check
|
|
10
|
+
|
|
11
|
+
| Check | Pattern | Why |
|
|
12
|
+
|-------|---------|-----|
|
|
13
|
+
| Named parameters | `:paramName` | Prevents SQL injection, readable |
|
|
14
|
+
| No string concatenation | `WHERE id = ${id}` | SQL injection |
|
|
15
|
+
| Parameterized IN clauses | `WHERE id IN (:ids)` | Injection protection |
|
|
16
|
+
| LIMIT on SELECT | `LIMIT 1000` | Memory protection |
|
|
17
|
+
|
|
18
|
+
### Detection Patterns
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
// CRITICAL: SQL injection via concatenation
|
|
22
|
+
await mysql.query(`SELECT * FROM users WHERE id = ${userId}`)
|
|
23
|
+
await mysql.query(`SELECT * FROM items WHERE name LIKE '%${search}%'`)
|
|
24
|
+
|
|
25
|
+
// SECURE: Named parameters
|
|
26
|
+
await mysql.query('SELECT * FROM users WHERE id = :userId', { userId })
|
|
27
|
+
await mysql.query('SELECT * FROM items WHERE name LIKE :search', { search: `%${search}%` })
|
|
28
|
+
|
|
29
|
+
// CRITICAL: Unbounded query
|
|
30
|
+
await mysql.query('SELECT * FROM items WHERE status = :status', { status })
|
|
31
|
+
|
|
32
|
+
// SECURE: With limit
|
|
33
|
+
await mysql.query('SELECT * FROM items WHERE status = :status LIMIT 1000', { status })
|
|
34
|
+
|
|
35
|
+
// WARNING: Dynamic column names (can't parameterize)
|
|
36
|
+
await mysql.query(`SELECT ${columns} FROM items`) // Validate columns first!
|
|
37
|
+
|
|
38
|
+
// SECURE: Whitelist columns
|
|
39
|
+
const allowedColumns = ['id', 'name', 'price']
|
|
40
|
+
const safeColumns = columns.filter(c => allowedColumns.includes(c))
|
|
41
|
+
await mysql.query(`SELECT ${safeColumns.join(',')} FROM items`)
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 2. Transactions
|
|
47
|
+
|
|
48
|
+
### CRITICAL - Must Check
|
|
49
|
+
|
|
50
|
+
| Check | Pattern | Why |
|
|
51
|
+
|-------|---------|-----|
|
|
52
|
+
| Multi-table ops in transaction | `START TRANSACTION` | Data consistency |
|
|
53
|
+
| ROLLBACK in catch | `catch { ROLLBACK }` | Cleanup on error |
|
|
54
|
+
| Connection released | `finally { release() }` | Connection pool |
|
|
55
|
+
| Deadlock handling | Retry on deadlock | Resilience |
|
|
56
|
+
|
|
57
|
+
### Detection Patterns
|
|
58
|
+
|
|
59
|
+
```javascript
|
|
60
|
+
// CRITICAL: Multi-table without transaction
|
|
61
|
+
await mysql.query('INSERT INTO orders ...')
|
|
62
|
+
await mysql.query('UPDATE inventory SET quantity = quantity - 1 ...')
|
|
63
|
+
await mysql.query('INSERT INTO order_items ...')
|
|
64
|
+
// If any fails, data is inconsistent!
|
|
65
|
+
|
|
66
|
+
// SECURE: With transaction
|
|
67
|
+
const connection = await mysql.getConnection()
|
|
68
|
+
try {
|
|
69
|
+
await connection.query('START TRANSACTION')
|
|
70
|
+
await connection.query('INSERT INTO orders ...')
|
|
71
|
+
await connection.query('UPDATE inventory SET quantity = quantity - 1 ...')
|
|
72
|
+
await connection.query('INSERT INTO order_items ...')
|
|
73
|
+
await connection.query('COMMIT')
|
|
74
|
+
} catch (e) {
|
|
75
|
+
await connection.query('ROLLBACK')
|
|
76
|
+
throw e
|
|
77
|
+
} finally {
|
|
78
|
+
connection.release()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// WARNING: No deadlock handling
|
|
82
|
+
try {
|
|
83
|
+
await runTransaction()
|
|
84
|
+
} catch (e) {
|
|
85
|
+
throw e // Deadlock causes permanent failure
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// SECURE: Retry on deadlock
|
|
89
|
+
const MAX_RETRIES = 3
|
|
90
|
+
for (let i = 0; i < MAX_RETRIES; i++) {
|
|
91
|
+
try {
|
|
92
|
+
await runTransaction()
|
|
93
|
+
break
|
|
94
|
+
} catch (e) {
|
|
95
|
+
if (e.code === 'ER_LOCK_DEADLOCK' && i < MAX_RETRIES - 1) {
|
|
96
|
+
await sleep(100 * (i + 1)) // Exponential backoff
|
|
97
|
+
continue
|
|
98
|
+
}
|
|
99
|
+
throw e
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 3. Schema Changes
|
|
107
|
+
|
|
108
|
+
### CRITICAL - Must Check
|
|
109
|
+
|
|
110
|
+
| Check | Pattern | Why |
|
|
111
|
+
|-------|---------|-----|
|
|
112
|
+
| Column removal has migration | Check readers first | Breaking change |
|
|
113
|
+
| Index added for new WHERE | `CREATE INDEX` | Query performance |
|
|
114
|
+
| NOT NULL has default | `DEFAULT value` | Existing rows |
|
|
115
|
+
| Foreign key has ON DELETE | `ON DELETE CASCADE/SET NULL` | Referential integrity |
|
|
116
|
+
|
|
117
|
+
### Detection Patterns
|
|
118
|
+
|
|
119
|
+
```sql
|
|
120
|
+
-- CRITICAL: Removing column without checking readers
|
|
121
|
+
ALTER TABLE items DROP COLUMN stable_price;
|
|
122
|
+
-- Search all repos for 'stable_price' first!
|
|
123
|
+
|
|
124
|
+
-- WARNING: Adding NOT NULL without default
|
|
125
|
+
ALTER TABLE users ADD COLUMN verified BOOLEAN NOT NULL;
|
|
126
|
+
-- Fails if table has existing rows!
|
|
127
|
+
|
|
128
|
+
-- SECURE: With default
|
|
129
|
+
ALTER TABLE users ADD COLUMN verified BOOLEAN NOT NULL DEFAULT FALSE;
|
|
130
|
+
|
|
131
|
+
-- WARNING: Missing index on frequently queried column
|
|
132
|
+
SELECT * FROM items WHERE status = 'active' AND game_id = 730;
|
|
133
|
+
-- If no index on (status, game_id), full table scan!
|
|
134
|
+
|
|
135
|
+
-- SECURE: Add composite index
|
|
136
|
+
CREATE INDEX idx_items_status_game ON items(status, game_id);
|
|
137
|
+
|
|
138
|
+
-- WARNING: Foreign key without ON DELETE
|
|
139
|
+
ALTER TABLE order_items ADD FOREIGN KEY (order_id) REFERENCES orders(id);
|
|
140
|
+
-- What happens when order deleted?
|
|
141
|
+
|
|
142
|
+
-- SECURE: Specify behavior
|
|
143
|
+
ALTER TABLE order_items ADD FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 4. Query Performance
|
|
149
|
+
|
|
150
|
+
### WARNING - Should Check
|
|
151
|
+
|
|
152
|
+
| Check | Pattern | Why |
|
|
153
|
+
|-------|---------|-----|
|
|
154
|
+
| No SELECT * | List specific columns | Network, memory |
|
|
155
|
+
| Indexes used | EXPLAIN shows index | Query speed |
|
|
156
|
+
| No N+1 queries | Query in loop | Performance |
|
|
157
|
+
| Pagination for large results | LIMIT + OFFSET | Memory |
|
|
158
|
+
|
|
159
|
+
### Detection Patterns
|
|
160
|
+
|
|
161
|
+
```javascript
|
|
162
|
+
// WARNING: SELECT * (fetches all columns)
|
|
163
|
+
await mysql.query('SELECT * FROM items WHERE id = :id', { id })
|
|
164
|
+
|
|
165
|
+
// SECURE: Specific columns
|
|
166
|
+
await mysql.query('SELECT id, name, price FROM items WHERE id = :id', { id })
|
|
167
|
+
|
|
168
|
+
// CRITICAL: N+1 query pattern
|
|
169
|
+
const users = await mysql.query('SELECT * FROM users')
|
|
170
|
+
for (const user of users) {
|
|
171
|
+
const orders = await mysql.query('SELECT * FROM orders WHERE user_id = :userId', { userId: user.id })
|
|
172
|
+
// N+1 queries!
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// SECURE: JOIN or batch query
|
|
176
|
+
const usersWithOrders = await mysql.query(`
|
|
177
|
+
SELECT u.*, o.* FROM users u
|
|
178
|
+
LEFT JOIN orders o ON o.user_id = u.id
|
|
179
|
+
`)
|
|
180
|
+
|
|
181
|
+
// Or batch:
|
|
182
|
+
const userIds = users.map(u => u.id)
|
|
183
|
+
const orders = await mysql.query('SELECT * FROM orders WHERE user_id IN (:userIds)', { userIds })
|
|
184
|
+
|
|
185
|
+
// WARNING: No pagination
|
|
186
|
+
const items = await mysql.query('SELECT * FROM items') // Could be millions!
|
|
187
|
+
|
|
188
|
+
// SECURE: Paginated
|
|
189
|
+
const items = await mysql.query('SELECT * FROM items LIMIT :limit OFFSET :offset', { limit: 100, offset: page * 100 })
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## 5. Redis Operations
|
|
195
|
+
|
|
196
|
+
### CRITICAL - Must Check
|
|
197
|
+
|
|
198
|
+
| Check | Pattern | Why |
|
|
199
|
+
|-------|---------|-----|
|
|
200
|
+
| TTL on all cache keys | `setEx()` not `set()` | Memory leak |
|
|
201
|
+
| Key naming consistent | `prefix:${id}:suffix` | Maintainability |
|
|
202
|
+
| Large values compressed | JSON.stringify + compress | Memory |
|
|
203
|
+
| Pipeline for batch ops | `multi()...exec()` | Performance |
|
|
204
|
+
|
|
205
|
+
### Detection Patterns
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
// CRITICAL: No TTL - memory leak
|
|
209
|
+
await redis.set(`cache:${userId}`, JSON.stringify(data))
|
|
210
|
+
|
|
211
|
+
// SECURE: With TTL
|
|
212
|
+
await redis.setEx(`cache:${userId}`, 3600, JSON.stringify(data))
|
|
213
|
+
|
|
214
|
+
// WARNING: Inconsistent key patterns
|
|
215
|
+
await redis.get(`user_${userId}`) // underscore
|
|
216
|
+
await redis.get(`user:${otherId}`) // colon
|
|
217
|
+
await redis.get(`USER:${anotherId}`) // uppercase
|
|
218
|
+
|
|
219
|
+
// SECURE: Consistent pattern with constants
|
|
220
|
+
const KEYS = {
|
|
221
|
+
user: (id) => `user:${id}`,
|
|
222
|
+
inventory: (steamId, gameId) => `inv:${steamId}:${gameId}`,
|
|
223
|
+
}
|
|
224
|
+
await redis.get(KEYS.user(userId))
|
|
225
|
+
|
|
226
|
+
// WARNING: Multiple individual operations
|
|
227
|
+
for (const key of keys) {
|
|
228
|
+
await redis.get(key) // N round trips!
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// SECURE: Pipeline
|
|
232
|
+
const pipeline = redis.pipeline()
|
|
233
|
+
for (const key of keys) {
|
|
234
|
+
pipeline.get(key)
|
|
235
|
+
}
|
|
236
|
+
const results = await pipeline.exec()
|
|
237
|
+
|
|
238
|
+
// WARNING: Large value without compression
|
|
239
|
+
const largeData = { items: [...thousandsOfItems] }
|
|
240
|
+
await redis.setEx(key, 3600, JSON.stringify(largeData)) // Could be MBs!
|
|
241
|
+
|
|
242
|
+
// SECURE: Compress large values
|
|
243
|
+
const compressed = await compress(JSON.stringify(largeData))
|
|
244
|
+
await redis.setEx(`${key}:compressed`, 3600, compressed)
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 6. Redis Key Changes (Breaking)
|
|
250
|
+
|
|
251
|
+
### CRITICAL - Must Check
|
|
252
|
+
|
|
253
|
+
| Check | Pattern | Why |
|
|
254
|
+
|-------|---------|-----|
|
|
255
|
+
| Key pattern change | Search all consumers | Breaking change |
|
|
256
|
+
| Key prefix change | Update all services | Data loss |
|
|
257
|
+
| TTL significantly changed | Verify cache strategy | Stale data |
|
|
258
|
+
|
|
259
|
+
### Consumer Search Required
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
# Key pattern changed from `user:${id}` to `u:${id}`
|
|
263
|
+
grep -rn "user:" tradeit-backend/
|
|
264
|
+
grep -rn "user:" tradeit-socket-server/
|
|
265
|
+
grep -rn "user:" pricing-manager/
|
|
266
|
+
|
|
267
|
+
# Check by-database.md for Redis consumers
|
|
268
|
+
cat .agents/_indexes/by-database.md | grep "Redis"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Common Key Patterns (DO NOT CHANGE without migration)
|
|
272
|
+
|
|
273
|
+
```javascript
|
|
274
|
+
// User data
|
|
275
|
+
`ud:${steamId}` // User data cache
|
|
276
|
+
`steamLevel:${steamId}` // Steam level cache
|
|
277
|
+
|
|
278
|
+
// Inventory
|
|
279
|
+
`cinv:${steamId}:${gameId}:compressed` // Compressed inventory
|
|
280
|
+
`sinv:${steamId}:${gameId}` // Store inventory
|
|
281
|
+
|
|
282
|
+
// Insight
|
|
283
|
+
`insight_chart:${gameId}:${slug}` // Chart data cache
|
|
284
|
+
`insight_chart_item_details:${gameId}:${itemId}`
|
|
285
|
+
|
|
286
|
+
// Session
|
|
287
|
+
`sess:${sessionId}` // User session
|
|
288
|
+
|
|
289
|
+
// Queue
|
|
290
|
+
`bull:${queueName}:*` // Bull queue keys
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## 7. Migration Safety
|
|
296
|
+
|
|
297
|
+
### CRITICAL - Must Check
|
|
298
|
+
|
|
299
|
+
| Check | Pattern | Why |
|
|
300
|
+
|-------|---------|-----|
|
|
301
|
+
| Backward compatible | Old code still works | Zero-downtime deploy |
|
|
302
|
+
| Reversible | Can rollback | Safety |
|
|
303
|
+
| Tested on copy | Run on staging first | Catch issues |
|
|
304
|
+
| Large table handled | pt-online-schema-change | Lock avoidance |
|
|
305
|
+
|
|
306
|
+
### Detection Patterns
|
|
307
|
+
|
|
308
|
+
```sql
|
|
309
|
+
-- CRITICAL: Non-backward compatible change
|
|
310
|
+
ALTER TABLE users RENAME COLUMN email TO email_address;
|
|
311
|
+
-- Old code using 'email' will break!
|
|
312
|
+
|
|
313
|
+
-- SECURE: Add new, migrate, remove old
|
|
314
|
+
ALTER TABLE users ADD COLUMN email_address VARCHAR(255);
|
|
315
|
+
UPDATE users SET email_address = email;
|
|
316
|
+
-- Deploy code that uses both
|
|
317
|
+
-- Later: ALTER TABLE users DROP COLUMN email;
|
|
318
|
+
|
|
319
|
+
-- WARNING: Large table ALTER without pt-osc
|
|
320
|
+
ALTER TABLE items ADD INDEX idx_price (price);
|
|
321
|
+
-- On 10M+ row table, this locks for minutes!
|
|
322
|
+
|
|
323
|
+
-- SECURE: Use pt-online-schema-change
|
|
324
|
+
pt-online-schema-change --alter "ADD INDEX idx_price (price)" D=tradeit,t=items
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## 8. Data Integrity
|
|
330
|
+
|
|
331
|
+
### CRITICAL - Must Check
|
|
332
|
+
|
|
333
|
+
| Check | Pattern | Why |
|
|
334
|
+
|-------|---------|-----|
|
|
335
|
+
| Unique constraints | `UNIQUE INDEX` | Prevent duplicates |
|
|
336
|
+
| Foreign keys | `REFERENCES` | Referential integrity |
|
|
337
|
+
| Check constraints | `CHECK (price >= 0)` | Data validation |
|
|
338
|
+
| NOT NULL where required | `NOT NULL` | Prevent nulls |
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Quick Checklist
|
|
343
|
+
|
|
344
|
+
Copy this for PR reviews:
|
|
345
|
+
|
|
346
|
+
```markdown
|
|
347
|
+
## Database Review
|
|
348
|
+
|
|
349
|
+
### MySQL Queries
|
|
350
|
+
- [ ] Named parameters used (not string concatenation)
|
|
351
|
+
- [ ] LIMIT on SELECT queries
|
|
352
|
+
- [ ] No SELECT * (specific columns listed)
|
|
353
|
+
- [ ] Indexes exist for WHERE/JOIN columns
|
|
354
|
+
|
|
355
|
+
### Transactions
|
|
356
|
+
- [ ] Multi-table operations in transaction
|
|
357
|
+
- [ ] ROLLBACK in catch block
|
|
358
|
+
- [ ] Connection released in finally
|
|
359
|
+
- [ ] Deadlock retry logic (if applicable)
|
|
360
|
+
|
|
361
|
+
### Schema Changes
|
|
362
|
+
- [ ] Column removal checked against all readers
|
|
363
|
+
- [ ] New columns have defaults (if NOT NULL)
|
|
364
|
+
- [ ] Indexes added for new query patterns
|
|
365
|
+
- [ ] Migration is backward compatible
|
|
366
|
+
|
|
367
|
+
### Redis
|
|
368
|
+
- [ ] TTL on all cache keys (setEx, not set)
|
|
369
|
+
- [ ] Key naming follows conventions
|
|
370
|
+
- [ ] Large values compressed
|
|
371
|
+
- [ ] Pipeline used for batch operations
|
|
372
|
+
|
|
373
|
+
### Breaking Changes
|
|
374
|
+
- [ ] No column removed without consumer check
|
|
375
|
+
- [ ] No Redis key pattern changed without migration
|
|
376
|
+
- [ ] Schema change tested on staging
|
|
377
|
+
|
|
378
|
+
### Consumer Search (if schema changed)
|
|
379
|
+
- [ ] Checked by-database.md for table readers
|
|
380
|
+
- [ ] Searched all repos for column name
|
|
381
|
+
- [ ] Searched all repos for Redis key pattern
|
|
382
|
+
```
|