@hivehub/rulebook 5.1.3 → 5.2.1
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/.claude/commands/continue.md +33 -33
- package/.claude/commands/ralph-config.md +112 -112
- package/.claude/commands/ralph-history.md +110 -110
- package/.claude/commands/ralph-init.md +72 -72
- package/.claude/commands/ralph-pause-resume.md +105 -105
- package/.claude/commands/ralph-run.md +101 -101
- package/.claude/commands/ralph-status.md +76 -76
- package/.claude/commands/rulebook-decision-create.md +55 -55
- package/.claude/commands/rulebook-decision-list.md +15 -15
- package/.claude/commands/rulebook-knowledge-add.md +41 -41
- package/.claude/commands/rulebook-knowledge-list.md +15 -15
- package/.claude/commands/rulebook-learn-capture.md +48 -48
- package/.claude/commands/rulebook-learn-list.md +13 -13
- package/.claude/commands/rulebook-memory-save.md +48 -48
- package/.claude/commands/rulebook-memory-search.md +47 -47
- package/.claude/commands/rulebook-task-apply.md +85 -67
- package/.claude/commands/rulebook-task-archive.md +103 -94
- package/.claude/commands/rulebook-task-create.md +93 -93
- package/.claude/commands/rulebook-task-list.md +42 -42
- package/.claude/commands/rulebook-task-show.md +52 -52
- package/.claude/commands/rulebook-task-validate.md +53 -53
- package/.claude-plugin/marketplace.json +28 -28
- package/.claude-plugin/plugin.json +8 -8
- package/README.md +25 -43
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +11 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/core/agent-template-engine.js +28 -28
- package/dist/core/generator.js +28 -28
- package/dist/core/task-manager.d.ts +23 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +163 -27
- package/dist/core/task-manager.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/mcp/rulebook-server.js +3 -3
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/dist/memory/memory-store.js +91 -91
- package/package.json +21 -22
- package/templates/agents/accessibility-reviewer.md +43 -43
- package/templates/agents/api-designer.md +42 -42
- package/templates/agents/architect.md +51 -51
- package/templates/agents/build-engineer.md +36 -36
- package/templates/agents/code-reviewer.md +47 -47
- package/templates/agents/compiler/codegen-debugger.md +34 -34
- package/templates/agents/compiler/stdlib-engineer.md +28 -28
- package/templates/agents/compiler/test-coverage-guardian.md +31 -31
- package/templates/agents/context-intelligence.md +52 -52
- package/templates/agents/database-architect.md +41 -41
- package/templates/agents/devops-engineer.md +42 -42
- package/templates/agents/docs-writer.md +38 -38
- package/templates/agents/game-engine/cpp-core-expert.md +35 -35
- package/templates/agents/game-engine/render-engineer.md +22 -22
- package/templates/agents/game-engine/shader-engineer.md +38 -38
- package/templates/agents/game-engine/systems-integration.md +43 -43
- package/templates/agents/generic/code-reviewer.md +41 -41
- package/templates/agents/generic/docs-writer.md +25 -25
- package/templates/agents/generic/project-manager.md +36 -36
- package/templates/agents/generic/researcher.md +34 -34
- package/templates/agents/generic/test-engineer.md +41 -41
- package/templates/agents/i18n-engineer.md +42 -42
- package/templates/agents/implementer.md +42 -42
- package/templates/agents/migration-engineer.md +42 -42
- package/templates/agents/mobile/platform-specialist.md +22 -22
- package/templates/agents/mobile/ui-engineer.md +22 -22
- package/templates/agents/performance-engineer.md +49 -49
- package/templates/agents/refactoring-agent.md +41 -41
- package/templates/agents/researcher.md +38 -38
- package/templates/agents/security-reviewer.md +40 -40
- package/templates/agents/team-lead.md +37 -37
- package/templates/agents/tester.md +48 -48
- package/templates/agents/ux-reviewer.md +43 -43
- package/templates/agents/web-app/api-designer.md +22 -22
- package/templates/agents/web-app/backend-engineer.md +30 -30
- package/templates/agents/web-app/database-engineer.md +22 -22
- package/templates/agents/web-app/frontend-engineer.md +29 -29
- package/templates/agents/web-app/security-reviewer.md +32 -32
- package/templates/ci/rulebook-review.yml +26 -26
- package/templates/cli/AIDER.md +49 -49
- package/templates/cli/AMAZON_Q.md +25 -25
- package/templates/cli/AUGGIE.md +32 -32
- package/templates/cli/CLAUDE.md +117 -117
- package/templates/cli/CLINE.md +99 -99
- package/templates/cli/CODEBUDDY.md +20 -20
- package/templates/cli/CODEIUM.md +20 -20
- package/templates/cli/CODEX.md +21 -21
- package/templates/cli/CONTINUE.md +34 -34
- package/templates/cli/CURSOR_CLI.md +62 -62
- package/templates/cli/FACTORY.md +18 -18
- package/templates/cli/GEMINI.md +35 -35
- package/templates/cli/KILOCODE.md +18 -18
- package/templates/cli/OPENCODE.md +18 -18
- package/templates/cli/_GENERIC_TEMPLATE.md +29 -29
- package/templates/commands/rulebook-decision-create.md +55 -55
- package/templates/commands/rulebook-decision-list.md +15 -15
- package/templates/commands/rulebook-knowledge-add.md +41 -41
- package/templates/commands/rulebook-knowledge-list.md +15 -15
- package/templates/commands/rulebook-learn-capture.md +48 -48
- package/templates/commands/rulebook-learn-list.md +13 -13
- package/templates/commands/rulebook-memory-save.md +48 -48
- package/templates/commands/rulebook-memory-search.md +47 -47
- package/templates/commands/rulebook-task-apply.md +67 -67
- package/templates/commands/rulebook-task-archive.md +94 -94
- package/templates/commands/rulebook-task-create.md +93 -93
- package/templates/commands/rulebook-task-list.md +42 -42
- package/templates/commands/rulebook-task-show.md +52 -52
- package/templates/commands/rulebook-task-validate.md +53 -53
- package/templates/core/AGENTS_LEAN.md +25 -25
- package/templates/core/AGENTS_OVERRIDE.md +16 -16
- package/templates/core/AGENT_AUTOMATION.md +296 -296
- package/templates/core/DAG.md +304 -304
- package/templates/core/DECISIONS.md +38 -38
- package/templates/core/DOCUMENTATION_RULES.md +36 -36
- package/templates/core/KNOWLEDGE.md +49 -49
- package/templates/core/MULTI_AGENT.md +74 -74
- package/templates/core/PLANS.md +28 -28
- package/templates/core/QUALITY_ENFORCEMENT.md +68 -68
- package/templates/core/RALPH.md +471 -471
- package/templates/core/RULEBOOK.md +1947 -1947
- package/templates/core/TIER1_PROHIBITIONS.md +154 -154
- package/templates/core/TOKEN_OPTIMIZATION.md +49 -49
- package/templates/frameworks/ANGULAR.md +36 -36
- package/templates/frameworks/DJANGO.md +83 -83
- package/templates/frameworks/ELECTRON.md +147 -147
- package/templates/frameworks/FLASK.md +38 -38
- package/templates/frameworks/FLUTTER.md +55 -55
- package/templates/frameworks/JQUERY.md +32 -32
- package/templates/frameworks/LARAVEL.md +38 -38
- package/templates/frameworks/NESTJS.md +43 -43
- package/templates/frameworks/NEXTJS.md +127 -127
- package/templates/frameworks/NUXT.md +40 -40
- package/templates/frameworks/RAILS.md +66 -66
- package/templates/frameworks/REACT.md +38 -38
- package/templates/frameworks/REACT_NATIVE.md +47 -47
- package/templates/frameworks/SPRING.md +39 -39
- package/templates/frameworks/SYMFONY.md +36 -36
- package/templates/frameworks/VUE.md +36 -36
- package/templates/frameworks/ZEND.md +35 -35
- package/templates/git/CI_CD_PATTERNS.md +661 -661
- package/templates/git/GITHUB_ACTIONS.md +728 -728
- package/templates/git/GITLAB_CI.md +730 -730
- package/templates/git/GIT_WORKFLOW.md +1192 -1192
- package/templates/git/SECRETS_MANAGEMENT.md +585 -585
- package/templates/hooks/COMMIT_MSG.md +530 -530
- package/templates/hooks/POST_CHECKOUT.md +546 -546
- package/templates/hooks/PREPARE_COMMIT_MSG.md +619 -619
- package/templates/hooks/PRE_COMMIT.md +414 -414
- package/templates/hooks/PRE_PUSH.md +601 -601
- package/templates/ides/CONTINUE_RULES.md +16 -16
- package/templates/ides/COPILOT.md +37 -37
- package/templates/ides/COPILOT_INSTRUCTIONS.md +23 -23
- package/templates/ides/CURSOR.md +43 -43
- package/templates/ides/GEMINI_RULES.md +17 -17
- package/templates/ides/JETBRAINS_AI.md +35 -35
- package/templates/ides/REPLIT.md +36 -36
- package/templates/ides/TABNINE.md +29 -29
- package/templates/ides/VSCODE.md +40 -40
- package/templates/ides/WINDSURF.md +36 -36
- package/templates/ides/WINDSURF_RULES.md +14 -14
- package/templates/ides/ZED.md +32 -32
- package/templates/ides/cursor-mdc/go.mdc +24 -24
- package/templates/ides/cursor-mdc/python.mdc +24 -24
- package/templates/ides/cursor-mdc/quality.mdc +25 -25
- package/templates/ides/cursor-mdc/ralph.mdc +39 -39
- package/templates/ides/cursor-mdc/rulebook.mdc +38 -38
- package/templates/ides/cursor-mdc/rust.mdc +24 -24
- package/templates/ides/cursor-mdc/typescript.mdc +25 -25
- package/templates/languages/C.md +333 -333
- package/templates/languages/CPP.md +743 -743
- package/templates/languages/CSHARP.md +417 -417
- package/templates/languages/ELIXIR.md +454 -454
- package/templates/languages/ERLANG.md +361 -361
- package/templates/languages/GO.md +645 -645
- package/templates/languages/HASKELL.md +177 -177
- package/templates/languages/JAVA.md +607 -607
- package/templates/languages/JAVASCRIPT.md +631 -631
- package/templates/languages/JULIA.md +97 -97
- package/templates/languages/KOTLIN.md +511 -511
- package/templates/languages/LISP.md +100 -100
- package/templates/languages/LUA.md +74 -74
- package/templates/languages/OBJECTIVEC.md +90 -90
- package/templates/languages/PHP.md +416 -416
- package/templates/languages/PYTHON.md +682 -682
- package/templates/languages/RUBY.md +421 -421
- package/templates/languages/RUST.md +477 -477
- package/templates/languages/SAS.md +73 -73
- package/templates/languages/SCALA.md +348 -348
- package/templates/languages/SOLIDITY.md +580 -580
- package/templates/languages/SQL.md +137 -137
- package/templates/languages/SWIFT.md +466 -466
- package/templates/languages/TYPESCRIPT.md +591 -591
- package/templates/languages/ZIG.md +265 -265
- package/templates/modules/ATLASSIAN.md +255 -255
- package/templates/modules/CONTEXT7.md +54 -54
- package/templates/modules/FIGMA.md +267 -267
- package/templates/modules/GITHUB_MCP.md +64 -64
- package/templates/modules/GRAFANA.md +328 -328
- package/templates/modules/MEMORY.md +126 -126
- package/templates/modules/NOTION.md +247 -247
- package/templates/modules/PLAYWRIGHT.md +90 -90
- package/templates/modules/RULEBOOK_MCP.md +156 -156
- package/templates/modules/SERENA.md +337 -337
- package/templates/modules/SUPABASE.md +223 -223
- package/templates/modules/SYNAP.md +69 -69
- package/templates/modules/VECTORIZER.md +63 -63
- package/templates/modules/sequential-thinking.md +42 -42
- package/templates/ralph/ralph-history.bat +4 -4
- package/templates/ralph/ralph-history.sh +5 -5
- package/templates/ralph/ralph-init.bat +5 -5
- package/templates/ralph/ralph-init.sh +5 -5
- package/templates/ralph/ralph-pause.bat +5 -5
- package/templates/ralph/ralph-pause.sh +5 -5
- package/templates/ralph/ralph-run.bat +5 -5
- package/templates/ralph/ralph-run.sh +5 -5
- package/templates/ralph/ralph-status.bat +4 -4
- package/templates/ralph/ralph-status.sh +5 -5
- package/templates/rules/follow-task-sequence.md +36 -36
- package/templates/rules/git-safety.md +29 -29
- package/templates/rules/incremental-tests.md +29 -29
- package/templates/rules/knowledge-base-usage.md +41 -0
- package/templates/rules/no-deferred.md +31 -31
- package/templates/rules/no-shortcuts.md +30 -30
- package/templates/rules/research-first.md +30 -30
- package/templates/rules/sequential-editing.md +21 -21
- package/templates/rules/session-workflow.md +24 -24
- package/templates/rules/task-decomposition.md +32 -32
- package/templates/services/AZURE_BLOB.md +184 -184
- package/templates/services/CASSANDRA.md +239 -239
- package/templates/services/DATADOG.md +26 -26
- package/templates/services/DOCKER.md +124 -124
- package/templates/services/DOCKER_COMPOSE.md +168 -168
- package/templates/services/DYNAMODB.md +308 -308
- package/templates/services/ELASTICSEARCH.md +347 -347
- package/templates/services/GCS.md +178 -178
- package/templates/services/HELM.md +194 -194
- package/templates/services/INFLUXDB.md +265 -265
- package/templates/services/KAFKA.md +341 -341
- package/templates/services/KUBERNETES.md +208 -208
- package/templates/services/MARIADB.md +183 -183
- package/templates/services/MEMCACHED.md +242 -242
- package/templates/services/MINIO.md +201 -201
- package/templates/services/MONGODB.md +268 -268
- package/templates/services/MYSQL.md +358 -358
- package/templates/services/NEO4J.md +247 -247
- package/templates/services/OPENTELEMETRY.md +25 -25
- package/templates/services/ORACLE.md +290 -290
- package/templates/services/PINO.md +24 -24
- package/templates/services/POSTGRESQL.md +326 -326
- package/templates/services/PROMETHEUS.md +33 -33
- package/templates/services/RABBITMQ.md +286 -286
- package/templates/services/REDIS.md +292 -292
- package/templates/services/S3.md +298 -298
- package/templates/services/SENTRY.md +23 -23
- package/templates/services/SQLITE.md +294 -294
- package/templates/services/SQLSERVER.md +294 -294
- package/templates/services/WINSTON.md +30 -30
- package/templates/skills/cli/aider/SKILL.md +59 -59
- package/templates/skills/cli/amazon-q/SKILL.md +35 -35
- package/templates/skills/cli/auggie/SKILL.md +42 -42
- package/templates/skills/cli/claude/SKILL.md +42 -42
- package/templates/skills/cli/cline/SKILL.md +42 -42
- package/templates/skills/cli/codebuddy/SKILL.md +30 -30
- package/templates/skills/cli/codeium/SKILL.md +30 -30
- package/templates/skills/cli/codex/SKILL.md +31 -31
- package/templates/skills/cli/continue/SKILL.md +44 -44
- package/templates/skills/cli/cursor-cli/SKILL.md +38 -38
- package/templates/skills/cli/factory/SKILL.md +28 -28
- package/templates/skills/cli/gemini/SKILL.md +45 -45
- package/templates/skills/cli/kilocode/SKILL.md +28 -28
- package/templates/skills/cli/opencode/SKILL.md +28 -28
- package/templates/skills/core/agent-automation/SKILL.md +194 -194
- package/templates/skills/core/dag/SKILL.md +314 -314
- package/templates/skills/core/documentation-rules/SKILL.md +46 -46
- package/templates/skills/core/quality-enforcement/SKILL.md +78 -78
- package/templates/skills/core/rulebook/SKILL.md +176 -176
- package/templates/skills/dev/accessibility/SKILL.md +17 -17
- package/templates/skills/dev/api-design/SKILL.md +15 -15
- package/templates/skills/dev/architect/SKILL.md +17 -17
- package/templates/skills/dev/build-fix/SKILL.md +17 -17
- package/templates/skills/dev/db-design/SKILL.md +15 -15
- package/templates/skills/dev/debug/SKILL.md +16 -16
- package/templates/skills/dev/deploy/SKILL.md +17 -17
- package/templates/skills/dev/docs/SKILL.md +17 -17
- package/templates/skills/dev/migrate/SKILL.md +15 -15
- package/templates/skills/dev/perf/SKILL.md +17 -17
- package/templates/skills/dev/refactor/SKILL.md +17 -17
- package/templates/skills/dev/research/SKILL.md +14 -14
- package/templates/skills/dev/review/SKILL.md +18 -18
- package/templates/skills/dev/security-audit/SKILL.md +17 -17
- package/templates/skills/frameworks/angular/SKILL.md +46 -46
- package/templates/skills/frameworks/django/SKILL.md +93 -93
- package/templates/skills/frameworks/electron/SKILL.md +157 -157
- package/templates/skills/frameworks/flask/SKILL.md +48 -48
- package/templates/skills/frameworks/flutter/SKILL.md +65 -65
- package/templates/skills/frameworks/jquery/SKILL.md +42 -42
- package/templates/skills/frameworks/laravel/SKILL.md +48 -48
- package/templates/skills/frameworks/nestjs/SKILL.md +53 -53
- package/templates/skills/frameworks/nextjs/SKILL.md +137 -137
- package/templates/skills/frameworks/nuxt/SKILL.md +50 -50
- package/templates/skills/frameworks/rails/SKILL.md +76 -76
- package/templates/skills/frameworks/react/SKILL.md +48 -48
- package/templates/skills/frameworks/react-native/SKILL.md +57 -57
- package/templates/skills/frameworks/spring/SKILL.md +49 -49
- package/templates/skills/frameworks/symfony/SKILL.md +46 -46
- package/templates/skills/frameworks/vue/SKILL.md +46 -46
- package/templates/skills/frameworks/zend/SKILL.md +45 -45
- package/templates/skills/ides/copilot/SKILL.md +47 -47
- package/templates/skills/ides/cursor/SKILL.md +53 -53
- package/templates/skills/ides/jetbrains-ai/SKILL.md +45 -45
- package/templates/skills/ides/replit/SKILL.md +46 -46
- package/templates/skills/ides/tabnine/SKILL.md +39 -39
- package/templates/skills/ides/vscode/SKILL.md +50 -50
- package/templates/skills/ides/windsurf/SKILL.md +46 -46
- package/templates/skills/ides/zed/SKILL.md +42 -42
- package/templates/skills/languages/c/SKILL.md +343 -343
- package/templates/skills/languages/cpp/SKILL.md +753 -753
- package/templates/skills/languages/csharp/SKILL.md +427 -427
- package/templates/skills/languages/elixir/SKILL.md +464 -464
- package/templates/skills/languages/erlang/SKILL.md +371 -371
- package/templates/skills/languages/go/SKILL.md +655 -655
- package/templates/skills/languages/haskell/SKILL.md +187 -187
- package/templates/skills/languages/java/SKILL.md +617 -617
- package/templates/skills/languages/javascript/SKILL.md +641 -641
- package/templates/skills/languages/julia/SKILL.md +107 -107
- package/templates/skills/languages/kotlin/SKILL.md +521 -521
- package/templates/skills/languages/lisp/SKILL.md +110 -110
- package/templates/skills/languages/lua/SKILL.md +84 -84
- package/templates/skills/languages/objectivec/SKILL.md +100 -100
- package/templates/skills/languages/php/SKILL.md +426 -426
- package/templates/skills/languages/python/SKILL.md +692 -692
- package/templates/skills/languages/ruby/SKILL.md +431 -431
- package/templates/skills/languages/rust/SKILL.md +487 -487
- package/templates/skills/languages/sas/SKILL.md +83 -83
- package/templates/skills/languages/scala/SKILL.md +358 -358
- package/templates/skills/languages/solidity/SKILL.md +590 -590
- package/templates/skills/languages/sql/SKILL.md +147 -147
- package/templates/skills/languages/swift/SKILL.md +476 -476
- package/templates/skills/languages/typescript/SKILL.md +302 -302
- package/templates/skills/languages/zig/SKILL.md +275 -275
- package/templates/skills/modules/atlassian/SKILL.md +265 -265
- package/templates/skills/modules/context7/SKILL.md +64 -64
- package/templates/skills/modules/figma/SKILL.md +277 -277
- package/templates/skills/modules/github-mcp/SKILL.md +74 -74
- package/templates/skills/modules/grafana/SKILL.md +338 -338
- package/templates/skills/modules/memory/SKILL.md +73 -73
- package/templates/skills/modules/notion/SKILL.md +257 -257
- package/templates/skills/modules/playwright/SKILL.md +100 -100
- package/templates/skills/modules/rulebook-mcp/SKILL.md +166 -166
- package/templates/skills/modules/serena/SKILL.md +347 -347
- package/templates/skills/modules/supabase/SKILL.md +233 -233
- package/templates/skills/modules/synap/SKILL.md +79 -79
- package/templates/skills/modules/vectorizer/SKILL.md +73 -73
- package/templates/skills/services/azure-blob/SKILL.md +194 -194
- package/templates/skills/services/cassandra/SKILL.md +249 -249
- package/templates/skills/services/dynamodb/SKILL.md +318 -318
- package/templates/skills/services/elasticsearch/SKILL.md +357 -357
- package/templates/skills/services/gcs/SKILL.md +188 -188
- package/templates/skills/services/influxdb/SKILL.md +275 -275
- package/templates/skills/services/kafka/SKILL.md +351 -351
- package/templates/skills/services/mariadb/SKILL.md +193 -193
- package/templates/skills/services/memcached/SKILL.md +252 -252
- package/templates/skills/services/minio/SKILL.md +211 -211
- package/templates/skills/services/mongodb/SKILL.md +278 -278
- package/templates/skills/services/mysql/SKILL.md +368 -368
- package/templates/skills/services/neo4j/SKILL.md +257 -257
- package/templates/skills/services/oracle/SKILL.md +300 -300
- package/templates/skills/services/postgresql/SKILL.md +336 -336
- package/templates/skills/services/rabbitmq/SKILL.md +296 -296
- package/templates/skills/services/redis/SKILL.md +302 -302
- package/templates/skills/services/s3/SKILL.md +308 -308
- package/templates/skills/services/sqlite/SKILL.md +304 -304
- package/templates/skills/services/sqlserver/SKILL.md +304 -304
- package/templates/skills/workflows/ralph/SKILL.md +309 -309
- package/templates/skills/workflows/ralph/install.sh +87 -87
- package/templates/skills/workflows/ralph/manifest.json +158 -158
|
@@ -1,336 +1,336 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "PostgreSQL"
|
|
3
|
-
description: "Use PostgreSQL for relational data storage with ACID compliance, transactions, and advanced features."
|
|
4
|
-
version: "1.0.0"
|
|
5
|
-
category: "services"
|
|
6
|
-
author: "Rulebook"
|
|
7
|
-
tags: ["services", "database"]
|
|
8
|
-
dependencies: []
|
|
9
|
-
conflicts: []
|
|
10
|
-
---
|
|
11
|
-
<!-- POSTGRESQL:START -->
|
|
12
|
-
# PostgreSQL Database Instructions
|
|
13
|
-
|
|
14
|
-
**CRITICAL**: Use PostgreSQL for relational data storage with ACID compliance, transactions, and advanced features.
|
|
15
|
-
|
|
16
|
-
## Core Features
|
|
17
|
-
|
|
18
|
-
### Connection
|
|
19
|
-
```typescript
|
|
20
|
-
// Using pg (Node.js)
|
|
21
|
-
import { Pool } from 'pg'
|
|
22
|
-
const pool = new Pool({
|
|
23
|
-
host: process.env.DB_HOST,
|
|
24
|
-
port: parseInt(process.env.DB_PORT || '5432'),
|
|
25
|
-
database: process.env.DB_NAME,
|
|
26
|
-
user: process.env.DB_USER,
|
|
27
|
-
password: process.env.DB_PASSWORD,
|
|
28
|
-
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
|
29
|
-
max: 20,
|
|
30
|
-
idleTimeoutMillis: 30000,
|
|
31
|
-
connectionTimeoutMillis: 2000,
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
// Using Prisma
|
|
35
|
-
import { PrismaClient } from '@prisma/client'
|
|
36
|
-
const prisma = new PrismaClient()
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Basic Queries
|
|
40
|
-
```typescript
|
|
41
|
-
// SELECT
|
|
42
|
-
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId])
|
|
43
|
-
const users = result.rows
|
|
44
|
-
|
|
45
|
-
// INSERT
|
|
46
|
-
const result = await pool.query(
|
|
47
|
-
'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
|
|
48
|
-
['John Doe', 'john@example.com']
|
|
49
|
-
)
|
|
50
|
-
const newUser = result.rows[0]
|
|
51
|
-
|
|
52
|
-
// UPDATE
|
|
53
|
-
const result = await pool.query(
|
|
54
|
-
'UPDATE users SET name = $1 WHERE id = $2 RETURNING *',
|
|
55
|
-
['Jane Doe', userId]
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
// DELETE
|
|
59
|
-
await pool.query('DELETE FROM users WHERE id = $1', [userId])
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### Transactions
|
|
63
|
-
```typescript
|
|
64
|
-
const client = await pool.connect()
|
|
65
|
-
try {
|
|
66
|
-
await client.query('BEGIN')
|
|
67
|
-
|
|
68
|
-
await client.query('INSERT INTO accounts (user_id, balance) VALUES ($1, $2)', [userId, 1000])
|
|
69
|
-
await client.query('INSERT INTO transactions (account_id, amount) VALUES ($1, $2)', [accountId, 1000])
|
|
70
|
-
|
|
71
|
-
await client.query('COMMIT')
|
|
72
|
-
} catch (error) {
|
|
73
|
-
await client.query('ROLLBACK')
|
|
74
|
-
throw error
|
|
75
|
-
} finally {
|
|
76
|
-
client.release()
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Advanced Features
|
|
81
|
-
```typescript
|
|
82
|
-
// JSONB queries
|
|
83
|
-
await pool.query(
|
|
84
|
-
'SELECT * FROM products WHERE metadata @> $1',
|
|
85
|
-
[JSON.stringify({ category: 'electronics' })]
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
// Full-text search
|
|
89
|
-
await pool.query(
|
|
90
|
-
"SELECT * FROM articles WHERE to_tsvector('english', content) @@ to_tsquery('english', $1)",
|
|
91
|
-
['search term']
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
// Array operations
|
|
95
|
-
await pool.query('SELECT * FROM posts WHERE tags && $1', [['javascript', 'typescript']])
|
|
96
|
-
|
|
97
|
-
// Window functions
|
|
98
|
-
await pool.query(`
|
|
99
|
-
SELECT
|
|
100
|
-
name,
|
|
101
|
-
salary,
|
|
102
|
-
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank
|
|
103
|
-
FROM employees
|
|
104
|
-
`)
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Common Patterns
|
|
108
|
-
|
|
109
|
-
### Connection Pooling
|
|
110
|
-
```typescript
|
|
111
|
-
// Reuse connection pool
|
|
112
|
-
let pool: Pool | null = null
|
|
113
|
-
|
|
114
|
-
export function getPool(): Pool {
|
|
115
|
-
if (!pool) {
|
|
116
|
-
pool = new Pool({
|
|
117
|
-
// ... config
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
pool.on('error', (err) => {
|
|
121
|
-
console.error('Unexpected error on idle client', err)
|
|
122
|
-
process.exit(-1)
|
|
123
|
-
})
|
|
124
|
-
}
|
|
125
|
-
return pool
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Graceful shutdown
|
|
129
|
-
process.on('SIGINT', async () => {
|
|
130
|
-
if (pool) {
|
|
131
|
-
await pool.end()
|
|
132
|
-
}
|
|
133
|
-
process.exit(0)
|
|
134
|
-
})
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Prepared Statements
|
|
138
|
-
```typescript
|
|
139
|
-
// Always use parameterized queries to prevent SQL injection
|
|
140
|
-
// ❌ WRONG
|
|
141
|
-
await pool.query(`SELECT * FROM users WHERE email = '${email}'`)
|
|
142
|
-
|
|
143
|
-
// ✅ CORRECT
|
|
144
|
-
await pool.query('SELECT * FROM users WHERE email = $1', [email])
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### Error Handling
|
|
148
|
-
```typescript
|
|
149
|
-
try {
|
|
150
|
-
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId])
|
|
151
|
-
if (result.rows.length === 0) {
|
|
152
|
-
throw new Error('User not found')
|
|
153
|
-
}
|
|
154
|
-
return result.rows[0]
|
|
155
|
-
} catch (error) {
|
|
156
|
-
if (error.code === '23505') { // Unique violation
|
|
157
|
-
throw new Error('Duplicate entry')
|
|
158
|
-
}
|
|
159
|
-
if (error.code === '23503') { // Foreign key violation
|
|
160
|
-
throw new Error('Referenced record does not exist')
|
|
161
|
-
}
|
|
162
|
-
throw error
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### Migrations
|
|
167
|
-
```typescript
|
|
168
|
-
// Using node-pg-migrate
|
|
169
|
-
import { migrate } from 'node-pg-migrate'
|
|
170
|
-
|
|
171
|
-
await migrate({
|
|
172
|
-
databaseUrl: process.env.DATABASE_URL,
|
|
173
|
-
dir: 'migrations',
|
|
174
|
-
direction: 'up',
|
|
175
|
-
migrationsTable: 'pgmigrations',
|
|
176
|
-
dryRun: false,
|
|
177
|
-
})
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
## Best Practices
|
|
181
|
-
|
|
182
|
-
✅ **DO:**
|
|
183
|
-
- Use connection pooling (max 20-30 connections)
|
|
184
|
-
- Always use parameterized queries ($1, $2, etc.)
|
|
185
|
-
- Use transactions for multi-step operations
|
|
186
|
-
- Create indexes on frequently queried columns
|
|
187
|
-
- Use EXPLAIN ANALYZE to optimize queries
|
|
188
|
-
- Enable connection pooling (PgBouncer for production)
|
|
189
|
-
- Use SSL in production
|
|
190
|
-
- Set appropriate connection timeouts
|
|
191
|
-
- Monitor connection pool usage
|
|
192
|
-
- Use prepared statements for repeated queries
|
|
193
|
-
|
|
194
|
-
❌ **DON'T:**
|
|
195
|
-
- Use string concatenation for queries (SQL injection risk)
|
|
196
|
-
- Create too many connections (exhaust pool)
|
|
197
|
-
- Skip error handling
|
|
198
|
-
- Ignore connection pool limits
|
|
199
|
-
- Use SELECT * in production (specify columns)
|
|
200
|
-
- Skip indexes on foreign keys
|
|
201
|
-
- Hardcode connection strings
|
|
202
|
-
- Skip SSL in production
|
|
203
|
-
- Ignore query performance
|
|
204
|
-
- Use synchronous queries
|
|
205
|
-
|
|
206
|
-
## Configuration
|
|
207
|
-
|
|
208
|
-
### Environment Variables
|
|
209
|
-
```bash
|
|
210
|
-
DB_HOST=localhost
|
|
211
|
-
DB_PORT=5432
|
|
212
|
-
DB_NAME=myapp
|
|
213
|
-
DB_USER=myuser
|
|
214
|
-
DB_PASSWORD=securepassword
|
|
215
|
-
DATABASE_URL=postgresql://user:password@host:port/database
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Docker Compose
|
|
219
|
-
```yaml
|
|
220
|
-
services:
|
|
221
|
-
postgres:
|
|
222
|
-
image: postgres:16-alpine
|
|
223
|
-
environment:
|
|
224
|
-
POSTGRES_DB: myapp
|
|
225
|
-
POSTGRES_USER: myuser
|
|
226
|
-
POSTGRES_PASSWORD: securepassword
|
|
227
|
-
ports:
|
|
228
|
-
- "5432:5432"
|
|
229
|
-
volumes:
|
|
230
|
-
- postgres_data:/var/lib/postgresql/data
|
|
231
|
-
healthcheck:
|
|
232
|
-
test: ["CMD-SHELL", "pg_isready -U myuser"]
|
|
233
|
-
interval: 10s
|
|
234
|
-
timeout: 5s
|
|
235
|
-
retries: 5
|
|
236
|
-
|
|
237
|
-
volumes:
|
|
238
|
-
postgres_data:
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Prisma Schema
|
|
242
|
-
```prisma
|
|
243
|
-
datasource db {
|
|
244
|
-
provider = "postgresql"
|
|
245
|
-
url = env("DATABASE_URL")
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
model User {
|
|
249
|
-
id Int @id @default(autoincrement())
|
|
250
|
-
email String @unique
|
|
251
|
-
name String?
|
|
252
|
-
createdAt DateTime @default(now())
|
|
253
|
-
posts Post[]
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
model Post {
|
|
257
|
-
id Int @id @default(autoincrement())
|
|
258
|
-
title String
|
|
259
|
-
content String?
|
|
260
|
-
authorId Int
|
|
261
|
-
author User @relation(fields: [authorId], references: [id])
|
|
262
|
-
createdAt DateTime @default(now())
|
|
263
|
-
}
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## Performance Optimization
|
|
267
|
-
|
|
268
|
-
### Indexing
|
|
269
|
-
```sql
|
|
270
|
-
-- Single column index
|
|
271
|
-
CREATE INDEX idx_users_email ON users(email);
|
|
272
|
-
|
|
273
|
-
-- Composite index
|
|
274
|
-
CREATE INDEX idx_posts_author_created ON posts(author_id, created_at DESC);
|
|
275
|
-
|
|
276
|
-
-- Partial index
|
|
277
|
-
CREATE INDEX idx_active_users ON users(email) WHERE active = true;
|
|
278
|
-
|
|
279
|
-
-- GIN index for JSONB
|
|
280
|
-
CREATE INDEX idx_products_metadata ON products USING GIN(metadata);
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### Query Optimization
|
|
284
|
-
```typescript
|
|
285
|
-
// Use LIMIT and OFFSET for pagination
|
|
286
|
-
const result = await pool.query(
|
|
287
|
-
'SELECT * FROM posts ORDER BY created_at DESC LIMIT $1 OFFSET $2',
|
|
288
|
-
[limit, offset]
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
// Use EXISTS instead of COUNT for existence checks
|
|
292
|
-
const result = await pool.query(
|
|
293
|
-
'SELECT EXISTS(SELECT 1 FROM users WHERE email = $1)',
|
|
294
|
-
[email]
|
|
295
|
-
)
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
## Integration with Development
|
|
299
|
-
|
|
300
|
-
### Testing
|
|
301
|
-
```typescript
|
|
302
|
-
// Use test database
|
|
303
|
-
const testPool = new Pool({
|
|
304
|
-
database: 'myapp_test',
|
|
305
|
-
// ... config
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
// Clean up after tests
|
|
309
|
-
afterEach(async () => {
|
|
310
|
-
await testPool.query('TRUNCATE TABLE users, posts CASCADE')
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
// Use transactions for test isolation
|
|
314
|
-
beforeEach(async () => {
|
|
315
|
-
await testPool.query('BEGIN')
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
afterEach(async () => {
|
|
319
|
-
await testPool.query('ROLLBACK')
|
|
320
|
-
})
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
### Health Checks
|
|
324
|
-
```typescript
|
|
325
|
-
async function checkDatabaseHealth(): Promise<boolean> {
|
|
326
|
-
try {
|
|
327
|
-
const result = await pool.query('SELECT 1')
|
|
328
|
-
return result.rows.length > 0
|
|
329
|
-
} catch {
|
|
330
|
-
return false
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
<!-- POSTGRESQL:END -->
|
|
336
|
-
|
|
1
|
+
---
|
|
2
|
+
name: "PostgreSQL"
|
|
3
|
+
description: "Use PostgreSQL for relational data storage with ACID compliance, transactions, and advanced features."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
category: "services"
|
|
6
|
+
author: "Rulebook"
|
|
7
|
+
tags: ["services", "database"]
|
|
8
|
+
dependencies: []
|
|
9
|
+
conflicts: []
|
|
10
|
+
---
|
|
11
|
+
<!-- POSTGRESQL:START -->
|
|
12
|
+
# PostgreSQL Database Instructions
|
|
13
|
+
|
|
14
|
+
**CRITICAL**: Use PostgreSQL for relational data storage with ACID compliance, transactions, and advanced features.
|
|
15
|
+
|
|
16
|
+
## Core Features
|
|
17
|
+
|
|
18
|
+
### Connection
|
|
19
|
+
```typescript
|
|
20
|
+
// Using pg (Node.js)
|
|
21
|
+
import { Pool } from 'pg'
|
|
22
|
+
const pool = new Pool({
|
|
23
|
+
host: process.env.DB_HOST,
|
|
24
|
+
port: parseInt(process.env.DB_PORT || '5432'),
|
|
25
|
+
database: process.env.DB_NAME,
|
|
26
|
+
user: process.env.DB_USER,
|
|
27
|
+
password: process.env.DB_PASSWORD,
|
|
28
|
+
ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
|
|
29
|
+
max: 20,
|
|
30
|
+
idleTimeoutMillis: 30000,
|
|
31
|
+
connectionTimeoutMillis: 2000,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
// Using Prisma
|
|
35
|
+
import { PrismaClient } from '@prisma/client'
|
|
36
|
+
const prisma = new PrismaClient()
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Basic Queries
|
|
40
|
+
```typescript
|
|
41
|
+
// SELECT
|
|
42
|
+
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId])
|
|
43
|
+
const users = result.rows
|
|
44
|
+
|
|
45
|
+
// INSERT
|
|
46
|
+
const result = await pool.query(
|
|
47
|
+
'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
|
|
48
|
+
['John Doe', 'john@example.com']
|
|
49
|
+
)
|
|
50
|
+
const newUser = result.rows[0]
|
|
51
|
+
|
|
52
|
+
// UPDATE
|
|
53
|
+
const result = await pool.query(
|
|
54
|
+
'UPDATE users SET name = $1 WHERE id = $2 RETURNING *',
|
|
55
|
+
['Jane Doe', userId]
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
// DELETE
|
|
59
|
+
await pool.query('DELETE FROM users WHERE id = $1', [userId])
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Transactions
|
|
63
|
+
```typescript
|
|
64
|
+
const client = await pool.connect()
|
|
65
|
+
try {
|
|
66
|
+
await client.query('BEGIN')
|
|
67
|
+
|
|
68
|
+
await client.query('INSERT INTO accounts (user_id, balance) VALUES ($1, $2)', [userId, 1000])
|
|
69
|
+
await client.query('INSERT INTO transactions (account_id, amount) VALUES ($1, $2)', [accountId, 1000])
|
|
70
|
+
|
|
71
|
+
await client.query('COMMIT')
|
|
72
|
+
} catch (error) {
|
|
73
|
+
await client.query('ROLLBACK')
|
|
74
|
+
throw error
|
|
75
|
+
} finally {
|
|
76
|
+
client.release()
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Advanced Features
|
|
81
|
+
```typescript
|
|
82
|
+
// JSONB queries
|
|
83
|
+
await pool.query(
|
|
84
|
+
'SELECT * FROM products WHERE metadata @> $1',
|
|
85
|
+
[JSON.stringify({ category: 'electronics' })]
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
// Full-text search
|
|
89
|
+
await pool.query(
|
|
90
|
+
"SELECT * FROM articles WHERE to_tsvector('english', content) @@ to_tsquery('english', $1)",
|
|
91
|
+
['search term']
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
// Array operations
|
|
95
|
+
await pool.query('SELECT * FROM posts WHERE tags && $1', [['javascript', 'typescript']])
|
|
96
|
+
|
|
97
|
+
// Window functions
|
|
98
|
+
await pool.query(`
|
|
99
|
+
SELECT
|
|
100
|
+
name,
|
|
101
|
+
salary,
|
|
102
|
+
ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) as rank
|
|
103
|
+
FROM employees
|
|
104
|
+
`)
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Common Patterns
|
|
108
|
+
|
|
109
|
+
### Connection Pooling
|
|
110
|
+
```typescript
|
|
111
|
+
// Reuse connection pool
|
|
112
|
+
let pool: Pool | null = null
|
|
113
|
+
|
|
114
|
+
export function getPool(): Pool {
|
|
115
|
+
if (!pool) {
|
|
116
|
+
pool = new Pool({
|
|
117
|
+
// ... config
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
pool.on('error', (err) => {
|
|
121
|
+
console.error('Unexpected error on idle client', err)
|
|
122
|
+
process.exit(-1)
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
return pool
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Graceful shutdown
|
|
129
|
+
process.on('SIGINT', async () => {
|
|
130
|
+
if (pool) {
|
|
131
|
+
await pool.end()
|
|
132
|
+
}
|
|
133
|
+
process.exit(0)
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Prepared Statements
|
|
138
|
+
```typescript
|
|
139
|
+
// Always use parameterized queries to prevent SQL injection
|
|
140
|
+
// ❌ WRONG
|
|
141
|
+
await pool.query(`SELECT * FROM users WHERE email = '${email}'`)
|
|
142
|
+
|
|
143
|
+
// ✅ CORRECT
|
|
144
|
+
await pool.query('SELECT * FROM users WHERE email = $1', [email])
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Error Handling
|
|
148
|
+
```typescript
|
|
149
|
+
try {
|
|
150
|
+
const result = await pool.query('SELECT * FROM users WHERE id = $1', [userId])
|
|
151
|
+
if (result.rows.length === 0) {
|
|
152
|
+
throw new Error('User not found')
|
|
153
|
+
}
|
|
154
|
+
return result.rows[0]
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (error.code === '23505') { // Unique violation
|
|
157
|
+
throw new Error('Duplicate entry')
|
|
158
|
+
}
|
|
159
|
+
if (error.code === '23503') { // Foreign key violation
|
|
160
|
+
throw new Error('Referenced record does not exist')
|
|
161
|
+
}
|
|
162
|
+
throw error
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Migrations
|
|
167
|
+
```typescript
|
|
168
|
+
// Using node-pg-migrate
|
|
169
|
+
import { migrate } from 'node-pg-migrate'
|
|
170
|
+
|
|
171
|
+
await migrate({
|
|
172
|
+
databaseUrl: process.env.DATABASE_URL,
|
|
173
|
+
dir: 'migrations',
|
|
174
|
+
direction: 'up',
|
|
175
|
+
migrationsTable: 'pgmigrations',
|
|
176
|
+
dryRun: false,
|
|
177
|
+
})
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Best Practices
|
|
181
|
+
|
|
182
|
+
✅ **DO:**
|
|
183
|
+
- Use connection pooling (max 20-30 connections)
|
|
184
|
+
- Always use parameterized queries ($1, $2, etc.)
|
|
185
|
+
- Use transactions for multi-step operations
|
|
186
|
+
- Create indexes on frequently queried columns
|
|
187
|
+
- Use EXPLAIN ANALYZE to optimize queries
|
|
188
|
+
- Enable connection pooling (PgBouncer for production)
|
|
189
|
+
- Use SSL in production
|
|
190
|
+
- Set appropriate connection timeouts
|
|
191
|
+
- Monitor connection pool usage
|
|
192
|
+
- Use prepared statements for repeated queries
|
|
193
|
+
|
|
194
|
+
❌ **DON'T:**
|
|
195
|
+
- Use string concatenation for queries (SQL injection risk)
|
|
196
|
+
- Create too many connections (exhaust pool)
|
|
197
|
+
- Skip error handling
|
|
198
|
+
- Ignore connection pool limits
|
|
199
|
+
- Use SELECT * in production (specify columns)
|
|
200
|
+
- Skip indexes on foreign keys
|
|
201
|
+
- Hardcode connection strings
|
|
202
|
+
- Skip SSL in production
|
|
203
|
+
- Ignore query performance
|
|
204
|
+
- Use synchronous queries
|
|
205
|
+
|
|
206
|
+
## Configuration
|
|
207
|
+
|
|
208
|
+
### Environment Variables
|
|
209
|
+
```bash
|
|
210
|
+
DB_HOST=localhost
|
|
211
|
+
DB_PORT=5432
|
|
212
|
+
DB_NAME=myapp
|
|
213
|
+
DB_USER=myuser
|
|
214
|
+
DB_PASSWORD=securepassword
|
|
215
|
+
DATABASE_URL=postgresql://user:password@host:port/database
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Docker Compose
|
|
219
|
+
```yaml
|
|
220
|
+
services:
|
|
221
|
+
postgres:
|
|
222
|
+
image: postgres:16-alpine
|
|
223
|
+
environment:
|
|
224
|
+
POSTGRES_DB: myapp
|
|
225
|
+
POSTGRES_USER: myuser
|
|
226
|
+
POSTGRES_PASSWORD: securepassword
|
|
227
|
+
ports:
|
|
228
|
+
- "5432:5432"
|
|
229
|
+
volumes:
|
|
230
|
+
- postgres_data:/var/lib/postgresql/data
|
|
231
|
+
healthcheck:
|
|
232
|
+
test: ["CMD-SHELL", "pg_isready -U myuser"]
|
|
233
|
+
interval: 10s
|
|
234
|
+
timeout: 5s
|
|
235
|
+
retries: 5
|
|
236
|
+
|
|
237
|
+
volumes:
|
|
238
|
+
postgres_data:
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Prisma Schema
|
|
242
|
+
```prisma
|
|
243
|
+
datasource db {
|
|
244
|
+
provider = "postgresql"
|
|
245
|
+
url = env("DATABASE_URL")
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
model User {
|
|
249
|
+
id Int @id @default(autoincrement())
|
|
250
|
+
email String @unique
|
|
251
|
+
name String?
|
|
252
|
+
createdAt DateTime @default(now())
|
|
253
|
+
posts Post[]
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
model Post {
|
|
257
|
+
id Int @id @default(autoincrement())
|
|
258
|
+
title String
|
|
259
|
+
content String?
|
|
260
|
+
authorId Int
|
|
261
|
+
author User @relation(fields: [authorId], references: [id])
|
|
262
|
+
createdAt DateTime @default(now())
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Performance Optimization
|
|
267
|
+
|
|
268
|
+
### Indexing
|
|
269
|
+
```sql
|
|
270
|
+
-- Single column index
|
|
271
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
272
|
+
|
|
273
|
+
-- Composite index
|
|
274
|
+
CREATE INDEX idx_posts_author_created ON posts(author_id, created_at DESC);
|
|
275
|
+
|
|
276
|
+
-- Partial index
|
|
277
|
+
CREATE INDEX idx_active_users ON users(email) WHERE active = true;
|
|
278
|
+
|
|
279
|
+
-- GIN index for JSONB
|
|
280
|
+
CREATE INDEX idx_products_metadata ON products USING GIN(metadata);
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Query Optimization
|
|
284
|
+
```typescript
|
|
285
|
+
// Use LIMIT and OFFSET for pagination
|
|
286
|
+
const result = await pool.query(
|
|
287
|
+
'SELECT * FROM posts ORDER BY created_at DESC LIMIT $1 OFFSET $2',
|
|
288
|
+
[limit, offset]
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
// Use EXISTS instead of COUNT for existence checks
|
|
292
|
+
const result = await pool.query(
|
|
293
|
+
'SELECT EXISTS(SELECT 1 FROM users WHERE email = $1)',
|
|
294
|
+
[email]
|
|
295
|
+
)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Integration with Development
|
|
299
|
+
|
|
300
|
+
### Testing
|
|
301
|
+
```typescript
|
|
302
|
+
// Use test database
|
|
303
|
+
const testPool = new Pool({
|
|
304
|
+
database: 'myapp_test',
|
|
305
|
+
// ... config
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
// Clean up after tests
|
|
309
|
+
afterEach(async () => {
|
|
310
|
+
await testPool.query('TRUNCATE TABLE users, posts CASCADE')
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
// Use transactions for test isolation
|
|
314
|
+
beforeEach(async () => {
|
|
315
|
+
await testPool.query('BEGIN')
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
afterEach(async () => {
|
|
319
|
+
await testPool.query('ROLLBACK')
|
|
320
|
+
})
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Health Checks
|
|
324
|
+
```typescript
|
|
325
|
+
async function checkDatabaseHealth(): Promise<boolean> {
|
|
326
|
+
try {
|
|
327
|
+
const result = await pool.query('SELECT 1')
|
|
328
|
+
return result.rows.length > 0
|
|
329
|
+
} catch {
|
|
330
|
+
return false
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
<!-- POSTGRESQL:END -->
|
|
336
|
+
|