vibes-plug 1.0.0 → 2.11.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 (183) hide show
  1. package/.claude/rules/vibes-plug-core.md +32 -0
  2. package/.cursor/rules/vibes-plug-core.mdc +51 -0
  3. package/.cursorrules +42 -0
  4. package/AGENTS.md +96 -0
  5. package/BLUEPRINT.md +309 -125
  6. package/CHANGELOG.md +183 -1
  7. package/CLAUDE.md +70 -0
  8. package/LICENSE +1 -1
  9. package/README.md +641 -263
  10. package/index.js +19 -0
  11. package/package.json +61 -25
  12. package/plugin.json +24 -7
  13. package/scripts/generate_swarm_gif.py +295 -0
  14. package/scripts/install.js +201 -0
  15. package/skills/accessibility-testing-expert/SKILL.md +116 -0
  16. package/skills/ai-cost-token-optimizer/SKILL.md +82 -0
  17. package/skills/ai-evals-benchmark-expert/SKILL.md +188 -0
  18. package/skills/ai-llm-integration-expert/SKILL.md +147 -122
  19. package/skills/ai-media-generation-expert/SKILL.md +172 -0
  20. package/skills/ai-prompt-engineering-expert/SKILL.md +84 -0
  21. package/skills/angular-expert/SKILL.md +148 -0
  22. package/skills/api-design-expert/SKILL.md +316 -309
  23. package/skills/api-gateway-proxy-expert/SKILL.md +81 -0
  24. package/skills/app-analyzer-optimizer/SKILL.md +195 -188
  25. package/skills/apple-ecosystem-expert/SKILL.md +145 -0
  26. package/skills/{asisten_ramah → asisten-ramah}/SKILL.md +7 -1
  27. package/skills/astro-framework-expert/SKILL.md +200 -0
  28. package/skills/async-queue-temporal-expert/SKILL.md +240 -0
  29. package/skills/authentication-identity-expert/SKILL.md +279 -45
  30. package/skills/auto-doc-updater/SKILL.md +219 -203
  31. package/skills/autonomous-chaos-monkey/SKILL.md +63 -0
  32. package/skills/autonomous-red-teamer/SKILL.md +203 -0
  33. package/skills/autonomous-tdd-debugger/SKILL.md +71 -0
  34. package/skills/background-jobs-queue-expert/SKILL.md +235 -0
  35. package/skills/biome-linter-formatter-expert/SKILL.md +89 -0
  36. package/skills/blockchain-web3-expert/SKILL.md +115 -0
  37. package/skills/bootstrap-to-modern/SKILL.md +93 -86
  38. package/skills/brainstorming/SKILL.md +381 -353
  39. package/skills/browser-automation-expert/SKILL.md +222 -0
  40. package/skills/bun-runtime-expert/SKILL.md +7 -1
  41. package/skills/chatbot-messaging-expert/SKILL.md +114 -0
  42. package/skills/ci-cd-devops-architect/SKILL.md +81 -45
  43. package/skills/cloud-hosting-expert/SKILL.md +249 -243
  44. package/skills/coderabbit/SKILL.md +197 -191
  45. package/skills/compliance-gdpr-privacy-expert/SKILL.md +85 -0
  46. package/skills/cron-scheduler-expert/SKILL.md +304 -0
  47. package/skills/data-pipeline-etl-expert/SKILL.md +84 -0
  48. package/skills/data-telemetry-expert/SKILL.md +218 -212
  49. package/skills/data-visualization-expert/SKILL.md +154 -0
  50. package/skills/database-migration-versioning-expert/SKILL.md +90 -0
  51. package/skills/database-orm-expert/SKILL.md +303 -293
  52. package/skills/dependency-upgrade-migrator/SKILL.md +301 -0
  53. package/skills/design-system-architect/SKILL.md +278 -242
  54. package/skills/desktop-electron-expert/SKILL.md +128 -0
  55. package/skills/documentation-site-expert/SKILL.md +59 -0
  56. package/skills/doku-mcp-server/SKILL.md +257 -0
  57. package/skills/doku-payment-gateway/SKILL.md +233 -0
  58. package/skills/domain-driven-design-expert/SKILL.md +82 -0
  59. package/skills/e2e-testing-expert/SKILL.md +320 -314
  60. package/skills/ecommerce-expert/SKILL.md +87 -0
  61. package/skills/edge-serverless-db-expert/SKILL.md +99 -0
  62. package/skills/email-notification-expert/SKILL.md +368 -0
  63. package/skills/error-resilience-expert/SKILL.md +486 -0
  64. package/skills/event-driven-architect/SKILL.md +86 -80
  65. package/skills/feature-flag-analytics-expert/SKILL.md +66 -0
  66. package/skills/file-upload-media-expert/SKILL.md +437 -0
  67. package/skills/firebase-security-expert/SKILL.md +7 -1
  68. package/skills/form-validation-expert/SKILL.md +407 -0
  69. package/skills/fullstack-expert/SKILL.md +260 -201
  70. package/skills/fullstack-expert/references/api_design_guide.md +466 -466
  71. package/skills/fullstack-expert/references/multi_language_backend.md +528 -528
  72. package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -253
  73. package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -326
  74. package/skills/gemini-agent-booster/SKILL.md +142 -104
  75. package/skills/geospatial-maps-expert/SKILL.md +80 -0
  76. package/skills/global-a11y-i18n-expert/SKILL.md +86 -80
  77. package/skills/glsl-shader-expert/SKILL.md +107 -0
  78. package/skills/go-programming-expert/SKILL.md +300 -294
  79. package/skills/graph-rag-knowledge-expert/SKILL.md +159 -0
  80. package/skills/graphql-apollo-expert/SKILL.md +114 -0
  81. package/skills/headless-cms-expert/SKILL.md +181 -0
  82. package/skills/hig/SKILL.md +193 -187
  83. package/skills/js-backend-expert/SKILL.md +218 -191
  84. package/skills/legacy-code-translator/SKILL.md +71 -0
  85. package/skills/local-slm-edge-ai-expert/SKILL.md +167 -0
  86. package/skills/logging-error-tracking-expert/SKILL.md +344 -0
  87. package/skills/mcp-client-orchestrator/SKILL.md +76 -0
  88. package/skills/mcp-server-architect/SKILL.md +226 -126
  89. package/skills/micro-frontend-architect/SKILL.md +112 -0
  90. package/skills/mobile-expo-expert/SKILL.md +191 -185
  91. package/skills/mobile-push-notification-expert/SKILL.md +71 -0
  92. package/skills/modern-css-native-expert/SKILL.md +189 -0
  93. package/skills/monday-design-aesthetic/SKILL.md +72 -66
  94. package/skills/monorepo-architect/SKILL.md +232 -226
  95. package/skills/mpa-orchestrator/SKILL.md +120 -101
  96. package/skills/multi-agent-orchestration/SKILL.md +173 -153
  97. package/skills/multiple-entry-points/SKILL.md +91 -55
  98. package/skills/mvc-expert/SKILL.md +237 -231
  99. package/skills/n8n-automation-expert/SKILL.md +89 -0
  100. package/skills/nextjs-app-router-expert/SKILL.md +148 -0
  101. package/skills/openapi-swagger-codegen-expert/SKILL.md +67 -0
  102. package/skills/payment-gateway-expert/SKILL.md +129 -45
  103. package/skills/pdf-document-generation-expert/SKILL.md +91 -0
  104. package/skills/performance-web-vitals/SKILL.md +337 -331
  105. package/skills/post-quantum-crypto-migrator/SKILL.md +57 -0
  106. package/skills/prd-architect/SKILL.md +206 -190
  107. package/skills/proactive-background-watcher/SKILL.md +68 -0
  108. package/skills/production-ready-hardener/PRODUCTION_READINESS_REPORT.md +67 -0
  109. package/skills/production-ready-hardener/SKILL.md +461 -468
  110. package/skills/production-ready-hardener/references/production_checklist.md +161 -161
  111. package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +881 -875
  112. package/skills/project-context-mapper/SKILL.md +85 -0
  113. package/skills/pwa-offline-first-expert/SKILL.md +185 -0
  114. package/skills/python-programming-expert/SKILL.md +407 -270
  115. package/skills/rate-limit-abuse-prevention/SKILL.md +377 -0
  116. package/skills/realtime-collaboration-expert/SKILL.md +99 -45
  117. package/skills/rich-text-editor-expert/SKILL.md +177 -0
  118. package/skills/rust-programming-expert/SKILL.md +240 -234
  119. package/skills/saas-billing/SKILL.md +382 -376
  120. package/skills/saas-multi-tenant/SKILL.md +256 -236
  121. package/skills/saas-mvp-launcher/SKILL.md +30 -1
  122. package/skills/saas-transformer/SKILL.md +499 -445
  123. package/skills/saas-transformer/references/billing_integration_guide.md +401 -401
  124. package/skills/saas-transformer/references/feature_gating_patterns.md +137 -137
  125. package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -121
  126. package/skills/saas-transformer/scripts/saas_transformation_scanner.py +39 -29
  127. package/skills/scalability-clean-code/SKILL.md +234 -228
  128. package/skills/search-engine-expert/SKILL.md +89 -0
  129. package/skills/secure-fuzz-testing/SKILL.md +7 -1
  130. package/skills/self-evolving-memory-graph/SKILL.md +91 -0
  131. package/skills/self-healing-cloud-orchestrator/SKILL.md +57 -0
  132. package/skills/senior-frontend/SKILL.md +85 -105
  133. package/skills/seo/SKILL.md +258 -224
  134. package/skills/session-context-loader/SKILL.md +83 -0
  135. package/skills/session-handoff-resume/SKILL.md +163 -157
  136. package/skills/{skill_baru → skill-baru}/SKILL.md +177 -146
  137. package/skills/solidjs-expert/SKILL.md +80 -0
  138. package/skills/spa-orchestrator/SKILL.md +306 -287
  139. package/skills/sse-websocket-streaming-expert/SKILL.md +93 -0
  140. package/skills/state-management-expert/SKILL.md +277 -271
  141. package/skills/supabase-migration/SKILL.md +47 -1
  142. package/skills/supabase-security-expert/SKILL.md +248 -242
  143. package/skills/svelte-sveltekit-expert/SKILL.md +91 -0
  144. package/skills/svg-animation-motion-expert/SKILL.md +115 -0
  145. package/skills/tailwind-expert/SKILL.md +139 -187
  146. package/skills/tanstack-query-expert/SKILL.md +204 -198
  147. package/skills/tauri-expert/SKILL.md +7 -1
  148. package/skills/token-saver/SKILL.md +118 -110
  149. package/skills/typescript-expert/SKILL.md +329 -278
  150. package/skills/ui-components-expert/SKILL.md +166 -63
  151. package/skills/ui-ux-pro-max/SKILL.md +221 -200
  152. package/skills/vector-db-rag-expert/SKILL.md +208 -0
  153. package/skills/vibe-code-gardener/SKILL.md +180 -172
  154. package/skills/visual-qa-vision-agent/SKILL.md +71 -0
  155. package/skills/voice-ai-realtime-agent/SKILL.md +202 -0
  156. package/skills/vue-frontend-expert/SKILL.md +132 -0
  157. package/skills/wasm-edge-computing-expert/SKILL.md +97 -0
  158. package/skills/web-3d-graphics-expert/SKILL.md +137 -0
  159. package/skills/web-game-engine-expert/SKILL.md +102 -0
  160. package/skills/web-scraper/SKILL.md +98 -146
  161. package/skills/website-design-cloner/SKILL.md +180 -0
  162. package/skills/webxr-ar-vr-expert/SKILL.md +123 -0
  163. package/skills/wordpress-headless-expert/SKILL.md +144 -0
  164. package/skills/zero-to-prod-orchestrator/SKILL.md +231 -180
  165. package/skills/zero-trust-secret-vault/SKILL.md +88 -0
  166. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  167. package/CONTRIBUTING.md +0 -199
  168. package/SECURITY.md +0 -21
  169. package/banner.png +0 -0
  170. package/skills/senior-fullstack/SKILL.md +0 -167
  171. package/skills/senior-fullstack/references/architecture_patterns.md +0 -160
  172. package/skills/senior-fullstack/references/development_workflows.md +0 -222
  173. package/skills/senior-fullstack/references/tech_stack_guide.md +0 -190
  174. package/skills/senior-fullstack/scripts/code_quality_analyzer.py +0 -114
  175. package/skills/senior-fullstack/scripts/fullstack_scaffolder.py +0 -114
  176. package/skills/senior-fullstack/scripts/project_scaffolder.py +0 -114
  177. package/skills/seo-aeo-landing-page-writer/SKILL.md +0 -97
  178. package/skills/seo-geo/SKILL.md +0 -188
  179. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
  180. package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
  181. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
  182. package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
  183. package/skills/ui_ux_expert/SKILL.md +0 -114
@@ -1,294 +1,304 @@
1
- ---
2
- name: database-orm-expert
3
- description: "Expert guide for database schema design, ORM tools (Prisma 6, Drizzle ORM, TypeORM), migrations, query optimization, and type-safe SQL patterns in TypeScript / Panduan ahli untuk desain skema database, ORM tools (Prisma 6, Drizzle ORM, TypeORM), migrasi, optimasi query, dan pola SQL type-safe di TypeScript."
1
+ ---
2
+ name: database-orm-expert
3
+ description: "Expert guide for database schema design, ORM tools (Prisma 6, Drizzle ORM, TypeORM), migrations, query optimization, and type-safe SQL patterns in TypeScript / Panduan ahli untuk desain skema database, ORM tools (Prisma 6, Drizzle ORM, TypeORM), migrasi, optimasi query, dan pola SQL type-safe di TypeScript."
4
4
  author: "Roedy Rustam"
5
- ---
6
-
7
- # Database ORM Expert (Prisma 6 + Drizzle ORM Edition)
8
-
9
- [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
10
-
11
- ---
12
-
13
- <a name="english"></a>
14
- ## English
15
-
16
- ### Description
17
- Expert-level database development covering schema design, ORM selection, migrations, query optimization, and type-safe SQL patterns. Focuses on **Prisma 6** and **Drizzle ORM** as primary modern ORMs, with coverage of TypeORM, raw SQL via `postgres.js`, and connection pooling strategies for production workloads.
18
-
19
- ### Trigger Conditions
20
- - Designing or migrating a database schema.
21
- - Choosing between Prisma, Drizzle ORM, or TypeORM.
22
- - Writing complex queries with joins, aggregations, or pagination.
23
- - Optimizing slow queries or N+1 problems.
24
- - Setting up database migrations in CI/CD pipelines.
25
- - Implementing Row Level Security (RLS) patterns.
26
- - Working with PostgreSQL, MySQL, SQLite, or PlanetScale.
27
-
28
- ---
29
-
30
- ### ORM Selection Guide
31
-
32
- | Criteria | Prisma 6 | Drizzle ORM | TypeORM |
33
- |---|---|---|---|
34
- | **Type Safety** | Schema-generated types | SQL-like, inferred types | Decorator-based |
35
- | **Bundle Size** | Heavy (binary client) | Lightweight (<35KB) | Medium |
36
- | **Query Style** | Fluent ORM API | SQL-first, composable | ActiveRecord / QueryBuilder |
37
- | **Edge Runtime** | Prisma Accelerate needed | Native edge support | No |
38
- | **Migrations** | `prisma migrate dev` | `drizzle-kit push/migrate` | `synchronize` (dev only) |
39
- | **Best For** | Rapid prototyping, teams | Production edge, monorepos | Legacy NestJS projects |
40
-
41
- **Recommendation**: Use **Drizzle ORM** for edge-compatible apps and performance-critical systems. Use **Prisma 6** for teams that prefer a schema-first DX and rich Studio tooling.
42
-
43
- ---
44
-
45
- ### Prisma 6 — Best Practices
46
-
47
- #### Schema Design
48
- ```prisma
49
- // schema.prisma
50
- generator client {
51
- provider = "prisma-client-js"
52
- previewFeatures = ["relationJoins", "nativeDistinct"]
53
- }
54
-
55
- datasource db {
56
- provider = "postgresql"
57
- url = env("DATABASE_URL")
58
- directUrl = env("DIRECT_URL") // for Supabase Pooler
59
- }
60
-
61
- model User {
62
- id String @id @default(cuid())
63
- email String @unique
64
- name String?
65
- role Role @default(USER)
66
- posts Post[]
67
- createdAt DateTime @default(now())
68
- updatedAt DateTime @updatedAt
69
-
70
- @@index([email])
71
- @@map("users")
72
- }
73
-
74
- model Post {
75
- id String @id @default(cuid())
76
- title String
77
- content String?
78
- published Boolean @default(false)
79
- authorId String
80
- author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
81
- publishedAt DateTime?
82
-
83
- @@index([authorId, published])
84
- @@map("posts")
85
- }
86
-
87
- enum Role {
88
- USER
89
- ADMIN
90
- SUPER_ADMIN
91
- }
92
- ```
93
-
94
- #### Avoiding N+1 with `include` vs `select`
95
- ```typescript
96
- // BAD: triggers N+1 queries
97
- const users = await prisma.user.findMany();
98
- for (const user of users) {
99
- const posts = await prisma.post.findMany({ where: { authorId: user.id } });
100
- }
101
-
102
- // GOOD: single query with JOIN (Prisma 5.7+ relationJoins preview)
103
- const users = await prisma.user.findMany({
104
- select: {
105
- id: true,
106
- name: true,
107
- email: true,
108
- _count: { select: { posts: true } },
109
- posts: {
110
- where: { published: true },
111
- select: { id: true, title: true },
112
- take: 5,
113
- orderBy: { publishedAt: 'desc' },
114
- },
115
- },
116
- });
117
- ```
118
-
119
- #### Optimistic Transactions
120
- ```typescript
121
- // Use $transaction for atomic operations
122
- const [updatedUser, newPost] = await prisma.$transaction([
123
- prisma.user.update({ where: { id }, data: { name } }),
124
- prisma.post.create({ data: { title, authorId: id } }),
125
- ]);
126
-
127
- // Interactive transaction for complex logic
128
- const result = await prisma.$transaction(async (tx) => {
129
- const user = await tx.user.findUniqueOrThrow({ where: { id } });
130
- if (user.role !== 'ADMIN') throw new Error('Unauthorized');
131
- return tx.post.updateMany({ where: { authorId: id }, data: { published: true } });
132
- });
133
- ```
134
-
135
- ---
136
-
137
- ### Drizzle ORM — Best Practices
138
-
139
- #### Schema Definition (PostgreSQL)
140
- ```typescript
141
- // src/db/schema.ts
142
- import { pgTable, text, boolean, timestamp, pgEnum, index } from 'drizzle-orm/pg-core';
143
- import { createId } from '@paralleldrive/cuid2';
144
- import { relations } from 'drizzle-orm';
145
-
146
- export const roleEnum = pgEnum('role', ['USER', 'ADMIN', 'SUPER_ADMIN']);
147
-
148
- export const users = pgTable('users', {
149
- id: text('id').primaryKey().$defaultFn(() => createId()),
150
- email: text('email').notNull().unique(),
151
- name: text('name'),
152
- role: roleEnum('role').default('USER').notNull(),
153
- createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
154
- updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull().$onUpdateFn(() => new Date()),
155
- }, (t) => [
156
- index('users_email_idx').on(t.email),
157
- ]);
158
-
159
- export const posts = pgTable('posts', {
160
- id: text('id').primaryKey().$defaultFn(() => createId()),
161
- title: text('title').notNull(),
162
- content: text('content'),
163
- published: boolean('published').default(false).notNull(),
164
- authorId: text('author_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
165
- publishedAt: timestamp('published_at', { withTimezone: true }),
166
- }, (t) => [
167
- index('posts_author_published_idx').on(t.authorId, t.published),
168
- ]);
169
-
170
- export const usersRelations = relations(users, ({ many }) => ({
171
- posts: many(posts),
172
- }));
173
-
174
- export const postsRelations = relations(posts, ({ one }) => ({
175
- author: one(users, { fields: [posts.authorId], references: [users.id] }),
176
- }));
177
- ```
178
-
179
- #### Type-safe Queries with Drizzle
180
- ```typescript
181
- // src/db/index.ts
182
- import { drizzle } from 'drizzle-orm/postgres-js';
183
- import postgres from 'postgres';
184
- import * as schema from './schema';
185
-
186
- const client = postgres(process.env.DATABASE_URL!);
187
- export const db = drizzle(client, { schema });
188
-
189
- // Type-safe query with joins
190
- import { eq, and, desc, count } from 'drizzle-orm';
191
-
192
- const usersWithPosts = await db.query.users.findMany({
193
- with: {
194
- posts: {
195
- where: eq(posts.published, true),
196
- orderBy: desc(posts.publishedAt),
197
- limit: 5,
198
- },
199
- },
200
- extras: {
201
- postCount: db.$count(posts, eq(posts.authorId, users.id)).as('post_count'),
202
- },
203
- });
204
-
205
- // Paginated query
206
- async function getPaginatedPosts(page: number, pageSize = 20) {
207
- const offset = (page - 1) * pageSize;
208
- const [items, [{ total }]] = await Promise.all([
209
- db.select().from(posts).where(eq(posts.published, true))
210
- .orderBy(desc(posts.publishedAt))
211
- .limit(pageSize)
212
- .offset(offset),
213
- db.select({ total: count() }).from(posts).where(eq(posts.published, true)),
214
- ]);
215
- return { items, total, pages: Math.ceil(total / pageSize) };
216
- }
217
- ```
218
-
219
- #### Drizzle Migration Workflow
220
- ```bash
221
- # drizzle.config.ts defines connection + schema path
222
- npx drizzle-kit generate # generate migration SQL files
223
- npx drizzle-kit migrate # apply migrations to database
224
- npx drizzle-kit push # push schema directly (dev only)
225
- npx drizzle-kit studio # open Drizzle Studio GUI
226
- ```
227
-
228
- ---
229
-
230
- ### Query Optimization Principles
231
-
232
- 1. **Always index foreign keys** and columns used in `WHERE`, `ORDER BY`, and `JOIN`.
233
- 2. **Use `EXPLAIN ANALYZE`** to detect sequential scans and missing indexes.
234
- 3. **Cursor-based pagination** over offset for large datasets:
235
- ```typescript
236
- // Cursor pagination with Drizzle
237
- const items = await db.select().from(posts)
238
- .where(cursor ? lt(posts.createdAt, cursor) : undefined)
239
- .orderBy(desc(posts.createdAt))
240
- .limit(pageSize);
241
- ```
242
- 4. **Connection pooling**: Use PgBouncer or Supabase's built-in pooler. Set `DIRECT_URL` for migrations and `DATABASE_URL` for pooled reads/writes.
243
- 5. **Avoid `SELECT *`**: Always select only the columns you need.
244
- 6. **Batch inserts**: Use `db.insert(table).values([...items])` instead of looping.
245
-
246
- ---
247
-
248
- ### Migration Best Practices
249
-
250
- - **Never use `synchronize: true`** in production (TypeORM).
251
- - **Never run `prisma db push`** in production — always use `prisma migrate deploy`.
252
- - Store migration files in version control.
253
- - Run migrations as a separate step before deploying new app versions.
254
- - Use **advisory locks** or migration tools to prevent concurrent migration runs.
255
-
256
- ---
257
-
258
- <a name="bahasa-indonesia"></a>
259
- ## Bahasa Indonesia
260
-
261
- ### Deskripsi
262
- Panduan pengembangan database level ahli mencakup desain skema, pemilihan ORM, migrasi, optimasi query, dan pola SQL type-safe. Berfokus pada **Prisma 6** dan **Drizzle ORM** sebagai ORM modern utama, dengan cakupan TypeORM, SQL mentah via `postgres.js`, dan strategi connection pooling untuk beban kerja produksi.
263
-
264
- ### Kondisi Pemicu
265
- - Merancang atau memigrasikan skema database.
266
- - Memilih antara Prisma, Drizzle ORM, atau TypeORM.
267
- - Menulis query kompleks dengan join, agregasi, atau paginasi.
268
- - Mengoptimalkan query lambat atau masalah N+1.
269
- - Menyiapkan migrasi database dalam pipeline CI/CD.
270
- - Mengimplementasikan pola Row Level Security (RLS).
271
- - Bekerja dengan PostgreSQL, MySQL, SQLite, atau PlanetScale.
272
-
273
- ### Panduan Pemilihan ORM
274
-
275
- Gunakan tabel di atas (lihat bagian English) sebagai referensi pemilihan ORM. Rekomendasi singkat:
276
- - **Drizzle ORM**: Untuk aplikasi edge-compatible dan sistem kritis performa.
277
- - **Prisma 6**: Untuk tim yang lebih menyukai DX schema-first dan tooling Studio yang kaya.
278
- - **TypeORM**: Hanya untuk proyek lama (legacy) berbasis NestJS.
279
-
280
- ### Prinsip Utama
281
-
282
- 1. **Selalu index foreign key** dan kolom yang digunakan di `WHERE`, `ORDER BY`, dan `JOIN`.
283
- 2. **Gunakan `EXPLAIN ANALYZE`** untuk mendeteksi sequential scan dan index yang hilang.
284
- 3. **Cursor-based pagination** lebih baik dari offset untuk dataset besar.
285
- 4. **Connection pooling**: Gunakan PgBouncer atau Supabase pooler bawaan.
286
- 5. **Hindari `SELECT *`**: Selalu pilih hanya kolom yang dibutuhkan.
287
- 6. **Batch insert**: Gunakan insert massal, bukan looping satu per satu.
288
-
289
- ### Prinsip Migrasi
290
-
291
- - Jangan gunakan `synchronize: true` di produksi (TypeORM).
292
- - Jangan jalankan `prisma db push` di produksi selalu gunakan `prisma migrate deploy`.
293
- - Simpan file migrasi di version control.
294
- - Jalankan migrasi sebagai langkah terpisah sebelum deploy versi aplikasi baru.
5
+ ---
6
+
7
+ # Database ORM Expert (Prisma 6 + Drizzle ORM Edition)
8
+
9
+ [English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
10
+
11
+ ---
12
+
13
+ <a name="english"></a>
14
+ ## English
15
+
16
+ ### Description
17
+ Design schemas, select ORMs, execute migrations, optimize queries, and implement type-safe SQL patterns. Prioritize **Prisma 6** and **Drizzle ORM**. Implement connection pooling for production workloads.
18
+
19
+ ### Trigger Conditions
20
+ - Designing or migrating a database schema.
21
+ - Choosing between Prisma, Drizzle ORM, or TypeORM.
22
+ - Writing complex queries with joins, aggregations, or pagination.
23
+ - Optimizing slow queries or N+1 problems.
24
+ - Setting up database migrations in CI/CD pipelines.
25
+ - Implementing Row Level Security (RLS) patterns.
26
+ - Working with PostgreSQL, MySQL, SQLite, or PlanetScale.
27
+
28
+ ## Orchestration & Integration
29
+ - `js-backend-expert`: For Node/Bun/Deno backend implementations integrating these ORMs.
30
+ - `edge-serverless-db-expert`: For edge/serverless connections (e.g., Supabase, Neon, Turso).
31
+ - `database-migration-versioning-expert`: For advanced migration strategies and CI/CD pipelines.
32
+
33
+ ---
34
+
35
+ ### ORM Selection Guide
36
+
37
+ | Criteria | Prisma 6 | Drizzle ORM | TypeORM |
38
+ |---|---|---|---|
39
+ | **Type Safety** | Schema-generated types | SQL-like, inferred types | Decorator-based |
40
+ | **Bundle Size** | Heavy (binary client) | Lightweight (<35KB) | Medium |
41
+ | **Query Style** | Fluent ORM API | SQL-first, composable | ActiveRecord / QueryBuilder |
42
+ | **Edge Runtime** | Prisma Accelerate needed | Native edge support | No |
43
+ | **Migrations** | `prisma migrate dev` | `drizzle-kit push/migrate` | `synchronize` (dev only) |
44
+ | **Best For** | Rapid prototyping, teams | Production edge, monorepos | Legacy NestJS projects |
45
+
46
+ **Recommendation**: Use **Drizzle ORM** for edge-compatible apps and performance-critical systems. Use **Prisma 6** for teams that prefer a schema-first DX and rich Studio tooling.
47
+
48
+ ---
49
+
50
+ ### Prisma 6 — Best Practices
51
+
52
+ #### Schema Design
53
+ ```prisma
54
+ // schema.prisma
55
+ generator client {
56
+ provider = "prisma-client-js"
57
+ previewFeatures = ["relationJoins", "nativeDistinct"]
58
+ }
59
+
60
+ datasource db {
61
+ provider = "postgresql"
62
+ url = env("DATABASE_URL")
63
+ directUrl = env("DIRECT_URL") // for Supabase Pooler
64
+ }
65
+
66
+ model User {
67
+ id String @id @default(cuid())
68
+ email String @unique
69
+ name String?
70
+ role Role @default(USER)
71
+ posts Post[]
72
+ createdAt DateTime @default(now())
73
+ updatedAt DateTime @updatedAt
74
+
75
+ @@index([email])
76
+ @@map("users")
77
+ }
78
+
79
+ model Post {
80
+ id String @id @default(cuid())
81
+ title String
82
+ content String?
83
+ published Boolean @default(false)
84
+ authorId String
85
+ author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
86
+ publishedAt DateTime?
87
+
88
+ @@index([authorId, published])
89
+ @@map("posts")
90
+ }
91
+
92
+ enum Role {
93
+ USER
94
+ ADMIN
95
+ SUPER_ADMIN
96
+ }
97
+ ```
98
+
99
+ #### Avoiding N+1 with `include` vs `select`
100
+ ```typescript
101
+ // BAD: triggers N+1 queries
102
+ const users = await prisma.user.findMany();
103
+ for (const user of users) {
104
+ const posts = await prisma.post.findMany({ where: { authorId: user.id } });
105
+ }
106
+
107
+ // GOOD: single query with JOIN (Prisma 5.7+ relationJoins preview)
108
+ const users = await prisma.user.findMany({
109
+ select: {
110
+ id: true,
111
+ name: true,
112
+ email: true,
113
+ _count: { select: { posts: true } },
114
+ posts: {
115
+ where: { published: true },
116
+ select: { id: true, title: true },
117
+ take: 5,
118
+ orderBy: { publishedAt: 'desc' },
119
+ },
120
+ },
121
+ });
122
+ ```
123
+
124
+ #### Optimistic Transactions
125
+ ```typescript
126
+ // Use $transaction for atomic operations
127
+ const [updatedUser, newPost] = await prisma.$transaction([
128
+ prisma.user.update({ where: { id }, data: { name } }),
129
+ prisma.post.create({ data: { title, authorId: id } }),
130
+ ]);
131
+
132
+ // Interactive transaction for complex logic
133
+ const result = await prisma.$transaction(async (tx) => {
134
+ const user = await tx.user.findUniqueOrThrow({ where: { id } });
135
+ if (user.role !== 'ADMIN') throw new Error('Unauthorized');
136
+ return tx.post.updateMany({ where: { authorId: id }, data: { published: true } });
137
+ });
138
+ ```
139
+
140
+ ---
141
+
142
+ ### Drizzle ORM Best Practices
143
+
144
+ #### Schema Definition (PostgreSQL)
145
+ ```typescript
146
+ // src/db/schema.ts
147
+ import { pgTable, text, boolean, timestamp, pgEnum, index } from 'drizzle-orm/pg-core';
148
+ import { createId } from '@paralleldrive/cuid2';
149
+ import { relations } from 'drizzle-orm';
150
+
151
+ export const roleEnum = pgEnum('role', ['USER', 'ADMIN', 'SUPER_ADMIN']);
152
+
153
+ export const users = pgTable('users', {
154
+ id: text('id').primaryKey().$defaultFn(() => createId()),
155
+ email: text('email').notNull().unique(),
156
+ name: text('name'),
157
+ role: roleEnum('role').default('USER').notNull(),
158
+ createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
159
+ updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull().$onUpdateFn(() => new Date()),
160
+ }, (t) => [
161
+ index('users_email_idx').on(t.email),
162
+ ]);
163
+
164
+ export const posts = pgTable('posts', {
165
+ id: text('id').primaryKey().$defaultFn(() => createId()),
166
+ title: text('title').notNull(),
167
+ content: text('content'),
168
+ published: boolean('published').default(false).notNull(),
169
+ authorId: text('author_id').notNull().references(() => users.id, { onDelete: 'cascade' }),
170
+ publishedAt: timestamp('published_at', { withTimezone: true }),
171
+ }, (t) => [
172
+ index('posts_author_published_idx').on(t.authorId, t.published),
173
+ ]);
174
+
175
+ export const usersRelations = relations(users, ({ many }) => ({
176
+ posts: many(posts),
177
+ }));
178
+
179
+ export const postsRelations = relations(posts, ({ one }) => ({
180
+ author: one(users, { fields: [posts.authorId], references: [users.id] }),
181
+ }));
182
+ ```
183
+
184
+ #### Type-safe Queries with Drizzle
185
+ ```typescript
186
+ // src/db/index.ts
187
+ import { drizzle } from 'drizzle-orm/postgres-js';
188
+ import postgres from 'postgres';
189
+ import * as schema from './schema';
190
+
191
+ const client = postgres(process.env.DATABASE_URL!);
192
+ export const db = drizzle(client, { schema });
193
+
194
+ // Type-safe query with joins
195
+ import { eq, and, desc, count } from 'drizzle-orm';
196
+
197
+ const usersWithPosts = await db.query.users.findMany({
198
+ with: {
199
+ posts: {
200
+ where: eq(posts.published, true),
201
+ orderBy: desc(posts.publishedAt),
202
+ limit: 5,
203
+ },
204
+ },
205
+ extras: {
206
+ postCount: db.$count(posts, eq(posts.authorId, users.id)).as('post_count'),
207
+ },
208
+ });
209
+
210
+ // Paginated query
211
+ async function getPaginatedPosts(page: number, pageSize = 20) {
212
+ const offset = (page - 1) * pageSize;
213
+ const [items, [{ total }]] = await Promise.all([
214
+ db.select().from(posts).where(eq(posts.published, true))
215
+ .orderBy(desc(posts.publishedAt))
216
+ .limit(pageSize)
217
+ .offset(offset),
218
+ db.select({ total: count() }).from(posts).where(eq(posts.published, true)),
219
+ ]);
220
+ return { items, total, pages: Math.ceil(total / pageSize) };
221
+ }
222
+ ```
223
+
224
+ #### Drizzle Migration Workflow
225
+ ```bash
226
+ # drizzle.config.ts defines connection + schema path
227
+ npx drizzle-kit generate # generate migration SQL files
228
+ npx drizzle-kit migrate # apply migrations to database
229
+ npx drizzle-kit push # push schema directly (dev only)
230
+ npx drizzle-kit studio # open Drizzle Studio GUI
231
+ ```
232
+
233
+ ---
234
+
235
+ ### Query Optimization Principles
236
+
237
+ 1. **Always index foreign keys** and columns used in `WHERE`, `ORDER BY`, and `JOIN`.
238
+ 2. **Use `EXPLAIN ANALYZE`** to detect sequential scans and missing indexes.
239
+ 3. **Cursor-based pagination** over offset for large datasets:
240
+ ```typescript
241
+ // Cursor pagination with Drizzle
242
+ const items = await db.select().from(posts)
243
+ .where(cursor ? lt(posts.createdAt, cursor) : undefined)
244
+ .orderBy(desc(posts.createdAt))
245
+ .limit(pageSize);
246
+ ```
247
+ 4. **Connection pooling**: Use PgBouncer or Supabase's built-in pooler. Set `DIRECT_URL` for migrations and `DATABASE_URL` for pooled reads/writes.
248
+ 5. **Avoid `SELECT *`**: Always select only the columns you need.
249
+ 6. **Batch inserts**: Use `db.insert(table).values([...items])` instead of looping.
250
+
251
+ ---
252
+
253
+ ### Migration Best Practices
254
+
255
+ - **Never use `synchronize: true`** in production (TypeORM).
256
+ - **Never run `prisma db push`** in production — always use `prisma migrate deploy`.
257
+ - Store migration files in version control.
258
+ - Run migrations as a separate step before deploying new app versions.
259
+ - Use **advisory locks** or migration tools to prevent concurrent migration runs.
260
+
261
+ ---
262
+
263
+ <a name="bahasa-indonesia"></a>
264
+ ## Bahasa Indonesia
265
+
266
+ ### Deskripsi
267
+ Rancang skema, pilih ORM, eksekusi migrasi, optimalkan query, dan implementasikan pola SQL type-safe. Prioritaskan **Prisma 6** dan **Drizzle ORM**. Implementasikan connection pooling untuk beban kerja produksi.
268
+
269
+ ### Kondisi Pemicu
270
+ - Merancang atau memigrasikan skema database.
271
+ - Memilih antara Prisma, Drizzle ORM, atau TypeORM.
272
+ - Menulis query kompleks dengan join, agregasi, atau paginasi.
273
+ - Mengoptimalkan query lambat atau masalah N+1.
274
+ - Menyiapkan migrasi database dalam pipeline CI/CD.
275
+ - Mengimplementasikan pola Row Level Security (RLS).
276
+ - Bekerja dengan PostgreSQL, MySQL, SQLite, atau PlanetScale.
277
+
278
+ ## Integrasi Orkestrasi
279
+ - `js-backend-expert`: Untuk implementasi backend Node/Bun/Deno yang menggunakan ORM ini.
280
+ - `edge-serverless-db-expert`: Untuk koneksi edge/serverless (mis. Supabase, Neon, Turso).
281
+ - `database-migration-versioning-expert`: Untuk strategi migrasi lanjutan dan pipeline CI/CD.
282
+
283
+ ### Panduan Pemilihan ORM
284
+
285
+ Gunakan tabel di atas (lihat bagian English) sebagai referensi pemilihan ORM. Rekomendasi singkat:
286
+ - **Drizzle ORM**: Untuk aplikasi edge-compatible dan sistem kritis performa.
287
+ - **Prisma 6**: Untuk tim yang lebih menyukai DX schema-first dan tooling Studio yang kaya.
288
+ - **TypeORM**: Hanya untuk proyek lama (legacy) berbasis NestJS.
289
+
290
+ ### Prinsip Utama
291
+
292
+ 1. **Selalu index foreign key** dan kolom yang digunakan di `WHERE`, `ORDER BY`, dan `JOIN`.
293
+ 2. **Gunakan `EXPLAIN ANALYZE`** untuk mendeteksi sequential scan dan index yang hilang.
294
+ 3. **Cursor-based pagination** lebih baik dari offset untuk dataset besar.
295
+ 4. **Connection pooling**: Gunakan PgBouncer atau Supabase pooler bawaan.
296
+ 5. **Hindari `SELECT *`**: Selalu pilih hanya kolom yang dibutuhkan.
297
+ 6. **Batch insert**: Gunakan insert massal, bukan looping satu per satu.
298
+
299
+ ### Prinsip Migrasi
300
+
301
+ - Jangan gunakan `synchronize: true` di produksi (TypeORM).
302
+ - Jangan jalankan `prisma db push` di produksi — selalu gunakan `prisma migrate deploy`.
303
+ - Simpan file migrasi di version control.
304
+ - Jalankan migrasi sebagai langkah terpisah sebelum deploy versi aplikasi baru.