Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

---

## v26.06.04 (2026-06-05)

### Documentation accuracy pass

A comprehensive sweep of the docs against the current codebase — no functional
changes.

- **New guide:** `docs/modules/session.md` (HTTP session store, `SessionFilter`,
in-memory/Redis stores, `pyfly.session.*`) — previously only mentioned inside
the security guide.
- **README** now advertises the unified structured logging, Spring-style logging
configuration, and on-by-default **PII redaction** (with the optional
`pyfly[pii]` / Presidio upgrade); the `pii` extra is listed in the installation
guide.
- **Indexes refreshed** (`docs/index.md`, `docs/README.md`,
`docs/modules/README.md`, `docs/adapters/README.md`) so every module/adapter
guide is linked; fixed the Logging link (was pointing at the observability
guide).
- **Corrected factual drift across ~37 guides** to match the code, e.g.: the five
always-active web filters and their ordering; `SecurityException` → HTTP 403;
relational pool keys (`pool.size`/`max-overflow`/…); `@message_listener`
`group=`; actuator `beans` `contexts` envelope and the `threaddump`/`prometheus`
endpoints; health statuses (`UP`/`UNKNOWN`/`OUT_OF_SERVICE`/`DOWN`); `@timed`/
`@counted`/`@span` work on sync and async; AOP advice sync/async semantics;
DI error types (`NoSuchBeanError`/`NoUniqueBeanError`/`BeanCurrentlyInCreationError`)
and the `Registration.factory` field; `Query.get_cache_key` SHA-256; the IDP
provider/route surface; notification provider adapters; and more.

---

## v26.06.03 (2026-06-05)

### Presidio PII path — now functional + CI-covered
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<a href="https://github.com/fireflyframework"><img src="https://img.shields.io/badge/Firefly_Framework-official-ff6600?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyeiIvPjwvc3ZnPg==" alt="Firefly Framework"></a>
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/python-3.12%2B-blue?logo=python&logoColor=white" alt="Python 3.12+"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-green" alt="License: Apache 2.0"></a>
<a href="#"><img src="https://img.shields.io/badge/version-26.06.03-brightgreen" alt="Version: 26.06.03"></a>
<a href="#"><img src="https://img.shields.io/badge/version-26.06.04-brightgreen" alt="Version: 26.06.04"></a>
<a href="#"><img src="https://img.shields.io/badge/type--checked-mypy%20strict-blue?logo=python&logoColor=white" alt="Type Checked: mypy strict"></a>
<a href="#"><img src="https://img.shields.io/badge/code%20style-ruff-purple?logo=ruff&logoColor=white" alt="Code Style: Ruff"></a>
<a href="#"><img src="https://img.shields.io/badge/async-first-brightgreen" alt="Async First"></a>
Expand Down Expand Up @@ -119,7 +119,7 @@ Every PyFly API is designed for `asyncio` from the ground up — no sync-to-asyn

### Production-Ready from Day One

The first time you run `pyfly run`, your application already has structured logging with correlation IDs, health check endpoints, Prometheus metrics, OWASP security headers, and graceful shutdown. These aren't features you opt into — they're the baseline.
The first time you run `pyfly run`, your application already has structured logging with correlation IDs, PII redaction, health check endpoints, Prometheus metrics, OWASP security headers, and graceful shutdown. These aren't features you opt into — they're the baseline.

---

Expand Down Expand Up @@ -998,7 +998,7 @@ PyFly ships with **39 fully-implemented modules** organized into five layers —
| **Container** | Dependency injection, stereotypes, bean factories | Spring DI (built-in) |
| **Context** | ApplicationContext, events, lifecycle hooks, conditions | Spring ApplicationContext |
| **Config** | Decentralized auto-configuration via `@auto_configuration` entry points | Spring Auto-Configuration |
| **Logging** | Structured logging port and adapters | `fireflyframework-observability` |
| **Logging** | Unified structured logging — intercepts all loggers (framework + third-party) through one formatter; Spring-style config (`pyfly.logging.*` — patterns, file output, rotation, external config file); PII redaction on by default (regex; optional Microsoft Presidio via `pyfly[pii]`) | `fireflyframework-observability` |

### Application Layer

Expand Down Expand Up @@ -1090,6 +1090,7 @@ Browse all guides in the [Module Guides Index](docs/modules/README.md):
- [IDP (Identity Provider)](docs/modules/idp.md) — Keycloak / AWS Cognito / Azure AD / internal-DB adapters
- [ECM (Content Management)](docs/modules/ecm.md) — Documents, folders, e-signature workflows
- [Admin Dashboard](docs/modules/admin.md) — Embedded management dashboard, server mode, custom views
- [Logging](docs/modules/logging.md) — Unified structured logging, Spring-style `pyfly.logging.*` config, PII redaction (`pyfly[pii]` for Presidio NER)

### Adapter Reference

Expand Down
24 changes: 23 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ All module guides are organized in the [`modules/`](modules/README.md) directory
| [Core & Lifecycle](modules/core.md) | Application bootstrap, startup sequence, configuration, profiles, banner |
| [Dependency Injection](modules/dependency-injection.md) | Container, stereotypes, scopes, bean factories, conditional beans, lifecycle hooks |
| [Configuration](modules/configuration.md) | YAML/TOML config, profiles, property binding, environment variables |
| [Config Server](modules/config-server.md) | Centralized config server (`ConfigServer`, `ConfigClient`), Spring-Cloud-Config-compatible responses, filesystem/in-memory backends |
| [Starters](modules/starters.md) | Layered bundles — `enable_core_stack`, `enable_web_stack`, `enable_application_stack`, `enable_data_stack`, `enable_domain_stack`, per-tier module activation |
| [Error Handling](modules/error-handling.md) | Exception hierarchy, HTTP status mapping, structured error responses |

### Web Development
Expand All @@ -44,6 +46,8 @@ All module guides are organized in the [`modules/`](modules/README.md) directory
| [Validation](modules/validation.md) | `Valid[T]` annotation, Pydantic model validation, structured 422 errors |
| [WebFilters](modules/web-filters.md) | Request/response filter chain — `TransactionIdFilter`, `RequestLoggingFilter`, `SecurityHeadersFilter` |
| [WebSocket](modules/websocket.md) | `@websocket_mapping`, `WebSocketSession`, `WebSocketHandler` lifecycle, `on_disconnect` hook, route discovery |
| [Server Module](modules/server.md) | `ApplicationServerPort`, Granian / Uvicorn / Hypercorn adapters, uvloop / asyncio selection, `ServerProperties`, `pyfly run` |
| [Internationalisation (i18n)](modules/i18n.md) | `MessageSource` port, `ResourceBundleMessageSource` (YAML/JSON bundles), locale fallback, `MessageFormat`-style placeholders |
| [Actuator](modules/actuator.md) | Health checks, beans endpoint, environment info, loggers, metrics |
| [Custom Actuator Endpoints](modules/custom-actuator-endpoints.md) | Build your own actuator endpoints with the `ActuatorEndpoint` protocol |

Expand All @@ -67,13 +71,16 @@ All module guides are organized in the [`modules/`](modules/README.md) directory

| Guide | Description |
|-------|-------------|
| [Transactional Engine](modules/transactional.md) | SAGA and TCC distributed transaction patterns, compensation, recovery, saga composition |
| [Transactional Engine](modules/transactional.md) | Saga (`@saga`, `@saga_step`), Workflow (`@workflow`, `@wait_for_signal`, `@wait_for_timer`), TCC (`@tcc`, `@tcc_participant`), DAG execution, compensation, DLQ, recovery |
| [Event Sourcing](modules/eventsourcing.md) | `AggregateRoot`, `EventStore` (in-memory + SQLAlchemy), `SnapshotStore`, `TransactionalOutbox`, `Projection` / `ProjectionRunner`, `EventUpcaster` |
| [Domain (DDD primitives)](modules/domain.md) | `Entity[TID]`, `ValueObject`, `AggregateRoot[TID]`, `DomainEvent`, `Specification`, `DomainRepository`, `BusinessRuleViolation`, `enable_domain_stack` |

### Security

| Guide | Description |
|-------|-------------|
| [Security](modules/security.md) | JWT authentication, password encoding, authorization, protected endpoints |
| [Session](modules/session.md) | Server-side session management, pluggable stores (in-memory, Redis), OAuth2 integration |

### Resilience & Performance

Expand All @@ -100,8 +107,21 @@ All module guides are organized in the [`modules/`](modules/README.md) directory
| Guide | Description |
|-------|-------------|
| [Observability](modules/observability.md) | Prometheus metrics, OpenTelemetry tracing, structured logging, health checks |
| [Logging](modules/logging.md) | `get_logger`, unified structured logging (intercepts all loggers), Spring-style `pyfly.logging.*` config, PII redaction (regex default; Presidio NER via `pyfly[pii]`) |
| [Scheduling](modules/scheduling.md) | Cron jobs, fixed-rate tasks, fixed-delay tasks, async execution |

### Integration

| Guide | Description |
|-------|-------------|
| [Callbacks (outbound webhooks)](modules/callbacks.md) | Subscriptions, HMAC signing, retry, execution tracking |
| [Webhooks (inbound)](modules/webhooks.md) | Signature validation, idempotency, listener pattern |
| [Notifications](modules/notifications.md) | Email / SMS / push ports, SendGrid / Twilio / Firebase / SMTP / dummy adapters |
| [IDP (Identity Provider)](modules/idp.md) | `IdpAdapter` port + Keycloak / AWS Cognito / Azure AD / internal-DB adapters, login, MFA, roles |
| [ECM (Content Management)](modules/ecm.md) | Document storage, metadata, folders, e-signature ports + AWS S3 / Azure Blob / DocuSign / Logalty adapters |
| [Plugins](modules/plugins.md) | `@plugin`, `@extension`, `@extension_point`, `PluginManager`, dependency resolution |
| [Rule Engine](modules/rule-engine.md) | YAML DSL, AST evaluator, batch evaluation, repository |

### Advanced

| Guide | Description |
Expand All @@ -122,6 +142,8 @@ Browse the full [Adapter Catalog](adapters/README.md), or jump directly:
| [SQLAlchemy](adapters/sqlalchemy.md) | PostgreSQL, MySQL, SQLite | Data Relational |
| [MongoDB](adapters/mongodb.md) | MongoDB (Beanie ODM) | Data Document |
| [Starlette](adapters/starlette.md) | Starlette / Uvicorn | Web |
| [FastAPI](adapters/fastapi.md) | FastAPI + Uvicorn / Granian | Web |
| [Granian](adapters/granian.md) | Granian (Rust/tokio ASGI server) | Server |
| [Kafka](adapters/kafka.md) | Apache Kafka (aiokafka) | Messaging |
| [RabbitMQ](adapters/rabbitmq.md) | RabbitMQ (aio-pika) | Messaging |
| [Redis](adapters/redis.md) | Redis (async) | Caching |
Expand Down
9 changes: 8 additions & 1 deletion docs/adapters/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,18 @@ For the shared port APIs (`RepositoryPort`, `Page`, `Pageable`, `QueryMethodPars
| [SQLAlchemy](sqlalchemy.md) | Data Relational | PostgreSQL, MySQL, SQLite | [Module Guide](../modules/data-relational.md) |
| [MongoDB](mongodb.md) | Data Document | MongoDB (Beanie ODM) | [Module Guide](../modules/data-document.md) |

## Web Adapter
## Web Adapters

| Adapter | Module | Backend | Guide |
|---------|--------|---------|-------|
| [Starlette](starlette.md) | Web | Starlette / Uvicorn | [Module Guide](../modules/web.md) |
| [FastAPI](fastapi.md) | Web | FastAPI + Uvicorn / Granian | [Module Guide](../modules/web.md) |

## Server Adapter

| Adapter | Module | Backend | Guide |
|---------|--------|---------|-------|
| [Granian](granian.md) | Server | Granian (Rust/tokio ASGI server) | [Module Guide](../modules/server.md) |

## Messaging Adapters

Expand Down
9 changes: 6 additions & 3 deletions docs/adapters/fastapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,17 @@ FastAPI generates OpenAPI schemas from its own route definitions, which means th

## Middleware and Filters

The FastAPI adapter reuses the same `WebFilterChainMiddleware` and built-in filters as the Starlette adapter:
The FastAPI adapter reuses the same `WebFilterChainMiddleware` and built-in filters as the Starlette adapter. Always-active filters:

| Filter | Purpose |
|--------|---------|
| `TransactionIdFilter` | Generates `X-Transaction-ID` for request tracing |
| `RequestContextFilter` | Initializes request-scoped context (runs first) |
| `CorrelationFilter` | Stamps W3C trace context and correlation headers |
| `TransactionIdFilter` | Propagates or generates `X-Transaction-Id` |
| `RequestLoggingFilter` | Logs request method, path, status, and duration |
| `SecurityHeadersFilter` | Adds OWASP security headers |
| `SecurityFilter` | JWT authentication and authorization |

Opt-in filters (registered as beans) such as `SecurityFilter`, `HttpSecurityFilter`, and `CsrfFilter` are auto-discovered and added to the chain when present.

Custom `WebFilter` beans registered in the DI container are auto-discovered and added to the chain, exactly as they are with the Starlette adapter.

Expand Down
8 changes: 4 additions & 4 deletions docs/adapters/granian.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Key characteristics:
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| `pyfly.server.type` | `str` | `"auto"` | Set to `"granian"` to force Granian |
| `pyfly.server.workers` | `int` | `0` | Worker processes (`0` = `cpu_count`) |
| `pyfly.server.workers` | `int` | `1` | Worker processes (`0` also resolves to 1) |
| `pyfly.server.backlog` | `int` | `1024` | TCP listen backlog |
| `pyfly.server.graceful-timeout` | `int` | `30` | Graceful shutdown timeout in seconds |
| `pyfly.server.http` | `str` | `"auto"` | HTTP version (`auto`, `1`, `2`) |
Expand Down Expand Up @@ -99,9 +99,9 @@ pyfly:

Granian is auto-selected when installed because it has the highest priority in the server auto-configuration cascade:

1. `GranianServerAutoConfiguration` -- `@conditional_on_class("granian")` + `@conditional_on_missing_bean(ApplicationServerPort)`
2. `UvicornServerAutoConfiguration` -- only activated if Granian is not installed
3. `HypercornServerAutoConfiguration` -- only activated if neither Granian nor Uvicorn is installed
1. `ServerAutoConfiguration.granian_server` bean -- `@conditional_on_class("granian")` + `@conditional_on_missing_bean(ApplicationServerPort)`
2. `ServerAutoConfiguration.uvicorn_server` bean -- only activated if Granian is not installed
3. `ServerAutoConfiguration.hypercorn_server` bean -- only activated if neither Granian nor Uvicorn is installed

To force Granian explicitly (even when other servers are installed):

Expand Down
8 changes: 4 additions & 4 deletions docs/adapters/kafka.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pyfly:
```python
from pyfly.messaging import message_listener

@message_listener(topic="orders", group_id="order-service")
async def handle_order(self, event: dict) -> None:
print(f"Received order: {event}")
@message_listener(topic="orders", group="order-service")
async def handle_order(msg: Message) -> None:
print(f"Received order: {msg.value}")
```

---
Expand Down Expand Up @@ -61,7 +61,7 @@ Implements `MessageBrokerPort` using `AIOKafkaProducer` and `AIOKafkaConsumer`.

### Consumer Groups

The `group_id` parameter on `@message_listener` maps directly to Kafka consumer groups for load-balanced consumption across instances.
The `group` parameter on `@message_listener` maps directly to Kafka consumer groups for load-balanced consumption across instances.

### Lifecycle

Expand Down
14 changes: 10 additions & 4 deletions docs/adapters/mongodb.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ class OrderRepository(MongoRepository[OrderDocument, str]):

### Beanie Initialization

The adapter calls `initialize_beanie()` at startup to register all document models with the Motor client. Document discovery is automatic via the DI container.
The adapter calls `init_beanie()` at startup to register all document models with the Motor client. Document discovery is automatic via the DI container.

### MongoQueryMethodCompiler

Expand All @@ -77,11 +77,17 @@ Wires compiled query methods onto `MongoRepository` subclasses at startup — id

### Transactions

Use `@mongo_transactional` for multi-document transactions:
Use `@mongo_transactional` for multi-document transactions. The decorator
requires a `Motor` client (injected from the auto-configured bean):

```python
@mongo_transactional
async def transfer(self, from_id: str, to_id: str, amount: float) -> None:
from pyfly.data.document.mongodb import mongo_transactional
from motor.motor_asyncio import AsyncIOMotorClient

client: AsyncIOMotorClient = ... # injected by DI

@mongo_transactional(client)
async def transfer(from_id: str, to_id: str, amount: float) -> None:
...
```

Expand Down
10 changes: 6 additions & 4 deletions docs/adapters/rabbitmq.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pyfly:
```python
from pyfly.messaging import message_listener

@message_listener(topic="orders", group_id="order-service")
async def handle_order(self, event: dict) -> None:
print(f"Received order: {event}")
@message_listener(topic="orders", group="order-service")
async def handle_order(msg: Message) -> None:
print(f"Received order: {msg.value}")
```

---
Expand All @@ -47,6 +47,8 @@ async def handle_order(self, event: dict) -> None:

When `provider` is `"auto"`, PyFly selects the adapter based on which library is installed. If `aio-pika` is found, the RabbitMQ adapter is used.

> **Note:** The exchange name defaults to `"pyfly"` and is not configurable via `pyfly.yaml` in the auto-configured adapter. To customise it, construct `RabbitMQAdapter(url=..., exchange_name=...)` manually as a `@bean`.

---

## Adapter-Specific Features
Expand All @@ -62,7 +64,7 @@ Implements `MessageBrokerPort` using `aio_pika.connect_robust()`.

### Consumer Groups

Consumer groups are mapped to RabbitMQ queues. Multiple instances with the same `group_id` share the queue for competing-consumer load balancing.
Consumer groups are mapped to RabbitMQ queues. Multiple instances with the same `group` share the queue for competing-consumer load balancing.

### Lifecycle

Expand Down
7 changes: 6 additions & 1 deletion docs/adapters/sqlalchemy.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ class OrderRepository(Repository[OrderEntity, int]):
| `pyfly.data.relational.enabled` | `bool` | `false` | Enable the SQLAlchemy adapter |
| `pyfly.data.relational.url` | `str` | `"sqlite+aiosqlite:///pyfly.db"` | Database connection URL |
| `pyfly.data.relational.echo` | `bool` | `false` | Log all SQL statements |
| `pyfly.data.relational.pool_size` | `int` | `5` | Connection pool size |
| `pyfly.data.relational.ddl-auto` | `str` | `"create"` | DDL strategy: `create`, `create-drop`, or `none` |
| `pyfly.data.relational.pool.size` | `int` | *(driver default)* | Connection pool size (`pool_size`) |
| `pyfly.data.relational.pool.max-overflow` | `int` | *(driver default)* | Max overflow connections above pool size |
| `pyfly.data.relational.pool.timeout` | `float` | *(driver default)* | Seconds to wait for a connection from the pool |
| `pyfly.data.relational.pool.recycle` | `int` | *(driver default)* | Seconds before a connection is recycled |
| `pyfly.data.relational.pool.pre-ping` | `bool` | *(driver default)* | Issue a `SELECT 1` ping before each checkout |

### Database URLs by Driver

Expand Down
15 changes: 12 additions & 3 deletions docs/adapters/starlette.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,23 @@ Implements `WebServerPort`. Creates a Starlette `Application` with routes, middl

### WebFilter Chain

`WebFilterChainMiddleware` runs an ordered chain of filters on every request. Built-in filters:
`WebFilterChainMiddleware` runs an ordered chain of filters on every request. Always-active built-in filters:

| Filter | Purpose |
|--------|---------|
| `TransactionIdFilter` | Generates `X-Transaction-ID` for request tracing |
| `RequestContextFilter` | Initializes request-scoped context (runs first) |
| `CorrelationFilter` | Stamps W3C trace context and correlation headers |
| `TransactionIdFilter` | Propagates or generates `X-Transaction-Id` |
| `RequestLoggingFilter` | Logs request method, path, status, and duration |
| `SecurityHeadersFilter` | Adds OWASP security headers |
| `SecurityFilter` | JWT authentication and authorization |

Opt-in filters (registered as beans):

| Filter | Purpose |
|--------|---------|
| `SecurityFilter` | JWT Bearer token authentication |
| `HttpSecurityFilter` | URL-pattern authorization rules |
| `CsrfFilter` | Double-submit cookie CSRF protection |

### OpenAPI & Documentation

Expand Down
Loading
Loading