Overview
Start Here
Installation
Tutorial
Architect App Builder
Todo List App
Beacon Beats Audio Store
UCAL App
Authoring
Dynamic Apps
Static Apps
dev_docs
Why Pharos Feels Different
Architect Builder
Framework
Artifacts & Layout
Configuration
Outbound Email
How to Use CLI
Contracts
YAML Authoring
Action Hooks and Middleware
Feature Transaction Primitives
Generated Surfaces
Declarative CRM
Input Validation
Identity and Tenancy
UI Surface Library
Social Connections
Payment Provider Management
Integration Adapters
Reference
Contract, UI, and Surface Reference
Styling UI Elements
Architect Media Artifacts
API Docs
Use Cases
Dynamic SPAs
Generated Admin and APIs
Scheduling and Marketplaces
Multi-App Hosting
Release Notes
Vision
Pharos Framework

← Back

Feature Transaction Primitives

Pharos provides a bounded set of framework-owned transaction primitives for common record, scope, reservation, and status workflows. Apps declare these primitives in contracts. The shared runtime executes them.

Available primitives

  • append_record
  • set_root_fields
  • update_record
  • append_records_from_input_list
  • append_records_from_related_collection
  • scoped_reassignment
  • bulk_update
  • replace_ordered_child_set
  • delete_records_by_scope
  • generated soft delete and restore
  • aggregate guards
  • reserve
  • confirm
  • release
  • approval transition
  • scoped status transition
  • derived or summary upsert

Where to look

  • generated soft delete and restore — ucal
  • aggregate guards before commit — commerce_spa
  • reservation and release — commerce_spa
  • parent plus many-child create — dynamic_app
  • relation-derived row creation — dynamic_app
  • scope-wide reassignment or update — dynamic_app
  • ordered child-set replacement — dynamic_app
  • status and approval transitions — dynamic_app

Append one record

Use append_record when one action should create one record through a declared field map.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • one action creates one new record
  • next_id, input, literal, and anchor-derived values are applied by the shared runtime

Set root fields

Use set_root_fields when an action should update top-level summary state after the main mutation.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Expected result:

  • the action updates a predictable top-level summary surface such as last_action
  • the app does not need post-mutation glue for that update

Update one matched record

Use update_record when one action should update one matched record by a declared key.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Expected result:

  • one matching record is updated
  • unmatched ids fail closed instead of mutating the wrong row

Append many records from one input list

Use append_records_from_input_list when one submitted list should create many child rows without an app-owned loop.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • one parent action expands one submitted list into many child rows
  • overflow either truncates with explicit skipped work or fails closed, depending on the declared contract

Append many records from a related collection

Use append_records_from_related_collection when one action should derive new rows from a matched related collection.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Expected result:

  • matched related rows are copied through a declared record contract
  • source-field mapping stays framework-owned and bounded

Scoped reassignment

Use scoped_reassignment when one action should rewrite one target field across a matched scope.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Expected result:

  • only rows in the matched scope are rewritten
  • overflow handling follows the declared bound

Bounded bulk update

Use bulk_update when one action should apply one declared field-update set across all rows in a matched scope.

Working examples:

  • apps/dynamic_app/data/contracts/actions.yml
  • apps/dev_docs/data/contracts/actions.yml

Expected result:

  • all allowed matching rows receive the declared updates
  • oversized matched scopes fail closed before partial mutation

Scoped delete by matched boundary

Use delete_records_by_scope when one action should remove rows across one declared scope without app-owned loops.

Runtime behavior:

  • matches rows by one declared scope field and one submitted input
  • counts the full matched set before mutation
  • fails closed when the matched scope exceeds max_records and overflow_policy is fail
  • removes rows and reports matched, removed, and skipped counts when the contract allows the operation

Working example:

  • apps/dynamic_app/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • strict overflow denial returns the declared validation failure before deletion
  • bounded purge removes the matched rows and reports final counts

Ordered child-set replace

Use replace_ordered_child_set when one parent-scoped action should replace a full ordered child collection in one bounded operation.

Runtime behavior:

  • matches one child collection by parent or scope field
  • updates existing rows in deterministic order
  • creates missing rows when the input list is longer than the current set
  • removes trailing rows when the input list is shorter than the current set
  • reports matched, created, updated, removed, and skipped counts

Working example:

  • apps/dynamic_app/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • the scoped child set is rewritten in order through one action
  • existing rows are updated before new rows are created
  • surplus scoped rows are removed
  • overflow can be truncated and reported as skipped work

Generated soft delete and restore

Use generated soft delete and restore when the entity is soft-deletable and operators need reversible removal.

Runtime behavior:

  • derives delete and restore routes for generated admin and generated API surfaces
  • hides inactive records where the generated surface contract requires it
  • restores the record through the shared runtime instead of app-local routes

Working examples:

  • apps/ucal/data/contracts/routes.yml
  • apps/ucal/data/contracts/actions.yml

Validation:

bin/pharos build app ucal --build-dir dist
sh scripts/check.sh ucal tenant-api

Expected result:

  • generated delete works
  • generated restore works
  • restored records become active again

Negative-path rule:

  • hard-delete entities do not receive restore behavior

Aggregate guards

Use aggregate guards when the app should reject a mutation based on bounded counts, sums, or existence checks before commit.

Working example:

  • apps/commerce_spa/data/features/cart.yml

Validation:

bin/pharos build app commerce_spa --build-dir dist
sh scripts/check.sh commerce-spa postgresql-runtime

Expected result:

  • over-cap mutations are rejected
  • the message comes from the declared contract
  • valid checkout and download flows still succeed

Reservation, confirm, and release

Use reserve, confirm, and release when the app needs a bounded hold before final commit.

Typical uses:

  • inventory reservation
  • booking slot holds
  • temporary entitlement claims
  • temporary capacity claims

Working examples:

  • apps/commerce_spa/data/features/cart.yml
  • apps/dynamic_app/data/contracts/actions.yml

Validation:

bin/pharos build app commerce_spa --build-dir dist
sh scripts/check.sh commerce-spa postgresql-runtime
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • reserve succeeds when capacity is available
  • reserve fails with a structured conflict when capacity is exhausted
  • release clears the held row
  • confirm advances the held row without app-local transaction code

Scoped status transition

Use scoped status transition when one action should move a bounded set of matching records from one declared status family to another.

Runtime behavior:

  • matches one declared scope
  • checks allowed from_statuses
  • writes the target status
  • can also write workflow-state or timestamp fields when the contract declares them

Working example:

  • apps/dynamic_app/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • all matching records move through the declared transition
  • the action report distinguishes matched, updated, and skipped work

Approval transition

Use approval transition when the app needs a submit, approve, or reject flow with consistent approver capture and reporting.

Working example:

  • apps/dynamic_app/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • approval requests can be submitted
  • approval requests can be approved
  • rejection captures the declared reason and actor fields

Derived or summary upsert

Use derived or summary upsert when an action should materialize one framework-owned summary or snapshot row from matched runtime data.

Working example:

  • apps/dynamic_app/data/contracts/actions.yml

Validation:

bin/pharos build app dynamic_app --build-dir dist
sh scripts/check.sh dynamic-app native-runtime

Expected result:

  • the shared runtime computes and persists the summary row
  • the app does not need bespoke glue code for the repeated pattern

When not to use these primitives

Do not use these primitives when the behavior:

  • depends on hidden app-owned imperative code
  • needs arbitrary database logic outside the bounded contract
  • cannot be explained with one app-owned declaration and one shared runtime rule

At that point the framework contract should be widened deliberately instead of hiding app logic behind a nominally shared primitive.

Related references

  • Extension seams
  • Action hooks and route middleware
  • Generated surfaces

Relative server timestamps

Declared query filter values can use {server_time_offset_seconds: -2592000} to select a UTC timestamp thirty days before the current server time. The expression accepts exactly one integer offset between minus and plus 366 days. It cannot execute code or select a browser-provided clock. Filters continue through the generic database predicate interface. For example, an app can combine operator: gte with this value to display upcoming records and the previous thirty days while retaining older records for administration.