Production handbook
Tenchi keeps production infrastructure outside the framework core, but it gives each concern a defined place. Process resources live in lifespan, request resources live in the context scope, external systems sit behind application-owned ports, and operational entrypoints call the same use cases as HTTP.
This handbook turns that model into concrete recipes for a service that needs to survive retries, concurrent writes, partial failures, and deployment changes.
What Tenchi owns
Tenchi provides the application seams and boundary guarantees:
| Concern | Tenchi's part | Your application's part |
|---|---|---|
| Configuration | Explicit composition and lifespan state | Load and validate environment-specific values |
| Database | Lifespan and request-scoped context managers | Choose a driver, migrations, transaction isolation, and adapters |
| Authentication | Boundary hooks and public-contract metadata | Verify credentials and supply the identity port |
| Authorization | Plain use cases and pure policies | Define abilities and owner-scoped repository methods |
| Retries | Canonical fingerprints, durable store transitions, typed replay, and declared errors | Implement storage in the command transaction and choose key scope and retention |
| Rate limiting | Atomic fixed-window store protocol, policy validation, and a standard 429 | Choose authenticated scope, shared storage, transaction semantics, and edge limits |
| Inbound webhooks | Exact-body verifier bindings, required composition, request limits, and typed validation | Verify the provider protocol, attach service identity, enforce replay rules, and store event ids |
| Background work | Validated job messages, handler bindings, dispatch, and scoped contexts | Choose a queue or outbox, schedule workers, and define retry policy |
| Operational maintenance | Validated named tasks, CLI/MCP discovery, and scoped execution | Define safe dry runs, operator access, and rollout procedure |
| Observability | Finalized outcomes plus an optional OpenTelemetry bridge | Configure the SDK, transport instrumentation, exporters, alerts, and retention |
| Deployment | Health routes, request limits, deadlines, tenchi check, and environment preflight | Configure the ASGI server, proxy, secrets, migrations, dependency credentials, and rollout |
Tenchi does not bundle an ORM, queue, scheduler, telemetry SDK, or settings package. Those libraries remain replaceable adapters. The handbook defines how they participate in the application lifecycle and failure model.
Build the production boundary
Use the following order when turning a working Tenchi application into a deployed service:
- Validate configuration and secrets once at startup.
- Open process resources and one transaction per request.
- Put outbound SDKs, repositories, clocks, and identity lookups behind ports.
- Make retried commands idempotent and defer external effects through a durable worker boundary.
- Apply authenticated operation quotas and configure edge limits.
- Verify inbound webhook bytes and collapse provider redeliveries.
- Emit low-cardinality request and worker telemetry.
- Declare read-only checks for the target environment.
- Configure health, limits, middleware, and the release gate.
Authentication and authorization have their own boundary-to-policy workflow. Testing follows the same resource model: use memory adapters for application behavior, then exercise real transactions and lifespan in integration tests.
Choose a consistency requirement before an adapter
A port should say what its caller needs, not which vendor implements it. A command repository normally needs strong reads and writes in the current transaction. A search port can explicitly permit stale results and use a read replica. A notification port can promise only that work was durably accepted, not that an email was delivered during the request.
Keep those meanings visible in method names and docstrings. Wiring can then change from SQLite to PostgreSQL, an in-process adapter to a service client, or a primary connection to a replica without silently weakening a use case.
Define the failure owner
For every boundary, decide which component owns each outcome:
- A contract owns valid HTTP inputs, outputs, and declared application errors.
- A request context owns commit or rollback.
- A use case owns business rejection through
AppError. - Tenchi job primitives validate producer messages, consumer input, and handler results.
- A worker owns acknowledgement, retry, dead-lettering, and backoff.
- A deployment process owns migrations and compatibility with the previous release.
- An observer reports an outcome but never changes it.
This avoids ambiguous failures such as retrying invalid payloads forever, committing state before its outbox record, or treating a logging outage as an API failure.
Production baseline
Before the first deployment, verify that the service has:
- validated startup configuration with no secret values in logs;
- graceful acquisition and cleanup for every pool and SDK client;
- commit-on-success and rollback-on-error request scopes;
- an explicit migration step and rollback-compatible deployment plan;
- idempotency for commands callers or infrastructure can retry;
- shared, atomic rate-limit storage plus gateway limits for unauthenticated traffic;
- exact-body verification, timestamp checks, and idempotency for inbound webhooks;
- retry and dead-letter rules for every background handler;
- trusted request IDs, bounded-cardinality telemetry, and actionable alerts;
- readiness checks for dependencies required to serve traffic;
- body-size limits and operation deadlines appropriate to the API;
- a read-only
tenchi preflightgate in the target environment; tenchi verify --base-ref <release-ref>for checks, strict architecture evidence, and OpenAPI and application-tool comparisons against one immutable release baseline.
The deployment guide turns this list into the final release sequence.