Function Registration History
Every function update, status change, rollback, and deletion is recorded as an immutable entity event on the ironflow:fn:{id} stream. This gives you a full audit trail of configuration changes with per-version snapshots, actor attribution, and change reasons.
Write Flows
Section titled “Write Flows”Register / Update Function
Section titled “Register / Update Function”Client │ │ RegisterFunction(id, config, change_reason) ▼Handler.RegisterFunction │ ├─[new]──► store.CreateFunction(fn, snapshot) ← single transaction │ ├─ INSERT INTO functions (version=1) │ └─ INSERT INTO events │ entity_id = "ironflow:fn:{id}" │ entity_type = "function" │ entity_version = 1 │ name = "FunctionCreated" │ data = { snapshot of initial config, change_type = "created" } │ └─[update]─► snapshot post-update config (state AT new version) │ ▼ store.UpdateFunction(fn, snapshot) ← single transaction │ ├─ SELECT MAX(entity_version) │ FROM events │ WHERE entity_id = "ironflow:fn:{id}" │ ├─ INSERT INTO events │ entity_id = "ironflow:fn:{id}" │ entity_type = "function" │ entity_version = prev + 1 │ name = "FunctionUpdated" │ data = { snapshot of new config } │ └─ UPDATE functions SET ... WHERE id = ? │ ▼ engine.NotifyFunctionUpdated(ctx, fn) engine.SyncFunction(ctx, fn)Update Function Status
Section titled “Update Function Status”Same transactional path as a config update, with change_type = "status_change".
Delete Function
Section titled “Delete Function”DeleteFunction(id) │ ├─ 1. GetFunction(id) ← capture final state │ ├─ 2. store.UpdateFunction(fn, snapshot) │ name = "FunctionDeleted" │ change_type = "delete" │ └─► entity event persists after row is gone │ └─ 3. store.DeleteFunction(id) ← row deleted, event survivesThe deletion snapshot is written before the row is removed so the final configuration remains queryable through ListFunctionHistory even after the function no longer exists.
Read Flows
Section titled “Read Flows”List Function History
Section titled “List Function History”ListFunctionHistory(fn_id, limit, from_version) │ ▼store.ListEntityEvents( entity_id = "ironflow:fn:{fn_id}", direction = "backward", ← newest first BeforeVersion = from_version, ← exclusive backward cursor (proto field `from_version` maps here) limit = limit + 1 ← +1 to detect has_more) │ ▼events table rows │ └─► for each row: json.Unmarshal(data) → FunctionConfigSnapshot │ ▼[]FunctionHistoryEntry { entity_version, snapshot, actor_id, change_reason, change_type }
has_more = len(results) > limitEntries are returned newest-first. The proto field from_version maps to opts.BeforeVersion (an exclusive backward cursor). Pass the lowest entity_version from the previous page to fetch the next.
Get Function at Version
Section titled “Get Function at Version”GetFunctionAtVersion(fn_id, version) │ ▼store.ListEntityEvents( entity_id = "ironflow:fn:{fn_id}", FromVersion = version, ← point lookup at this exact version limit = 1, direction = "forward") │ ├─[not found or version mismatch]──► CodeNotFound └─[found]──► FunctionHistoryEntryRollback Flow
Section titled “Rollback Flow”RollbackFunction(fn_id, target_version, change_reason) │ ├─ 1. GetFunction(fn_id) │ currentFn ← current live config │ ├─ 2. GetFunctionAtVersion(target_version) │ snapshot.Function ← old config to restore │ └─ guard: reject if snapshot.Status == archived │ ├─ 3. Reconstruct fn from snapshot │ fn.ID = currentFn.ID │ fn.Version = currentFn.Version + 1 │ fn.EnvironmentID = currentFn.EnvironmentID │ ├─ 4. Build rollback snapshot (state AT new version = restored config) │ { │ Function: fn, ← restored config (state at new version) │ ChangeType: "rollback", │ ChangeReason: "rollback to v{N}" │ } │ ├─ 5. store.UpdateFunctionVersioned(fn, currentFn.Version, snapshot) │ CAS: WHERE id = ? AND version = ? │ ├─[version conflict]──► CodeAborted (retry) │ └─[ok]──► same atomic transaction as write flow │ entity event written, function row updated │ ├─ 6. engine.SyncFunction(ctx, fn) └─ 7. engine.NotifyFunctionUpdated(ctx, fn)Rollback is itself recorded as a new history entry, so the audit trail shows both the intent and the resulting config change.
Data Model
Section titled “Data Model”History events are rows in the shared events table, namespaced under the reserved ironflow: entity ID prefix. User-defined entity streams cannot use this prefix.
events table┌──────────────────┬──────────────┬────────────────┬──────────────────────┐│ entity_id │ entity_type │ entity_version │ name │├──────────────────┼──────────────┼────────────────┼──────────────────────┤│ ironflow:fn:abc │ function │ 1 │ FunctionCreated ││ ironflow:fn:abc │ function │ 2 │ FunctionUpdated ││ ironflow:fn:abc │ function │ 3 │ FunctionDeleted ││ user:order:xyz │ order │ 1 │ OrderPlaced │ ← user stream└──────────────────┴──────────────┴────────────────┴──────────────────────┘Each data column is a FunctionConfigSnapshot JSON blob containing:
| Field | Description |
|---|---|
function | Full function config as of this version (state AT this entity_version, not before it) |
actor_id | API key or user that triggered the change |
change_reason | Optional free-text label (e.g. "deploy v2.1.0") |
change_type | created | update | status_change | rollback | delete |
snapshot_version | 0 (absent) = legacy pre-change semantics; 1 = current post-change semantics |
API Reference
Section titled “API Reference”| RPC | Description |
|---|---|
RegisterFunction | Pass change_reason to annotate the history entry |
ListFunctionHistory | Paginated history, newest-first, keyset via from_version (maps to BeforeVersion). limit defaults to 50, capped at 200. |
GetFunctionAtVersion | Fetch snapshot at a specific entity_version |
RollbackFunction | Restore a prior version; recorded as a rollback entry |