@wazir-dev/cli 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.
Files changed (629) hide show
  1. package/AGENTS.md +111 -0
  2. package/CHANGELOG.md +14 -0
  3. package/CONTRIBUTING.md +101 -0
  4. package/LICENSE +21 -0
  5. package/README.md +314 -0
  6. package/assets/composition-engine.mmd +34 -0
  7. package/assets/demo-script.sh +17 -0
  8. package/assets/logo-dark.svg +14 -0
  9. package/assets/logo.svg +14 -0
  10. package/assets/pipeline.mmd +39 -0
  11. package/assets/record-demo.sh +51 -0
  12. package/docs/README.md +51 -0
  13. package/docs/adapters/context-mode.md +60 -0
  14. package/docs/concepts/architecture.md +87 -0
  15. package/docs/concepts/artifact-model.md +60 -0
  16. package/docs/concepts/composition-engine.md +36 -0
  17. package/docs/concepts/indexing-and-recall.md +160 -0
  18. package/docs/concepts/observability.md +41 -0
  19. package/docs/concepts/roles-and-workflows.md +59 -0
  20. package/docs/concepts/terminology-policy.md +27 -0
  21. package/docs/getting-started/01-installation.md +78 -0
  22. package/docs/getting-started/02-first-run.md +102 -0
  23. package/docs/getting-started/03-adding-to-project.md +15 -0
  24. package/docs/getting-started/04-host-setup.md +15 -0
  25. package/docs/guides/ci-integration.md +15 -0
  26. package/docs/guides/creating-skills.md +15 -0
  27. package/docs/guides/expertise-module-authoring.md +15 -0
  28. package/docs/guides/hook-development.md +15 -0
  29. package/docs/guides/memory-and-learnings.md +34 -0
  30. package/docs/guides/multi-host-export.md +15 -0
  31. package/docs/guides/troubleshooting.md +101 -0
  32. package/docs/guides/writing-custom-roles.md +15 -0
  33. package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
  34. package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
  35. package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
  36. package/docs/readmes/INDEX.md +99 -0
  37. package/docs/readmes/features/expertise/README.md +171 -0
  38. package/docs/readmes/features/exports/README.md +222 -0
  39. package/docs/readmes/features/hooks/README.md +103 -0
  40. package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
  41. package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
  42. package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
  43. package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
  44. package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
  45. package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
  46. package/docs/readmes/features/hooks/session-start.md +119 -0
  47. package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
  48. package/docs/readmes/features/roles/README.md +157 -0
  49. package/docs/readmes/features/roles/clarifier.md +152 -0
  50. package/docs/readmes/features/roles/content-author.md +190 -0
  51. package/docs/readmes/features/roles/designer.md +193 -0
  52. package/docs/readmes/features/roles/executor.md +184 -0
  53. package/docs/readmes/features/roles/learner.md +210 -0
  54. package/docs/readmes/features/roles/planner.md +182 -0
  55. package/docs/readmes/features/roles/researcher.md +164 -0
  56. package/docs/readmes/features/roles/reviewer.md +184 -0
  57. package/docs/readmes/features/roles/specifier.md +162 -0
  58. package/docs/readmes/features/roles/verifier.md +215 -0
  59. package/docs/readmes/features/schemas/README.md +178 -0
  60. package/docs/readmes/features/skills/README.md +63 -0
  61. package/docs/readmes/features/skills/brainstorming.md +96 -0
  62. package/docs/readmes/features/skills/debugging.md +148 -0
  63. package/docs/readmes/features/skills/design.md +120 -0
  64. package/docs/readmes/features/skills/prepare-next.md +109 -0
  65. package/docs/readmes/features/skills/run-audit.md +159 -0
  66. package/docs/readmes/features/skills/scan-project.md +109 -0
  67. package/docs/readmes/features/skills/self-audit.md +176 -0
  68. package/docs/readmes/features/skills/tdd.md +137 -0
  69. package/docs/readmes/features/skills/using-skills.md +92 -0
  70. package/docs/readmes/features/skills/verification.md +120 -0
  71. package/docs/readmes/features/skills/writing-plans.md +104 -0
  72. package/docs/readmes/features/tooling/README.md +320 -0
  73. package/docs/readmes/features/workflows/README.md +186 -0
  74. package/docs/readmes/features/workflows/author.md +181 -0
  75. package/docs/readmes/features/workflows/clarify.md +154 -0
  76. package/docs/readmes/features/workflows/design-review.md +171 -0
  77. package/docs/readmes/features/workflows/design.md +169 -0
  78. package/docs/readmes/features/workflows/discover.md +162 -0
  79. package/docs/readmes/features/workflows/execute.md +173 -0
  80. package/docs/readmes/features/workflows/learn.md +167 -0
  81. package/docs/readmes/features/workflows/plan-review.md +165 -0
  82. package/docs/readmes/features/workflows/plan.md +170 -0
  83. package/docs/readmes/features/workflows/prepare-next.md +167 -0
  84. package/docs/readmes/features/workflows/review.md +169 -0
  85. package/docs/readmes/features/workflows/run-audit.md +191 -0
  86. package/docs/readmes/features/workflows/spec-challenge.md +159 -0
  87. package/docs/readmes/features/workflows/specify.md +160 -0
  88. package/docs/readmes/features/workflows/verify.md +177 -0
  89. package/docs/readmes/packages/README.md +50 -0
  90. package/docs/readmes/packages/ajv.md +117 -0
  91. package/docs/readmes/packages/context-mode.md +118 -0
  92. package/docs/readmes/packages/gray-matter.md +116 -0
  93. package/docs/readmes/packages/node-test.md +137 -0
  94. package/docs/readmes/packages/yaml.md +112 -0
  95. package/docs/reference/configuration-reference.md +159 -0
  96. package/docs/reference/expertise-index.md +52 -0
  97. package/docs/reference/git-flow.md +43 -0
  98. package/docs/reference/hooks.md +87 -0
  99. package/docs/reference/host-exports.md +50 -0
  100. package/docs/reference/launch-checklist.md +172 -0
  101. package/docs/reference/marketplace-listings.md +76 -0
  102. package/docs/reference/release-process.md +34 -0
  103. package/docs/reference/roles-reference.md +77 -0
  104. package/docs/reference/skills.md +33 -0
  105. package/docs/reference/templates.md +29 -0
  106. package/docs/reference/tooling-cli.md +94 -0
  107. package/docs/truth-claims.yaml +222 -0
  108. package/expertise/PROGRESS.md +63 -0
  109. package/expertise/README.md +18 -0
  110. package/expertise/antipatterns/PROGRESS.md +56 -0
  111. package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
  112. package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
  113. package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
  114. package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
  115. package/expertise/antipatterns/backend/index.md +24 -0
  116. package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
  117. package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
  118. package/expertise/antipatterns/code/async-antipatterns.md +622 -0
  119. package/expertise/antipatterns/code/code-smells.md +1186 -0
  120. package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
  121. package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
  122. package/expertise/antipatterns/code/index.md +27 -0
  123. package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
  124. package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
  125. package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
  126. package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
  127. package/expertise/antipatterns/design/dark-patterns.md +1121 -0
  128. package/expertise/antipatterns/design/index.md +22 -0
  129. package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
  130. package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
  131. package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
  132. package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
  133. package/expertise/antipatterns/frontend/index.md +23 -0
  134. package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
  135. package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
  136. package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
  137. package/expertise/antipatterns/index.md +31 -0
  138. package/expertise/antipatterns/performance/index.md +20 -0
  139. package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
  140. package/expertise/antipatterns/performance/premature-optimization.md +623 -0
  141. package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
  142. package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
  143. package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
  144. package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
  145. package/expertise/antipatterns/process/index.md +23 -0
  146. package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
  147. package/expertise/antipatterns/security/index.md +20 -0
  148. package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
  149. package/expertise/antipatterns/security/security-theater.md +843 -0
  150. package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
  151. package/expertise/architecture/PROGRESS.md +70 -0
  152. package/expertise/architecture/data/caching-architecture.md +671 -0
  153. package/expertise/architecture/data/data-consistency.md +574 -0
  154. package/expertise/architecture/data/data-modeling.md +536 -0
  155. package/expertise/architecture/data/event-streams-and-queues.md +634 -0
  156. package/expertise/architecture/data/index.md +25 -0
  157. package/expertise/architecture/data/search-architecture.md +663 -0
  158. package/expertise/architecture/data/sql-vs-nosql.md +708 -0
  159. package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
  160. package/expertise/architecture/decisions/build-vs-buy.md +616 -0
  161. package/expertise/architecture/decisions/index.md +23 -0
  162. package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
  163. package/expertise/architecture/decisions/technology-selection.md +616 -0
  164. package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
  165. package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
  166. package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
  167. package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
  168. package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
  169. package/expertise/architecture/distributed/index.md +25 -0
  170. package/expertise/architecture/distributed/saga-pattern.md +797 -0
  171. package/expertise/architecture/foundations/architectural-thinking.md +460 -0
  172. package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
  173. package/expertise/architecture/foundations/design-principles-solid.md +649 -0
  174. package/expertise/architecture/foundations/domain-driven-design.md +719 -0
  175. package/expertise/architecture/foundations/index.md +25 -0
  176. package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
  177. package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
  178. package/expertise/architecture/index.md +34 -0
  179. package/expertise/architecture/integration/api-design-graphql.md +638 -0
  180. package/expertise/architecture/integration/api-design-grpc.md +804 -0
  181. package/expertise/architecture/integration/api-design-rest.md +892 -0
  182. package/expertise/architecture/integration/index.md +25 -0
  183. package/expertise/architecture/integration/third-party-integration.md +795 -0
  184. package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
  185. package/expertise/architecture/integration/websockets-realtime.md +791 -0
  186. package/expertise/architecture/mobile-architecture/index.md +22 -0
  187. package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
  188. package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
  189. package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
  190. package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
  191. package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
  192. package/expertise/architecture/patterns/event-driven.md +797 -0
  193. package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
  194. package/expertise/architecture/patterns/index.md +27 -0
  195. package/expertise/architecture/patterns/layered-architecture.md +736 -0
  196. package/expertise/architecture/patterns/microservices.md +753 -0
  197. package/expertise/architecture/patterns/modular-monolith.md +692 -0
  198. package/expertise/architecture/patterns/monolith.md +626 -0
  199. package/expertise/architecture/patterns/plugin-architecture.md +735 -0
  200. package/expertise/architecture/patterns/serverless.md +780 -0
  201. package/expertise/architecture/scaling/database-scaling.md +615 -0
  202. package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
  203. package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
  204. package/expertise/architecture/scaling/index.md +24 -0
  205. package/expertise/architecture/scaling/multi-tenancy.md +800 -0
  206. package/expertise/architecture/scaling/stateless-design.md +787 -0
  207. package/expertise/backend/embedded-firmware.md +625 -0
  208. package/expertise/backend/go.md +853 -0
  209. package/expertise/backend/index.md +24 -0
  210. package/expertise/backend/java-spring.md +448 -0
  211. package/expertise/backend/node-typescript.md +625 -0
  212. package/expertise/backend/python-fastapi.md +724 -0
  213. package/expertise/backend/rust.md +458 -0
  214. package/expertise/backend/solidity.md +711 -0
  215. package/expertise/composition-map.yaml +443 -0
  216. package/expertise/content/foundations/content-modeling.md +395 -0
  217. package/expertise/content/foundations/editorial-standards.md +449 -0
  218. package/expertise/content/foundations/index.md +24 -0
  219. package/expertise/content/foundations/microcopy.md +455 -0
  220. package/expertise/content/foundations/terminology-governance.md +509 -0
  221. package/expertise/content/index.md +34 -0
  222. package/expertise/content/patterns/accessibility-copy.md +518 -0
  223. package/expertise/content/patterns/index.md +24 -0
  224. package/expertise/content/patterns/notification-content.md +433 -0
  225. package/expertise/content/patterns/sample-content.md +486 -0
  226. package/expertise/content/patterns/state-copy.md +439 -0
  227. package/expertise/design/PROGRESS.md +58 -0
  228. package/expertise/design/disciplines/dark-mode-theming.md +577 -0
  229. package/expertise/design/disciplines/design-systems.md +595 -0
  230. package/expertise/design/disciplines/index.md +25 -0
  231. package/expertise/design/disciplines/information-architecture.md +800 -0
  232. package/expertise/design/disciplines/interaction-design.md +788 -0
  233. package/expertise/design/disciplines/responsive-design.md +552 -0
  234. package/expertise/design/disciplines/usability-testing.md +516 -0
  235. package/expertise/design/disciplines/user-research.md +792 -0
  236. package/expertise/design/foundations/accessibility-design.md +796 -0
  237. package/expertise/design/foundations/color-theory.md +797 -0
  238. package/expertise/design/foundations/iconography.md +795 -0
  239. package/expertise/design/foundations/index.md +26 -0
  240. package/expertise/design/foundations/motion-and-animation.md +653 -0
  241. package/expertise/design/foundations/rtl-design.md +585 -0
  242. package/expertise/design/foundations/spacing-and-layout.md +607 -0
  243. package/expertise/design/foundations/typography.md +800 -0
  244. package/expertise/design/foundations/visual-hierarchy.md +761 -0
  245. package/expertise/design/index.md +32 -0
  246. package/expertise/design/patterns/authentication-flows.md +474 -0
  247. package/expertise/design/patterns/content-consumption.md +789 -0
  248. package/expertise/design/patterns/data-display.md +618 -0
  249. package/expertise/design/patterns/e-commerce.md +1494 -0
  250. package/expertise/design/patterns/feedback-and-states.md +642 -0
  251. package/expertise/design/patterns/forms-and-input.md +819 -0
  252. package/expertise/design/patterns/gamification.md +801 -0
  253. package/expertise/design/patterns/index.md +31 -0
  254. package/expertise/design/patterns/microinteractions.md +449 -0
  255. package/expertise/design/patterns/navigation.md +800 -0
  256. package/expertise/design/patterns/notifications.md +705 -0
  257. package/expertise/design/patterns/onboarding.md +700 -0
  258. package/expertise/design/patterns/search-and-filter.md +601 -0
  259. package/expertise/design/patterns/settings-and-preferences.md +768 -0
  260. package/expertise/design/patterns/social-and-community.md +748 -0
  261. package/expertise/design/platforms/desktop-native.md +612 -0
  262. package/expertise/design/platforms/index.md +25 -0
  263. package/expertise/design/platforms/mobile-android.md +825 -0
  264. package/expertise/design/platforms/mobile-cross-platform.md +983 -0
  265. package/expertise/design/platforms/mobile-ios.md +699 -0
  266. package/expertise/design/platforms/tablet.md +794 -0
  267. package/expertise/design/platforms/web-dashboard.md +790 -0
  268. package/expertise/design/platforms/web-responsive.md +550 -0
  269. package/expertise/design/psychology/behavioral-nudges.md +449 -0
  270. package/expertise/design/psychology/cognitive-load.md +1191 -0
  271. package/expertise/design/psychology/error-psychology.md +778 -0
  272. package/expertise/design/psychology/index.md +22 -0
  273. package/expertise/design/psychology/persuasive-design.md +736 -0
  274. package/expertise/design/psychology/user-mental-models.md +623 -0
  275. package/expertise/design/tooling/open-pencil.md +266 -0
  276. package/expertise/frontend/angular.md +1073 -0
  277. package/expertise/frontend/desktop-electron.md +546 -0
  278. package/expertise/frontend/flutter.md +782 -0
  279. package/expertise/frontend/index.md +27 -0
  280. package/expertise/frontend/native-android.md +409 -0
  281. package/expertise/frontend/native-ios.md +490 -0
  282. package/expertise/frontend/react-native.md +1160 -0
  283. package/expertise/frontend/react.md +808 -0
  284. package/expertise/frontend/vue.md +1089 -0
  285. package/expertise/humanize/domain-rules-code.md +79 -0
  286. package/expertise/humanize/domain-rules-content.md +67 -0
  287. package/expertise/humanize/domain-rules-technical-docs.md +56 -0
  288. package/expertise/humanize/index.md +35 -0
  289. package/expertise/humanize/self-audit-checklist.md +87 -0
  290. package/expertise/humanize/sentence-patterns.md +218 -0
  291. package/expertise/humanize/vocabulary-blacklist.md +105 -0
  292. package/expertise/i18n/PROGRESS.md +65 -0
  293. package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
  294. package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
  295. package/expertise/i18n/advanced/complex-scripts.md +30 -0
  296. package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
  297. package/expertise/i18n/advanced/testing-i18n.md +28 -0
  298. package/expertise/i18n/content/content-adaptation.md +23 -0
  299. package/expertise/i18n/content/locale-specific-formatting.md +23 -0
  300. package/expertise/i18n/content/machine-translation-integration.md +28 -0
  301. package/expertise/i18n/content/translation-management.md +29 -0
  302. package/expertise/i18n/foundations/date-time-calendars.md +67 -0
  303. package/expertise/i18n/foundations/i18n-architecture.md +272 -0
  304. package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
  305. package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
  306. package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
  307. package/expertise/i18n/foundations/string-externalization.md +236 -0
  308. package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
  309. package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
  310. package/expertise/i18n/index.md +38 -0
  311. package/expertise/i18n/platform/backend-i18n.md +31 -0
  312. package/expertise/i18n/platform/flutter-i18n.md +148 -0
  313. package/expertise/i18n/platform/native-android-i18n.md +36 -0
  314. package/expertise/i18n/platform/native-ios-i18n.md +36 -0
  315. package/expertise/i18n/platform/react-i18n.md +103 -0
  316. package/expertise/i18n/platform/web-css-i18n.md +81 -0
  317. package/expertise/i18n/rtl/arabic-specific.md +175 -0
  318. package/expertise/i18n/rtl/hebrew-specific.md +149 -0
  319. package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
  320. package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
  321. package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
  322. package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
  323. package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
  324. package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
  325. package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
  326. package/expertise/i18n/rtl/rtl-typography.md +160 -0
  327. package/expertise/index.md +113 -0
  328. package/expertise/index.yaml +216 -0
  329. package/expertise/infrastructure/cloud-aws.md +597 -0
  330. package/expertise/infrastructure/cloud-gcp.md +599 -0
  331. package/expertise/infrastructure/cybersecurity.md +816 -0
  332. package/expertise/infrastructure/database-mongodb.md +447 -0
  333. package/expertise/infrastructure/database-postgres.md +400 -0
  334. package/expertise/infrastructure/devops-cicd.md +787 -0
  335. package/expertise/infrastructure/index.md +27 -0
  336. package/expertise/performance/PROGRESS.md +50 -0
  337. package/expertise/performance/backend/api-latency.md +1204 -0
  338. package/expertise/performance/backend/background-jobs.md +506 -0
  339. package/expertise/performance/backend/connection-pooling.md +1209 -0
  340. package/expertise/performance/backend/database-query-optimization.md +515 -0
  341. package/expertise/performance/backend/index.md +23 -0
  342. package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
  343. package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
  344. package/expertise/performance/foundations/caching-strategies.md +489 -0
  345. package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
  346. package/expertise/performance/foundations/index.md +24 -0
  347. package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
  348. package/expertise/performance/foundations/memory-management.md +964 -0
  349. package/expertise/performance/foundations/performance-budgets.md +1314 -0
  350. package/expertise/performance/index.md +31 -0
  351. package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
  352. package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
  353. package/expertise/performance/infrastructure/index.md +22 -0
  354. package/expertise/performance/infrastructure/load-balancing.md +1081 -0
  355. package/expertise/performance/infrastructure/observability.md +1079 -0
  356. package/expertise/performance/mobile/index.md +23 -0
  357. package/expertise/performance/mobile/mobile-animations.md +544 -0
  358. package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
  359. package/expertise/performance/mobile/mobile-network.md +452 -0
  360. package/expertise/performance/mobile/mobile-rendering.md +599 -0
  361. package/expertise/performance/mobile/mobile-startup-time.md +505 -0
  362. package/expertise/performance/platform-specific/flutter-performance.md +647 -0
  363. package/expertise/performance/platform-specific/index.md +22 -0
  364. package/expertise/performance/platform-specific/node-performance.md +1307 -0
  365. package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
  366. package/expertise/performance/platform-specific/react-performance.md +1403 -0
  367. package/expertise/performance/web/bundle-optimization.md +1239 -0
  368. package/expertise/performance/web/image-and-media.md +636 -0
  369. package/expertise/performance/web/index.md +24 -0
  370. package/expertise/performance/web/network-optimization.md +1133 -0
  371. package/expertise/performance/web/rendering-performance.md +1098 -0
  372. package/expertise/performance/web/ssr-and-hydration.md +918 -0
  373. package/expertise/performance/web/web-vitals.md +1374 -0
  374. package/expertise/quality/accessibility.md +985 -0
  375. package/expertise/quality/evidence-based-verification.md +499 -0
  376. package/expertise/quality/index.md +24 -0
  377. package/expertise/quality/ml-model-audit.md +614 -0
  378. package/expertise/quality/performance.md +600 -0
  379. package/expertise/quality/testing-api.md +891 -0
  380. package/expertise/quality/testing-mobile.md +496 -0
  381. package/expertise/quality/testing-web.md +849 -0
  382. package/expertise/security/PROGRESS.md +54 -0
  383. package/expertise/security/agentic-identity.md +540 -0
  384. package/expertise/security/compliance-frameworks.md +601 -0
  385. package/expertise/security/data/data-encryption.md +364 -0
  386. package/expertise/security/data/data-privacy-gdpr.md +692 -0
  387. package/expertise/security/data/database-security.md +1171 -0
  388. package/expertise/security/data/index.md +22 -0
  389. package/expertise/security/data/pii-handling.md +531 -0
  390. package/expertise/security/foundations/authentication.md +1041 -0
  391. package/expertise/security/foundations/authorization.md +603 -0
  392. package/expertise/security/foundations/cryptography.md +1001 -0
  393. package/expertise/security/foundations/index.md +25 -0
  394. package/expertise/security/foundations/owasp-top-10.md +1354 -0
  395. package/expertise/security/foundations/secrets-management.md +1217 -0
  396. package/expertise/security/foundations/secure-sdlc.md +700 -0
  397. package/expertise/security/foundations/supply-chain-security.md +698 -0
  398. package/expertise/security/index.md +31 -0
  399. package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
  400. package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
  401. package/expertise/security/infrastructure/container-security.md +721 -0
  402. package/expertise/security/infrastructure/incident-response.md +1295 -0
  403. package/expertise/security/infrastructure/index.md +24 -0
  404. package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
  405. package/expertise/security/infrastructure/network-security.md +1337 -0
  406. package/expertise/security/mobile/index.md +23 -0
  407. package/expertise/security/mobile/mobile-android-security.md +1218 -0
  408. package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
  409. package/expertise/security/mobile/mobile-data-storage.md +1265 -0
  410. package/expertise/security/mobile/mobile-ios-security.md +1401 -0
  411. package/expertise/security/mobile/mobile-network-security.md +1520 -0
  412. package/expertise/security/smart-contract-security.md +594 -0
  413. package/expertise/security/testing/index.md +22 -0
  414. package/expertise/security/testing/penetration-testing.md +1258 -0
  415. package/expertise/security/testing/security-code-review.md +1765 -0
  416. package/expertise/security/testing/threat-modeling.md +1074 -0
  417. package/expertise/security/testing/vulnerability-scanning.md +1062 -0
  418. package/expertise/security/web/api-security.md +586 -0
  419. package/expertise/security/web/cors-and-headers.md +433 -0
  420. package/expertise/security/web/csrf.md +562 -0
  421. package/expertise/security/web/file-upload.md +1477 -0
  422. package/expertise/security/web/index.md +25 -0
  423. package/expertise/security/web/injection.md +1375 -0
  424. package/expertise/security/web/session-management.md +1101 -0
  425. package/expertise/security/web/xss.md +1158 -0
  426. package/exports/README.md +17 -0
  427. package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
  428. package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
  429. package/exports/hosts/claude/.claude/agents/designer.md +55 -0
  430. package/exports/hosts/claude/.claude/agents/executor.md +55 -0
  431. package/exports/hosts/claude/.claude/agents/learner.md +51 -0
  432. package/exports/hosts/claude/.claude/agents/planner.md +53 -0
  433. package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
  434. package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
  435. package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
  436. package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
  437. package/exports/hosts/claude/.claude/commands/author.md +42 -0
  438. package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
  439. package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
  440. package/exports/hosts/claude/.claude/commands/design.md +44 -0
  441. package/exports/hosts/claude/.claude/commands/discover.md +37 -0
  442. package/exports/hosts/claude/.claude/commands/execute.md +48 -0
  443. package/exports/hosts/claude/.claude/commands/learn.md +38 -0
  444. package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
  445. package/exports/hosts/claude/.claude/commands/plan.md +39 -0
  446. package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
  447. package/exports/hosts/claude/.claude/commands/review.md +40 -0
  448. package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
  449. package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
  450. package/exports/hosts/claude/.claude/commands/specify.md +38 -0
  451. package/exports/hosts/claude/.claude/commands/verify.md +37 -0
  452. package/exports/hosts/claude/.claude/settings.json +34 -0
  453. package/exports/hosts/claude/CLAUDE.md +19 -0
  454. package/exports/hosts/claude/export.manifest.json +38 -0
  455. package/exports/hosts/claude/host-package.json +67 -0
  456. package/exports/hosts/codex/AGENTS.md +19 -0
  457. package/exports/hosts/codex/export.manifest.json +38 -0
  458. package/exports/hosts/codex/host-package.json +41 -0
  459. package/exports/hosts/cursor/.cursor/hooks.json +16 -0
  460. package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
  461. package/exports/hosts/cursor/export.manifest.json +38 -0
  462. package/exports/hosts/cursor/host-package.json +42 -0
  463. package/exports/hosts/gemini/GEMINI.md +19 -0
  464. package/exports/hosts/gemini/export.manifest.json +38 -0
  465. package/exports/hosts/gemini/host-package.json +41 -0
  466. package/hooks/README.md +18 -0
  467. package/hooks/definitions/loop_cap_guard.yaml +21 -0
  468. package/hooks/definitions/post_tool_capture.yaml +24 -0
  469. package/hooks/definitions/pre_compact_summary.yaml +19 -0
  470. package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
  471. package/hooks/definitions/protected_path_write_guard.yaml +19 -0
  472. package/hooks/definitions/session_start.yaml +19 -0
  473. package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
  474. package/hooks/loop-cap-guard +17 -0
  475. package/hooks/post-tool-lint +36 -0
  476. package/hooks/protected-path-write-guard +17 -0
  477. package/hooks/session-start +41 -0
  478. package/llms-full.txt +2355 -0
  479. package/llms.txt +43 -0
  480. package/package.json +79 -0
  481. package/roles/README.md +20 -0
  482. package/roles/clarifier.md +42 -0
  483. package/roles/content-author.md +63 -0
  484. package/roles/designer.md +55 -0
  485. package/roles/executor.md +55 -0
  486. package/roles/learner.md +51 -0
  487. package/roles/planner.md +53 -0
  488. package/roles/researcher.md +43 -0
  489. package/roles/reviewer.md +54 -0
  490. package/roles/specifier.md +47 -0
  491. package/roles/verifier.md +71 -0
  492. package/schemas/README.md +24 -0
  493. package/schemas/accepted-learning.schema.json +20 -0
  494. package/schemas/author-artifact.schema.json +156 -0
  495. package/schemas/clarification.schema.json +19 -0
  496. package/schemas/design-artifact.schema.json +80 -0
  497. package/schemas/docs-claim.schema.json +18 -0
  498. package/schemas/export-manifest.schema.json +20 -0
  499. package/schemas/hook.schema.json +67 -0
  500. package/schemas/host-export-package.schema.json +18 -0
  501. package/schemas/implementation-plan.schema.json +19 -0
  502. package/schemas/proposed-learning.schema.json +19 -0
  503. package/schemas/research.schema.json +18 -0
  504. package/schemas/review.schema.json +29 -0
  505. package/schemas/run-manifest.schema.json +18 -0
  506. package/schemas/spec-challenge.schema.json +18 -0
  507. package/schemas/spec.schema.json +20 -0
  508. package/schemas/usage.schema.json +102 -0
  509. package/schemas/verification-proof.schema.json +29 -0
  510. package/schemas/wazir-manifest.schema.json +173 -0
  511. package/skills/README.md +40 -0
  512. package/skills/brainstorming/SKILL.md +77 -0
  513. package/skills/debugging/SKILL.md +50 -0
  514. package/skills/design/SKILL.md +61 -0
  515. package/skills/dispatching-parallel-agents/SKILL.md +128 -0
  516. package/skills/executing-plans/SKILL.md +70 -0
  517. package/skills/finishing-a-development-branch/SKILL.md +169 -0
  518. package/skills/humanize/SKILL.md +123 -0
  519. package/skills/init-pipeline/SKILL.md +124 -0
  520. package/skills/prepare-next/SKILL.md +20 -0
  521. package/skills/receiving-code-review/SKILL.md +123 -0
  522. package/skills/requesting-code-review/SKILL.md +105 -0
  523. package/skills/requesting-code-review/code-reviewer.md +108 -0
  524. package/skills/run-audit/SKILL.md +197 -0
  525. package/skills/scan-project/SKILL.md +41 -0
  526. package/skills/self-audit/SKILL.md +153 -0
  527. package/skills/subagent-driven-development/SKILL.md +154 -0
  528. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
  529. package/skills/subagent-driven-development/implementer-prompt.md +102 -0
  530. package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  531. package/skills/tdd/SKILL.md +23 -0
  532. package/skills/using-git-worktrees/SKILL.md +163 -0
  533. package/skills/using-skills/SKILL.md +95 -0
  534. package/skills/verification/SKILL.md +22 -0
  535. package/skills/wazir/SKILL.md +463 -0
  536. package/skills/writing-plans/SKILL.md +30 -0
  537. package/skills/writing-skills/SKILL.md +157 -0
  538. package/skills/writing-skills/anthropic-best-practices.md +122 -0
  539. package/skills/writing-skills/persuasion-principles.md +50 -0
  540. package/templates/README.md +20 -0
  541. package/templates/artifacts/README.md +10 -0
  542. package/templates/artifacts/accepted-learning.md +19 -0
  543. package/templates/artifacts/accepted-learning.template.json +12 -0
  544. package/templates/artifacts/author.md +74 -0
  545. package/templates/artifacts/author.template.json +19 -0
  546. package/templates/artifacts/clarification.md +21 -0
  547. package/templates/artifacts/clarification.template.json +12 -0
  548. package/templates/artifacts/execute-notes.md +19 -0
  549. package/templates/artifacts/implementation-plan.md +21 -0
  550. package/templates/artifacts/implementation-plan.template.json +11 -0
  551. package/templates/artifacts/learning-proposal.md +19 -0
  552. package/templates/artifacts/next-run-handoff.md +21 -0
  553. package/templates/artifacts/plan-review.md +19 -0
  554. package/templates/artifacts/proposed-learning.template.json +12 -0
  555. package/templates/artifacts/research.md +21 -0
  556. package/templates/artifacts/research.template.json +12 -0
  557. package/templates/artifacts/review-findings.md +19 -0
  558. package/templates/artifacts/review.template.json +11 -0
  559. package/templates/artifacts/run-manifest.template.json +8 -0
  560. package/templates/artifacts/spec-challenge.md +19 -0
  561. package/templates/artifacts/spec-challenge.template.json +11 -0
  562. package/templates/artifacts/spec.md +21 -0
  563. package/templates/artifacts/spec.template.json +12 -0
  564. package/templates/artifacts/verification-proof.md +19 -0
  565. package/templates/artifacts/verification-proof.template.json +11 -0
  566. package/templates/examples/accepted-learning.example.json +14 -0
  567. package/templates/examples/author.example.json +152 -0
  568. package/templates/examples/clarification.example.json +15 -0
  569. package/templates/examples/docs-claim.example.json +8 -0
  570. package/templates/examples/export-manifest.example.json +7 -0
  571. package/templates/examples/host-export-package.example.json +11 -0
  572. package/templates/examples/implementation-plan.example.json +17 -0
  573. package/templates/examples/proposed-learning.example.json +13 -0
  574. package/templates/examples/research.example.json +15 -0
  575. package/templates/examples/research.example.md +6 -0
  576. package/templates/examples/review.example.json +17 -0
  577. package/templates/examples/run-manifest.example.json +9 -0
  578. package/templates/examples/spec-challenge.example.json +14 -0
  579. package/templates/examples/spec.example.json +21 -0
  580. package/templates/examples/verification-proof.example.json +21 -0
  581. package/templates/examples/wazir-manifest.example.yaml +65 -0
  582. package/templates/task-definition-schema.md +99 -0
  583. package/tooling/README.md +20 -0
  584. package/tooling/src/adapters/context-mode.js +50 -0
  585. package/tooling/src/capture/command.js +376 -0
  586. package/tooling/src/capture/store.js +99 -0
  587. package/tooling/src/capture/usage.js +270 -0
  588. package/tooling/src/checks/branches.js +50 -0
  589. package/tooling/src/checks/brand-truth.js +110 -0
  590. package/tooling/src/checks/changelog.js +231 -0
  591. package/tooling/src/checks/command-registry.js +36 -0
  592. package/tooling/src/checks/commits.js +102 -0
  593. package/tooling/src/checks/docs-drift.js +103 -0
  594. package/tooling/src/checks/docs-truth.js +201 -0
  595. package/tooling/src/checks/runtime-surface.js +156 -0
  596. package/tooling/src/cli.js +116 -0
  597. package/tooling/src/command-options.js +56 -0
  598. package/tooling/src/commands/validate.js +320 -0
  599. package/tooling/src/doctor/command.js +91 -0
  600. package/tooling/src/export/command.js +77 -0
  601. package/tooling/src/export/compiler.js +498 -0
  602. package/tooling/src/guards/loop-cap-guard.js +52 -0
  603. package/tooling/src/guards/protected-path-write-guard.js +67 -0
  604. package/tooling/src/index/command.js +152 -0
  605. package/tooling/src/index/storage.js +1061 -0
  606. package/tooling/src/index/summarizers.js +261 -0
  607. package/tooling/src/loaders.js +18 -0
  608. package/tooling/src/project-root.js +22 -0
  609. package/tooling/src/recall/command.js +225 -0
  610. package/tooling/src/schema-validator.js +30 -0
  611. package/tooling/src/state-root.js +40 -0
  612. package/tooling/src/status/command.js +71 -0
  613. package/wazir.manifest.yaml +135 -0
  614. package/workflows/README.md +19 -0
  615. package/workflows/author.md +42 -0
  616. package/workflows/clarify.md +38 -0
  617. package/workflows/design-review.md +46 -0
  618. package/workflows/design.md +44 -0
  619. package/workflows/discover.md +37 -0
  620. package/workflows/execute.md +48 -0
  621. package/workflows/learn.md +38 -0
  622. package/workflows/plan-review.md +42 -0
  623. package/workflows/plan.md +39 -0
  624. package/workflows/prepare-next.md +37 -0
  625. package/workflows/review.md +40 -0
  626. package/workflows/run-audit.md +41 -0
  627. package/workflows/spec-challenge.md +41 -0
  628. package/workflows/specify.md +38 -0
  629. package/workflows/verify.md +37 -0
@@ -0,0 +1,800 @@
1
+ # Multi-Tenancy — Architecture Expertise Module
2
+
3
+ > Multi-tenancy allows a single application instance to serve multiple customers (tenants) while keeping their data isolated. The key decision is the isolation level: shared database with tenant ID column (simple, dense), schema-per-tenant (moderate isolation), or database-per-tenant (maximum isolation, highest cost). Most SaaS applications should start with shared database + tenant ID.
4
+
5
+ > **Category:** Scaling
6
+ > **Complexity:** Complex
7
+ > **Applies when:** Building SaaS applications that serve multiple customers from the same infrastructure
8
+
9
+ ---
10
+
11
+ ## What This Is
12
+
13
+ Multi-tenancy is a software architecture in which a **single instance of an application serves multiple customers (tenants)**, each of whom perceives the system as their own private deployment. Tenants share compute, storage, and network infrastructure while their data, configurations, and customizations remain logically — and sometimes physically — separated.
14
+
15
+ The concept predates cloud computing. IBM mainframes in the 1960s time-shared resources across organizations. But the modern incarnation was shaped by two forces:
16
+
17
+ - **Salesforce (1999-present):** Pioneered the metadata-driven multi-tenant architecture where all tenants share a single database with a single schema. Customer data model changes are stored as rows in metadata tables — no `ALTER TABLE` needed. This architecture now serves over 150,000 organizations from the same codebase and database schema. It remains the most ambitious and successful shared-everything multi-tenant system ever built.
18
+ - **AWS and the cloud era (2006-present):** Made infrastructure elastic, enabling the hybrid models where most tenants share resources but enterprise customers receive dedicated infrastructure on demand.
19
+
20
+ ### Single-Tenant vs Multi-Tenant
21
+
22
+ | Dimension | Single-Tenant | Multi-Tenant |
23
+ |---|---|---|
24
+ | Infrastructure | Dedicated per customer | Shared across customers |
25
+ | Cost per customer | High (dedicated resources idle 80%+ of the time) | Low (resources pooled and utilized efficiently) |
26
+ | Deployment | One deployment per customer | One deployment serves all |
27
+ | Customization | Unlimited (separate codebase possible) | Bounded by configuration, feature flags, metadata |
28
+ | Upgrades | Per-customer rollout (slow, error-prone) | Single rollout for all tenants (fast, uniform) |
29
+ | Data isolation | Physical (different databases/servers) | Logical (tenant ID, RLS) or physical (per-tenant DB) |
30
+ | Operational burden | O(n) with customer count | O(1) — same system regardless of tenant count |
31
+ | Compliance | Simple (natural isolation) | Requires explicit isolation controls |
32
+
33
+ **The fundamental economics:** A single-tenant SaaS provider with 1,000 customers operates 1,000 deployments. Each must be monitored, patched, backed up, and upgraded independently. A multi-tenant provider with 1,000 customers operates one deployment. This is not a 2x or 5x difference — it is the difference between a company that can scale with a platform team of 5 and one that needs a platform team of 50.
34
+
35
+ ### The Four Isolation Models
36
+
37
+ Multi-tenancy exists on a spectrum. The four canonical models, from least to most isolated:
38
+
39
+ **1. Shared-Everything (Single Database, Shared Schema)**
40
+
41
+ All tenants' data lives in the same tables, distinguished by a `tenant_id` column. The application filters every query by tenant. This is what Salesforce, Slack, Notion, and most modern SaaS applications use.
42
+
43
+ ```
44
+ ┌─────────────────────────────────┐
45
+ │ Application │
46
+ │ (tenant context in request) │
47
+ ├─────────────────────────────────┤
48
+ │ Shared Database │
49
+ │ ┌───────────────────────────┐ │
50
+ │ │ orders table │ │
51
+ │ │ tenant_id | order_id ... │ │
52
+ │ │ acme | 001 │ │
53
+ │ │ globex | 002 │ │
54
+ │ │ acme | 003 │ │
55
+ │ └───────────────────────────┘ │
56
+ └─────────────────────────────────┘
57
+ ```
58
+
59
+ **2. Shared Database, Separate Schema**
60
+
61
+ Each tenant gets their own schema within the same database instance. Tables are structurally identical but physically separate. Used by some Rails applications via the `apartment` gem and Django via `django-tenants`.
62
+
63
+ ```
64
+ ┌─────────────────────────────────┐
65
+ │ Shared Database │
66
+ │ ┌────────────┐ ┌────────────┐ │
67
+ │ │ acme schema │ │globex │ │
68
+ │ │ orders │ │schema │ │
69
+ │ │ users │ │ orders │ │
70
+ │ │ products │ │ users │ │
71
+ │ └────────────┘ │ products │ │
72
+ │ └────────────┘ │
73
+ └─────────────────────────────────┘
74
+ ```
75
+
76
+ **3. Separate Database (Database-per-Tenant)**
77
+
78
+ Each tenant gets a dedicated database instance. The application routes connections based on tenant context. Provides strong isolation but linear cost scaling.
79
+
80
+ ```
81
+ ┌──────────────┐ ┌──────────────┐
82
+ │ acme_db │ │ globex_db │
83
+ │ orders │ │ orders │
84
+ │ users │ │ users │
85
+ │ products │ │ products │
86
+ └──────────────┘ └──────────────┘
87
+ ```
88
+
89
+ **4. Hybrid (Tiered Isolation)**
90
+
91
+ Most tenants share a pooled database, while enterprise tenants with compliance or performance requirements receive dedicated databases. This is the mature model used by most successful B2B SaaS companies at scale.
92
+
93
+ ```
94
+ ┌──────────────────────┐ ┌──────────────┐
95
+ │ Shared Pool DB │ │ enterprise_db│
96
+ │ (free + standard │ │ (dedicated │
97
+ │ tier tenants) │ │ for BigCorp)│
98
+ └──────────────────────┘ └──────────────┘
99
+ ```
100
+
101
+ ---
102
+
103
+ ## When to Use Shared Database (tenant_id Column)
104
+
105
+ The shared database model is the correct starting point for the vast majority of SaaS applications. Use it when:
106
+
107
+ ### Startups and early-stage products
108
+
109
+ Before you have 100 paying customers, the operational overhead of managing per-tenant databases is a distraction that provides no business value. Every hour spent on per-tenant infrastructure automation is an hour not spent on product-market fit.
110
+
111
+ **Slack** started with a shared PostgreSQL database and grew to millions of workspaces before needing to shard. The shared model got them through the critical growth phase without infrastructure complexity slowing feature velocity.
112
+
113
+ ### Cost-sensitive SaaS (< $50/month price points)
114
+
115
+ When your average revenue per tenant is $20/month, a dedicated $50/month database instance per tenant is economically impossible. Shared databases let you serve 10,000 tenants from a single database that costs $500/month — $0.05 per tenant.
116
+
117
+ ### Up to ~1,000 tenants with moderate data volumes
118
+
119
+ A well-indexed PostgreSQL database with Row Level Security can serve 1,000+ tenants with excellent performance as long as total data volume fits on a single instance (typically up to 1-4 TB with proper indexing). Beyond this, consider Citus for distributed multi-tenant PostgreSQL before jumping to per-tenant databases.
120
+
121
+ ### Uniform schema requirements
122
+
123
+ When all tenants use the same data model — same tables, same columns, same relationships — schema-per-tenant and database-per-tenant add complexity without benefit. The shared model lets you add a column once and all tenants get it immediately.
124
+
125
+ ### Fast tenant onboarding
126
+
127
+ In the shared model, creating a new tenant is an `INSERT INTO tenants` row. In database-per-tenant, it is provisioning a database, running migrations, configuring connection pooling, setting up monitoring, and updating routing tables. If your business depends on instant self-service signups, shared database removes an entire category of onboarding friction.
128
+
129
+ ---
130
+
131
+ ## When to Use Separate Database (Database-per-Tenant)
132
+
133
+ This model is justified under specific, concrete conditions — not as a default "enterprise-grade" choice.
134
+
135
+ ### Regulatory or contractual data residency requirements
136
+
137
+ When enterprise customers contractually require their data to reside in a specific geographic region, or when regulations like GDPR, HIPAA, or SOC2 auditors specifically require physical data separation (not just logical isolation), a dedicated database in the required region is the cleanest compliance path.
138
+
139
+ **Example:** A healthcare SaaS serving hospitals in the EU and US may need patient data for German hospitals stored in Frankfurt and US hospital data in Virginia. Per-tenant databases in the appropriate region satisfy this cleanly.
140
+
141
+ ### Very large tenants with asymmetric data volumes
142
+
143
+ When one tenant has 100x the data volume of an average tenant, they will dominate shared database resources — indexes, vacuum operations, buffer cache. A dedicated database prevents this tenant from degrading performance for all others.
144
+
145
+ **Example:** An analytics SaaS where most tenants have 10 GB of data but one enterprise customer has 2 TB. That single tenant would consume the majority of shared I/O bandwidth and make vacuum operations take hours.
146
+
147
+ ### Tenant-specific backup and restore requirements
148
+
149
+ In a shared database, restoring a single tenant's data to a point in time requires surgically extracting their rows from a full database backup. With a dedicated database, you restore the entire database — a standard, well-tested operation that any DBA can perform under pressure at 3 AM.
150
+
151
+ ### Tenants with custom schema extensions
152
+
153
+ If your product allows enterprise customers to define custom tables, custom columns, or stored procedures, a dedicated database prevents one tenant's schema experiments from affecting others' query performance.
154
+
155
+ ---
156
+
157
+ ## When NOT to Over-Isolate
158
+
159
+ **This section is deliberately as long as the sections above because over-isolation is the more common and more expensive mistake.** Teams default to database-per-tenant out of a vague sense that "more isolation is always better" without understanding the costs. It is architectural over-engineering with compounding operational consequences.
160
+
161
+ ### Database-per-tenant at 10,000 tenants is an operational nightmare
162
+
163
+ Consider the concrete operational reality of managing 10,000 separate databases:
164
+
165
+ - **Schema migrations:** Every `ALTER TABLE` must run against 10,000 databases. If each migration takes 2 seconds (fast for a production database with locks), the total migration takes 5.5 hours. A failed migration on database #7,431 requires investigation and remediation while 2,569 databases are in the old schema and 7,431 are in the new one. Your application must handle both schema versions simultaneously.
166
+ - **Connection pooling:** Each database requires its own connection pool. At 10 connections per pool, you need 100,000 database connections. PgBouncer can help, but you are now operating PgBouncer as critical infrastructure managing 10,000 upstream databases.
167
+ - **Monitoring:** 10,000 databases means 10,000 sets of slow-query logs, 10,000 replication lag monitors, 10,000 disk-space alerts. Your monitoring system is now larger than most companies' entire infrastructure.
168
+ - **Backups:** 10,000 nightly backups, 10,000 backup verification jobs, 10,000 retention policies. One failed backup goes unnoticed, and that tenant's data is unrecoverable.
169
+ - **Cost:** Even at $10/month per managed database instance (the cheapest available), 10,000 databases cost $100,000/month just for database infrastructure. A single shared database handling the same workload might cost $2,000/month.
170
+
171
+ **Real-world cautionary tale:** Multiple SaaS companies have publicly discussed spending 6-12 months migrating from database-per-tenant back to shared databases after reaching the point where migration tooling consumed more engineering time than product development. The Atlas schema migration tool specifically addresses this pain point, but the tooling exists because the problem is so painful.
172
+
173
+ ### Shared database with Row Level Security handles most compliance needs
174
+
175
+ Teams often choose database-per-tenant because "compliance requires data isolation." In practice, most compliance frameworks — SOC2, HIPAA, GDPR — require **access control**, not physical separation. Row Level Security in PostgreSQL provides database-enforced access control that satisfies auditors:
176
+
177
+ ```sql
178
+ -- This policy is enforced by the database engine itself, not application code.
179
+ -- Even if application code has a bug, the database will not return
180
+ -- another tenant's data.
181
+ ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
182
+
183
+ CREATE POLICY tenant_isolation ON orders
184
+ USING (tenant_id = current_setting('app.current_tenant')::uuid);
185
+ ```
186
+
187
+ SOC2 auditors care that **no code path can access another tenant's data**, not whether data lives in separate physical databases. RLS provides this guarantee at the database layer, which is actually stronger than relying on application-level `WHERE tenant_id = ?` clauses that a developer might forget.
188
+
189
+ **PostgreSQL CVE note:** CVE-2024-10976 demonstrated that RLS policies could disregard user ID changes in certain edge cases, and CVE-2025-8713 revealed that optimizer statistics could leak sampled data from RLS-protected rows. These vulnerabilities were patched, but they underscore the importance of keeping PostgreSQL updated and having defense-in-depth (application-level filtering as a second layer).
190
+
191
+ ### The hybrid model is almost always the right answer at scale
192
+
193
+ Instead of choosing one isolation level for all tenants, successful SaaS companies offer tiered isolation:
194
+
195
+ | Tier | Isolation Level | Price Point | Target Customer |
196
+ |---|---|---|---|
197
+ | Free / Starter | Shared DB, shared schema | $0-29/mo | Individual users, small teams |
198
+ | Professional | Shared DB, RLS-enforced | $30-299/mo | SMBs |
199
+ | Enterprise | Dedicated database, optional dedicated compute | $300-5000+/mo | Enterprises with compliance needs |
200
+
201
+ This model aligns isolation cost with revenue. The enterprise customers who need and demand dedicated infrastructure pay the premium that funds it. The free-tier users who generate minimal revenue share infrastructure efficiently.
202
+
203
+ **Slack, Notion, Figma, and most successful B2B SaaS companies** use variants of this hybrid approach.
204
+
205
+ ---
206
+
207
+ ## How It Works
208
+
209
+ ### Tenant Context Propagation
210
+
211
+ Every request in a multi-tenant system must carry tenant identity. The tenant context must be set **once at the edge** and propagated through every layer — never derived from user input deep in the stack.
212
+
213
+ ```
214
+ Request → API Gateway → Middleware → Service → Database
215
+ │ │
216
+ │ └─ Sets tenant context:
217
+ │ SET app.current_tenant = 'acme-corp';
218
+ └─ Extracts tenant from:
219
+ - JWT claim (tenant_id)
220
+ - Subdomain (acme.app.com)
221
+ - API key lookup
222
+ - OAuth token introspection
223
+ ```
224
+
225
+ **Implementation (Express.js middleware example):**
226
+
227
+ ```javascript
228
+ // Tenant middleware — runs before any route handler
229
+ async function tenantMiddleware(req, res, next) {
230
+ // Extract tenant from JWT, subdomain, or API key
231
+ const tenantId = extractTenantId(req);
232
+
233
+ if (!tenantId) {
234
+ return res.status(401).json({ error: 'Tenant not identified' });
235
+ }
236
+
237
+ // Validate tenant exists and is active
238
+ const tenant = await tenantRegistry.get(tenantId);
239
+ if (!tenant || tenant.status !== 'active') {
240
+ return res.status(403).json({ error: 'Tenant suspended or not found' });
241
+ }
242
+
243
+ // Attach to request context (available to all downstream handlers)
244
+ req.tenantId = tenantId;
245
+ req.tenantConfig = tenant.config;
246
+
247
+ // Set database-level context for RLS
248
+ await db.query("SET app.current_tenant = $1", [tenantId]);
249
+
250
+ next();
251
+ }
252
+ ```
253
+
254
+ ### Row Level Security in PostgreSQL
255
+
256
+ RLS is the single most important tool for multi-tenant data isolation in a shared database. It moves tenant filtering from application code (where developers can forget it) to the database engine (where it is enforced unconditionally).
257
+
258
+ **Step 1: Enable RLS on every tenant-scoped table**
259
+
260
+ ```sql
261
+ -- Create the table with tenant_id as the first column
262
+ -- (first column in composite indexes for efficient filtering)
263
+ CREATE TABLE orders (
264
+ tenant_id UUID NOT NULL,
265
+ order_id UUID NOT NULL DEFAULT gen_random_uuid(),
266
+ customer TEXT NOT NULL,
267
+ total NUMERIC(10,2) NOT NULL,
268
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
269
+ PRIMARY KEY (tenant_id, order_id)
270
+ );
271
+
272
+ -- Enable RLS (without this, policies are ignored)
273
+ ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
274
+
275
+ -- Force RLS even for table owners (critical for security)
276
+ ALTER TABLE orders FORCE ROW LEVEL SECURITY;
277
+
278
+ -- Create the isolation policy
279
+ CREATE POLICY tenant_isolation_policy ON orders
280
+ FOR ALL
281
+ USING (tenant_id = current_setting('app.current_tenant')::uuid)
282
+ WITH CHECK (tenant_id = current_setting('app.current_tenant')::uuid);
283
+ ```
284
+
285
+ **Step 2: Set tenant context per connection/transaction**
286
+
287
+ ```sql
288
+ -- At the start of every request, set the tenant context
289
+ -- This is typically done by middleware before any queries run
290
+ SET LOCAL app.current_tenant = 'a1b2c3d4-...';
291
+
292
+ -- Now all queries are automatically scoped:
293
+ SELECT * FROM orders;
294
+ -- Internally becomes: SELECT * FROM orders WHERE tenant_id = 'a1b2c3d4-...';
295
+
296
+ -- Inserts are also checked:
297
+ INSERT INTO orders (tenant_id, customer, total)
298
+ VALUES ('wrong-tenant-id', 'test', 100);
299
+ -- ERROR: new row violates row-level security policy
300
+ ```
301
+
302
+ **Step 3: Create an application database role that respects RLS**
303
+
304
+ ```sql
305
+ -- The application connects as this role, NOT as the table owner
306
+ CREATE ROLE app_user LOGIN PASSWORD '...';
307
+ GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO app_user;
308
+ -- app_user is subject to RLS policies
309
+ -- The table owner (used only for migrations) bypasses RLS by default
310
+ ```
311
+
312
+ ### Query Scoping (Defense-in-Depth)
313
+
314
+ Even with RLS, application-level query scoping provides defense-in-depth. Use repository patterns or ORM scopes that automatically include tenant filtering:
315
+
316
+ ```python
317
+ # Python/SQLAlchemy example: automatic tenant scoping
318
+ class TenantQuery(Query):
319
+ def get(self, *args, **kwargs):
320
+ # Automatically add tenant filter to every query
321
+ return super().filter(
322
+ self._entity.tenant_id == g.current_tenant_id
323
+ ).get(*args, **kwargs)
324
+
325
+ class Order(Base):
326
+ __tablename__ = 'orders'
327
+ tenant_id = Column(UUID, nullable=False, index=True)
328
+ order_id = Column(UUID, primary_key=True)
329
+ # ...
330
+
331
+ query_class = TenantQuery # All queries auto-scoped
332
+ ```
333
+
334
+ ### Tenant-Aware Caching
335
+
336
+ Caching in a multi-tenant system requires tenant-scoped cache keys. A cache key of `orders:recent` is a cross-tenant data leak waiting to happen. Every cache key must include the tenant identifier.
337
+
338
+ ```python
339
+ # WRONG — cross-tenant data leak
340
+ cache.get("orders:recent")
341
+
342
+ # CORRECT — tenant-scoped cache key
343
+ cache.get(f"tenant:{tenant_id}:orders:recent")
344
+
345
+ # For Redis, use key prefixes or separate databases per tier:
346
+ # Free tier: redis DB 0, keys prefixed with tenant_id
347
+ # Enterprise: dedicated Redis instance per tenant
348
+ ```
349
+
350
+ **Cache invalidation** also becomes tenant-scoped. When tenant A's data changes, only tenant A's cache entries should be invalidated — not the entire cache.
351
+
352
+ ### Tenant-Aware Background Jobs
353
+
354
+ Background jobs (email sending, report generation, data exports) must carry tenant context explicitly. A job that loses its tenant context will either fail or — worse — operate on the wrong tenant's data.
355
+
356
+ ```python
357
+ # Enqueue with tenant context
358
+ queue.enqueue(
359
+ 'generate_report',
360
+ tenant_id='acme-corp',
361
+ report_type='monthly_sales',
362
+ month='2025-01'
363
+ )
364
+
365
+ # Worker sets tenant context before execution
366
+ def process_job(job):
367
+ tenant_id = job.data['tenant_id']
368
+ set_tenant_context(tenant_id) # Sets DB session, cache prefix, etc.
369
+ try:
370
+ execute_job(job)
371
+ finally:
372
+ clear_tenant_context() # Prevent context leaking to next job
373
+ ```
374
+
375
+ ### Data Migration Across Isolation Levels
376
+
377
+ A well-designed multi-tenant system supports migrating a tenant between isolation levels — typically from shared to dedicated when they upgrade to enterprise tier.
378
+
379
+ **Migration steps (shared DB to dedicated DB):**
380
+
381
+ 1. Provision new dedicated database, run schema migrations
382
+ 2. Begin dual-write: all writes go to both shared and dedicated DB
383
+ 3. Backfill: copy historical data from shared DB to dedicated DB
384
+ 4. Verify: compare row counts and checksums between databases
385
+ 5. Switch reads: point tenant's read path to dedicated DB
386
+ 6. Stop dual-write to shared DB
387
+ 7. Archive and delete tenant's rows from shared DB
388
+
389
+ This process should be automated and tested regularly. If it is a manual runbook, it will fail under pressure.
390
+
391
+ ---
392
+
393
+ ## Trade-Offs Matrix
394
+
395
+ | Dimension | Shared DB + tenant_id | Schema-per-Tenant | Database-per-Tenant |
396
+ |---|---|---|---|
397
+ | **Tenant onboarding speed** | Instant (insert a row) | Seconds (create schema, run migrations) | Minutes to hours (provision DB, configure) |
398
+ | **Cost per tenant** | ~$0.01-0.10/mo (amortized) | ~$0.50-2/mo (schema overhead) | $10-200+/mo (dedicated instance) |
399
+ | **Data isolation** | Logical (application + RLS) | Moderate (schema boundary) | Physical (separate instance) |
400
+ | **Noisy neighbor risk** | High (shared I/O, CPU, memory) | Medium (shared I/O, separate tables) | None (fully isolated resources) |
401
+ | **Schema migration speed** | Fast (one ALTER TABLE) | Slow (N schemas x migration) | Very slow (N databases x migration) |
402
+ | **Tenant-specific schema** | Not possible | Possible but complicates migrations | Fully flexible |
403
+ | **Backup/restore granularity** | Difficult (extract rows from full backup) | Moderate (pg_dump single schema) | Easy (standard DB restore) |
404
+ | **Cross-tenant queries** | Easy (single query, no tenant filter) | Moderate (cross-schema joins) | Very difficult (federated queries) |
405
+ | **Connection pooling** | Simple (one pool) | Moderate (one pool, schema switching) | Complex (N pools or N routing rules) |
406
+ | **Monitoring complexity** | Simple (one database to monitor) | Moderate (per-schema metrics) | High (N databases to monitor) |
407
+ | **Maximum practical tenants** | 100,000+ | ~5,000 (schema creation overhead) | ~500-1,000 (operational ceiling) |
408
+ | **Compliance satisfaction** | RLS satisfies most auditors | Stronger isolation for stricter audits | Satisfies all compliance requirements |
409
+ | **Operational team size needed** | Small (1-2 DBAs) | Medium (2-3 DBAs) | Large (3-5+ DBAs or heavy automation) |
410
+
411
+ ---
412
+
413
+ ## Evolution Path
414
+
415
+ The most successful multi-tenant architectures evolve through stages, driven by concrete business needs — not speculative "we might need this."
416
+
417
+ ### Stage 1: Shared Database (Day 1 — ~1,000 tenants)
418
+
419
+ Start here. Every table has a `tenant_id` column. Enable RLS from day one — it is far easier to enable on empty tables than to retrofit. Build your ORM/repository layer with automatic tenant scoping.
420
+
421
+ **Key discipline:** Include `tenant_id` in every primary key and every foreign key as a composite. This makes future sharding possible without restructuring your data model.
422
+
423
+ ```sql
424
+ -- DO THIS from day one
425
+ PRIMARY KEY (tenant_id, order_id)
426
+ FOREIGN KEY (tenant_id, customer_id) REFERENCES customers (tenant_id, customer_id)
427
+
428
+ -- NOT THIS — makes future sharding extremely painful
429
+ PRIMARY KEY (order_id)
430
+ FOREIGN KEY (customer_id) REFERENCES customers (customer_id)
431
+ ```
432
+
433
+ ### Stage 2: Shared Database + Noisy Neighbor Controls (~1,000-10,000 tenants)
434
+
435
+ Add per-tenant rate limiting, query timeouts, and resource quotas. Monitor per-tenant resource consumption. Identify tenants whose usage patterns degrade the experience for others.
436
+
437
+ ```python
438
+ # Per-tenant rate limiting
439
+ @rate_limit(
440
+ key=lambda req: req.tenant_id,
441
+ limits={
442
+ 'free': '100/minute',
443
+ 'pro': '1000/minute',
444
+ 'enterprise': '10000/minute'
445
+ }
446
+ )
447
+ def api_handler(req):
448
+ ...
449
+ ```
450
+
451
+ ### Stage 3: Hybrid — Selective Isolation for Enterprise (~5,000+ tenants)
452
+
453
+ When you sign enterprise customers with compliance requirements or data volumes that degrade shared infrastructure, offer dedicated databases as a premium tier. Build the migration tooling (Stage 1 → Stage 3) as a product feature, not an ad-hoc project.
454
+
455
+ ### Stage 4: Distributed Multi-Tenant (Citus/Sharding) (~50,000+ tenants)
456
+
457
+ When a single PostgreSQL instance cannot handle the total data volume or query load, use Citus to distribute the shared database across multiple nodes while maintaining the shared-schema model. Tenant data is automatically co-located on the same node, preserving efficient joins.
458
+
459
+ ```sql
460
+ -- Citus: distribute tables by tenant_id
461
+ SELECT create_distributed_table('orders', 'tenant_id');
462
+ SELECT create_distributed_table('order_items', 'tenant_id');
463
+ -- Queries filtered by tenant_id route to a single node
464
+ -- Cross-tenant aggregations still work (distributed query engine)
465
+ ```
466
+
467
+ ### Stage 5: Cell-Based Architecture (~100,000+ tenants)
468
+
469
+ At massive scale, partition tenants into cells — self-contained units of infrastructure that each serve a subset of tenants. Each cell is a complete stack (application, database, cache, queue). New tenants are assigned to cells with capacity. Failing cells affect only their tenants, not the entire platform.
470
+
471
+ AWS presented this as "SaaS meets cell-based architecture" at re:Invent 2024, describing it as a natural fit for multi-tenant systems at hyperscale.
472
+
473
+ ---
474
+
475
+ ## Failure Modes
476
+
477
+ ### Data Leakage Between Tenants — The Worst Possible Bug
478
+
479
+ Cross-tenant data leakage is the most severe bug a multi-tenant system can have. It is worse than downtime. It is worse than data loss. A single incident destroys customer trust and can trigger regulatory action.
480
+
481
+ **How it happens:**
482
+
483
+ 1. **Missing WHERE clause:** A developer writes `SELECT * FROM orders` without the tenant filter. In testing (single-tenant test database), this works perfectly. In production, it returns all tenants' orders.
484
+ 2. **Cached data served to wrong tenant:** A cache key without tenant scoping (`cache.get("dashboard_data")`) returns tenant A's dashboard to tenant B.
485
+ 3. **Background job loses tenant context:** A job is enqueued with tenant context but the worker does not set the database session variable before executing. Queries run without RLS filtering.
486
+ 4. **API endpoint missing tenant middleware:** A new endpoint is added without the tenant authentication middleware. Requests without a valid tenant token access an unscoped database view.
487
+ 5. **ORM eager loading bypasses RLS:** Some ORMs, when performing eager/lazy loading of associations, issue separate queries that may not carry the tenant context set for the parent query.
488
+
489
+ **Real incidents:**
490
+ - A 2021 Microsoft Azure vulnerability ("ChaosDB") allowed attackers to access other customers' Cosmos DB instances through a misconfigured Jupyter notebook feature.
491
+ - AWS AppSync had a cross-tenant vulnerability allowing access to resources in other organizations' accounts.
492
+ - Multiple SaaS companies have disclosed incidents where API endpoints returned data belonging to other tenants due to missing tenant filtering in new code paths.
493
+
494
+ **Prevention:**
495
+ - RLS as the primary barrier (database-enforced, not application-enforced)
496
+ - Application-level tenant scoping as defense-in-depth
497
+ - Integration tests that create two tenants, insert data for both, and verify each tenant can only see their own data — run these tests on every deployment
498
+ - Code review checklists that specifically verify tenant filtering on every new query
499
+ - Static analysis rules that flag raw SQL without tenant_id references
500
+
501
+ ### Noisy Neighbor
502
+
503
+ One tenant's heavy workload degrades performance for all tenants sharing the same infrastructure.
504
+
505
+ **Symptoms:** Spike in response times for all tenants correlated with one tenant's batch processing job, large data export, or traffic surge.
506
+
507
+ **Mitigations:**
508
+ - Per-tenant query timeouts: `SET LOCAL statement_timeout = '5s';`
509
+ - Per-tenant connection limits in the connection pool
510
+ - Per-tenant rate limiting at the API gateway
511
+ - Resource quotas (CPU, memory) via Kubernetes resource limits for tenant-specific workloads
512
+ - Separate queues for background jobs by tenant tier
513
+ - Move consistently noisy tenants to dedicated infrastructure (and charge accordingly)
514
+
515
+ ### Tenant-Specific Outage Cascading
516
+
517
+ A bug triggered by one tenant's specific data pattern crashes the application for all tenants.
518
+
519
+ **Example:** Tenant A uploads a 500 MB CSV file. The import handler loads it entirely into memory, OOM-kills the application process, and all tenants lose service.
520
+
521
+ **Mitigations:**
522
+ - Tenant-specific error isolation (catch and contain errors per-tenant request)
523
+ - Circuit breakers per tenant: if tenant A's requests fail 5 times consecutively, temporarily reject tenant A's requests while continuing to serve others
524
+ - Bulkhead pattern: separate thread/process pools for different tenants or tenant tiers
525
+ - Input validation with per-tenant resource limits (max file size, max rows per import, max API payload size)
526
+
527
+ ### Migration Complexity
528
+
529
+ Moving a tenant between isolation levels (shared to dedicated, or between shards) risks data loss or inconsistency.
530
+
531
+ **Mitigations:**
532
+ - Dual-write during migration with reconciliation checks
533
+ - Automated migration tooling tested in staging with production-sized datasets
534
+ - Rollback capability: ability to move the tenant back to shared if dedicated has issues
535
+ - Migration as a product feature, not an operational procedure
536
+
537
+ ---
538
+
539
+ ## Technology Landscape
540
+
541
+ ### PostgreSQL Row Level Security (RLS)
542
+
543
+ The most mature and widely used solution for shared-database multi-tenancy. Available since PostgreSQL 9.5 (2016).
544
+
545
+ **Strengths:**
546
+ - Policies enforced by the database engine — cannot be bypassed by application code (unless connecting as table owner)
547
+ - Works with standard PostgreSQL tooling (pg_dump, pg_restore, logical replication)
548
+ - Minimal performance overhead (typically < 5%) when policies use indexed columns
549
+ - Policies can be arbitrarily complex (not limited to tenant_id equality)
550
+
551
+ **Limitations:**
552
+ - RLS is bypassed by the table owner role and roles with BYPASSRLS attribute — ensure the application connects as a non-owner role
553
+ - Complex permission models (row-level + column-level + attribute-based) may outgrow RLS capabilities
554
+ - Debugging RLS issues requires careful logging since policy execution is not directly observable
555
+ - Must keep PostgreSQL patched — CVEs have specifically targeted RLS enforcement
556
+
557
+ ### Schema-Based Multi-Tenancy Libraries
558
+
559
+ - **`django-tenants`** (Python/Django): Maps tenants to PostgreSQL schemas via `search_path`. Middleware automatically sets the schema based on the request's subdomain or header.
560
+ - **`apartment`** (Ruby/Rails): Schema-based tenant switching for ActiveRecord. Each tenant gets a separate PostgreSQL schema with identical table structures.
561
+ - **`spring-multitenancy`** and **Hibernate multi-tenancy**: Java ecosystem support for schema-per-tenant and database-per-tenant patterns with connection routing.
562
+
563
+ **Common issue with schema-based libraries:** Schema creation and migration across N schemas becomes slow. At 5,000 schemas, a migration that adds a column takes 5,000 `ALTER TABLE` statements. Tools like Atlas and Flyway have specific support for batch multi-schema migrations.
564
+
565
+ ### Citus for Distributed Multi-Tenant PostgreSQL
566
+
567
+ Citus is an open-source PostgreSQL extension (now part of Azure Cosmos DB for PostgreSQL) that distributes tables across multiple nodes while preserving the PostgreSQL interface.
568
+
569
+ **How it works for multi-tenancy:**
570
+ - All tables are distributed by `tenant_id` (the distribution column)
571
+ - Rows for the same tenant are co-located on the same physical node
572
+ - Queries filtered by `tenant_id` route to a single node — same performance as standard PostgreSQL
573
+ - Cross-tenant aggregate queries (admin dashboards) use the distributed query engine
574
+ - Large tenants can be isolated on dedicated nodes using tenant placement controls
575
+
576
+ **Citus 12+ schema-based sharding:** As an alternative to row-based distribution, Citus 12 introduced schema-based sharding where each tenant gets a PostgreSQL schema that is automatically placed on a node. This requires minimal query changes (just set `search_path`) and suits applications that already use schema-per-tenant.
577
+
578
+ ### Other Technologies
579
+
580
+ - **AWS RDS Proxy:** Connection pooling and routing for database-per-tenant architectures on AWS. Reduces the connection overhead of managing many databases.
581
+ - **ProxySQL / PgBouncer:** Connection poolers that can route queries to different backends based on tenant context.
582
+ - **Kubernetes Namespaces:** Provide compute-level isolation for tenants requiring dedicated application instances alongside dedicated databases.
583
+ - **HashiCorp Vault:** Manages per-tenant encryption keys, database credentials, and secrets in multi-tenant environments.
584
+
585
+ ---
586
+
587
+ ## Decision Tree
588
+
589
+ ```
590
+ Start: Building a SaaS application?
591
+
592
+ ├─ YES: How many tenants do you expect in 2 years?
593
+ │ │
594
+ │ ├─ < 10 tenants, all enterprise, high-touch sales
595
+ │ │ └─ Consider single-tenant deployments
596
+ │ │ (operational overhead is manageable at this scale,
597
+ │ │ and enterprise customers may contractually require it)
598
+ │ │
599
+ │ ├─ 10-100,000 tenants, self-service signups
600
+ │ │ │
601
+ │ │ ├─ Do any tenants have regulatory requirements
602
+ │ │ │ for physical data separation?
603
+ │ │ │ │
604
+ │ │ │ ├─ NO → Shared DB + RLS
605
+ │ │ │ │ (simplest, cheapest, fastest to build)
606
+ │ │ │ │
607
+ │ │ │ └─ YES, but < 5% of tenants
608
+ │ │ │ └─ Hybrid: Shared DB for standard,
609
+ │ │ │ dedicated DB for enterprise
610
+ │ │ │
611
+ │ │ ├─ Will individual tenants have > 100 GB of data?
612
+ │ │ │ │
613
+ │ │ │ ├─ NO → Shared DB + RLS (handles this easily)
614
+ │ │ │ │
615
+ │ │ │ └─ YES → Hybrid or Citus
616
+ │ │ │ (co-locate large tenants on dedicated nodes)
617
+ │ │ │
618
+ │ │ └─ Do tenants need custom schema extensions?
619
+ │ │ │
620
+ │ │ ├─ NO → Shared DB + RLS
621
+ │ │ │
622
+ │ │ └─ YES → Schema-per-tenant or metadata-driven
623
+ │ │ (Salesforce-style: store custom fields as
624
+ │ │ metadata rows, not physical columns)
625
+ │ │
626
+ │ └─ > 100,000 tenants
627
+ │ └─ Shared DB + Citus distributed sharding
628
+ │ or cell-based architecture
629
+ │ (database-per-tenant is operationally impossible
630
+ │ at this scale)
631
+
632
+ └─ NO: Multi-tenancy is not relevant to your architecture.
633
+ ```
634
+
635
+ ---
636
+
637
+ ## Implementation Sketch
638
+
639
+ ### Complete PostgreSQL RLS Setup
640
+
641
+ ```sql
642
+ -- 1. Tenants registry
643
+ CREATE TABLE tenants (
644
+ tenant_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
645
+ name TEXT NOT NULL, slug TEXT UNIQUE NOT NULL,
646
+ tier TEXT NOT NULL DEFAULT 'free' CHECK (tier IN ('free','pro','enterprise')),
647
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','suspended','deleted')),
648
+ config JSONB NOT NULL DEFAULT '{}', created_at TIMESTAMPTZ NOT NULL DEFAULT now()
649
+ );
650
+
651
+ -- 2. Tenant-scoped table (composite PK is critical for future sharding)
652
+ CREATE TABLE orders (
653
+ tenant_id UUID NOT NULL REFERENCES tenants(tenant_id),
654
+ order_id UUID NOT NULL DEFAULT gen_random_uuid(),
655
+ customer TEXT NOT NULL,
656
+ total NUMERIC(10,2) NOT NULL,
657
+ status TEXT NOT NULL DEFAULT 'pending',
658
+ created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
659
+ PRIMARY KEY (tenant_id, order_id)
660
+ );
661
+ CREATE INDEX idx_orders_tenant_created ON orders (tenant_id, created_at DESC);
662
+
663
+ -- 3. Enable RLS + single policy for all operations
664
+ ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
665
+ ALTER TABLE orders FORCE ROW LEVEL SECURITY;
666
+
667
+ CREATE POLICY tenant_isolation ON orders FOR ALL
668
+ USING (tenant_id = current_setting('app.current_tenant')::uuid)
669
+ WITH CHECK (tenant_id = current_setting('app.current_tenant')::uuid);
670
+
671
+ -- 4. Application role (subject to RLS — NOT the table owner)
672
+ CREATE ROLE app_service LOGIN PASSWORD 'strong-password-here';
673
+ GRANT USAGE ON SCHEMA public TO app_service;
674
+ GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO app_service;
675
+
676
+ -- 5. Admin role for cross-tenant reads (dashboards, support)
677
+ CREATE ROLE admin_service LOGIN PASSWORD 'different-strong-password';
678
+ GRANT SELECT ON ALL TABLES IN SCHEMA public TO admin_service;
679
+ CREATE POLICY admin_read ON orders FOR SELECT TO admin_service USING (true);
680
+ ```
681
+
682
+ ### Tenant Middleware and Query Wrapper (Node.js/Express)
683
+
684
+ ```javascript
685
+ const pool = new Pool({ user: 'app_service', database: 'saas_app', max: 20 });
686
+
687
+ // Middleware: extract tenant from JWT (or subdomain, API key, etc.)
688
+ function tenantContext(req, res, next) {
689
+ const tenantId = req.auth?.tenantId;
690
+ if (!tenantId) return res.status(401).json({ error: 'Tenant not identified' });
691
+ req.tenantId = tenantId;
692
+ next();
693
+ }
694
+
695
+ // DB wrapper: sets tenant context via SET LOCAL (transaction-scoped)
696
+ async function tenantQuery(tenantId, queryText, params) {
697
+ const client = await pool.connect();
698
+ try {
699
+ await client.query('BEGIN');
700
+ await client.query("SELECT set_config('app.current_tenant', $1, true)", [tenantId]);
701
+ const result = await client.query(queryText, params);
702
+ await client.query('COMMIT');
703
+ return result;
704
+ } catch (err) {
705
+ await client.query('ROLLBACK');
706
+ throw err;
707
+ } finally {
708
+ client.release(); // Returns to pool WITHOUT tenant context
709
+ }
710
+ }
711
+
712
+ // Route handler — no WHERE tenant_id needed, RLS handles it
713
+ app.get('/api/orders', tenantContext, async (req, res) => {
714
+ const result = await tenantQuery(req.tenantId,
715
+ 'SELECT order_id, customer, total, status FROM orders ORDER BY created_at DESC LIMIT 50');
716
+ res.json(result.rows);
717
+ });
718
+ ```
719
+
720
+ ### Tenant-Aware Integration Test
721
+
722
+ ```javascript
723
+ describe('Multi-tenant data isolation', () => {
724
+ const tenantA = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
725
+ const tenantB = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb';
726
+
727
+ beforeAll(async () => {
728
+ await adminQuery(`INSERT INTO tenants (tenant_id, name, slug)
729
+ VALUES ($1, 'Tenant A', 'a'), ($2, 'Tenant B', 'b')`, [tenantA, tenantB]);
730
+ await tenantQuery(tenantA, `INSERT INTO orders (tenant_id, customer, total)
731
+ VALUES ($1, 'Alice', 100)`, [tenantA]);
732
+ await tenantQuery(tenantB, `INSERT INTO orders (tenant_id, customer, total)
733
+ VALUES ($1, 'Bob', 200)`, [tenantB]);
734
+ });
735
+
736
+ test('Tenant A sees only own data', async () => {
737
+ const r = await tenantQuery(tenantA, 'SELECT * FROM orders');
738
+ expect(r.rows).toHaveLength(1);
739
+ expect(r.rows[0].customer).toBe('Alice');
740
+ });
741
+
742
+ test('Cross-tenant insert is rejected by RLS', async () => {
743
+ await expect(tenantQuery(tenantA,
744
+ `INSERT INTO orders (tenant_id, customer, total) VALUES ($1, 'Mallory', 999)`,
745
+ [tenantB])).rejects.toThrow(/row-level security/);
746
+ });
747
+
748
+ test('No tenant context = no data (default-deny)', async () => {
749
+ const client = await pool.connect();
750
+ try {
751
+ const r = await client.query('SELECT * FROM orders');
752
+ expect(r.rows).toHaveLength(0);
753
+ } finally { client.release(); }
754
+ });
755
+ });
756
+ ```
757
+
758
+ ---
759
+
760
+ ## Key Takeaways
761
+
762
+ 1. **Start with shared database + tenant_id + RLS.** It is the simplest, cheapest, and most operationally sustainable model. You can always add isolation later; you cannot easily remove it.
763
+
764
+ 2. **Include tenant_id in every composite primary key and foreign key from day one.** This single discipline preserves all future options — sharding, migration to dedicated databases, Citus distribution.
765
+
766
+ 3. **Use Row Level Security as your primary isolation mechanism**, not application-level WHERE clauses. RLS is enforced by the database engine and cannot be bypassed by application bugs (as long as the application connects as a non-owner role).
767
+
768
+ 4. **Build the hybrid model as a product feature.** The ability to migrate a tenant from shared to dedicated infrastructure is a premium offering that enterprise customers will pay for.
769
+
770
+ 5. **Cross-tenant data leakage is an existential threat.** Invest more in preventing it than in any other aspect of your multi-tenant architecture. Integration tests that verify isolation on every deployment are non-negotiable.
771
+
772
+ 6. **Database-per-tenant is a last resort, not a default.** At more than a few hundred tenants, the operational cost (migrations, monitoring, backups, connection management) exceeds the benefit for all but the most demanding compliance environments.
773
+
774
+ 7. **Noisy neighbor is a solvable problem without physical isolation.** Per-tenant rate limiting, query timeouts, connection limits, and resource quotas handle 95% of noisy neighbor scenarios at a fraction of the cost of dedicated databases.
775
+
776
+ ---
777
+
778
+ ## Cross-References
779
+
780
+ - **[Database Scaling](../data/database-scaling.md)** — Vertical vs horizontal scaling, read replicas, connection pooling strategies that underpin multi-tenant database architecture
781
+ - **[Data Consistency](../data/data-consistency.md)** — Consistency guarantees across tenant isolation boundaries, especially during tenant migration between isolation levels
782
+ - **[Horizontal vs Vertical Scaling](horizontal-vs-vertical.md)** — When to scale up a shared database vs shard across nodes, directly relevant to multi-tenant growth stages
783
+ - **[Feature Flags and Rollouts](../../design/feature-flags-and-rollouts.md)** — Tenant-scoped feature flags for gradual rollouts, A/B testing per tenant tier, and tenant-specific configuration
784
+
785
+ ---
786
+
787
+ ## Sources
788
+
789
+ - [Salesforce Platform Multitenant Architecture](https://architect.salesforce.com/fundamentals/platform-multitenant-architecture)
790
+ - [AWS: Multi-tenant data isolation with PostgreSQL Row Level Security](https://aws.amazon.com/blogs/database/multi-tenant-data-isolation-with-postgresql-row-level-security/)
791
+ - [Azure: Multitenant SaaS Database Tenancy Patterns](https://learn.microsoft.com/en-us/azure/azure-sql/database/saas-tenancy-app-design-patterns)
792
+ - [Citus: Sharding a Multi-Tenant App with Postgres](https://docs.citusdata.com/en/stable/articles/sharding_mt_app.html)
793
+ - [Crunchy Data: Row Level Security for Tenants in Postgres](https://www.crunchydata.com/blog/row-level-security-for-tenants-in-postgres)
794
+ - [The Nile Dev: Shipping multi-tenant SaaS using Postgres Row-Level Security](https://www.thenile.dev/blog/multi-tenant-rls)
795
+ - [Citus 12: Schema-based sharding for PostgreSQL](https://www.citusdata.com/blog/2023/07/18/citus-12-schema-based-sharding-for-postgres/)
796
+ - [AWS re:Invent 2024: SaaS meets cell-based architecture](https://reinvent.awsevents.com/content/dam/reinvent/2024/slides/sas/SAS315_SaaS-meets-cell-based-architecture-A-natural-multi-tenant-fit.pdf)
797
+ - [OWASP: Multi Tenant Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Multi_Tenant_Security_Cheat_Sheet.html)
798
+ - [Bytebase: Multi-Tenant Database Architecture Patterns Explained](https://www.bytebase.com/blog/multi-tenant-database-architecture-patterns-explained/)
799
+ - [WorkOS: The developer's guide to SaaS multi-tenant architecture](https://workos.com/blog/developers-guide-saas-multi-tenant-architecture)
800
+ - [Inngest: Fixing noisy neighbor problems in multi-tenant queueing systems](https://www.inngest.com/blog/fixing-multi-tenant-queueing-concurrency-problems)