Contracts and traits
A contract is a Rust trait plus the types it needs. It says what a capability does. It must not know SQL, HTTP, HTML, or a concrete provider.
The framework keeps contracts small and places each one with the layer that owns it.
Traits by concern
| Concern | Traits | Defined in |
|---|---|---|
| Application lifecycle | Module, Worker, Runtime, Shutdown, TaskSpawner, Probe | iet-app |
| Calls and validation | UseCase, Validate, Session, SessionFactory, Operation, Authorizer | iet-core |
| Persistence | Persistent, TransactionSession, QueryField | iet-core, iet-db |
| Configuration | ConfigSource, Config | iet-config |
| Authentication | Authenticate, TokenIssuer, Csrf, ProfileStore | iet-auth |
| Authorization | Authorizer, RoleStore, AccessStore | iet-authz |
| Caching | Cache | iet-cache |
| Database lifecycle | Database, Migrations | iet-db |
| Rate limiting | RateLimit | iet-rate-limit-core |
| Object storage | object and stream ports | iet-storage |
| Telemetry | operation identities and recording | iet-telemetry |
The exact signatures are on each crate page. This page explains why the traits are split this way.
Calls: access before validation
iet-core combines the call context, input validation, and access checks:
// In a service entrypoint.
.await?;
operation::check reads the operation's ACCESS, performs the identity or
Authorizer step it requires, and only then calls Validate::validate.
sequenceDiagram
participant S as "Service"
participant K as "operation::check"
participant A as "Authorizer"
participant V as "Validate"
S->>K: "check Operation input"
K->>K: "read Operation::ACCESS"
alt Permission
K->>A: "authorize context permission"
A-->>S: "AppResult"
end
K->>V: "validate input"
V-->>K: "AppResult"
K-->>S: "AppResult"Unauthorized input is never validated, so validation cannot leak information or run side effects for a denied caller.
CallContext is claimed trust, not verified trust. Authenticate at the edge,
then carry the Principal inward. See
Calls and transactions for CallScope,
transactions, and cancellation rules.
Persistence: contracts without SQL types
iet-db defines database lifecycle and reviewed migrations without importing
driver SQL types. A provider such as iet-db-timescale
implements the session and transaction traits and owns migrations.
A repository port may have an associated Session type. That lets storage
require a database session without leaking a concrete database into the contract.
Dependency direction
core ← features ← integrations ← stacks ← applications
- Core defines traits and neutral types. It selects nothing.
- Feature crates provide one concrete mechanism, such as a transport, store, runtime, or policy.
- Integration crates bind one transport or storage engine to a contract.
- Stacks compose lower layers into a preset.
- Applications select concrete types in the composition root.
A contract never imports a provider. An adapter and an implementation both depend on the contract, not on each other. See How your application is shaped for the same rule in application code.