# ⏳ chrono-temporal

[![PyPI version](https://badge.fury.io/py/chrono-temporal.svg)](https://pypi.org/project/chrono-temporal/)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Time-travel queries for any data entity.**

Query what your data looked like at any point in history, track full change histories, and diff any two points in time — all with a simple Python API.

---

## The Problem

Most databases only store the **current state** of data. When something changes, the old version is gone forever:

- *"What was this user's plan when they filed a dispute?"* — you can't know
- Audit trails and compliance become a nightmare
- Debugging issues that depended on state that no longer exists

---

## Installation

```bash
pip install chrono-temporal
```

---

## Quick Start

```python
from chrono_temporal import TemporalService, TemporalRecordCreate, get_engine, get_session, create_tables
from datetime import datetime, timezone

# Setup
engine = get_engine("postgresql+asyncpg://user:pass@localhost/mydb")
session_factory = get_session(engine)

async def main():
    # Create tables
    await create_tables(engine)

    async with session_factory() as session:
        svc = TemporalService(session)

        # Create a record
        await svc.create(TemporalRecordCreate(
            entity_type="user",
            entity_id="user_001",
            valid_from=datetime(2024, 1, 1, tzinfo=timezone.utc),
            data={"name": "Daniel", "plan": "free"}
        ))

        # Time-travel query — what was the state on March 1st 2024?
        records = await svc.get_at_point_in_time(
            "user", "user_001", datetime(2024, 3, 1, tzinfo=timezone.utc)
        )
        print(records[0].data)  # {"name": "Daniel", "plan": "free"}

        # Diff — what changed between two dates?
        diff = await svc.get_diff(
            "user", "user_001",
            datetime(2024, 1, 1, tzinfo=timezone.utc),
            datetime(2025, 7, 1, tzinfo=timezone.utc),
        )
        print(diff["changed"])  # {"plan": {"from": "free", "to": "pro"}}
```

---

## Features

- 🕐 **Time-travel queries** — get entity state at any point in history
- 📜 **Full history** — complete timeline of changes for any entity
- 🔍 **Diff engine** — compare any two points in time
- 📦 **Generic** — works with any entity type (users, orders, products, contracts)
- ⚡ **Async-first** — built on async SQLAlchemy for high performance
- 🐘 **PostgreSQL** — battle-tested, production-ready

---

## API Reference

### `TemporalService`

| Method | Description |
|--------|-------------|
| `create(payload)` | Create a new temporal record |
| `get_current(entity_type, entity_id)` | Get currently valid records |
| `get_at_point_in_time(entity_type, entity_id, as_of)` | Time-travel query |
| `get_history(entity_type, entity_id)` | Full change history |
| `get_diff(entity_type, entity_id, from_dt, to_dt)` | Diff two points in time |
| `close_record(record_id, closed_at)` | Close a record (set end date) |

### `get_engine(database_url, echo, **kwargs)`
Create an async SQLAlchemy engine connected to PostgreSQL.

### `get_session(engine)`
Create an async session factory from the engine.

### `create_tables(engine)`
Auto-create all required tables in the database.

---

## Full API Server

Want a ready-made REST API with authentication, Docker support, and a demo app?

Check out the full framework:
👉 [github.com/Daniel7303/chrono-temporal-api-framework](https://github.com/Daniel7303/chrono-temporal-api-framework)

---

## Requirements

- Python 3.11+
- PostgreSQL 15+
- asyncpg
- SQLAlchemy 2.0+
- Pydantic 2.0+

---

## License

MIT License — free to use, modify, and distribute.
