# PiCloud Changelog ## v1.1.1 — Storage & Events (unreleased) The triggers framework — KV store + universal outbox + dispatcher + NATS-style sync HTTP + per-route async dispatch + dead-letter handling + dashboard surface. Every subsequent v1.1.x service module (docs, files, pubsub, …) hangs off the dispatcher built here. ### Added - **KV store** — `kv_entries` table keyed `(app_id, collection, key)` with JSONB values. Rhai SDK exposes the handle pattern: `kv::collection(name).{get,set,has,delete,list}`. Cursor-style pagination with opaque base64 cursors. Cross-app isolation enforced via `cx.app_id` (never script-passed). - **Triggers framework (Layout E)** — parent `triggers` table + per-kind detail tables (`kv_trigger_details`, `dead_letter_trigger_details`). Trigger CRUD admin endpoints (`/api/v1/admin/apps/{id}/triggers/{kv,dead_letter}`) + `Capability::AppManageTriggers(AppId)`. - **Universal outbox + dispatcher** — single tokio task that polls the outbox via `FOR UPDATE SKIP LOCKED`, routes due rows to the executor through the shared `ExecutionGate`. Retry with exponential backoff + ±jitter; on exhaustion, dead-letter. - **NATS-style sync HTTP via outbox** — `InboxRegistry` (in-process oneshot map) lets the orchestrator await dispatcher delivery on every sync HTTP request. Cluster mode (v1.3+) swaps this for `LISTEN/NOTIFY` behind the same `InboxResolver` trait. - **`dispatch_mode: async` on routes** — `POST` to a route with `dispatch_mode = 'async'` returns `202 Accepted` immediately; the script runs via the dispatcher (with retries / dead-letter). - **Dead-letter handling** — separate `dead_letters` table per design notes §4. `dead_letters::{replay,resolve}` Rhai SDK + admin endpoints + `Capability::AppDeadLetterManage(AppId)`. Recursion-stop rule: dead-letter handler failures annotate the original row as `resolution = 'handler_failed'` and never produce a new dead-letter or retry. - **Dashboard surface for dead letters** — unresolved-count red badge on the apps list + per-app page; per-app dead-letters list view at `/admin/apps/{slug}/dead-letters` with Replay + Mark resolved per-row actions and expandable payload detail. - **`abandoned_executions` table** — forensic row written by the dispatcher when it tries to resolve an inbox the orchestrator already abandoned (timed out). Counter metric path reserved. - **Trigger-depth limit** — `cx.trigger_depth > max_trigger_depth` (default 8) skips execution + logs; does NOT dead-letter (depth-exceeded means "you built a loop"). - **GC sweepers** — weekly retention sweeps for `dead_letters` (30 days) and `abandoned_executions` (7 days), both with `FOR UPDATE SKIP LOCKED` for cluster-mode safety. - **Env-overridable trigger config** — `TriggerConfig::from_env` reads `PICLOUD_MAX_TRIGGER_DEPTH`, `PICLOUD_TRIGGER_RETRY_*`, `PICLOUD_DEAD_LETTER_RETENTION_DAYS`, `PICLOUD_ABANDONED_EXECUTIONS_RETENTION_DAYS`. ### Changed - **Workspace version**: `1.1.0` → `1.1.1`. - **Rhai SDK version**: `1.1` → `1.2` (additive — every v1.1 script still runs unchanged; new surfaces: `kv::*`, `dead_letters::*`, `ctx.event` for triggered handlers). - **Dashboard version**: `0.6.0` → `0.7.0` for the dead-letters UI. - **`Services` bundle** — replaces v1.1.0's no-arg `Services::new()` with explicit `Services::new(kv, dead_letters, events)`. Tests use `Services::default()` for an all-noop bundle. - **`SdkCallCx`** grows `is_dead_letter_handler: bool` and `event: Option` fields. - **`ExecRequest`** mirrors the new `SdkCallCx` fields and grows `event` for serializable trigger payload transport. - **Routes table** grows `dispatch_mode TEXT NOT NULL DEFAULT 'sync'` (CHECK in {sync, async}). - **Schema version**: 6 → 12 (migrations 0007 through 0012). ### Migrations - `0007_kv.sql` — `kv_entries` table + index - `0008_triggers.sql` — `triggers` + `kv_trigger_details` + `dead_letter_trigger_details` - `0009_outbox.sql` — universal `outbox` table + due-row partial index - `0010_dead_letters.sql` — `dead_letters` table + unresolved partial index + GC index - `0011_abandoned_executions.sql` — forensic table + GC index - `0012_routes_dispatch_mode.sql` — `routes.dispatch_mode` column ## v1.1.0 — Foundation & Standard Library See `docs/v1.1.x-design-notes.md` §7 for the full v1.1.x roadmap.