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,571 @@
1
+ # App 最小子包规范
2
+
3
+ > settings 单一路径口径:Python 运行时代码只允许 `import pz_settings_center.public as settings_center`,并通过 `settings_center.settings.<app_id>.<field>` 读取;`settings.py` / `settings/` 只负责声明,不再作为运行时读取入口。
4
+ > 命名单一路径口径:每个正式最小子包必须有稳定唯一的 `app_id`,settings namespace 必须与 `app_id` 一致;新建子包默认让目录名、import 包名与 `app_id` 对齐,distribution 使用对应的 Python 分发名,但不强制特定技术前缀。运行时发现的唯一入口真相源是标准 `apps.py`,目录结构只作为组织与治理约束。
5
+
6
+ ## 1. 目标
7
+
8
+ `pz` 的最小装配单元是 app。
9
+
10
+ - `pz` 是唯一正式基础包,也是唯一可以独立启动的包
11
+ - 其它最小子包统一作为 `pz` 的插件被发现和加载
12
+
13
+ 无论是官方维护最小子包、外部业务子包还是独立子包,均使用同一套结构约定。
14
+
15
+ 分类:
16
+
17
+ - 官方维护最小子包
18
+ - 官方 `library app`
19
+ - 允许被其它 app 通过 `public.py` 依赖
20
+ - 独立子包 app
21
+ - `integration app`
22
+ - 不允许被其它 app 直接 import
23
+ - 只允许通过稳定集成边界交互
24
+
25
+ ## 2. 标准目录要求
26
+
27
+ 完整项目目录结构以 `01-目录与分层规范.md` 为准。
28
+
29
+ app 子包自身至少应具备以下组成:
30
+
31
+ - `pyproject.toml`
32
+ - app 包目录
33
+ - `__init__.py`
34
+ - `apps.py`
35
+ - `public.py`
36
+ - `auth/`
37
+ - `configs/default.jsonc`
38
+ - `configs/default.env`
39
+ - `settings.py` 或 `settings/`
40
+ - `urls.py` 或 `urls/`
41
+ - `models.py`
42
+ - `templates/`
43
+ - `static/`
44
+ - `locales/`
45
+ - `pages/`
46
+ - `migrations/<app_id>/`
47
+
48
+ 约束:
49
+ - `apps.py` 是唯一正式 app 入口
50
+ - `public.py`、`auth/`、`configs/default.jsonc`、`configs/default.env`、`settings.py` 或 `settings/`、`urls.py` 或 `urls/`、`models.py`、`templates/`、`static/`、`locales/`、`pages/`、`migrations/` 按能力需要出现
51
+ - `configs/` 是正式 Python 子包,必须包含 `configs/__init__.py`;`configs/default.jsonc` 与 `configs/default.env` 必须随 wheel 一起分发
52
+ - `pages/` 是页面声明目录,只放页面中心可编译的页面声明,不放 settings 默认值、secret、运行时逻辑或业务 provider 实现
53
+ - `auth/` 推荐作为每个最小子包都预留的空包;普通场景保持为空,不作为第二套默认认证入口
54
+
55
+ ### 2.1 `pages/` 页面声明目录
56
+
57
+ `pages/` 用于承载页面中心从业务 app 收集的正式页面声明。它是 app 资源的一类,不是第二套 settings,也不是第二套 app 入口。
58
+
59
+ `pages/` 是按治理需求启用的声明目录,不是所有 Web 页面的必填登记册。普通功能页、用户态页面、轻量支持页优先使用 `<pkg>.urls` 声明显式路由,用 `templates/`、`static/`、`locales/` 和页面 controller 完成渲染;需要共享 shell、多语言页面状态时,通过 `page.profile_provider` / `PageProfile` 或 `pz_site_ui` 的 request page state 合同提供事实。只有页面需要 Page Center 的自动注册、canonical / alias / hreflang、sitemap、page renderer、长尾治理或索引审查能力时,才进入 `pages/*.jsonc`。
60
+
61
+ 正式约束:
62
+
63
+ - 路径固定为 `<app_package>/pages/`
64
+ - 页面声明按页面命名空间与页面文件组织,例如 `pages/base.jsonc`、`pages/<namespace>/base.jsonc`、`pages/<namespace>/<page>.jsonc`
65
+ - 页面声明拥有独立的页面配置命名空间;它和 settings namespace 一样必须稳定、单一、可审计
66
+ - 页面配置命名空间固定由 `owner_app + 页面相对路径` 共同确定,不允许再单独声明第二个 `page_namespace`
67
+ - `pages/base.jsonc` 属于 owner app 自己的根页面命名空间,不是无主的全局页面
68
+ - `pages/` 服从和 `templates/`、`static/`、`locales/`、`template_config/`、`migrations/` 相同的正式资源覆盖语义
69
+ - 页面声明文件必须由页面中心定义 schema、校验、冲突裁决和编译诊断
70
+ - 页面声明在运行时使用前必须先进入 app registry / resource discovery / `ResourceManifest` / 页面中心编译链
71
+ - Web、CLI、worker 运行期不得绕过编译链临时扫描 `pages/` 并形成第二份运行图
72
+ - 未进入 `pages/` 的普通页面不得为了共享多语言或 shell 再发明第二套页面配置;它们应消费 `PageProfile` / `pz_site_ui` 的正式页面状态合同
73
+ - `configs/default.jsonc` 只放 `pz settings init/update` 可同步到项目配置的 app settings 默认值和受控顶层路由默认值;页面声明不得塞回 `configs/default.jsonc`
74
+
75
+ ## 3. `apps.py` 约定
76
+
77
+ 每个 app 必须暴露一个 `app` 对象。
78
+
79
+ 补充说明:
80
+
81
+ - `installed_apps` 可以声明正式最小子包,也可以声明文件夹/容器目录
82
+ - 每个最小子包都必须显式提供自己的 `apps.py`
83
+ - 分组目录只用于 Git 与源码组织,不是运行时 namespace
84
+ - 若 `installed_apps` 声明的是文件夹/容器目录,框架必须自动递归发现其中嵌套的最小子包
85
+ - 宿主不需要手工把容器内所有最小子包逐个列出
86
+ - `installed_apps` 的条目语法固定为目录名,不接受文件系统路径、distribution 名或 `<pkg>.apps:app`
87
+ - `installed_apps` 一旦同时出现容器条目与显式叶子条目,作者面工具写回时必须收敛成单一的叶子 app 有序列表,不保留长期混写状态
88
+
89
+ ### 3.1 最小子包发现算法
90
+
91
+ 为了避免不同入口各自实现一套扫描逻辑,最小子包发现算法固定如下:
92
+
93
+ 1. 先按 `installed_apps` 中声明的顺序处理每个目录名
94
+ 2. 若条目本身命中最小子包,则直接收录并停止继续向下递归
95
+ 3. 若条目是容器目录,则只递归扫描其子目录
96
+ 4. 容器内部统一按目录名字典序做深度优先展开
97
+ 5. 展开完成后,以得到的最小子包有序列表进入 app registry / settings / resources / routes
98
+
99
+ 最小子包的判定标准固定为标准 `apps.py`:
100
+
101
+ - 候选目录或其 Python 包目录内存在 `apps.py`
102
+ - `apps.py` 内有 app class
103
+ - app class 内以静态字符串声明 `id`
104
+ - `apps.py` 内有模块级 `app = <AppClass>()`
105
+ - 该 `app` 对象最终可解析出合法 `app.id`
106
+
107
+ 补充约束:
108
+
109
+ - 一旦某个目录已被判定为最小子包,就停止向下扫描其内部子目录
110
+ - 不允许通过模块名猜测、历史 alias、旧容器命名或 package-level `app` 猜测把一个目录判成最小子包
111
+ - 非 app 模块不允许使用 `apps.py` 作为普通实现文件名;`apps.py` 是 app 入口保留名
112
+ - 只有标准 `apps.py` 才能进入 app registry / settings / resources / routes 的正式装配链
113
+ - 发现阶段若得到重复 `app_id`,必须直接报错,不允许静默跳过或以后出现者覆盖先出现者
114
+ - 发现阶段必须忽略 `.git/`、`.venv/`、`__pycache__/`、`dist/`、`build/` 这类非源码目录
115
+
116
+ 最小示例:
117
+
118
+ ```python
119
+ from fastapi import APIRouter
120
+
121
+
122
+ class MyApp:
123
+ id = "pz_my_app"
124
+ name = "My App"
125
+ version = "0.1.0"
126
+ required_pz = ">=0.1.0"
127
+
128
+ def routers(self):
129
+ return []
130
+
131
+
132
+ app = MyApp()
133
+ ```
134
+
135
+ ## 4. app 元数据约定
136
+
137
+ 正式字段:
138
+ - `id`
139
+ - `name`
140
+ - `version`
141
+ - `required_pz`
142
+
143
+ 按需字段:
144
+ - `requires_apps`
145
+ - `required_protocols`
146
+
147
+ 约束:
148
+ - `id` 必须稳定、唯一,并使用项目内正式注册的 app id
149
+ - 同一 app 的配置命名空间、迁移目录、模型 label 应统一使用同一 `app_id`
150
+ - `required_pz` 应成为标准字段,不只在官方维护最小子包中使用
151
+ - 若声明 `requires_apps`,应优先写 `app_id`,而不是依赖模块路径后缀匹配
152
+
153
+ 补充要求:
154
+ - `name` 只用于展示,不参与装配判断
155
+ - `id` 一旦对外发布,不应随重构轻易变更
156
+ - app 元数据不负责声明“替换谁”;app 替换关系的唯一正式真相源是项目级 `[app_replacements]`
157
+
158
+ 补充约束:
159
+
160
+ - `id` 应使用稳定的 lower_snake_case 技术名,不应混用大小写、短横风格或展示名
161
+ - `id` 必须同时作为:
162
+ - settings namespace
163
+ - migration owner
164
+ - extension owner
165
+ - 诊断输出中的正式身份
166
+ - 不强制特定技术前缀;历史 app id 以已发布稳定值为准。若后续确需改名,必须对 `app.id`、settings namespace、目录名、import 包名、distribution 和项目配置做一次性显式迁移,不允许长期同时支持两套 namespace。
167
+ - 若 app 需要被外部依赖,还应明确声明其 `public.py` 入口与对外 facade/capability contract
168
+
169
+ ### 4.1 `app.id` 与 settings namespace 的单一规则
170
+
171
+ 为了避免“包名一套、`app.id` 一套、settings namespace 又一套”的三重真相源,正式规则固定如下:
172
+
173
+ - 每个正式叶子 app 只有一个稳定身份:`app.id`
174
+ - settings namespace 必须与 `app.id` 完全一致
175
+ - 不允许再单独声明 `settings_namespace`、`config_namespace` 或任何同义字段
176
+ - 不允许通过包尾名、replacement 名、历史 alias 自动派生第二个 namespace
177
+
178
+ 补充要求:
179
+
180
+ - `apps.py` 必须通过模块级 `app` 对象显式声明 `app.id`
181
+ - `app.id` 应是 class 上的静态字符串,不能依赖 settings 常量、环境变量、函数调用或运行时计算
182
+ - 新建子包的 `app.id` 默认应等于最小子包目录名与 import 包名
183
+ - 不允许再声明第二个 settings namespace;运行时以 `app.id` 为唯一身份真相
184
+ - 脚手架默认使用最小子包目录名填充 `app.id`
185
+
186
+ 结论:
187
+
188
+ - 标准 `apps.py` 中的 `app.id` 是正式 namespace 真相源
189
+ - “最小子包名字”是脚手架默认值来源;历史子包若已发布稳定 `app.id`,不得仅因命名口径变化强制迁移
190
+ - 不存在独立可配置的第二个 settings namespace
191
+
192
+ ## 5. 生命周期约定
193
+
194
+ app 可按需实现以下钩子:
195
+ - `init(pz_ctx)`
196
+ - `startup(fastapi_app, pz_ctx)`
197
+ - `shutdown(fastapi_app, pz_ctx)`
198
+ - `extensions()`
199
+
200
+ 要求:
201
+ - 生命周期钩子应幂等
202
+ - 不能无条件依赖 DB、Redis 等可选设施
203
+ - 不能在 import 阶段执行重型初始化
204
+ - `startup()` 不应默认偷偷启动后台 worker 或注册长期循环任务
205
+ - 若 app 需要后台 worker,应提供显式 CLI / runner 入口
206
+ - `shutdown()` 若注册了 provider、event subscriber、background loop,必须对称清理
207
+ - `init()` / `startup()` 失败语义应明确,不应靠 warning 吞掉后继续装配
208
+
209
+ ### 5.0 生命周期状态机
210
+
211
+ app 生命周期统一服从正式状态机:
212
+
213
+ - declared
214
+ - compiled
215
+ - bound
216
+ - started
217
+ - stopped
218
+
219
+ 钩子语义固定为:
220
+
221
+ - `init()`
222
+ - 只负责声明期注册
223
+ - 不启动运行期副作用
224
+ - `startup()`
225
+ - 只负责激活已绑定的运行期能力
226
+ - 不补声明、不补裁决
227
+ - `shutdown()`
228
+ - 只负责对称清理已启动能力
229
+ - 不承担重新配置或重新编译
230
+
231
+ 不允许:
232
+
233
+ - app 在 `startup()` 中补 route/extension/provider 正式声明
234
+ - app 在 `shutdown()` 中隐式触发下一轮初始化准备
235
+ - app 自定义第二套正式生命周期名词替代上述状态机
236
+
237
+ ### 5.1 `extensions()` 约定
238
+
239
+ `extensions()` 是 app 向 `pz` 声明正式扩展点的唯一入口。
240
+
241
+ 正式要求:
242
+
243
+ - `extensions()` 返回值必须是结构化扩展对象序列
244
+ - 每个扩展对象至少必须包含:
245
+ - `kind`
246
+ - `id`
247
+ - `owner_app`
248
+ - `api_version`
249
+ - `priority`
250
+ - 扩展对象声明本身不得带副作用
251
+
252
+ 最常用的正式扩展点包括:
253
+
254
+ - `host.builder`
255
+ - `settings.provider`
256
+ - `cli.tool`
257
+ - middleware / lifecycle / route / resource contribution
258
+
259
+ 额外约束:
260
+
261
+ - `host.builder` 只能通过 `build(ctx) -> HostBuildResult` 产出 host
262
+ - `settings.provider` 只能通过 `provide(ctx) -> tuple[SettingsPatch, ...]` 返回 patch
263
+ - `cli.tool` 只能通过 `configure(parser)` 与 `run(ctx) -> int` 暴露命令
264
+ - 不允许 `extensions()` 返回裸函数、字符串路径或依赖 import-time 注册的对象
265
+
266
+ ## 5.2 app 声明协议的单一路径原则
267
+
268
+ app 的声明面必须固定,避免 decorator、全局 registry、脚本扫描并存。
269
+
270
+ 正式要求:
271
+
272
+ - app 的正式声明只来自:
273
+ - `apps.py` 中的 `app` 对象元数据
274
+ - `configs/default.jsonc`
275
+ - `settings.py` / `settings/` 中的 `AppSettings`
276
+ - `urls.py` 或 `urls/`
277
+ - `extensions()`
278
+ - 标准资源目录
279
+ - 标准迁移目录
280
+ - 标准 `cli/` 目录
281
+ - `init()` 只负责声明期注册,不得承担第二套声明协议
282
+ - `startup()` / `shutdown()` 只负责运行期激活与清理,不得补声明
283
+
284
+ 不允许:
285
+
286
+ - import-time decorator 注册 route/extension/provider 当成正式声明来源
287
+ - 模块级全局列表/字典作为第二套声明真相源
288
+ - 通过扫描任意模块名猜测 app 资源、命令或声明对象
289
+
290
+ 结论:
291
+
292
+ - app 的声明协议只有一套
293
+ - 编译阶段只读取这套声明协议
294
+ - 运行阶段不再补第二套声明
295
+
296
+ ## 5.3 `required_protocols` 的唯一语义
297
+
298
+ `required_protocols` 不得成为含糊的“随便依赖某个实现模块”字段。
299
+
300
+ 正式要求:
301
+
302
+ - `required_protocols` 只声明 capability contract 名称
303
+ - 其解析只基于当前 `CapabilityRegistry`
304
+ - 不允许写模块路径、类名、导入短名或具体官方 app / 独立子包实现名
305
+
306
+ 结论:
307
+
308
+ - app 依赖的是协议,不是实现
309
+ - `required_protocols` 只服务于依赖倒置,不服务于实现耦合
310
+
311
+ ## 6. 路由约定
312
+
313
+ 每个 app 必须通过 `<app_package>.urls` 暴露自己的 URL 真相源。
314
+
315
+ 推荐形态:
316
+
317
+ - 简单 app 使用 `urls.py`
318
+ - 复杂 app 使用 `urls/` 目录,但正式入口仍然是 `urls/__init__.py`
319
+ - 宿主与共享层永远只认 `<pkg>.urls`
320
+
321
+ `<pkg>.urls` 的职责:
322
+
323
+ - 作为 app URL 的唯一正式声明入口
324
+ - 使用 FastAPI 原生 `APIRouter()` / `include_router()` 组织本 app 的路由树
325
+ - 只声明本 app 自己的路径结构、子模块 include 关系与稳定 namespace
326
+ - 不承担跨 app prefix 挂载、全局排序、全局清理、冲突修补
327
+
328
+ 正式原则:
329
+
330
+ - 采用 Django 风格的 include 式装配
331
+ - 子包自带独立路由模块
332
+ - prefix 由上层统一挂载
333
+ - namespace 必须清晰、稳定、可审计
334
+ - 业务包只声明,不装配
335
+ - 全站 URL 末尾斜杠语义必须统一
336
+
337
+ 全站 URL 末尾斜杠规则:
338
+
339
+ - 目录型页面 canonical path 必须以 `/` 结尾
340
+ - 文件型资源、文件型接口与显式文件下载 URL 不得以 `/` 结尾
341
+ - 同一条正式 URL 不允许同时长期暴露“带 `/`”与“不带 `/`”两份 canonical
342
+ - slashless 到带 `/`、或带 `/` 到 slashless 的规范化跳转必须由共享 host / routing 规则统一承接,不允许每个业务包各自发明第二套 trailing-slash 语义
343
+ - 页面 owner、SEO owner、sitemap owner、redirect owner 输出的 canonical / alias / hreflang / sitemap URL 必须与这套规则一致
344
+ - 业务包在 `urls.py` 中只声明 canonical 版本,不手工注册成对的重复尾斜杠别名,除非该别名本身就是正式 route alias
345
+
346
+ 约束:
347
+
348
+ - `apps.py` 不负责组装 URL 主链
349
+ - URL 注册顺序不由 `apps.py`、`startup()`、`lifespan` 或局部 helper 的隐式顺序决定
350
+ - 所有 app 的 URL 声明由官方扩展层统一收集并装配
351
+ - `clean_and_reorder_routes()` 这类最终清理与排序逻辑只能存在于共享装配层
352
+ - 通用动态路由必须显式处理与静态路由的冲突
353
+ - 不允许依赖“某个官方 app 一定先于自己加载”,除非显式写入 `requires_apps`
354
+ - 不允许依赖“重复路由时框架会替自己保留某一份”这类隐式行为
355
+ - 不允许在 `startup()`、`lifespan`、局部 helper 中临时补挂正式路由
356
+
357
+ 模块组织约定:
358
+
359
+ - 普通业务包优先只写一个 `urls.py`
360
+ - 只有路由树复杂时才拆成 `urls/` 目录
361
+ - 即使拆目录,对外也只暴露 `<pkg>.urls`
362
+ - `<pkg>.urls` 只负责声明 Django 风格的 `urlpatterns`;它不负责构建路由,实际路由构建与绑定统一通过 `foundation/routing` 的正式 helper 完成
363
+ - 如果 app 涉及页面开发,目录组织应遵循 MVC 心智:`models` 负责数据模型,`templates` / `static` 负责视图展示,页面处理函数负责控制器职责
364
+ - `pages/` 保留给 Page Center 治理页声明目录;普通页面入口函数从 `urls.py` 拆出时统一命名为 `views.py` 或 `views/`
365
+ - `urls.py` 或 `urls/` 只存放 URL 声明与 `urlpatterns` 导出;不在其中堆业务编排、页面配置拼装、数据访问细节、手工路由绑定或任何路由构建逻辑
366
+ - `urlpatterns` 里的路径字符串使用 FastAPI / Starlette 原生 path 参数语法;既支持 `/{lang}/{module}/{slug}`,也支持 `/{lang:locale}/{slug}` 这类 convertor 形式
367
+
368
+ 页面开发补充约定:
369
+
370
+ - 页面 HTML、模板片段、样式与前端脚本优先只负责展示层
371
+ - 数据交互、状态修改、异步提交与查询优先通过 AJAX 调用后端 API 完成
372
+ - 不鼓励把复杂业务状态机、数据聚合逻辑或长期演进的交互协议堆进模板脚本
373
+ - 页面控制器负责把模板渲染和 API 接线接到正式后端能力,不负责在前端复制第二套业务主链
374
+
375
+ ## 7. settings 声明与读取约定
376
+
377
+ 每个 app 的 settings 作者面默认模板只允许有一个正式来源。
378
+
379
+ 默认情况下,正式来源是 app 根目录下的 `configs/default.jsonc`。
380
+
381
+ `configs/default.jsonc` 只由 `pz settings init/update` 读取,用于生成或补全项目根 `pz.jsonc` / `pz.{PZ_ENV}.jsonc`。其中 `routing.default_language`、`routing.all_supported_languages`、`routing.language_aliases` 会被提升到项目根 `routing`;`commands` 会被提升到项目根快捷命令区;`apps.*.sources.source_mode` 这类项目装配状态会被提升到根 `apps` 中对应 owner。它们不会作为声明它们的 app 私有 settings 暴露。启动阶段不得直接读取 app 包内的 `configs/default.jsonc`。
382
+
383
+ `configs/default.env` 是同一 app 的密钥模板配对文件,只允许放已由 `settings.py` / `settings/` schema 声明的 password、secret、token、key 类占位符。它可以被 Git 追踪,由 `pz settings init/update` 合并生成项目根 `.env` 与 `.env.{PZ_ENV}`。启动阶段不得直接读取 app 包内的 `configs/default.env`。
384
+
385
+ 每个 app 的 settings 声明模块固定为:`settings.py` 或 `settings/`。
386
+ 每个 app 的 Python 运行时读取入口固定为:`settings_center.settings.<app_id>`。
387
+
388
+ 文件形态允许两种:
389
+
390
+ - `settings.py`
391
+ - `settings/__init__.py`
392
+
393
+ 无论采用哪种形态,声明侧都只负责:
394
+ - `AppSettings`
395
+ - `__runtime_overrides__`
396
+
397
+ 示例:
398
+
399
+ ```python
400
+ from pydantic import BaseModel
401
+
402
+
403
+ class AppSettings(BaseModel):
404
+ ENABLED: bool
405
+ FEATURE_FLAG: bool
406
+ ```
407
+
408
+ 要求:
409
+ - app 私有配置统一走 `settings_center.settings.<app_id>`
410
+ - app 代码不得直接读取 `os.environ`
411
+ - 不再向全局根 settings 扁平化暴露业务私有字段
412
+ - `AppSettings` 必须使用 `BaseModel`,由框架统一完成环境变量与配置文件聚合
413
+ - 各 app 不再通过 `BaseSettings + env_prefix` 独立读取环境变量
414
+ - app 默认配置模板只能位于 `configs/default.jsonc`,且只能由 `pz settings init/update` 消费
415
+ - app 密钥占位模板只能位于 `configs/default.env`,且只能由 `pz settings init/update` 消费
416
+ - 启动阶段的 settings 编译只读取项目根 `pz.jsonc`、`pz.{PZ_ENV}.jsonc`、`.env`、`.env.{PZ_ENV}` 与显式环境变量
417
+ - 子包新增 settings 字段后,必须同时更新 `configs/default.jsonc` 模板,并要求项目执行 `pz settings update` 把新键同步到项目配置;启动期不得从包内模板临时补齐
418
+ - Python 运行时代码不再直接 import app 的 `settings.py`
419
+
420
+ ### 7.1 namespace 与读取边界
421
+
422
+ settings 读取边界固定如下:
423
+
424
+ - 正式叶子 app:
425
+ - 只通过自己的 `settings_center.settings.<app_id>` 读取配置
426
+ - 其运行时 namespace 固定为 `app.id`
427
+ - 非 app 的内部实现模块:
428
+ - 不允许自建 namespace
429
+ - 只能读取所属最小子包的 `settings_center.settings.<app_id>`
430
+ - 若读取的是项目级装配信息,只能通过 `settings_center.settings.project.<field>` 读取
431
+
432
+ 不允许:
433
+
434
+ - 内部 client / adapter / service 子目录各自声明一套独立 namespace
435
+ - 没有 `apps.py` 的实现子目录偷偷读取一份自己的 TOML
436
+ - 用模块路径或目录名临时拼接出新的 settings 读取规则
437
+
438
+ 判断标准:
439
+
440
+ - 有正式 `apps.py` 且被安装声明的最小子包,才有资格拥有自己的 settings namespace
441
+ - 没有最小子包身份,就没有自己的 settings namespace
442
+ - 若使用 `settings/` 目录,只有 `settings/__init__.py` 可以作为正式入口;其它文件只允许做内部拆分
443
+ - `apps.py`、`urls.py`、`urls/`、`public.py`、`services/*` 不得再成为第二套默认配置模板来源或运行时配置读取入口
444
+ - `settings.py` / `settings/` 不得在 import 阶段读取 `configs/default.jsonc`、`configs/default.env` 或项目 `.env*`
445
+
446
+ 补充要求:
447
+
448
+ - `AppSettings` 应只表达配置 schema、结构化校验、normalize 与 `__runtime_overrides__`
449
+ - 不应在 `AppSettings` validator 中夹带跨模块 I/O、路径推断或全局单例改写
450
+ - 允许线上热更新的字段,应在 `configs/default.jsonc` 中给出 settings init/update 模板默认值;若字段允许 `None` 且 TOML 无法表达空值,可暂时省略该键
451
+
452
+ ## 8. 资源约定
453
+
454
+ 若存在以下目录,则视为 app 资源:
455
+ - `templates/`
456
+ - `static/`
457
+ - `locales/`
458
+
459
+ 规则:
460
+ - 资源发现只依赖 app 包路径
461
+ - 覆盖顺序只依赖 `installed_apps`:按 `installed_apps` 从前到后合并,同相对路径资源由后面的 app 覆盖前面的 app
462
+ - 运行时合并产物写入外部 `cache_dir`
463
+
464
+ ## 9. 模型与迁移约定
465
+
466
+ 模型:
467
+ - 统一放在 `<app>.models` 入口下,即 `models.py` 或 `models/`
468
+ - 其所属 app label 必须与 `app.id` 保持一致
469
+ - 不应依赖 `pz` 为某个具体 app 特判 `module.models` / `runtime.models` 才能工作
470
+ - 若模型显式声明 ORM 的 app label,应与 `app.id` 完全一致
471
+
472
+ 迁移:
473
+ - 必须位于 `migrations/<app_id>/`
474
+ - 若 app 提供模型,则必须提供对应迁移目录
475
+ - 不允许一个 app 包内同时维护多个 app_id 的迁移归属
476
+
477
+ ## 10. 依赖规则
478
+
479
+ 正式允许的依赖:
480
+ - `app -> pz`
481
+ - `app -> pz` 暴露的稳定门面
482
+
483
+ 不允许:
484
+ - app 直接依赖其它 app 的内部实现模块
485
+ - app 在无门面情况下直接耦合 infra 私有实现
486
+
487
+ 正式要求:
488
+ - 跨 app 依赖统一走 `public.py`
489
+ - 若某 app 提供平台能力,应将该能力做成 `public.py` 暴露的稳定 facade,而不是让调用方 import 内部 service/models
490
+
491
+ ## 10.1 app 的最小交付要求
492
+
493
+ 从工程实用角度,能被长期维护的 app 不应只有代码结构,还应有最小交付面。
494
+
495
+ 每个正式 app 至少具备:
496
+
497
+ - `apps.py`
498
+ - `settings.py` 或明确声明“无 app settings”
499
+ - 迁移目录或明确声明“无持久化模型”
500
+ - `public.py` 或明确声明“仅内部使用”
501
+ - 最小契约测试
502
+
503
+ 对外分发的 app 还必须具备:
504
+
505
+ - README
506
+ - 版本范围声明
507
+ - 配置示例
508
+ - 替换/升级说明
509
+
510
+ ## 11. import 时行为约束
511
+
512
+ app 模块在 import 阶段不得:
513
+ - 启动后台任务
514
+ - 初始化 DB / Redis 连接
515
+ - 创建依赖首次 settings 快照的重型全局对象
516
+ - 注册影响全局进程状态且不可回滚的 provider / resolver / singleton
517
+ - 订阅无法显式取消的全局事件处理器
518
+
519
+ app 模块仅允许:
520
+ - 定义轻量 schema、常量、纯内存 registry
521
+ - 暴露 lazy factory 或 facade
522
+
523
+ ## 12. app 公共 API 约定
524
+
525
+ 如果 app 需要被其它 app 或项目代码依赖,稳定入口只允许放在:
526
+
527
+ - `public.py`
528
+
529
+ 不再把以下路径当作长期公共契约:
530
+
531
+ - `service.py`
532
+ - `runtime/*`
533
+ - `module/*`
534
+ - `models.py`
535
+ - 任意内部 helper
536
+
537
+ 原则:
538
+
539
+ - 能力通过 facade 暴露
540
+ - 实现保持可替换
541
+ - 对外依赖面尽量小
542
+
543
+ ## 13. app CLI 发现约定
544
+
545
+ app CLI 也必须只有一种正式发现方式。
546
+
547
+ 正式要求:
548
+
549
+ - app CLI 工具固定放在 `<app>/cli/<tool>.py`
550
+ - 框架只按这个目录约定发现并暴露 `pz <app_id> <tool>`
551
+ - 不再支持通过 entry point、模块级注册器、import-time decorator 动态注册第二套 app CLI 主链
552
+
553
+ 结论:
554
+
555
+ - app CLI 的正式真相源是包内 `cli/` 目录
556
+ - CLI manager 只做发现与执行,不做二次猜测和旁路注册
557
+
558
+ ## 14. app 资源声明约定
559
+
560
+ 资源边界同样必须只有一种正式表达方式。
561
+
562
+ 正式要求:
563
+
564
+ - 模板、静态、语言、迁移目录统一按标准目录约定声明
565
+ - 框架只从 app 包内标准目录读取资源源
566
+ - app 不再自定义第二套 `resources()` / `assets()` / path helper 协议作为正式资源声明入口
567
+
568
+ 结论:
569
+
570
+ - app 的资源源真相源是标准包目录布局
571
+ - 资源合并、模板渲染、静态定位都只消费后续编译出的 manifest,不回头读私有声明协议