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,499 @@
|
|
|
1
|
+
# 数据库与可选基础设施规范
|
|
2
|
+
|
|
3
|
+
## 1. 目标
|
|
4
|
+
|
|
5
|
+
数据库、Redis、观测能力必须成为可选基础设施,而不是 `pz` 最小运行前提。
|
|
6
|
+
|
|
7
|
+
## 2. base 运行要求
|
|
8
|
+
|
|
9
|
+
`pz` base 安装必须支持:
|
|
10
|
+
- 无数据库
|
|
11
|
+
- 无 Redis
|
|
12
|
+
- 无 Prometheus
|
|
13
|
+
- 无 OpenTelemetry
|
|
14
|
+
|
|
15
|
+
最小应用在这种情况下仍应可以:
|
|
16
|
+
- 装载 app
|
|
17
|
+
- 注册路由
|
|
18
|
+
- 使用模板/静态/语言资源
|
|
19
|
+
- 正常启动与关闭
|
|
20
|
+
|
|
21
|
+
约束:
|
|
22
|
+
|
|
23
|
+
- “最小应用可运行”不等于“所有官方 app 都可运行”
|
|
24
|
+
- 凡依赖 DB/Redis/metrics/OTel 的能力,都必须通过显式 capability 建模
|
|
25
|
+
|
|
26
|
+
## 3. 数据库支持范围
|
|
27
|
+
|
|
28
|
+
正式数据库支持:
|
|
29
|
+
- SQLite
|
|
30
|
+
- MySQL
|
|
31
|
+
- PostgreSQL
|
|
32
|
+
|
|
33
|
+
约束:
|
|
34
|
+
- SQLite 必须是一级支持目标,不是临时开发兜底
|
|
35
|
+
- MySQL 与 PostgreSQL 通过独立 extras 装驱动
|
|
36
|
+
|
|
37
|
+
## 4. 依赖分层
|
|
38
|
+
|
|
39
|
+
- `pz[db]`
|
|
40
|
+
- ORM、迁移基础能力
|
|
41
|
+
- `pz[db-postgres]`
|
|
42
|
+
- PostgreSQL 驱动
|
|
43
|
+
- owning infra package extra, e.g. `[db-mysql]`
|
|
44
|
+
- MySQL 驱动
|
|
45
|
+
- owning infra package extra, e.g. `[redis]`
|
|
46
|
+
- Redis 客户端
|
|
47
|
+
|
|
48
|
+
要求:
|
|
49
|
+
- 安装 `pz` core 本体时不应强制拉取全部数据库驱动
|
|
50
|
+
|
|
51
|
+
## 5. 启用策略
|
|
52
|
+
|
|
53
|
+
数据库与 Redis 应显式启用。
|
|
54
|
+
|
|
55
|
+
示例:
|
|
56
|
+
|
|
57
|
+
```toml
|
|
58
|
+
[apps.<infra_owner>.database]
|
|
59
|
+
enabled = true
|
|
60
|
+
driver = "sqlite"
|
|
61
|
+
database = "app.db"
|
|
62
|
+
|
|
63
|
+
[apps.<infra_owner>.cache]
|
|
64
|
+
enabled = false
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
行为要求:
|
|
68
|
+
- `enabled = false` 时不初始化对应客户端
|
|
69
|
+
- 未安装对应 extra 且配置启用时,启动期给出明确错误
|
|
70
|
+
|
|
71
|
+
补充要求:
|
|
72
|
+
- `database.enabled = false` 时,不应再要求提供默认 `db_host/db_name/db_user`
|
|
73
|
+
- `redis.enabled = false` 时,不应再默认回落到 `127.0.0.1:6379`
|
|
74
|
+
|
|
75
|
+
settings 模型必须按 `database.enabled` 与 SQLite 一级支持目标收口,不得默认假设数据库存在。
|
|
76
|
+
|
|
77
|
+
## 6. 生命周期行为
|
|
78
|
+
|
|
79
|
+
### 6.1 数据库
|
|
80
|
+
|
|
81
|
+
- 配置启用时初始化
|
|
82
|
+
- 未配置或禁用时跳过
|
|
83
|
+
- readiness 仅在启用数据库后才探测数据库状态
|
|
84
|
+
- 不得在全局 `setup_infra()` 中默认强制初始化 DB 并把失败视为所有应用的启动失败
|
|
85
|
+
- `create_app()`、Web `startup()`、`setup_infra()`、`/ready` 都不得执行 `generate_schemas`、自动建表、迁移修补或 schema auto-heal
|
|
86
|
+
|
|
87
|
+
启动链必须拆出“数据库初始化”和“数据库连通性前提”,按 `database.enabled` 驱动的可选模型收口。
|
|
88
|
+
|
|
89
|
+
补充要求:
|
|
90
|
+
|
|
91
|
+
- 将“初始化数据库连接池”和“执行 schema/migration 操作”拆成两个明确阶段
|
|
92
|
+
- Web 启动不应隐式承担 migration/apply-schema 职责
|
|
93
|
+
- schema 创建、迁移执行、迁移文件修补只能通过显式 `pz db ...` 或显式 repair/check 流程触发,不能作为“启动成功前顺手完成”的副作用
|
|
94
|
+
|
|
95
|
+
### 6.2 Redis
|
|
96
|
+
|
|
97
|
+
- 配置启用时初始化
|
|
98
|
+
- 未配置或禁用时跳过
|
|
99
|
+
- app 代码若依赖 Redis,必须显式声明并在运行时优雅失败
|
|
100
|
+
- 不得在 `create_redis()`、dependency helper、middleware 构造阶段默认回落 `127.0.0.1:6379`
|
|
101
|
+
- 中间件、限流器、task runtime 若依赖 Redis,必须先消费统一的 `redis.enabled` 判定
|
|
102
|
+
|
|
103
|
+
### 6.3 Task dispatch / Worker 类基础设施
|
|
104
|
+
|
|
105
|
+
task dispatch / worker owner 这类平台级 app 与 Redis 的关系应明确建模:
|
|
106
|
+
|
|
107
|
+
- 若 task dispatch / worker owner 需要 Redis,则必须显式声明
|
|
108
|
+
- Redis 未启用时,应明确报错或禁用该 app 的相关入口
|
|
109
|
+
- 不应通过全局单例隐式探测后“半工作”
|
|
110
|
+
- task dispatch / worker owner 的 readiness surface 不能只返回固定 `ok`,必须反映其自身关键依赖是否可用
|
|
111
|
+
- worker SDK 不应仅靠轮询 Web 进程的 owner 私有 readiness URL 来推断整个任务系统已可用
|
|
112
|
+
|
|
113
|
+
补充约束:
|
|
114
|
+
- task dispatch / worker owner 的 delay sweeper / reclaimer / worker cleanup 后台循环,不应在运行过程中反复 `ensure_full_settings(global_settings)`
|
|
115
|
+
- worker register / heartbeat / pull 协议里返回给客户端的 server 参数,应在入口期由当前 settings snapshot 固定,而不是每次请求从全局 settings 现取
|
|
116
|
+
|
|
117
|
+
### 6.4 InfraSettings 快照约束
|
|
118
|
+
|
|
119
|
+
正式运行时必须构造唯一一份 `InfraSettings` / `InfraContext` typed snapshot:
|
|
120
|
+
|
|
121
|
+
- 这些对象必须带 `enabled` 语义
|
|
122
|
+
- 不能默认把 DB/Redis 视为必填对象
|
|
123
|
+
- 不能在 disabled 场景下仍构造出“看似可用”的默认 host/port 配置
|
|
124
|
+
- Web、worker、CLI、health/readiness 都只允许消费这同一份 typed snapshot,而不是各自重新从全局 settings 推导
|
|
125
|
+
|
|
126
|
+
typed snapshot 必须真正表达 `enabled/disabled/ready/unavailable`,不能只是“再包装一层全局 settings”。
|
|
127
|
+
|
|
128
|
+
补充要求:
|
|
129
|
+
|
|
130
|
+
- `InfraSettings` / `InfraContext` 成为基础设施能力的唯一真相源
|
|
131
|
+
- DB、Redis、mail、metrics、overrides/L2 都必须先编译进 typed snapshot,再进入后续 capability 装配
|
|
132
|
+
- `pz` 基础层只拥有 typed snapshot 与编译协议,不直接拥有 concrete database/redis/mail/storage 作者面
|
|
133
|
+
- concrete 配置真相源必须归属正式 capability owner app;官方或业务实现通过自己的 settings 持有 `database/cache/mail/storage/health/observability` 等配置,再通过 `infra.provider` 编译进 `InfraContext`
|
|
134
|
+
- 基础设施状态统一收敛为显式枚举:
|
|
135
|
+
- `disabled`
|
|
136
|
+
- `enabled`
|
|
137
|
+
- `ready`
|
|
138
|
+
- `unavailable`
|
|
139
|
+
- 不再允许某些入口使用 typed snapshot,另一些入口直接读取全局 settings 或默认单例
|
|
140
|
+
|
|
141
|
+
### 6.5 readiness 聚合器约束
|
|
142
|
+
|
|
143
|
+
readiness 聚合器必须只探测显式启用的组件:
|
|
144
|
+
|
|
145
|
+
- `database.enabled = false` 时,不调用 DB 初始化或连接校验
|
|
146
|
+
- `redis.enabled = false` 时,不创建 Redis client,不探测 Redis
|
|
147
|
+
- 未启用的依赖统一返回 `disabled`
|
|
148
|
+
- 已声明但属于 disabled capability 的 provider,不得把状态抬升成 `enabled` 或 `unavailable`
|
|
149
|
+
|
|
150
|
+
不允许:
|
|
151
|
+
|
|
152
|
+
- 为了生成 `/ready` 响应而隐式初始化 DB/Redis
|
|
153
|
+
- 把“未配置”解释成“检查本机默认实例”
|
|
154
|
+
|
|
155
|
+
现有 `/ready` 语义必须收口为“只探测显式启用组件”,并把 `disabled` 作为正式状态语义。
|
|
156
|
+
|
|
157
|
+
## 7. app 编码约束
|
|
158
|
+
|
|
159
|
+
app 不得:
|
|
160
|
+
- 在 import 阶段无条件初始化 DB
|
|
161
|
+
- 在 import 阶段无条件初始化 Redis
|
|
162
|
+
- 假设 Redis 一定存在
|
|
163
|
+
- 假设数据库一定存在
|
|
164
|
+
- 将测试专用降级路径作为正式运行时契约的一部分
|
|
165
|
+
|
|
166
|
+
app 应:
|
|
167
|
+
- 通过依赖注入或门面获取 DB / Redis 能力
|
|
168
|
+
- 在缺失可选基础设施时有明确错误或降级行为
|
|
169
|
+
|
|
170
|
+
约束:
|
|
171
|
+
- 像 `PZ_TEST_DISABLE_REDIS` 这类测试开关,只能是测试辅助机制,不能成为生产运行模型的一部分
|
|
172
|
+
|
|
173
|
+
补充约束:
|
|
174
|
+
- cache/L2/version/lock 一类基础能力若依赖 Redis,也必须先经过统一 `redis.enabled` 判定
|
|
175
|
+
- 不应通过“拿不到 Redis 就吞异常并假装成功”把一致性问题静默隐藏
|
|
176
|
+
|
|
177
|
+
## 8. 健康检查约定
|
|
178
|
+
|
|
179
|
+
健康检查应区分:
|
|
180
|
+
- liveness
|
|
181
|
+
- readiness
|
|
182
|
+
|
|
183
|
+
readiness 规则:
|
|
184
|
+
- 只聚合当前已启用的基础设施探针
|
|
185
|
+
- 未启用的后端不计为失败项
|
|
186
|
+
|
|
187
|
+
约束:
|
|
188
|
+
- 未启用 DB/Redis 时,对应 readiness 项统一标注 `disabled`
|
|
189
|
+
- 不得标成 `error`
|
|
190
|
+
- liveness 必须保持纯轻量,不得触发重型 DB/Redis 初始化
|
|
191
|
+
|
|
192
|
+
补充要求:
|
|
193
|
+
|
|
194
|
+
- `liveness` 与 `readiness` 必须是两条明确分离的 surface
|
|
195
|
+
- `readiness` 结果必须来自显式 capability 状态聚合,而不是在 router 内部 best-effort import 某个旧聚合器
|
|
196
|
+
- 当 readiness 聚合器不可用、某项 probe 未实现或 capability 未声明时,不得默认回退成固定成功的 `/ready`
|
|
197
|
+
- dev/debug/extensions 之类诊断 surface 不得混入 health 默认路由
|
|
198
|
+
- readiness probe 不得因为“顺便验证数据库可用”而触发 schema 创建、自动建表、迁移修补或 provider init 副作用
|
|
199
|
+
- 周期性数据库 readiness probe 可以由数据库 owner 后台任务提供;如果执行 SQL,必须证明使用 autocommit-safe 连接,且不得进入请求路径或 liveness 路由
|
|
200
|
+
- 数据库探活不得留下 `idle in transaction`;无法证明不引入事务时必须拒绝探活,而不是用隐式事务和 rollback 作为正式运行模型
|
|
201
|
+
- 数据库连接池容量耗尽、获取连接超时一类信号不得被当成断连自动重建信号,应作为性能或连接泄漏风险暴露
|
|
202
|
+
|
|
203
|
+
正式失败语义:
|
|
204
|
+
|
|
205
|
+
- 缺 capability 定义
|
|
206
|
+
- `disabled` 或显式配置错误
|
|
207
|
+
- capability 已启用但 probe 缺失
|
|
208
|
+
- 配置/装配错误
|
|
209
|
+
- capability 已启用但初始化失败
|
|
210
|
+
- `unavailable`
|
|
211
|
+
|
|
212
|
+
不得采用:
|
|
213
|
+
|
|
214
|
+
- import 失败就返回固定 `{"status": "ready"}`
|
|
215
|
+
- 为了让 worker 继续跑而把 readiness 永久做成宽松成功
|
|
216
|
+
|
|
217
|
+
## 8.1 指标与追踪的工程边界
|
|
218
|
+
|
|
219
|
+
观测能力除了“可选启用”,还需要遵守工程上的低侵入原则。
|
|
220
|
+
|
|
221
|
+
要求:
|
|
222
|
+
|
|
223
|
+
- metrics/tracing 关闭时,业务热路径仍可正常运行
|
|
224
|
+
- metrics/tracing 开启时,不应把高基数标签变成默认行为
|
|
225
|
+
- exporter 不可用时,不应拖垮主业务请求路径
|
|
226
|
+
|
|
227
|
+
要求:
|
|
228
|
+
|
|
229
|
+
- metrics 名称、标签、单位形成正式规范
|
|
230
|
+
- request path、user id、query text 这类高基数或敏感信息不得直接作为默认 label
|
|
231
|
+
- tracing/metrics 的 flush/export 重试策略必须显式,而不是隐式阻塞请求关闭流程
|
|
232
|
+
|
|
233
|
+
## 9. 迁移约定
|
|
234
|
+
|
|
235
|
+
迁移仅在数据库启用时有意义。
|
|
236
|
+
|
|
237
|
+
要求:
|
|
238
|
+
- `pz db ...` 相关 CLI 必须在数据库未启用时给出明确诊断
|
|
239
|
+
- SQLite、MySQL、PostgreSQL 共用同一迁移归属规则:`migrations/<app_id>/`
|
|
240
|
+
|
|
241
|
+
补充要求:
|
|
242
|
+
- 有 ORM models 的 app,必须显式提供:
|
|
243
|
+
- `migrations/`
|
|
244
|
+
- `migrations/<app_id>/`
|
|
245
|
+
- migration owner 应优先由 app registry / 项目配置决定
|
|
246
|
+
- 不应继续依赖:
|
|
247
|
+
- suffix match
|
|
248
|
+
- 历史 `app` 路径猜测
|
|
249
|
+
- 临时 `PYTHONPATH` 注入
|
|
250
|
+
这类启发式来决定迁移归属
|
|
251
|
+
- Aerich/Tortoise 配置应按当前 project context 惰性生成,不能在模块导入时固化全局 `TORTOISE_ORM`
|
|
252
|
+
- ORM app 列表应优先来自正式 app registry,而不是在 DB config 内部再次拼接 `installed_apps + installed_apps_extension`
|
|
253
|
+
- 宿主业务 app 可以保留正式迁移链;`apps/.sources` 下的官方/共享源码包只保留数据库 init,不进入 Aerich 历史迁移链
|
|
254
|
+
- `pz db migrate` 对共享源码包只能执行幂等 schema 初始化;真正传给迁移执行器的 owners 应只包含非 `.sources` 的业务包
|
|
255
|
+
|
|
256
|
+
补充约束:
|
|
257
|
+
|
|
258
|
+
- `db` CLI 的临时配置文件、迁移工作目录、日志输出目录都必须来自当前 `ProjectContext`
|
|
259
|
+
- 不得写入 repo-root 或包内 merged 目录下的 `aerich.ini`
|
|
260
|
+
- 不得再通过 `_repo_root()`、`_merged_base_dir()`、`PYTHONPATH` 注入来推导迁移工作空间
|
|
261
|
+
- `db` CLI 不得在正式迁移主路径里自动执行“best-effort 修补旧 migration 文件格式”
|
|
262
|
+
|
|
263
|
+
ORM/迁移配置必须复用入口期 app registry 真相源,`aerich` 相关配置也不得再带 import-time 固化快照。
|
|
264
|
+
|
|
265
|
+
## 9.1 concrete owner 约束
|
|
266
|
+
|
|
267
|
+
对于 database、cache、mail、storage、health、metrics、tracing 这类 capability,需要同时区分两层 owner:
|
|
268
|
+
|
|
269
|
+
- `pz`
|
|
270
|
+
- 只拥有 typed contract、编译协议与 capability 状态语义
|
|
271
|
+
- capability owner app
|
|
272
|
+
- 拥有 concrete settings namespace、默认值、provider/client/bootstrap 实现
|
|
273
|
+
|
|
274
|
+
正式要求:
|
|
275
|
+
|
|
276
|
+
- 不允许 `pz` 顶层 project settings 与 owner app namespace 同时长期承载同一套 concrete infra 配置
|
|
277
|
+
- 若 `pz` 已退回协议层,则 concrete 作者面必须统一下放到 owner app
|
|
278
|
+
- owner app 的正式字段必须通过 `infra.provider` 编译进 `InfraContext`
|
|
279
|
+
|
|
280
|
+
## 10. 依赖分发目标
|
|
281
|
+
|
|
282
|
+
依赖分发目标:
|
|
283
|
+
|
|
284
|
+
- base 不强装全部数据库与 Redis 依赖
|
|
285
|
+
- `aerich`、DB 驱动、Redis 客户端按 extra 分层
|
|
286
|
+
- SQLite 在 base 或 `db` extra 中即可使用
|
|
287
|
+
|
|
288
|
+
## 11. Redis 客户端生命周期补充约束
|
|
289
|
+
|
|
290
|
+
Redis 的“可选”不仅是 settings 开关,也包括客户端创建与缓存语义。
|
|
291
|
+
|
|
292
|
+
要求:
|
|
293
|
+
|
|
294
|
+
- `redis.enabled = false` 时,不应创建任何默认 Redis client
|
|
295
|
+
- Redis client cache 不应仅按 host/port 值缓存,还应受当前 project context / lifecycle 管理
|
|
296
|
+
- 不能继续让 `_DEFAULT_CFG`、模块级 `redis_manager`、`atexit` 清理构成正式运行模型
|
|
297
|
+
|
|
298
|
+
Redis 必须出清“默认存在”的旧心智,client lifecycle 也必须按 owner/reset/project scope 收口。
|
|
299
|
+
|
|
300
|
+
## 12. metrics / health 可选能力补充约束
|
|
301
|
+
|
|
302
|
+
Prometheus、health surface 也必须遵守显式启用原则。
|
|
303
|
+
|
|
304
|
+
要求:
|
|
305
|
+
|
|
306
|
+
- `metrics_enabled = false` 时,不应导入后就把默认 metrics registry 当成正式全局事实
|
|
307
|
+
- `/metrics` 是否挂载、挂载在哪里、是否公开,必须显式配置
|
|
308
|
+
- dev/debug route 不应混入 health 默认 surface
|
|
309
|
+
- `pz` 基础层只应预留 metrics/exporter/provider 边界,不应把 Prometheus server、Grafana、Alertmanager、scrape jobs 变成框架内核职责
|
|
310
|
+
- 文件日志输出是否启用、输出到哪里,也必须显式配置;不得默认落到进程当前工作目录
|
|
311
|
+
- Bot/告警 handler 若存在,必须具备显式 enabled 开关、背压/丢弃策略与 shutdown 语义,不能只靠类级 `ThreadPoolExecutor` 常驻进程
|
|
312
|
+
|
|
313
|
+
metrics / health / dev surface 都必须收口到统一 capability 边界,并按显式启用模型出清。
|
|
314
|
+
|
|
315
|
+
## 12.1 Prometheus 集成的正式边界
|
|
316
|
+
|
|
317
|
+
针对“整个项目统一接 Prometheus”这个目标,`pz` 应当预留空位,但空位必须收口在框架边界内。
|
|
318
|
+
|
|
319
|
+
`pz` 基础层应负责:
|
|
320
|
+
|
|
321
|
+
- 提供统一 metrics facade / provider interface
|
|
322
|
+
- web app、worker、平台 app、外部 app 都通过统一接口注册指标
|
|
323
|
+
- 根据 settings 显式决定是否挂载 exporter route
|
|
324
|
+
- 提供 exporter 路径、namespace、labels、暴露策略等正式配置入口
|
|
325
|
+
|
|
326
|
+
`pz` 基础层不应负责:
|
|
327
|
+
|
|
328
|
+
- Prometheus server 本身部署
|
|
329
|
+
- Prometheus scrape jobs 编排
|
|
330
|
+
- Alertmanager 规则
|
|
331
|
+
- Grafana dashboard
|
|
332
|
+
- 监控平台拓扑、remote write、存储保留策略
|
|
333
|
+
|
|
334
|
+
也就是说:
|
|
335
|
+
|
|
336
|
+
- `pz` 需要“集成边界”
|
|
337
|
+
- 但不需要“内置完整监控平台”
|
|
338
|
+
|
|
339
|
+
## 12.2 metrics 正式配置模型
|
|
340
|
+
|
|
341
|
+
正式配置段如下:
|
|
342
|
+
|
|
343
|
+
```toml
|
|
344
|
+
[metrics]
|
|
345
|
+
enabled = true
|
|
346
|
+
path = "/metrics"
|
|
347
|
+
namespace = "pz"
|
|
348
|
+
include_process_metrics = true
|
|
349
|
+
bind_internal_only = true
|
|
350
|
+
protected = false
|
|
351
|
+
|
|
352
|
+
[metrics.labels]
|
|
353
|
+
project = "manga-translate"
|
|
354
|
+
service = "web"
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
补充约束:
|
|
358
|
+
|
|
359
|
+
- `metrics.enabled` 是唯一正式启用开关
|
|
360
|
+
- Prometheus 是当前唯一正式 exporter,不提供第二套 `metrics.exporter` 配置
|
|
361
|
+
- `metrics.path` 不应硬编码为根路径 `/metrics`
|
|
362
|
+
- `namespace`、常驻 labels、process/runtime metrics 是否启用,都应显式配置
|
|
363
|
+
- `/metrics` 是否内网暴露、是否鉴权,必须进入正式配置或部署契约
|
|
364
|
+
|
|
365
|
+
## 12.3 Core 预留的能力点
|
|
366
|
+
|
|
367
|
+
为支持整项目统一监控,`pz` 基础层必须明确预留以下能力点:
|
|
368
|
+
|
|
369
|
+
### 12.3.1 指标门面
|
|
370
|
+
|
|
371
|
+
- 统一的 counter / gauge / histogram 注册入口
|
|
372
|
+
- 统一的 label 规范
|
|
373
|
+
- 统一的 disabled / noop 语义
|
|
374
|
+
|
|
375
|
+
要求:
|
|
376
|
+
|
|
377
|
+
- app/worker 不应直接依赖模块级全局 `metrics`
|
|
378
|
+
- 业务代码不应直接假设 Prometheus 默认 registry 就是唯一真相源
|
|
379
|
+
|
|
380
|
+
### 12.3.2 exporter 挂载边界
|
|
381
|
+
|
|
382
|
+
- exporter route 的挂载必须走显式 capability
|
|
383
|
+
- 路径、prefix、鉴权、可见性必须可配置
|
|
384
|
+
- health、metrics、debug surface 不应共用同一个“顺手挂载”的隐式逻辑
|
|
385
|
+
|
|
386
|
+
### 12.3.3 app / worker 扩展注册点
|
|
387
|
+
|
|
388
|
+
- 外部 app 通过统一 facade 注册自己的指标
|
|
389
|
+
- worker/background jobs 通过统一 facade 注册自己的 collector
|
|
390
|
+
- 平台级 app 若暴露观测能力,应通过 facade/provider 暴露,而不是直接 import 全局 registry
|
|
391
|
+
|
|
392
|
+
### 12.3.4 生命周期与隔离
|
|
393
|
+
|
|
394
|
+
- metrics provider 必须支持 reset / shutdown / project scope
|
|
395
|
+
- 多次 `create_app()`、多项目上下文、并行测试之间不得共享脏状态
|
|
396
|
+
- scoped registry 只允许由 context-bound provider 决定,不得由 import-time 单例决定
|
|
397
|
+
|
|
398
|
+
## 12.4 Prometheus 集成中的禁止事项
|
|
399
|
+
|
|
400
|
+
不应继续采用:
|
|
401
|
+
|
|
402
|
+
- 模块导入即创建正式全局 `MetricsRegistry`
|
|
403
|
+
- 直接绑定 Prometheus 默认 registry 作为跨项目共享事实
|
|
404
|
+
- `metrics_enabled = true` 时就把 `/metrics` 固定挂到根路径
|
|
405
|
+
- 把 `/metrics` 默认视为公开接口
|
|
406
|
+
- 让 app 直接 import `pz.infra.observability.metrics.metrics` 作为稳定公共契约
|
|
407
|
+
- 把项目级 scrape 目标、抓取频率、监控平台部署配置写死在 `pz` 包内
|
|
408
|
+
|
|
409
|
+
## 12.5 对标准 pip 包化的意义
|
|
410
|
+
|
|
411
|
+
Prometheus 边界如果不提前收口,会直接影响 `pz` 的 pip 包化质量:
|
|
412
|
+
|
|
413
|
+
- base 安装会继续携带过强的 observability 假设
|
|
414
|
+
- 多项目 / 多实例 / 测试环境容易共享同一批全局指标状态
|
|
415
|
+
- `/metrics` 暴露边界会和项目部署边界纠缠在一起
|
|
416
|
+
|
|
417
|
+
因此结论是:
|
|
418
|
+
|
|
419
|
+
- `pz` 必须为 Prometheus 预留正式空位
|
|
420
|
+
- 但这块空位应是“接口与配置边界”
|
|
421
|
+
- 不是“把整套监控平台实现进 core”
|
|
422
|
+
|
|
423
|
+
## 13. `infra` 边界引用
|
|
424
|
+
|
|
425
|
+
`infra` 的正式目录边界以 `01-目录与分层规范.md` 为准;facade / capability 公开面以 `13-正式Facade总表.md` 为准。
|
|
426
|
+
|
|
427
|
+
在本文件中,`infra` 只保留一条约束:
|
|
428
|
+
|
|
429
|
+
- 与 DB、Redis、mail、metrics、storage 相关的基础设施语义,必须通过最小基础设施边界进入运行图,不得通过 `pz.infra.*` 私有实现路径扩散为公共依赖面
|
|
430
|
+
|
|
431
|
+
## 14. settings overrides / L2 依赖补充约束
|
|
432
|
+
|
|
433
|
+
settings overrides / L2 不应被重新定义为 core/infra 基础能力;它们属于 settings runtime owner 或替代平台 app 提供的配置能力,但其底层仍可能依赖 DB/Redis。
|
|
434
|
+
|
|
435
|
+
要求:
|
|
436
|
+
|
|
437
|
+
- DB overrides loader、L2 client 不应在基础包启动时默认写入进程级全局 facade
|
|
438
|
+
- 没有 provider / 没有 Redis / 没有 settings runtime owner 时,语义必须显式为 `disabled` 或 `unavailable`
|
|
439
|
+
- 不应通过 deferred lookup + 吞异常 + 返回 `{}` 来把配置边界错误静默隐藏
|
|
440
|
+
|
|
441
|
+
overrides/L2 必须出清“默认开启的全局机制”心智,并按 `config` 平台 capability 和 project scope 收口。
|
|
442
|
+
|
|
443
|
+
补充要求:
|
|
444
|
+
|
|
445
|
+
- overrides/L2 不并入 `InfraContext` 作为 core/infra capability
|
|
446
|
+
- overrides/L2 应通过 `config` 平台 capability 或对应 facade 暴露
|
|
447
|
+
- `overrides.enabled = false` 时,不注册 loader,不创建 L2 client,不暴露 reload 入口
|
|
448
|
+
- provider 缺失、Redis 缺失、版本游标缺失时,必须分别落入 `disabled` 或 `unavailable`,不再统一吞成 `{}` 或静默 no-op
|
|
449
|
+
|
|
450
|
+
## 15. 基础设施 adapter 边界
|
|
451
|
+
|
|
452
|
+
数据库、Redis、metrics 相关实现都必须经过统一基础设施边界,不得在 adapter 层重新定义策略;overrides/L2 的底层依赖只通过其所消费的 DB/Redis/config 平台能力进入。
|
|
453
|
+
|
|
454
|
+
基础设施 adapter 只允许做:
|
|
455
|
+
|
|
456
|
+
- 依据 `InfraContext` 创建或关闭客户端
|
|
457
|
+
- 把 typed snapshot 翻译为第三方库要求的参数格式
|
|
458
|
+
- 输出标准化的 `ready/unavailable` 结果
|
|
459
|
+
|
|
460
|
+
基础设施 adapter 不允许做:
|
|
461
|
+
|
|
462
|
+
- 读取全局 settings 或环境变量补配置
|
|
463
|
+
- 默认补 host/port/user/password/db name
|
|
464
|
+
- 根据 import 成功与否静默切换另一套行为
|
|
465
|
+
- 在内部自行决定 `enabled/disabled`
|
|
466
|
+
- 自行维护进程级默认 client、默认 registry、默认 exporter
|
|
467
|
+
- 把网络错误、认证错误、驱动缺失错误统一吞成空对象或固定成功
|
|
468
|
+
|
|
469
|
+
正式要求:
|
|
470
|
+
|
|
471
|
+
- SQLite / MySQL / PostgreSQL 的差异只体现在 provider/adapter 实现,不体现在上层 capability 语义
|
|
472
|
+
- Redis、metrics 必须先由 `InfraContext` 决定是否启用,再进入 adapter 层;overrides/L2 只通过其所归属的 `config` 平台 capability 决定启用语义
|
|
473
|
+
- readiness、health、metrics exporter、DB CLI 不得各自再维护一套 infra 判定逻辑
|
|
474
|
+
|
|
475
|
+
## 16. 基础设施能力的单一路径原则
|
|
476
|
+
|
|
477
|
+
从工程治理角度,基础设施能力必须明确“编译一次、执行一次、消费多次”的单一路径。
|
|
478
|
+
|
|
479
|
+
正式要求:
|
|
480
|
+
|
|
481
|
+
1. `SettingsSnapshot` 编译出 `InfraSettings`
|
|
482
|
+
2. `InfraSettings` 编译出 `InfraContext`
|
|
483
|
+
3. 执行阶段基于 `InfraContext` 创建 provider/client
|
|
484
|
+
4. Web / CLI / worker / readiness / exporter 统一消费同一份 `InfraContext`
|
|
485
|
+
|
|
486
|
+
禁止:
|
|
487
|
+
|
|
488
|
+
- Web 启动自己建一份 DB/Redis 配置
|
|
489
|
+
- readiness 再临时建一份探针配置
|
|
490
|
+
- worker 再从全局 settings 动态拼一份 redis client 参数
|
|
491
|
+
- metrics exporter 再通过模块级默认 registry 判断自己是否启用
|
|
492
|
+
|
|
493
|
+
这条约束适用于:
|
|
494
|
+
|
|
495
|
+
- DB client
|
|
496
|
+
- Redis client
|
|
497
|
+
- mail provider
|
|
498
|
+
- metrics provider
|
|
499
|
+
- overrides/L2 provider
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# App 替换规范
|
|
2
|
+
|
|
3
|
+
## 1. 目标
|
|
4
|
+
|
|
5
|
+
外部 app 替换官方维护最小子包的唯一正式方式,是项目在 `pz.jsonc` 中显式声明替换关系。
|
|
6
|
+
|
|
7
|
+
## 2. 默认冲突策略
|
|
8
|
+
|
|
9
|
+
默认规则:
|
|
10
|
+
|
|
11
|
+
- 同 `app_id` 冲突直接报错
|
|
12
|
+
- 同 `Extension.id` 冲突直接报错
|
|
13
|
+
- 同 `(method, path)` 路由冲突直接报错
|
|
14
|
+
- 同一 middleware 重复声明直接报错,只有显式 `replace_target` 才允许替换
|
|
15
|
+
|
|
16
|
+
目的:
|
|
17
|
+
|
|
18
|
+
- 避免“谁后加载谁覆盖”的隐式行为
|
|
19
|
+
- 避免模板、迁移、settings、路由、模型归属产生不透明结果
|
|
20
|
+
- 避免继续依赖历史来源优先级
|
|
21
|
+
|
|
22
|
+
## 3. 显式替换机制
|
|
23
|
+
|
|
24
|
+
替换关系的唯一正式真相源:
|
|
25
|
+
|
|
26
|
+
- `pz.jsonc` 中的 `[app_replacements]`
|
|
27
|
+
|
|
28
|
+
示例:
|
|
29
|
+
|
|
30
|
+
```toml
|
|
31
|
+
[app_replacements]
|
|
32
|
+
"catalog_app" = "third_party.catalog_app"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
约束:
|
|
36
|
+
|
|
37
|
+
- app 包元数据不负责触发替换
|
|
38
|
+
- 第三方 app 可以声明自己的 `app_id`、`required_pz`、public facade 与 capability contract
|
|
39
|
+
- 是否替换官方 app 只能由项目配置决定
|
|
40
|
+
- route、middleware、extension 若存在 replace 语义,必须在声明对象中显式携带 owner、id、replace target
|
|
41
|
+
- app import path 只能走单一路径,不接受短名补全、自动前缀拼接或 package-level `app` 猜测
|
|
42
|
+
- 扩展点消费侧统一走正式 extension registry,不保留第二套私有收集链
|
|
43
|
+
|
|
44
|
+
## 3.1 替换关系图模型
|
|
45
|
+
|
|
46
|
+
app 替换必须是单一、可审计、无歧义的映射关系。
|
|
47
|
+
|
|
48
|
+
要求:
|
|
49
|
+
|
|
50
|
+
- 一个 target app 只能有一个 replacement app
|
|
51
|
+
- 一个 replacement app 只能替换一个 target app
|
|
52
|
+
- 不允许链式替换
|
|
53
|
+
- 不允许一对多替换
|
|
54
|
+
- 不允许运行时动态改写替换图
|
|
55
|
+
|
|
56
|
+
也就是说:
|
|
57
|
+
|
|
58
|
+
- `[app_replacements]` 必须构成一张一对一、无环、一次解析完成的映射图
|
|
59
|
+
- 替换关系必须在 app registry compiler 阶段一次性裁决完成
|
|
60
|
+
- 后续 route、middleware、extension、resource、infra 都只消费裁决后的结果
|
|
61
|
+
|
|
62
|
+
## 4. 替换规则
|
|
63
|
+
|
|
64
|
+
替换生效的前提:
|
|
65
|
+
|
|
66
|
+
- 项目配置中显式声明替换关系
|
|
67
|
+
- 替换目标与替换来源都已出现在 `installed_apps`
|
|
68
|
+
|
|
69
|
+
替换生效后:
|
|
70
|
+
|
|
71
|
+
- 被替换 app 不参与装载
|
|
72
|
+
- 被替换 app 的资源、迁移、settings 不再进入合并链
|
|
73
|
+
- 路由、模型、扩展点均以替换后的 app 为准
|
|
74
|
+
|
|
75
|
+
约束:
|
|
76
|
+
|
|
77
|
+
- app 级替换成功后,依赖图中的 `requires_apps` 指向替换后的正式 app 实体
|
|
78
|
+
- 被替换 app 不得先装载再在后续阶段被清理
|
|
79
|
+
- 冲突检测必须发生在 app registry、extension registry、middleware plan 与 route manifest 编译阶段
|
|
80
|
+
|
|
81
|
+
## 4.1 app 替换与声明级 replace 的边界
|
|
82
|
+
|
|
83
|
+
app 替换与 route/middleware/extension replace 不是一回事。
|
|
84
|
+
|
|
85
|
+
要求:
|
|
86
|
+
|
|
87
|
+
- app 替换只解决“哪个 app 进入装配链”
|
|
88
|
+
- route replace 只解决 route 声明冲突
|
|
89
|
+
- middleware replace 只解决 middleware 声明冲突
|
|
90
|
+
- extension replace 只解决 extension 声明冲突
|
|
91
|
+
|
|
92
|
+
禁止:
|
|
93
|
+
|
|
94
|
+
- 用 route/middleware/extension replace 模拟整 app 替换
|
|
95
|
+
- 已经 app-level 替换后,仍让原 app 的部分声明进入正式主链
|
|
96
|
+
- 一边声明 app 替换,一边仍保留原 app 的 provider、route、template、static 或 migration 声明
|
|
97
|
+
|
|
98
|
+
## 4.2 数据与迁移归属
|
|
99
|
+
|
|
100
|
+
app 替换最大风险在于数据、迁移和存储归属是否清晰。
|
|
101
|
+
|
|
102
|
+
要求:
|
|
103
|
+
|
|
104
|
+
- 替换 app 若接管原 app 的持久化模型,必须显式声明迁移归属策略
|
|
105
|
+
- 不允许两个 app 在未声明关系的情况下共同写同一批表、集合或持久化目录
|
|
106
|
+
- 被替换 app 的 migration owner、model owner、storage owner 必须有明确切换方案
|
|
107
|
+
- 替换不能只看 `app_id` 相同,还要看:
|
|
108
|
+
- schema 连续性
|
|
109
|
+
- migration 连续性
|
|
110
|
+
- `public.py`、facade、capability contract 是否保持同一公开契约
|
|
111
|
+
|
|
112
|
+
对涉及 DB/存储的替换,额外提供:
|
|
113
|
+
|
|
114
|
+
- 升级路径
|
|
115
|
+
- 回滚路径
|
|
116
|
+
- 数据变化说明
|
|
117
|
+
|
|
118
|
+
## 5. 不允许的替换方式
|
|
119
|
+
|
|
120
|
+
不允许:
|
|
121
|
+
|
|
122
|
+
- 依赖 `installed_apps` 顺序隐式覆盖
|
|
123
|
+
- 仅凭相同 `app_id` 静默抢占
|
|
124
|
+
- 通过 monkey patch 强行替换其它 app 内部实现
|
|
125
|
+
- 依赖 `Extension.source` 或来源 rank 做静默覆盖
|
|
126
|
+
- 依赖重复路由去重逻辑“保留先注册项”
|
|
127
|
+
- 依赖 middleware 去重逻辑“保留最后一个同 key”
|
|
128
|
+
- 依赖 `requires_apps` 的 suffix match 抢占命名
|
|
129
|
+
- 依赖自动补全导入成功来伪装“可替换 app”
|
|
130
|
+
- 依赖 package-level `app` 导出作为正式 app 装载入口
|
|
131
|
+
- 依赖多套 provider 收集链做隐式替换
|
|
132
|
+
|
|
133
|
+
## 6. 公共契约要求
|
|
134
|
+
|
|
135
|
+
外部替换 app 若要替代官方维护最小子包,必须保持以下公开契约:
|
|
136
|
+
|
|
137
|
+
- 稳定的 `app_id`
|
|
138
|
+
- 必需的扩展点协议
|
|
139
|
+
- 必需的 settings 命名空间
|
|
140
|
+
- 必需的路由或 `public.py` / facade 契约
|
|
141
|
+
- 必需的 provider contract / internal binding / events 协议
|
|
142
|
+
|
|
143
|
+
约束:
|
|
144
|
+
|
|
145
|
+
- 若被替换对象本身承担平台级能力,则替换 app 还必须保持其 facade、`public.py` 与 capability contract 的同一公开边界
|
|
146
|
+
- middleware 判定不能只看“最终类名相同”,还应看:
|
|
147
|
+
- middleware `id`
|
|
148
|
+
- `owner`
|
|
149
|
+
- 显式配置契约
|
|
150
|
+
- 身份 / 展示层这类平台侧替换,还必须保持:
|
|
151
|
+
- widget、menu、assets 的统一消费门面
|
|
152
|
+
- 模板渲染门面
|
|
153
|
+
- 静态资源版本与公共静态目录定位
|
|
154
|
+
|
|
155
|
+
## 7. 版本范围
|
|
156
|
+
|
|
157
|
+
继续使用:
|
|
158
|
+
|
|
159
|
+
- `required_pz`
|
|
160
|
+
|
|
161
|
+
补充要求:
|
|
162
|
+
|
|
163
|
+
- 替换 app 必须声明其支持的 core 版本范围
|
|
164
|
+
- 如替换的是官方维护最小子包,应在文档中声明对应的官方版本范围
|
|
165
|
+
|
|
166
|
+
## 8. 项目级声明
|
|
167
|
+
|
|
168
|
+
项目配置正式支持且必须作为唯一替换声明入口:
|
|
169
|
+
|
|
170
|
+
```toml
|
|
171
|
+
[app_replacements]
|
|
172
|
+
"catalog_app" = "third_party.catalog_app"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
用途:
|
|
176
|
+
|
|
177
|
+
- 让项目显式表达“我用哪个外部 app 替代哪个官方 app”
|
|
178
|
+
- 便于 CLI、诊断输出和契约测试识别
|
|
179
|
+
|
|
180
|
+
若替换涉及数据或迁移归属,则显式声明元数据,例如:
|
|
181
|
+
|
|
182
|
+
- 是否接管原 migration owner
|
|
183
|
+
- 是否要求一次性 schema cutover
|
|
184
|
+
- 是否仅替换路由或 UI 层
|
|
185
|
+
|
|
186
|
+
## 9. 诊断要求
|
|
187
|
+
|
|
188
|
+
装配期应输出清晰诊断:
|
|
189
|
+
|
|
190
|
+
- 哪些 app 被装载
|
|
191
|
+
- 哪些 app 因替换被跳过
|
|
192
|
+
- 哪些替换关系来自项目配置
|
|
193
|
+
- 哪些冲突导致装配中止
|
|
194
|
+
|
|
195
|
+
## 10. 测试要求
|
|
196
|
+
|
|
197
|
+
替换机制需要契约测试覆盖:
|
|
198
|
+
|
|
199
|
+
- 同 `app_id` 默认冲突报错
|
|
200
|
+
- `requires_apps` 缺失依赖时报错
|
|
201
|
+
- app dependency cycle 默认报错
|
|
202
|
+
- app import path 不再依赖短名补全、自动前缀拼接或 package-level `app` 猜测
|
|
203
|
+
- `validate_and_sort_apps()` 不再接受 module suffix match 作为正式依赖解析语义
|
|
204
|
+
- 同 `Extension.id` 默认冲突报错
|
|
205
|
+
- route、middleware、extension replace 的结果可预测
|
|
206
|
+
- 未满足版本范围约束时装配失败
|