Metadata-Version: 2.4
Name: id_crud
Version: 0.4.2
Summary: Base CRUD modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: SQLAlchemy>=2.0
Requires-Dist: pydantic>=2.0
Requires-Dist: internal_calls<0.6,>=0.4

# id_crud

Shared async SQLAlchemy CRUD primitives for institute-scoped services.

## Core guarantees

- Every domain identifier is a UUID.
- `institute_fk_id` is required and every default query is institute-scoped.
- Physical deletion is not supported. Records are soft-deleted or archived.
- Client payloads cannot set `status`, `created_fk_by`, or `institute_fk_id`.
- Audit events are persisted through a transactional outbox.

## Installation

```bash
pip install id_crud
```

## Request context

`institute_fk_id` must be extracted from a verified authentication context. It
must never be copied from an untrusted client payload.

```python
from uuid import UUID

from id_crud import RequesterCTX

context = RequesterCTX(
    user_id=UUID("2f2e266a-28a4-4927-a94f-543bf6524cf6"),
    institute_fk_id=UUID("3e83c482-a5f9-4bd9-9f83-07a57b5058cd"),
)
```

## Deletion policy

```python
from id_crud import BaseCRUD

soft_delete_crud = BaseCRUD(Model, "model_pk_id", delete_mode="soft")
archive_crud = BaseCRUD(Model, "model_pk_id", delete_mode="archive")
```

The old `hard` and `audit` delete modes are intentionally rejected.

## Transactional outbox

Domain changes and their audit event are inserted into the same database
transaction. A separate worker publishes committed outbox messages.

```python
from id_crud import dispatch_outbox_batch

async def publish(message):
    await rabbit_client.publish(
        destination=message.destination,
        payload=message.payload,
        idempotency_key=str(message.event_pk_id),
    )

result = await dispatch_outbox_batch(db, publish)
```

The publisher and consumer must use `event_pk_id` as an idempotency key because
the dispatcher intentionally provides at-least-once delivery.

## Database migration

Applications adopting this release must generate and review an Alembic
migration that:

1. Makes domain `institute_fk_id` columns non-nullable.
2. Adds institute-aware indexes and business unique constraints.
3. Creates the `outbox_events` table and its indexes.
4. Migrates existing physical-delete behavior to lifecycle statuses.

## Tests

```bash
python -m unittest discover -s tests -v
```

The test suite covers request scoping, protected fields, soft deletion,
archiving, transactional audit staging, outbox dispatch, and rollback behavior.
