prr-kit 1.1.2 → 1.2.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 (173) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +260 -235
  3. package/docs/assets/banner.svg +33 -165
  4. package/docs/assets/how-it-works.svg +87 -0
  5. package/package.json +60 -60
  6. package/src/core/agents/prr-master.agent.yaml +18 -7
  7. package/src/core/tasks/clear.md +140 -0
  8. package/src/core/tasks/help.md +15 -13
  9. package/src/core/workflows/clear/workflow.md +6 -0
  10. package/src/core/workflows/help/workflow.md +6 -0
  11. package/src/core/workflows/party-mode/steps/step-01-load-reviewers.md +35 -24
  12. package/src/core/workflows/party-mode/steps/step-02-discussion.md +45 -25
  13. package/src/core/workflows/party-mode/workflow.md +2 -2
  14. package/src/prr/agents/architecture-reviewer.agent.yaml +65 -45
  15. package/src/prr/agents/business-reviewer.agent.yaml +66 -0
  16. package/src/prr/agents/general-reviewer.agent.yaml +64 -48
  17. package/src/prr/agents/performance-reviewer.agent.yaml +65 -45
  18. package/src/prr/agents/security-reviewer.agent.yaml +67 -43
  19. package/src/prr/config-template.yaml +97 -0
  20. package/src/prr/data/stacks/actix.md +55 -0
  21. package/src/prr/data/stacks/alpine.md +47 -0
  22. package/src/prr/data/stacks/android.md +53 -0
  23. package/src/prr/data/stacks/angular.md +96 -0
  24. package/src/prr/data/stacks/ansible.md +55 -0
  25. package/src/prr/data/stacks/apollo.md +54 -0
  26. package/src/prr/data/stacks/astro.md +48 -0
  27. package/src/prr/data/stacks/aws-cdk.md +55 -0
  28. package/src/prr/data/stacks/axum.md +56 -0
  29. package/src/prr/data/stacks/babylonjs.md +55 -0
  30. package/src/prr/data/stacks/bash.md +53 -0
  31. package/src/prr/data/stacks/bevy.md +53 -0
  32. package/src/prr/data/stacks/bootstrap.md +52 -0
  33. package/src/prr/data/stacks/bun.md +55 -0
  34. package/src/prr/data/stacks/cpp.md +57 -0
  35. package/src/prr/data/stacks/csharp.md +95 -0
  36. package/src/prr/data/stacks/css.md +55 -0
  37. package/src/prr/data/stacks/cypress.md +53 -0
  38. package/src/prr/data/stacks/d3.md +53 -0
  39. package/src/prr/data/stacks/deno.md +49 -0
  40. package/src/prr/data/stacks/django.md +92 -0
  41. package/src/prr/data/stacks/docker.md +79 -0
  42. package/src/prr/data/stacks/drizzle.md +54 -0
  43. package/src/prr/data/stacks/dynamodb.md +55 -0
  44. package/src/prr/data/stacks/electron.md +44 -0
  45. package/src/prr/data/stacks/elixir.md +53 -0
  46. package/src/prr/data/stacks/expo.md +53 -0
  47. package/src/prr/data/stacks/expressjs.md +82 -0
  48. package/src/prr/data/stacks/fastapi.md +88 -0
  49. package/src/prr/data/stacks/fastify.md +60 -0
  50. package/src/prr/data/stacks/fiber.md +55 -0
  51. package/src/prr/data/stacks/firebase.md +43 -0
  52. package/src/prr/data/stacks/flask.md +46 -0
  53. package/src/prr/data/stacks/flutter.md +75 -0
  54. package/src/prr/data/stacks/gin.md +57 -0
  55. package/src/prr/data/stacks/github-actions.md +71 -0
  56. package/src/prr/data/stacks/go.md +88 -0
  57. package/src/prr/data/stacks/godot.md +56 -0
  58. package/src/prr/data/stacks/graphql.md +76 -0
  59. package/src/prr/data/stacks/grpc.md +56 -0
  60. package/src/prr/data/stacks/haskell.md +48 -0
  61. package/src/prr/data/stacks/helm.md +54 -0
  62. package/src/prr/data/stacks/hono.md +54 -0
  63. package/src/prr/data/stacks/htmx.md +38 -0
  64. package/src/prr/data/stacks/java.md +87 -0
  65. package/src/prr/data/stacks/jest-vitest.md +87 -0
  66. package/src/prr/data/stacks/jquery.md +50 -0
  67. package/src/prr/data/stacks/junit.md +53 -0
  68. package/src/prr/data/stacks/kotlin.md +89 -0
  69. package/src/prr/data/stacks/kubernetes.md +148 -0
  70. package/src/prr/data/stacks/langchain.md +56 -0
  71. package/src/prr/data/stacks/laravel.md +56 -0
  72. package/src/prr/data/stacks/libgdx.md +46 -0
  73. package/src/prr/data/stacks/lit.md +49 -0
  74. package/src/prr/data/stacks/love2d.md +51 -0
  75. package/src/prr/data/stacks/lua.md +51 -0
  76. package/src/prr/data/stacks/mobx.md +54 -0
  77. package/src/prr/data/stacks/mongodb.md +85 -0
  78. package/src/prr/data/stacks/monogame.md +51 -0
  79. package/src/prr/data/stacks/mysql.md +57 -0
  80. package/src/prr/data/stacks/nestjs.md +95 -0
  81. package/src/prr/data/stacks/nextjs.md +88 -0
  82. package/src/prr/data/stacks/nginx.md +55 -0
  83. package/src/prr/data/stacks/node.md +56 -0
  84. package/src/prr/data/stacks/nuxtjs.md +91 -0
  85. package/src/prr/data/stacks/openai-api.md +54 -0
  86. package/src/prr/data/stacks/opengl.md +54 -0
  87. package/src/prr/data/stacks/phaser.md +54 -0
  88. package/src/prr/data/stacks/phoenix.md +55 -0
  89. package/src/prr/data/stacks/php.md +56 -0
  90. package/src/prr/data/stacks/playwright.md +86 -0
  91. package/src/prr/data/stacks/postgresql.md +60 -0
  92. package/src/prr/data/stacks/prisma.md +81 -0
  93. package/src/prr/data/stacks/pygame.md +52 -0
  94. package/src/prr/data/stacks/pytest.md +53 -0
  95. package/src/prr/data/stacks/python.md +94 -0
  96. package/src/prr/data/stacks/pytorch.md +54 -0
  97. package/src/prr/data/stacks/qwik.md +50 -0
  98. package/src/prr/data/stacks/rails.md +48 -0
  99. package/src/prr/data/stacks/react-native.md +77 -0
  100. package/src/prr/data/stacks/react.md +104 -0
  101. package/src/prr/data/stacks/redis.md +76 -0
  102. package/src/prr/data/stacks/redux.md +107 -0
  103. package/src/prr/data/stacks/remix.md +51 -0
  104. package/src/prr/data/stacks/rust.md +88 -0
  105. package/src/prr/data/stacks/sass.md +51 -0
  106. package/src/prr/data/stacks/scala.md +50 -0
  107. package/src/prr/data/stacks/scikit-learn.md +53 -0
  108. package/src/prr/data/stacks/sequelize.md +54 -0
  109. package/src/prr/data/stacks/socket-io.md +54 -0
  110. package/src/prr/data/stacks/solidity.md +53 -0
  111. package/src/prr/data/stacks/solidjs.md +45 -0
  112. package/src/prr/data/stacks/spring-boot.md +92 -0
  113. package/src/prr/data/stacks/sql.md +85 -0
  114. package/src/prr/data/stacks/sqlite.md +55 -0
  115. package/src/prr/data/stacks/styled-components.md +51 -0
  116. package/src/prr/data/stacks/supabase.md +57 -0
  117. package/src/prr/data/stacks/svelte.md +77 -0
  118. package/src/prr/data/stacks/sveltekit.md +54 -0
  119. package/src/prr/data/stacks/swift.md +61 -0
  120. package/src/prr/data/stacks/tailwindcss.md +10 -0
  121. package/src/prr/data/stacks/tanstack-query.md +48 -0
  122. package/src/prr/data/stacks/tauri.md +52 -0
  123. package/src/prr/data/stacks/terraform.md +53 -0
  124. package/src/prr/data/stacks/three.md +53 -0
  125. package/src/prr/data/stacks/trpc.md +49 -0
  126. package/src/prr/data/stacks/typeorm.md +40 -0
  127. package/src/prr/data/stacks/typescript.md +83 -0
  128. package/src/prr/data/stacks/unity.md +61 -0
  129. package/src/prr/data/stacks/unreal.md +58 -0
  130. package/src/prr/data/stacks/vite.md +48 -0
  131. package/src/prr/data/stacks/vue3.md +95 -0
  132. package/src/prr/data/stacks/vulkan.md +53 -0
  133. package/src/prr/data/stacks/wasm.md +49 -0
  134. package/src/prr/data/stacks/webpack.md +48 -0
  135. package/src/prr/data/stacks/zig.md +51 -0
  136. package/src/prr/data/stacks/zustand.md +56 -0
  137. package/src/prr/workflows/1-discover/select-pr/steps/step-05-confirm.md +1 -0
  138. package/src/prr/workflows/1-discover/select-pr/workflow.md +1 -1
  139. package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-01-analyze-files.md +334 -0
  140. package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-02-collect-sources.md +451 -0
  141. package/src/prr/workflows/2-analyze/collect-pr-context/steps/step-03-build-knowledge-base.md +337 -0
  142. package/src/prr/workflows/2-analyze/collect-pr-context/workflow.md +123 -0
  143. package/src/prr/workflows/2-analyze/describe-pr/steps/step-02-classify.md +12 -6
  144. package/src/prr/workflows/2-analyze/describe-pr/steps/step-03-walkthrough.md +59 -1
  145. package/src/prr/workflows/3-review/architecture-review/checklist.md +4 -0
  146. package/src/prr/workflows/3-review/architecture-review/instructions.xml +32 -4
  147. package/src/prr/workflows/3-review/architecture-review/workflow.yaml +17 -18
  148. package/src/prr/workflows/3-review/business-review/checklist.md +27 -0
  149. package/src/prr/workflows/3-review/business-review/instructions.xml +153 -0
  150. package/src/prr/workflows/3-review/business-review/workflow.yaml +17 -0
  151. package/src/prr/workflows/3-review/general-review/checklist.md +5 -1
  152. package/src/prr/workflows/3-review/general-review/instructions.xml +39 -8
  153. package/src/prr/workflows/3-review/general-review/workflow.yaml +17 -18
  154. package/src/prr/workflows/3-review/performance-review/checklist.md +3 -1
  155. package/src/prr/workflows/3-review/performance-review/instructions.xml +10 -3
  156. package/src/prr/workflows/3-review/performance-review/workflow.yaml +17 -18
  157. package/src/prr/workflows/3-review/security-review/checklist.md +2 -1
  158. package/src/prr/workflows/3-review/security-review/instructions.xml +8 -3
  159. package/src/prr/workflows/3-review/security-review/workflow.yaml +18 -19
  160. package/src/prr/workflows/4-improve/improve-code/workflow.yaml +17 -18
  161. package/src/prr/workflows/6-report/generate-report/steps/step-01-collect.md +9 -2
  162. package/src/prr/workflows/6-report/generate-report/steps/step-02-organize.md +28 -7
  163. package/src/prr/workflows/6-report/generate-report/steps/step-03-write.md +6 -4
  164. package/src/prr/workflows/6-report/generate-report/templates/review-report.template.md +124 -78
  165. package/src/prr/workflows/6-report/post-comments/steps/step-01-format.md +104 -13
  166. package/src/prr/workflows/6-report/post-comments/steps/step-02-post.md +92 -21
  167. package/src/prr/workflows/6-report/post-comments/workflow.md +6 -0
  168. package/src/prr/workflows/quick/workflow.md +138 -32
  169. package/src/prr/workflows/0-setup/collect-project-context/steps/step-01-scan-configs.md +0 -106
  170. package/src/prr/workflows/0-setup/collect-project-context/steps/step-02-extract-rules.md +0 -131
  171. package/src/prr/workflows/0-setup/collect-project-context/steps/step-03-ask-context.md +0 -194
  172. package/src/prr/workflows/0-setup/collect-project-context/steps/step-04-save-context.md +0 -161
  173. package/src/prr/workflows/0-setup/collect-project-context/workflow.md +0 -58
@@ -0,0 +1,54 @@
1
+ # Sequelize — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `sequelize`, `from 'sequelize'`, `new Sequelize(`, `Model.findAll`, `Model.create`, `DataTypes.`, `sequelize.define`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** Raw queries via `sequelize.query(userInput)` or `sequelize.query(\`SELECT * WHERE id = ${userInput}\`)` without `replacements` or `bind` → SQL injection. Always use `replacements: [value]` (positional `?`) or `bind: { key: value }` (named `:key`) with `sequelize.query()`.
10
+ - **[HIGH]** Mass assignment via `Model.create(req.body)` or `Model.update(req.body, ...)` without a `fields` whitelist → attacker sets any column including `isAdmin`, `role`, or `createdAt`. Always pass `{ fields: ['allowedField1', 'allowedField2'] }` to limit which columns are written.
11
+ - **[HIGH]** `include` associations built from user-controlled strings → unintended related models loaded, exposing data beyond the intended query scope. Hardcode all `include` association references; never derive them from request input.
12
+ - **[MEDIUM]** Database connection string with credentials hardcoded in `config/database.js` or `config/config.json` → credentials committed to version control. Load all credentials from environment variables; add `config.json` with real values to `.gitignore`.
13
+ - **[MEDIUM]** `paranoid: false` override on queries that return soft-deleted records containing sensitive data → deleted records (e.g., removed users, cancelled orders) exposed to callers. Apply `paranoid: false` only in explicit admin/audit queries; document the intent clearly.
14
+
15
+ ---
16
+
17
+ ## Performance
18
+ - **[HIGH]** N+1 pattern — calling `findAll()` then `instance.getAssociation()` per row in a loop → one DB round-trip per row. Use `include: [{ model: Association }]` in the parent `findAll()` to eager-load in a single JOIN query.
19
+ - **[HIGH]** Missing `attributes: ['id', 'name']` on `findAll`/`findOne` calls → `SELECT *` fetches all columns, preventing covering-index use and sending unnecessary data. Always specify the minimal column list in `attributes`.
20
+ - **[HIGH]** `findAll()` called without `limit` on tables that may grow large → entire table loaded into Node.js heap, causing OOM on large datasets. Always include `limit` and `offset` (or cursor-based pagination) on list queries.
21
+ - **[MEDIUM]** `raw: true` not used for read-only reporting queries → Sequelize builds full Model instances with prototype methods, adding unnecessary overhead. Add `{ raw: true }` to queries that only read data and do not need Model instance methods.
22
+ - **[MEDIUM]** Multiple sequential model mutations not wrapped in a managed transaction → partial failure leaves DB in inconsistent state; no rollback occurs. Use `sequelize.transaction(async (t) => { ... })` for all multi-step write operations.
23
+ - **[MEDIUM]** `Op.in` not used for multi-value filters → individual queries fired in a loop instead of a single `WHERE id IN (...)`. Replace looped `findByPk` calls with a single `findAll({ where: { id: { [Op.in]: ids } } })`.
24
+ - **[LOW]** Not using `findAndCountAll` for paginated endpoints that also need a total count → two separate queries (findAll + count) issued when one suffices. Use `findAndCountAll({ limit, offset })` to get `rows` and `count` in one call.
25
+
26
+ ---
27
+
28
+ ## Architecture
29
+ - **[HIGH]** Business logic (calculations, validations, side effects) placed in Model class static or instance methods → logic is tightly coupled to the ORM and untestable without a DB. Move business logic to a service layer; keep Model methods as thin DB-access wrappers.
30
+ - **[HIGH]** Model associations (belongsTo, hasMany, etc.) not defined in model files → Sequelize JOIN/include queries fail at runtime with "association does not exist". Define all associations in model files and call them in a central `models/index.js` setup function.
31
+ - **[MEDIUM]** Sequelize migrations not used → schema managed with `sync({ alter: true })` or manual SQL, causing environment drift. Use `sequelize-cli` to generate and apply versioned migration files; commit them to the repository.
32
+ - **[MEDIUM]** Singleton Sequelize instance created inside a test helper that does not tear down after tests → connection pool keeps test process alive or bleeds state between test suites. Export the Sequelize instance and call `sequelize.close()` in an `afterAll` hook.
33
+ - **[MEDIUM]** Models defined inline in route files rather than in dedicated model files → model definitions scattered across the codebase, causing duplicate definitions and association conflicts. Define each model in `models/{ModelName}.js` and export from `models/index.js`.
34
+ - **[LOW]** Model files not organized by domain or feature → flat `models/` directory with 50+ files becomes hard to navigate. Group related models into subdirectories (`models/auth/`, `models/billing/`) with an index barrel.
35
+
36
+ ---
37
+
38
+ ## Code Quality
39
+ - **[HIGH]** Model `validate` option not defined on columns with domain constraints → invalid data (empty strings, out-of-range numbers) persists to DB without error. Add Sequelize validators (`isEmail`, `notEmpty`, `min`, `max`) on all columns with domain rules.
40
+ - **[MEDIUM]** Model hooks (`beforeCreate`, `afterUpdate`) performing external API calls or complex business logic → hooks are hard to trace, cannot be disabled for testing, and cause hidden side effects. Move side effects to the service layer; use hooks only for data transformations (e.g., hashing a password).
41
+ - **[MEDIUM]** `sequelize.sync({ force: true })` present in non-development code paths → drops and recreates all tables, destroying production data on restart. Remove `force: true` from all environments; use `{ alter: true }` only in development, and migrations in production.
42
+ - **[MEDIUM]** `Model.find()` (Sequelize v3 API) used in a v6 codebase → method does not exist in v6, causing a runtime `TypeError`. Replace with `Model.findOne()` and audit for other deprecated v3 APIs (`Model.findById` → `Model.findByPk`).
43
+ - **[LOW]** No TypeScript types via `sequelize-typescript` or manual attribute interfaces → `model.get('fieldName')` returns `any`, eliminating compile-time safety. Use `sequelize-typescript` decorators or define `ModelAttributes` interfaces and use typed getters.
44
+
45
+ ---
46
+
47
+ ## Common Bugs & Pitfalls
48
+ - **[HIGH]** `Model.create(req.body)` with no field filtering → mass assignment sets any column the attacker names in the request body. Always destructure and allowlist fields before passing to `create()` or use the `fields` option.
49
+ - **[HIGH]** Missing `await` on Sequelize promise-returning methods (`findAll`, `create`, `update`, `destroy`) → method returns a pending Promise; subsequent code operates on the Promise object, not the result. Add `await` to every Sequelize call inside an `async` function.
50
+ - **[MEDIUM]** Multiple associations of the same model without an `as` alias → Sequelize cannot distinguish them in `include`, producing "ambiguous alias" errors. Always provide `as: 'aliasName'` when the same model is associated more than once.
51
+ - **[MEDIUM]** `upsert()` return value interpreted inconsistently across databases → PostgreSQL returns `[instance, created]`; MySQL and SQLite may differ. Destructure `const [instance, created] = await Model.upsert(...)` and test behavior per DB dialect.
52
+ - **[MEDIUM]** `DATE` column stored in UTC but rendered in server's local timezone without explicit conversion → timestamps shift based on where the server runs. Use `DATEONLY` for dates without time, `DATE` for UTC datetimes, and always convert to user timezone in the presentation layer.
53
+ - **[LOW]** `findOrCreate` used in concurrent requests without a unique constraint → race condition causes duplicate rows when two requests reach `find` before either creates the record. Add a unique DB-level constraint so the second insert fails and is retried safely.
54
+
@@ -0,0 +1,54 @@
1
+ # Socket.IO — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `from 'socket.io'`, `from 'socket.io-client'`, `io.on(`, `socket.emit(`, `socket.join(`, `io.to(`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** No authentication middleware on `io.use()` → anonymous WebSocket connections accepted, bypassing all auth. Implement JWT or session validation in a `io.use((socket, next) => { ... })` middleware and call `next(new Error('unauthorized'))` on failure.
10
+ - **[CRITICAL]** No authorization check before `socket.join(room)` → any connected user can join any room including private or admin rooms. Validate room membership against user roles/permissions before calling `join`.
11
+ - **[HIGH]** User-supplied event payloads broadcast directly without sanitization → XSS when received data is rendered in the browser. Sanitize or validate all incoming event data with a schema library (Zod, Joi) before processing or broadcasting.
12
+ - **[HIGH]** No rate limiting on socket event handlers → malicious client floods the server with events causing DoS. Implement per-socket rate limiting with `socket.io-rate-limiter` or a token bucket in middleware.
13
+ - **[HIGH]** `socket.id` used as a persistent user identifier for authorization decisions → `socket.id` changes on reconnect and is not authenticated. Map authenticated user ID (from JWT/session) to socket ID server-side; never trust `socket.id` as identity.
14
+ - **[MEDIUM]** Authentication tokens passed in WebSocket handshake query string `?token=...` → tokens logged in plaintext by proxies, load balancers, and server access logs. Pass tokens in the `auth` handshake object: `io({ auth: { token } })` and read from `socket.handshake.auth`.
15
+
16
+ ---
17
+
18
+ ## Performance
19
+ - **[HIGH]** `io.emit(event, data)` used for updates relevant to only one user → payload broadcast to all connected clients. Use `io.to(socket.id).emit()` or `socket.emit()` for single-user targeted events.
20
+ - **[HIGH]** Large data payloads sent on high-frequency events (position updates, typing indicators) → network saturation. Batch updates and send at a fixed interval, or use the `volatile` flag for non-critical data that can be dropped.
21
+ - **[MEDIUM]** Rooms and namespaces not used to segment message routing → all events evaluated by all handlers regardless of relevance. Group related sockets into rooms and use namespaces to separate distinct features (chat, notifications).
22
+ - **[MEDIUM]** `volatile` flag not used for real-time data that is acceptable to drop (game position, cursor position) → guaranteed delivery overhead on high-frequency low-importance events. Use `socket.volatile.emit()` for best-effort real-time data.
23
+ - **[MEDIUM]** `perMessageDeflate` compression not configured → large repeated JSON payloads sent uncompressed. Enable `perMessageDeflate: { threshold: 1024 }` on the server for large message payloads.
24
+ - **[LOW]** Binary data (images, audio) serialized to Base64 JSON strings → 33% size overhead. Send binary as `Buffer` or `ArrayBuffer`; Socket.IO handles binary frames natively.
25
+
26
+ ---
27
+
28
+ ## Architecture
29
+ - **[HIGH]** Business logic (database queries, email sending, payment processing) written directly inside socket event handlers → untestable, non-reusable, and violates separation of concerns. Extract to service layer functions called from handlers.
30
+ - **[HIGH]** Per-socket state stored only in JavaScript closure variables → state lost on server restart or when socket reconnects to a different server node. Store user/session state in Redis or a shared database; use `socket.io-redis` adapter for multi-node deployments.
31
+ - **[HIGH]** Client-side reconnection logic absent → after disconnect, client does not re-subscribe to rooms or re-sync state. Handle the `connect` event on the client to re-authenticate and re-join relevant rooms after reconnection.
32
+ - **[MEDIUM]** All event handlers registered in a single monolithic connection handler → hundreds of `socket.on()` calls in one file. Organize handlers into feature modules and register them via a router pattern.
33
+ - **[MEDIUM]** Socket.IO server not separated from the Express HTTP server into its own module → tight coupling makes testing and scaling difficult. Attach `io` to the HTTP server but encapsulate socket logic in a separate module.
34
+ - **[LOW]** No versioning strategy for socket events → breaking changes to event schemas break all connected clients simultaneously. Namespace events by version or use a versioned handshake field.
35
+
36
+ ---
37
+
38
+ ## Code Quality
39
+ - **[HIGH]** Socket event names and payload shapes not typed → `socket.on('event', (data: any) => ...)` with no contract. Define a typed event map interface and use Socket.IO's generic type parameters: `Socket<ClientToServerEvents, ServerToClientEvents>`.
40
+ - **[MEDIUM]** Event listeners added inside `io.on('connection')` not removed on `disconnect` → handlers accumulate per reconnection causing memory leaks and duplicate processing. Use `socket.once` for one-time handlers or explicitly call `socket.off()` in the disconnect handler.
41
+ - **[MEDIUM]** `socket.emit` used for critical operations (payment, account change) without an acknowledgment callback → no confirmation that the client received the message. Use acknowledgments `socket.emit('event', data, (ack) => { ... })` for operations requiring delivery confirmation.
42
+ - **[MEDIUM]** Error events not emitted back to client on handler failure → client has no way to detect server-side errors and cannot show meaningful feedback. Emit structured error events `socket.emit('error', { code, message })` on failure.
43
+ - **[LOW]** `console.log` statements in production socket event handlers → high-traffic servers generate log flood making logs unusable. Replace with a structured logger (`pino`, `winston`) with appropriate log levels.
44
+
45
+ ---
46
+
47
+ ## Common Bugs & Pitfalls
48
+ - **[HIGH]** Event listener registered inside `io.on('connection')` not scoped to the socket → using `io.on(event)` instead of `socket.on(event)` broadcasts to all sockets, not just the connected one.
49
+ - **[HIGH]** Missing `'error'` event handler on the socket → unhandled error events crash the Node.js process in older versions or cause silent failures. Always attach `socket.on('error', handler)`.
50
+ - **[HIGH]** Room membership not persisted → after server restart or when using multiple server nodes without a Redis adapter, users lose room membership. Use `socket.io-redis` adapter and re-join rooms on reconnect.
51
+ - **[MEDIUM]** `socket.broadcast.emit()` vs `io.emit()` confusion → `broadcast` excludes the sender while `io.emit` includes all clients including the sender. Choose based on whether the emitting client should receive its own message.
52
+ - **[MEDIUM]** Binary data sent via `JSON.stringify` as a JSON string instead of passing a `Buffer` directly → Socket.IO serializes Buffer as binary frame automatically; wrapping in JSON defeats this and adds encoding overhead.
53
+ - **[MEDIUM]** `socket.rooms` set iterated immediately after `socket.join()` before join completes in async context → room not yet in set. `socket.join()` is synchronous in Socket.IO v4 but was async in v2/v3; verify version behavior.
54
+ - **[LOW]** Client `socket.io` version not matching server version → protocol mismatches cause silent connection failures or degraded behavior. Pin client and server versions together and update in lockstep.
@@ -0,0 +1,53 @@
1
+ # Solidity — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `*.sol`, `pragma solidity`, `contract `, `function `, `mapping(`, `emit `, `require(`, `msg.sender`, `hardhat`, `foundry`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** Reentrancy vulnerability — state updated after external call → attacker re-enters the function before state change completes and drains funds. Follow checks-effects-interactions pattern strictly and add OpenZeppelin's `ReentrancyGuard`.
10
+ - **[CRITICAL]** Integer overflow/underflow without SafeMath or Solidity 0.8+ built-in checked arithmetic → balances wrap around to unexpected values. Use Solidity ^0.8.0 (auto-checked) or `SafeMath` on older compilers; never use `unchecked` on user-supplied values.
11
+ - **[CRITICAL]** `tx.origin` used for authentication → a phishing contract called by the victim passes `tx.origin` check. Replace all `tx.origin` authentication with `msg.sender`.
12
+ - **[CRITICAL]** `delegatecall` to a user-controlled address → arbitrary code executed in the calling contract's storage context. Only `delegatecall` to audited, immutable addresses; never accept implementation addresses from users.
13
+ - **[HIGH]** Missing access control on sensitive functions → anyone can call `withdraw()`, `mint()`, or `pause()`. Add `onlyOwner`, role-based modifiers, or OpenZeppelin `AccessControl` to all privileged functions.
14
+ - **[HIGH]** Front-running on price-sensitive or commitment transactions → miner or bot sees pending tx and reorders. Use a commit-reveal scheme or on-chain VRF (Chainlink VRF) for randomness and auctions.
15
+ - **[HIGH]** Unchecked return value of low-level `.call()` → failed transfer silently ignored, contract state out of sync. Always check `(bool success, ) = addr.call{...}(...)` and `require(success)`.
16
+ - **[MEDIUM]** `block.timestamp` used for randomness or time-critical logic → miner can shift timestamp by ~15 seconds. Use block-based delays for time locks and Chainlink VRF for randomness.
17
+
18
+ ---
19
+
20
+ ## Performance
21
+ - **[HIGH]** Writing to storage inside loops → each SSTORE costs 20,000 gas; loop body multiplies this. Read storage into memory variables before the loop, operate in memory, write back once after.
22
+ - **[HIGH]** Unbounded array iteration → gas cost grows with array length, eventually hitting block gas limit (DoS). Cap iteration with a max count or paginate using offset/limit patterns.
23
+ - **[HIGH]** Storing large data on-chain → SSTORE is 20,000 gas per 32 bytes; 1 KB costs ~640,000 gas. Store data off-chain (IPFS/Arweave) and commit only the content hash on-chain.
24
+ - **[MEDIUM]** Struct variables not packed into 32-byte slots → each unoptimized slot wastes gas on reads and writes. Order struct fields from largest to smallest type so adjacent small types share a slot.
25
+ - **[MEDIUM]** `public` state variables generating automatic getters when manual getters duplicate the same logic → dead code and increased bytecode size. Remove manual getters that replicate the auto-generated one.
26
+ - **[MEDIUM]** Not using `calldata` for read-only function parameters → `memory` copy costs extra gas. Declare external function array and string parameters as `calldata`.
27
+
28
+ ---
29
+
30
+ ## Architecture
31
+ - **[HIGH]** Upgradability not planned before deployment → bugs in production contract are permanent. Use OpenZeppelin's Upgradeable proxy pattern (UUPS or Transparent) if post-deployment fixes are expected.
32
+ - **[HIGH]** Reinventing standard patterns instead of using OpenZeppelin's audited contracts → subtle security bugs. Inherit from `ERC20`, `ERC721`, `Ownable`, `AccessControl`, `ReentrancyGuard` rather than reimplementing.
33
+ - **[MEDIUM]** Single monolithic contract for unrelated responsibilities → harder to audit, test, and upgrade. Separate token logic, governance, and treasury into distinct contracts with clear interfaces.
34
+ - **[MEDIUM]** Events not emitted for all important state changes → off-chain indexers (The Graph, explorers) cannot track contract activity. Emit an event in every function that mutates significant state.
35
+ - **[LOW]** Public/external functions lack NatSpec (`@notice`, `@param`, `@return`) → ABI documentation absent from etherscan and tooling. Add NatSpec to all user-facing functions.
36
+
37
+ ---
38
+
39
+ ## Code Quality
40
+ - **[HIGH]** Magic numbers in `require` conditions and arithmetic → intent unclear and values duplicated across the codebase. Define named `constant` or `immutable` variables at the contract level.
41
+ - **[HIGH]** Checks-Effects-Interactions (CEI) pattern not followed → reentrancy window between external call and state update. Reorder so all checks come first, state updates second, and external calls last.
42
+ - **[MEDIUM]** Events missing for all state-changing functions → incomplete audit trail. Add a corresponding `event` and `emit` to every function that modifies storage.
43
+ - **[MEDIUM]** Constructor not validating input parameters → zero-address, zero-amount, or out-of-range values accepted silently at deploy time. Add `require` checks in the constructor for all critical parameters.
44
+ - **[LOW]** `public` visibility on functions only called externally → `external` is slightly cheaper for calldata parameters. Use `external` for all functions not called internally.
45
+
46
+ ---
47
+
48
+ ## Common Bugs & Pitfalls
49
+ - **[CRITICAL]** Reentrancy in `withdraw()` pattern without `ReentrancyGuard` → classic DAO-style drain attack. Apply `nonReentrant` modifier from OpenZeppelin and follow CEI pattern.
50
+ - **[HIGH]** `selfdestruct` leaving references in other contracts that assume it still exists → calls to destroyed contract return success with empty data. Avoid `selfdestruct`; design deactivation via a pause flag instead.
51
+ - **[HIGH]** ERC20 `approve()` front-running race condition → spender can use old and new allowance if owner changes it. Use `increaseAllowance`/`decreaseAllowance` or the EIP-2612 `permit` pattern.
52
+ - **[MEDIUM]** `delete array[i]` on a dynamic storage array leaves a zero gap, shifting indices → iteration over the array skips or misprocesses elements. Use swap-and-pop (`arr[i] = arr[arr.length - 1]; arr.pop()`) for unordered arrays.
53
+ - **[MEDIUM]** Floating pragma `^0.8.0` compiled with different patch versions across environments → non-deterministic bytecode and potential behaviour differences. Pin to an exact version (e.g., `pragma solidity 0.8.24`) in production contracts.
@@ -0,0 +1,45 @@
1
+ # SolidJS — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `from 'solid-js'` · `createSignal` · `createEffect` · `createStore` · `<Show>` · `<For>` · `<Switch>` · `vite-plugin-solid` · `solid-start`
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[HIGH]** `innerHTML={userContent}` or direct DOM `.innerHTML =` with user-controlled data → XSS. Use text interpolation `{userContent}` which escapes output, or sanitize with DOMPurify before setting innerHTML.
11
+
12
+ ---
13
+
14
+ ## Performance
15
+
16
+ - **[CRITICAL]** Destructuring props: `const { count, label } = props` in a component → breaks reactivity. Props in Solid are reactive getters; destructuring extracts the current value at call time. Always access as `props.count`.
17
+ - **[HIGH]** Calling a signal getter outside a tracking scope (effect, memo, JSX) → dependency not tracked, UI won't update when signal changes.
18
+ - **[HIGH]** Expensive computation inside JSX without `createMemo` → recomputes on every reactive update in the enclosing scope, not just when its inputs change. Wrap in `createMemo`.
19
+ - **[MEDIUM]** `createEffect` with side effects that depend on signals read outside the effect body → those signals aren't tracked. Read all reactive dependencies inside the effect.
20
+ - **[LOW]** `<Index>` used for a list that frequently adds/removes items (vs. `<For>`) → `<Index>` is optimized for stable items; `<For>` reconciles by identity. Pick the right list primitive.
21
+
22
+ ---
23
+
24
+ ## Architecture
25
+
26
+ - **[HIGH]** Applying React mental model to Solid → Solid signals ≠ React hooks. Solid components run once; there is no re-render cycle. Logic that worked with React's render-on-state-change will behave differently.
27
+ - **[MEDIUM]** Overusing `createStore` for flat, simple state where `createSignal` suffices → `createStore` is for nested reactive objects. Signals are simpler and more explicit for primitive values.
28
+ - **[LOW]** Top-level reactive state in a module (singleton store) without cleanup → fine for app-level state but leaks between tests if module isn't reset.
29
+
30
+ ---
31
+
32
+ ## Code Quality
33
+
34
+ - **[HIGH]** Missing `onCleanup` inside `createEffect` for subscriptions, event listeners, or timers → resources leak when the reactive scope is disposed (component unmounted).
35
+ - **[MEDIUM]** `createMemo` wrapping a non-expensive expression → memo adds tracking overhead. Only use for computationally expensive or derived values.
36
+ - **[LOW]** Using `untrack()` broadly to suppress reactivity instead of restructuring code → hides the real issue of over-broad reactive dependencies.
37
+
38
+ ---
39
+
40
+ ## Common Bugs & Pitfalls
41
+
42
+ - **[CRITICAL]** Signal read in JSX without calling the getter: `<div>{count}</div>` instead of `<div>{count()}</div>` → renders the function reference as a string, no reactivity. In Solid, signals are functions — always call them.
43
+ - **[HIGH]** Async `createEffect` → Solid's tracking context does not extend across `async/await`. Signals read after the first `await` are not tracked. Use `createResource` for async data.
44
+ - **[MEDIUM]** `batch()` not used when dispatching multiple signal updates that should trigger a single downstream effect → each `set*` call triggers separate reactive updates; batch them for atomic updates.
45
+ - **[LOW]** Conditional signal reads that change between renders → in Solid, reactive graph is static per component execution. Dynamic conditional reads can cause unstable dependency graphs.
@@ -0,0 +1,92 @@
1
+ # Spring Boot — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `@SpringBootApplication`, `@RestController`, `@Service`, `@Repository`, `application.properties` / `application.yml`, `pom.xml` with spring-boot-starter, `@Entity`, `@Transactional`
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** `@PreAuthorize` / security check missing on sensitive endpoints → unauthorized access.
11
+ - **[CRITICAL]** JPQL/HQL or native query with string concatenation of user input → injection. Use `:param` binding or `CriteriaBuilder`.
12
+ - **[CRITICAL]** Mass assignment via `@RequestBody` mapped directly to `@Entity` → over-posting (attacker sets `admin=true`). Use request DTOs.
13
+ - **[HIGH]** Returning `@Entity` directly from REST controller → exposes passwords, internal IDs. Use response DTOs with `@JsonIgnore`.
14
+ - **[HIGH]** Actuator endpoints (`/actuator/env`, `/actuator/heapdump`, `/actuator/beans`) exposed without auth in production.
15
+ - **[HIGH]** `@CrossOrigin(origins = "*")` on authenticated endpoints → CORS credential leakage.
16
+ - **[HIGH]** Secrets in `application.properties` committed to VCS → use env vars, Spring Cloud Config, or HashiCorp Vault.
17
+ - **[HIGH]** JWT secret too short or default value in `application.yml` → token forging.
18
+ - **[HIGH]** Missing CSRF protection on state-changing endpoints when using session auth.
19
+ - **[HIGH]** `@Secured` / method security not enabled (`@EnableMethodSecurity`) → annotations silently ignored.
20
+ - **[HIGH]** Path traversal via user-controlled file path in `FileSystemResource` / `Files.readAllBytes()`.
21
+ - **[MEDIUM]** XXE in XML processing without disabling external entities in `DocumentBuilderFactory`.
22
+ - **[MEDIUM]** Spring Security `permitAll()` too broad on `/api/**` prefix.
23
+ - **[LOW]** Swagger/OpenAPI UI accessible in production without authentication.
24
+
25
+ ---
26
+
27
+ ## Performance
28
+
29
+ - **[HIGH]** N+1 Hibernate queries — `@OneToMany` with `FetchType.LAZY` accessed in loop → use `JOIN FETCH` or `@EntityGraph`.
30
+ - **[HIGH]** `FetchType.EAGER` on collections → loads all relations on every query even when unneeded.
31
+ - **[HIGH]** Missing `@Transactional(readOnly = true)` on read-only queries → Hibernate dirty-checking overhead.
32
+ - **[HIGH]** `findAll()` without pagination → unbounded result set, OOM on large tables.
33
+ - **[HIGH]** Missing database connection pool config (`spring.datasource.hikari.maximum-pool-size`) → default 10 connections under load.
34
+ - **[HIGH]** `@Async` methods not configured with custom `TaskExecutor` → uses default single-threaded executor.
35
+ - **[HIGH]** `ResponseEntity` with large body not streaming → buffering entire response in memory.
36
+ - **[MEDIUM]** Hibernate `OpenSessionInView` (default enabled in Spring Boot) → lazy loading in view layer, hidden N+1.
37
+ - **[MEDIUM]** Missing `@Cacheable` on expensive, stable query results.
38
+ - **[MEDIUM]** Multiple `@Transactional` service calls not merged → separate transactions, round-trips.
39
+ - **[MEDIUM]** `@Scheduled` tasks running too frequently blocking scheduler thread pool.
40
+ - **[LOW]** Jackson serialization of large objects without `@JsonView` → over-fetching in API responses.
41
+ - **[LOW]** Not using Spring Data projections for partial entity fetching.
42
+
43
+ ---
44
+
45
+ ## Architecture
46
+
47
+ - **[HIGH]** Business logic in `@RestController` → move to `@Service`.
48
+ - **[HIGH]** `@Autowired` on fields instead of constructor injection → harder to test, hidden dependencies.
49
+ - **[HIGH]** `@Repository` calling another `@Repository` directly → breaks layered architecture.
50
+ - **[HIGH]** `@Transactional` on `@RestController` → transaction spans HTTP serialization, scope too wide.
51
+ - **[HIGH]** Domain `@Entity` classes used as API DTOs → tight coupling, security risk.
52
+ - **[HIGH]** Not using `@ControllerAdvice` for global exception handling → inconsistent error responses.
53
+ - **[MEDIUM]** God `@Service` class >500 lines → split by domain responsibility.
54
+ - **[MEDIUM]** `@Component` used where `@Service`/`@Repository`/`@Configuration` is semantically correct.
55
+ - **[MEDIUM]** Spring Events not used for decoupling → direct service-to-service calls creating coupling.
56
+ - **[MEDIUM]** Not using Spring Profiles for environment-specific config → hardcoded env checks.
57
+ - **[MEDIUM]** `@Configuration` class doing too much → split by concern.
58
+ - **[LOW]** Missing `@Valid` on `@RequestBody` → Bean Validation annotations on DTO ignored.
59
+ - **[LOW]** Circular bean dependencies → startup failure or unexpected behavior.
60
+
61
+ ---
62
+
63
+ ## Code Quality
64
+
65
+ - **[HIGH]** `Optional.get()` without `isPresent()` check → `NoSuchElementException`. Use `orElse`/`orElseThrow`.
66
+ - **[HIGH]** Missing `@Valid` / `@Validated` on input DTOs → no input validation.
67
+ - **[HIGH]** `NullPointerException` risk from JPA `findById()` returning `Optional` not handled.
68
+ - **[MEDIUM]** `System.out.println` in production → use SLF4J `@Slf4j`.
69
+ - **[MEDIUM]** Catching `Exception` too broadly and swallowing → silent failure.
70
+ - **[MEDIUM]** Not using Lombok (`@Data`, `@Builder`, `@Slf4j`) where it reduces boilerplate.
71
+ - **[MEDIUM]** `@RestController` methods returning `Object` instead of typed `ResponseEntity<T>`.
72
+ - **[MEDIUM]** Not using `@ConfigurationProperties` for typed config → scattered `@Value` strings.
73
+ - **[MEDIUM]** Magic strings for request mapping paths → use constants.
74
+ - **[LOW]** Not using Spring Boot DevTools in development → slower feedback loop.
75
+ - **[LOW]** Not using Actuator health endpoints for Kubernetes liveness/readiness.
76
+
77
+ ---
78
+
79
+ ## Common Bugs & Pitfalls
80
+
81
+ - **[HIGH]** `@Transactional` on `private` method → AOP proxy doesn't intercept private methods, annotation silently ignored.
82
+ - **[HIGH]** Calling `@Transactional` method from within same bean (self-invocation) → proxy bypassed, no transaction.
83
+ - **[HIGH]** `@Async` method called from same class → proxy bypassed, executes synchronously.
84
+ - **[HIGH]** `LazyInitializationException` — accessing lazy relation outside `@Transactional` context.
85
+ - **[HIGH]** `@Entity` `equals()`/`hashCode()` based on mutable fields → breaks JPA identity semantics. Base on `id` only.
86
+ - **[HIGH]** `@Scheduled` cron expression incorrect timezone → runs at wrong time in different TZ deployments.
87
+ - **[MEDIUM]** `LocalDateTime` without timezone in `@Entity` → bugs in multi-timezone deployments. Use `Instant` or `OffsetDateTime`.
88
+ - **[MEDIUM]** `@OneToMany` `cascade = CascadeType.ALL` with `orphanRemoval = true` deleting unintended records.
89
+ - **[MEDIUM]** Spring Security filter order → custom filter added without `@Order` or `addFilterBefore` → wrong execution order.
90
+ - **[MEDIUM]** `@Value("${property}")` on static field → never injected. Use `@PostConstruct` or non-static.
91
+ - **[LOW]** `CommandLineRunner` / `ApplicationRunner` beans running in production → ensure `@Profile("!prod")` if dev-only.
92
+ - **[LOW]** Bean name collision between auto-configured and custom beans → unexpected bean override.
@@ -0,0 +1,85 @@
1
+ # SQL — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `*.sql` files, raw SQL in code (`SELECT`, `INSERT`, `UPDATE`, `DELETE`), `db.query(`, `connection.execute(`, `cursor.execute(`, `rawQuery`, migrations
5
+
6
+ ---
7
+
8
+ ## Security
9
+
10
+ - **[CRITICAL]** SQL query built with string concatenation/interpolation of user input → SQL injection. Always use parameterized queries / prepared statements.
11
+ - **[CRITICAL]** `UPDATE` or `DELETE` without `WHERE` clause → wipes entire table. Require explicit confirmation.
12
+ - **[HIGH]** `SELECT *` in application queries → over-fetches sensitive columns (passwords, tokens, PII).
13
+ - **[HIGH]** User-controlled `ORDER BY` column name without allowlist → SQL injection via column name.
14
+ - **[HIGH]** Missing `LIMIT` on user-controlled queries → full table dump, DoS.
15
+ - **[HIGH]** Stored procedure using `EXEC` / `sp_executesql` with user input → injection inside stored proc.
16
+ - **[HIGH]** Database user has DDL rights for application account → schema destruction on compromise. Use least-privilege role.
17
+ - **[HIGH]** Sensitive columns (SSN, card numbers, passwords) stored in plaintext → encrypt at rest or hash.
18
+ - **[MEDIUM]** Dynamic column/table name from user input even if quoted → SQL injection via quoting bypass.
19
+ - **[MEDIUM]** Excessive permissions granted to `PUBLIC` role → all users can access schema.
20
+ - **[MEDIUM]** Database connection string logged in application logs → credentials in log files.
21
+ - **[LOW]** DDL statements in application code path (not migrations) → accidental schema mutation.
22
+
23
+ ---
24
+
25
+ ## Performance
26
+
27
+ - **[CRITICAL]** N+1 query — SELECT inside loop for each row of outer query. Use JOIN or batch fetch.
28
+ - **[HIGH]** Missing index on `WHERE`, `JOIN ON`, `ORDER BY`, `GROUP BY` columns for frequent queries.
29
+ - **[HIGH]** Function applied to indexed column in WHERE: `WHERE LOWER(email) = ?` → index unused, full scan.
30
+ - **[HIGH]** Implicit type coercion in JOIN/WHERE (INT vs VARCHAR) → index skipped.
31
+ - **[HIGH]** `SELECT` without `LIMIT` on large table → unbounded result set, OOM.
32
+ - **[HIGH]** Correlated subquery in WHERE re-executed per row → O(n²). Rewrite as JOIN or CTE.
33
+ - **[HIGH]** `OFFSET` pagination on large tables → full scan up to offset. Use cursor/keyset pagination.
34
+ - **[MEDIUM]** `ORDER BY` on non-indexed column in large table → filesort.
35
+ - **[MEDIUM]** `COUNT(*)` on large table without suitable index → full scan.
36
+ - **[MEDIUM]** Missing `EXPLAIN ANALYZE` before shipping complex queries.
37
+ - **[MEDIUM]** Composite index column order wrong → index not used for partial prefix queries.
38
+ - **[MEDIUM]** `DISTINCT` papering over duplicates from bad JOIN → fix the JOIN cardinality.
39
+ - **[LOW]** Index on low-cardinality column (boolean, status with 3 values) → often ignored by optimizer.
40
+ - **[LOW]** Missing partial index for common filtered subset → full index scanned unnecessarily.
41
+
42
+ ---
43
+
44
+ ## Architecture
45
+
46
+ - **[HIGH]** Multi-step mutations without transaction → partial failure leaves inconsistent state.
47
+ - **[HIGH]** Missing foreign key constraints → orphaned records, broken referential integrity.
48
+ - **[HIGH]** Business logic in stored procedures/triggers → hard to version, test, deploy.
49
+ - **[HIGH]** Schema changes (ADD/DROP COLUMN) mixed with data migrations in same script → risky rollback.
50
+ - **[MEDIUM]** No rollback strategy for destructive migrations (DROP TABLE, TRUNCATE) → data loss on failed deploy.
51
+ - **[MEDIUM]** Denormalized data without documented justification → update anomalies accumulate.
52
+ - **[MEDIUM]** Missing soft-delete pattern for business-critical records → hard DELETE destroys audit trail.
53
+ - **[MEDIUM]** Long transactions locking rows → blocking other writers for extended time.
54
+ - **[MEDIUM]** Missing `created_at` / `updated_at` / `deleted_at` timestamps → no audit trail.
55
+ - **[LOW]** UUID vs sequential ID not chosen based on write patterns → UUID index fragmentation.
56
+ - **[LOW]** Not using database schema versioning tool (Flyway, Liquibase, Alembic).
57
+
58
+ ---
59
+
60
+ ## Code Quality
61
+
62
+ - **[HIGH]** Missing `NOT NULL` constraints on columns that should always have values.
63
+ - **[HIGH]** Missing `UNIQUE` constraint on columns requiring uniqueness (email, username) → duplicates possible despite app-level validation.
64
+ - **[MEDIUM]** `TIMESTAMP` without timezone (`TIMESTAMP` vs `TIMESTAMPTZ`) → timezone bugs for international users.
65
+ - **[MEDIUM]** `VARCHAR` without length limit or with unreasonably large limit → storage/performance implications.
66
+ - **[MEDIUM]** Inconsistent naming conventions (camelCase in app, snake_case in DB) → mapping confusion.
67
+ - **[MEDIUM]** Missing `CHECK` constraints for domain validation (positive amounts, valid status values).
68
+ - **[MEDIUM]** `ENUM` type not used where values are constrained → free-text with no DB-level validation.
69
+ - **[LOW]** SQL keywords not uppercase → inconsistent style.
70
+ - **[LOW]** Missing comments on complex queries (window functions, CTEs with non-obvious logic).
71
+
72
+ ---
73
+
74
+ ## Common Bugs & Pitfalls
75
+
76
+ - **[HIGH]** `NULL` compared with `=` instead of `IS NULL` → condition always false (`NULL = NULL` is `NULL` in SQL).
77
+ - **[HIGH]** Off-by-one in OFFSET pagination: `OFFSET (page-1) * limit` → page 0 and 1 return same rows.
78
+ - **[HIGH]** Transaction not committed → changes visible in session but lost on disconnect.
79
+ - **[MEDIUM]** `BETWEEN` inclusive on both ends — may include/exclude boundary unexpectedly for dates/times.
80
+ - **[MEDIUM]** `GROUP BY` without aggregate in non-strict mode → non-deterministic result columns.
81
+ - **[MEDIUM]** `LEFT JOIN` filtering in `WHERE` clause converting it to `INNER JOIN` behavior → use `WHERE t2.id IS NULL` for exclusive left join.
82
+ - **[MEDIUM]** Division without zero check → division by zero runtime error.
83
+ - **[MEDIUM]** `IN (NULL)` condition always false → use `IS NULL` separately.
84
+ - **[LOW]** `LIKE '%text%'` not using index → trigram index (pg_trgm) needed for substring search.
85
+ - **[LOW]** Storing comma-separated values in single column → violates 1NF, query complexity explosion.
@@ -0,0 +1,55 @@
1
+ # SQLite — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `sqlite3`, `better-sqlite3`, `from 'better-sqlite3'`, `sqlite`, `*.db`, `*.sqlite`, `*.sqlite3`, `SQLITE_`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** SQL injection via string concatenation instead of `?` placeholders → attacker can read, modify, or delete all data in the file. Use parameterized queries with `?` placeholders in all drivers (`sqlite3`, `better-sqlite3`, `database/sql`).
10
+ - **[HIGH]** Database file stored in a web-accessible directory (e.g., `public/`, `static/`, `wwwroot/`) → direct HTTP download exposes entire database. Store the `.db` file outside the web root and serve data only via application endpoints.
11
+ - **[HIGH]** `ATTACH DATABASE` used with user-controlled filename → allows attacker to read or overwrite arbitrary `.db` files on the server. Never pass user input to `ATTACH DATABASE`; hardcode all attached database paths.
12
+ - **[HIGH]** WAL-mode journal files (`.db-wal`, `.db-shm`) served publicly → exposes uncommitted transaction data. Add `.db-wal` and `.db-shm` to the web server's deny list alongside the primary `.db` file.
13
+ - **[MEDIUM]** No encryption at rest for databases containing sensitive data → any process with filesystem access reads the entire database. Use SQLCipher or encrypt at the filesystem/disk level for sensitive deployments.
14
+ - **[MEDIUM]** Database file has world-readable permissions (e.g., `chmod 644`) → any OS user can open and read or copy the file. Set permissions to `600` (owner read/write only) and run the application as a dedicated user.
15
+
16
+ ---
17
+
18
+ ## Performance
19
+ - **[CRITICAL]** WAL mode not enabled (`PRAGMA journal_mode=WAL`) → default DELETE journal mode serializes all reads during writes, blocking concurrent read access. Run `PRAGMA journal_mode=WAL` once on database open for all applications with concurrent readers.
20
+ - **[HIGH]** `PRAGMA synchronous` not tuned for workload → default `FULL` mode flushes to disk on every transaction, causing very slow write throughput. Set `PRAGMA synchronous=NORMAL` for a balance of durability and performance in most workloads.
21
+ - **[HIGH]** Bulk inserts executed outside an explicit transaction → SQLite auto-commits each statement, causing a full fsync per row; 10,000 rows can take minutes. Wrap all bulk inserts in `BEGIN` / `COMMIT`.
22
+ - **[HIGH]** Missing indexes on columns used in `WHERE` or `ORDER BY` clauses → SQLite performs full-file linear scan. Run `EXPLAIN QUERY PLAN` on all queries and add indexes for any `SCAN TABLE` results.
23
+ - **[MEDIUM]** `VACUUM` not run periodically after large deletes → free pages accumulate inside the file, increasing its size and slowing reads. Schedule periodic `VACUUM` or enable `PRAGMA auto_vacuum=INCREMENTAL`.
24
+ - **[MEDIUM]** Large BLOBs (images, documents) stored directly in the database → inflates database file size, slows page cache, increases memory pressure. Store binary files on disk or object storage; keep only the file path or key in the DB.
25
+ - **[LOW]** `PRAGMA cache_size` not adjusted from the 2 MB default for large working sets → frequent page eviction causes repeated disk reads. Tune `PRAGMA cache_size` (negative value = KB) based on available RAM and dataset size.
26
+
27
+ ---
28
+
29
+ ## Architecture
30
+ - **[HIGH]** SQLite chosen for a workload requiring multiple concurrent writers (e.g., multi-process server, high-throughput API) → write serialization and locking cause `SQLITE_BUSY` errors under load. Migrate to PostgreSQL or MySQL for any workload with concurrent writes from multiple connections.
31
+ - **[HIGH]** Database file placed on a network-mounted filesystem (NFS, SMB) → POSIX file locking is unreliable over NFS, causing database corruption. SQLite must reside on a local filesystem; use a client-server DB for shared network storage.
32
+ - **[MEDIUM]** Repeated identical queries not using prepared statements → SQL parsed and planned on every execution. Prepare statements once and reuse them for hot code paths.
33
+ - **[MEDIUM]** Schema version not tracked with a `schema_version` table or `PRAGMA user_version` → no way to detect schema drift or apply incremental migrations. Use `PRAGMA user_version` to store and check schema version on startup.
34
+ - **[MEDIUM]** Application deployed with multiple processes sharing one SQLite file → each process holds its own connection, increasing lock contention. Use a single in-process connection or switch to a client-server database.
35
+ - **[LOW]** `WITHOUT ROWID` not considered for tables where the primary key is always used for access → standard rowid table adds an extra hidden integer column and a secondary lookup. Use `WITHOUT ROWID` for small, frequently accessed tables keyed only by their primary key.
36
+
37
+ ---
38
+
39
+ ## Code Quality
40
+ - **[HIGH]** `better-sqlite3` synchronous API used on the main Node.js event loop thread without a worker thread → every DB operation blocks the entire event loop during execution. Offload `better-sqlite3` calls to a worker thread or use the async `sqlite3` driver.
41
+ - **[MEDIUM]** Database connection not explicitly closed on process exit → in-flight WAL data may not be checkpointed, risking data loss or corruption on the next open. Register a `process.on('exit')` handler that calls `db.close()`.
42
+ - **[MEDIUM]** Multi-step operations (insert + update) not wrapped in `db.transaction()` (better-sqlite3) or `BEGIN`/`COMMIT` → partial failure leaves the database in an inconsistent state. Use `db.transaction(fn)()` for all operations that must be atomic.
43
+ - **[MEDIUM]** Foreign key enforcement not enabled (`PRAGMA foreign_keys=ON` missing) → SQLite ignores FK constraints by default, allowing orphaned rows silently. Enable `PRAGMA foreign_keys=ON` immediately after every new connection is opened.
44
+ - **[LOW]** Database opened with `readonly: false` when only reads are needed → accidental writes possible; WAL checkpointing triggered unnecessarily. Open with `{ readonly: true }` for connections that only read data.
45
+
46
+ ---
47
+
48
+ ## Common Bugs & Pitfalls
49
+ - **[CRITICAL]** `PRAGMA foreign_keys` is `OFF` by default → all `FOREIGN KEY` constraints are silently ignored until explicitly enabled. Add `PRAGMA foreign_keys=ON` to every connection initialization path.
50
+ - **[HIGH]** Concurrent writes from multiple OS processes cause `SQLITE_BUSY` or `SQLITE_LOCKED` errors → SQLite allows only one writer at a time across all processes. Implement retry-with-backoff on `SQLITE_BUSY`, or restructure to a single writer process.
51
+ - **[HIGH]** `INTEGER PRIMARY KEY` assumed to be a UUID or random identifier → it is an alias for the 64-bit rowid and is sequential and predictable. Use a `TEXT` column with `gen_random_uuid()` or a UUID library if non-guessable IDs are required.
52
+ - **[MEDIUM]** Date and time values stored as inconsistently formatted `TEXT` (e.g., mix of ISO 8601 and locale strings) → lexicographic sort and comparison produce wrong results. Store all datetimes as ISO 8601 UTC strings (`YYYY-MM-DDTHH:MM:SSZ`) or as Unix epoch integers.
53
+ - **[MEDIUM]** `NULL` stored in a column where `0` or empty string is the intended value → `WHERE col = 0` misses NULL rows; aggregates like `COUNT` skip NULLs. Add `NOT NULL DEFAULT 0` (or appropriate default) to columns that should never be absent.
54
+ - **[LOW]** Boolean values stored as `0`/`1` INTEGER without a `CHECK` constraint → values like `2` or `-1` accepted silently. Add `CHECK (col IN (0, 1))` or use a named constant in application code.
55
+
@@ -0,0 +1,51 @@
1
+ # Styled Components — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `from 'styled-components'`, `styled.div`, `` css` ``, `ThemeProvider`, `createGlobalStyle`, `keyframes`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** Interpolating user-controlled input directly into a CSS template string `styled.div\`color: ${userInput}\`` → CSS injection, potentially leaking data via `url()` or overriding layout. Sanitize or validate all dynamic CSS values before interpolation.
10
+ - **[HIGH]** Dynamic styled component receiving user-controlled style props that map to raw CSS values → style injection allowing arbitrary CSS. Whitelist allowed values and reject freeform strings.
11
+ - **[MEDIUM]** `dangerouslySetInnerHTML` used inside a styled component → XSS vector unrelated to CSS but compounded by component complexity. Remove or sanitize HTML before rendering.
12
+ - **[MEDIUM]** CSS custom properties (`var(--color)`) bound to values derived from user input in server-rendered HTML → CSS injection via `style` attribute. Encode or restrict user-influenced CSS variable values.
13
+ - **[LOW]** External font or image `url()` in global styles loaded from user-configurable CMS fields → unexpected resource loading. Validate URLs against an allowlist before use in CSS.
14
+
15
+ ---
16
+
17
+ ## Performance
18
+ - **[HIGH]** Styled component defined inside another component's render function → a new component class and stylesheet entry is generated on every render. Move all `styled.*` definitions to module scope, outside render.
19
+ - **[HIGH]** `ThemeProvider` mounted at a granular or frequently re-rendering level → all children re-render when theme reference changes. Place a single `ThemeProvider` at the app root and memoize the theme object.
20
+ - **[HIGH]** Complex conditional styles using many props without the `css` helper → styled-components generates a unique class for each prop combination, causing class explosion. Use the `css` helper with conditional logic to minimize class variants.
21
+ - **[MEDIUM]** `createGlobalStyle` component instantiated inside a component body → global styles re-injected into the `<head>` on every mount. Render `createGlobalStyle` components once at the app root only.
22
+ - **[MEDIUM]** Deeply nested CSS selectors (>3 levels) in styled component templates → high specificity output, larger CSS bundle, harder override. Flatten selector hierarchy or compose via component props.
23
+ - **[LOW]** `shouldForwardProp` not configured for custom props → unknown HTML attributes forwarded to the DOM, React warnings in console and potential attribute bloat. Use `.withConfig({ shouldForwardProp })` or prefix custom props with `$`.
24
+
25
+ ---
26
+
27
+ ## Architecture
28
+ - **[HIGH]** Business logic or conditional rendering logic embedded inside CSS template literals → logic not testable and duplicated across style and component. Keep templates as pure styling; move logic to component level.
29
+ - **[MEDIUM]** Colors, spacing, and typography hardcoded inside styled components instead of consumed from theme → global restyling requires grep-and-replace across all files. Define a design token theme and access via `${({ theme }) => theme.colors.primary}`.
30
+ - **[MEDIUM]** No clear boundary between global styles (`createGlobalStyle`) and component-scoped styles → specificity conflicts and unintended style bleed. Reserve global styles for resets and root variables only.
31
+ - **[MEDIUM]** Styled components not organized per feature/component → style files scattered without clear ownership. Co-locate `styled.ts` or `styles.ts` alongside each component file.
32
+ - **[LOW]** Styled components exported without display names (anonymous) → DevTools and error stack traces show `styled.div` instead of meaningful names. Name styled components explicitly or use the Babel/SWC plugin for automatic display names.
33
+
34
+ ---
35
+
36
+ ## Code Quality
37
+ - **[HIGH]** TypeScript `DefaultTheme` interface not augmented → `theme` prop typed as `{}`, no autocomplete or type checking on theme tokens. Augment `DefaultTheme` in a `.d.ts` file with the full theme shape.
38
+ - **[MEDIUM]** Custom props on styled components not declared in the TypeScript generic → prop types inferred as `any`, breaking type safety. Pass prop interface as generic: `styled.div<{ $active: boolean }>`.
39
+ - **[MEDIUM]** Mixing inline `style` attribute with styled-components on the same element → specificity conflicts and unclear style source of truth. Choose one mechanism; use styled-components props for dynamic values.
40
+ - **[MEDIUM]** `attrs` used to set dynamic values that change frequently (e.g., cursor position) → `attrs` values become part of the class hash, generating a new class per value. Use inline `style` for values that change on every frame.
41
+ - **[LOW]** `keyframes` animations defined inline within component files rather than in a shared animations module → duplicated keyframe blocks across the bundle. Extract to a shared `animations.ts` and import where needed.
42
+
43
+ ---
44
+
45
+ ## Common Bugs & Pitfalls
46
+ - **[HIGH]** Server-side rendered styled-components class names not matching client-side names → React hydration mismatch and style flicker. Install and configure the `babel-plugin-styled-components` or `@swc/plugin-styled-components` and enable `ssr: true`.
47
+ - **[HIGH]** `attrs` used to inject dynamic values that change on every interaction → a new class is injected into the stylesheet per unique value, causing stylesheet pollution and memory growth. Use the `style` prop for high-frequency dynamic values.
48
+ - **[MEDIUM]** `ref` forwarding broken on a styled component wrapping a custom component → `ref` not passed through to DOM node. Ensure the inner component uses `React.forwardRef`.
49
+ - **[MEDIUM]** Component using `theme` values rendered outside a `ThemeProvider` → theme is `undefined`, causing runtime crash or missing styles. Provide a default theme fallback or always wrap the app in `ThemeProvider`.
50
+ - **[MEDIUM]** Extending styled components with `styled(ComponentA)` when `ComponentA` does not accept `className` prop → styles silently not applied. Ensure base components accept and apply the `className` prop.
51
+ - **[LOW]** CSS specificity conflicts with CSS reset or third-party libraries → styled-components class specificity (single class) loses to multi-selector resets. Increase specificity with `&&` or restructure the reset.
@@ -0,0 +1,57 @@
1
+ # Supabase — Stack-Specific Review Rules
2
+
3
+ > Applies to: GR · SR · PR · AR · BR
4
+ > Detection signals: `@supabase/supabase-js`, `from '@supabase/supabase-js'`, `createClient(`, `supabase.from(`, `supabase.auth`, `SUPABASE_URL`, `SUPABASE_KEY`
5
+
6
+ ---
7
+
8
+ ## Security
9
+ - **[CRITICAL]** `SUPABASE_SERVICE_ROLE_KEY` exposed in client-side code → service role bypasses all RLS policies; attacker gains full unrestricted DB access. Move all service role usage to server-side API routes or Edge Functions only.
10
+ - **[CRITICAL]** RLS not enabled on tables with user-owned data → any authenticated user can read, update, or delete all rows. Enable RLS on every table and define at least one policy per operation type.
11
+ - **[HIGH]** RLS policies not tested for bypass → policies may have logic errors allowing cross-user data access. Write SQL tests for each policy using `SET LOCAL role` to simulate different authenticated users.
12
+ - **[HIGH]** `anon` key used in server-side code for operations requiring elevated trust → anon key is publicly known. Use the service role key on the server and the anon key only in the browser.
13
+ - **[HIGH]** Storage bucket set to public for files containing private user data → any person with the URL can access the file without authentication. Set buckets to private and generate signed URLs server-side.
14
+ - **[MEDIUM]** Edge Functions not validating the JWT before processing requests → unauthenticated callers can invoke business logic. Call `supabase.auth.getUser()` at the start of every Edge Function and return 401 if it errors.
15
+ - **[MEDIUM]** Supabase project URL and anon key committed to repository → exposes project ref enabling targeted enumeration. Store all keys in environment variables.
16
+
17
+ ---
18
+
19
+ ## Performance
20
+ - **[HIGH]** N+1 queries via multiple sequential `.from('table').select()` calls in a loop → one HTTP round-trip per item. Use embedded resource syntax: `.select('*, related_table(*)')` to join in a single request.
21
+ - **[HIGH]** `.select('*')` without specifying a column list → over-fetches all columns, wastes bandwidth. Always pass an explicit column list.
22
+ - **[HIGH]** No pagination on list queries on growing tables → full table returned to client. Add `.range(from, to)` or `.limit(n)` to all list endpoints.
23
+ - **[MEDIUM]** Realtime subscriptions not filtered by channel filter → client receives events for all rows. Add a `filter` option to `.on()` calls to scope subscriptions to the authenticated user.
24
+ - **[MEDIUM]** Supabase Storage not using image transformation parameters → full-resolution images served to clients that need thumbnails. Use `getPublicUrl(path, { transform: { width, height } })`.
25
+ - **[MEDIUM]** Multiple Supabase client instances created per request → each holds a new HTTP client and auth session state. Create one Supabase client at module level and reuse it.
26
+ - **[LOW]** PostgREST response caching headers not leveraged → identical list queries hit the database on every request. Add `Cache-Control` headers for read-heavy public endpoints.
27
+
28
+ ---
29
+
30
+ ## Architecture
31
+ - **[HIGH]** Direct Supabase client calls from UI components without server layer → business validation bypassed; client has direct DB access. Route sensitive mutations through Edge Functions or a server API layer.
32
+ - **[HIGH]** Business logic embedded in RLS policies → policies become unmaintainable SQL. Keep RLS policies simple (e.g., `auth.uid() = user_id`); move complex validation to Edge Functions.
33
+ - **[MEDIUM]** Not using Supabase Edge Functions for sensitive operations (payment, third-party API calls with secrets) → secrets must be exposed client-side. Implement sensitive operations as Edge Functions with secrets in Supabase Vault.
34
+ - **[MEDIUM]** Auth state managed manually instead of using `onAuthStateChange` → auth state drifts; stale tokens used after expiry. Use `supabase.auth.onAuthStateChange()` as the single source of truth.
35
+ - **[MEDIUM]** Supabase CLI not used for local development → developers test against a shared cloud project, polluting production data. Use `supabase start` to run a local Supabase stack.
36
+ - **[LOW]** Database functions written via Dashboard SQL editor without version control → schema drift; no rollback path. Write all DB functions as migration files under `supabase/migrations/`.
37
+
38
+ ---
39
+
40
+ ## Code Quality
41
+ - **[HIGH]** Error not checked after every Supabase call (`error` ignored in destructured result) → silent failures; stale `data` used as if valid. Check `if (error) throw error` immediately after every Supabase call.
42
+ - **[HIGH]** `supabase.auth.getSession()` used server-side → returns session from token without re-validating against the server; a tampered JWT can pass. Use `supabase.auth.getUser()` server-side.
43
+ - **[MEDIUM]** TypeScript types not generated from the Supabase schema → all `supabase.from()` calls return `any`. Run `supabase gen types typescript --local` and import the generated `Database` type.
44
+ - **[MEDIUM]** Table names used as magic strings (`supabase.from('users')`) → table rename requires grep-and-replace. Extract table names to a typed constants object.
45
+ - **[MEDIUM]** Not using `.single()` when exactly one row is expected → `.select()` returns an array; `data[0]` silently returns `undefined` if no rows match. Use `.single()` to get a plain object and receive an error on mismatch.
46
+ - **[LOW]** Supabase client created with service role key in a file bundled for both server and client → service role key may leak into the client bundle. Use separate client files for browser and server.
47
+
48
+ ---
49
+
50
+ ## Common Bugs & Pitfalls
51
+ - **[CRITICAL]** RLS enabled on a table but no policy created → all SELECT, INSERT, UPDATE, DELETE return 0 rows with no error; data appears to vanish. After enabling RLS, immediately create at least one permissive policy for the intended roles.
52
+ - **[HIGH]** `supabase.auth.getSession()` used server-side instead of `getUser()` → session JWT taken at face value; forged or expired token accepted. Replace all server-side `getSession()` calls with `getUser()`.
53
+ - **[HIGH]** Realtime channel not unsubscribed on component unmount → WebSocket connection and event listener leak on each mount. Call `supabase.removeChannel(channel)` in the cleanup function.
54
+ - **[MEDIUM]** `upsert()` called with an `onConflict` column lacking a unique constraint → Supabase throws a runtime error instead of upserting. Ensure a `UNIQUE` constraint exists on the `onConflict` column.
55
+ - **[MEDIUM]** Storage file paths not namespaced by user ID (e.g., `avatar.png` instead of `{userId}/avatar.png`) → a user can overwrite another user's file by guessing the path. Always prefix file paths with the authenticated user's ID.
56
+ - **[MEDIUM]** `.insert([...])` not chaining `.select()` after insert → generated columns (id, created_at) not returned; application references undefined. Chain `.select()` after `.insert()` to return the created row.
57
+ - **[LOW]** Supabase free-tier project paused after inactivity → API calls return 503 in staging. Upgrade to a paid tier for persistent staging or implement a keep-alive ping.