Skip to content
Merged
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1405,6 +1405,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **generate:** `autumn generate scaffold --searchable title,body` makes the named text fields full-text searchable — it adds `#[searchable]` attributes to the model, `searchable` to the `#[repository]`, a migration adding a `search_vector tsvector GENERATED ALWAYS AS (…) STORED` column plus a GIN index, and a search box on the index wired to `GET /<plural>/search` (an empty `?q` falls back to the plain paginated list). Omitting `--searchable` leaves scaffold output byte-identical; the `--live`/`--live-validation` index variants gate the search box off; naming a non-text/unknown field, a uuid-PK model, or an owner-scoped model fails generation before any files are written (issue #1319).
- **generate:** `autumn generate scaffold post avatar:Attachment` now produces working no-JS file uploads end-to-end — the create/update handlers take an `autumn_web::extract::Multipart` extractor, stream each uploaded file to the `BlobStore` via `field.save_to_blob_store(&*store, key)`, and bind the returned `Blob` from a plain `multipart/form-data` submit. `autumn destroy` also no longer strips the `multipart`/`storage` features when a hand-written route still uses them (part of #1236).
- **cli:** `autumn new <name> --api` scaffolds a JSON-first project — handlers return `Json<…>`, `autumn-web` is pinned `default-features = false` to a lean API feature set (`db`, `cache-moka`, `http-client`, `reporting`, `flash`) that drops the maud/htmx/tailwind view stack, and no `static/` tree, `input.css`, `tailwind.config.js`, vendored assets, or Tailwind CI/README notes are generated (the first `cargo run` serves JSON). `--api` cannot be combined with `--daemon` or `--bundled-pg` but composes with `--with-i18n` and `--with-seed`.
- **cli:** `autumn deploy` — first-class push-button deployment of an Autumn app to your own Linux host over SSH, no Docker (issue #1607). It reads a `[deploy]` config block and splits into four subcommands. `autumn deploy check` runs a preflight (SSH reachability, signing secret, database URL, and pending migrations) and reports pass/fail without touching the server — it does **not** print the plan (#1884); `autumn deploy plan` prints the dry-run systemd unit and ordered rollout plan (#1884); `autumn deploy up` uploads a **prebuilt** release binary — built beforehand by a separate `autumn build --embed` step (→ `target/release/<app>`), failing fast with an actionable error if it is absent (`up` never builds from source) — over an injectable SSH executor into a versioned systemd slot on the host, writes the env file, and starts the app (#1912); subsequent deploys perform a **zero-downtime cutover** via kamal-proxy, running pending migrations against the live database *before* flipping the proxy to the new release slot so a request is never served by an un-migrated build (#1928); and `autumn deploy rollback` — plus automatic rollback when a release fails to come up healthy — restores the previous release slot and secrets in one step (#1937). Deploy runs in the **production** profile by default, overridable through a `[deploy]` profile knob (#1956), and a push-button walkthrough is documented in the deploy guide (#1950).
- **testing:** an end-to-end `autumn deploy` acceptance harness exercises the real ssh/systemd/kamal-proxy release lifecycle against a throwaway container — first deploy, zero-downtime cutover, and rollback end to end (AC-7 of #1607, #1949). [no-plugin]
- **web:** `#[lifecycle]` typed state machines prove your domain lifecycles sound at build time (issue #1675) — annotate an enum with its allowed transitions and the framework generates a typed transition API that makes an illegal state change a compile error, with `autumn lifecycle check` validating the declared graph and `autumn lifecycle diagram` emitting a Mermaid diagram of it (#1916). The `transition_controls` view helper renders a record's currently-legal transitions as accessible no-JS form buttons (part of #1326, #1917). `autumn generate scaffold`'s `:states(...)` marker wires those transitions into the generated scaffold, emitting guarded transition routes and controls (#1935), and a field-level `#[state_machine(lifecycle = SomeEnum)]` can now reference a `#[lifecycle]` enum so the two mechanisms share one source of truth (issue #1911, #1944).
- **cli:** SQLite backend foundation (issue #1614) — Autumn now detects a SQLite `database.url`, maps generator DDL to SQLite column types, and `autumn doctor` understands the backend; features SQLite cannot support are rejected at generate time rather than failing at runtime, and the capability/support matrix is documented in a new backend-support guide (#1918).
- **a11y:** four more typed accessible form primitives join `TextField` (part of #1706) — `TextArea`, `Select` with `SelectOption`, `Checkbox`, and `FileField` each make the accessible name a compile-time obligation the same way, and every primitive gains a `.hx(name, value)` escape hatch for attaching arbitrary `hx-*` (and other) attributes without dropping back to raw `html!` (#1946).
- **generate:** `autumn generate scaffold` now routes every generated form field through the typed `a11y` primitives instead of hand-rolled `html!` (part of #1706) — text inputs through `a11y::TextField` (with a new `TextField::label_class` for the label wrapper) (#1913), constrained `String`/`Text` fields through `a11y::TextArea` (#1953), and the shared `FieldControl` rendering through the typed primitives (#1954); `--live-validation` fields render through the primitives plus `.hx()` for their inline-validation `hx-*` wiring (closes #1951, #1964). Scaffolds are now accessible by construction and pass `autumn a11y verify`.
- **security:** security posture manifest v2 (part of #1627) — the build-time security manifest now wraps its output in a provenance envelope and adds CSRF and security-headers coverage dimensions alongside the route auth classification, so a CI consumer can prove the shipped build's CSRF protection and header policy, not just its route gating (#1879).
- **web:** content-negotiated responses let one handler serve both HTML and JSON (#1881) — a new `Negotiate` extractor/response inspects the request `Accept` header and renders the matching representation, so an endpoint can back both a browser page and an API client without duplicating the handler.
- **generate:** `autumn generate scaffold` gains authorization variants (#1830) and owner-scoped list/search codegen (#1841) — generated resources can emit policy-authorized handler variants and scope their index/search queries to the current user's own rows (#1882).
- **web:** nested `has_many` form binding for atomic master-detail saves (#1915) — `NestedChangesetForm` with `inputs_for`, `seeded`, and `blank` renders and binds a parent plus its child collection from a single submit and persists them in one atomic save, so a form like an order with its line items round-trips without hand-written child wiring.

### Fixed

Expand Down Expand Up @@ -1680,6 +1690,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **generate:** `autumn generate auth`'s browser auth pages now render through the shared 4-arg `crate::layout(title, current_path, flash, content)` — the same helper `autumn new`/scaffold emit — instead of a private bare-DOCTYPE stub; the generator preflights for a shared `pub fn layout` in `src/main.rs` and fails with an actionable message pointing at `autumn new` when it is missing (issue #1353).
- **generate:** scaffolded resources now route every URL through a generated `autumn_web::paths![index, show, new, create, edit, update, delete]` module (plus `events` under `--live` and one `validate_{field}` per validated field under `--live-validation`) instead of hand-written path strings — all view hrefs, form actions, redirects, the SSE `sse-connect`, and inline-validation `hx-post` attributes call `paths::*`, giving each resource's URLs a single source of truth (issue #1133).
- **reliability:** the request-path module set (~25 modules including `form`, `extract`, `idempotency`, session/scheduler/storage/sync, and the middleware stack) is now gated by clippy restriction lints that deny `unwrap`/`expect`/`panic`/`unreachable`/`todo`/`unimplemented`/`indexing_slicing` on non-test builds, and poison-prone locks recover via `unwrap_or_else(PoisonError::into_inner)` rather than panicking — so a poisoned lock or stray unwrap can no longer panic-abort a worker on the request path. A `scripts/check-panic-gate.sh` manifest, run in CI's lint job, keeps the gate from being silently dropped (part of #1611).
- **a11y:** the field DSL now rejects an inline `String`/`Text` length bound greater than `u32::MAX` at parse time (part of #1706, #1913) — an out-of-range `maxlength`/`minlength` constraint that could never be represented in the generated HTML validation attribute is a generate-time error rather than a silently truncated or overflowing value.
- **web:** the htmx form helpers now thread the configured submit-token field name (`[security.submit_token]`) into the hidden field they emit instead of assuming the default `_submit_token`, so a project that renamed the field still gets working one-time-submit protection on helper-rendered forms (#1843, #1883).
- **ci:** CI now discovers Docker-dependent `#[ignore]` database tests dynamically instead of a hard-coded allowlist, so a new testcontainer DB test runs in CI with no workflow edit (#1941). [no-plugin]

### Fixed

Expand Down Expand Up @@ -1723,6 +1736,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
silently skipping the write, and a loom model-check
(`chaos_job_client_loom`) exercises the first-init race across all
interleavings.
- **doctor:** `autumn doctor`'s deploy check now fails on a malformed `previous_secrets` block, matching `autumn deploy check` — the two no longer disagree about whether a deploy config is valid (#1904).
- **cli:** `autumn lifecycle diagram` now module-qualifies node ids so two same-named enums in different modules no longer collide into a single node in the emitted diagram (#1929).
- **doctor:** `autumn doctor` now fails a malformed `[[database.shards]]` entry instead of silently treating it as a no-shards configuration, so a typo in a shard block is surfaced rather than passing the SQLite/single-DB path by accident (#1939).
- **security:** CSRF token extraction from a multipart body now scans only a bounded prefix for the token field and streams the remainder rather than buffering the whole body into memory, closing a memory-exhaustion vector on large uploads; the prefix size is tunable via `security.csrf.token_scan_bytes` (#1887).
- **web:** a multipart part with an empty filename is now treated as ordinary non-file input rather than an uploaded file, so a browser submitting an untouched `<input type=file>` (blank filename) no longer produces a spurious empty blob (fixes #1873, #1878).
- **generate:** scaffolded create/update handlers now delete already-uploaded blobs when the handler returns early (e.g. on a validation failure) instead of orphaning them in the blob store (#1888).
- **config:** the startup schema walk no longer aborts when it hits a `statement_timeout`; strict schema enforcement rolls out warn-first, and a new `strict_config_enforce_all` knob opts into failing on every strict finding rather than warning (#1914).
- **security:** tenant-isolation fixes for the repository layer (#1962) — a cross-tenant `update` targeting a foreign or missing id now returns a 404 rather than a 500, and a bulk upsert silently filters out cross-tenant rows for non-versioned records instead of writing across the tenant boundary.

## [0.6.0] - 2026-06-30

Expand Down
19 changes: 16 additions & 3 deletions docs/guide/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,22 @@ below and are better fits in specific cases:
[How the production image works](#how-the-production-image-works)) — a
portable OCI image you run on Kubernetes, ECS, Nomad, or any Docker host.

> **HTTPS/TLS.** kamal-proxy fronts your app on the public port. TLS termination
> and ACME certificate issuance are covered in the TLS guide (tracked in
> [#1860](https://github.com/madmax983/autumn/issues/1860)).
> **HTTPS/TLS.** kamal-proxy fronts your app on the public port, but as
> configured by `autumn deploy` today it listens on plain **HTTP** and does
> **not** provision a TLS certificate — so following this path as shipped serves
> HTTP on the public port. To serve HTTPS on the deploy path, place an
> **external TLS terminator in front of** the deploy-managed kamal-proxy: a
> TLS-terminating load balancer or reverse proxy that owns the certificate and
> forwards plain HTTP to the kamal-proxy public port. The deploy-managed
> kamal-proxy is HTTP-only — `autumn deploy` runs it as `kamal-proxy run
> --http-port` and issues `kamal-proxy deploy --target --health-check-path` with
> no `--host`/`--tls`, so it can't create or preserve TLS on that proxy. Don't
> enable in-process
> `[server.tls]`/ACME on a deploy-managed app — deploy binds each slot to a
> private loopback HTTP port that the readiness gate and kamal-proxy target over
> plain HTTP, so a TLS listener there breaks its health checks. See the [TLS &
> HTTPS guide](./tls.md) for the full picture, including in-process TLS for
> self-run apps.

> **Version.** The `autumn deploy` subcommands (`check` / `plan` / `up` /
> `rollback`) are newer than the `autumn-cli 0.5.0` pinned under
Expand Down
Loading
Loading