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.
- pz_cli-5.0.0.dist-info/METADATA +51 -0
- pz_cli-5.0.0.dist-info/RECORD +399 -0
- pz_cli-5.0.0.dist-info/WHEEL +4 -0
- pz_cli-5.0.0.dist-info/entry_points.txt +5 -0
- pz_core/__init__.py +64 -0
- pz_core/__main__.py +7 -0
- pz_core/app.py +45 -0
- pz_core/assembly/__init__.py +17 -0
- pz_core/assembly/app_discovery.py +1240 -0
- pz_core/assembly/apps/__init__.py +25 -0
- pz_core/assembly/apps/compiler.py +824 -0
- pz_core/assembly/apps/providers.py +188 -0
- pz_core/assembly/cli/__init__.py +9 -0
- pz_core/assembly/cli/compiler.py +166 -0
- pz_core/assembly/diagnostics/__init__.py +21 -0
- pz_core/assembly/diagnostics/checks.py +257 -0
- pz_core/assembly/diagnostics/dev_sources.py +569 -0
- pz_core/assembly/events/__init__.py +5 -0
- pz_core/assembly/events/compiler.py +219 -0
- pz_core/assembly/extensions/__init__.py +5 -0
- pz_core/assembly/extensions/compiler.py +696 -0
- pz_core/assembly/infra/__init__.py +6 -0
- pz_core/assembly/infra/compiler.py +272 -0
- pz_core/assembly/lifecycle/__init__.py +5 -0
- pz_core/assembly/lifecycle/compiler.py +95 -0
- pz_core/assembly/middlewares/__init__.py +19 -0
- pz_core/assembly/middlewares/compiler.py +508 -0
- pz_core/assembly/project/__init__.py +7 -0
- pz_core/assembly/project/compiler.py +9 -0
- pz_core/assembly/project/context.py +17 -0
- pz_core/assembly/project/discovery.py +227 -0
- pz_core/assembly/resources/__init__.py +19 -0
- pz_core/assembly/resources/compiler.py +310 -0
- pz_core/assembly/resources/settings.py +129 -0
- pz_core/assembly/routes/__init__.py +7 -0
- pz_core/assembly/routes/compiler.py +400 -0
- pz_core/assembly/runtime_manifests/__init__.py +13 -0
- pz_core/assembly/runtime_manifests/compiler.py +159 -0
- pz_core/assembly/settings/__init__.py +17 -0
- pz_core/assembly/settings/compiler.py +786 -0
- pz_core/assembly/settings/host_project_overrides.py +82 -0
- pz_core/assembly/settings/host_runtime_endpoint.py +207 -0
- pz_core/authoring/__init__.py +79 -0
- pz_core/authoring/app_init_service.py +946 -0
- pz_core/authoring/app_versions.py +814 -0
- pz_core/authoring/cli.py +192 -0
- pz_core/authoring/commands.py +1810 -0
- pz_core/authoring/conflicts.py +180 -0
- pz_core/authoring/dev_bindings.py +916 -0
- pz_core/authoring/dev_git.py +1087 -0
- pz_core/authoring/dev_import.py +1061 -0
- pz_core/authoring/dev_manifest.py +522 -0
- pz_core/authoring/dev_sources.py +1638 -0
- pz_core/authoring/env_cli.py +454 -0
- pz_core/authoring/files.py +109 -0
- pz_core/authoring/ide_projection.py +1129 -0
- pz_core/authoring/naming.py +58 -0
- pz_core/authoring/official_dev_sources.py +432 -0
- pz_core/authoring/official_sources.json +156 -0
- pz_core/authoring/orchestration_service.py +558 -0
- pz_core/authoring/project_default.jsonc +53 -0
- pz_core/authoring/project_defaults.py +88 -0
- pz_core/authoring/project_metadata_service.py +199 -0
- pz_core/authoring/project_settings_checks.py +51 -0
- pz_core/authoring/project_settings_cli.py +299 -0
- pz_core/authoring/project_settings_service.py +1700 -0
- pz_core/authoring/project_state.py +399 -0
- pz_core/authoring/publish_git.py +423 -0
- pz_core/authoring/publish_lock.py +188 -0
- pz_core/authoring/publish_source.py +195 -0
- pz_core/authoring/release.py +1382 -0
- pz_core/authoring/repo_keys.py +29 -0
- pz_core/authoring/root_cli.py +28 -0
- pz_core/authoring/scaffold_service.py +325 -0
- pz_core/authoring/sync_service.py +787 -0
- pz_core/authoring/templates/app/__init__.py +1 -0
- pz_core/authoring/templates/app/api.py +25 -0
- pz_core/authoring/templates/app/apps.py +31 -0
- pz_core/authoring/templates/app/auth_package_init.py +14 -0
- pz_core/authoring/templates/app/auth_readme.py +29 -0
- pz_core/authoring/templates/app/configs_package_init.py +14 -0
- pz_core/authoring/templates/app/default_env.py +18 -0
- pz_core/authoring/templates/app/default_jsonc.py +25 -0
- pz_core/authoring/templates/app/locales_readme.py +25 -0
- pz_core/authoring/templates/app/migrations_readme.py +19 -0
- pz_core/authoring/templates/app/models.py +14 -0
- pz_core/authoring/templates/app/package_init.py +8 -0
- pz_core/authoring/templates/app/pages_base.py +161 -0
- pz_core/authoring/templates/app/pages_readme.py +25 -0
- pz_core/authoring/templates/app/public.py +31 -0
- pz_core/authoring/templates/app/pyproject.py +77 -0
- pz_core/authoring/templates/app/readme.py +74 -0
- pz_core/authoring/templates/app/settings.py +46 -0
- pz_core/authoring/templates/app/static_app_js.py +24 -0
- pz_core/authoring/templates/app/static_readme.py +31 -0
- pz_core/authoring/templates/app/template_config_page.py +23 -0
- pz_core/authoring/templates/app/template_index_html.py +28 -0
- pz_core/authoring/templates/app/templates_readme.py +32 -0
- pz_core/authoring/templates/app/urls.py +36 -0
- pz_core/authoring/templates/app/views.py +36 -0
- pz_core/authoring/templates/project/__init__.py +1 -0
- pz_core/authoring/templates/project/agents.py +51 -0
- pz_core/authoring/templates/project/apps_container_readme.py +37 -0
- pz_core/authoring/templates/project/main_py.py +59 -0
- pz_core/authoring/templates/project/project_env.py +19 -0
- pz_core/authoring/templates/project/pyproject.py +26 -0
- pz_core/authoring/templates/project/pz_env_env.py +65 -0
- pz_core/authoring/templates/project/pz_env_jsonc.py +69 -0
- pz_core/authoring/templates/project/pz_jsonc.py +12 -0
- pz_core/authoring/templates/project/readme.py +94 -0
- pz_core/authoring/templates/project/root_gitkeep.py +8 -0
- pz_core/authoring/templates/shared/__init__.py +5 -0
- pz_core/authoring/templates/shared/text.py +10 -0
- pz_core/authoring/venv_service.py +87 -0
- pz_core/authoring/workspace.py +167 -0
- pz_core/cli.py +291 -0
- pz_core/cli_options.py +74 -0
- pz_core/core/__init__.py +3 -0
- pz_core/core/errors/__init__.py +5 -0
- pz_core/core/errors/models.py +117 -0
- pz_core/core/events/__init__.py +5 -0
- pz_core/core/events/registry.py +54 -0
- pz_core/core/extensions/__init__.py +51 -0
- pz_core/core/extensions/registry.py +790 -0
- pz_core/core/health/__init__.py +6 -0
- pz_core/core/health/contracts.py +10 -0
- pz_core/core/middlewares/__init__.py +6 -0
- pz_core/core/middlewares/models.py +24 -0
- pz_core/core/routing/__init__.py +5 -0
- pz_core/core/routing/models.py +21 -0
- pz_core/core/settings_contracts.py +25 -0
- pz_core/docs/README.md +20 -0
- pz_core/docs/distribution-README.md +438 -0
- pz_core/docs/pz/345/221/275/344/273/244/346/200/273/350/247/210.md +1011 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- pz_core/docs/pz/350/247/204/350/214/203/344/270/216/344/275/277/347/224/250/README.md +98 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- pz_core/docs//345/217/221/347/211/210/345/211/215/346/270/205/345/215/225-4.0.11.md +84 -0
- pz_core/docs//346/226/260/346/211/213/346/214/207/345/215/227.md +422 -0
- pz_core/infra/__init__.py +17 -0
- pz_core/infra/db/__init__.py +23 -0
- pz_core/infra/db/contracts.py +73 -0
- pz_core/infra/health/__init__.py +5 -0
- pz_core/infra/health/contracts.py +8 -0
- pz_core/infra/kv/__init__.py +5 -0
- pz_core/infra/kv/contracts.py +17 -0
- pz_core/infra/observability/__init__.py +23 -0
- pz_core/infra/observability/contracts.py +142 -0
- pz_core/infra/resilience/__init__.py +5 -0
- pz_core/infra/resilience/contracts.py +17 -0
- pz_core/infra/resources/__init__.py +5 -0
- pz_core/infra/resources/contracts.py +16 -0
- pz_core/infra/settings/__init__.py +17 -0
- pz_core/infra/settings/models.py +81 -0
- pz_core/infra/storage/__init__.py +5 -0
- pz_core/infra/storage/ports.py +27 -0
- pz_core/project_root_commands.py +282 -0
- pz_core/project_runtime_cli.py +344 -0
- pz_core/project_sources.py +253 -0
- pz_core/pz_launcher.py +209 -0
- pz_core/root_cli.py +70 -0
- pz_core/runtime/__init__.py +229 -0
- pz_core/runtime/access.py +86 -0
- pz_core/runtime/adapters/__init__.py +5 -0
- pz_core/runtime/adapters/base.py +18 -0
- pz_core/runtime/asyncio_bridge.py +18 -0
- pz_core/runtime/bindings/__init__.py +5 -0
- pz_core/runtime/bindings/container.py +50 -0
- pz_core/runtime/cli/__init__.py +5 -0
- pz_core/runtime/cli/_args.py +67 -0
- pz_core/runtime/cli/app_commands.py +417 -0
- pz_core/runtime/cli/check.py +214 -0
- pz_core/runtime/cli/db.py +297 -0
- pz_core/runtime/cli/main.py +89 -0
- pz_core/runtime/cli/resources.py +280 -0
- pz_core/runtime/discovery.py +23 -0
- pz_core/runtime/environment_integrity.py +157 -0
- pz_core/runtime/errors.py +5 -0
- pz_core/runtime/events.py +87 -0
- pz_core/runtime/facades/__init__.py +38 -0
- pz_core/runtime/facades/_capabilities.py +46 -0
- pz_core/runtime/facades/cache.py +103 -0
- pz_core/runtime/facades/database.py +71 -0
- pz_core/runtime/facades/events.py +380 -0
- pz_core/runtime/facades/health.py +101 -0
- pz_core/runtime/facades/mail.py +121 -0
- pz_core/runtime/facades/observability.py +102 -0
- pz_core/runtime/facades/providers.py +75 -0
- pz_core/runtime/facades/resources.py +52 -0
- pz_core/runtime/facades/storage.py +296 -0
- pz_core/runtime/health/__init__.py +5 -0
- pz_core/runtime/health/service.py +102 -0
- pz_core/runtime/host.py +188 -0
- pz_core/runtime/host_runner.py +282 -0
- pz_core/runtime/http/__init__.py +20 -0
- pz_core/runtime/http/app.py +576 -0
- pz_core/runtime/http_timing.py +173 -0
- pz_core/runtime/invocation.py +29 -0
- pz_core/runtime/json_safe.py +47 -0
- pz_core/runtime/lifecycle/__init__.py +25 -0
- pz_core/runtime/lifecycle/manager.py +533 -0
- pz_core/runtime/plan.py +214 -0
- pz_core/runtime/plan_context.py +33 -0
- pz_core/runtime/plan_snapshot.py +177 -0
- pz_core/runtime/registries/__init__.py +27 -0
- pz_core/runtime/registries/capabilities.py +101 -0
- pz_core/runtime/registries/providers.py +396 -0
- pz_core/runtime/resource_assets.py +344 -0
- pz_core/runtime/run_cli.py +211 -0
- pz_core/runtime/settings.py +888 -0
- pz_core/runtime/worker/__init__.py +21 -0
- pz_core/runtime/worker/engine.py +921 -0
- pz_core/runtime/worker/runtime.py +25 -0
- pz_core/testing/__init__.py +15 -0
- pz_core/testing/doc_route_contracts.py +305 -0
- pz_core/utils/__init__.py +44 -0
- pz_core/utils/env.py +65 -0
- pz_core/utils/project_jsonc/__init__.py +29 -0
- pz_core/utils/project_jsonc/document.py +420 -0
- pz_core/utils/project_settings.py +99 -0
- pz_foundation/__init__.py +50 -0
- pz_foundation/_contracts.py +81 -0
- pz_foundation/_errors.py +34 -0
- pz_foundation/api.py +14 -0
- pz_foundation/apps.py +127 -0
- pz_foundation/auth/__init__.py +1 -0
- pz_foundation/cache_control.py +233 -0
- pz_foundation/cli/__init__.py +2 -0
- pz_foundation/cli/workers.py +565 -0
- pz_foundation/configs/__init__.py +0 -0
- pz_foundation/configs/default.env +15 -0
- pz_foundation/configs/default.jsonc +452 -0
- pz_foundation/db/__init__.py +94 -0
- pz_foundation/db/aerich_executor.py +664 -0
- pz_foundation/db/config.py +358 -0
- pz_foundation/db/connection_manager.py +689 -0
- pz_foundation/db/connection_probe.py +204 -0
- pz_foundation/db/database.py +1291 -0
- pz_foundation/db/deps.py +47 -0
- pz_foundation/db/lifecycle_status.py +85 -0
- pz_foundation/db/migrations.py +477 -0
- pz_foundation/db/mysql.py +57 -0
- pz_foundation/db/postgresql.py +409 -0
- pz_foundation/db/production_pool_fallback.py +143 -0
- pz_foundation/db/public.py +45 -0
- pz_foundation/db/session.py +369 -0
- pz_foundation/db/sqlite.py +15 -0
- pz_foundation/db/tortoise_manager.py +724 -0
- pz_foundation/db/tortoise_psycopg.py +148 -0
- pz_foundation/docs/README.md +18 -0
- pz_foundation/docs/distribution-README.md +319 -0
- 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
- 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
- pz_foundation/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +288 -0
- 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
- pz_foundation/health.py +105 -0
- pz_foundation/host/__init__.py +11 -0
- pz_foundation/host/builder.py +34 -0
- pz_foundation/host/cache_runtime.py +44 -0
- pz_foundation/host/db/__init__.py +17 -0
- pz_foundation/host/db/aerich_config.py +36 -0
- pz_foundation/host/db/config.py +106 -0
- pz_foundation/host/db/connection_manager.py +48 -0
- pz_foundation/host/db/deps.py +5 -0
- pz_foundation/host/db/orm_retry_patch.py +566 -0
- pz_foundation/host/db/request_adapter.py +325 -0
- pz_foundation/host/db/router.py +28 -0
- pz_foundation/host/db/session.py +284 -0
- pz_foundation/host/db/tortoise_manager.py +10 -0
- pz_foundation/host/idempotency.py +132 -0
- pz_foundation/host/lifespan.py +247 -0
- pz_foundation/host/redis_runtime.py +100 -0
- pz_foundation/host/web.py +790 -0
- pz_foundation/infra_provider.py +236 -0
- pz_foundation/kv/__init__.py +25 -0
- pz_foundation/kv/cache.py +1166 -0
- pz_foundation/kv/deps.py +84 -0
- pz_foundation/kv/public.py +25 -0
- pz_foundation/kv/redis_manager.py +1531 -0
- pz_foundation/lazy_exports.py +43 -0
- pz_foundation/lazy_imports.py +124 -0
- pz_foundation/lifecycle.py +392 -0
- pz_foundation/managed_workers.py +1117 -0
- pz_foundation/middlewares/__init__.py +26 -0
- pz_foundation/middlewares/_settings.py +250 -0
- pz_foundation/middlewares/analytics.py +124 -0
- pz_foundation/middlewares/cache_control.py +156 -0
- pz_foundation/middlewares/compression.py +202 -0
- pz_foundation/middlewares/cors.py +62 -0
- pz_foundation/middlewares/geo_country.py +44 -0
- pz_foundation/middlewares/inner_router.py +50 -0
- pz_foundation/middlewares/rate_limited/__init__.py +3 -0
- pz_foundation/middlewares/rate_limited/key_limiter.py +115 -0
- pz_foundation/middlewares/request_logging.py +104 -0
- pz_foundation/middlewares/route_owner.py +309 -0
- pz_foundation/middlewares/security_csrf.py +44 -0
- pz_foundation/middlewares/security_headers/__init__.py +4 -0
- pz_foundation/middlewares/security_headers/conflicts.py +44 -0
- pz_foundation/middlewares/security_headers/csp_nonce.py +200 -0
- pz_foundation/middlewares/security_headers/security_headers.py +44 -0
- pz_foundation/migrations/__init__.py +1 -0
- pz_foundation/migrations/pz_foundation/__init__.py +1 -0
- pz_foundation/models.py +22 -0
- pz_foundation/notifications/__init__.py +23 -0
- pz_foundation/notifications/email.py +542 -0
- pz_foundation/notifications/public.py +31 -0
- pz_foundation/observability/__init__.py +71 -0
- pz_foundation/observability/http.py +34 -0
- pz_foundation/observability/logger/__init__.py +49 -0
- pz_foundation/observability/logger/_bot_settings.py +126 -0
- pz_foundation/observability/logger/bot_message.py +592 -0
- pz_foundation/observability/logger/core.py +385 -0
- pz_foundation/observability/logger/delivery_audit.py +84 -0
- pz_foundation/observability/logger/feishu_bot.py +199 -0
- pz_foundation/observability/logger/telegram_bot.py +194 -0
- pz_foundation/observability/metrics.py +365 -0
- pz_foundation/observability/runtime.py +68 -0
- pz_foundation/public.py +405 -0
- pz_foundation/resources/__init__.py +12 -0
- pz_foundation/resources/builder.py +900 -0
- pz_foundation/resources/images.py +363 -0
- pz_foundation/root_cli.py +20 -0
- pz_foundation/routing/__init__.py +203 -0
- pz_foundation/routing/canonical.py +486 -0
- pz_foundation/routing/convertors.py +82 -0
- pz_foundation/routing/declarations.py +843 -0
- pz_foundation/routing/exports.py +148 -0
- pz_foundation/routing/loaders.py +138 -0
- pz_foundation/routing/manifest.py +215 -0
- pz_foundation/routing/manifest_provider.py +47 -0
- pz_foundation/routing/mounts.py +101 -0
- pz_foundation/routing/ordering.py +172 -0
- pz_foundation/routing/registry.py +133 -0
- pz_foundation/routing/utils.py +28 -0
- pz_foundation/runtime.py +234 -0
- pz_foundation/settings.py +253 -0
- pz_foundation/settings_normalization.py +130 -0
- pz_foundation/storage/__init__.py +25 -0
- pz_foundation/storage/local.py +209 -0
- pz_foundation/storage/public.py +106 -0
- pz_foundation/storage/s3.py +116 -0
- pz_foundation/storage/service.py +234 -0
- pz_foundation/urls.py +19 -0
- pz_foundation/utils/__init__.py +6 -0
- pz_foundation/utils/merge.py +160 -0
- pz_foundation/worker_replicas.py +55 -0
- pz_settings_center/__init__.py +5 -0
- pz_settings_center/api/__init__.py +5 -0
- pz_settings_center/api/runtime_overrides.py +360 -0
- pz_settings_center/apps.py +28 -0
- pz_settings_center/configs/__init__.py +0 -0
- pz_settings_center/configs/default.env +2 -0
- pz_settings_center/configs/default.jsonc +1 -0
- pz_settings_center/docs/01-settings_center/350/203/275/345/212/233/350/276/271/347/225/214.md +124 -0
- pz_settings_center/docs/README.md +12 -0
- pz_settings_center/docs/distribution-README.md +150 -0
- pz_settings_center/docs//350/256/276/350/256/241/346/226/207/346/241/243.md +48 -0
- pz_settings_center/integration_payload.py +18 -0
- pz_settings_center/project_helpers.py +405 -0
- pz_settings_center/public.py +139 -0
- pz_settings_center/routing_helpers.py +73 -0
- pz_settings_center/runtime_override_provider.py +61 -0
- pz_settings_center/typed_settings.py +324 -0
- pz_settings_center/urls.py +9 -0
|
@@ -0,0 +1,1177 @@
|
|
|
1
|
+
# Settings 与配置规范
|
|
2
|
+
|
|
3
|
+
> 单一正式读取入口:Python 运行时代码只允许 `import pz_settings_center.public as settings_center`,app 配置只允许 `settings_center.settings.<app_id>.<field>`;`settings.py` / `settings/` 只负责 `AppSettings`、normalize、默认值聚合与 `__runtime_overrides__` 声明。
|
|
4
|
+
|
|
5
|
+
## 1. 目标
|
|
6
|
+
|
|
7
|
+
配置体系必须同时满足:
|
|
8
|
+
- 标准 `pip` 安装场景
|
|
9
|
+
- 多 app 命名空间装配
|
|
10
|
+
- 结构化配置表达
|
|
11
|
+
- 环境变量覆盖
|
|
12
|
+
- 最小魔法与明确边界
|
|
13
|
+
- 面向人的作者面可理解性
|
|
14
|
+
|
|
15
|
+
配置协议固定为三类 owner 协作模型:
|
|
16
|
+
|
|
17
|
+
- module config owner
|
|
18
|
+
- 全局唯一模块配置编排职责
|
|
19
|
+
- settings runtime owner
|
|
20
|
+
- 全局唯一配置写入、运行时变更与 runtime override 职责
|
|
21
|
+
- settings center
|
|
22
|
+
- 全局唯一运行时读取职责
|
|
23
|
+
|
|
24
|
+
`pz` 本身只负责在启动与编译期按约定组装这些 owner 的声明与 provider 输出,不承载它们的具体实现;官方实现归属对应最小子包文档。
|
|
25
|
+
|
|
26
|
+
## 1.1 三层职责边界
|
|
27
|
+
|
|
28
|
+
### module config owner
|
|
29
|
+
|
|
30
|
+
职责:
|
|
31
|
+
|
|
32
|
+
- 声明模块配置
|
|
33
|
+
- 编排模块配置
|
|
34
|
+
- 产出可并入最终 settings snapshot 的配置补丁
|
|
35
|
+
|
|
36
|
+
不负责:
|
|
37
|
+
|
|
38
|
+
- 业务代码运行时直接读取配置
|
|
39
|
+
- 持有第二套运行态 settings 状态
|
|
40
|
+
- 绕开 `settings_center` 直接提供并列读取 API
|
|
41
|
+
|
|
42
|
+
### settings runtime owner
|
|
43
|
+
|
|
44
|
+
职责:
|
|
45
|
+
|
|
46
|
+
- 配置写入
|
|
47
|
+
- 配置修改校验
|
|
48
|
+
- 配置审计与变更治理
|
|
49
|
+
- runtime override 生效模式治理
|
|
50
|
+
|
|
51
|
+
不负责:
|
|
52
|
+
|
|
53
|
+
- 成为业务代码正式读取入口
|
|
54
|
+
- 发明未声明字段
|
|
55
|
+
- 自己维护第二套 settings snapshot
|
|
56
|
+
|
|
57
|
+
### settings center
|
|
58
|
+
|
|
59
|
+
职责:
|
|
60
|
+
|
|
61
|
+
- 提供最终运行时读取 surface
|
|
62
|
+
- 统一暴露 `settings_center.settings`
|
|
63
|
+
- 汇总项目配置、环境层、module config 编排结果与 runtime overrides
|
|
64
|
+
|
|
65
|
+
不负责:
|
|
66
|
+
|
|
67
|
+
- 模块配置管理 UI
|
|
68
|
+
- 配置写入后台逻辑
|
|
69
|
+
- 第二套 schema 声明入口
|
|
70
|
+
|
|
71
|
+
## 1.2 正式数据流
|
|
72
|
+
|
|
73
|
+
正式数据流固定为:
|
|
74
|
+
|
|
75
|
+
1. `settings.py` / `settings/` 中的 settings schema
|
|
76
|
+
2. `pz.jsonc`
|
|
77
|
+
3. `pz.{PZ_ENV}.jsonc`
|
|
78
|
+
4. module config owner 编译出的 module config patches
|
|
79
|
+
5. `<project_dir>/.env`
|
|
80
|
+
6. `<project_dir>/.env.{PZ_ENV}`
|
|
81
|
+
7. 显式环境变量
|
|
82
|
+
8. settings runtime owner 产出的 runtime overrides
|
|
83
|
+
9. settings center 读取 surface
|
|
84
|
+
|
|
85
|
+
结论:
|
|
86
|
+
|
|
87
|
+
- `module_config` 只影响最终 snapshot
|
|
88
|
+
- settings runtime owner 只在正式声明允许的字段上做运行时覆写
|
|
89
|
+
- 业务代码最终仍然只读 settings center 的正式公开面
|
|
90
|
+
|
|
91
|
+
## 1.3 面向人的配置作者面原则
|
|
92
|
+
|
|
93
|
+
配置作者面首先服务于“人应该去哪里找、怎么看、怎么填”,其次才服务于代码如何消费。
|
|
94
|
+
|
|
95
|
+
完整的人类配置心智固定为:
|
|
96
|
+
|
|
97
|
+
1. 先按领域找唯一 owner
|
|
98
|
+
例如观察链去观察 owner app,执行链去执行 owner app,控制面/运行装配去 runtime owner app。
|
|
99
|
+
2. 在 owner app 的 `configs/default.jsonc` 看完整配置骨架
|
|
100
|
+
非敏感结构、开关、列表、对象、ref 字段,以及敏感字段对应的位置,都应在这里可见。
|
|
101
|
+
3. 在 owner app 的 `configs/default.env` 只填写敏感覆盖值
|
|
102
|
+
例如密钥、token、密码、cookie、私钥、credential path。
|
|
103
|
+
4. 运行期由 env layer 覆盖项目 JSONC 静态层
|
|
104
|
+
不允许反过来由 JSONC 覆盖 env 中的 secret。
|
|
105
|
+
|
|
106
|
+
正式要求:
|
|
107
|
+
|
|
108
|
+
- 一个领域、一类能力或一组 concrete 凭证,只允许有一个正式配置 owner。
|
|
109
|
+
- 项目维护者看到某类配置时,应当一眼知道该去哪个 owner app 的 settings namespace 查找与 author。
|
|
110
|
+
- 同一领域的 concrete 配置不得拆散在多个 app namespace 中分别 author;调用方可以消费 ref、projection 或编译结果,但不能把同一组 concrete 字段再复制到自己的 settings 下。
|
|
111
|
+
- 根 `pz.jsonc` 只是 `pz settings init/update` 汇总后的项目作者面,不是允许跨 owner 重新分摊 concrete 配置职责的“第二入口”。
|
|
112
|
+
|
|
113
|
+
判断标准:
|
|
114
|
+
|
|
115
|
+
- 如果一个配置项属于观察链,就应统一放在观察 owner app。
|
|
116
|
+
- 如果一个配置项属于执行链,就应统一放在执行 owner app。
|
|
117
|
+
- 如果一个配置项属于控制面或运行装配,就应统一放在控制面 / runtime owner app。
|
|
118
|
+
|
|
119
|
+
禁止:
|
|
120
|
+
|
|
121
|
+
- 为了让调用方“顺手就近读取”,把同一领域配置拆成东一块、西一块。
|
|
122
|
+
- 在运行控制面、领域 app、宿主 app 或项目根层同时长期 author 同一套 concrete 配置。
|
|
123
|
+
- 让人必须先理解内部调用链,才能判断一个配置该去哪里改。
|
|
124
|
+
|
|
125
|
+
## 2. 配置来源
|
|
126
|
+
|
|
127
|
+
正式配置文件:
|
|
128
|
+
- `pz.jsonc`
|
|
129
|
+
- `pz.{PZ_ENV}.jsonc`
|
|
130
|
+
- `<project_dir>/.env`
|
|
131
|
+
- `<project_dir>/.env.{PZ_ENV}`
|
|
132
|
+
|
|
133
|
+
settings 作者面模板:
|
|
134
|
+
- 已安装子包的 `configs/default.jsonc`
|
|
135
|
+
- 已安装子包的 `configs/default.env`
|
|
136
|
+
|
|
137
|
+
`configs/default.jsonc` 与 `configs/default.env` 只允许由 `pz settings init/update` 读取,用于生成或补全项目根配置文件。启动阶段不得直接读取已安装子包的 `configs/default.jsonc` 或 `configs/default.env`。
|
|
138
|
+
|
|
139
|
+
作者面模板口径固定为:
|
|
140
|
+
|
|
141
|
+
- `configs/default.jsonc` 必须表达该 owner app 的完整配置骨架。
|
|
142
|
+
- 这里的“完整”指:非敏感结构化字段、开关、列表、对象、ref 字段,以及敏感字段在 schema 上对应的位置,都应在 `default.jsonc` 中可见。
|
|
143
|
+
- 敏感字段在 `default.jsonc` 中只保留空值、占位值或 ref 占位,用来告诉人“这里存在这项配置”,不得写入真实 secret。
|
|
144
|
+
- `configs/default.env` 只承载密钥、token、密码、cookie、私钥、credential path 等敏感 env 覆盖项;不承载第二套非敏感结构化配置。
|
|
145
|
+
- `configs/default.env` 的正式语义是:为 `default.jsonc` 中对应的敏感字段提供 env 覆盖作者面,而不是另起第二套 schema。
|
|
146
|
+
|
|
147
|
+
关键注意事项:
|
|
148
|
+
- 子包升级后新增的默认配置键不会自动进入运行时,必须通过 `pz settings update` 显式同步到项目根配置
|
|
149
|
+
- 启动期发现必需配置缺失时,应报出缺失路径与修复建议,例如提示执行 `pz settings update --project-dir <project_dir>`,不得回退读取包内模板来补值
|
|
150
|
+
- `pz check` 应包含一个正式的 settings update drift 诊断项;该诊断只能复用 `pz settings update` 的同源 dry-run 计划判断“当前执行 update 是否会产生配置同步变更”,不得按 `default.jsonc` 的 mtime、hash 或手写 diff 另建第二套判断规则
|
|
151
|
+
- `settings.py` / `settings/` 可以声明 schema、normalize 与 runtime override metadata,但 import 阶段不得读取包内 `configs/default.jsonc`、包内 `configs/default.env`、项目 `.env*` 或进程环境变量
|
|
152
|
+
- 包内 `configs/default.jsonc` / `configs/default.env` 仍必须随 wheel 分发,因为生产环境的 `pz settings init/update` 需要从已安装包读取模板
|
|
153
|
+
- 包升级、wheel 内容变化、缺少模板文件都不应改变已经生成的运行时 `SettingsSnapshot`;线上默认行为只由项目根配置与 env layer 决定
|
|
154
|
+
|
|
155
|
+
项目级 JSONC 协议:
|
|
156
|
+
- 项目级配置唯一正式作者面固定为 `pz.jsonc`
|
|
157
|
+
- 环境级项目覆盖唯一正式作者面固定为 `pz.{PZ_ENV}.jsonc`
|
|
158
|
+
- JSONC 的正式读写必须统一通过 `pz/utils/project_jsonc/` 模块,不允许各处自行解析或回写
|
|
159
|
+
- `project_jsonc` 负责:
|
|
160
|
+
- 解析 JSONC
|
|
161
|
+
- 过滤普通注释的语义影响
|
|
162
|
+
- 保留并处理工具注释
|
|
163
|
+
- 提供统一的读写、托管区更新与写回能力
|
|
164
|
+
|
|
165
|
+
工具注释约定:
|
|
166
|
+
- 工具注释独占前缀固定为 `// @pz:`
|
|
167
|
+
- 当前正式支持的 directive 只有:
|
|
168
|
+
- `// @pz:managed:start <path>`
|
|
169
|
+
- `// @pz:managed:end <path>`
|
|
170
|
+
- 其它 `// @pz:*` 暂视为保留扩展位;当前版本应识别为工具注释但默认忽略,不得因未知 directive 直接报错
|
|
171
|
+
- 其它普通 `// ...` 注释只作为人类说明文本,不参与配置语义
|
|
172
|
+
- `project_jsonc` 在写回时应尽量保留普通 `// ...` 注释与相邻结构位置,但不承诺字节级原样保留
|
|
173
|
+
|
|
174
|
+
`installed_apps` 语义:
|
|
175
|
+
- `installed_apps` 可以直接声明正式最小子包,也可以声明文件夹/容器目录
|
|
176
|
+
- 每个最小子包都必须显式拥有自己的 `configs/default.jsonc`
|
|
177
|
+
- 每个最小子包都应配对拥有自己的 `configs/default.env`;无密钥字段时保留空模板即可
|
|
178
|
+
- `configs/` 必须是正式 Python 子包并包含 `configs/__init__.py`;`configs/default.jsonc` 与 `configs/default.env` 必须进入 wheel 后仍可被 settings 工具读取
|
|
179
|
+
- 分组目录只用于 Git 与源码组织,不参与运行时 namespace
|
|
180
|
+
- 若声明的是文件夹/容器目录,框架必须自动递归发现其中嵌套的最小子包
|
|
181
|
+
- settings、app registry、resources、routes 等正式装配单元等于递归展开后的最小子包集合
|
|
182
|
+
- `installed_apps` 的条目语法固定为目录名,不接受文件系统路径、distribution 名或 `<pkg>.apps:app`
|
|
183
|
+
|
|
184
|
+
叶子 app namespace 语义:
|
|
185
|
+
- 每个叶子 app 的唯一配置命名空间固定为其 `app.id`
|
|
186
|
+
- 不允许再单独声明第二个 settings namespace
|
|
187
|
+
- 新建子包默认让 `app.id` 等于最小子包目录名与 import 包名;历史子包已发布的 `app.id` 以稳定值为准,不因文档命名口径变化自动迁移
|
|
188
|
+
|
|
189
|
+
环境覆盖:
|
|
190
|
+
- 环境变量
|
|
191
|
+
- `<project_dir>/.env`
|
|
192
|
+
- `<project_dir>/.env.{PZ_ENV}`
|
|
193
|
+
|
|
194
|
+
密钥模板:
|
|
195
|
+
- 已安装子包的 `configs/default.env`
|
|
196
|
+
|
|
197
|
+
`configs/default.jsonc` 只作为 `pz settings init/update` 生成或补全项目 `pz.jsonc` / `pz.{PZ_ENV}.jsonc` 的 authoring 模板来源,不属于 `SettingsSnapshot` 的启动期输入。
|
|
198
|
+
|
|
199
|
+
`configs/default.env` 只作为 `pz settings init/update` 生成项目 `.env*` 的 authoring 模板来源,不属于 `SettingsSnapshot` 的启动期输入。启动阶段的 env layer 只读取项目 `.env`、项目 `.env.{PZ_ENV}` 与显式环境变量。
|
|
200
|
+
|
|
201
|
+
两者关系固定为:
|
|
202
|
+
|
|
203
|
+
- `default.jsonc` 先声明完整配置骨架。
|
|
204
|
+
- `default.env` 再为其中需要保密的字段提供覆盖入口。
|
|
205
|
+
- 运行期进入 `SettingsSnapshot` 时,env layer 对项目 JSONC 静态层生效覆盖;不允许反过来由 JSONC 覆盖 env 中的 secret。
|
|
206
|
+
- 因此,人的作者面心智应当是“先在 `default.jsonc` 看完整长相,再在 `default.env` 填敏感值覆盖对应字段”。
|
|
207
|
+
|
|
208
|
+
`configs/default.env` 可对需要自动生成的密钥使用 `@pz:secret:urlsafe64` 或 `@pz:secret:hex64` 作为值。`pz settings init/update` 会在项目 `.env` 中生成持久强随机值;如果项目 `.env` 已存在非空值则保留,存在空值则补齐。`.env.{PZ_ENV}` 仍只渲染注释占位符,除非项目已有显式环境值。
|
|
209
|
+
|
|
210
|
+
项目环境选择:
|
|
211
|
+
- `PZ_ENV`
|
|
212
|
+
|
|
213
|
+
约束:
|
|
214
|
+
- `PZ_ENV` 是唯一正式环境选择变量
|
|
215
|
+
- 编译后的 project snapshot 可以暴露派生字段 `project.pz_env`,但它不是新的外部输入入口
|
|
216
|
+
- 未显式指定 `PZ_ENV` 时,正式默认环境固定为 `develop`
|
|
217
|
+
- `product` 环境必须在启动命令或进程环境中显式指定;不允许靠读取 `.env.product` 反向推导当前环境
|
|
218
|
+
- `.env.{PZ_ENV}` 只允许在环境已经选定后参与加载,不得作为环境选择输入来源
|
|
219
|
+
- `project.environment` / `project.env` / `project.pz_env` / 顶层 `environment` / 顶层 `pz_env` 都不再作为输入来源
|
|
220
|
+
- 上述旧环境选择字段如果出现在 `pz.jsonc` 或传入 payload 中,正式行为是直接报错,而不是静默忽略
|
|
221
|
+
|
|
222
|
+
## 3. 配置优先级
|
|
223
|
+
|
|
224
|
+
`SettingsSnapshot` 编译顺序固定为:
|
|
225
|
+
|
|
226
|
+
1. 读取 `settings.py` / `settings/` 的 schema、normalize 与 runtime override 声明;声明模块不得在 import 阶段读取 `configs/default.jsonc` 或 `.env*`
|
|
227
|
+
2. 读取 `pz.jsonc`
|
|
228
|
+
3. 读取 `pz.{PZ_ENV}.jsonc`
|
|
229
|
+
4. 读取 module config owner 编译出的 module config patches
|
|
230
|
+
5. 读取 `<project_dir>/.env`
|
|
231
|
+
6. 在环境已选定后读取 `<project_dir>/.env.{PZ_ENV}`
|
|
232
|
+
7. 叠加显式环境变量,形成受保护的 env layer
|
|
233
|
+
8. 合并项目静态层与 env layer,优先级固定为:
|
|
234
|
+
- `pz.jsonc`
|
|
235
|
+
- `pz.{PZ_ENV}.jsonc`
|
|
236
|
+
- module config patches
|
|
237
|
+
- `.env`
|
|
238
|
+
- `.env.{PZ_ENV}`
|
|
239
|
+
- 显式环境变量
|
|
240
|
+
9. 解析 `installed_apps` / `app_replacements`
|
|
241
|
+
10. 组装 `apps.<app_id>`
|
|
242
|
+
|
|
243
|
+
补充说明:
|
|
244
|
+
- `.env`、`.env.{PZ_ENV}` 与显式环境变量组成统一 env layer,其中显式环境变量优先于 `.env.{PZ_ENV}`,`.env.{PZ_ENV}` 优先于 `.env`
|
|
245
|
+
- `pz.jsonc` 与 `pz.{PZ_ENV}.jsonc` 是启动期项目静态配置来源,不得覆盖 env layer
|
|
246
|
+
- 上述顺序描述的是 `SettingsSnapshot` 的正式编译主链
|
|
247
|
+
- `SettingsSnapshot` 编译主链不得调用 `load_app_default_settings_payload()`、`load_local_default_settings()` 或任何等价的包内默认模板读取 helper
|
|
248
|
+
- 对 app 运行时代码而言,正式读取顺序固定为:
|
|
249
|
+
1. `SettingsSnapshot.apps.<app_id>` 基线值
|
|
250
|
+
2. app settings provider 补充值
|
|
251
|
+
3. settings runtime owner runtime overrides
|
|
252
|
+
- provider 只参与运行时读取,不参与 `SettingsSnapshot` 编译
|
|
253
|
+
- 普通业务运行时读取入口固定为 `settings_center.settings.<app_id>`;`resolve_settings(project_dir=...)` 只允许用于明确的跨项目工具面或 owner 级基础设施探针,不得成为业务子包的第二套 app settings 读取主链
|
|
254
|
+
- `pz settings init` 只负责一次性读取 `installed_apps` 展开后的所有最小子包 `configs/default.jsonc` / `configs/default.env`,并生成项目根 `pz*.jsonc` 与 `.env*`
|
|
255
|
+
- 底层 scaffold service 应同时生成项目根 `pz.jsonc`、`pz.develop.jsonc`、`pz.test.jsonc`、`pz.product.jsonc`、`.env`、`.env.develop`、`.env.test`、`.env.product`;公开 CLI 初始化入口固定为分组命令
|
|
256
|
+
- `pz.develop.jsonc` / `pz.test.jsonc` / `pz.product.jsonc` 必须写入对应环境的非敏感静态覆盖骨架,不能使用空 `{}` 作为长期正式模板
|
|
257
|
+
- `pz settings init` 在这些文件缺失时也必须补齐同名骨架;其中 `.env` 必须写入默认 env 模板,`.env.develop` / `.env.test` / `.env.product` 必须写入对应环境占位模板
|
|
258
|
+
- `pz settings init/update` 必须读取已安装最小子包的 `configs/default.env`,把其中变量合并进项目 `.env*`;`.env` 使用未注释占位,`.env.{PZ_ENV}` 使用注释占位,已有同名项目值必须保留
|
|
259
|
+
- 默认 `.env` 模板应参考当前正式项目 env 键面,只保留当前正式 settings/source-of-truth 仍认可的 env 项;`PZ_AGENT*`、`SEO_OPS*` 这类已移出当前正式 settings 真相源的键不得进入默认模板
|
|
260
|
+
- 默认环境 JSONC 模板应只放非敏感、结构化、适合进入 `pz.{env}.jsonc` 的覆盖项,例如 `project.base_url`、`project.STATIC_TARGET_*`、middleware 静态覆盖;不得把 secrets 写回 JSONC
|
|
261
|
+
- `pz settings init` 自动补齐 env / jsonc 骨架时,不得覆盖项目中已存在的同名文件
|
|
262
|
+
- `pz settings init` 不得内置业务宿主模板白名单,也不定义面向业务默认值的项目骨架扩展机制
|
|
263
|
+
- 当前版本不定义正式的初始化骨架扩展协议;`pz settings init` 只生成 `pz` 内建的通用作者面骨架
|
|
264
|
+
- `pz` 不提供第二套 init 命令、业务 profile 参数或初始化骨架注册器
|
|
265
|
+
- 项目级 `pz.jsonc` 默认骨架属于作者面能力,正式真相源固定为 `pz/authoring/project_default.jsonc`
|
|
266
|
+
- `project_default.jsonc` 的正式职责固定为:`pz` 的通用作者面默认骨架
|
|
267
|
+
- `project_default.jsonc` 当前没有正式扩展点;项目级通用骨架只能由 `pz` 内建实现维护
|
|
268
|
+
- 各最小子包 `configs/default.jsonc` 的正式职责固定为:各子包自己的 settings 作者面默认模板,只供 `pz settings init/update` 读取
|
|
269
|
+
- 各最小子包 `configs/default.jsonc` 可以声明受控的顶层路由默认值 `routing.default_language`、`routing.all_supported_languages`、`routing.language_aliases`;`pz settings init/update` 会把这些值提升到根 `routing`,并从 `apps.<app_id>` 私有配置中剥离
|
|
270
|
+
- 各最小子包 `configs/default.jsonc` 可以声明受控的顶层快捷命令 `commands`;`pz settings init/update` 会把这些值提升到根 `commands`,同名命令以 app 默认刷新,未声明的项目自定义命令保留
|
|
271
|
+
- 各最小子包 `configs/default.jsonc` 可以声明受控的项目装配状态 `apps.*.sources.source_mode`;`pz settings init/update` 会把该字段提升到根 `apps` 对应 owner,作为 local/git/package 源码策略的单一真相
|
|
272
|
+
- 各最小子包 `configs/default.env` 的正式职责固定为:各子包自己的 Git 可追踪 secret 占位模板,只供 `pz settings init/update` 读取
|
|
273
|
+
- `project_jsonc` 只负责协议与读写规则,不承载默认骨架内容
|
|
274
|
+
- `pz` 是该骨架的唯一作者面与 CLI 执行器;`pz_settings_center` 只提供运行时 settings surface,不再承担作者面职责
|
|
275
|
+
- 生成时应基于当前已安装目录声明递归发现最小子包,并使用 `project_jsonc` 在 JSONC 中生成托管区块
|
|
276
|
+
- 托管区块必须通过 `// @pz:managed:start <path>` / `// @pz:managed:end <path>` 表达,而不是由业务层自行约定其它注释协议
|
|
277
|
+
- `pz settings init` 的正式托管区固定为:
|
|
278
|
+
- `installed_apps`
|
|
279
|
+
- `middlewares`
|
|
280
|
+
- `middlewares` 托管区是项目级 middleware 作者面真相源;工具应基于当前发现结果编译 conventional middleware manifest,并写回顶层 `middlewares`
|
|
281
|
+
- 若根目录已存在 `pz.jsonc`,默认必须拒绝覆盖;只有显式传入 `pz settings init --force` 时,才允许在自动备份后按当前发现结果整体重生成 settings 文件
|
|
282
|
+
- `pz settings init --force` 的正式语义是“备份当前 `pz.jsonc`、`pz.{env}.jsonc` 与 `.env*` 后,删除旧 settings 语义并按当前可发现 app 集重新生成”,不是在旧 `pz.jsonc` 上做保留式 merge
|
|
283
|
+
- `pz settings update` 负责再次扫描已安装 app,只补充新增的默认配置键,不覆盖 `pz.jsonc` 中已经存在的项目级值
|
|
284
|
+
- `pz settings update` 是“把包内模板变成项目运行时配置”的唯一正式入口;不要在启动、provider、middleware、lifespan 或业务 import 阶段临时补写默认值
|
|
285
|
+
- settings update drift 诊断是 `pz settings update` 的只读预演:它可以读取同一批 app `configs/default.jsonc` / `configs/default.env` 与项目 settings 文件,比较 dry-run 的 settings payload 与 env 模板合并结果是否会改变 `pz.jsonc`、`pz.{env}.jsonc` 或 `.env*`;诊断结果只进入 `pz check` 的 `CheckReport`,不写文件、不创建备份、不生成运行时默认值
|
|
286
|
+
- 上述“不覆盖”只适用于项目作者显式写入的业务值;如果某个 app 在 `settings.py` / `settings/` 中正式声明了 normalize 规则,`pz settings update` 只允许在当前稳定合同内做归一化,不再负责历史别名或旧键迁移
|
|
287
|
+
- 这类归一化必须由 app 自己在 `settings.py` / `settings/` 中声明,不能靠宿主手改 `pz.jsonc`、middleware 构造期临时补写、bootstrap 阶段偷偷修正,或工具侧兼容旧键
|
|
288
|
+
- `pz settings update` 更新 `middlewares` 托管区时,应先按当前 app 集合重新编译 conventional middleware manifest;若项目中已存在显式 middleware 顺序,则已知 middleware id 的相对顺序保持项目作者面真相,并按 conventional manifest 追加新发现的 middleware
|
|
289
|
+
- `pz settings update --reset-middlewares-order` 可显式要求按当前 conventional middleware manifest 重写托管区顺序;该选项只影响托管区,不覆盖非托管业务配置
|
|
290
|
+
- `pz settings update <target>` 允许只补充指定最小子包的默认配置
|
|
291
|
+
|
|
292
|
+
边界:
|
|
293
|
+
- `.env` 本质属于环境变量来源的一部分
|
|
294
|
+
- `.env` / `.env.{PZ_ENV}` 仅作为开发便利,不应替代正式配置文件
|
|
295
|
+
- 数据库、Redis、密钥、外部服务地址等敏感或部署相关配置应优先放在 `.env`
|
|
296
|
+
|
|
297
|
+
补充约束:
|
|
298
|
+
- `.env` 搜索不应继续围绕 `ROOT_DIR` 或框架源码仓库根目录展开
|
|
299
|
+
- `.env` 只允许使用 `<project_dir>/.env`
|
|
300
|
+
- `.env.{PZ_ENV}` 只允许使用 `<project_dir>/.env.{PZ_ENV}`
|
|
301
|
+
- 配置加载器不应再把合并后的环境键值写回 `os.environ`
|
|
302
|
+
- settings 构建应消费显式 env snapshot,而不是通过“先改写进程环境,再让 `BaseSettings` 回读”实现
|
|
303
|
+
- `pyproject.toml` 中的历史框架私有配置段不作为正式配置来源
|
|
304
|
+
|
|
305
|
+
## 3.1 配置装配的确定性约束
|
|
306
|
+
|
|
307
|
+
从工程实践看,配置系统首先必须是可预测的。
|
|
308
|
+
|
|
309
|
+
要求:
|
|
310
|
+
|
|
311
|
+
- 同一组输入在同一版本下必须产出同一份 settings snapshot
|
|
312
|
+
- 配置解析阶段不得触发网络 I/O
|
|
313
|
+
- 配置解析阶段不得触发 DB/Redis 探测
|
|
314
|
+
- 配置解析阶段不得顺手执行资源 merge、asset build、migrations 聚合
|
|
315
|
+
- settings snapshot 一旦完成,就应作为入口期稳定输入传入后续装配链
|
|
316
|
+
- settings snapshot 必须视为只读编译产物,不允许在 bootstrap/lifespan/startup 中被原地改写
|
|
317
|
+
|
|
318
|
+
不采用:
|
|
319
|
+
|
|
320
|
+
- 先给一份半初始化 settings
|
|
321
|
+
- 后续 bootstrap/lifespan 再补字段、改字段、重算字段
|
|
322
|
+
|
|
323
|
+
## 3.2 Settings 编译边界
|
|
324
|
+
|
|
325
|
+
Settings 编译阶段只允许做三类事情:
|
|
326
|
+
|
|
327
|
+
1. 读取输入
|
|
328
|
+
- `pz.jsonc`
|
|
329
|
+
- `pz.{PZ_ENV}.jsonc`
|
|
330
|
+
- `<project_dir>/.env`
|
|
331
|
+
- `<project_dir>/.env.{PZ_ENV}`
|
|
332
|
+
- 显式环境变量
|
|
333
|
+
2. 归一化字段
|
|
334
|
+
- 路径锚点
|
|
335
|
+
- 命名空间映射
|
|
336
|
+
- 派生字段计算
|
|
337
|
+
3. 产出只读 `SettingsSnapshot`
|
|
338
|
+
|
|
339
|
+
禁止:
|
|
340
|
+
|
|
341
|
+
- 在 `AppSettings` / `CoreSettings` validator 中做跨 app 规则裁决
|
|
342
|
+
- 在配置编译阶段执行 I/O、provider lookup、client 初始化、resource 扫描
|
|
343
|
+
- 在 settings 模型中混入 route/middleware/resource/infra 的运行时装配逻辑
|
|
344
|
+
- 通过 settings hook/validator 顺手修改全局单例或注册 provider
|
|
345
|
+
|
|
346
|
+
补充要求:
|
|
347
|
+
|
|
348
|
+
- 数据库、Redis、外部服务 client 等启动前依赖的配置,必须在 `SettingsSnapshot` 编译完成后即可完整可读
|
|
349
|
+
- app provider 只能补充“app 已启动后才能知道的运行态配置”,不能承担基础连接配置真相源职责
|
|
350
|
+
- provider 不得反向改写 `SettingsSnapshot`
|
|
351
|
+
|
|
352
|
+
正式要求:
|
|
353
|
+
|
|
354
|
+
- `AppSettings` / `SettingsSnapshot` 只表达配置结果,不承担运行时副作用职责
|
|
355
|
+
- 跨 app 规则、冲突治理、capability 绑定都必须在后续专用 compiler/registry 中完成
|
|
356
|
+
|
|
357
|
+
## 3.3 配置读取的单一路径原则
|
|
358
|
+
|
|
359
|
+
从运行时代码视角,配置读取也必须只有一种正式方式。
|
|
360
|
+
|
|
361
|
+
正式要求:
|
|
362
|
+
|
|
363
|
+
- 编译阶段统一产出唯一 `SettingsSnapshot`
|
|
364
|
+
- 运行阶段可以基于当前 `SettingsSnapshot` 派生内部 `ResolvedSettings` 视图,但这些都不是应用层正式读取入口
|
|
365
|
+
- Web / CLI / worker / app runtime 在应用层只允许通过 `settings_center.settings` 读取配置
|
|
366
|
+
- app 代码读取私有配置时,只能读取 `settings_center.settings.<app_id>`
|
|
367
|
+
- app 运行时正式入口固定为:
|
|
368
|
+
- `settings_center.settings`
|
|
369
|
+
|
|
370
|
+
补充要求:
|
|
371
|
+
|
|
372
|
+
- `app_id` 必须来自正式叶子 app 的 `app.id`
|
|
373
|
+
- 没有叶子 app 身份的内部模块,不允许自造新的 `app_id`
|
|
374
|
+
- 这类内部模块只能读取所属父 app 的 `<app>.settings` 命名空间,也就是 `settings_center.settings.<parent_app_id>`
|
|
375
|
+
- 若读取的是项目级装配信息,只能读取 `settings_center.settings.project.<field>`
|
|
376
|
+
|
|
377
|
+
不允许:
|
|
378
|
+
|
|
379
|
+
- 一部分代码读 `SettingsSnapshot`
|
|
380
|
+
- 一部分代码再读基础包内部 settings helper
|
|
381
|
+
- 一部分代码再直接读 `os.environ`
|
|
382
|
+
- 一部分代码再去项目目录重读 `pz.jsonc`
|
|
383
|
+
- 一部分代码再自己推导非 `PZ_ENV` 的环境选择路径
|
|
384
|
+
|
|
385
|
+
约束:
|
|
386
|
+
|
|
387
|
+
- `SettingsSnapshot` 是唯一正式配置真相源
|
|
388
|
+
- `ResolvedSettings` 是唯一正式运行时大 settings 视图
|
|
389
|
+
- `settings_center.settings` 是应用层唯一正式 Python settings 入口对象
|
|
390
|
+
- `pz.runtime.settings` 只保留底层 machinery
|
|
391
|
+
- 任意 request helper、middleware、CLI tool、worker loop 都不得自建第二套 settings 读取路径
|
|
392
|
+
|
|
393
|
+
补充结论:
|
|
394
|
+
|
|
395
|
+
- module config owner 不是运行时读取入口
|
|
396
|
+
- settings runtime owner 不是运行时读取入口
|
|
397
|
+
- 运行时代码只允许 `import pz_settings_center.public as settings_center`
|
|
398
|
+
|
|
399
|
+
### 3.4 settings lazy autoload
|
|
400
|
+
|
|
401
|
+
`settings_center.settings` 支持正式的 settings lazy autoload。它的目标是让普通脚本与 app 运行时代码拥有同一条配置读取心智:
|
|
402
|
+
|
|
403
|
+
```python
|
|
404
|
+
import pz_settings_center.public as settings_center
|
|
405
|
+
|
|
406
|
+
value = settings_center.settings.<app_id>.<field>
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
正式语义:
|
|
410
|
+
|
|
411
|
+
- `import pz_settings_center.public as settings_center` 只取得 settings 读取 surface,不得在 import 阶段编译或绑定 `SettingsSnapshot`
|
|
412
|
+
- 第一次访问 `settings_center.settings.project`、`settings_center.settings.<app_id>`、`settings_center.settings.get(...)` 或 `settings_center.settings.app_settings(...)` 时,如果当前进程还没有绑定 snapshot,框架才自动编译当前项目的 `SettingsSnapshot`
|
|
413
|
+
- 如果当前进程已经处在 `pz run`、`pz <app_id> <tool>`、worker 或其它正式入口中,lazy autoload 必须优先消费当前已绑定的 runtime snapshot
|
|
414
|
+
- 直接运行脚本并通过 `settings_center.settings` 读取时,project 选择优先级固定为:已绑定 runtime snapshot > `PZ_PROJECT_DIR` > 从当前工作目录向上查找 `pz.jsonc`
|
|
415
|
+
- 跨项目工具面显式调用 `settings_center.resolve_settings(project_dir=...)` 时,该显式 `project_dir` 只作用于本次解析,并优先于当前进程的默认项目发现
|
|
416
|
+
- 环境选择仍只认 `PZ_ENV`,未显式指定时固定为 `develop`
|
|
417
|
+
- lazy autoload 只保证 settings center 可用;它不是 runtime autoload,不保证 `RuntimePlan`、route manifest、resource manifest、infra provider、middleware、worker lifecycle 或 runtime bindings 已经完成
|
|
418
|
+
|
|
419
|
+
约束:
|
|
420
|
+
|
|
421
|
+
- settings lazy autoload 不得读取已安装子包的 `configs/default.jsonc` / `configs/default.env` 来补值
|
|
422
|
+
- 找不到项目、配置缺失或类型错误时,必须按 settings 编译链报正式错误,不得 fallback 到包内默认值或第二套项目发现规则
|
|
423
|
+
- app 运行时代码不得因为 lazy autoload 存在而改用 `resolve_settings(project_dir=...)` 作为第二读取主链;普通读取仍固定为 `settings_center.settings.<app_id>`
|
|
424
|
+
- settings provider 必须轻量、确定且无运行时副作用,只能依赖 `SettingsSnapshot` / `ProjectContext` / provider context,不得依赖 Web app、route manifest、resource build、数据库连接、Redis 连接或 runtime bindings
|
|
425
|
+
- provider patch 仍只参与最终 settings 视图,不得反向改写 `SettingsSnapshot`
|
|
426
|
+
|
|
427
|
+
## 4. 全局配置与 app 配置
|
|
428
|
+
|
|
429
|
+
### 4.1 全局配置
|
|
430
|
+
|
|
431
|
+
核心字段使用:
|
|
432
|
+
- `settings_center.settings.project.<field>`
|
|
433
|
+
|
|
434
|
+
例如:
|
|
435
|
+
- `settings_center.settings.project.name`
|
|
436
|
+
- `settings_center.settings.project.base_url`
|
|
437
|
+
- `settings_center.settings.project.installed_apps`
|
|
438
|
+
- `settings_center.settings.project.cache_dir`
|
|
439
|
+
- `settings_center.settings.project.runtime_dir`
|
|
440
|
+
- `settings_center.settings.project.asset_dir`
|
|
441
|
+
|
|
442
|
+
补充约束:
|
|
443
|
+
- `create_app()`、`create_host_app()`、CLI、worker 都不应默认回落到进程级全局 `settings`
|
|
444
|
+
- 它们应优先消费显式传入或显式解析出来的 settings snapshot
|
|
445
|
+
- “导入模块就锁定当前项目上下文”的旧行为必须删除,不能继续作为正式配置模型
|
|
446
|
+
|
|
447
|
+
### 4.2 app 配置
|
|
448
|
+
|
|
449
|
+
业务或插件配置统一使用:
|
|
450
|
+
- `settings_center.settings.<app_id>.<field>`
|
|
451
|
+
|
|
452
|
+
例如:
|
|
453
|
+
- `settings_center.settings.content_app.route_policy`
|
|
454
|
+
- `settings_center.settings.example_app.site_image`
|
|
455
|
+
|
|
456
|
+
要求:
|
|
457
|
+
- 不再将 app 私有字段扁平化注入全局根命名空间
|
|
458
|
+
|
|
459
|
+
补充约束:
|
|
460
|
+
- app 运行时代码不应长期保留“命名空间优先、根级历史字段回退”的双读模式
|
|
461
|
+
- 任何 app 私有字段与根级历史字段并存的双读方式,都必须收口到单一路径
|
|
462
|
+
- 新版规范里,app 私有配置的唯一稳定读取入口应为 `settings_center.settings.<app_id>`
|
|
463
|
+
- 不允许再额外引入 `settings.<custom_namespace>` 这类独立于 `app.id` 的第二命名空间
|
|
464
|
+
|
|
465
|
+
### 4.2.1 app 运行时消费边界
|
|
466
|
+
|
|
467
|
+
`settings_center.settings.<app_id>` 是 app 运行时拿到的最终 typed 配置对象。进入业务运行时后,字段值已经完成项目配置、环境层、provider patch 与 runtime override 的合并、类型化、默认补齐与必要 normalize。
|
|
468
|
+
|
|
469
|
+
子包运行时代码只允许消费最终字段值:
|
|
470
|
+
|
|
471
|
+
- 读取路径固定为 `settings_center.settings.<app_id>.<field>`
|
|
472
|
+
- 可以把字段值直接传入 service、store、client、worker、middleware、URL builder 等运行时对象
|
|
473
|
+
- 可以在 runtime builder 中把多个字段组装成业务构造参数,但该组装不得重新定义配置来源、默认值或类型语义
|
|
474
|
+
|
|
475
|
+
子包运行时代码不允许再做 settings center 已经负责的事情:
|
|
476
|
+
|
|
477
|
+
- 不允许新增 `runtime_settings.py`、`system_settings.py`、`load_<app>_settings()`、`resolve_<app>_settings()` 等第二读取主链
|
|
478
|
+
- 不允许读取 `os.environ`、项目 `.env*`、`pz*.jsonc`、包内 `configs/default.jsonc` / `configs/default.env` 来补配置
|
|
479
|
+
- 不允许在运行时使用 `bool(...)`、`int(...)`、`float(...)`、`str(...)` 等方式重新解释 settings 字段类型
|
|
480
|
+
- 不允许用本地 dataclass 默认值、硬编码默认值、`or <default>`、`try/except missing -> default` 覆盖 settings center 的最终值
|
|
481
|
+
- 不允许包装一套本地 “settings missing” 错误来隐藏 settings center / `SettingsSnapshot` 的缺失语义
|
|
482
|
+
- 不允许通过 `env` 参数、legacy root 字段、历史 namespace 或 helper fallback 形成第二套读取顺序
|
|
483
|
+
|
|
484
|
+
子包需要做的配置工作只限声明层:
|
|
485
|
+
|
|
486
|
+
- 在 `settings.py` / `settings/` 中声明 `AppSettings` 字段类型、校验、必要 normalize 与 `__runtime_overrides__`
|
|
487
|
+
- 在 `configs/default.jsonc` / `configs/default.env` 中提供 `pz settings init/update` 的作者面默认模板
|
|
488
|
+
- 在子包设计文档中说明字段语义、取值范围、运行时影响与 owner 边界
|
|
489
|
+
|
|
490
|
+
如果某个字段需要默认值、类型转换、别名兼容、环境变量覆盖或 runtime override 生效,必须进入 settings 编译链或 settings runtime owner 的正式链路,不能落在业务运行时模块里。
|
|
491
|
+
|
|
492
|
+
## 4.3 app settings 实现方式
|
|
493
|
+
|
|
494
|
+
新规范采用:
|
|
495
|
+
- app 的 `AppSettings` 使用 `BaseModel`
|
|
496
|
+
- `AppSettings` 只承载 schema、类型校验与必要 normalize,不再承载默认值真相源
|
|
497
|
+
- 框架统一负责从 `pz.jsonc`、`pz.{PZ_ENV}.jsonc`、项目 `.env*`、显式环境变量、运行时覆盖中构建 `settings_center.settings.<app_id>`
|
|
498
|
+
- 运行时不再公开 `load_app_settings()`、`load_typed_app_settings()`、`load_<app>_settings()` 这类第二入口
|
|
499
|
+
|
|
500
|
+
不允许:
|
|
501
|
+
- 每个 app 自己使用 `BaseSettings + env_prefix` 各自再读一遍环境变量
|
|
502
|
+
|
|
503
|
+
目的:
|
|
504
|
+
- 避免配置读取逻辑分散
|
|
505
|
+
- 避免聚合器与 app 自读环境形成双重真相源
|
|
506
|
+
- 便于未来统一配置文件语义
|
|
507
|
+
|
|
508
|
+
补充要求:
|
|
509
|
+
- app settings 聚合器正式只包含:
|
|
510
|
+
- `pz.jsonc` / `pz.{PZ_ENV}.jsonc` 中的 `apps.<app_id>`
|
|
511
|
+
- 项目 `.env` / `.env.{PZ_ENV}` / 显式环境变量中的 `<APPID>__*`
|
|
512
|
+
- app settings provider
|
|
513
|
+
- 运行时覆盖
|
|
514
|
+
- 包内正式默认模板文件固定为 `configs/default.jsonc`,只由 `pz settings init/update` 消费
|
|
515
|
+
- 不再支持项目级 `configs/apps/*.toml`
|
|
516
|
+
- 项目级 app 配置搜索不应再把 `Path.cwd()` 与 `ROOT_DIR` 一起并列当成 project root 候选
|
|
517
|
+
- app settings 聚合器不应反向 import 基础包全局 settings 实例或私有 env helper 再拼装命名空间
|
|
518
|
+
- namespace attach 与 runtime overrides schema 注册不应再混在同一个副作用流程里
|
|
519
|
+
|
|
520
|
+
## 4.4 module config 正式协议
|
|
521
|
+
|
|
522
|
+
module config owner 的正式对象固定为:
|
|
523
|
+
|
|
524
|
+
- `ModuleConfigDefinition`
|
|
525
|
+
- `ModuleConfigField`
|
|
526
|
+
- `ModuleConfigBinding`
|
|
527
|
+
- `ModuleConfigPatch`
|
|
528
|
+
|
|
529
|
+
其中:
|
|
530
|
+
|
|
531
|
+
- 前三者属于声明期对象
|
|
532
|
+
- `ModuleConfigPatch` 属于编译产物
|
|
533
|
+
|
|
534
|
+
### 4.4.1 `ModuleConfigDefinition`
|
|
535
|
+
|
|
536
|
+
至少应包含:
|
|
537
|
+
|
|
538
|
+
- `module_id`
|
|
539
|
+
- `title`
|
|
540
|
+
- `owner_app`
|
|
541
|
+
- `version`
|
|
542
|
+
- `description`
|
|
543
|
+
- `enabled_by_default`
|
|
544
|
+
- `fields`
|
|
545
|
+
- `bindings`
|
|
546
|
+
- `depends_on`
|
|
547
|
+
|
|
548
|
+
约束:
|
|
549
|
+
|
|
550
|
+
- `module_id` 全局唯一
|
|
551
|
+
- `owner_app` 必须是正式 `app.id`
|
|
552
|
+
- `fields` 内字段名唯一
|
|
553
|
+
- `bindings` 只能引用本 definition 内已声明的 `source_field`
|
|
554
|
+
|
|
555
|
+
### 4.4.2 `ModuleConfigField`
|
|
556
|
+
|
|
557
|
+
至少应包含:
|
|
558
|
+
|
|
559
|
+
- `name`
|
|
560
|
+
- `type`
|
|
561
|
+
- `label`
|
|
562
|
+
- `description`
|
|
563
|
+
- `required`
|
|
564
|
+
- `default`
|
|
565
|
+
- `choices`
|
|
566
|
+
- `secret`
|
|
567
|
+
- `group`
|
|
568
|
+
- `runtime_override`
|
|
569
|
+
- `restart_mode`
|
|
570
|
+
|
|
571
|
+
`type` 必须采用封闭类型系统,只允许正式枚举集合:
|
|
572
|
+
|
|
573
|
+
- `string`
|
|
574
|
+
- `text`
|
|
575
|
+
- `int`
|
|
576
|
+
- `float`
|
|
577
|
+
- `bool`
|
|
578
|
+
- `enum`
|
|
579
|
+
- `json`
|
|
580
|
+
- `list[string]`
|
|
581
|
+
- `list[int]`
|
|
582
|
+
- `list[enum]`
|
|
583
|
+
- `dict[string,string]`
|
|
584
|
+
- `secret`
|
|
585
|
+
- `url`
|
|
586
|
+
- `email`
|
|
587
|
+
- `path`
|
|
588
|
+
- `duration`
|
|
589
|
+
- `bytesize`
|
|
590
|
+
|
|
591
|
+
不允许:
|
|
592
|
+
|
|
593
|
+
- `custom`
|
|
594
|
+
- 任意 Python type path
|
|
595
|
+
- callable / class / instance 进入类型层
|
|
596
|
+
|
|
597
|
+
### 4.4.3 `ModuleConfigBinding`
|
|
598
|
+
|
|
599
|
+
至少应包含:
|
|
600
|
+
|
|
601
|
+
- `source_field`
|
|
602
|
+
- `target_app`
|
|
603
|
+
- `target_path`
|
|
604
|
+
- `transform`
|
|
605
|
+
- `priority`
|
|
606
|
+
- `condition`
|
|
607
|
+
|
|
608
|
+
约束:
|
|
609
|
+
|
|
610
|
+
- `target_path` 必须是声明式点路径
|
|
611
|
+
- 默认只允许 `source_field -> target_app.target_path`
|
|
612
|
+
- `transform` 仅允许作为受控例外存在
|
|
613
|
+
- `transform` 必须引用已注册、命名、纯函数式转换器
|
|
614
|
+
- 不允许任意写入函数
|
|
615
|
+
- 不允许以执行代码的方式直接改写 settings tree
|
|
616
|
+
|
|
617
|
+
### 4.4.4 `ModuleConfigPatch`
|
|
618
|
+
|
|
619
|
+
至少应包含:
|
|
620
|
+
|
|
621
|
+
- `app_id`
|
|
622
|
+
- `payload`
|
|
623
|
+
- `source_module`
|
|
624
|
+
- `priority`
|
|
625
|
+
|
|
626
|
+
约束:
|
|
627
|
+
|
|
628
|
+
- patch 必须是纯数据
|
|
629
|
+
- patch 最终只能并入 `SettingsSnapshot`
|
|
630
|
+
- patch 不是业务代码正式读取对象
|
|
631
|
+
|
|
632
|
+
### 4.4.5 页面域 module config 输入
|
|
633
|
+
|
|
634
|
+
页面相关的 `module config` 静态默认值已经并入 `pz_page_center`。
|
|
635
|
+
|
|
636
|
+
正式输入固定为:
|
|
637
|
+
|
|
638
|
+
- app `pages/base.jsonc`
|
|
639
|
+
|
|
640
|
+
约束:
|
|
641
|
+
|
|
642
|
+
- 页面相关 `module config` 必须由 `pz_page_center` 在启动编译期统一扫描和编译
|
|
643
|
+
- 页面相关 `module config` 拥有独立的页面配置命名空间;它不是 `settings_center.settings.<app_id>` 的子树,也不是第二套 settings namespace
|
|
644
|
+
- 页面配置命名空间固定由 `owner_app + 页面相对路径` 确定,并由 `pz_page_center` 统一裁决
|
|
645
|
+
- 业务 app 不再通过 `public.py` 暴露 `get_public_module_configs()`
|
|
646
|
+
- 多个 app 的页面域静态输入,按 app registry / `installed_apps` 顺序由 `pz_page_center` 统一裁决
|
|
647
|
+
- `base` 页面配置允许由多个 app 在自己的 `pages/base.jsonc` 中共同贡献
|
|
648
|
+
- `locales/config.json` 不再作为 `module config` 的正式文件输入
|
|
649
|
+
- app 若需要私有 JSON 文件,只能作为 app 内部实现细节存在,不得再提升成第二套框架级页面配置入口
|
|
650
|
+
|
|
651
|
+
## 4.5 module config 与 settings runtime owner 的边界
|
|
652
|
+
|
|
653
|
+
正式边界:
|
|
654
|
+
|
|
655
|
+
- module config owner 负责“这是什么配置”
|
|
656
|
+
- settings runtime owner 负责“这个配置如何被修改和生效”
|
|
657
|
+
- settings center 负责“运行时代码如何读取最终配置”
|
|
658
|
+
|
|
659
|
+
不允许:
|
|
660
|
+
|
|
661
|
+
- module config owner 自己暴露并列运行时读取 API
|
|
662
|
+
- settings runtime owner 自己成为配置读取入口
|
|
663
|
+
- settings center 再定义第二套模块配置 schema 协议
|
|
664
|
+
|
|
665
|
+
正式原则:
|
|
666
|
+
|
|
667
|
+
- 配置可以有声明层、编排层、写入层
|
|
668
|
+
- 运行时读取层只能有一层,即 settings center 的正式公开面
|
|
669
|
+
|
|
670
|
+
### 4.5.1 基础设施配置归属
|
|
671
|
+
|
|
672
|
+
database、cache、storage、mail、health、observability、bot logger 这类基础设施配置必须由对应 infra owner 的 app settings 承载。
|
|
673
|
+
|
|
674
|
+
`pz` core 只规定:
|
|
675
|
+
|
|
676
|
+
- `pz settings init/update` 从 owner 子包的 `configs/default.jsonc` 把默认配置补入项目配置
|
|
677
|
+
- 项目覆盖来自 `pz.jsonc` / `pz.{PZ_ENV}.jsonc` 的 `apps.<app_id>`
|
|
678
|
+
- 环境变量只作为覆盖层,命名遵守本文规则
|
|
679
|
+
- runtime override 必须通过 `AppSettings.__runtime_overrides__` 声明
|
|
680
|
+
|
|
681
|
+
具体字段、默认值、降级语义、renderer 名称、第三方通道环境变量等实现细节,必须写在对应 owner 子包设计文档中,不得沉入 core settings 规范。
|
|
682
|
+
|
|
683
|
+
补充约束:
|
|
684
|
+
|
|
685
|
+
- owner app 的选择应优先服从“人对这个领域会去哪里找”的心智,而不是“当前哪段代码最先读取到它”。
|
|
686
|
+
- 一旦某类 concrete 配置已经归属某个 owner app,其它 app 只能引用、编译或消费,不得再新增第二处 authoring 入口。
|
|
687
|
+
|
|
688
|
+
## 4.4 app settings provider 与热更新标注
|
|
689
|
+
|
|
690
|
+
当某个 app 的部分配置只能在 app 启动后确定时,正式做法如下:
|
|
691
|
+
|
|
692
|
+
- 由 app `extensions()` 声明正式 `settings.provider`,运行时统一编译为 `SettingsProviderSpec`
|
|
693
|
+
- provider 输入固定为:
|
|
694
|
+
- `app_id`
|
|
695
|
+
- `SettingsSnapshot`
|
|
696
|
+
- `project_dir`
|
|
697
|
+
- provider 只能返回当前 app 的补充值,不得直接读写全局单例 settings
|
|
698
|
+
- provider 必须可 reset,且具备 owner 语义
|
|
699
|
+
|
|
700
|
+
正式合并顺序固定为:
|
|
701
|
+
|
|
702
|
+
1. `SettingsSnapshot.apps.<app_id>`
|
|
703
|
+
2. provider 返回值
|
|
704
|
+
3. runtime overrides 作为 `pz_settings_center` 的高优先级 `settings.provider` patch 进入同一条 provider 合并链路;`pz` core 不持有 runtime override 状态或命令式写入口
|
|
705
|
+
|
|
706
|
+
热更新暴露规则:
|
|
707
|
+
|
|
708
|
+
- 哪些字段允许被 settings runtime owner 线上热更新,必须在 `AppSettings` 上显式标注
|
|
709
|
+
- 正式标注方式固定为:
|
|
710
|
+
- `AppSettings.__runtime_overrides__`
|
|
711
|
+
- settings runtime owner 只读取这套标注生成 runtime override schema
|
|
712
|
+
|
|
713
|
+
正式写法固定为“字段 -> 配置对象”的 dict:
|
|
714
|
+
|
|
715
|
+
- `__runtime_overrides__ = {"enabled": {"mode": "live", "label": "启用开关"}}`
|
|
716
|
+
|
|
717
|
+
正式 mode:
|
|
718
|
+
|
|
719
|
+
- `live`
|
|
720
|
+
- `refresh`
|
|
721
|
+
- `restart_required`
|
|
722
|
+
|
|
723
|
+
写入行为固定为:
|
|
724
|
+
|
|
725
|
+
- `live`
|
|
726
|
+
- 保存后立即应用到当前进程运行态
|
|
727
|
+
- `refresh`
|
|
728
|
+
- 保存后写入持久层与 L2
|
|
729
|
+
- 由运行态刷新链路在下一次 refresh 时生效
|
|
730
|
+
- `restart_required`
|
|
731
|
+
- 保存后只进入持久层
|
|
732
|
+
- 必须重启进程后才生效
|
|
733
|
+
|
|
734
|
+
附加约束:
|
|
735
|
+
|
|
736
|
+
- 未注册 namespace 不允许写入 runtime override
|
|
737
|
+
- 未在 schema 中声明的 key 不允许写入
|
|
738
|
+
- 写入值必须通过服务端类型校验,不能把任意 JSON 直接塞进运行态
|
|
739
|
+
- `__runtime_overrides__` 配置错误必须在注册期直接失败,不能静默忽略
|
|
740
|
+
|
|
741
|
+
不允许:
|
|
742
|
+
|
|
743
|
+
- 由 settings runtime owner 直接反射任意 `AppSettings` 字段并默认全部开放热更新
|
|
744
|
+
- 继续在业务代码里长期维护一份脱离 `AppSettings` 的手写热更新白名单
|
|
745
|
+
- 在 `AppSettings` 上同时长期保留 tuple/list 简写、字段级元信息标记等多套并行声明方式
|
|
746
|
+
- 继续暴露手工 `register_runtime_override_schema(...)` 之类的旁路 API 让业务绕过 `AppSettings.__runtime_overrides__`
|
|
747
|
+
|
|
748
|
+
## 5. 环境变量命名
|
|
749
|
+
|
|
750
|
+
项目环境选择:
|
|
751
|
+
- `PZ_ENV`
|
|
752
|
+
|
|
753
|
+
约束:
|
|
754
|
+
- `PZ_ENV` 是唯一正式环境选择变量
|
|
755
|
+
- 未显式指定时默认 `develop`
|
|
756
|
+
- `product` 必须在启动命令或进程环境中显式指定
|
|
757
|
+
- `.env.{PZ_ENV}` 只在 `PZ_ENV` 已确定后参与加载
|
|
758
|
+
- 不允许继续引入 `ENVIRONMENT`、`project.environment`、`project.env` 等第二套环境选择入口
|
|
759
|
+
|
|
760
|
+
全局字段:
|
|
761
|
+
- 顶层字段继续使用字段名
|
|
762
|
+
- 项目与路由字段必须使用 section path
|
|
763
|
+
|
|
764
|
+
例如:
|
|
765
|
+
- `CACHE_DIR`
|
|
766
|
+
- `RUNTIME_DIR`
|
|
767
|
+
- `PROJECT__NAME`
|
|
768
|
+
- `PROJECT__DEFAULT_MODULE`
|
|
769
|
+
- `PROJECT__BASE_URL`
|
|
770
|
+
- `ROUTING__DEFAULT_LANGUAGE`
|
|
771
|
+
- `ROUTING__SUPPORTED_LANGUAGES`
|
|
772
|
+
- `DATABASE__HOST`
|
|
773
|
+
- `DATABASE__PORT`
|
|
774
|
+
- `REDIS__HOST`
|
|
775
|
+
- `REDIS__PORT`
|
|
776
|
+
|
|
777
|
+
app 字段:
|
|
778
|
+
- 使用 `<APPID>__KEY`
|
|
779
|
+
|
|
780
|
+
例如:
|
|
781
|
+
- `EXAMPLE_APP__FEATURE_ENABLED=false`
|
|
782
|
+
- `EXAMPLE_APP__SITE_IMAGE=https://example.com/cover.png`
|
|
783
|
+
|
|
784
|
+
规则:
|
|
785
|
+
- `__` 是唯一嵌套分隔符
|
|
786
|
+
- app 代码不得直接自己解析环境变量
|
|
787
|
+
|
|
788
|
+
补充约束:
|
|
789
|
+
|
|
790
|
+
- 环境变量只应作为覆盖层,不应成为唯一正式配置源
|
|
791
|
+
- 同一逻辑字段不得同时支持多套长期前缀体系
|
|
792
|
+
- 大小写、分隔符、布尔/列表/对象解析规则必须形成稳定契约
|
|
793
|
+
- `BASE_URL`、`APP_PORT` 这类大写变量属于宿主 `main.py` / host settings override 的启动特例,不属于通用 settings 命名规则
|
|
794
|
+
- 对 `project.base_url` 的正式 settings 覆盖写法仍然是 `project__base_url` 或 `PROJECT__BASE_URL`,不要把 `BASE_URL` 扩散成项目级通用配置键
|
|
795
|
+
|
|
796
|
+
## 6. `pz.jsonc` / `pz.{PZ_ENV}.jsonc` 正式结构
|
|
797
|
+
|
|
798
|
+
项目级 JSONC 顶层结构推荐固定为:
|
|
799
|
+
|
|
800
|
+
```jsonc
|
|
801
|
+
{
|
|
802
|
+
// @pz:managed:start installed_apps
|
|
803
|
+
"installed_apps": [],
|
|
804
|
+
// @pz:managed:end installed_apps
|
|
805
|
+
|
|
806
|
+
"project": {},
|
|
807
|
+
"apps": {}
|
|
808
|
+
}
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
结构约束:
|
|
812
|
+
- `installed_apps`
|
|
813
|
+
- 项目装配真相源
|
|
814
|
+
- `project`
|
|
815
|
+
- 项目级手写配置
|
|
816
|
+
- `apps`
|
|
817
|
+
- 各 app 的项目级手写 override
|
|
818
|
+
|
|
819
|
+
正式要求:
|
|
820
|
+
- runtime 编译时只消费 `installed_apps`、`project`、`apps`、环境层与运行时覆盖
|
|
821
|
+
- runtime 编译时不允许业务层直接扫描 `@pz` 注释
|
|
822
|
+
- `project_jsonc` 必须在写回时尽量保留普通 `// ...` 注释,但这些普通注释不参与配置语义,也不承诺字节级原样保留
|
|
823
|
+
|
|
824
|
+
示例:
|
|
825
|
+
|
|
826
|
+
```jsonc
|
|
827
|
+
{
|
|
828
|
+
// @pz:managed:start installed_apps
|
|
829
|
+
"installed_apps": [
|
|
830
|
+
"control_panel_app",
|
|
831
|
+
"identity_app",
|
|
832
|
+
"content_app",
|
|
833
|
+
"catalog_app"
|
|
834
|
+
],
|
|
835
|
+
// @pz:managed:end installed_apps
|
|
836
|
+
|
|
837
|
+
"project": {
|
|
838
|
+
"name": "example-project",
|
|
839
|
+
"default_module": "example_app",
|
|
840
|
+
"base_url": "https://example.com",
|
|
841
|
+
"cache_dir": ".runtime/cache",
|
|
842
|
+
"runtime_dir": ".runtime/run",
|
|
843
|
+
"asset_dir": ".assets"
|
|
844
|
+
},
|
|
845
|
+
|
|
846
|
+
"app_replacements": {
|
|
847
|
+
"catalog_app": "custom_catalog_app"
|
|
848
|
+
},
|
|
849
|
+
|
|
850
|
+
"apps": {
|
|
851
|
+
"content_app": {
|
|
852
|
+
"route_policy": {
|
|
853
|
+
"default": "protected"
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
"catalog_app": {
|
|
857
|
+
"default_locale": "zh-CN"
|
|
858
|
+
},
|
|
859
|
+
"<infra_owner>": {
|
|
860
|
+
"database": {
|
|
861
|
+
"enabled": true,
|
|
862
|
+
"driver": "postgresql",
|
|
863
|
+
"host": "127.0.0.1",
|
|
864
|
+
"port": 5432,
|
|
865
|
+
"database": "app",
|
|
866
|
+
"user": "app"
|
|
867
|
+
},
|
|
868
|
+
"cache": {
|
|
869
|
+
"enabled": false
|
|
870
|
+
},
|
|
871
|
+
"observability": {
|
|
872
|
+
"metrics": {
|
|
873
|
+
"enabled": true,
|
|
874
|
+
"path": "/metrics",
|
|
875
|
+
"namespace": "demo_app"
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
补充约束:
|
|
884
|
+
|
|
885
|
+
- `apps.<infra_owner>.database.enabled` / `apps.<infra_owner>.cache.enabled` 是正式稳定字段
|
|
886
|
+
- `apps.<infra_owner>.observability.metrics.enabled` / `path` / `namespace` 是正式稳定字段
|
|
887
|
+
- `[app_replacements]` 是唯一正式 app 替换声明入口
|
|
888
|
+
- 历史 `db_*`、`DB_*`、`redis_*`、`REDIS_*` 必须在单一归一化阶段折叠
|
|
889
|
+
- 像 `db_generate_schemas_on_startup` 这类高影响启动行为,不应继续默认开启而不经过显式能力建模
|
|
890
|
+
- `redis_host = 127.0.0.1`、`redis_port = 6379` 这类“未配置即本机 Redis”默认值不应继续作为正式语义
|
|
891
|
+
- `/metrics` 是否公开、是否鉴权、是否内网暴露,不应继续依赖代码硬编码或反向代理偶然约束
|
|
892
|
+
|
|
893
|
+
## 6.1 app 配置入口
|
|
894
|
+
|
|
895
|
+
正式 app 配置入口固定为:
|
|
896
|
+
|
|
897
|
+
- `pz.jsonc` / `pz.{PZ_ENV}.jsonc` 中的 `apps.<app_id>`
|
|
898
|
+
- 项目 `.env` / `.env.{PZ_ENV}` / 显式环境变量中的 `<APPID>__*`
|
|
899
|
+
|
|
900
|
+
统一由框架聚合后挂载到:
|
|
901
|
+
|
|
902
|
+
- `settings_center.settings.<app_id>`
|
|
903
|
+
|
|
904
|
+
包内 `configs/default.jsonc` 是 `pz settings init/update` 的作者面输入,不是启动期 app 配置入口。
|
|
905
|
+
|
|
906
|
+
## 6.2 路径字段约束
|
|
907
|
+
|
|
908
|
+
凡涉及文件系统路径的配置,必须明确声明其锚点:
|
|
909
|
+
|
|
910
|
+
- 相对 `project_dir`
|
|
911
|
+
- 或显式绝对路径
|
|
912
|
+
|
|
913
|
+
不再允许隐式相对:
|
|
914
|
+
|
|
915
|
+
- `ROOT_DIR`
|
|
916
|
+
- 框架源码目录
|
|
917
|
+
- 当前导入文件所在目录
|
|
918
|
+
|
|
919
|
+
约束:
|
|
920
|
+
- 配置加载器不应因为当前 shell 的 `cwd` 恰好位于某个仓库内,就把该仓库根自动视为当前项目
|
|
921
|
+
|
|
922
|
+
补充要求:
|
|
923
|
+
|
|
924
|
+
- 路径归一化只允许发生在 settings compiler 中
|
|
925
|
+
- 一旦进入 `SettingsSnapshot`,所有路径字段都必须已经是确定语义:
|
|
926
|
+
- 显式绝对路径
|
|
927
|
+
- 或带明确锚点的 project-relative 结果
|
|
928
|
+
- 后续 registry/facade/adapter 不得再重新解释路径锚点
|
|
929
|
+
|
|
930
|
+
## 6.3 保留字段与命名空间约束
|
|
931
|
+
|
|
932
|
+
为了避免 app 生态扩张后互相踩配置命名空间,正式约束如下:
|
|
933
|
+
|
|
934
|
+
- 顶层字段保留给 core/runtime 边界
|
|
935
|
+
- app 私有配置只进入 `[apps.<app_id>]`
|
|
936
|
+
- 不允许 app 在顶层平铺自己的私有字段
|
|
937
|
+
- 不允许 app 额外声明独立于 `app.id` 的 settings namespace
|
|
938
|
+
- 不允许实现子目录通过目录名、模块路径或历史 alias 占用新的 app 配置空间
|
|
939
|
+
|
|
940
|
+
以下命名空间是正式保留命名空间:
|
|
941
|
+
|
|
942
|
+
- `database`
|
|
943
|
+
- `redis`
|
|
944
|
+
- `metrics`
|
|
945
|
+
- `logging`
|
|
946
|
+
- `runtime`
|
|
947
|
+
- `storage`
|
|
948
|
+
- `app_replacements`
|
|
949
|
+
- `apps`
|
|
950
|
+
|
|
951
|
+
## 7. 默认清单策略
|
|
952
|
+
|
|
953
|
+
正式规则:
|
|
954
|
+
- `installed_apps` 默认值为空列表
|
|
955
|
+
- 框架自身不再默认硬编码任何业务 `app`
|
|
956
|
+
|
|
957
|
+
官方样板清单只通过以下渠道提供:
|
|
958
|
+
- 样板项目
|
|
959
|
+
- `pz dev init` / 项目脚手架
|
|
960
|
+
- 文档示例
|
|
961
|
+
|
|
962
|
+
而不是写死进框架默认 settings。
|
|
963
|
+
|
|
964
|
+
约束:
|
|
965
|
+
- 当前 `CoreSettings` 中那类“超长默认 installed_apps + installed_apps_extension + 默认 app=app”模型必须退出正式主链
|
|
966
|
+
- 标准 pip 包目标下,默认清单应收缩到真正最小集合,业务 app 不应再由框架默认注入
|
|
967
|
+
- 默认 middleware 清单也应同步瘦身,不应把身份、页面元信息、analytics、db_connection 等平台能力作为基础包硬编码默认值
|
|
968
|
+
- `INSTALLED_APPS` 的环境覆盖语义也不应再把带顺序的声明抹平成纯名字列表
|
|
969
|
+
- `ROUTE_CONFLICT_POLICY` 的正式默认值应收口到显式失败,而不是继续保留 `warn`
|
|
970
|
+
- `analytics_enabled` 这类环境态衍生开关,应进入单一“配置派生阶段”统一计算,而不是散落在 `CoreSettings` validator 中强制改写
|
|
971
|
+
- `db_min_size` / `db_max_size` 这类连接池默认值,若需按环境派生,也应在统一派生阶段完成,而不是由 `DBMixin` 在 validator 中隐式改写
|
|
972
|
+
|
|
973
|
+
默认 app 清单、env 覆盖后的顺序语义以及运行边界开关,都必须收口到“最小默认值 + 单一配置派生阶段”模型。
|
|
974
|
+
|
|
975
|
+
## 8. 运行时覆盖
|
|
976
|
+
|
|
977
|
+
运行时覆盖只应用于显式白名单字段。
|
|
978
|
+
|
|
979
|
+
要求:
|
|
980
|
+
- 覆盖能力必须可审计
|
|
981
|
+
- 默认只允许非高危配置项动态刷新
|
|
982
|
+
- app 级覆盖仍写入 `settings_center.settings.<app_id>` 命名空间
|
|
983
|
+
|
|
984
|
+
补充要求:
|
|
985
|
+
- 运行时覆盖不应改写“项目目录边界”字段
|
|
986
|
+
- `project_dir`、`cache_dir`、`runtime_dir`、`asset_dir` 不应在进程运行中被动态切换
|
|
987
|
+
- 运行时覆盖若支持嵌套键,必须正式规定路径语义
|
|
988
|
+
- 运行时覆盖不得依赖“先调用 `ensure_full_settings()` 再原地补挂 namespace”这一类进程级补丁式流程
|
|
989
|
+
- CLI、HTTP、worker 应基于同一份完成聚合后的 settings 快照启动
|
|
990
|
+
- 历史 helper `ensure_full_settings()` 不得继续吞掉装配异常后静默返回残缺 settings
|
|
991
|
+
|
|
992
|
+
补充约束:
|
|
993
|
+
|
|
994
|
+
- 运行时覆盖默认不应用于:
|
|
995
|
+
- app 装载清单
|
|
996
|
+
- 路由边界
|
|
997
|
+
- `project_dir/cache_dir/runtime_dir/asset_dir`
|
|
998
|
+
- DB/Redis driver 这类基础能力类型切换
|
|
999
|
+
- 运行时覆盖更适合:
|
|
1000
|
+
- feature flags
|
|
1001
|
+
- 限流/缓存/展示类参数
|
|
1002
|
+
- 已明确白名单的 app 私有行为配置
|
|
1003
|
+
|
|
1004
|
+
补充约束:
|
|
1005
|
+
- `ensure_full_settings()` 这类 helper 不得继续承担正式配置装配主路径
|
|
1006
|
+
|
|
1007
|
+
### 8.0 settings helper 禁止表
|
|
1008
|
+
|
|
1009
|
+
以下行为不得进入正式配置装配主链:
|
|
1010
|
+
|
|
1011
|
+
- 通过“先收集 env、再回写 `os.environ`、再让 `BaseSettings` 回读”完成装配。
|
|
1012
|
+
- 在模块导入时立即创建全局 `settings` 单例。
|
|
1013
|
+
- 在运行期补挂 app namespace,并吞掉装配异常后继续返回对象。
|
|
1014
|
+
- app settings 聚合器把空 `installed_apps` 自动回退到类默认清单。
|
|
1015
|
+
- app settings 模块保留 `get_settings()` 作为默认值主链。
|
|
1016
|
+
- app settings 聚合器反向依赖基础包全局 settings 实例或私有 env helper。
|
|
1017
|
+
|
|
1018
|
+
正式要求:
|
|
1019
|
+
|
|
1020
|
+
- 任何 helper 不得承担正式配置装配主链。
|
|
1021
|
+
- 正式主链必须能独立产出完整 `SettingsSnapshot`。
|
|
1022
|
+
- 非正式 helper 一旦被调用,必须输出清晰诊断,而不是静默维持并行语义。
|
|
1023
|
+
- 历史 helper 不得吞掉结构性配置错误并返回半初始化结果
|
|
1024
|
+
|
|
1025
|
+
迁移落点:
|
|
1026
|
+
|
|
1027
|
+
- env 收集、别名折叠、派生字段生成进入单一 settings compiler
|
|
1028
|
+
- app namespace 组装进入 compiler/assembly 阶段,而不是运行期 patch helper
|
|
1029
|
+
- runtime overrides loader、L2 client、cursor/check interval 进入 context-bound 对象,不再挂在模块级 facade
|
|
1030
|
+
|
|
1031
|
+
## 8.1 嵌套覆盖语义
|
|
1032
|
+
|
|
1033
|
+
运行时覆盖采用如下唯一语义:
|
|
1034
|
+
|
|
1035
|
+
```toml
|
|
1036
|
+
[apps.<app_id>]
|
|
1037
|
+
images.enabled = true
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
或运行时注册:
|
|
1041
|
+
|
|
1042
|
+
- `images.enabled`
|
|
1043
|
+
- `checks.currency.enabled`
|
|
1044
|
+
|
|
1045
|
+
则框架必须真正支持对嵌套对象做路径赋值,而不是仅支持顶层 `setattr()`。
|
|
1046
|
+
|
|
1047
|
+
正式规则:
|
|
1048
|
+
|
|
1049
|
+
- 配置文件里使用结构化 TOML
|
|
1050
|
+
- 环境变量用 `APPID__IMAGES__ENABLED`
|
|
1051
|
+
- 运行时覆盖使用统一路径语义,例如 `images.enabled`
|
|
1052
|
+
|
|
1053
|
+
三者应指向同一命名空间对象结构。
|
|
1054
|
+
|
|
1055
|
+
运行时覆盖对 dotted path 的声明能力与实际赋值能力必须一致,overrides/L2 也必须收口到 context-bound 隔离模型。
|
|
1056
|
+
|
|
1057
|
+
补充要求:
|
|
1058
|
+
|
|
1059
|
+
- 只有在正式实现嵌套路径赋值语义后,才允许注册 dotted key
|
|
1060
|
+
- overrides loader、L2 client、version cursor、check interval 都应进入 context-bound facade,而不是继续挂在模块级全局变量上
|
|
1061
|
+
|
|
1062
|
+
## 8.2 middleware 相关 settings 收口边界
|
|
1063
|
+
|
|
1064
|
+
middleware 相关 settings 仍带有一批历史字段折叠与派生逻辑,重构时需要显式收口,而不是让它们继续散落在 mixin/validator 中。
|
|
1065
|
+
|
|
1066
|
+
收口范围:
|
|
1067
|
+
|
|
1068
|
+
- `CorsMixin` 仍支持从历史环境变量 `ALLOWED_ORIGINS` 注入 `allow_origins`
|
|
1069
|
+
- `I18nMixin` 仍默认:
|
|
1070
|
+
- `i18n_enabled = true`
|
|
1071
|
+
- `i18n_url_prefix = true`
|
|
1072
|
+
- 自动做语言代码规范化与别名折叠
|
|
1073
|
+
- 自动从 `currency_default_languages` 倒排生成 `language_default_currency`
|
|
1074
|
+
- `SettingsL2RefreshMixin` 仍默认:
|
|
1075
|
+
- `settings_l2_check_interval = 10.0`
|
|
1076
|
+
- 且强制最小值为 `1.0`
|
|
1077
|
+
- 多个 middleware mixin 仍默认启用,或内置默认规则/默认清单,例如:
|
|
1078
|
+
- `TrailingSlashMixin`
|
|
1079
|
+
- `DatabaseRedirectMixin`
|
|
1080
|
+
- `SecurityCSRFMixin`
|
|
1081
|
+
- `DenyAPIMixin`
|
|
1082
|
+
- `CmsAuthGuardMixin`
|
|
1083
|
+
- `RedirectMiddlewareMixin` 不再注入默认语言别名规则,需显式配置 `redirect_rules_raw`
|
|
1084
|
+
- HTML 缓存策略也属于 middleware settings 合同的一部分,不能继续留在“源站随手写 header”或“CDN 面板临时补规则”的灰区:
|
|
1085
|
+
- 用户态 HTML 必须显式进入私有缓存路径
|
|
1086
|
+
- 匿名 HTML 必须显式区分浏览器缓存与 CDN 边缘缓存
|
|
1087
|
+
- 用户态识别面若依赖 cookie / `Authorization` / 已编译 settings,可被直接建模为正式配置字段或 normalize 规则,不得继续依赖前端首帧纠偏
|
|
1088
|
+
- `BASE_URL` / `API_BASE_URL` / `IMAGE_BASE_URL` / `worker_storage_path` 的历史字段回填,不应继续分散在:
|
|
1089
|
+
- settings validator
|
|
1090
|
+
- app settings bootstrap helper
|
|
1091
|
+
|
|
1092
|
+
最小默认基线:
|
|
1093
|
+
|
|
1094
|
+
- base install 默认不注入业务 app
|
|
1095
|
+
- base install 默认不注入依赖 DB、页面元信息、身份、analytics、内容 guard 的 middleware
|
|
1096
|
+
- 若需要提供官方默认链,只能以显式 preset / sample project / init-project 模板提供
|
|
1097
|
+
- 任何“默认启用”的 middleware 都必须属于真正最小框架边界,并能在 disabled 场景下显式表达状态
|
|
1098
|
+
|
|
1099
|
+
结论:
|
|
1100
|
+
|
|
1101
|
+
- middleware 配置当前不只是“字段定义”,还混入了历史别名桥接、运行期派生值和强默认值
|
|
1102
|
+
- 某些“便利字段”甚至不是在 settings 聚合阶段确定,而是在 bootstrap 时继续补写
|
|
1103
|
+
- 这些历史字段折叠逻辑必须进入单一配置聚合器,而不是继续分散在 middleware mixin 内部
|
|
1104
|
+
|
|
1105
|
+
要求:
|
|
1106
|
+
|
|
1107
|
+
- 新文档明确区分:
|
|
1108
|
+
- 正式稳定字段
|
|
1109
|
+
- 历史别名
|
|
1110
|
+
- 运行时派生字段
|
|
1111
|
+
- 默认启用的 middleware、默认 redirect 规则、默认保护/豁免清单,也要单独归类为显式 preset,而不是隐式散落在各 mixin 默认值里
|
|
1112
|
+
- 历史别名若需要被识别,也只能在单一归一化阶段被一次性折叠,不得进入新正式字段模型
|
|
1113
|
+
- 运行时派生字段应由统一 settings 聚合层生成,而不是在 middleware 自己的配置类里各自派生
|
|
1114
|
+
- `BASE_URL -> API_BASE_URL -> IMAGE_BASE_URL`、`UPLOAD_DIR -> worker_storage_path` 这类历史字段回填,也应只在单一 normalization 阶段完成
|
|
1115
|
+
- 对 HTML 缓存控制,正式稳定口径固定为:
|
|
1116
|
+
- 用户态 HTML:`Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0, s-maxage=0`
|
|
1117
|
+
- 用户态 HTML:显式发送 `Cloudflare-CDN-Cache-Control: no-store`
|
|
1118
|
+
- 用户态 HTML:显式发送 `Vary: Cookie, Authorization`
|
|
1119
|
+
- 匿名 HTML:浏览器侧使用 `Cache-Control: public, max-age=0, must-revalidate`
|
|
1120
|
+
- 匿名 HTML:CDN 侧使用 `Cloudflare-CDN-Cache-Control: public, max-age=<ttl_seconds>`,TTL 唯一来自 `apps.pz_foundation.cache_control.policies["http.public_html_cdn"].ttl_seconds`
|
|
1121
|
+
- 健康检查与 no-store 路径:统一 `no-store`
|
|
1122
|
+
|
|
1123
|
+
特别约束:
|
|
1124
|
+
|
|
1125
|
+
- `ROUTE_CONFLICT_POLICY`、middleware 装配开关、i18n 前缀策略这类运行边界字段,应被视为核心配置契约的一部分
|
|
1126
|
+
- 不能继续依赖“middleware 初始化时自动猜 settings 字段名”来弥补配置模型不完整
|
|
1127
|
+
- middleware 参数映射若要进入稳定契约,必须来自:
|
|
1128
|
+
- 显式 `ParamsModel`
|
|
1129
|
+
- 或显式字段映射表
|
|
1130
|
+
不能继续依赖:
|
|
1131
|
+
- `__init__` 反射
|
|
1132
|
+
- suffix / normalized match
|
|
1133
|
+
- alias map
|
|
1134
|
+
- manager 内部硬编码修正
|
|
1135
|
+
|
|
1136
|
+
## 8.3 配置派生字段的唯一生成点
|
|
1137
|
+
|
|
1138
|
+
为了避免 bootstrap、middleware、CLI helper 再次派生配置,所有派生字段必须只有一个生成点。
|
|
1139
|
+
|
|
1140
|
+
正式要求:
|
|
1141
|
+
|
|
1142
|
+
- 派生字段统一由 settings compiler 生成
|
|
1143
|
+
- 派生结果必须直接进入 `SettingsSnapshot`
|
|
1144
|
+
- 后续阶段只允许消费派生结果,不允许再次重算
|
|
1145
|
+
|
|
1146
|
+
适用范围包括:
|
|
1147
|
+
|
|
1148
|
+
- `API_BASE_URL`
|
|
1149
|
+
- `IMAGE_BASE_URL`
|
|
1150
|
+
- `worker_storage_path`
|
|
1151
|
+
- middleware preset 派生值
|
|
1152
|
+
- i18n 默认语言/货币映射派生值
|
|
1153
|
+
- analytics/feature preset 派生值
|
|
1154
|
+
|
|
1155
|
+
禁止:
|
|
1156
|
+
|
|
1157
|
+
- bootstrap 再补派生字段
|
|
1158
|
+
- middleware 初始化时临时重算派生字段
|
|
1159
|
+
- worker/client SDK 按请求临时回退根级历史字段重算派生值
|
|
1160
|
+
|
|
1161
|
+
## 9. 禁止事项
|
|
1162
|
+
|
|
1163
|
+
不允许:
|
|
1164
|
+
- app 自己直接 `os.environ.get(...)`
|
|
1165
|
+
- 根 `.env` 承载整个系统的全部默认配置
|
|
1166
|
+
- 业务 app 依赖根 settings 中某个历史扁平字段是否存在
|
|
1167
|
+
- app 通过 import-time `BaseSettings()` 抢先读取环境并固化为全局单例
|
|
1168
|
+
- 用“从对象自动推断哪些字段可 runtime override”替代显式稳定白名单
|
|
1169
|
+
- settings loader 默认把 `ROOT_DIR/.env` 注入到所有运行模式
|
|
1170
|
+
- app 配置目录发现同时混用 `PZ_PROJECT_DIR`、`cwd`、`ROOT_DIR` 而没有明确单一 project_dir
|
|
1171
|
+
- settings 构建先把合并后的 env snapshot 回写 `os.environ`,再让 `BaseSettings` 回读
|
|
1172
|
+
- middleware 在构造时再回退读取全局 settings 单例作为正式配置来源
|
|
1173
|
+
- environment/profile 候选名由 loader 内部隐式展开,而不是由正式配置契约定义
|
|
1174
|
+
- bootstrap helper 在 settings namespace attach 之后继续补写 `API_BASE_URL`、`IMAGE_BASE_URL`、`worker_storage_path`
|
|
1175
|
+
- 运行时覆盖注册表声称支持 `images.enabled` 这类 dotted key,但实际仍只做顶层 `setattr()`
|
|
1176
|
+
- 通过模块级 `_overrides_loader`、`_l2_client`、`_last_version`、`_last_check_at` 维护跨项目共享的 overrides/L2 状态
|
|
1177
|
+
- 在 settings 装配完成后,再由 bootstrap/lifespan 隐式补写正式稳定字段
|