@evertonferreira96/agents 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. package/.claude/agents/api.md +45 -0
  2. package/.claude/agents/app.md +41 -0
  3. package/.claude/agents/architect.md +49 -0
  4. package/.claude/agents/infra.md +27 -0
  5. package/.claude/agents/product.md +58 -0
  6. package/.claude/agents/quick.md +33 -0
  7. package/.claude/agents/security.md +39 -0
  8. package/.claude/agents/ui.md +54 -0
  9. package/.claude/agents/verifier.md +56 -0
  10. package/.claude/agents/web.md +41 -0
  11. package/.claude/hooks/config-update-check.mjs +14 -0
  12. package/.claude/hooks/context-budget.mjs +51 -0
  13. package/.claude/hooks/graphify-update.sh +16 -0
  14. package/.claude/hooks/guard-bash.sh +64 -0
  15. package/.claude/hooks/orchestrator-guard.sh +49 -0
  16. package/.claude/hooks/post-compact.sh +26 -0
  17. package/.claude/hooks/readonly-guard.sh +54 -0
  18. package/.claude/hooks/stop-verify.sh +52 -0
  19. package/.claude/rules/api.md +21 -0
  20. package/.claude/rules/db.md +9 -0
  21. package/.claude/rules/delivery-diagram.md +16 -0
  22. package/.claude/rules/git-workflow.md +34 -0
  23. package/.claude/rules/graphify.md +3 -0
  24. package/.claude/rules/mobile.md +22 -0
  25. package/.claude/rules/tickets.md +9 -0
  26. package/.claude/rules/ui.md +14 -0
  27. package/.claude/rules/web.md +27 -0
  28. package/.claude/settings.json +114 -0
  29. package/.claude/skills/animate/RECIPES.md +324 -0
  30. package/.claude/skills/animate/SKILL.md +208 -0
  31. package/.claude/skills/animate/agents/openai.yaml +5 -0
  32. package/.claude/skills/animate-expo/RECIPES.md +385 -0
  33. package/.claude/skills/animate-expo/SKILL.md +264 -0
  34. package/.claude/skills/animate-expo/agents/openai.yaml +5 -0
  35. package/.claude/skills/animation-performance/SKILL.md +223 -0
  36. package/.claude/skills/animation-performance/agents/openai.yaml +5 -0
  37. package/.claude/skills/apple-design/SKILL.md +291 -0
  38. package/.claude/skills/apple-design/agents/openai.yaml +5 -0
  39. package/.claude/skills/arch-api/SKILL.md +291 -0
  40. package/.claude/skills/arch-api/agents/openai.yaml +3 -0
  41. package/.claude/skills/arch-api/references/common.md +174 -0
  42. package/.claude/skills/arch-api/references/contract.md +289 -0
  43. package/.claude/skills/arch-api/references/domain.md +301 -0
  44. package/.claude/skills/arch-api/references/endpoints.md +184 -0
  45. package/.claude/skills/arch-api/references/review.md +228 -0
  46. package/.claude/skills/arch-api/references/security.md +151 -0
  47. package/.claude/skills/arch-app/SKILL.md +278 -0
  48. package/.claude/skills/arch-app/agents/openai.yaml +3 -0
  49. package/.claude/skills/arch-app/references/navigation-session.md +257 -0
  50. package/.claude/skills/arch-app/references/review.md +155 -0
  51. package/.claude/skills/arch-app/references/screens.md +214 -0
  52. package/.claude/skills/arch-app/references/services.md +301 -0
  53. package/.claude/skills/arch-app/references/ui-mobile.md +124 -0
  54. package/.claude/skills/arch-db/SKILL.md +181 -0
  55. package/.claude/skills/arch-db/agents/openai.yaml +3 -0
  56. package/.claude/skills/arch-db/references/indexes-queries.md +251 -0
  57. package/.claude/skills/arch-db/references/migrations.md +191 -0
  58. package/.claude/skills/arch-db/references/modeling.md +214 -0
  59. package/.claude/skills/arch-db/references/mysql.md +262 -0
  60. package/.claude/skills/arch-db/references/pooling-ops.md +112 -0
  61. package/.claude/skills/arch-db/references/review.md +143 -0
  62. package/.claude/skills/arch-db/references/transactions-locks.md +141 -0
  63. package/.claude/skills/arch-web/SKILL.md +307 -0
  64. package/.claude/skills/arch-web/agents/openai.yaml +3 -0
  65. package/.claude/skills/arch-web/references/auth-session-env.md +165 -0
  66. package/.claude/skills/arch-web/references/blocks.md +198 -0
  67. package/.claude/skills/arch-web/references/cache.md +124 -0
  68. package/.claude/skills/arch-web/references/review.md +142 -0
  69. package/.claude/skills/arch-web/references/services.md +297 -0
  70. package/.claude/skills/arch-web/references/tests.md +159 -0
  71. package/.claude/skills/arch-web/references/ui-forms.md +143 -0
  72. package/.claude/skills/break-ui/CATALOG.md +135 -0
  73. package/.claude/skills/break-ui/SKILL.md +176 -0
  74. package/.claude/skills/break-ui/agents/openai.yaml +5 -0
  75. package/.claude/skills/brief/SKILL.md +91 -0
  76. package/.claude/skills/brief/agents/openai.yaml +3 -0
  77. package/.claude/skills/diagnosing-bugs/SKILL.md +138 -0
  78. package/.claude/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  79. package/.claude/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  80. package/.claude/skills/emil-design-eng/SKILL.md +675 -0
  81. package/.claude/skills/emil-design-eng/agents/openai.yaml +5 -0
  82. package/.claude/skills/find-animation-opportunities/SKILL.md +141 -0
  83. package/.claude/skills/find-animation-opportunities/agents/openai.yaml +5 -0
  84. package/.claude/skills/graphify/.graphify_version +1 -0
  85. package/.claude/skills/graphify/SKILL.md +742 -0
  86. package/.claude/skills/graphify/agents/openai.yaml +3 -0
  87. package/.claude/skills/graphify/references/add-watch.md +56 -0
  88. package/.claude/skills/graphify/references/exports.md +91 -0
  89. package/.claude/skills/graphify/references/extraction-spec.md +70 -0
  90. package/.claude/skills/graphify/references/github-and-merge.md +46 -0
  91. package/.claude/skills/graphify/references/hooks.md +33 -0
  92. package/.claude/skills/graphify/references/query.md +317 -0
  93. package/.claude/skills/graphify/references/transcribe.md +52 -0
  94. package/.claude/skills/graphify/references/update.md +221 -0
  95. package/.claude/skills/grill-me/SKILL.md +7 -0
  96. package/.claude/skills/grill-me/agents/openai.yaml +5 -0
  97. package/.claude/skills/grill-with-docs/SKILL.md +64 -0
  98. package/.claude/skills/grill-with-docs/agents/openai.yaml +5 -0
  99. package/.claude/skills/grilling/SKILL.md +30 -0
  100. package/.claude/skills/grilling/agents/openai.yaml +3 -0
  101. package/.claude/skills/handoff/SKILL.md +28 -0
  102. package/.claude/skills/handoff/agents/openai.yaml +5 -0
  103. package/.claude/skills/impeccable/SKILL.md +89 -0
  104. package/.claude/skills/impeccable/agents/openai.yaml +5 -0
  105. package/.claude/skills/impeccable/reference/adapt.md +318 -0
  106. package/.claude/skills/impeccable/reference/adapt.native.md +58 -0
  107. package/.claude/skills/impeccable/reference/android.md +46 -0
  108. package/.claude/skills/impeccable/reference/animate.md +89 -0
  109. package/.claude/skills/impeccable/reference/audit.md +137 -0
  110. package/.claude/skills/impeccable/reference/audit.native.md +139 -0
  111. package/.claude/skills/impeccable/reference/bolder.md +33 -0
  112. package/.claude/skills/impeccable/reference/clarify.md +94 -0
  113. package/.claude/skills/impeccable/reference/colorize.md +86 -0
  114. package/.claude/skills/impeccable/reference/component-review.md +63 -0
  115. package/.claude/skills/impeccable/reference/craft-floor.md +44 -0
  116. package/.claude/skills/impeccable/reference/craft.md +5 -0
  117. package/.claude/skills/impeccable/reference/critique.md +809 -0
  118. package/.claude/skills/impeccable/reference/degraded/asset-producer.md +42 -0
  119. package/.claude/skills/impeccable/reference/degraded/documenter.md +24 -0
  120. package/.claude/skills/impeccable/reference/degraded/finish-reviewer.md +38 -0
  121. package/.claude/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  122. package/.claude/skills/impeccable/reference/delight.md +70 -0
  123. package/.claude/skills/impeccable/reference/distill.md +111 -0
  124. package/.claude/skills/impeccable/reference/doctor.md +54 -0
  125. package/.claude/skills/impeccable/reference/document.md +416 -0
  126. package/.claude/skills/impeccable/reference/extract.md +69 -0
  127. package/.claude/skills/impeccable/reference/generate.md +101 -0
  128. package/.claude/skills/impeccable/reference/harden.md +345 -0
  129. package/.claude/skills/impeccable/reference/hooks.md +113 -0
  130. package/.claude/skills/impeccable/reference/init.md +131 -0
  131. package/.claude/skills/impeccable/reference/ios.md +51 -0
  132. package/.claude/skills/impeccable/reference/layout.md +84 -0
  133. package/.claude/skills/impeccable/reference/live-setup.md +104 -0
  134. package/.claude/skills/impeccable/reference/live.md +325 -0
  135. package/.claude/skills/impeccable/reference/mode-operate.md +21 -0
  136. package/.claude/skills/impeccable/reference/mode-persuade.md +19 -0
  137. package/.claude/skills/impeccable/reference/mode-read.md +21 -0
  138. package/.claude/skills/impeccable/reference/new-work.md +154 -0
  139. package/.claude/skills/impeccable/reference/onboard.md +234 -0
  140. package/.claude/skills/impeccable/reference/operate.md +61 -0
  141. package/.claude/skills/impeccable/reference/optimize.md +258 -0
  142. package/.claude/skills/impeccable/reference/overdrive.md +127 -0
  143. package/.claude/skills/impeccable/reference/polish.md +105 -0
  144. package/.claude/skills/impeccable/reference/quieter.md +99 -0
  145. package/.claude/skills/impeccable/reference/region-map.md +26 -0
  146. package/.claude/skills/impeccable/reference/routing.md +24 -0
  147. package/.claude/skills/impeccable/reference/shape.md +59 -0
  148. package/.claude/skills/impeccable/reference/typeset.md +80 -0
  149. package/.claude/skills/impeccable/reference/visualize.md +47 -0
  150. package/.claude/skills/impeccable/scripts/VERSION +1 -0
  151. package/.claude/skills/impeccable/scripts/command-metadata.json +98 -0
  152. package/.claude/skills/impeccable/scripts/data/font-index-failures.json +121 -0
  153. package/.claude/skills/impeccable/scripts/data/font-index.json +1 -0
  154. package/.claude/skills/impeccable/scripts/impeccable +206 -0
  155. package/.claude/skills/impeccable/scripts/impeccable.cmd +214 -0
  156. package/.claude/skills/impeccable/scripts/live-browser-dom.js +281 -0
  157. package/.claude/skills/impeccable/scripts/live-browser-ignores.js +242 -0
  158. package/.claude/skills/impeccable/scripts/live-browser-session.js +148 -0
  159. package/.claude/skills/impeccable/scripts/live-browser.js +13532 -0
  160. package/.claude/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  161. package/.claude/skills/improve-animations/AUDIT.md +115 -0
  162. package/.claude/skills/improve-animations/PLAN-TEMPLATE.md +73 -0
  163. package/.claude/skills/improve-animations/SKILL.md +110 -0
  164. package/.claude/skills/improve-animations/agents/openai.yaml +5 -0
  165. package/.claude/skills/mobile-native/SKILL.md +311 -0
  166. package/.claude/skills/mobile-native/agents/openai.yaml +3 -0
  167. package/.claude/skills/orchestrate/SKILL.md +181 -0
  168. package/.claude/skills/orchestrate/agents/openai.yaml +3 -0
  169. package/.claude/skills/pick-ui-library/SKILL.md +85 -0
  170. package/.claude/skills/pick-ui-library/agents/openai.yaml +5 -0
  171. package/.claude/skills/ponytail/SKILL.md +52 -0
  172. package/.claude/skills/ponytail/agents/openai.yaml +3 -0
  173. package/.claude/skills/ponytail-audit/SKILL.md +103 -0
  174. package/.claude/skills/ponytail-audit/agents/openai.yaml +3 -0
  175. package/.claude/skills/ponytail-debt/SKILL.md +44 -0
  176. package/.claude/skills/ponytail-debt/agents/openai.yaml +3 -0
  177. package/.claude/skills/ponytail-review/SKILL.md +101 -0
  178. package/.claude/skills/ponytail-review/agents/openai.yaml +3 -0
  179. package/.claude/skills/postgres-best-practices/SKILL.md +42 -0
  180. package/.claude/skills/postgres-best-practices/agents/openai.yaml +3 -0
  181. package/.claude/skills/postgres-best-practices/references/backup-restore.md +372 -0
  182. package/.claude/skills/postgres-best-practices/references/bulk-loading.md +315 -0
  183. package/.claude/skills/postgres-best-practices/references/connection-pooling.md +310 -0
  184. package/.claude/skills/postgres-best-practices/references/hot-standby.md +221 -0
  185. package/.claude/skills/postgres-best-practices/references/indexing.md +318 -0
  186. package/.claude/skills/postgres-best-practices/references/logical-replication.md +610 -0
  187. package/.claude/skills/postgres-best-practices/references/major-version-upgrades.md +334 -0
  188. package/.claude/skills/postgres-best-practices/references/performance-diagnostics.md +553 -0
  189. package/.claude/skills/postgres-best-practices/references/query-optimization.md +294 -0
  190. package/.claude/skills/postgres-best-practices/references/query-patterns.md +566 -0
  191. package/.claude/skills/postgres-best-practices/references/schema-design.md +362 -0
  192. package/.claude/skills/postgres-best-practices/references/security-roles.md +489 -0
  193. package/.claude/skills/postgres-best-practices/references/transaction-isolation.md +344 -0
  194. package/.claude/skills/project-docs/SKILL.md +330 -0
  195. package/.claude/skills/project-docs/agents/openai.yaml +3 -0
  196. package/.claude/skills/prototype/PICKER.md +197 -0
  197. package/.claude/skills/prototype/SKILL.md +98 -0
  198. package/.claude/skills/prototype/agents/openai.yaml +5 -0
  199. package/.claude/skills/retro/SKILL.md +43 -0
  200. package/.claude/skills/retro/agents/openai.yaml +5 -0
  201. package/.claude/skills/review/SKILL.md +74 -0
  202. package/.claude/skills/review/agents/openai.yaml +3 -0
  203. package/.claude/skills/review/references/smells.md +23 -0
  204. package/.claude/skills/review-animations/SKILL.md +120 -0
  205. package/.claude/skills/review-animations/STANDARDS.md +187 -0
  206. package/.claude/skills/review-animations/agents/openai.yaml +5 -0
  207. package/.claude/skills/tdd/SKILL.md +38 -0
  208. package/.claude/skills/tdd/agents/openai.yaml +3 -0
  209. package/.claude/skills/tdd/mocking.md +59 -0
  210. package/.claude/skills/tdd/tests.md +77 -0
  211. package/.claude/skills/triage/SKILL.md +58 -0
  212. package/.claude/skills/triage/agents/openai.yaml +3 -0
  213. package/.claude/skills/ui-ux-pro-max/SKILL.md +378 -0
  214. package/.claude/skills/ui-ux-pro-max/agents/openai.yaml +5 -0
  215. package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
  216. package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
  217. package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
  218. package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
  219. package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
  220. package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  221. package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  222. package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  223. package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  224. package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  225. package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  226. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  227. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  228. package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  229. package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  230. package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  231. package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  232. package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  233. package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  234. package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
  235. package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
  236. package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  237. package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  238. package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  239. package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
  240. package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  241. package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
  242. package/.claude/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  243. package/.claude/skills/writing-for-agents/SKILL.md +81 -0
  244. package/.claude/skills/writing-for-agents/agents/openai.yaml +3 -0
  245. package/.worktreeinclude +3 -0
  246. package/AGENTS.md +44 -0
  247. package/README.md +14 -2
  248. package/VERSION +1 -0
  249. package/bin/agents.mjs +45 -0
  250. package/docs/adr/README.md +31 -0
  251. package/docs/brief-template.md +3 -0
  252. package/docs/plans/README.md +73 -0
  253. package/package.json +46 -4
  254. package/scripts/bootstrap.mjs +188 -0
  255. package/scripts/check-catalog.mjs +43 -0
  256. package/scripts/skills-update.mjs +51 -0
  257. package/skills-lock.json +269 -0
  258. package/templates/CLAUDE.project.md +41 -0
@@ -0,0 +1,310 @@
1
+ # Connection Pooling Reference
2
+
3
+ ## Contents
4
+ - Why connection pooling matters
5
+ - PgBouncer configuration
6
+ - Pool modes
7
+ - Prepared statement handling
8
+ - Monitoring and diagnostics
9
+ - Application-side pooling
10
+
11
+ ## Why Connection Pooling Matters
12
+
13
+ Each PostgreSQL connection spawns a dedicated backend process (~5-10 MB of memory). Without pooling:
14
+
15
+ - 500 application instances × 10 connections each = 5,000 backend processes
16
+ - Memory: 5,000 × 10 MB = ~50 GB just for connection overhead
17
+ - Context switching degrades performance above a few hundred active backends
18
+ - `max_connections` must be set high, wasting shared memory
19
+
20
+ A connection pooler sits between the application and PostgreSQL, multiplexing many client connections onto fewer server connections.
21
+
22
+ ### Connection Overhead
23
+
24
+ ```sql
25
+ -- Current connections vs. limit
26
+ SELECT
27
+ count(*) AS current,
28
+ (SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max,
29
+ (SELECT setting::int FROM pg_settings WHERE name = 'superuser_reserved_connections') AS reserved
30
+ FROM pg_stat_activity;
31
+
32
+ -- Potential per-operation and per-session memory settings
33
+ SELECT
34
+ name,
35
+ current_setting(name) AS configured_value,
36
+ pg_size_bytes(current_setting(name)) AS configured_bytes
37
+ FROM pg_settings
38
+ WHERE name IN ('work_mem', 'temp_buffers')
39
+ ORDER BY name;
40
+ ```
41
+
42
+ These are not baseline allocations per backend. `work_mem` can be consumed by multiple query operations, while `temp_buffers` is allocated lazily when a session uses temporary tables.
43
+
44
+ ## PgBouncer Configuration
45
+
46
+ PgBouncer is the most widely used connection pooler for PostgreSQL.
47
+
48
+ ### Essential pgbouncer.ini Settings
49
+
50
+ ```ini
51
+ [databases]
52
+ mydb = host=127.0.0.1 port=5432 dbname=mydb
53
+
54
+ [pgbouncer]
55
+ listen_addr = 0.0.0.0
56
+ listen_port = 6432
57
+ auth_type = scram-sha-256
58
+ auth_file = /etc/pgbouncer/userlist.txt
59
+
60
+ # Pool sizing
61
+ pool_mode = transaction
62
+ default_pool_size = 20
63
+ min_pool_size = 5
64
+ max_client_conn = 1000
65
+ max_db_connections = 50
66
+
67
+ # Timeouts
68
+ server_idle_timeout = 300
69
+ client_idle_timeout = 0
70
+ query_timeout = 0
71
+ query_wait_timeout = 120
72
+ server_login_retry = 15
73
+
74
+ # Logging
75
+ log_connections = 0
76
+ log_disconnections = 0
77
+ stats_period = 60
78
+ ```
79
+
80
+ ### Key Parameters
81
+
82
+ | Parameter | Recommended | Purpose |
83
+ |-----------|------------|---------|
84
+ | `default_pool_size` | 20-50 | Server connections per user/database pair |
85
+ | `min_pool_size` | 5 | Minimum idle server connections to keep open |
86
+ | `max_client_conn` | 1000-10000 | Max client connections PgBouncer accepts |
87
+ | `max_db_connections` | 50-100 | Hard cap on server connections per database |
88
+ | `reserve_pool_size` | 5 | Extra connections for burst traffic |
89
+ | `reserve_pool_timeout` | 3 | Seconds before using reserve pool |
90
+ | `query_wait_timeout` | 120 | Max time a client waits for a server connection |
91
+
92
+ ### Sizing Rule of Thumb
93
+
94
+ **Server connections**: Set `default_pool_size` to roughly 2-4x the number of CPU cores on the database server. More connections don't help — they just increase lock contention and context switching.
95
+
96
+ **Client connections**: Set `max_client_conn` high enough for all application instances. PgBouncer handles thousands of idle client connections with minimal memory.
97
+
98
+ ```
99
+ App instances (500 clients) ──→ PgBouncer (max_client_conn=1000) ──→ PostgreSQL (pool_size=20)
100
+ ```
101
+
102
+ ## Pool Modes
103
+
104
+ ### Transaction Mode (Recommended for Most Applications)
105
+
106
+ ```ini
107
+ pool_mode = transaction
108
+ ```
109
+
110
+ Server connection is assigned when a transaction begins and returned when it commits/rolls back. Between transactions, the connection is available to other clients.
111
+
112
+ **Compatible with**: Standard SQL, parameterized queries, most ORMs.
113
+
114
+ **NOT compatible with** (session-level features):
115
+ - `SET` / `RESET` (use `SET LOCAL` inside a transaction instead)
116
+ - `LISTEN` / `NOTIFY`
117
+ - SQL-level `PREPARE` / `DEALLOCATE` (use protocol-level prepared statements)
118
+ - `DECLARE ... WITH HOLD` cursors
119
+ - Temporary tables with `ON COMMIT PRESERVE ROWS`
120
+ - Session-level advisory locks (`pg_advisory_lock` — use `pg_advisory_xact_lock` instead)
121
+ - `LOAD` statement
122
+
123
+ ### Session Mode
124
+
125
+ ```ini
126
+ pool_mode = session
127
+ ```
128
+
129
+ Server connection is held for the entire client session. Compatible with all PostgreSQL features but offers less multiplexing benefit.
130
+
131
+ **Use when**: Application relies on session-level features (temp tables, LISTEN/NOTIFY, SET parameters).
132
+
133
+ ### Statement Mode
134
+
135
+ ```ini
136
+ pool_mode = statement
137
+ ```
138
+
139
+ Server connection released after every statement. Maximum multiplexing but **incompatible with multi-statement transactions**.
140
+
141
+ **Use when**: Application only runs autocommit single statements (rare).
142
+
143
+ ### Choosing a Mode
144
+
145
+ | Application pattern | Recommended mode |
146
+ |--------------------|-----------------|
147
+ | Web apps, APIs, serverless | Transaction |
148
+ | Applications using LISTEN/NOTIFY | Session |
149
+ | Applications using temp tables across transactions | Session |
150
+ | Applications with SET session variables | Session (or refactor to `SET LOCAL`) |
151
+ | Simple autocommit queries | Statement |
152
+
153
+ ## Prepared Statement Handling
154
+
155
+ ### The Problem
156
+
157
+ SQL-level `PREPARE`/`EXECUTE` creates server-side prepared statements tied to a session. In transaction mode, the next transaction may use a different server connection where the prepared statement doesn't exist.
158
+
159
+ ### Solutions
160
+
161
+ **Protocol-level prepared statements**: Most modern drivers use the PostgreSQL wire protocol's `Parse`/`Bind`/`Execute` messages, which PgBouncer (1.21+) can handle:
162
+
163
+ ```ini
164
+ # PgBouncer 1.21+
165
+ max_prepared_statements = 100 # per server connection
166
+ ```
167
+
168
+ **Driver-level configuration** to avoid SQL-level PREPARE:
169
+
170
+ ```python
171
+ # Python psycopg: uses protocol-level by default — no change needed
172
+ ```
173
+
174
+ ```javascript
175
+ // Node.js pg: protocol-level by default
176
+ const pool = new Pool({ ...config });
177
+ // For explicit control:
178
+ // statement_timeout via SET LOCAL, not SET
179
+ ```
180
+
181
+ ```java
182
+ // JDBC: protocol-level by default with prepareThreshold
183
+ // ?prepareThreshold=5 (default: 5 uses before server-side prepare)
184
+ // ?prepareThreshold=0 (disable server-side prepare entirely)
185
+ ```
186
+
187
+ ```ruby
188
+ # Ruby pg: protocol-level by default
189
+ # ActiveRecord: no special config needed
190
+ ```
191
+
192
+ ## Monitoring and Diagnostics
193
+
194
+ ### PgBouncer Admin Console
195
+
196
+ Connect to PgBouncer's admin port:
197
+
198
+ ```bash
199
+ psql -h 127.0.0.1 -p 6432 -U pgbouncer pgbouncer
200
+ ```
201
+
202
+ ### Key Commands
203
+
204
+ ```text
205
+ -- Pool status (most useful)
206
+ SHOW POOLS;
207
+ -- Columns: database, user, cl_active, cl_waiting, sv_active, sv_idle, sv_used, pool_mode
208
+
209
+ -- Active client and server connections
210
+ SHOW CLIENTS;
211
+ SHOW SERVERS;
212
+
213
+ -- Aggregate statistics
214
+ SHOW STATS;
215
+ -- Columns: total_xact_count, total_query_count, avg_xact_time, avg_query_time
216
+
217
+ -- Configuration
218
+ SHOW CONFIG;
219
+
220
+ -- Memory usage
221
+ SHOW MEM;
222
+ ```
223
+
224
+ These commands use PgBouncer's admin protocol and fail if sent directly to PostgreSQL.
225
+
226
+ ### What to Watch
227
+
228
+ | Metric | Healthy | Problem |
229
+ |--------|---------|---------|
230
+ | `cl_waiting` | 0 | > 0 = clients waiting for server connections |
231
+ | `sv_active` | < pool_size | = pool_size = pool exhausted |
232
+ | `sv_idle` | > 0 | 0 = no spare connections |
233
+ | `avg_xact_time` | < 100ms | High = long transactions hogging connections |
234
+ | `avg_wait_time` | 0 | > 0 = pool too small or transactions too long |
235
+
236
+ ### Common Issues
237
+
238
+ **Clients waiting (`cl_waiting > 0`)**:
239
+ 1. Check for long-running transactions: `SELECT * FROM pg_stat_activity WHERE state = 'idle in transaction';`
240
+ 2. Increase `default_pool_size` (but diminishing returns beyond ~4x CPU cores)
241
+ 3. Check if `query_wait_timeout` is being hit (errors in application logs)
242
+
243
+ **Server connections not being returned**:
244
+ 1. `idle in transaction` sessions hold connections — set `idle_in_transaction_session_timeout` in PostgreSQL
245
+ 2. Application not committing/rolling back — add explicit transaction management
246
+
247
+ ## Application-Side Pooling
248
+
249
+ When PgBouncer isn't available, most drivers offer built-in connection pooling.
250
+
251
+ ### Recommended Pool Sizes
252
+
253
+ **Per application instance**: 5-20 connections. Start low, increase only if you see connection wait times.
254
+
255
+ **Total across all instances**: Should not exceed ~4x database CPU cores for active connections.
256
+
257
+ ### Common Driver Configuration
258
+
259
+ ```python
260
+ # Python (psycopg pool)
261
+ from psycopg_pool import ConnectionPool
262
+
263
+ pool = ConnectionPool(
264
+ conninfo="host=db port=5432 dbname=mydb",
265
+ min_size=5,
266
+ max_size=20,
267
+ max_idle=300, # close idle connections after 5 min
268
+ )
269
+
270
+ with pool.connection() as conn:
271
+ conn.execute("SELECT ...")
272
+ ```
273
+
274
+ ```javascript
275
+ // Node.js (pg)
276
+ const { Pool } = require('pg');
277
+ const pool = new Pool({
278
+ host: 'db',
279
+ database: 'mydb',
280
+ max: 20, // max connections in pool
281
+ idleTimeoutMillis: 30000,
282
+ connectionTimeoutMillis: 5000,
283
+ });
284
+
285
+ const result = await pool.query('SELECT ...');
286
+ ```
287
+
288
+ ```java
289
+ // Java (HikariCP)
290
+ HikariConfig config = new HikariConfig();
291
+ config.setJdbcUrl("jdbc:postgresql://db:5432/mydb");
292
+ config.setMaximumPoolSize(20);
293
+ config.setMinimumIdle(5);
294
+ config.setIdleTimeout(300000);
295
+ config.setConnectionTimeout(5000);
296
+
297
+ HikariDataSource ds = new HikariDataSource(config);
298
+ ```
299
+
300
+ ### Application Pool + PgBouncer
301
+
302
+ You can stack both. Each application instance pools locally (5-10 connections), and PgBouncer pools across all instances:
303
+
304
+ ```
305
+ App1 (pool: 10) ──┐
306
+ App2 (pool: 10) ──┼──→ PgBouncer (pool: 30) ──→ PostgreSQL
307
+ App3 (pool: 10) ──┘
308
+ ```
309
+
310
+ Set application pool sizes low when using PgBouncer — the point is to reduce total connections, not add them up.
@@ -0,0 +1,221 @@
1
+ # Hot Standby & Read Replicas Reference
2
+
3
+ ## Contents
4
+ - Streaming replication overview
5
+ - Hot standby configuration
6
+ - Monitoring replication lag
7
+ - Replication conflicts
8
+ - Synchronous vs asynchronous replication
9
+ - Promoting a standby
10
+
11
+ ## Streaming Replication Overview
12
+
13
+ Physical (streaming) replication creates an exact copy of the primary database on one or more standby servers. Unlike logical replication, it replicates the entire cluster (all databases, all objects) at the WAL level.
14
+
15
+ **Hot standby** allows read-only queries on the standby while it continuously replays WAL from the primary. This is the standard mechanism for PostgreSQL read replicas.
16
+
17
+ ### Key Differences from Logical Replication
18
+
19
+ | Aspect | Physical (streaming) | Logical |
20
+ |--------|---------------------|---------|
21
+ | Scope | Entire cluster | Selected tables |
22
+ | PG versions | Must match major version | Can differ |
23
+ | Standby writable? | No (read-only) | Yes (for non-replicated tables) |
24
+ | DDL replicated? | Yes (via WAL) | No |
25
+ | Use case | HA, read replicas | CDC, selective sync, cross-version migration |
26
+
27
+ ## Hot Standby Configuration
28
+
29
+ ### On the Primary
30
+
31
+ ```sql
32
+ -- Check current settings
33
+ SHOW wal_level; -- must be 'replica' or 'logical'
34
+ SHOW max_wal_senders; -- must have available sender slots
35
+ SHOW max_replication_slots; -- one per standby for slot-based replication
36
+ ```
37
+
38
+ Key settings (in `postgresql.conf`):
39
+ - `wal_level = replica` (default)
40
+ - `max_wal_senders = 10` (enough for all standbys)
41
+ - `max_replication_slots = 10` (optional but recommended — prevents WAL removal before standby catches up)
42
+
43
+ ### On the Standby
44
+
45
+ Key settings:
46
+ - `hot_standby = on` (allows read queries during recovery — default)
47
+ - `primary_conninfo = 'host=primary_host user=repl_user ...'` (connection to primary)
48
+ - `primary_slot_name = 'standby_slot'` (optional — use a replication slot)
49
+
50
+ ### Replication Slots (Recommended)
51
+
52
+ Slots prevent the primary from removing WAL segments before the standby has replayed them:
53
+
54
+ ```sql
55
+ -- On the primary: create a physical replication slot
56
+ SELECT pg_create_physical_replication_slot('standby1_slot');
57
+
58
+ -- List slots
59
+ SELECT slot_name, slot_type, active, restart_lsn
60
+ FROM pg_replication_slots;
61
+
62
+ -- Drop a slot (if standby is permanently removed)
63
+ SELECT pg_drop_replication_slot('standby1_slot');
64
+ ```
65
+
66
+ **Warning**: An inactive slot causes WAL to accumulate indefinitely on the primary, potentially filling the disk.
67
+
68
+ ## Monitoring Replication Lag
69
+
70
+ ### On the Primary: pg_stat_replication
71
+
72
+ ```sql
73
+ SELECT
74
+ pid,
75
+ application_name,
76
+ client_addr,
77
+ state,
78
+ sent_lsn,
79
+ write_lsn,
80
+ flush_lsn,
81
+ replay_lsn,
82
+ pg_size_pretty(pg_wal_lsn_diff(sent_lsn, replay_lsn)) AS replay_lag,
83
+ pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn)) AS send_lag,
84
+ write_lag,
85
+ flush_lag,
86
+ replay_lag AS replay_lag_time
87
+ FROM pg_stat_replication;
88
+ ```
89
+
90
+ **LSN progression**: `pg_current_wal_lsn()` → `sent_lsn` → `write_lsn` → `flush_lsn` → `replay_lsn`. The gap between any two is a measure of lag at that stage.
91
+
92
+ ### On the Standby: pg_stat_wal_receiver
93
+
94
+ ```sql
95
+ SELECT
96
+ status,
97
+ written_lsn,
98
+ flushed_lsn,
99
+ latest_end_lsn,
100
+ latest_end_time,
101
+ slot_name,
102
+ conninfo
103
+ FROM pg_stat_wal_receiver;
104
+ ```
105
+
106
+ ### On the Standby: Lag in Seconds
107
+
108
+ ```sql
109
+ -- How far behind is the standby?
110
+ SELECT
111
+ now() - pg_last_xact_replay_timestamp() AS replay_lag,
112
+ pg_last_wal_receive_lsn() AS received_lsn,
113
+ pg_last_wal_replay_lsn() AS replayed_lsn,
114
+ pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) AS replay_lag_bytes;
115
+ ```
116
+
117
+ **Caveat**: `pg_last_xact_replay_timestamp()` only updates when transactions are replayed. On an idle primary, it may show a large lag even though the standby is fully caught up. Check `received_lsn = replayed_lsn` for actual status.
118
+
119
+ ### Is the Standby in Recovery?
120
+
121
+ ```sql
122
+ -- Returns true on a standby, false on a primary
123
+ SELECT pg_is_in_recovery();
124
+ ```
125
+
126
+ ## Replication Conflicts
127
+
128
+ On a hot standby, long-running read queries can conflict with WAL replay. When replay needs to apply changes that conflict with an active query (e.g., dropping a table, vacuuming rows the query is reading), PostgreSQL must choose: wait for the query or cancel it.
129
+
130
+ ### max_standby_streaming_delay
131
+
132
+ Controls how long the standby waits for conflicting queries before cancelling them:
133
+
134
+ ```sql
135
+ SHOW max_standby_streaming_delay; -- default: 30s
136
+ ```
137
+
138
+ - `30s` (default): Standby waits up to 30 seconds, then cancels conflicting queries
139
+ - `-1`: Wait forever (replay pauses until the query finishes — can cause unbounded lag)
140
+ - `0`: Cancel conflicting queries immediately (minimal lag, but queries may fail)
141
+
142
+ ### max_standby_archive_delay
143
+
144
+ Same concept but for WAL segments being replayed from archive (rather than streaming):
145
+
146
+ ```sql
147
+ SHOW max_standby_archive_delay; -- default: 30s
148
+ ```
149
+
150
+ ### The Common Error
151
+
152
+ When a query on the standby is cancelled due to a conflict:
153
+
154
+ ```
155
+ ERROR: canceling statement due to conflict with recovery
156
+ DETAIL: User was holding shared buffer pin for too long.
157
+ ```
158
+
159
+ **Solutions (in order of preference):**
160
+ 1. Keep queries on the standby short
161
+ 2. Increase `max_standby_streaming_delay` (trades lag for query stability)
162
+ 3. Enable `hot_standby_feedback` (see below)
163
+ 4. Use a logical replica instead of hot standby for long-running analytics
164
+
165
+ ### hot_standby_feedback
166
+
167
+ When enabled, the standby informs the primary about which rows it still needs, preventing the primary's VACUUM from removing them:
168
+
169
+ ```sql
170
+ SHOW hot_standby_feedback; -- default: off
171
+ ```
172
+
173
+ **Pros**: Eliminates most replication conflicts — long queries on the standby won't be cancelled.
174
+
175
+ **Cons**: Can cause table bloat on the primary because VACUUM can't remove dead rows that the standby still references.
176
+
177
+ **Recommendation**: Enable only if you have long-running analytical queries on the standby and can tolerate some extra bloat on the primary.
178
+
179
+ ## Synchronous vs Asynchronous Replication
180
+
181
+ ### Asynchronous (Default)
182
+
183
+ The primary doesn't wait for standby acknowledgment before committing. Fastest, but a primary failure can lose recently committed transactions not yet replicated.
184
+
185
+ ### Synchronous
186
+
187
+ The primary waits for at least one standby to confirm before returning commit success:
188
+
189
+ ```sql
190
+ -- On the primary
191
+ SHOW synchronous_standby_names; -- e.g., 'standby1'
192
+ SHOW synchronous_commit; -- 'on', 'remote_write', 'remote_apply', etc.
193
+ ```
194
+
195
+ Synchronous commit levels:
196
+
197
+ | Level | Primary waits for | Durability | Latency impact |
198
+ |-------|-------------------|------------|----------------|
199
+ | `on` (default with sync standbys) | Standby WAL flush | Strong | Moderate |
200
+ | `remote_write` | Standby WAL write (not fsync) | Good | Lower |
201
+ | `remote_apply` | Standby WAL replay | Strongest (read-your-writes on standby) | Highest |
202
+ | `local` | Local WAL flush only | Primary only | None |
203
+ | `off` | Nothing | Weakest | None |
204
+
205
+ ## Promoting a Standby
206
+
207
+ To promote a standby to become the new primary (failover):
208
+
209
+ ```sql
210
+ -- On the standby:
211
+ SELECT pg_promote();
212
+
213
+ -- Or from the command line:
214
+ -- pg_ctl promote -D /path/to/data
215
+ ```
216
+
217
+ After promotion:
218
+ - The standby stops replay and opens for writes
219
+ - Applications must be redirected to the new primary
220
+ - Other standbys must be reconfigured to follow the new primary
221
+ - The old primary must not be restarted without reconfiguring (risk of split-brain)