bros-harness 0.1.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 (187) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +183 -0
  4. package/SECURITY.md +16 -0
  5. package/assets/agents.manifest.json +55 -0
  6. package/assets/commands.manifest.json +35 -0
  7. package/assets/docs.manifest.json +20 -0
  8. package/assets/import-report.md +25 -0
  9. package/assets/manifest.json +799 -0
  10. package/assets/opencode/agents/README.md +3 -0
  11. package/assets/opencode/agents/bro-build.md +256 -0
  12. package/assets/opencode/agents/bro-design.md +77 -0
  13. package/assets/opencode/agents/bro-docs.md +72 -0
  14. package/assets/opencode/agents/bro-explore.md +143 -0
  15. package/assets/opencode/agents/bro-ops.md +195 -0
  16. package/assets/opencode/agents/bro-shield.md +77 -0
  17. package/assets/opencode/agents/bro-test.md +204 -0
  18. package/assets/opencode/agents/bro-ui.md +135 -0
  19. package/assets/opencode/agents/mighty-bro.md +252 -0
  20. package/assets/opencode/commands/README.md +3 -0
  21. package/assets/opencode/commands/bros-assemble.md +32 -0
  22. package/assets/opencode/commands/bros-build.md +58 -0
  23. package/assets/opencode/commands/bros-plan.md +83 -0
  24. package/assets/opencode/commands/bros-review.md +38 -0
  25. package/assets/opencode/commands/bros-status.md +26 -0
  26. package/assets/opencode/docs/README.md +3 -0
  27. package/assets/opencode/docs/bros-builtin-skills.md +63 -0
  28. package/assets/opencode/docs/bros-harness.md +194 -0
  29. package/assets/opencode/skills/README.md +3 -0
  30. package/assets/opencode/skills/agent-architecture-audit/SKILL.md +256 -0
  31. package/assets/opencode/skills/agent-harness-construction/.openskills.json +7 -0
  32. package/assets/opencode/skills/agent-harness-construction/SKILL.md +73 -0
  33. package/assets/opencode/skills/agent-introspection-debugging/.openskills.json +7 -0
  34. package/assets/opencode/skills/agent-introspection-debugging/SKILL.md +153 -0
  35. package/assets/opencode/skills/api-design/.openskills.json +7 -0
  36. package/assets/opencode/skills/api-design/agents/openai.yaml +7 -0
  37. package/assets/opencode/skills/architecture-decision-records/.openskills.json +7 -0
  38. package/assets/opencode/skills/architecture-decision-records/SKILL.md +179 -0
  39. package/assets/opencode/skills/article-writing/.openskills.json +7 -0
  40. package/assets/opencode/skills/article-writing/SKILL.md +79 -0
  41. package/assets/opencode/skills/article-writing/agents/openai.yaml +7 -0
  42. package/assets/opencode/skills/automation-audit-ops/.openskills.json +7 -0
  43. package/assets/opencode/skills/automation-audit-ops/SKILL.md +142 -0
  44. package/assets/opencode/skills/backend-patterns/.openskills.json +7 -0
  45. package/assets/opencode/skills/backend-patterns/SKILL.md +561 -0
  46. package/assets/opencode/skills/backend-patterns/agents/openai.yaml +7 -0
  47. package/assets/opencode/skills/benchmark/.openskills.json +7 -0
  48. package/assets/opencode/skills/benchmark/SKILL.md +93 -0
  49. package/assets/opencode/skills/bros-orchestrate/SKILL.md +455 -0
  50. package/assets/opencode/skills/browser-qa/.openskills.json +7 -0
  51. package/assets/opencode/skills/browser-qa/SKILL.md +87 -0
  52. package/assets/opencode/skills/canary-watch/.openskills.json +7 -0
  53. package/assets/opencode/skills/canary-watch/SKILL.md +107 -0
  54. package/assets/opencode/skills/code-review-expert/SKILL.md +155 -0
  55. package/assets/opencode/skills/code-review-expert/agents/agent.yaml +7 -0
  56. package/assets/opencode/skills/code-review-expert/references/code-quality-checklist.md +130 -0
  57. package/assets/opencode/skills/code-review-expert/references/removal-plan.md +52 -0
  58. package/assets/opencode/skills/code-review-expert/references/security-checklist.md +118 -0
  59. package/assets/opencode/skills/code-review-expert/references/solid-checklist.md +65 -0
  60. package/assets/opencode/skills/code-tour/.openskills.json +7 -0
  61. package/assets/opencode/skills/code-tour/SKILL.md +236 -0
  62. package/assets/opencode/skills/coding-standards/.openskills.json +7 -0
  63. package/assets/opencode/skills/coding-standards/SKILL.md +549 -0
  64. package/assets/opencode/skills/coding-standards/agents/openai.yaml +7 -0
  65. package/assets/opencode/skills/context-budget/.openskills.json +7 -0
  66. package/assets/opencode/skills/context-budget/SKILL.md +135 -0
  67. package/assets/opencode/skills/database-migrations/.openskills.json +7 -0
  68. package/assets/opencode/skills/database-migrations/SKILL.md +429 -0
  69. package/assets/opencode/skills/deployment-patterns/.openskills.json +7 -0
  70. package/assets/opencode/skills/deployment-patterns/SKILL.md +427 -0
  71. package/assets/opencode/skills/design-system/.openskills.json +7 -0
  72. package/assets/opencode/skills/design-system/SKILL.md +82 -0
  73. package/assets/opencode/skills/docker-patterns/.openskills.json +7 -0
  74. package/assets/opencode/skills/docker-patterns/SKILL.md +364 -0
  75. package/assets/opencode/skills/documentation-lookup/.openskills.json +7 -0
  76. package/assets/opencode/skills/documentation-lookup/SKILL.md +90 -0
  77. package/assets/opencode/skills/documentation-lookup/agents/openai.yaml +7 -0
  78. package/assets/opencode/skills/e2e-testing/.openskills.json +7 -0
  79. package/assets/opencode/skills/e2e-testing/SKILL.md +326 -0
  80. package/assets/opencode/skills/e2e-testing/agents/openai.yaml +7 -0
  81. package/assets/opencode/skills/error-handling/SKILL.md +376 -0
  82. package/assets/opencode/skills/frontend-design/.openskills.json +7 -0
  83. package/assets/opencode/skills/frontend-design/SKILL.md +145 -0
  84. package/assets/opencode/skills/frontend-design-direction/SKILL.md +92 -0
  85. package/assets/opencode/skills/frontend-patterns/.openskills.json +7 -0
  86. package/assets/opencode/skills/frontend-patterns/SKILL.md +642 -0
  87. package/assets/opencode/skills/frontend-patterns/agents/openai.yaml +7 -0
  88. package/assets/opencode/skills/gateguard/.openskills.json +7 -0
  89. package/assets/opencode/skills/gateguard/SKILL.md +125 -0
  90. package/assets/opencode/skills/git-master/SKILL.md +60 -0
  91. package/assets/opencode/skills/golang-patterns/.openskills.json +7 -0
  92. package/assets/opencode/skills/golang-patterns/SKILL.md +674 -0
  93. package/assets/opencode/skills/golang-testing/.openskills.json +7 -0
  94. package/assets/opencode/skills/golang-testing/SKILL.md +720 -0
  95. package/assets/opencode/skills/grafana-dashboard-design/SKILL.md +65 -0
  96. package/assets/opencode/skills/hexagonal-architecture/.openskills.json +7 -0
  97. package/assets/opencode/skills/hexagonal-architecture/SKILL.md +276 -0
  98. package/assets/opencode/skills/java-coding-standards/.openskills.json +7 -0
  99. package/assets/opencode/skills/java-coding-standards/SKILL.md +383 -0
  100. package/assets/opencode/skills/jpa-patterns/.openskills.json +7 -0
  101. package/assets/opencode/skills/jpa-patterns/SKILL.md +151 -0
  102. package/assets/opencode/skills/knowledge-ops/.openskills.json +7 -0
  103. package/assets/opencode/skills/knowledge-ops/SKILL.md +154 -0
  104. package/assets/opencode/skills/make-interfaces-feel-better/SKILL.md +151 -0
  105. package/assets/opencode/skills/mysql-patterns/SKILL.md +412 -0
  106. package/assets/opencode/skills/nestjs-patterns/.openskills.json +7 -0
  107. package/assets/opencode/skills/nestjs-patterns/SKILL.md +230 -0
  108. package/assets/opencode/skills/nextjs-turbopack/.openskills.json +7 -0
  109. package/assets/opencode/skills/nextjs-turbopack/SKILL.md +57 -0
  110. package/assets/opencode/skills/nextjs-turbopack/agents/openai.yaml +7 -0
  111. package/assets/opencode/skills/parallel-execution-optimizer/SKILL.md +72 -0
  112. package/assets/opencode/skills/postgres-patterns/.openskills.json +7 -0
  113. package/assets/opencode/skills/postgres-patterns/SKILL.md +147 -0
  114. package/assets/opencode/skills/prisma-patterns/SKILL.md +371 -0
  115. package/assets/opencode/skills/product-capability/.openskills.json +7 -0
  116. package/assets/opencode/skills/product-capability/SKILL.md +141 -0
  117. package/assets/opencode/skills/product-lens/.openskills.json +7 -0
  118. package/assets/opencode/skills/product-lens/SKILL.md +92 -0
  119. package/assets/opencode/skills/production-audit/SKILL.md +206 -0
  120. package/assets/opencode/skills/python-patterns/.openskills.json +7 -0
  121. package/assets/opencode/skills/python-patterns/SKILL.md +750 -0
  122. package/assets/opencode/skills/python-testing/.openskills.json +7 -0
  123. package/assets/opencode/skills/python-testing/SKILL.md +816 -0
  124. package/assets/opencode/skills/redis-patterns/SKILL.md +403 -0
  125. package/assets/opencode/skills/requirements-clarity/README.md +260 -0
  126. package/assets/opencode/skills/requirements-clarity/SKILL.md +324 -0
  127. package/assets/opencode/skills/rust-patterns/.openskills.json +7 -0
  128. package/assets/opencode/skills/rust-patterns/SKILL.md +499 -0
  129. package/assets/opencode/skills/rust-testing/.openskills.json +7 -0
  130. package/assets/opencode/skills/rust-testing/SKILL.md +500 -0
  131. package/assets/opencode/skills/safety-guard/.openskills.json +7 -0
  132. package/assets/opencode/skills/safety-guard/SKILL.md +75 -0
  133. package/assets/opencode/skills/search-first/.openskills.json +7 -0
  134. package/assets/opencode/skills/search-first/SKILL.md +181 -0
  135. package/assets/opencode/skills/security-review/.openskills.json +7 -0
  136. package/assets/opencode/skills/security-review/agents/openai.yaml +7 -0
  137. package/assets/opencode/skills/security-review/cloud-infrastructure-security.md +361 -0
  138. package/assets/opencode/skills/security-scan/.openskills.json +7 -0
  139. package/assets/opencode/skills/security-scan/SKILL.md +165 -0
  140. package/assets/opencode/skills/springboot-patterns/.openskills.json +7 -0
  141. package/assets/opencode/skills/springboot-patterns/SKILL.md +314 -0
  142. package/assets/opencode/skills/springboot-tdd/.openskills.json +7 -0
  143. package/assets/opencode/skills/springboot-tdd/SKILL.md +158 -0
  144. package/assets/opencode/skills/springboot-verification/.openskills.json +7 -0
  145. package/assets/opencode/skills/springboot-verification/SKILL.md +231 -0
  146. package/assets/opencode/skills/strategic-compact/.openskills.json +7 -0
  147. package/assets/opencode/skills/strategic-compact/SKILL.md +131 -0
  148. package/assets/opencode/skills/strategic-compact/agents/openai.yaml +7 -0
  149. package/assets/opencode/skills/strategic-compact/suggest-compact.sh +54 -0
  150. package/assets/opencode/skills/tdd-workflow/.openskills.json +7 -0
  151. package/assets/opencode/skills/tdd-workflow/SKILL.md +463 -0
  152. package/assets/opencode/skills/tdd-workflow/agents/openai.yaml +7 -0
  153. package/assets/opencode/skills/verification-loop/.openskills.json +7 -0
  154. package/assets/opencode/skills/verification-loop/SKILL.md +126 -0
  155. package/assets/opencode/skills/verification-loop/agents/openai.yaml +7 -0
  156. package/assets/opencode/skills/vite-patterns/SKILL.md +449 -0
  157. package/assets/opencode/skills/web-doc-search/SKILL.md +51 -0
  158. package/assets/opencode/templates/README.md +3 -0
  159. package/assets/opencode/templates/bros/adr.md +39 -0
  160. package/assets/opencode/templates/bros/delivery-report.md +71 -0
  161. package/assets/opencode/templates/bros/explorer-evidence-packet.md +51 -0
  162. package/assets/opencode/templates/bros/prd.md +72 -0
  163. package/assets/opencode/templates/bros/security-review.md +48 -0
  164. package/assets/opencode/templates/bros/status-board.md +33 -0
  165. package/assets/opencode/templates/bros/task-packet.md +94 -0
  166. package/assets/opencode/templates/bros/test-strategy.md +57 -0
  167. package/assets/opencode/templates/bros/ui-implementation-packet.md +64 -0
  168. package/assets/skills.manifest.json +650 -0
  169. package/assets/templates.manifest.json +55 -0
  170. package/bin/bros.mjs +122 -0
  171. package/docs/compatibility.md +9 -0
  172. package/docs/installation.md +66 -0
  173. package/docs/integrations/claude.md +5 -0
  174. package/docs/integrations/codex.md +5 -0
  175. package/docs/integrations/opencode.md +39 -0
  176. package/docs/migration/from-local-opencode-config.md +10 -0
  177. package/docs/release-process.md +11 -0
  178. package/docs/repository-structure.md +15 -0
  179. package/docs/roadmap.md +20 -0
  180. package/docs/security.md +18 -0
  181. package/docs/testing.md +9 -0
  182. package/examples/opencode/README.md +11 -0
  183. package/examples/opencode/opencode.example.jsonc +4 -0
  184. package/package.json +43 -0
  185. package/scripts/validate-assets.mjs +22 -0
  186. package/scripts/verify-no-secrets.mjs +38 -0
  187. package/src/plugin.mjs +98 -0
@@ -0,0 +1,371 @@
1
+ ---
2
+ name: prisma-patterns
3
+ description: Prisma ORM patterns for TypeScript backends — schema design, query optimization, transactions, pagination, and critical traps like updateMany returning count not records, $transaction timeouts, migrate dev resetting the DB, @updatedAt skipped on bulk writes, and serverless connection exhaustion.
4
+ origin: ECC
5
+ ---
6
+
7
+ # Prisma Patterns
8
+
9
+ Production patterns and non-obvious traps for Prisma ORM in TypeScript backends.
10
+ Tested against Prisma 5.x and 6.x. Some behaviors differ from Prisma 4.
11
+
12
+ Check the Prisma version before applying version-specific patterns:
13
+
14
+ ```bash
15
+ npx prisma --version
16
+ ```
17
+
18
+ Prisma 5 introduced `relationJoins`, which can load relations via JOIN rather than separate queries depending on query strategy and configuration. The `omit` field modifier and `prisma.$extends` Client Extensions API were also added. Note: `relationJoins` can cause row explosion on large 1:N relations or deep nested `include` — benchmark both approaches when relations may return many rows per parent.
19
+
20
+ ## When to Activate
21
+
22
+ - Designing or modifying Prisma schema models and relations
23
+ - Writing queries, transactions, or pagination logic
24
+ - Using `updateMany`, `deleteMany`, or any bulk operation
25
+ - Running or planning database migrations
26
+ - Deploying to serverless environments (Vercel, Lambda, Cloudflare Workers)
27
+ - Implementing soft delete or multi-tenant row filtering
28
+
29
+ ## Core Concepts
30
+
31
+ ### ID Strategy
32
+
33
+ | Strategy | Use When | Avoid When |
34
+ |---|---|---|
35
+ | `@default(cuid())` | Default choice — URL-safe, sortable, no collisions | Sequential IDs needed for external systems |
36
+ | `@default(uuid())` | Interoperability with non-Prisma systems required | High-write tables (random UUIDs fragment B-tree indexes) |
37
+ | `@default(autoincrement())` | Internal join tables, audit logs | Public-facing IDs (exposes record count) |
38
+
39
+ ### Schema Defaults
40
+
41
+ ```prisma
42
+ model User {
43
+ id String @id @default(cuid())
44
+ email String @unique // @unique already creates an index — no @@index needed
45
+ name String
46
+ role Role @default(USER)
47
+ posts Post[]
48
+ createdAt DateTime @default(now())
49
+ updatedAt DateTime @updatedAt
50
+ deletedAt DateTime?
51
+
52
+ @@index([createdAt])
53
+ @@index([deletedAt, createdAt]) // composite for soft-delete + sort queries
54
+ }
55
+ ```
56
+
57
+ - Add `@@index` on every foreign key and column used in `WHERE` or `ORDER BY`.
58
+ - Declare `deletedAt DateTime?` upfront when soft delete is a foreseeable requirement — adding it later requires a migration on a live table.
59
+ - `updatedAt @updatedAt` is set automatically by Prisma on `update` and `upsert` only (see Anti-Patterns for bulk update trap).
60
+
61
+ ### `include` vs `select`
62
+
63
+ | | `include` | `select` |
64
+ |---|---|---|
65
+ | Returns | All scalar fields + specified relations | Only specified fields |
66
+ | Use when | You need most fields plus a relation | Hot paths, large tables, avoiding over-fetch |
67
+ | Performance | May over-fetch on wide tables | Minimal payload, faster on large datasets |
68
+ | Prisma 5 note | Uses JOIN by default (`relationJoins`) | Same |
69
+
70
+ ```ts
71
+ // include — all columns + relation
72
+ const user = await prisma.user.findUnique({
73
+ where: { id },
74
+ include: { posts: { select: { id: true, title: true } } },
75
+ });
76
+
77
+ // select — explicit allowlist
78
+ const user = await prisma.user.findUnique({
79
+ where: { id },
80
+ select: { id: true, email: true, name: true },
81
+ });
82
+ ```
83
+
84
+ Never return raw Prisma entities from API responses — map to response DTOs to control exposed fields:
85
+
86
+ ```ts
87
+ // BAD: leaks passwordHash, deletedAt, internal fields
88
+ return await prisma.user.findUniqueOrThrow({ where: { id } });
89
+
90
+ // GOOD: explicit DTO mapping
91
+ const user = await prisma.user.findUniqueOrThrow({ where: { id } });
92
+ return { id: user.id, name: user.name, email: user.email };
93
+ ```
94
+
95
+ ### Transaction Form Selection
96
+
97
+ | Situation | Use |
98
+ |---|---|
99
+ | Independent operations, no inter-dependency | Array form |
100
+ | Later step depends on earlier result | Interactive form |
101
+ | External calls (email, HTTP) involved | Outside transaction entirely |
102
+
103
+ ```ts
104
+ // Array form — batched in one round trip
105
+ const [user, post] = await prisma.$transaction([
106
+ prisma.user.update({ where: { id }, data: { name } }),
107
+ prisma.post.create({ data: { title, authorId: id } }),
108
+ ]);
109
+
110
+ // Interactive form — use tx client only, never the outer prisma client
111
+ const post = await prisma.$transaction(async (tx) => {
112
+ const user = await tx.user.findUniqueOrThrow({ where: { id } });
113
+ if (user.role !== 'ADMIN') throw new Error('Forbidden');
114
+ return tx.post.create({ data: { title, authorId: user.id } });
115
+ });
116
+ ```
117
+
118
+ ### PrismaClient Singleton
119
+
120
+ Each `PrismaClient` instance opens its own connection pool. Instantiate once.
121
+
122
+ ```ts
123
+ // lib/prisma.ts
124
+ import { PrismaClient } from '@prisma/client';
125
+
126
+ const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };
127
+
128
+ export const prisma =
129
+ globalForPrisma.prisma ??
130
+ new PrismaClient({
131
+ log: process.env.NODE_ENV === 'development' ? ['query', 'error'] : ['error'],
132
+ });
133
+
134
+ if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
135
+ ```
136
+
137
+ The `globalThis` pattern prevents duplicate instances during hot reload (Next.js, nodemon, ts-node-dev).
138
+
139
+ ### N+1 Problem
140
+
141
+ Loading relations inside a loop issues one query per row.
142
+
143
+ ```ts
144
+ // BAD: N+1 — one extra query per user
145
+ const users = await prisma.user.findMany();
146
+ for (const user of users) {
147
+ const posts = await prisma.post.findMany({ where: { authorId: user.id } });
148
+ }
149
+
150
+ // GOOD: single query
151
+ const users = await prisma.user.findMany({ include: { posts: true } });
152
+ ```
153
+
154
+ With Prisma 5+ `relationJoins`, the `include` form uses a single JOIN. On large 1:N sets this may increase result set size — benchmark both approaches if the relation can return many rows per parent.
155
+
156
+ ## Code Examples
157
+
158
+ ### Cursor Pagination (preferred for feeds and large datasets)
159
+
160
+ ```ts
161
+ async function getPosts(cursor?: string, limit = 20) {
162
+ const items = await prisma.post.findMany({
163
+ where: { published: true },
164
+ orderBy: [
165
+ { createdAt: 'desc' },
166
+ { id: 'desc' }, // secondary sort prevents unstable pagination on duplicate timestamps
167
+ ],
168
+ take: limit + 1,
169
+ ...(cursor && { cursor: { id: cursor }, skip: 1 }),
170
+ });
171
+
172
+ const hasNextPage = items.length > limit;
173
+ if (hasNextPage) items.pop();
174
+
175
+ return { items, nextCursor: hasNextPage ? items[items.length - 1].id : null };
176
+ }
177
+ ```
178
+
179
+ Fetch `limit + 1` and pop — canonical way to detect `hasNextPage` without an extra count query. Always include a unique field (e.g. `id`) as a secondary `orderBy` to prevent unstable pagination when multiple rows share the same timestamp. Use offset pagination only when users need to jump to arbitrary pages (admin tables).
180
+
181
+ ### Soft Delete
182
+
183
+ ```ts
184
+ // Always filter explicitly — do not rely on middleware (hides behavior, hard to debug)
185
+ const activeUsers = await prisma.user.findMany({ where: { deletedAt: null } });
186
+
187
+ await prisma.user.update({ where: { id }, data: { deletedAt: new Date() } });
188
+ await prisma.user.update({ where: { id }, data: { deletedAt: null } }); // restore
189
+ ```
190
+
191
+ ### Error Handling
192
+
193
+ ```ts
194
+ import { Prisma } from '@prisma/client';
195
+
196
+ try {
197
+ await prisma.user.create({ data: { email } });
198
+ } catch (e) {
199
+ if (e instanceof Prisma.PrismaClientKnownRequestError) {
200
+ if (e.code === 'P2002') throw new ConflictError('Email already exists');
201
+ if (e.code === 'P2025') throw new NotFoundError('Record not found');
202
+ if (e.code === 'P2003') throw new BadRequestError('Referenced record does not exist');
203
+ }
204
+ throw e;
205
+ }
206
+ ```
207
+
208
+ Common codes: `P2002` unique violation · `P2025` not found · `P2003` foreign key violation.
209
+
210
+ Catch at the service boundary and translate to domain errors. Never expose raw Prisma messages to API consumers.
211
+
212
+ ### Connection Pool — Serverless
213
+
214
+ Embed connection params directly in `DATABASE_URL` — string concatenation breaks if the URL already has query parameters (e.g. `?schema=public`):
215
+
216
+ ```bash
217
+ # .env — preferred: embed params in the URL
218
+ DATABASE_URL="postgresql://user:pass@host/db?connection_limit=1&pool_timeout=20"
219
+
220
+ # With an external pooler (PgBouncer, Supabase pooler)
221
+ DATABASE_URL="postgresql://user:pass@host/db?pgbouncer=true&connection_limit=1"
222
+ ```
223
+
224
+ ```ts
225
+ // Vercel, AWS Lambda, and similar serverless runtimes: cap pool to 1 per instance
226
+ // connection_limit and pool_timeout are controlled via DATABASE_URL
227
+ const prisma = new PrismaClient();
228
+ ```
229
+
230
+ ## Anti-Patterns
231
+
232
+ ### `updateMany` returns a count, not records
233
+
234
+ ```ts
235
+ // BAD: result is { count: 2 } — users[0] is undefined
236
+ const users = await prisma.user.updateMany({ where: { role: 'GUEST' }, data: { role: 'USER' } });
237
+
238
+ // GOOD: capture IDs first, then update, then fetch only the affected rows
239
+ const targets = await prisma.user.findMany({
240
+ where: { role: 'GUEST' },
241
+ select: { id: true },
242
+ });
243
+ const ids = targets.map((u) => u.id);
244
+ await prisma.user.updateMany({ where: { id: { in: ids } }, data: { role: 'USER' } });
245
+ const updated = await prisma.user.findMany({ where: { id: { in: ids } } });
246
+ ```
247
+
248
+ Same applies to `deleteMany` — returns `{ count: n }`, never the deleted rows.
249
+
250
+ ### `$transaction` interactive form times out after 5 seconds
251
+
252
+ ```ts
253
+ // BAD: external call inside transaction exceeds 5s default → "Transaction already closed"
254
+ await prisma.$transaction(async (tx) => {
255
+ const user = await tx.user.findUniqueOrThrow({ where: { id } });
256
+ await sendWelcomeEmail(user.email); // external call
257
+ await tx.user.update({ where: { id }, data: { emailSent: true } });
258
+ });
259
+
260
+ // GOOD: external calls outside the transaction
261
+ const user = await prisma.user.findUniqueOrThrow({ where: { id } });
262
+ await sendWelcomeEmail(user.email);
263
+ await prisma.user.update({ where: { id }, data: { emailSent: true } });
264
+
265
+ // Only raise timeout when bulk processing genuinely needs it
266
+ await prisma.$transaction(async (tx) => { ... }, { timeout: 30_000 });
267
+ ```
268
+
269
+ ### `migrate dev` can reset the database
270
+
271
+ `migrate dev` detects schema drift and may prompt to reset the DB, dropping all data.
272
+
273
+ ```bash
274
+ # NEVER on shared dev, staging, or production
275
+ npx prisma migrate dev --name add_column
276
+
277
+ # Safe everywhere except local solo dev
278
+ npx prisma migrate deploy
279
+
280
+ # Check drift without applying
281
+ npx prisma migrate diff \
282
+ --from-migrations ./prisma/migrations \
283
+ --to-schema-datamodel ./prisma/schema.prisma \
284
+ --shadow-database-url "$SHADOW_DATABASE_URL"
285
+ ```
286
+
287
+ ### Manually editing a migration file breaks future deploys
288
+
289
+ Prisma checksums every migration file. Editing after apply causes `P3006 checksum mismatch` on every environment where the original already ran. Create a new migration instead.
290
+
291
+ ### Breaking schema changes require multi-step migration
292
+
293
+ Adding `NOT NULL` to an existing column or renaming a column in one migration will lock the table or drop data. Use expand-and-contract:
294
+
295
+ ```bash
296
+ # Step 1: create migration locally, then deploy
297
+ npx prisma migrate dev --name add_new_column # local only
298
+ npx prisma migrate deploy # staging / production
299
+ ```
300
+
301
+ ```ts
302
+ // Step 2: backfill data (run in a script or migration job, not in the shell)
303
+ await prisma.user.updateMany({ data: { newColumn: derivedValue } });
304
+ ```
305
+
306
+ ```bash
307
+ # Step 3: create the NOT NULL constraint migration locally, then deploy
308
+ npx prisma migrate dev --name make_new_column_required # local only
309
+ npx prisma migrate deploy # staging / production
310
+ ```
311
+
312
+ ### `@updatedAt` does not fire on `updateMany`
313
+
314
+ `@updatedAt` is set automatically only on `update` and `upsert`. Bulk writes leave it stale.
315
+
316
+ ```ts
317
+ // BAD: updatedAt stays at its old value
318
+ await prisma.post.updateMany({ where: { authorId }, data: { published: true } });
319
+
320
+ // GOOD
321
+ await prisma.post.updateMany({
322
+ where: { authorId },
323
+ data: { published: true, updatedAt: new Date() },
324
+ });
325
+ ```
326
+
327
+ ### Soft delete + `findUniqueOrThrow` leaks deleted records
328
+
329
+ `findUniqueOrThrow` throws `P2025` only when the row does not exist in the DB. Soft-deleted rows still exist and are returned without error.
330
+
331
+ `findUniqueOrThrow` requires a unique constraint field in `where` — adding `deletedAt: null` alongside `id` breaks the type because `{ id, deletedAt }` is not a compound unique constraint. Use `findFirstOrThrow` instead.
332
+
333
+ ```ts
334
+ // BAD: returns soft-deleted user
335
+ const user = await prisma.user.findUniqueOrThrow({ where: { id } });
336
+
337
+ // BAD: Prisma type error — { id, deletedAt } is not a unique constraint
338
+ const user = await prisma.user.findUniqueOrThrow({ where: { id, deletedAt: null } });
339
+
340
+ // GOOD: findFirstOrThrow supports arbitrary where conditions
341
+ const user = await prisma.user.findFirstOrThrow({ where: { id, deletedAt: null } });
342
+ ```
343
+
344
+ ### `deleteMany` without `where` deletes every row
345
+
346
+ ```ts
347
+ // BAD: silently wipes the table
348
+ await prisma.post.deleteMany();
349
+
350
+ // GOOD
351
+ await prisma.post.deleteMany({ where: { authorId: userId } });
352
+ ```
353
+
354
+ ## Best Practices
355
+
356
+ | Rule | Reason |
357
+ |---|---|
358
+ | `migrate deploy` in CI/CD, `migrate dev` only locally | `migrate dev` can reset the DB on drift |
359
+ | Map entities to response DTOs | Prevents leaking internal fields |
360
+ | Catch `PrismaClientKnownRequestError` at service boundary | Translate to domain errors |
361
+ | Prefer `*OrThrow` methods over manual null checks | Throws P2025 automatically; use `findFirstOrThrow` when filtering non-unique fields |
362
+ | `connection_limit=1` + external pooler in serverless | Prevents connection exhaustion |
363
+ | Always provide `where` on `deleteMany` | Prevents accidental table wipe |
364
+ | Set `updatedAt: new Date()` manually in `updateMany` | `@updatedAt` skips bulk writes |
365
+
366
+ ## Related Skills
367
+
368
+ - `nestjs-patterns` — NestJS service layer that integrates Prisma
369
+ - `postgres-patterns` — PostgreSQL-level indexing and connection tuning
370
+ - `database-migrations` — multi-step migration planning for production
371
+ - `backend-patterns` — general API and service layer design
@@ -0,0 +1,7 @@
1
+ {
2
+ "source": "affaan-m/everything-claude-code",
3
+ "sourceType": "git",
4
+ "repoUrl": "https://github.com/affaan-m/everything-claude-code",
5
+ "subpath": "skills/product-capability",
6
+ "installedAt": "2026-04-16T03:02:31.944Z"
7
+ }
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: product-capability
3
+ description: Translate PRD intent, roadmap asks, or product discussions into an implementation-ready capability plan that exposes constraints, invariants, interfaces, and unresolved decisions before multi-service work starts. Use when the user needs an ECC-native PRD-to-SRS lane instead of vague planning prose.
4
+ origin: ECC
5
+ ---
6
+
7
+ # Product Capability
8
+
9
+ This skill turns product intent into explicit engineering constraints.
10
+
11
+ Use it when the gap is not "what should we build?" but "what exactly must be true before implementation starts?"
12
+
13
+ ## When to Use
14
+
15
+ - A PRD, roadmap item, discussion, or founder note exists, but the implementation constraints are still implicit
16
+ - A feature crosses multiple services, repos, or teams and needs a capability contract before coding
17
+ - Product intent is clear, but architecture, data, lifecycle, or policy implications are still fuzzy
18
+ - Senior engineers keep restating the same hidden assumptions during review
19
+ - You need a reusable artifact that can survive across harnesses and sessions
20
+
21
+ ## Canonical Artifact
22
+
23
+ If the repo has a durable product-context file such as `PRODUCT.md`, `docs/product/`, or a program-spec directory, update it there.
24
+
25
+ If no capability manifest exists yet, create one using the template at:
26
+
27
+ - `docs/examples/product-capability-template.md`
28
+
29
+ The goal is not to create another planning stack. The goal is to make hidden capability constraints durable and reusable.
30
+
31
+ ## Non-Negotiable Rules
32
+
33
+ - Do not invent product truth. Mark unresolved questions explicitly.
34
+ - Separate user-visible promises from implementation details.
35
+ - Call out what is fixed policy, what is architecture preference, and what is still open.
36
+ - If the request conflicts with existing repo constraints, say so clearly instead of smoothing it over.
37
+ - Prefer one reusable capability artifact over scattered ad hoc notes.
38
+
39
+ ## Inputs
40
+
41
+ Read only what is needed:
42
+
43
+ 1. Product intent
44
+ - issue, discussion, PRD, roadmap note, founder message
45
+ 2. Current architecture
46
+ - relevant repo docs, contracts, schemas, routes, existing workflows
47
+ 3. Existing capability context
48
+ - `PRODUCT.md`, design docs, RFCs, migration notes, operating-model docs
49
+ 4. Delivery constraints
50
+ - auth, billing, compliance, rollout, backwards compatibility, performance, review policy
51
+
52
+ ## Core Workflow
53
+
54
+ ### 1. Restate the capability
55
+
56
+ Compress the ask into one precise statement:
57
+
58
+ - who the user or operator is
59
+ - what new capability exists after this ships
60
+ - what outcome changes because of it
61
+
62
+ If this statement is weak, the implementation will drift.
63
+
64
+ ### 2. Resolve capability constraints
65
+
66
+ Extract the constraints that must hold before implementation:
67
+
68
+ - business rules
69
+ - scope boundaries
70
+ - invariants
71
+ - trust boundaries
72
+ - data ownership
73
+ - lifecycle transitions
74
+ - rollout / migration requirements
75
+ - failure and recovery expectations
76
+
77
+ These are the things that often live only in senior-engineer memory.
78
+
79
+ ### 3. Define the implementation-facing contract
80
+
81
+ Produce an SRS-style capability plan with:
82
+
83
+ - capability summary
84
+ - explicit non-goals
85
+ - actors and surfaces
86
+ - required states and transitions
87
+ - interfaces / inputs / outputs
88
+ - data model implications
89
+ - security / billing / policy constraints
90
+ - observability and operator requirements
91
+ - open questions blocking implementation
92
+
93
+ ### 4. Translate into execution
94
+
95
+ End with the exact handoff:
96
+
97
+ - ready for direct implementation
98
+ - needs architecture review first
99
+ - needs product clarification first
100
+
101
+ If useful, point to the next ECC-native lane:
102
+
103
+ - `project-flow-ops`
104
+ - `workspace-surface-audit`
105
+ - `api-connector-builder`
106
+ - `dashboard-builder`
107
+ - `tdd-workflow`
108
+ - `verification-loop`
109
+
110
+ ## Output Format
111
+
112
+ Return the result in this order:
113
+
114
+ ```text
115
+ CAPABILITY
116
+ - one-paragraph restatement
117
+
118
+ CONSTRAINTS
119
+ - fixed rules, invariants, and boundaries
120
+
121
+ IMPLEMENTATION CONTRACT
122
+ - actors
123
+ - surfaces
124
+ - states and transitions
125
+ - interface/data implications
126
+
127
+ NON-GOALS
128
+ - what this lane explicitly does not own
129
+
130
+ OPEN QUESTIONS
131
+ - blockers or product decisions still required
132
+
133
+ HANDOFF
134
+ - what should happen next and which ECC lane should take it
135
+ ```
136
+
137
+ ## Good Outcomes
138
+
139
+ - Product intent is now concrete enough to implement without rediscovering hidden constraints mid-PR.
140
+ - Engineering review has a durable artifact instead of relying on memory or Slack context.
141
+ - The resulting plan is reusable across Claude Code, Codex, Cursor, OpenCode, and ECC 2.0 planning surfaces.
@@ -0,0 +1,7 @@
1
+ {
2
+ "source": "affaan-m/everything-claude-code",
3
+ "sourceType": "git",
4
+ "repoUrl": "https://github.com/affaan-m/everything-claude-code",
5
+ "subpath": "skills/product-lens",
6
+ "installedAt": "2026-04-16T03:02:31.944Z"
7
+ }
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: product-lens
3
+ description: Use this skill to validate the "why" before building, run product diagnostics, and pressure-test product direction before the request becomes an implementation contract.
4
+ origin: ECC
5
+ ---
6
+
7
+ # Product Lens — Think Before You Build
8
+
9
+ This lane owns product diagnosis, not implementation-ready specification writing.
10
+
11
+ If the user needs a durable PRD-to-SRS or capability-contract artifact, hand off to `product-capability`.
12
+
13
+ ## When to Use
14
+
15
+ - Before starting any feature — validate the "why"
16
+ - Weekly product review — are we building the right thing?
17
+ - When stuck choosing between features
18
+ - Before a launch — sanity check the user journey
19
+ - When converting a vague idea into a product brief before engineering planning starts
20
+
21
+ ## How It Works
22
+
23
+ ### Mode 1: Product Diagnostic
24
+
25
+ Like YC office hours but automated. Asks the hard questions:
26
+
27
+ ```
28
+ 1. Who is this for? (specific person, not "developers")
29
+ 2. What's the pain? (quantify: how often, how bad, what do they do today?)
30
+ 3. Why now? (what changed that makes this possible/necessary?)
31
+ 4. What's the 10-star version? (if money/time were unlimited)
32
+ 5. What's the MVP? (smallest thing that proves the thesis)
33
+ 6. What's the anti-goal? (what are you explicitly NOT building?)
34
+ 7. How do you know it's working? (metric, not vibes)
35
+ ```
36
+
37
+ Output: a `PRODUCT-BRIEF.md` with answers, risks, and a go/no-go recommendation.
38
+
39
+ If the result is "yes, build this," the next lane is `product-capability`, not more founder-theater.
40
+
41
+ ### Mode 2: Founder Review
42
+
43
+ Reviews your current project through a founder lens:
44
+
45
+ ```
46
+ 1. Read README, CLAUDE.md, package.json, recent commits
47
+ 2. Infer: what is this trying to be?
48
+ 3. Score: product-market fit signals (0-10)
49
+ - Usage growth trajectory
50
+ - Retention indicators (repeat contributors, return users)
51
+ - Revenue signals (pricing page, billing code, Stripe integration)
52
+ - Competitive moat (what's hard to copy?)
53
+ 4. Identify: the one thing that would 10x this
54
+ 5. Flag: things you're building that don't matter
55
+ ```
56
+
57
+ ### Mode 3: User Journey Audit
58
+
59
+ Maps the actual user experience:
60
+
61
+ ```
62
+ 1. Clone/install the product as a new user
63
+ 2. Document every friction point (confusing steps, errors, missing docs)
64
+ 3. Time each step
65
+ 4. Compare to competitor onboarding
66
+ 5. Score: time-to-value (how long until the user gets their first win?)
67
+ 6. Recommend: top 3 fixes for onboarding
68
+ ```
69
+
70
+ ### Mode 4: Feature Prioritization
71
+
72
+ When you have 10 ideas and need to pick 2:
73
+
74
+ ```
75
+ 1. List all candidate features
76
+ 2. Score each on: impact (1-5) × confidence (1-5) ÷ effort (1-5)
77
+ 3. Rank by ICE score
78
+ 4. Apply constraints: runway, team size, dependencies
79
+ 5. Output: prioritized roadmap with rationale
80
+ ```
81
+
82
+ ## Output
83
+
84
+ All modes output actionable docs, not essays. Every recommendation has a specific next step.
85
+
86
+ ## Integration
87
+
88
+ Pair with:
89
+ - `/browser-qa` to verify the user journey audit findings
90
+ - `/design-system audit` for visual polish assessment
91
+ - `/canary-watch` for post-launch monitoring
92
+ - `product-capability` when the product brief needs to become an implementation-ready capability plan