Metadata-Version: 2.4
Name: domainkit
Version: 0.5.0
Summary: A Django-style framework for domain-driven FastAPI services.
License-Expression: MIT
License-File: LICENSE
Keywords: ddd,domain-driven-design,fastapi,sqlalchemy,outbox,framework
Author: karim magdy
Author-email: karimhady111@gmail.com
Requires-Python: >=3.13,<4
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: FastAPI
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Typing :: Typed
Provides-Extra: immudb
Provides-Extra: metrics
Provides-Extra: postgres
Provides-Extra: rabbitmq
Provides-Extra: redis
Provides-Extra: sqlite
Provides-Extra: testing
Provides-Extra: tracing
Requires-Dist: aio-pika (>=10.1.0,<11.0.0) ; extra == "rabbitmq"
Requires-Dist: aiosqlite (>=0.22.1,<0.23.0) ; extra == "sqlite"
Requires-Dist: alembic (>=1.20.0,<2.0.0)
Requires-Dist: asyncpg (>=0.31.0,<0.32.0) ; extra == "postgres"
Requires-Dist: fastapi (>=0.141.1,<0.142.0)
Requires-Dist: httpx2 (>=2.13.0,<3.0.0) ; extra == "testing"
Requires-Dist: immudb-py (>=1.5.0,<1.6.0) ; extra == "immudb"
Requires-Dist: opentelemetry-api (>=1.45.1,<2.0.0) ; extra == "tracing"
Requires-Dist: prometheus-client (>=0.26.0,<0.27.0) ; extra == "metrics"
Requires-Dist: pydantic (>=2.14.1,<3.0.0)
Requires-Dist: pytest (>=9.1.1,<10.0.0) ; extra == "testing"
Requires-Dist: python-dotenv (>=1.2.4,<2.0.0)
Requires-Dist: redis (>=8.1.0,<9.0.0) ; extra == "redis"
Requires-Dist: sqlalchemy[asyncio] (>=2.0.54,<2.1)
Requires-Dist: uvicorn[standard] (>=0.54.0,<0.55.0)
Project-URL: Changelog, https://github.com/karimmattar/domainkit/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/karimmattar/domainkit/blob/main/docs/reference.md
Project-URL: Homepage, https://github.com/karimmattar/domainkit
Project-URL: Issues, https://github.com/karimmattar/domainkit/issues
Description-Content-Type: text/markdown

# domainkit

A Django-style framework for domain-driven FastAPI services. It provides:

- settings modules and installed domains
- `manage.py` commands and migrations
- DDD building blocks, with the layer rules between them enforced
- several databases: domains routed to their own, sharding by key,
  PostgreSQL range partitioning, and immudb ledgers for evidence
- caches in memory or in Redis and Valkey, with stampede protection, and
  rate limits shared by every replica
- background work through a transactional outbox, run by polling workers or
  through RabbitMQ, with queues for separate worker pools
- optional apps for reliable messaging, audit trails, idempotent requests,
  and tamper-evident evidence

```bash
pip install "domainkit[postgres]"     # extras: postgres, sqlite, immudb, redis, rabbitmq, metrics, tracing, testing
```

## Documentation

- [docs/reference.md](https://github.com/karimmattar/domainkit/blob/main/docs/reference.md): settings, middleware, errors,
  observability, testing, commands, and extension points
- [docs/databases.md](https://github.com/karimmattar/domainkit/blob/main/docs/databases.md): several databases, routing,
  sharding, partitioning, and ledgers
- [docs/cache.md](https://github.com/karimmattar/domainkit/blob/main/docs/cache.md): caches in memory, Redis, and Valkey,
  and shared rate limits
- [docs/contrib.md](https://github.com/karimmattar/domainkit/blob/main/docs/contrib.md): messaging (and workers on RabbitMQ),
  audit, idempotency, and evidence
- [docs/versioning.md](https://github.com/karimmattar/domainkit/blob/main/docs/versioning.md): compatibility, deprecations, and releases
- [docs/adr/](https://github.com/karimmattar/domainkit/tree/main/docs/adr): the decisions behind the design
- [CHANGELOG.md](https://github.com/karimmattar/domainkit/blob/main/CHANGELOG.md) and [SECURITY.md](https://github.com/karimmattar/domainkit/blob/main/SECURITY.md)

## Quick start

```bash
python3.13 -m venv .venv && . .venv/bin/activate
pip install "domainkit[postgres,sqlite,testing]"
domainkit init billingAPI billing     # the name sets the variable prefix: BILLING_API_*
cd billing
python manage.py check
python manage.py startdomain invoices --aggregate Invoice   # prints how to install it
python manage.py makemigrations -m "create invoices" && python manage.py migrate
pytest
python manage.py runserver            # http://127.0.0.1:8000/docs
```

`domainkit init` creates a project that passes `check` and its tests as it is:

```text
billing/
  pyproject.toml          the name, dependencies, and the pytest plugin
  manage.py
  .env                    selects config.settings.local on this machine
  .gitignore
  src/config/settings/    base, local, test, and production settings
  src/config/urls.py      the root router: mount each domain's router here
  src/config/asgi.py      the application, for uvicorn
  src/domains/            the bounded contexts
  tests/test_health.py
```

The production settings read `BILLING_API_ALLOWED_HOSTS` and
`BILLING_API_DATABASE_URL` from the environment, and the deployment checks
refuse to start without them, or without verified TLS to the database.

## Developing domainkit

```bash
poetry install --all-extras            # Python 3.13
pre-commit install                     # after: pipx install pre-commit

poetry run ruff check . && poetry run ruff format --check . && poetry run mypy
poetry run pytest --cov                # random order; coverage gate in pyproject.toml
poetry run mutmut run "domainkit.http*" && poetry run mutmut results
```

Without servers, the database tests use SQLite, the Redis and RabbitMQ
tests use in-memory fakes, and the tests that need PostgreSQL, immudb, or a
real Redis, Valkey, or RabbitMQ are skipped. Point them at throwaway servers to run
them; each test cleans up after itself:

```bash
docker run -d --rm --name domainkit-postgres -e POSTGRES_PASSWORD=postgres \
  -p 127.0.0.1:55432:5432 postgres:18-alpine
docker run -d --rm --name domainkit-redis -p 127.0.0.1:56379:6379 redis:8-alpine
DOMAINKIT_TEST_POSTGRES_URL=postgresql+asyncpg://postgres:postgres@127.0.0.1:55432/postgres \
DOMAINKIT_TEST_REDIS_URL=redis://127.0.0.1:56379/0 \
  poetry run pytest
```

The other variables (immudb, Redis over TLS, Valkey, RabbitMQ) are listed
at the top of `domainkit_tests/test_immudb.py`, `test_redis.py`, and
`test_rabbitmq.py`. Each run must cover
98%; CI also combines the runs with and without servers, which must cover
100%. To check that locally, run `pytest --cov` once without and once with
the servers, each with its own `COVERAGE_FILE`, then `coverage combine` and
`coverage report --fail-under=100`.

CI (`.github/workflows/ci.yml`) runs on every push and pull request:

- lint and strict typing
- the tests on Python 3.13 and 3.14
- the tests again against PostgreSQL 18, immudb with TLS and a signing key,
  Redis 8 (plain and TLS), Valkey 9, and RabbitMQ 4 (plain and TLS); no test
  may be skipped there
- coverage of both runs combined, which must be 100%
- a wheel build, installed and imported in a clean environment
- pip-audit, and a gitleaks scan of the whole history

A full mutation testing run happens weekly. Releases are published to PyPI
from a version tag; see [docs/versioning.md](https://github.com/karimmattar/domainkit/blob/main/docs/versioning.md).

## License

MIT; see [LICENSE](https://github.com/karimmattar/domainkit/blob/main/LICENSE).

