pz-cli 5.0.0__py3-none-any.whl

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 (399) hide show
  1. pz_cli-5.0.0.dist-info/METADATA +51 -0
  2. pz_cli-5.0.0.dist-info/RECORD +399 -0
  3. pz_cli-5.0.0.dist-info/WHEEL +4 -0
  4. pz_cli-5.0.0.dist-info/entry_points.txt +5 -0
  5. pz_core/__init__.py +64 -0
  6. pz_core/__main__.py +7 -0
  7. pz_core/app.py +45 -0
  8. pz_core/assembly/__init__.py +17 -0
  9. pz_core/assembly/app_discovery.py +1240 -0
  10. pz_core/assembly/apps/__init__.py +25 -0
  11. pz_core/assembly/apps/compiler.py +824 -0
  12. pz_core/assembly/apps/providers.py +188 -0
  13. pz_core/assembly/cli/__init__.py +9 -0
  14. pz_core/assembly/cli/compiler.py +166 -0
  15. pz_core/assembly/diagnostics/__init__.py +21 -0
  16. pz_core/assembly/diagnostics/checks.py +257 -0
  17. pz_core/assembly/diagnostics/dev_sources.py +569 -0
  18. pz_core/assembly/events/__init__.py +5 -0
  19. pz_core/assembly/events/compiler.py +219 -0
  20. pz_core/assembly/extensions/__init__.py +5 -0
  21. pz_core/assembly/extensions/compiler.py +696 -0
  22. pz_core/assembly/infra/__init__.py +6 -0
  23. pz_core/assembly/infra/compiler.py +272 -0
  24. pz_core/assembly/lifecycle/__init__.py +5 -0
  25. pz_core/assembly/lifecycle/compiler.py +95 -0
  26. pz_core/assembly/middlewares/__init__.py +19 -0
  27. pz_core/assembly/middlewares/compiler.py +508 -0
  28. pz_core/assembly/project/__init__.py +7 -0
  29. pz_core/assembly/project/compiler.py +9 -0
  30. pz_core/assembly/project/context.py +17 -0
  31. pz_core/assembly/project/discovery.py +227 -0
  32. pz_core/assembly/resources/__init__.py +19 -0
  33. pz_core/assembly/resources/compiler.py +310 -0
  34. pz_core/assembly/resources/settings.py +129 -0
  35. pz_core/assembly/routes/__init__.py +7 -0
  36. pz_core/assembly/routes/compiler.py +400 -0
  37. pz_core/assembly/runtime_manifests/__init__.py +13 -0
  38. pz_core/assembly/runtime_manifests/compiler.py +159 -0
  39. pz_core/assembly/settings/__init__.py +17 -0
  40. pz_core/assembly/settings/compiler.py +786 -0
  41. pz_core/assembly/settings/host_project_overrides.py +82 -0
  42. pz_core/assembly/settings/host_runtime_endpoint.py +207 -0
  43. pz_core/authoring/__init__.py +79 -0
  44. pz_core/authoring/app_init_service.py +946 -0
  45. pz_core/authoring/app_versions.py +814 -0
  46. pz_core/authoring/cli.py +192 -0
  47. pz_core/authoring/commands.py +1810 -0
  48. pz_core/authoring/conflicts.py +180 -0
  49. pz_core/authoring/dev_bindings.py +916 -0
  50. pz_core/authoring/dev_git.py +1087 -0
  51. pz_core/authoring/dev_import.py +1061 -0
  52. pz_core/authoring/dev_manifest.py +522 -0
  53. pz_core/authoring/dev_sources.py +1638 -0
  54. pz_core/authoring/env_cli.py +454 -0
  55. pz_core/authoring/files.py +109 -0
  56. pz_core/authoring/ide_projection.py +1129 -0
  57. pz_core/authoring/naming.py +58 -0
  58. pz_core/authoring/official_dev_sources.py +432 -0
  59. pz_core/authoring/official_sources.json +156 -0
  60. pz_core/authoring/orchestration_service.py +558 -0
  61. pz_core/authoring/project_default.jsonc +53 -0
  62. pz_core/authoring/project_defaults.py +88 -0
  63. pz_core/authoring/project_metadata_service.py +199 -0
  64. pz_core/authoring/project_settings_checks.py +51 -0
  65. pz_core/authoring/project_settings_cli.py +299 -0
  66. pz_core/authoring/project_settings_service.py +1700 -0
  67. pz_core/authoring/project_state.py +399 -0
  68. pz_core/authoring/publish_git.py +423 -0
  69. pz_core/authoring/publish_lock.py +188 -0
  70. pz_core/authoring/publish_source.py +195 -0
  71. pz_core/authoring/release.py +1382 -0
  72. pz_core/authoring/repo_keys.py +29 -0
  73. pz_core/authoring/root_cli.py +28 -0
  74. pz_core/authoring/scaffold_service.py +325 -0
  75. pz_core/authoring/sync_service.py +787 -0
  76. pz_core/authoring/templates/app/__init__.py +1 -0
  77. pz_core/authoring/templates/app/api.py +25 -0
  78. pz_core/authoring/templates/app/apps.py +31 -0
  79. pz_core/authoring/templates/app/auth_package_init.py +14 -0
  80. pz_core/authoring/templates/app/auth_readme.py +29 -0
  81. pz_core/authoring/templates/app/configs_package_init.py +14 -0
  82. pz_core/authoring/templates/app/default_env.py +18 -0
  83. pz_core/authoring/templates/app/default_jsonc.py +25 -0
  84. pz_core/authoring/templates/app/locales_readme.py +25 -0
  85. pz_core/authoring/templates/app/migrations_readme.py +19 -0
  86. pz_core/authoring/templates/app/models.py +14 -0
  87. pz_core/authoring/templates/app/package_init.py +8 -0
  88. pz_core/authoring/templates/app/pages_base.py +161 -0
  89. pz_core/authoring/templates/app/pages_readme.py +25 -0
  90. pz_core/authoring/templates/app/public.py +31 -0
  91. pz_core/authoring/templates/app/pyproject.py +77 -0
  92. pz_core/authoring/templates/app/readme.py +74 -0
  93. pz_core/authoring/templates/app/settings.py +46 -0
  94. pz_core/authoring/templates/app/static_app_js.py +24 -0
  95. pz_core/authoring/templates/app/static_readme.py +31 -0
  96. pz_core/authoring/templates/app/template_config_page.py +23 -0
  97. pz_core/authoring/templates/app/template_index_html.py +28 -0
  98. pz_core/authoring/templates/app/templates_readme.py +32 -0
  99. pz_core/authoring/templates/app/urls.py +36 -0
  100. pz_core/authoring/templates/app/views.py +36 -0
  101. pz_core/authoring/templates/project/__init__.py +1 -0
  102. pz_core/authoring/templates/project/agents.py +51 -0
  103. pz_core/authoring/templates/project/apps_container_readme.py +37 -0
  104. pz_core/authoring/templates/project/main_py.py +59 -0
  105. pz_core/authoring/templates/project/project_env.py +19 -0
  106. pz_core/authoring/templates/project/pyproject.py +26 -0
  107. pz_core/authoring/templates/project/pz_env_env.py +65 -0
  108. pz_core/authoring/templates/project/pz_env_jsonc.py +69 -0
  109. pz_core/authoring/templates/project/pz_jsonc.py +12 -0
  110. pz_core/authoring/templates/project/readme.py +94 -0
  111. pz_core/authoring/templates/project/root_gitkeep.py +8 -0
  112. pz_core/authoring/templates/shared/__init__.py +5 -0
  113. pz_core/authoring/templates/shared/text.py +10 -0
  114. pz_core/authoring/venv_service.py +87 -0
  115. pz_core/authoring/workspace.py +167 -0
  116. pz_core/cli.py +291 -0
  117. pz_core/cli_options.py +74 -0
  118. pz_core/core/__init__.py +3 -0
  119. pz_core/core/errors/__init__.py +5 -0
  120. pz_core/core/errors/models.py +117 -0
  121. pz_core/core/events/__init__.py +5 -0
  122. pz_core/core/events/registry.py +54 -0
  123. pz_core/core/extensions/__init__.py +51 -0
  124. pz_core/core/extensions/registry.py +790 -0
  125. pz_core/core/health/__init__.py +6 -0
  126. pz_core/core/health/contracts.py +10 -0
  127. pz_core/core/middlewares/__init__.py +6 -0
  128. pz_core/core/middlewares/models.py +24 -0
  129. pz_core/core/routing/__init__.py +5 -0
  130. pz_core/core/routing/models.py +21 -0
  131. pz_core/core/settings_contracts.py +25 -0
  132. pz_core/docs/README.md +20 -0
  133. pz_core/docs/distribution-README.md +438 -0
  134. pz_core/docs/pz/345/221/275/344/273/244/346/200/273/350/247/210.md +1011 -0
  135. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/00-pz/346/236/266/346/236/204/346/200/273/347/272/262.md +240 -0
  136. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/01-/347/233/256/345/275/225/344/270/216/345/210/206/345/261/202/350/247/204/350/214/203.md +216 -0
  137. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/02-/345/214/205/344/270/216/345/210/206/345/217/221/350/247/204/350/214/203.md +403 -0
  138. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/03-App/346/234/200/345/260/217/345/255/220/345/214/205/350/247/204/350/214/203.md +571 -0
  139. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/04-Settings/344/270/216/351/205/215/347/275/256/350/247/204/350/214/203.md +1177 -0
  140. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/05-/350/265/204/346/272/220/344/270/216/350/277/220/350/241/214/347/233/256/345/275/225/350/247/204/350/214/203.md +575 -0
  141. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/06-/346/225/260/346/215/256/345/272/223/344/270/216/345/217/257/351/200/211/345/237/272/347/241/200/350/256/276/346/226/275/350/247/204/350/214/203.md +499 -0
  142. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/07-App/346/233/277/346/215/242/350/247/204/350/214/203.md +206 -0
  143. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/08-/345/271/263/345/217/260/347/272/247App/344/270/216/350/277/220/350/241/214/346/227/266/345/215/225/344/276/213/350/247/204/350/214/203.md +445 -0
  144. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/09-CLI/344/270/216Worker/345/205/245/345/217/243/350/247/204/350/214/203.md +950 -0
  145. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/10-/346/265/213/350/257/225/344/270/216/345/245/221/347/272/246/350/247/204/350/214/203.md +1001 -0
  146. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/11-/344/273/223/345/272/223/347/234/237/347/233/270/346/272/220/345/234/260/345/233/276.md +102 -0
  147. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/12-/346/236/204/345/273/272/344/270/216/345/217/221/345/270/203/346/243/200/346/237/245/346/270/205/345/215/225.md +171 -0
  148. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/13-/346/255/243/345/274/217Facade/346/200/273/350/241/250.md +402 -0
  149. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/14-/345/210/206/345/261/202/344/270/216/346/211/251/345/261/225/350/247/204/350/214/203.md +550 -0
  150. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/15-/345/255/220/345/214/205/345/274/200/345/217/221/344/275/277/347/224/250/346/211/213/345/206/214.md +1004 -0
  151. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/16-/346/211/251/345/261/225/347/202/271/346/255/243/345/274/217/345/215/217/350/256/256/346/270/205/345/215/225.md +352 -0
  152. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/17-pz.protocols.v1/346/255/243/345/274/217/345/215/217/350/256/256.md +266 -0
  153. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/18-/346/211/251/345/261/225/347/202/271/345/206/262/347/252/201/350/243/201/345/206/263/346/200/273/350/241/250.md +131 -0
  154. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/19-/351/224/231/350/257/257/347/240/201/344/270/216/350/257/212/346/226/255/345/215/217/350/256/256.md +176 -0
  155. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/20-/347/247/201/346/234/211/345/214/205/344/273/223/344/270/216/347/273/237/344/270/200/350/256/244/350/257/201/351/203/250/347/275/262/350/247/204/350/214/203.md +243 -0
  156. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/21-contrib/347/272/246/345/256/232/344/270/216Provider/346/216/245/345/205/245/350/247/204/350/214/203.md +365 -0
  157. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/22-/345/244/232/345/233/275/350/257/255/350/250/200/350/265/204/346/272/220/346/262/273/347/220/206/344/270/216/346/214/211/351/234/200/345/212/240/350/275/275/350/247/204/350/214/203.md +912 -0
  158. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/23-/351/246/226/345/261/217/345/261/225/347/244/272/344/270/216/351/246/226/345/270/247/347/250/263/345/256/232/350/247/204/350/214/203.md +269 -0
  159. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/24-pz/345/220/257/345/212/250/344/270/216/350/277/220/350/241/214/346/227/266/347/274/226/350/257/221/346/265/201/347/250/213.md +245 -0
  160. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/25-/351/235/242/345/220/221/345/257/271/350/261/241/345/274/200/345/217/221/350/247/204/350/214/203.md +300 -0
  161. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/README.md +98 -0
  162. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/00-legacy_core/346/240/207/345/207/206pip/345/214/205/345/214/226/351/207/215/346/236/204/346/200/273/347/272/262.md +1073 -0
  163. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/01-/347/233/256/345/275/225/344/270/216/345/210/206/345/261/202/351/207/215/346/236/204/346/211/247/350/241/214/346/226/271/346/241/210.md +224 -0
  164. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/02-/345/214/205/344/270/216/345/210/206/345/217/221/350/247/204/350/214/203-/345/220/253/345/216/206/345/217/262/345/217/243/345/276/204.md +671 -0
  165. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/13-/344/270/200/346/254/241/346/200/247/345/256/236/346/226/275/346/270/205/345/215/225.md +387 -0
  166. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/14-/345/255/220/345/214/205/351/200/202/351/205/215/346/224/271/351/200/240/346/270/205/345/215/225.md +592 -0
  167. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/15-infra/350/243/201/345/211/252/344/270/216/350/220/275/344/275/215/346/270/205/345/215/225.md +81 -0
  168. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/19-core/345/215/225/344/270/200/346/255/243/345/274/217/346/226/271/346/241/210/346/224/266/346/225/233/346/211/247/350/241/214/346/270/205/345/215/225.md +161 -0
  169. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/25-/345/215/217/350/256/256/345/210/260/346/272/220/347/240/201/345/267/256/350/267/235/346/270/205/345/215/225.md +377 -0
  170. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/26-cutover/345/256/214/345/267/245/346/243/200/346/237/245/346/270/205/345/215/225.md +117 -0
  171. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/29-/345/244/232/345/233/275/350/257/255/350/250/200/350/265/204/346/272/220/346/262/273/347/220/206/344/270/216/346/214/211/351/234/200/345/212/240/350/275/275/350/247/204/350/214/203-/345/220/253/350/277/201/347/247/273/347/255/226/347/225/245.md +956 -0
  172. pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/archive//344/270/255/351/227/264/346/200/201/99-/350/265/204/346/272/220/346/224/266/345/217/243/345/220/216/347/273/255TODO.md +84 -0
  173. pz_core/docs//345/217/221/347/211/210/345/211/215/346/270/205/345/215/225-4.0.11.md +84 -0
  174. pz_core/docs//346/226/260/346/211/213/346/214/207/345/215/227.md +422 -0
  175. pz_core/infra/__init__.py +17 -0
  176. pz_core/infra/db/__init__.py +23 -0
  177. pz_core/infra/db/contracts.py +73 -0
  178. pz_core/infra/health/__init__.py +5 -0
  179. pz_core/infra/health/contracts.py +8 -0
  180. pz_core/infra/kv/__init__.py +5 -0
  181. pz_core/infra/kv/contracts.py +17 -0
  182. pz_core/infra/observability/__init__.py +23 -0
  183. pz_core/infra/observability/contracts.py +142 -0
  184. pz_core/infra/resilience/__init__.py +5 -0
  185. pz_core/infra/resilience/contracts.py +17 -0
  186. pz_core/infra/resources/__init__.py +5 -0
  187. pz_core/infra/resources/contracts.py +16 -0
  188. pz_core/infra/settings/__init__.py +17 -0
  189. pz_core/infra/settings/models.py +81 -0
  190. pz_core/infra/storage/__init__.py +5 -0
  191. pz_core/infra/storage/ports.py +27 -0
  192. pz_core/project_root_commands.py +282 -0
  193. pz_core/project_runtime_cli.py +344 -0
  194. pz_core/project_sources.py +253 -0
  195. pz_core/pz_launcher.py +209 -0
  196. pz_core/root_cli.py +70 -0
  197. pz_core/runtime/__init__.py +229 -0
  198. pz_core/runtime/access.py +86 -0
  199. pz_core/runtime/adapters/__init__.py +5 -0
  200. pz_core/runtime/adapters/base.py +18 -0
  201. pz_core/runtime/asyncio_bridge.py +18 -0
  202. pz_core/runtime/bindings/__init__.py +5 -0
  203. pz_core/runtime/bindings/container.py +50 -0
  204. pz_core/runtime/cli/__init__.py +5 -0
  205. pz_core/runtime/cli/_args.py +67 -0
  206. pz_core/runtime/cli/app_commands.py +417 -0
  207. pz_core/runtime/cli/check.py +214 -0
  208. pz_core/runtime/cli/db.py +297 -0
  209. pz_core/runtime/cli/main.py +89 -0
  210. pz_core/runtime/cli/resources.py +280 -0
  211. pz_core/runtime/discovery.py +23 -0
  212. pz_core/runtime/environment_integrity.py +157 -0
  213. pz_core/runtime/errors.py +5 -0
  214. pz_core/runtime/events.py +87 -0
  215. pz_core/runtime/facades/__init__.py +38 -0
  216. pz_core/runtime/facades/_capabilities.py +46 -0
  217. pz_core/runtime/facades/cache.py +103 -0
  218. pz_core/runtime/facades/database.py +71 -0
  219. pz_core/runtime/facades/events.py +380 -0
  220. pz_core/runtime/facades/health.py +101 -0
  221. pz_core/runtime/facades/mail.py +121 -0
  222. pz_core/runtime/facades/observability.py +102 -0
  223. pz_core/runtime/facades/providers.py +75 -0
  224. pz_core/runtime/facades/resources.py +52 -0
  225. pz_core/runtime/facades/storage.py +296 -0
  226. pz_core/runtime/health/__init__.py +5 -0
  227. pz_core/runtime/health/service.py +102 -0
  228. pz_core/runtime/host.py +188 -0
  229. pz_core/runtime/host_runner.py +282 -0
  230. pz_core/runtime/http/__init__.py +20 -0
  231. pz_core/runtime/http/app.py +576 -0
  232. pz_core/runtime/http_timing.py +173 -0
  233. pz_core/runtime/invocation.py +29 -0
  234. pz_core/runtime/json_safe.py +47 -0
  235. pz_core/runtime/lifecycle/__init__.py +25 -0
  236. pz_core/runtime/lifecycle/manager.py +533 -0
  237. pz_core/runtime/plan.py +214 -0
  238. pz_core/runtime/plan_context.py +33 -0
  239. pz_core/runtime/plan_snapshot.py +177 -0
  240. pz_core/runtime/registries/__init__.py +27 -0
  241. pz_core/runtime/registries/capabilities.py +101 -0
  242. pz_core/runtime/registries/providers.py +396 -0
  243. pz_core/runtime/resource_assets.py +344 -0
  244. pz_core/runtime/run_cli.py +211 -0
  245. pz_core/runtime/settings.py +888 -0
  246. pz_core/runtime/worker/__init__.py +21 -0
  247. pz_core/runtime/worker/engine.py +921 -0
  248. pz_core/runtime/worker/runtime.py +25 -0
  249. pz_core/testing/__init__.py +15 -0
  250. pz_core/testing/doc_route_contracts.py +305 -0
  251. pz_core/utils/__init__.py +44 -0
  252. pz_core/utils/env.py +65 -0
  253. pz_core/utils/project_jsonc/__init__.py +29 -0
  254. pz_core/utils/project_jsonc/document.py +420 -0
  255. pz_core/utils/project_settings.py +99 -0
  256. pz_foundation/__init__.py +50 -0
  257. pz_foundation/_contracts.py +81 -0
  258. pz_foundation/_errors.py +34 -0
  259. pz_foundation/api.py +14 -0
  260. pz_foundation/apps.py +127 -0
  261. pz_foundation/auth/__init__.py +1 -0
  262. pz_foundation/cache_control.py +233 -0
  263. pz_foundation/cli/__init__.py +2 -0
  264. pz_foundation/cli/workers.py +565 -0
  265. pz_foundation/configs/__init__.py +0 -0
  266. pz_foundation/configs/default.env +15 -0
  267. pz_foundation/configs/default.jsonc +452 -0
  268. pz_foundation/db/__init__.py +94 -0
  269. pz_foundation/db/aerich_executor.py +664 -0
  270. pz_foundation/db/config.py +358 -0
  271. pz_foundation/db/connection_manager.py +689 -0
  272. pz_foundation/db/connection_probe.py +204 -0
  273. pz_foundation/db/database.py +1291 -0
  274. pz_foundation/db/deps.py +47 -0
  275. pz_foundation/db/lifecycle_status.py +85 -0
  276. pz_foundation/db/migrations.py +477 -0
  277. pz_foundation/db/mysql.py +57 -0
  278. pz_foundation/db/postgresql.py +409 -0
  279. pz_foundation/db/production_pool_fallback.py +143 -0
  280. pz_foundation/db/public.py +45 -0
  281. pz_foundation/db/session.py +369 -0
  282. pz_foundation/db/sqlite.py +15 -0
  283. pz_foundation/db/tortoise_manager.py +724 -0
  284. pz_foundation/db/tortoise_psycopg.py +148 -0
  285. pz_foundation/docs/README.md +18 -0
  286. pz_foundation/docs/distribution-README.md +319 -0
  287. pz_foundation/docs/infra/350/243/201/345/211/252/344/270/216/350/220/275/344/275/215/350/257/264/346/230/216.md +39 -0
  288. pz_foundation/docs//345/205/254/345/274/200/345/205/215/350/264/271/346/216/245/345/217/243/351/230/262/346/273/245/347/224/250/344/270/216/344/272/272/346/234/272/346/240/241/351/252/214.md +680 -0
  289. pz_foundation/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +288 -0
  290. pz_foundation/docs//350/267/257/347/224/261/344/270/216URL/345/244/204/347/220/206/350/247/204/350/214/203.md +119 -0
  291. pz_foundation/health.py +105 -0
  292. pz_foundation/host/__init__.py +11 -0
  293. pz_foundation/host/builder.py +34 -0
  294. pz_foundation/host/cache_runtime.py +44 -0
  295. pz_foundation/host/db/__init__.py +17 -0
  296. pz_foundation/host/db/aerich_config.py +36 -0
  297. pz_foundation/host/db/config.py +106 -0
  298. pz_foundation/host/db/connection_manager.py +48 -0
  299. pz_foundation/host/db/deps.py +5 -0
  300. pz_foundation/host/db/orm_retry_patch.py +566 -0
  301. pz_foundation/host/db/request_adapter.py +325 -0
  302. pz_foundation/host/db/router.py +28 -0
  303. pz_foundation/host/db/session.py +284 -0
  304. pz_foundation/host/db/tortoise_manager.py +10 -0
  305. pz_foundation/host/idempotency.py +132 -0
  306. pz_foundation/host/lifespan.py +247 -0
  307. pz_foundation/host/redis_runtime.py +100 -0
  308. pz_foundation/host/web.py +790 -0
  309. pz_foundation/infra_provider.py +236 -0
  310. pz_foundation/kv/__init__.py +25 -0
  311. pz_foundation/kv/cache.py +1166 -0
  312. pz_foundation/kv/deps.py +84 -0
  313. pz_foundation/kv/public.py +25 -0
  314. pz_foundation/kv/redis_manager.py +1531 -0
  315. pz_foundation/lazy_exports.py +43 -0
  316. pz_foundation/lazy_imports.py +124 -0
  317. pz_foundation/lifecycle.py +392 -0
  318. pz_foundation/managed_workers.py +1117 -0
  319. pz_foundation/middlewares/__init__.py +26 -0
  320. pz_foundation/middlewares/_settings.py +250 -0
  321. pz_foundation/middlewares/analytics.py +124 -0
  322. pz_foundation/middlewares/cache_control.py +156 -0
  323. pz_foundation/middlewares/compression.py +202 -0
  324. pz_foundation/middlewares/cors.py +62 -0
  325. pz_foundation/middlewares/geo_country.py +44 -0
  326. pz_foundation/middlewares/inner_router.py +50 -0
  327. pz_foundation/middlewares/rate_limited/__init__.py +3 -0
  328. pz_foundation/middlewares/rate_limited/key_limiter.py +115 -0
  329. pz_foundation/middlewares/request_logging.py +104 -0
  330. pz_foundation/middlewares/route_owner.py +309 -0
  331. pz_foundation/middlewares/security_csrf.py +44 -0
  332. pz_foundation/middlewares/security_headers/__init__.py +4 -0
  333. pz_foundation/middlewares/security_headers/conflicts.py +44 -0
  334. pz_foundation/middlewares/security_headers/csp_nonce.py +200 -0
  335. pz_foundation/middlewares/security_headers/security_headers.py +44 -0
  336. pz_foundation/migrations/__init__.py +1 -0
  337. pz_foundation/migrations/pz_foundation/__init__.py +1 -0
  338. pz_foundation/models.py +22 -0
  339. pz_foundation/notifications/__init__.py +23 -0
  340. pz_foundation/notifications/email.py +542 -0
  341. pz_foundation/notifications/public.py +31 -0
  342. pz_foundation/observability/__init__.py +71 -0
  343. pz_foundation/observability/http.py +34 -0
  344. pz_foundation/observability/logger/__init__.py +49 -0
  345. pz_foundation/observability/logger/_bot_settings.py +126 -0
  346. pz_foundation/observability/logger/bot_message.py +592 -0
  347. pz_foundation/observability/logger/core.py +385 -0
  348. pz_foundation/observability/logger/delivery_audit.py +84 -0
  349. pz_foundation/observability/logger/feishu_bot.py +199 -0
  350. pz_foundation/observability/logger/telegram_bot.py +194 -0
  351. pz_foundation/observability/metrics.py +365 -0
  352. pz_foundation/observability/runtime.py +68 -0
  353. pz_foundation/public.py +405 -0
  354. pz_foundation/resources/__init__.py +12 -0
  355. pz_foundation/resources/builder.py +900 -0
  356. pz_foundation/resources/images.py +363 -0
  357. pz_foundation/root_cli.py +20 -0
  358. pz_foundation/routing/__init__.py +203 -0
  359. pz_foundation/routing/canonical.py +486 -0
  360. pz_foundation/routing/convertors.py +82 -0
  361. pz_foundation/routing/declarations.py +843 -0
  362. pz_foundation/routing/exports.py +148 -0
  363. pz_foundation/routing/loaders.py +138 -0
  364. pz_foundation/routing/manifest.py +215 -0
  365. pz_foundation/routing/manifest_provider.py +47 -0
  366. pz_foundation/routing/mounts.py +101 -0
  367. pz_foundation/routing/ordering.py +172 -0
  368. pz_foundation/routing/registry.py +133 -0
  369. pz_foundation/routing/utils.py +28 -0
  370. pz_foundation/runtime.py +234 -0
  371. pz_foundation/settings.py +253 -0
  372. pz_foundation/settings_normalization.py +130 -0
  373. pz_foundation/storage/__init__.py +25 -0
  374. pz_foundation/storage/local.py +209 -0
  375. pz_foundation/storage/public.py +106 -0
  376. pz_foundation/storage/s3.py +116 -0
  377. pz_foundation/storage/service.py +234 -0
  378. pz_foundation/urls.py +19 -0
  379. pz_foundation/utils/__init__.py +6 -0
  380. pz_foundation/utils/merge.py +160 -0
  381. pz_foundation/worker_replicas.py +55 -0
  382. pz_settings_center/__init__.py +5 -0
  383. pz_settings_center/api/__init__.py +5 -0
  384. pz_settings_center/api/runtime_overrides.py +360 -0
  385. pz_settings_center/apps.py +28 -0
  386. pz_settings_center/configs/__init__.py +0 -0
  387. pz_settings_center/configs/default.env +2 -0
  388. pz_settings_center/configs/default.jsonc +1 -0
  389. pz_settings_center/docs/01-settings_center/350/203/275/345/212/233/350/276/271/347/225/214.md +124 -0
  390. pz_settings_center/docs/README.md +12 -0
  391. pz_settings_center/docs/distribution-README.md +150 -0
  392. pz_settings_center/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +48 -0
  393. pz_settings_center/integration_payload.py +18 -0
  394. pz_settings_center/project_helpers.py +405 -0
  395. pz_settings_center/public.py +139 -0
  396. pz_settings_center/routing_helpers.py +73 -0
  397. pz_settings_center/runtime_override_provider.py +61 -0
  398. pz_settings_center/typed_settings.py +324 -0
  399. pz_settings_center/urls.py +9 -0
@@ -0,0 +1,148 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ _CLIENT_CLASS: type | None = None
6
+
7
+
8
+ def get_client_class(db_info: dict[str, Any] | None = None) -> type:
9
+ del db_info
10
+ global _CLIENT_CLASS
11
+ if _CLIENT_CLASS is None:
12
+ _CLIENT_CLASS = _build_client_class()
13
+ return _CLIENT_CLASS
14
+
15
+
16
+ def _build_client_class() -> type:
17
+ from ssl import SSLContext
18
+
19
+ from tortoise.backends.base_postgres import client as postgres_client
20
+ from tortoise.backends.psycopg.client import (
21
+ AsyncConnectionPool as TortoiseAsyncConnectionPool,
22
+ PsycopgClient,
23
+ exceptions,
24
+ psycopg,
25
+ psycopg_pool,
26
+ )
27
+
28
+ class FoundationPsycopgClient(PsycopgClient):
29
+ foundation_pool_class = TortoiseAsyncConnectionPool
30
+
31
+ def __init__(
32
+ self,
33
+ *args: Any,
34
+ conninfo: str = "",
35
+ connect_timeout: float | int | None = None,
36
+ server_options: str = "",
37
+ sslmode: str = "",
38
+ sslrootcert: str = "",
39
+ sslcert: str = "",
40
+ sslkey: str = "",
41
+ sslpassword: str = "",
42
+ target_session_attrs: str = "",
43
+ **kwargs: Any,
44
+ ) -> None:
45
+ self._foundation_conninfo = str(conninfo or "").strip()
46
+ self._foundation_connect_timeout = float(connect_timeout or 0)
47
+ self._foundation_server_options = str(server_options or "").strip()
48
+ self._foundation_conninfo_settings = {
49
+ key: value
50
+ for key, value in {
51
+ "sslmode": sslmode,
52
+ "sslrootcert": sslrootcert,
53
+ "sslcert": sslcert,
54
+ "sslkey": sslkey,
55
+ "sslpassword": sslpassword,
56
+ "target_session_attrs": target_session_attrs,
57
+ }.items()
58
+ if str(value or "").strip()
59
+ }
60
+ super().__init__(*args, **kwargs)
61
+
62
+ async def create_pool(self, **kwargs: Any) -> TortoiseAsyncConnectionPool:
63
+ pool = self.foundation_pool_class(open=False, **kwargs)
64
+ await pool.open()
65
+ return pool
66
+
67
+ @postgres_client.translate_exceptions
68
+ async def create_connection(self, with_db: bool) -> None:
69
+ if self._pool is not None:
70
+ raise RuntimeError("Connection pool already created")
71
+
72
+ server_settings = {
73
+ key: value
74
+ for key, value in dict(self.server_settings or {}).items()
75
+ if value not in (None, "")
76
+ }
77
+ server_options = _join_server_options(
78
+ str(server_settings.pop("options", "") or ""),
79
+ self._foundation_server_options,
80
+ f"-c search_path={self.schema}" if self.schema else "",
81
+ )
82
+ if server_options:
83
+ server_settings["options"] = server_options
84
+ if self.application_name:
85
+ server_settings["application_name"] = self.application_name
86
+
87
+ extra = self.extra.copy()
88
+ extra.setdefault("timeout", self.default_timeout)
89
+ ssl: SSLContext | None = extra.pop("ssl", None)
90
+ if ssl:
91
+ if isinstance(ssl, SSLContext) and ssl.check_hostname:
92
+ server_settings["sslmode"] = "verify-full"
93
+ else:
94
+ server_settings["sslmode"] = "require"
95
+ for key, value in self._foundation_conninfo_settings.items():
96
+ server_settings.setdefault(key, value)
97
+
98
+ if self._foundation_conninfo:
99
+ conninfo = psycopg.conninfo.make_conninfo(self._foundation_conninfo, **server_settings)
100
+ else:
101
+ conninfo = psycopg.conninfo.make_conninfo(
102
+ host=self.host,
103
+ port=self.port,
104
+ user=self.user,
105
+ password=self.password,
106
+ dbname=self.database if with_db else None,
107
+ **server_settings,
108
+ )
109
+
110
+ connection_kwargs: dict[str, Any] = {
111
+ "autocommit": True,
112
+ "row_factory": psycopg.rows.dict_row,
113
+ }
114
+ if self._foundation_connect_timeout > 0:
115
+ connection_kwargs["connect_timeout"] = int(max(1, self._foundation_connect_timeout))
116
+
117
+ self._template = {
118
+ "conninfo": conninfo,
119
+ "min_size": self.pool_minsize,
120
+ "max_size": self.pool_maxsize,
121
+ "kwargs": connection_kwargs,
122
+ "connection_class": psycopg.AsyncConnection,
123
+ **extra,
124
+ }
125
+
126
+ try:
127
+ self._pool = await self.create_pool(**self._template)
128
+ await self._pool.open(wait=True, timeout=extra["timeout"])
129
+ self.log.debug("Created connection pool %s with params: %s", self._pool, self._template)
130
+ except (psycopg.errors.InvalidCatalogName, psycopg_pool.PoolTimeout):
131
+ raise exceptions.DBConnectionError(
132
+ f"Can't establish connection to database {self.database}"
133
+ )
134
+
135
+ return FoundationPsycopgClient
136
+
137
+
138
+ def _join_server_options(*values: str) -> str:
139
+ return " ".join(part.strip() for part in values if str(part or "").strip())
140
+
141
+
142
+ def __getattr__(name: str) -> Any:
143
+ if name == "FoundationPsycopgClient":
144
+ return get_client_class()
145
+ raise AttributeError(name)
146
+
147
+
148
+ __all__ = ["FoundationPsycopgClient", "get_client_class"]
@@ -0,0 +1,18 @@
1
+ # Docs Index
2
+
3
+ 这是 `pz_foundation` 的正式文档入口。
4
+
5
+ 阅读顺序:
6
+ - `设计文档.md`
7
+ - `路由与URL处理规范.md`
8
+ - `公开免费接口防滥用与人机校验.md`
9
+ - `../README.md`
10
+ - `pz_foundation/public.py`
11
+ - `pz_foundation/urls.py`(如果存在)
12
+ - `pz_foundation/settings.py`
13
+ - `configs/default.jsonc`
14
+ - `tests/`
15
+
16
+ 说明:
17
+ - `docs/设计文档.md` 是当前包的冻结设计入口。
18
+ - `README.md`、正式公开面与契约测试用于补充设计文档未展开的实现细节。
@@ -0,0 +1,319 @@
1
+ # pz_foundation
2
+
3
+ `pz_foundation` 是 `pz_contrib` 下的官方基础设施最小子包。
4
+
5
+ 按 `pz` 设计文档口径,它是 `pz-cli==5.0.0` wheel 内的正式叶子 app:
6
+
7
+ - distribution: `pz-cli`(`pz-foundation` 独立 distribution 已退出发布图)
8
+ - 目录名: `pz_foundation`
9
+ - import 包名: `pz_foundation`
10
+ - `app_id`: `pz_foundation`
11
+
12
+ ## 设计依据
13
+
14
+ 本 README 按 `pz` 正式设计文档口径编写,回链如下:
15
+
16
+ 如果本 README 与 `pz` 设计文档、正式 contract 或正式装配约定冲突,以 `pz` 设计文档为准。
17
+
18
+ - [`03-App最小子包规范`](../../../../pz_core/pz_core/docs/pz规范与使用/03-App最小子包规范.md)
19
+ - [`10-测试与契约规范`](../../../../pz_core/pz_core/docs/pz规范与使用/10-测试与契约规范.md)
20
+ - [`14-分层与扩展规范`](../../../../pz_core/pz_core/docs/pz规范与使用/14-分层与扩展规范.md)
21
+ - [`15-子包开发使用手册`](../../../../pz_core/pz_core/docs/pz规范与使用/15-子包开发使用手册.md)
22
+
23
+ ## 负责什么
24
+
25
+ - database、cache、storage、mail、health、observability 等基础设施 runtime。
26
+ - 事务、连接生命周期、idempotency 与基础资源装配。
27
+ - 通用资源 merge/build、图片响应式派生与资源构建缓存。
28
+ - 通用中间件、provider 与 infra facade。
29
+ - 官方基础设施启动与关闭协议。
30
+ - 项目级 detached managed worker supervisor,以及 `worker.role` 的统一拉起 / 停止 / 状态编排。
31
+
32
+ ## 不负责什么
33
+
34
+ - 业务数据模型与业务状态机真相。
35
+ - 页面、SEO、账户、认证与后台控制面真相。
36
+ - 宿主项目专用 bootstrap hack。
37
+
38
+ ## 正式入口与真相源
39
+
40
+ - `pz_foundation/apps.py`
41
+ - 唯一正式 app 入口;声明 lifecycle、provider 与 middleware 装配。
42
+ - `pz_foundation/urls.py`
43
+ - 唯一正式 URL 真相源。
44
+ - `pz_foundation/public.py`
45
+ - 唯一稳定公开面;对外暴露 `FoundationFacade`、DB facade、idempotency helper 与 infra startup/shutdown contract。
46
+ - `pz_foundation/settings.py`
47
+ - 正式 settings schema 声明入口。
48
+ - `pz_foundation/configs/default.jsonc`
49
+ - 静态默认值真相源。
50
+
51
+ ## 功能拆分
52
+
53
+ - `db/`
54
+ - 连接管理、session、事务与 ORM 绑定。
55
+ - `host/`
56
+ - host 级 cache / db / lifespan runtime。
57
+ - `storage/`
58
+ - storage facade 与存储访问公开面。
59
+ - `observability/`
60
+ - logger、business event、bot message 等观测能力。
61
+ - `notifications/`
62
+ - mail 与通知相关能力。
63
+ - `managed_workers.py`
64
+ - `worker.role` 的发现、目标副本数展开、状态聚合、supervisor 生命周期与强制停止协议。
65
+ - `cli/workers.py`
66
+ - 项目级 worker 管理 CLI;提供 `list/status/stop/restart/run`,并负责 detached supervisor 的签名比对与重启策略。
67
+ - `resources/`
68
+ - 通用资源构建 provider、`resources.post_build` 扩展执行、图片响应式派生策略与资源构建缓存。
69
+
70
+ ## 扩展点与公开面
71
+
72
+ 本包的 app 入口会统一挂载 foundation middlewares 与 providers;其它 app 不应再重复建立第二套 infra runtime。
73
+
74
+ ### Routing 与 Lazy Helper
75
+
76
+ `pz_foundation` 承担官方通用 routing helper 的落地职责;这类 helper 不属于 `pz` core。
77
+
78
+ 正式约定:
79
+
80
+ - 每个 app 的正式 URL 入口固定为 `<pkg>.urls`
81
+ - 简单 app 使用 `urls.py`
82
+ - 复杂 app 使用 `urls/`,但正式入口仍然是 `urls/__init__.py`
83
+ - 子包只声明自己的 URL 模块与 include 关系
84
+ - prefix 由上层统一挂载
85
+ - 业务包不负责最终装配、排序与清理
86
+
87
+ foundation 当前提供两层 API:
88
+
89
+ - `urls/include` 声明式 API
90
+ - `DeclaredUrlSpec(...)`
91
+ - `path(...)`
92
+ - `include(...)`
93
+ - `mount(...)`
94
+ - `compile_urlpatterns(...)`
95
+
96
+ 正式合同:
97
+
98
+ - `<pkg>.urls` 只允许导出 `urlpatterns`
99
+ - `urlpatterns` 必须是 `path(...)`、`include(...)`、`mount(...)` 或 `DeclaredUrlSpec(...)` 的声明序列
100
+ - `<pkg>.urls` 使用 `path(...)` 时必须声明 `app_name`
101
+ - `path(...)` 必须直接传入函数对象;不再支持字符串 handler 名
102
+ - `path(...)` 的路径字符串使用 FastAPI / Starlette 原生 path 参数语法;既支持 `/{lang}/{module}/{slug}`,也支持 `/{lang:locale}/{slug}` 这类 convertor 形式
103
+ - `path(...)` 声明的路径字符串会原样进入 FastAPI 路由表;foundation 不会在运行时再次重写业务声明层的 path 参数语法
104
+ - `path(..., enabled_when="runtime_flag")` 表示这条路径只会在 `runtime.runtime_flag` 为真时注册
105
+ - 目录型页面 canonical URL 统一以 `/` 结尾;文件型 URL 不以 `/` 结尾
106
+ - `urlpatterns` 只声明 canonical 版本;不要在业务包里同时手工注册两套尾斜杠路径
107
+ - 全站 trailing-slash 规范只有一套正式方案:由 route manifest 持有 slash policy,由 host 统一执行 normalization
108
+ - 业务包不得在 handler、middleware 或局部 helper 里重复实现第二套 slash redirect 逻辑
109
+ - UI href 生成统一使用 `pz_foundation.routing.public_canonical_href(...)`,模板层使用 `pz_site_ui` 暴露的 `canonical_public_href(...)`
110
+ - 子包模板不要手动拼接 `/{lang}/...`、`/en/...` 或尾斜杠;语言前缀、alias、query、fragment 与 API/static 跳过规则由 foundation 统一处理
111
+ - `DeclaredUrlSpec.namespace` 必须是稳定、非空、可审计的 dotted identifier
112
+ - `DeclaredUrlSpec.path_prefix` 只能是空字符串或以 `/` 开头的非根 prefix
113
+ - `DeclaredUrlSpec.replace_target` 若存在,必须指向已声明 namespace,用于显式替换
114
+ - `DeclaredUrlSpec.route_hints` 必须在声明期固化
115
+ - `DeclaredUrlSpec.conflict_policy` 的正式默认值固定为 `fail`
116
+ - `include(...)` 负责子模块 include;上层 prefix 会与子模块 prefix 叠加;上层 namespace 会作为子模块 namespace 前缀继续下沉
117
+ - `mount(...)` / `include(...)` 遵循 Django 风格父子 URLconf 语义:父级消费公共 prefix,子 app / 子 router 只声明相对路径,不得重复声明 mount prefix;例如挂载到 `/api/v1/payments` 时,子路由写 `/create-checkout-session`,不能写 `/api/v1/payments/create-checkout-session`
118
+ - foundation 会先编译 `route_manifest`,再进入 FastAPI 挂载;同一路径/方法冲突必须在真实挂载前失败
119
+ - `host.route` / `admin.panel` 这类 host 扩展路由也会先转成 `DeclaredUrlSpec`,再进入同一条 registry 编译链
120
+ - host 挂载后会把 mounted route namespace 记录到 `app.state.pz_route_registry`
121
+ - host 也会保留已编译的 `app.state.pz_route_manifest`
122
+
123
+ 推荐示例:
124
+
125
+ ```python
126
+ from __future__ import annotations
127
+
128
+ from pz_foundation.routing import include, path
129
+
130
+ from .views import demo_page
131
+
132
+
133
+ app_name = "pz_demo"
134
+
135
+ urlpatterns = (
136
+ path("/demo", demo_page, name="pz_demo:demo-page"),
137
+ include("pz_demo.api", path_prefix="/api/v1", namespace="pz_demo.api"),
138
+ )
139
+ ```
140
+
141
+ URL 处理细则见 [`docs/路由与URL处理规范.md`](docs/路由与URL处理规范.md)。
142
+
143
+ `public.py` 当前稳定导出聚焦:
144
+
145
+ - `FoundationFacade`
146
+ - `FoundationDbFacade`
147
+ - `get_foundation_facade()`
148
+ - `get_db_facade()`
149
+ - `setup_infra()`
150
+ - `shutdown_infra()`
151
+ - `ensure_db()`
152
+ - `in_transaction()`
153
+ - `run_in_transaction()`
154
+ - `claim_idempotency()`
155
+ - `clear_idempotency_claim()`
156
+
157
+ `COMPAT_EXPORTS` 当前为空。
158
+
159
+ ## 配置约定
160
+
161
+ 本包默认配置位于 `pz_foundation/configs/default.jsonc`,运行时正式读取路径为:
162
+
163
+ - `settings_center.settings.pz_foundation.cache`
164
+ - `settings_center.settings.pz_foundation.health`
165
+ - `settings_center.settings.pz_foundation.mail`
166
+ - `settings_center.settings.pz_foundation.observability`
167
+ - `settings_center.settings.pz_foundation.resources.images`
168
+ - `settings_center.settings.pz_foundation.storage`
169
+
170
+ database 的唯一正式真相源位于 `settings_center.settings.pz_foundation.database` /
171
+ `pz.jsonc -> apps.pz_foundation.database`;
172
+ `pz_foundation` 不再维护第二套 app 级 database namespace。
173
+
174
+ database runtime 还正式承载生产连接参数:`connect_timeout`、`pool_acquire_timeout`、
175
+ `statement_timeout_ms`、`idle_in_transaction_session_timeout_ms`、`pool_max_lifetime`、
176
+ `pool_max_idle`、`reconnect_timeout`、`health_check_interval`。这些参数由 settings center 编译后传入
177
+ foundation Tortoise backend,不允许子包在业务路径直接拼接第二套数据库连接配置。
178
+
179
+ PostgreSQL HA 的正式 surface 是 `database.urls`。单节点数据库也写成一个元素的 URL 列表;当解析出多个
180
+ writer 候选节点时,foundation 必须把 `default` 编译成一个 psycopg/libpq multi-host conninfo,并用
181
+ `target_session_attrs=read-write` 在新建连接时选择当前可写节点;不得把第一个 URL 或第一个 host 固定成长期主库。
182
+ 集群切换后,已有连接不会自动迁移,只有明确的连接失效或写连接命中只读节点等角色失效信号才触发受控重建 pool。
183
+
184
+ 数据库探活分为两类:启动/请求路径只检查 manager 与 pool lifecycle 状态,不执行 SQL;
185
+ 周期性 readiness probe 可以执行 `SELECT 1`,但只允许由 foundation 后台任务执行,且必须先证明连接
186
+ 处于 autocommit 模式。无法证明 autocommit 时必须拒绝探测,不能用隐式事务加 rollback 作为兜底,
187
+ 也不能留下 `idle in transaction`。请求路径只读取 lifecycle,default pool 不 ready 时 fail fast,
188
+ 不在请求里执行 `ensure_ready()`、`reconnect()` 或 SQL 探活。
189
+
190
+ 生产健康检查按职责分层:`/health` / `/live` 只表示进程存活,不碰数据库;`/ready` 只读取 manager / pool
191
+ lifecycle 状态,不执行 SQL、不借业务连接;后台 readiness probe 是唯一允许常规执行 SQL 的探活路径。
192
+ `PoolTimeout` 被视为池容量耗尽、连接泄漏或补连接失败风险,不属于断连重建信号。记录该错误时必须带
193
+ pool size、可用连接数、等待队列、连接错误、请求错误等池快照;必要时可以带冷却窗口额外执行一次独立短连接
194
+ 诊断来区分“数据库不可达”和“业务池耗尽”。独立诊断不得复用业务池、不得进入业务事务、不得访问业务表。
195
+ `PoolTimeout` 日志必须输出 `diagnosis.category`,用于直接区分数据库不可达、应用池耗尽、pool 补连接停滞和普通容量压力。
196
+ 连接池轮换只能作为受控恢复动作,必须有冷却窗口,不能在单次容量超时、锁等待或未知错误时自动重建。
197
+
198
+ `settings.py` 只负责 `AppSettings` schema、默认值与 runtime override 声明。
199
+
200
+ 资源图片派生的正式配置位于 `pz_foundation.resources.images`。常规 `pz run` 只补齐缺失派生;合并 static 内已有同名派生文件且未显式 force 时会跳过。
201
+ 默认配置中 `pz_foundation.resources.images.force=true`,因此 `pz resources images` 不传 `--force` 也会强制覆盖同名派生;如果宿主显式改为 false,则可继续通过 CLI 参数强制:
202
+
203
+ ```bash
204
+ pz resources images --force -d .
205
+ ```
206
+
207
+ 图片派生输出只进入当前 `ResourceManifest` 的合并 static 产物,不写回业务包源码目录;站点业务包不得再提供第二套图片派生命令或配置 namespace。
208
+
209
+ 环境变量覆盖示例由本包维护,不再由 `pz` core 项目模板托管。需要写入宿主 `.env` 时,使用本包 settings namespace:
210
+
211
+ - `pz_foundation__database__password`
212
+ - `pz_foundation__database__ssl_root_cert`
213
+ - `pz_foundation__mail__password`
214
+ - `pz_foundation__cache__password`
215
+ - `pz_foundation__storage__access_key_id`
216
+ - `pz_foundation__storage__secret_access_key`
217
+
218
+ observability logger 的可选通知通道也属于 `pz_foundation.observability.logger`,运行时只消费 settings center;项目按需显式声明,不进入默认托管模板:
219
+
220
+ - `feishu.webhook_error_event` / `feishu.secret_error_event`
221
+ - `feishu.webhook_warning_event` / `feishu.secret_warning_event`
222
+ - `feishu.webhook_custom_event` / `feishu.secret_custom_event`
223
+ - `feishu.webhook` / `feishu.secret`
224
+ - `telegram.bot_token` / `telegram.chat_id`
225
+ - `telegram.bot_token_custom_event` / `telegram.chat_id_custom_event`
226
+
227
+ managed worker 补充约定:
228
+
229
+ - `pz_foundation` 不保存业务 worker 的数量真相;目标副本数仍由声明该 `worker.role` 的 owner app settings 提供。
230
+ - `pz_foundation.managed_workers.force_restart_on_host_start` 是 `pz run` 自动托管入口是否强制收口旧 supervisor / worker 的唯一配置真相源,默认值为 `true`。
231
+ - `pz_foundation.managed_workers.default_replica_count` 是 worker 声明了 `replica_count_setting` 但 owner app settings 缺失 / 非正数时的全局兜底副本数,默认值为 `1`。
232
+ - `WorkerRoleSpec.replica_count_setting` 是副本数量的正式绑定字段;正常每个 worker 都应显式声明自己的 count setting。supervisor 运行时只从 `plan.settings.app_settings(<owner_app>)` 读取对应值,不读取子包 `configs/default.jsonc`。
233
+ - 未声明 `replica_count_setting` 的 worker 视为冻结 / legacy singleton,目标副本数固定为 `1`,不受全局 fallback 扩容。
234
+ - `WorkerReplicaCountResolver` 是 managed worker 副本数解析的唯一对象;其它代码不得手工拼接 owner settings、Task Center settings 或默认值。
235
+ - `WorkerRoleSpec.auto_start_setting` 是自动拉起开关的正式绑定字段;声明阶段只给默认值,supervisor 运行时从 owner app settings 读取最终值。
236
+ - `WorkerRoleSpec.worker_kind` 是 worker 进程职责分类;foundation 只在 status、worker_targets 和 CLI projection 中透出,不据此替业务 owner 判断任务、角色或成功真相。
237
+ - 新增 worker count 默认键时,owner app 必须同时更新 settings schema 与 `configs/default.jsonc` 模板,并通过 `pz settings update --project-dir <project>` 同步到项目根配置;运行时真相仍是 settings center 编译后的 `SettingsSnapshot`。
238
+ - detached supervisor 的状态真相位于项目 runtime 目录下的 `managed_workers/supervisor.state.json`,其中包含:
239
+ - `pz_env`
240
+ - `worker_targets`
241
+ - 当前 supervisor pid 与 phase
242
+ - managed worker 的日志与副本状态文件统一收口到 `managed_workers/` 目录下:
243
+ - `managed_workers/logs/*.log`
244
+ - `managed_workers/workers/<app>/<tool>/`
245
+ - worker 管理 CLI 集中在 `pz_foundation.cli.workers`:
246
+ - `pz workers list [name ...]`
247
+ - `pz workers status [name ...]`
248
+ - `pz workers stop [name ...]`
249
+ - `pz workers restart [name ...]`
250
+ - `pz workers run [name ...]`
251
+ - `workers restart --start-timeout <seconds>` 控制启动后等待状态刷新的时间,超时后继续用 `workers status` 读取最终状态。
252
+ - `pz pz_foundation workers ...` 是同一实现的 app CLI 入口;root 入口与 app 入口不得分叉。
253
+
254
+ ## 运行边界
255
+
256
+ - 其它官方子包如需 DB、cache、storage、observability,应统一复用 `pz_foundation.public`,不要在包内各自复制基础设施实现。
257
+ - `pz_foundation` 只提供通用 infra,不拥有业务成功真相。
258
+ - 若某项能力需要业务扩展,应优先通过正式 provider / facade 方式扩展,而不是修改宿主 bootstrap。
259
+ - cache / redis 的正式语义是“能力可降级,但不能把整个宿主默认拖死”:
260
+ - redis 未启用或未配置时,宿主仍应正常启动,cache capability 标记为 `disabled` / `unavailable`
261
+ - redis 已配置但连接失败时,宿主仍应启动,并把 cache capability 标记为 `degraded` / `unavailable`
262
+ - `settings_center.settings.pz_foundation.cache` 还正式承载 redis 快失败参数:`connect_timeout_seconds`、`socket_timeout_seconds`、`operation_max_attempts`、`connection_retry_attempts`、`retry_base_delay_seconds`、`retry_max_delay_seconds`、`acquire_failure_cooldown_seconds`、`health_failure_cooldown_seconds`
263
+ - foundation 的 async cache facade 会把 redis 操作错误向上抛出,由上层子包决定记录 error、继续当前状态、回退 DB 或返回 `503`
264
+ - 依赖 cache 的上层能力(例如 `pz_auth` 的 session control)在请求期继续按各自 contract fail-closed,不得静默放行
265
+ - managed worker 由拥有 worker 的子包通过正式 app CLI 暴露启动入口,由 `pz_foundation` detached supervisor 统一托管;`pz run` 是宿主启动时自动托管入口。
266
+ - `pz run` 自动托管看到的基础设施或外部入口 worker,不代表 Agent actor / role 实例都被系统默认启动;actor 常驻与任务驱动边界由 Agent 支持包自己的设计文档约束。
267
+ - `pz run` 触发 worker 自动托管前必须先做 Web host/port 绑定预检;地址不可用时直接失败,不得先停止旧 supervisor / worker。
268
+ - worker supervisor 的正式行为由 `pz_foundation` 实现:
269
+ - `force_restart_on_host_start = true` 或命令显式 `--force-restart` 时,先 stop 再按当前 `RuntimePlan` / settings 重启 supervisor;
270
+ - `--no-force-restart` 或配置显式关闭时,当前健康 worker 数量已达到 `worker_targets` 时不重复拉起;
271
+ - 当前数量不足时补齐到目标数量;
272
+ - `pz_env` 或 `worker_targets` 签名变化时,先 stop 再重启 supervisor;
273
+ - detached supervisor 和它托管的 worker 子进程统一通过正式 `pz` 启动;`PZ_ENV` 优先继承当前宿主 `pz run`,缺失时才回退到当前 `RuntimePlan` 的 `pz_env`,并显式携带 `PZ_PROJECT_DIR`。
274
+ - `stop_managed_workers(...)` 属于强制收口入口,会停止 supervisor 与匹配 worker 副本并重写 stopped state;不传选择条件时作用于自动托管 worker 集合。
275
+ - `workers restart` 是人工运维的一键重启入口,会先执行正式 stop,再拉起新的 detached supervisor。
276
+ - `workers run --detach --force-restart` 仍是底层 supervisor 入口;`--no-force-restart` 可为本次命令显式关闭该行为。
277
+
278
+ ## 验证方式
279
+
280
+ 子包级 import smoke:
281
+
282
+ ```bash
283
+ cd <pz_contrib_root>/pz_foundation
284
+ .venv/bin/python -c 'import pz_foundation, pz_foundation.public'
285
+ ```
286
+
287
+ 稳定 import surface smoke:
288
+
289
+ ```bash
290
+ cd <pz_contrib_root>/pz_foundation
291
+ .venv/bin/python - <<'PY'
292
+ import importlib
293
+
294
+ modules = [
295
+ "pz_foundation.public",
296
+ "pz_foundation.db",
297
+ "pz_foundation.kv",
298
+ "pz_foundation.observability",
299
+ "pz_foundation.notifications",
300
+ "pz_foundation.middlewares",
301
+ ]
302
+ failed = []
303
+ for module in modules:
304
+ try:
305
+ importlib.import_module(module)
306
+ print("OK", module)
307
+ except Exception as exc:
308
+ failed.append((module, repr(exc)))
309
+ print("FAIL", module, repr(exc))
310
+ if failed:
311
+ raise SystemExit(1)
312
+ PY
313
+ ```
314
+
315
+ 共享 surface 改动后的最终验证:
316
+
317
+ ```bash
318
+ pz env sync --project-dir /path/to/project
319
+ ```
@@ -0,0 +1,39 @@
1
+ # infra 裁剪与落位说明
2
+
3
+ `pz_foundation` 是官方基础设施 owner。旧 core / infra 中携带具体实现语义的内容,必须下沉到本包或对应 owning 子包,不能回流到 `pz` core。
4
+
5
+ ## foundation 接管的能力
6
+
7
+ `pz_foundation` 负责以下官方通用基础设施实现:
8
+
9
+ - DB 连接、事务、迁移执行与 ORM 绑定。
10
+ - cache / Redis facade 与降级状态。
11
+ - storage facade 与本地 / 对象存储 adapter。
12
+ - mail / notifications。
13
+ - observability logger、业务事件、bot message 与 exporter 绑定。
14
+ - 通用 infra middleware,例如 request logging、cache control、security headers、CSRF、analytics、geo country。
15
+ - host 级 infra startup / shutdown lifecycle。
16
+
17
+ ## 不属于 foundation 的能力
18
+
19
+ 以下内容必须继续由自己的 owner 维护:
20
+
21
+ - 模板、Jinja、i18n、站点 UI、共享前端 runtime:`pz_site_ui`。
22
+ - auth resolver、admin checker、登录跳转、route policy 消费:`pz_auth`。
23
+ - redirect rules cache 与 redirect runtime:redirect owner。
24
+ - API key、额度、billing、worker、task dispatch 等业务域能力:对应业务 / platform owner。
25
+
26
+ ## 迁移落位规则
27
+
28
+ - 具体第三方 SDK、adapter、exporter、middleware 实现不得留在 `pz` core。
29
+ - foundation 对外只暴露 `public.py` 中的稳定 facade;其它子包不得依赖 foundation 内部 manager / adapter 路径。
30
+ - 所有运行态状态必须绑定 `ProjectContext` / app context,不能通过 import-time 全局单例跨项目复用。
31
+ - local storage 未显式配置 `base_dir` 时,默认根必须来自 `ProjectContext.asset_dir`,再追加 `storage.subdir`;不得回退到历史 `data_dir` 或 `.runtime`。
32
+ - middleware 必须消费编译后的 middleware config / transport config,不得构造期直接读取全局 settings。
33
+ - request logging、security headers、CSRF、geo、analytics 等实现需要明确 owner、scope、reset、shutdown 与敏感信息脱敏规则。
34
+
35
+ ## 验证要求
36
+
37
+ - foundation 自己维护稳定 import surface smoke,不由 `pz` core 发布门禁硬编码。
38
+ - foundation 的 DB/cache/storage/observability/middleware 契约测试归本包测试集。
39
+ - core 侧只验证 provider / manifest / lifecycle 协议,不验证 foundation 内部模块清单。