Metadata-Version: 2.4
Name: sonnet-server
Version: 0.1.7
Summary: Domain-service foundation for Petrarca Labs backend services
Author-email: Wolfgang Miller <wolfgang.miller@petrarca-labs.com>
License-Expression: Apache-2.0
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.14
Requires-Python: <4.0,>=3.14
Description-Content-Type: text/markdown
License-File: LICENSE.md
Requires-Dist: fastapi>=0.135.1
Requires-Dist: uvicorn>=0.41.0
Requires-Dist: typer>=0.24.1
Requires-Dist: python-dotenv>=1.2.2
Requires-Dist: loguru>=0.7.3
Requires-Dist: jinja2>=3.1.6
Requires-Dist: sqlmodel>=0.0.37
Requires-Dist: sqlalchemy>=2.0.48
Requires-Dist: alembic>=1.18.4
Requires-Dist: tenacity>=9.1.4
Requires-Dist: pydantic-settings>=2.13.1
Requires-Dist: arrow>=1.4.0
Requires-Dist: jsonschema>=4.23.0
Requires-Dist: cachetools>=7.0.5
Provides-Extra: filtering
Requires-Dist: lark>=1.3.1; extra == "filtering"
Provides-Extra: graphql
Requires-Dist: strawberry-graphql[fastapi]>=0.312.3; extra == "graphql"
Provides-Extra: postgres
Requires-Dist: psycopg>=3.3.3; extra == "postgres"
Requires-Dist: psycopg-binary>=3.3.3; extra == "postgres"
Provides-Extra: nats
Requires-Dist: nats-py>=2.14.0; extra == "nats"
Provides-Extra: redis
Requires-Dist: redis[hiredis]>=7.0; extra == "redis"
Provides-Extra: all
Requires-Dist: sonnet-server[filtering,graphql,nats,postgres,redis]; extra == "all"
Provides-Extra: dev
Requires-Dist: sonnet-server[all]; extra == "dev"
Requires-Dist: setuptools-scm; extra == "dev"
Requires-Dist: ruff>=0.3.0; extra == "dev"
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
Requires-Dist: pre-commit>=4.3.0; extra == "dev"
Requires-Dist: fakeredis>=2.0; extra == "dev"
Requires-Dist: testcontainers[postgres,redis]>=4.0; extra == "dev"
Requires-Dist: watchfiles>=0.19.0; extra == "dev"
Dynamic: license-file

# Sonnet Server

Domain-service foundation for Petrarca backend services. Provides the
infrastructure layer that every backend service inherits: FastAPI app
factory, extension-based lifecycle, database connectivity, messaging,
caching, DI, readiness pipeline, guards, CLI framework, and system
endpoints.

## What it provides

- **Extension protocol** -- opt-in subsystem lifecycle (database, messaging,
  cache, profiles). Infrastructure and profile extensions with conditional
  startup and router mounting.
- **Database** -- engine management, ambient sessions, CRUD repository,
  Alembic utilities, advisory locks.
- **Messaging** -- content-based router with pluggable channels (Postgres
  LISTEN/NOTIFY, NATS, in-process), CloudEvents envelope, `@handles`
  decorator.
- **Cache** -- managed cache with pluggable backends (local, distributed,
  near-cache), cross-process invalidation via messaging.
- **Readiness pipeline** -- composable health check stages with decorator-based
  auto-discovery.
- **Guards** -- protocol-based authentication and tenant context validation.
- **DI** -- type-keyed service registry with factory and singleton patterns.
- **CLI** -- Typer-based framework with reusable `db check` / `db upgrade`
  commands.
- **System endpoints** -- `/ping`, `/version`, `/health-check`, plus
  extension-contributed routes (`/messaging`, `/cache`).

## Prerequisites

- Python 3.14+
- [Task](https://taskfile.dev/) (task runner)
- [uv](https://docs.astral.sh/uv/) (Python package manager)

## Setup

| Situation | Command |
|---|---|
| Fresh clone | `task install` |
| After `git pull` (no dep changes) | `task sync` |
| After editing `pyproject.toml` | `task install` |
| Upgrade deps to latest | `task upgrade` → commit `uv.lock` |

`sonnet-server` has no local path dependencies, so there is no `install:dev` variant.

```bash
task install
```

## Development

```bash
# Format, check, test
task fct

# Individual steps
task format
task check
task test
```

## Consumer usage

### Dependency

Add to your project's `pyproject.toml`:

```toml
[project]
dependencies = [
    "sonnet-server[all]>=0.1.0",
]
```

For local co-development, add an editable source override:

```toml
[tool.uv.sources]
sonnet-server = { path = "../../sonnet-server", editable = true }
```

### Settings

Subclass `Settings` with your own env prefix. Call `init_settings()` at the
bottom of your settings module to register with sonnet-server:

```python
# my_app/settings.py
from functools import lru_cache
from pydantic_settings import SettingsConfigDict
from sonnet_server.settings import Settings as SonnetSettings, init_settings

class Settings(SonnetSettings):
    model_config = SettingsConfigDict(env_prefix="MY_APP_", ...)
    # project-specific fields here

@lru_cache
def get_settings() -> Settings:
    return Settings()

init_settings(get_settings())
```

All sonnet-server infrastructure (database, messaging, cache, checks) will
then read from `MY_APP_*` env vars.

## License

Apache License 2.0. See [LICENSE.md](LICENSE.md).
