Metadata-Version: 2.4
Name: python-ddd-framework
Version: 0.3.2
Summary: Modular DDD application framework with project CLI and bundled templates
License-Expression: LicenseRef-Proprietary
License-File: LICENSE
License-File: src/python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: croniter>=6.2.4,<7
Requires-Dist: dishka>=1.10.1,<2
Requires-Dist: fastapi>=0.141.1,<0.142
Requires-Dist: filelock==3.32.6
Requires-Dist: httpx>=0.28.1,<0.29
Requires-Dist: pgqueuer[asyncpg]>=1.3.2,<1.4
Requires-Dist: pydantic>=2.13.5,<3
Requires-Dist: pydantic-settings[yaml]>=2.15.0,<3
Requires-Dist: python-multipart==0.0.32
Requires-Dist: uvicorn>=0.52.4,<0.53
Requires-Dist: wsproto>=1.3.2,<2
Requires-Dist: pyjwt>=2.13.0,<3
Requires-Dist: pwdlib[argon2]>=0.3.1,<0.4
Requires-Dist: python-json-logger==4.2.0
Requires-Dist: sqlalchemy[asyncio]>=2.0.52,<2.1
Requires-Dist: alembic>=1.19.1,<2
Requires-Dist: asyncpg>=0.31,<0.32
Requires-Dist: anyio>=4.14.2,<5
Requires-Dist: redis>=8.1.0,<9
Requires-Dist: opentelemetry-api==1.44.0
Requires-Dist: opentelemetry-sdk==1.44.0
Requires-Dist: opentelemetry-exporter-otlp-proto-http==1.44.0
Requires-Dist: opentelemetry-instrumentation-fastapi==0.65b0
Requires-Dist: opentelemetry-instrumentation-httpx==0.65b0
Requires-Dist: cookiecutter>=2.7.1,<2.8 ; extra == 'developer-kit'
Requires-Dist: libcst>=1.9.0,<1.10 ; extra == 'developer-kit'
Requires-Python: >=3.12, <3.15
Provides-Extra: developer-kit
Description-Content-Type: text/markdown

# Python DDD Framework

Build modular Python applications with explicit domain boundaries, transactional application services, and a consistent path from local development to deployment.

Python DDD Framework combines a module system with FastAPI, Dishka, Pydantic, SQLAlchemy, PostgreSQL, and Redis. It includes the `pddd` CLI and project templates, so you can create an application, add business modules, manage their database migrations, and run the same application through HTTP, background jobs, or direct service calls.

**Python 3.12–3.14 · Windows and Linux · Async application services · Typed public APIs**

[Features](#features) · [Quick start](#quick-start) · [CLI reference](#cli-reference) · [Application development](#application-development) · [Deployment](#deployment) · [Upgrading](#upgrading) · [Documentation](#documentation)

## Features

| Capability | What you can build with it |
| --- | --- |
| Modular applications | Declare module dependencies, compose a Host, and run ordered initialization and shutdown with application-local state. |
| Domain-driven design | Define aggregates, value objects, repository contracts, domain events, and optimistic concurrency rules. Keep domain models separate from DTOs and ORM models. |
| Application services | Use typed service contracts and a shared invocation pipeline for validation, authorization, interceptors, auditing, and units of work. |
| Dependency injection | Register services and native Dishka providers, discover implementations within module-owned packages, and manage application, request, and action scopes. |
| Configuration | Bind YAML and environment inputs to typed Options, validate them at composition time, and inspect configuration sources with sensitive values redacted. |
| HTTP APIs | Expose selected application services through FastAPI, or write explicit routers. Use OpenAPI, filters, file uploads, downloads, and streaming responses. |
| Persistence and events | Use async SQLAlchemy repositories, explicit transaction boundaries, module-owned Alembic migrations, seed contributors, and local events before or after commit. |
| Identity and permissions | Add JWT authentication, refresh sessions, users and roles, permission definitions, and authorization on service methods. |
| Cache, settings, and locks | Use typed Redis caching, runtime settings with conditional updates and reset, settings refresh notifications, and explicit Redis-backed business locks. |
| Background execution | Enqueue durable PostgreSQL jobs with typed payloads, schedule recurring work, run periodic workers, and select in-process or managed subprocess execution. |
| Real-time communication | Add authenticated WebSocket connections, typed messages, and targeted notifications to connected clients. |
| Hosting and observability | Manage long-lived integrations with `HostedService`, coordinate shutdown, and use structured logging, correlation, OpenTelemetry tracing, and lifecycle health endpoints. |
| Developer tooling | Generate projects and business modules, inspect composition, run local infrastructure, and reuse `TestApplication` for application tests. |

The **Module** owns a feature and its dependencies. The **Host** composes modules, selects providers, and supplies configuration. Your application owns the generated source code and database migrations.

Runtime integrations ship in the base package; the Host explicitly enables the modules it needs. Installing the package does not start database connections, workers, or trace export. Local events stay within an application process, and WebSocket notifications do not include a distributed backplane or offline replay.

<a id="开始使用"></a>

## Quick start

### Prerequisites

- A supported Python interpreter; the examples use Python 3.12.
- [uv](https://docs.astral.sh/uv/getting-started/installation/) for tool installation, dependency management, and project commands.
- Docker with Compose, running locally, for the generated application's PostgreSQL and Redis services.

The supported versions and dependencies are defined in [pyproject.toml](https://github.com/componet-architecture/python-ddd-framework/blob/main/pyproject.toml). The framework, CLI, and bundled templates share one package version.

> **Version 0.3:** This version introduces the `python-ddd-framework` name, unified runtime installation, and application documentation templates. Check [release status](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/status.md#当前发布) before selecting a PyPI version. Use the local-wheel route below when evaluating a checkout that has not been published.

### 1. Install the CLI and create a project

For a published release:

```sh
uv tool install --python 3.12 "python-ddd-framework[developer-kit]"
pddd new my-app
cd my-app
```

To select a specific release, append `==<version>` to the quoted package requirement. `pddd new` creates the Host, configuration, tests, deployment files, and four application documents: `README.md`, `AGENTS.md`, `docs/architecture.md`, and `docs/development.md`. It then runs `uv sync` and pins both the runtime dependency and developer tools to the CLI's exact framework version. The destination directory must not already exist.

<details>
<summary>Using an unreleased local wheel</summary>

Obtain a wheel built from the checkout you want to evaluate. Replace `<absolute-wheel-path>` with its full `.whl` path, and use the same wheel for the CLI and the generated application:

```sh
uv tool install --python 3.12 "<absolute-wheel-path>[developer-kit]"
pddd new my-app --framework-wheel "<absolute-wheel-path>"
cd my-app
```

The generator checks that the wheel contains `python-ddd-framework` at the CLI's version, copies it into the application's `vendor/` directory, and records the local dependency source. Installing a CLI from source alone does not change where generated applications obtain their framework dependency.

</details>

### 2. Prepare infrastructure and add a business module

Run project commands from the generated application's root directory:

```sh
uv run pddd dev-init
uv run pddd add module orders
```

`dev-init` starts or reuses local PostgreSQL and Redis using `app.development.yaml`. It preserves existing data; database migration and seeding are separate steps.

`add module orders` generates an order-management example and registers it with the Host. The example includes an aggregate, service contracts, application services, persistence, HTTP endpoints, module tests, and a module README describing its actual behavior and boundaries.

### 3. Initialize the database

Apply the provider migrations selected by the generated Host, then generate the business module's first migration:

```sh
uv run pddd db upgrade --module identity
uv run pddd db upgrade --module settings
uv run pddd db upgrade --module auditing
uv run pddd db upgrade --module background_jobs
uv run pddd db revision --module orders
```

Review the generated revision in `src/modules/orders/sqlalchemy/migrations/` before applying it. Then upgrade and seed:

```sh
uv run pddd db upgrade --module orders
uv run pddd db status --module orders
uv run pddd db seed --module identity
uv run pddd db seed --module orders
```

Migration commands operate on the selected module. When a migration requires another module's revision, upgrade that prerequisite explicitly. Starting the Host does not migrate or seed the database.

### 4. Run the application and explore the API

```sh
uv run pddd dev
```

Open **http://127.0.0.1:8000/docs**. Use the generated `identity.seed_admin_username` and `identity.seed_admin_password` in `app.development.yaml` to call `/api/auth/login`, then enter the returned access token in Swagger's **Authorize** dialog.

With the `orders` module installed, you can create and query orders at `/api/orders`, approve an order at `/api/orders/{id}/approve`, and enqueue approval at `/api/orders/{id}/queue-approval`. Swagger shows the request schemas and all available operations. The example also includes file transfer and an authenticated WebSocket endpoint at `/ws/orders`.

The default business API prefix is `/api`. Liveness and readiness are exposed at `/health/live` and `/health/ready`; readiness describes application lifecycle state, not continuous database or Redis health.

## CLI reference

Use `pddd` to create a project. Inside an existing project, use **`uv run pddd`** so commands run with that project's framework version.

| Command | Purpose |
| --- | --- |
| `pddd new my-app` | Generate a new Host project and install its dependencies. |
| `uv run pddd add module orders` | Generate a business module and register its packages and Host dependencies. |
| `uv run pddd dev-init` | Prepare the local PostgreSQL and Redis services from development configuration. |
| `uv run pddd dev` | Start the development web server with reload at `127.0.0.1:8000`. |
| `uv run pddd db revision --module orders` | Generate an Alembic revision for the module's models. Review it before applying. |
| `uv run pddd db upgrade --module orders` | Apply the selected module's migrations. |
| `uv run pddd db status --module orders` | Check that the database is at the selected module's migration heads; fail if it is not. |
| `uv run pddd db seed --module orders` | Run the selected module's seed contributors after checking its migrations. |
| `uv run pddd inspect` | Print the composed module graph, service registrations, and redacted configuration inputs as JSON. |

Common variations:

```sh
pddd new my-app --dry-run
uv run pddd add module billing --dry-run
uv run pddd dev --host 127.0.0.1 --port 8080
uv run pddd inspect --environment development
uv run pddd db status --module orders --environment production
```

Generation supports `--dry-run` without writing files. Database commands require `--module`; aliases come from installed `python_ddd_framework.modules` entry points and must belong to the current application's module graph.

`db` and `inspect` use `--environment`, then `PYTHON_DDD_FRAMEWORK_ENVIRONMENT`, then `development`. `dev` always selects development, and `dev-init` is restricted to development infrastructure.

`inspect` builds and closes the application without starting services or running migrations. Its output describes a newly composed Host, not a running process. Configuration output contains input values and their sources; it does not include Options defaults or later module contributions.

For the complete options supported by your installed version:

```sh
uv run pddd
uv run pddd new --help
uv run pddd add module --help
uv run pddd db --help
uv run pddd inspect --help
```

## Application development

### Find the right place for a change

The generated project starts with `src/host/` for composition and startup. Business modules live under `src/modules/`; each generated module has these responsibilities:

| Location within a module | Responsibility |
| --- | --- |
| `domain_shared/` | Shared values, errors, and permission names. |
| `domain/` | Aggregates, business rules, events, repository contracts, settings, and seed contributors. |
| `application_contracts/` | DTOs and public application-service contracts. |
| `application/` | Use-case orchestration, service implementations, event handlers, jobs, and workers. |
| `sqlalchemy/` | ORM models, repository implementations, and migrations. |
| `http_api/` | Service exposure, explicit routes, file transfer, and WebSocket endpoints. |
| `tests/` | Tests owned by the business module; excluded from the production wheel. |

For a new use case, define its input and output in `application_contracts/`, put business rules in `domain/`, and coordinate the work in `application/`. Persist through a repository contract. The HTTP module selects which application services to expose; the Host selects infrastructure providers.

For a model change, edit `sqlalchemy/models/`, generate a revision, review it, then run `db upgrade` for that module. For another business module, repeat the `add module`, `db revision`, `db upgrade`, and `db seed` steps. Add application-specific dependencies with `uv add <package>`.

See the [development guide](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md) for service registration, typed invocation, HTTP declarations, transactions, background handlers, and distributed locks.

### Configure the application

Edit `app.development.yaml` for local connections, identity settings, logging, and module Options. An optional `app.yaml` can hold shared configuration. Environment variables override file inputs; generated Hosts use the `PDDD_` prefix and `__` between nested fields. For example, `PDDD_HTTP__API_PREFIX=/v1` changes the business API prefix.

`PYTHON_DDD_FRAMEWORK_ENVIRONMENT` selects the Host environment; it is separate from business configuration. Typed Options validate configuration during application composition. Use `uv run pddd inspect` to investigate input values and where they came from.

Generated credentials are for local development. Production configuration is supplied separately in `app.production.yaml`. See [configuration](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#定义-module-与配置) and [background and logging configuration](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#settings后台与日志).

### Run application tests

After completing local database setup:

```sh
uv run pytest
```

The generated application includes module tests and Host tests. Keep Docker available for tests that use real infrastructure. For custom application tests, the framework's `TestApplication` reuses the normal application builder and typed service invocation. Framework contributor checks are documented separately in [framework validation](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#框架验证).

## Deployment

Generated applications include a `Dockerfile` and `compose.production.yaml`. Build an application distribution with:

```sh
uv build --no-sources
```

For container deployment:

1. Supply `app.production.yaml` with production connections and credentials; keep it out of source control and the image. The generated Compose file mounts it read-only for both migration and web services.
2. Build and validate the application image, then set `APP_IMAGE` to that image's immutable digest.
3. Run database upgrades for each required module in dependency order. Run initial seed operations explicitly with `--environment production`.
4. Start the web service from the same image and check its health endpoints.

The image uses `python -m host.main` without development reload. Runtime installations use the base framework package; `developer-kit` is only needed for generation. Follow the [Docker deployment guide](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#docker-交付) for commands and operational boundaries.

<a id="版本与升级"></a>

## Upgrading

Framework upgrades update dependencies. They do not regenerate your business code, Host, configuration, templates, or migrations. Updating a globally installed CLI also leaves existing projects unchanged.

1. Read the target release's migration notes. Pin both `python-ddd-framework` in runtime dependencies and `python-ddd-framework[developer-kit]` in the development group to the same target version.
2. When adopting the unified installation layout, use `python-ddd-framework==<version>` for runtime dependencies and remove the old capability extras. Legacy extra names and `[all]` are not retained. Preserve the application's own dependencies and sources.
3. When moving a local-wheel or old Git installation to PyPI, remove only the framework's entry in `[tool.uv.sources]`. Keep unrelated source overrides and vendor files.
4. Apply any required source and configuration changes, update the environment, and run your application's validation:

```sh
uv lock --upgrade-package python-ddd-framework
uv sync --locked
uv run pytest
uv build --no-sources
```

During `0.x`, compatible fixes use a patch release; changes requiring consumer adaptation use a minor release with migration instructions. Publishing changed package contents requires a new version. Release evidence, including the limits of previously tested upgrade paths, is recorded in [status](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/status.md).

### Migration notes

These notes remain the authoritative consumer migration instructions. Historical versions below refer to the former package name.

<a id="框架更名迁移未发布"></a>

<details>
<summary>0.3.x — framework name, unified installation, and application guidance</summary>

The distribution is `python-ddd-framework`, the import package is `python_ddd_framework`, and the CLI is `pddd`. Neither `python-platform` nor the unreleased intermediate name `python-modular-framework` retains a package, import, or command alias. The intermediate name belongs to a different PyPI project. Version `0.3.1` carries this breaking migration; `0.3.0` did not pass the release gate and was not published. Publication evidence is tracked in [release status](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/status.md#当前发布).

- Replace dependency names, Python and dynamic imports, and entry point groups. Use `python_ddd_framework.hosts` and `python_ddd_framework.modules`. Replace `pp`/`pmf` commands, framework wheel source keys, and deployment commands, then relock and rebuild without regenerating business code.
- Use `python-ddd-framework==0.3.2` for runtime dependencies and `python-ddd-framework[developer-kit]==0.3.2` for development. Remove former capability extras; the base package includes runtime integrations while the Host still selects and enables providers.
- New projects receive English setup, agent guidance, architecture, and development documents; newly generated modules receive a README. Existing applications are not regenerated or overwritten. Adopt the relevant guidance manually and preserve project-specific business rules and instructions.
- Replace `PYTHON_PLATFORM_ENVIRONMENT` or `PYTHON_MODULAR_FRAMEWORK_ENVIRONMENT` with `PYTHON_DDD_FRAMEWORK_ENVIRONMENT`. New templates use `PDDD_` for business configuration; existing applications may retain their own business prefixes.
- Stop old Hosts and workers before switching. The local lock directory is now `.python-ddd-framework`; old processes may still hold locks under the former directory.
- Storage and protocol identifiers now use capability names. The default queue schema is `background_jobs`, the default Redis prefix is `app`, and generated applications use their project name as the Redis prefix. Table names, revisions, and branch labels follow their owning capability. WebSocket framework errors use `framework.problem.v1`.
- There is no compatibility path for the old database, cache keys, or protocol identifiers. Recreate disposable development databases; explicitly migrate any data you need to retain. Installation identity remains configurable through `redis.key_prefix`, PgQueuer Options, and SQLAlchemy migration Options.
- Give installations sharing a database separate Alembic version table names or schemas. A version table cannot reside in the queue's exclusive schema. PgQueuer notification channels derive from the schema and object prefix and do not reuse the old channel. Changing these identities for an existing installation requires explicit migration of data and migration records. See [configuration examples](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#settings后台与日志).

</details>

<a id="021-升级说明"></a>

<details>
<summary>0.2.1 — application, HTTP, background, and persistence contracts</summary>

The `0.2` line introduced changes requiring application updates. Version `0.2.0` did not pass the full CI gate and was not released; the corrected release used the former `python-platform` name at `0.2.1`. See the [historical release record](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/status.md#当前发布). For that release, both runtime and developer-kit dependencies were pinned to `==0.2.1`. Consumption under the new name additionally requires the rename steps above.

- **Repositories and service scopes:** Repository interfaces inherit `RepositoryContract, Protocol`; implementations belong in the persistence layer's `repositories/` package and are scanned by their module. Remove manual scope and interface mappings. Repositories use cached REQUEST scope, application-service implementations use ACTION, and `HostedService` uses cached APP scope. Conflicting lifecycle declarations and non-cached providers are rejected.
- **Jobs and workers:** Move job declarations to class attributes and discover them through `Module.scan_packages`; enqueue with `enqueue(JobType, payload)`. Register worker classes in `Module.background_workers`, with interval and enabled state on the class. Remove explicit class Definition registration and `jobs.enabled` configuration. Function registrations and durable name/version/payload identities remain unchanged. Approval payloads require `order_id`; drain or explicitly migrate old statistics jobs instead of passing them to the approval handler.
- **Hosted services and shutdown:** `HostedService` is opt-in. Hosted services start after module initialization and before background execution; the application reaches RUNNING only after all starts succeed. Shutdown waits for background execution first. Failed-start rollback waits for background, hosted-service, module, and container cleanup; cancellation propagates afterward with the original failure retained.
- **HTTP routes:** Set the global prefix with `FastApiAdapter(api_prefix=...)`; generated Hosts read `http.api_prefix`. The default `root_path` no longer contains `app`. Remove `/api` from module override paths and make method paths relative to the service path; a status-only HTTP declaration may omit its path. The default orders URLs are unchanged, while custom routes must be checked against OpenAPI. Explicit business `HttpRouter` instances use `use_api_prefix=True`; independent routes remain separately declared. Managed routers preserve Host operation-ID generation and exclude the deployment prefix from generated IDs.
- **ORM models:** Move models into `sqlalchemy/models/`, with `Base` owned by the package entry point and business models in separate files. Use `SqlAlchemyModelRegistration.from_package`, and update imports such as `OrderRow`. Keep migrations independently managed and execute upgrades explicitly. Function providers for closed generic repositories also undergo the fixed-scope checks.
- **Host configuration:** Generated applications provide only `app.development.yaml`. Deployment supplies `app.production.yaml` as a read-only mount outside source control and the image. Host and tests share the configuration entry point; `dev-init` derives Compose values from the composed snapshot. Replace private server entry points with `python_ddd_framework.fastapi.server.run_host`. Module generation preserves dependency-tuple comments and formatting, and template imports are ordered for the consumer package.

</details>

<details>
<summary>0.1.1 — public package consumption</summary>

- `0.1.1` was the first public-installation target under the former name. `0.1.0` did not complete public release; the patch retriggered publishing without changing API, dependency, or database contracts. See [release evidence](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/status.md#当前发布).
- Project generation switched to exact PyPI dependencies while retaining same-version local-wheel validation. `--framework-source` and implicit Git-source inference were removed. Applications moving from private prereleases pinned runtime and developer-kit dependencies to `==0.1.1`, removed only the framework source override, then relocked and validated.
- Dockerfiles may remove Git/SSH tooling and credential mounts used solely to fetch the framework; assess other Git dependencies separately. This consumption change introduced no framework schema migration.
- New projects start with a Host skeleton and add business code through `add module`. Existing applications keep their source layout. Check their Host/module entry points and database ownership against the [development guide](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#数据库聚合与迁移).

</details>

<a id="更早私有版本的迁移"></a>

<details>
<summary>Earlier private versions</summary>

Apply only the migrations relevant to your application. Completed migrations do not need to be repeated.

| Former usage | Migration |
| --- | --- |
| Application TOML, `OptionDefinition`/class metadata, `Editor.patch`, direct injection of concrete Options types | Move to YAML configuration and `pre_configure`/`configure` with `values`; inject `Options[T]`. Preserve parent configuration hooks through `super` or a dependency on their owning module. No legacy loader or alias remains. |
| Public `ApplicationServiceInvoker` or `invoke(ServiceType, method, ...)` | Inject the public service proxy or use `invoke(Service.method, ...)`. Put policies on the final implementation and signatures on the contract. Keep a separate contract for `IntegrationService`. |
| Module Settings/permission definition lists or `GlobalSettings` | Define synchronous `SettingDefinitionProvider`/`PermissionDefinitionProvider` classes inside scanned packages. Read through `SettingProvider`, write through `SettingManager`, and avoid unbound convenience properties during construction. |
| `HostedRuntime`/Definition or ready/not-ready/failure callbacks | Register `HostedService` types and implement async `start`/`stop`. Components own runtime failure and recovery; opt into background-process instances explicitly when required. |
| `SoftDeleteMixin`, `include_soft_deleted`, or restore APIs | Use physical deletion, foreign-key constraints, and the published follow-up migrations. Handle historical soft-deleted data first; do not edit old revisions or bypass guards. |
| Integer settings versions or deleting version records on reset | Apply the existing version-token migration. Conditional update/reset uses the queried UUID/null expected version; reset retains a new version record, and old tokens cannot be reused. |
| Manual aggregate-event collection or private repository operations | Use public `SessionProvider.operation(..., aggregate=...)`; collect events once after successful staging and retain explicit DTO/aggregate/ORM mapping. |
| Earlier conventional HTTP action paths | Check the HTTP module and generated OpenAPI. CRUD routes omit the action segment and static routes take priority; old URL aliases are not retained. |
| `ReferenceOrderView` or public `fail_after_add` | Use `ReferenceOrderDto` and remove the fault-injection parameter. The reference application's `reference_orders_0002` migration adds `version` to existing data; updates compete on the expected version. No old type alias remains. |
| Interpreters or backports outside `requires-python` | Select a supported interpreter from package metadata, relock, and run application validation. |

Do not remove durable job payload versions merely because their Python APIs were removed. First drain the queue or explicitly migrate its data. See [transaction and persistence boundaries](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/architecture.md#uow持久化与本地事件).

</details>

<details>
<summary>For maintainers: publishing a changed version</summary>

Routine code and documentation commits may retain the current version. Pushes to `main` still run CI but skip publication unless the version increased across the push; initial creation of `main` publishes its current version. Manual workflow runs validate only. A failed run may be retried, but a later same-version push does not resume publication: changed contents require another version bump. Follow [release operations](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md#发布操作) for publisher setup and retry boundaries. A future version is not evidence of a completed upgrade test.

</details>

## Documentation

The engineering guides below are maintained in Chinese in the private GitHub repository and require repository access. This README and the documents bundled with generated applications provide the English product and development guides.

| If you need to… | Read |
| --- | --- |
| Implement services, configure modules, or operate the database | [Development and operations](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/development.md) |
| Understand ownership, lifecycle, transaction, and failure guarantees | [Architecture and contracts](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/architecture.md) |
| Understand why a design was chosen | [Architecture decision records](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/README.md#架构决策索引) |
| Check release evidence and remaining validation limits | [Status and validation](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/status.md) |
| Change the framework itself | [Contributor guidance](https://github.com/componet-architecture/python-ddd-framework/blob/main/AGENTS.md) and [focused reading paths](https://github.com/componet-architecture/python-ddd-framework/blob/main/docs/README.md#重构的最短阅读路径) |

Generated applications include a self-contained English README, `AGENTS.md`, architecture document, and development guide for their template version. `AGENTS.md` directs Codex and other contributors to the affected guidance and module README. Each document has a distinct owner, and the application maintains them after generation; framework upgrades do not overwrite them.

## License

Python DDD Framework is distributed under the [hank-repo Proprietary License](https://github.com/componet-architecture/python-ddd-framework/blob/main/LICENSE). Use requires a separate written agreement; public package availability does not grant additional rights. The source repository is private, with public PyPI packages as the intended delivery channel. PgQueuer-derived code retains its [upstream license](https://github.com/componet-architecture/python-ddd-framework/blob/main/src/python_ddd_framework/background_jobs/pgqueuer/UPSTREAM_LICENSE.txt).
