vibes-plug 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/BLUEPRINT.md +125 -0
- package/CHANGELOG.md +195 -0
- package/CONTRIBUTING.md +199 -0
- package/LICENSE +21 -0
- package/README.md +263 -0
- package/SECURITY.md +21 -0
- package/banner.png +0 -0
- package/package.json +25 -0
- package/plugin.json +8 -0
- package/scripts/update_skills.js +75 -0
- package/skills/ai-llm-integration-expert/SKILL.md +162 -0
- package/skills/api-design-expert/SKILL.md +310 -0
- package/skills/app-analyzer-optimizer/SKILL.md +189 -0
- package/skills/asisten_ramah/SKILL.md +41 -0
- package/skills/authentication-identity-expert/SKILL.md +45 -0
- package/skills/auto-doc-updater/SKILL.md +204 -0
- package/skills/bootstrap-to-modern/SKILL.md +87 -0
- package/skills/brainstorming/SKILL.md +353 -0
- package/skills/bun-runtime-expert/SKILL.md +211 -0
- package/skills/ci-cd-devops-architect/SKILL.md +45 -0
- package/skills/cloud-hosting-expert/SKILL.md +244 -0
- package/skills/coderabbit/SKILL.md +192 -0
- package/skills/data-telemetry-expert/SKILL.md +213 -0
- package/skills/database-orm-expert/SKILL.md +294 -0
- package/skills/design-system-architect/SKILL.md +243 -0
- package/skills/e2e-testing-expert/SKILL.md +315 -0
- package/skills/event-driven-architect/SKILL.md +81 -0
- package/skills/firebase-security-expert/SKILL.md +195 -0
- package/skills/fullstack-expert/SKILL.md +202 -0
- package/skills/fullstack-expert/references/api_design_guide.md +466 -0
- package/skills/fullstack-expert/references/devops_infrastructure.md +477 -0
- package/skills/fullstack-expert/references/multi_language_backend.md +528 -0
- package/skills/fullstack-expert/references/system_design_patterns.md +358 -0
- package/skills/fullstack-expert/scripts/api_contract_validator.py +253 -0
- package/skills/fullstack-expert/scripts/architecture_analyzer.py +326 -0
- package/skills/gemini-agent-booster/SKILL.md +135 -0
- package/skills/global-a11y-i18n-expert/SKILL.md +81 -0
- package/skills/go-programming-expert/SKILL.md +295 -0
- package/skills/hig/SKILL.md +188 -0
- package/skills/js-backend-expert/SKILL.md +192 -0
- package/skills/mcp-server-architect/SKILL.md +194 -0
- package/skills/mobile-expo-expert/SKILL.md +186 -0
- package/skills/monday-design-aesthetic/SKILL.md +67 -0
- package/skills/monorepo-architect/SKILL.md +227 -0
- package/skills/mpa-orchestrator/SKILL.md +101 -0
- package/skills/multi-agent-orchestration/SKILL.md +234 -0
- package/skills/multiple-entry-points/SKILL.md +55 -0
- package/skills/mvc-expert/SKILL.md +231 -0
- package/skills/payment-gateway-expert/SKILL.md +45 -0
- package/skills/performance-web-vitals/SKILL.md +332 -0
- package/skills/prd-architect/SKILL.md +191 -0
- package/skills/production-ready-hardener/SKILL.md +469 -0
- package/skills/production-ready-hardener/references/performance_optimization.md +441 -0
- package/skills/production-ready-hardener/references/production_checklist.md +161 -0
- package/skills/production-ready-hardener/references/security_hardening_guide.md +379 -0
- package/skills/production-ready-hardener/scripts/production_readiness_scanner.py +875 -0
- package/skills/python-programming-expert/SKILL.md +271 -0
- package/skills/realtime-collaboration-expert/SKILL.md +45 -0
- package/skills/rust-programming-expert/SKILL.md +235 -0
- package/skills/saas-billing/SKILL.md +377 -0
- package/skills/saas-multi-tenant/SKILL.md +237 -0
- package/skills/saas-mvp-launcher/SKILL.md +231 -0
- package/skills/saas-transformer/SKILL.md +446 -0
- package/skills/saas-transformer/references/billing_integration_guide.md +401 -0
- package/skills/saas-transformer/references/feature_gating_patterns.md +137 -0
- package/skills/saas-transformer/references/saas_transformation_checklist.md +121 -0
- package/skills/saas-transformer/scripts/saas_transformation_scanner.py +254 -0
- package/skills/scalability-clean-code/SKILL.md +229 -0
- package/skills/secure-fuzz-testing/SKILL.md +201 -0
- package/skills/senior-frontend/SKILL.md +161 -0
- package/skills/senior-frontend/references/frontend_best_practices.md +806 -0
- package/skills/senior-frontend/references/nextjs_optimization_guide.md +724 -0
- package/skills/senior-frontend/references/react_patterns.md +746 -0
- package/skills/senior-frontend/scripts/bundle_analyzer.py +407 -0
- package/skills/senior-frontend/scripts/component_generator.py +329 -0
- package/skills/senior-frontend/scripts/frontend_scaffolder.py +1005 -0
- package/skills/senior-fullstack/SKILL.md +167 -0
- package/skills/senior-fullstack/references/architecture_patterns.md +160 -0
- package/skills/senior-fullstack/references/development_workflows.md +222 -0
- package/skills/senior-fullstack/references/tech_stack_guide.md +190 -0
- package/skills/senior-fullstack/scripts/code_quality_analyzer.py +114 -0
- package/skills/senior-fullstack/scripts/fullstack_scaffolder.py +114 -0
- package/skills/senior-fullstack/scripts/project_scaffolder.py +114 -0
- package/skills/seo/SKILL.md +225 -0
- package/skills/seo/references/cwv-thresholds.md +108 -0
- package/skills/seo/references/eeat-framework.md +214 -0
- package/skills/seo/references/quality-gates.md +155 -0
- package/skills/seo/references/schema-types.md +118 -0
- package/skills/seo-aeo-landing-page-writer/SKILL.md +97 -0
- package/skills/seo-geo/SKILL.md +188 -0
- package/skills/session-handoff-resume/SKILL.md +158 -0
- package/skills/skill_baru/SKILL.md +147 -0
- package/skills/spa-orchestrator/SKILL.md +288 -0
- package/skills/state-management-expert/SKILL.md +272 -0
- package/skills/supabase-migration/SKILL.md +45 -0
- package/skills/supabase-security-expert/SKILL.md +243 -0
- package/skills/tailwind-expert/SKILL.md +188 -0
- package/skills/tanstack-query-expert/SKILL.md +199 -0
- package/skills/tauri-expert/SKILL.md +97 -0
- package/skills/token-saver/SKILL.md +111 -0
- package/skills/typescript-expert/SKILL.md +279 -0
- package/skills/ui-components-expert/SKILL.md +63 -0
- package/skills/ui-ux-pro-max/SKILL.md +201 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/prompts.csv +24 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +59 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-310.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-312.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-310.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-312.pyc +0 -0
- package/skills/ui-ux-pro-max/scripts/core.py +257 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +493 -0
- package/skills/ui-ux-pro-max/scripts/search.py +81 -0
- package/skills/ui_ux_expert/SKILL.md +114 -0
- package/skills/vibe-code-gardener/SKILL.md +173 -0
- package/skills/web-scraper/SKILL.md +205 -0
- package/skills/web-scraper/references/data-transforms.md +397 -0
- package/skills/web-scraper/references/extraction-patterns.md +475 -0
- package/skills/web-scraper/references/output-templates.md +481 -0
- package/skills/zero-to-prod-orchestrator/SKILL.md +180 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-telemetry-expert
|
|
3
|
+
description: "Expert guide for observability, analytics, telemetry, and data pipelines (OpenTelemetry, PostHog, Mixpanel) / Panduan ahli untuk observabilitas, telemetri, dan analitik."
|
|
4
|
+
author: "Roedy Rustam"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Data & Telemetry Expert (OpenTelemetry 1.x / ClickHouse Edition)
|
|
8
|
+
|
|
9
|
+
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<a name="english"></a>
|
|
14
|
+
## English
|
|
15
|
+
|
|
16
|
+
### Description
|
|
17
|
+
Expert guide for production observability, product analytics, and data pipelines. Covers **OpenTelemetry 1.x** (stable, vendor-neutral traces/metrics/logs), **PostHog** (open-source product analytics), **ClickHouse** (OLAP analytics database), Grafana stack, and AI agent observability patterns.
|
|
18
|
+
|
|
19
|
+
### Trigger Conditions
|
|
20
|
+
- Adding distributed tracing to a microservice or Next.js application.
|
|
21
|
+
- Setting up structured logging and metrics collection.
|
|
22
|
+
- Implementing product analytics (funnel analysis, feature flags, session replay).
|
|
23
|
+
- Building a high-performance analytics pipeline with ClickHouse.
|
|
24
|
+
- Monitoring AI agent runs, LLM token costs, and response quality.
|
|
25
|
+
|
|
26
|
+
### OpenTelemetry 1.x — Vendor-Neutral Observability
|
|
27
|
+
|
|
28
|
+
OpenTelemetry (OTel) is the CNCF standard for generating traces, metrics, and logs from any application.
|
|
29
|
+
|
|
30
|
+
#### Three Pillars of OTel
|
|
31
|
+
|
|
32
|
+
| Signal | What It Captures | Example |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| **Traces** | Request flow across services | `GET /api/users` → DB query → cache |
|
|
35
|
+
| **Metrics** | Numeric measurements over time | `http_requests_total`, `db_query_duration` |
|
|
36
|
+
| **Logs** | Structured event records | `{"level":"error","msg":"DB timeout"}` |
|
|
37
|
+
|
|
38
|
+
#### Next.js 15 + OTel Instrumentation
|
|
39
|
+
```typescript
|
|
40
|
+
// instrumentation.ts (Next.js built-in OTel support)
|
|
41
|
+
export async function register() {
|
|
42
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
43
|
+
const { NodeSDK } = await import('@opentelemetry/sdk-node');
|
|
44
|
+
const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http');
|
|
45
|
+
const { OTLPMetricExporter } = await import('@opentelemetry/exporter-metrics-otlp-http');
|
|
46
|
+
const { PeriodicExportingMetricReader } = await import('@opentelemetry/sdk-metrics');
|
|
47
|
+
const { Resource } = await import('@opentelemetry/resources');
|
|
48
|
+
const { SEMRESATTRS_SERVICE_NAME } = await import('@opentelemetry/semantic-conventions');
|
|
49
|
+
|
|
50
|
+
const sdk = new NodeSDK({
|
|
51
|
+
resource: new Resource({
|
|
52
|
+
[SEMRESATTRS_SERVICE_NAME]: 'my-saas-app',
|
|
53
|
+
}),
|
|
54
|
+
traceExporter: new OTLPTraceExporter({
|
|
55
|
+
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
|
|
56
|
+
}),
|
|
57
|
+
metricReader: new PeriodicExportingMetricReader({
|
|
58
|
+
exporter: new OTLPMetricExporter(),
|
|
59
|
+
exportIntervalMillis: 30_000,
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
sdk.start();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### Custom Spans for Business Logic
|
|
69
|
+
```typescript
|
|
70
|
+
import { trace, SpanStatusCode } from '@opentelemetry/api';
|
|
71
|
+
|
|
72
|
+
const tracer = trace.getTracer('my-service', '1.0.0');
|
|
73
|
+
|
|
74
|
+
async function processOrder(orderId: string) {
|
|
75
|
+
return tracer.startActiveSpan('processOrder', async (span) => {
|
|
76
|
+
span.setAttribute('order.id', orderId);
|
|
77
|
+
span.setAttribute('order.source', 'api');
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const order = await db.order.findUnique({ where: { id: orderId } });
|
|
81
|
+
span.setAttribute('order.amount', order.amount);
|
|
82
|
+
|
|
83
|
+
const result = await chargeCustomer(order);
|
|
84
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
85
|
+
return result;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
span.recordException(error as Error);
|
|
88
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: String(error) });
|
|
89
|
+
throw error;
|
|
90
|
+
} finally {
|
|
91
|
+
span.end();
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### ClickHouse — High-Performance Analytics Database
|
|
98
|
+
ClickHouse is the 2026 standard for analytical workloads — ingests billions of events and queries them in milliseconds:
|
|
99
|
+
|
|
100
|
+
```sql
|
|
101
|
+
-- Create an events table optimized for time-series analytics
|
|
102
|
+
CREATE TABLE events (
|
|
103
|
+
event_id UUID DEFAULT generateUUIDv4(),
|
|
104
|
+
workspace_id String,
|
|
105
|
+
user_id String,
|
|
106
|
+
event_name LowCardinality(String),
|
|
107
|
+
properties JSON,
|
|
108
|
+
timestamp DateTime64(3, 'UTC'),
|
|
109
|
+
date Date DEFAULT toDate(timestamp)
|
|
110
|
+
)
|
|
111
|
+
ENGINE = MergeTree()
|
|
112
|
+
PARTITION BY toYYYYMM(date)
|
|
113
|
+
ORDER BY (workspace_id, event_name, timestamp)
|
|
114
|
+
TTL date + INTERVAL 1 YEAR;
|
|
115
|
+
|
|
116
|
+
-- Query: Funnel analysis — users who signed up then upgraded
|
|
117
|
+
SELECT
|
|
118
|
+
countIf(event_name = 'signup') AS signups,
|
|
119
|
+
countIf(event_name = 'plan_upgraded') AS upgrades,
|
|
120
|
+
round(countIf(event_name = 'plan_upgraded') / countIf(event_name = 'signup') * 100, 2) AS conversion_rate
|
|
121
|
+
FROM events
|
|
122
|
+
WHERE workspace_id = 'ws_abc'
|
|
123
|
+
AND timestamp >= now() - INTERVAL 30 DAY;
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
// Node.js ClickHouse client
|
|
128
|
+
import { createClient } from '@clickhouse/client';
|
|
129
|
+
|
|
130
|
+
const client = createClient({ url: process.env.CLICKHOUSE_URL });
|
|
131
|
+
|
|
132
|
+
await client.insert({
|
|
133
|
+
table: 'events',
|
|
134
|
+
values: [{
|
|
135
|
+
workspace_id: 'ws_abc',
|
|
136
|
+
user_id: 'user_123',
|
|
137
|
+
event_name: 'page_view',
|
|
138
|
+
properties: { path: '/dashboard', referrer: 'google.com' },
|
|
139
|
+
timestamp: new Date().toISOString(),
|
|
140
|
+
}],
|
|
141
|
+
format: 'JSONEachRow',
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### PostHog — Open-Source Product Analytics
|
|
146
|
+
```typescript
|
|
147
|
+
// Next.js + PostHog (client-side)
|
|
148
|
+
import posthog from 'posthog-js';
|
|
149
|
+
|
|
150
|
+
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
|
151
|
+
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST ?? 'https://app.posthog.com',
|
|
152
|
+
capture_pageview: false, // Manual with App Router
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Track custom events
|
|
156
|
+
posthog.capture('feature_used', {
|
|
157
|
+
feature: 'ai_assistant',
|
|
158
|
+
plan: user.plan,
|
|
159
|
+
workspace_id: workspace.id,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Feature flags
|
|
163
|
+
if (posthog.isFeatureEnabled('new-dashboard')) {
|
|
164
|
+
return <NewDashboard />;
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### AI Agent Observability
|
|
169
|
+
Track LLM costs, latency, and quality for production AI applications:
|
|
170
|
+
```typescript
|
|
171
|
+
// Custom OTel attributes for LLM calls
|
|
172
|
+
span.setAttribute('llm.model', 'claude-4-sonnet');
|
|
173
|
+
span.setAttribute('llm.input_tokens', response.usage.input_tokens);
|
|
174
|
+
span.setAttribute('llm.output_tokens', response.usage.output_tokens);
|
|
175
|
+
span.setAttribute('llm.cost_usd', calculateCost(response.usage));
|
|
176
|
+
span.setAttribute('llm.latency_ms', Date.now() - startTime);
|
|
177
|
+
span.setAttribute('llm.cached', response.usage.cache_read_input_tokens > 0);
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Backend tracing tools for LLM: **LangSmith** (LangChain/LangGraph), **OpenAI Tracing** (Agents SDK), **Langfuse** (open-source, any LLM).
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
<a name="bahasa-indonesia"></a>
|
|
185
|
+
## Bahasa Indonesia
|
|
186
|
+
|
|
187
|
+
### Deskripsi
|
|
188
|
+
Panduan ahli untuk observabilitas produksi, analitik produk, dan pipeline data. Mencakup **OpenTelemetry 1.x** (stabil, vendor-neutral traces/metrics/logs), **PostHog** (analitik produk open-source), **ClickHouse** (database analitik OLAP), dan pola observabilitas agen AI.
|
|
189
|
+
|
|
190
|
+
### Kondisi Pemicu
|
|
191
|
+
- Menambahkan distributed tracing ke microservice atau aplikasi Next.js.
|
|
192
|
+
- Menyiapkan structured logging dan pengumpulan metrik.
|
|
193
|
+
- Mengimplementasikan analitik produk (analisis funnel, feature flags, session replay).
|
|
194
|
+
- Membangun pipeline analitik berkinerja tinggi dengan ClickHouse.
|
|
195
|
+
- Memantau run agen AI, biaya token LLM, dan kualitas respons.
|
|
196
|
+
|
|
197
|
+
### OpenTelemetry 1.x — Observabilitas Vendor-Neutral
|
|
198
|
+
|
|
199
|
+
Tiga pilar OTel:
|
|
200
|
+
- **Traces**: Aliran permintaan antar layanan.
|
|
201
|
+
- **Metrics**: Pengukuran numerik dari waktu ke waktu.
|
|
202
|
+
- **Logs**: Catatan peristiwa terstruktur.
|
|
203
|
+
|
|
204
|
+
Integrasikan dengan Next.js 15 melalui file `instrumentation.ts` bawaan — OTel SDK otomatis mendistribusikan trace ke backend pilihan (Grafana Tempo, Jaeger, Honeycomb, Datadog, dll.).
|
|
205
|
+
|
|
206
|
+
### ClickHouse — Database Analitik Berkinerja Tinggi
|
|
207
|
+
ClickHouse adalah standar 2026 untuk workload analitik — menyerap miliaran event dan melakukan query dalam milidetik. Gunakan engine `MergeTree` dengan partisi per bulan dan pengurutan berdasarkan kolom yang sering di-filter.
|
|
208
|
+
|
|
209
|
+
### PostHog — Analitik Produk Open-Source
|
|
210
|
+
PostHog menyediakan analisis funnel, feature flags, session replay, dan A/B testing dalam satu platform yang dapat di-self-host. Integrasikan dengan Next.js App Router menggunakan `posthog-js`.
|
|
211
|
+
|
|
212
|
+
### Observabilitas Agen AI
|
|
213
|
+
Lacak biaya LLM, latensi, dan kualitas untuk aplikasi AI produksi menggunakan custom OTel attributes. Gunakan LangSmith, OpenAI Tracing, atau Langfuse (open-source) sebagai backend tracing LLM.
|
|
@@ -0,0 +1,294 @@
|
|
|
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
|
+
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.
|