pub struct ServiceDef {Show 18 fields
pub name: String,
pub display_name: Option<String>,
pub description: Option<String>,
pub fields: Vec<FieldDef>,
pub actions: Vec<ActionDef>,
pub guards: Vec<GuardDef>,
pub relationships: Vec<RelationshipDef>,
pub intent_hints: Vec<IntentHint>,
pub state_machine: Option<StateMachine>,
pub mcp_exposed: bool,
pub tenant_column: Option<String>,
pub mcp_ability: Option<String>,
pub creatable: bool,
pub updatable: bool,
pub deletable: bool,
pub mcp_write_ability: Option<String>,
pub table: Option<String>,
pub soft_delete_column: Option<String>,
}Expand description
A service definition describing a domain entity and its fields.
Constructed via a builder API with method chaining:
use ferro_projections::{ServiceDef, DataType, FieldMeaning};
let order = ServiceDef::new("order")
.display_name("Order")
.description("Manages customer orders")
.field("id", DataType::Integer, FieldMeaning::Identifier)
.field("total", DataType::Float, FieldMeaning::Money)
.optional_field("notes", DataType::String, FieldMeaning::FreeText);Fields§
§name: String§display_name: Option<String>§description: Option<String>§fields: Vec<FieldDef>§actions: Vec<ActionDef>§guards: Vec<GuardDef>§relationships: Vec<RelationshipDef>§intent_hints: Vec<IntentHint>§state_machine: Option<StateMachine>§mcp_exposed: boolWhether this projection is exposed as an MCP tool.
Defaults to false. Only projections with mcp_exposed: true
appear in a tools/list response.
tenant_column: Option<String>FK column name used to scope reads to a tenant. Plain metadata read by ferro-mcp-server dispatch; no auth dependency here.
mcp_ability: Option<String>Gate ability required to call this projection via MCP. Plain metadata read by the app’s MCP handler; no auth dependency here.
creatable: boolWhether create_<svc> is derived for this projection (Track A).
Enabling any CRUD write verb requires mcp_write_ability (see validate).
updatable: boolWhether update_<svc> (data-field patch) is derived for this projection.
deletable: boolWhether delete_<svc> (soft-delete, confirmation-gated) is derived.
mcp_write_ability: Option<String>Gate ability required to call the create/update/delete tools.
Required when any of creatable/updatable/deletable is set.
table: Option<String>Backing table name for derived CRUD dispatch (field→column binding).
When None, the dispatch layer derives it from the service name.
soft_delete_column: Option<String>Soft-delete column name. When None, the dispatch layer defaults to deleted_at.
Implementations§
Source§impl ServiceDef
impl ServiceDef
Sourcepub fn new(name: impl Into<String>) -> Self
pub fn new(name: impl Into<String>) -> Self
Creates a new service definition with the given name.
Sourcepub fn display_name(self, name: impl Into<String>) -> Self
pub fn display_name(self, name: impl Into<String>) -> Self
Sets the human-readable display name.
Sourcepub fn description(self, desc: impl Into<String>) -> Self
pub fn description(self, desc: impl Into<String>) -> Self
Sets the service description.
Sourcepub fn mcp_exposed(self, exposed: bool) -> Self
pub fn mcp_exposed(self, exposed: bool) -> Self
Marks this projection as MCP-exposed.
Sourcepub fn tenant_column(self, col: impl Into<String>) -> Self
pub fn tenant_column(self, col: impl Into<String>) -> Self
Declares the FK column name used to scope reads to a tenant. Plain metadata read by ferro-mcp-server dispatch; no auth dependency here.
Sourcepub fn mcp_ability(self, ability: impl Into<String>) -> Self
pub fn mcp_ability(self, ability: impl Into<String>) -> Self
Declares the Gate ability required to call this projection via MCP. Plain metadata read by the app’s MCP handler; no auth dependency here.
Sourcepub fn creatable(self, yes: bool) -> Self
pub fn creatable(self, yes: bool) -> Self
Enables derivation of create_<svc>. Requires mcp_write_ability (Track A).
Sourcepub fn updatable(self, yes: bool) -> Self
pub fn updatable(self, yes: bool) -> Self
Enables derivation of update_<svc> (data-field patch). Requires mcp_write_ability.
Sourcepub fn deletable(self, yes: bool) -> Self
pub fn deletable(self, yes: bool) -> Self
Enables derivation of delete_<svc> (soft-delete, confirmation-gated).
Requires mcp_write_ability.
Sourcepub fn mcp_write_ability(self, ability: impl Into<String>) -> Self
pub fn mcp_write_ability(self, ability: impl Into<String>) -> Self
Declares the Gate ability required to call create/update/delete tools.
Sourcepub fn table(self, table: impl Into<String>) -> Self
pub fn table(self, table: impl Into<String>) -> Self
Declares the backing table for derived CRUD dispatch (field→column binding).
Sourcepub fn soft_delete_column(self, col: impl Into<String>) -> Self
pub fn soft_delete_column(self, col: impl Into<String>) -> Self
Declares the soft-delete column (defaults to deleted_at when unset).
Sourcepub fn resolved_table(&self) -> String
pub fn resolved_table(&self) -> String
Returns the backing table name: explicit .table() value or the
default format!("{}s", name.to_lowercase()).
Matches the inline derivation previously at dispatch.rs:123 — the default MUST stay byte-identical or existing projections query the wrong table.
Sourcepub fn resolved_soft_delete_column(&self) -> &str
pub fn resolved_soft_delete_column(&self) -> &str
Returns the soft-delete column name: explicit .soft_delete_column() value
or the default "deleted_at".
Sourcepub fn is_server_injected_field(&self, field: &FieldDef) -> bool
pub fn is_server_injected_field(&self, field: &FieldDef) -> bool
Returns true if the field must be server-injected and never an agent input.
Covers:
- Identifier fields (primary key — set by DB auto-increment)
- CreatedAt fields (set by DB DEFAULT current_timestamp)
- The tenant column (injected from McpContext, never from agent payload)
This is the schema-derivation boundary Phase 240 consumes to exclude these fields from derived write input schemas (T-239-01 mitigation substrate).
Sourcepub fn is_write_excluded_field(
&self,
field: &FieldDef,
exclude_sm_status: bool,
) -> bool
pub fn is_write_excluded_field( &self, field: &FieldDef, exclude_sm_status: bool, ) -> bool
Returns true if a field must be excluded from write input schemas
(create and update). Composes Self::is_server_injected_field and adds
UpdatedAt, Sensitive, and list-field exclusions.
exclude_sm_status: callers pass self.state_machine.is_some(); when true,
a Status field is also excluded because the StateMachine sets it server-side
to the initial state.
Sourcepub fn field(
self,
name: impl Into<String>,
data_type: DataType,
meaning: FieldMeaning,
) -> Self
pub fn field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self
Adds a required read-write field.
Sourcepub fn field_with_hint(
self,
name: impl Into<String>,
data_type: DataType,
meaning: FieldMeaning,
hint: RenderHint,
) -> Self
pub fn field_with_hint( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, hint: RenderHint, ) -> Self
Adds a required read-write field carrying a non-visual RenderHint.
Use for Url/ImageUrl fields whose raw value has no useful text form:
RenderHint::AltText(s) substitutes s, RenderHint::Skip omits the
field from non-visual output. The visual renderer ignores the hint.
Sourcepub fn optional_field(
self,
name: impl Into<String>,
data_type: DataType,
meaning: FieldMeaning,
) -> Self
pub fn optional_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self
Adds an optional (nullable) read-write field.
Sourcepub fn list_field(
self,
name: impl Into<String>,
data_type: DataType,
meaning: FieldMeaning,
) -> Self
pub fn list_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self
Adds a required read-write list field.
Sourcepub fn read_only_field(
self,
name: impl Into<String>,
data_type: DataType,
meaning: FieldMeaning,
) -> Self
pub fn read_only_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self
Adds a required read-only field (readable but not writable).
For system-assigned or computed fields like id, created_at, or totals.
Sourcepub fn write_only_field(
self,
name: impl Into<String>,
data_type: DataType,
meaning: FieldMeaning,
) -> Self
pub fn write_only_field( self, name: impl Into<String>, data_type: DataType, meaning: FieldMeaning, ) -> Self
Adds a required write-only field (writable but not readable).
For sensitive inputs like passwords or API keys that should not be read back.
Sourcepub fn relationship(self, rel: RelationshipDef) -> Self
pub fn relationship(self, rel: RelationshipDef) -> Self
Adds a relationship definition to this service.
Sourcepub fn belongs_to(
self,
name: impl Into<String>,
target: impl Into<String>,
) -> Self
pub fn belongs_to( self, name: impl Into<String>, target: impl Into<String>, ) -> Self
Adds a many-to-one relationship (this service belongs to target).
Sourcepub fn has_many(
self,
name: impl Into<String>,
target: impl Into<String>,
) -> Self
pub fn has_many( self, name: impl Into<String>, target: impl Into<String>, ) -> Self
Adds a one-to-many relationship (this service has many of target).
Sourcepub fn has_one(self, name: impl Into<String>, target: impl Into<String>) -> Self
pub fn has_one(self, name: impl Into<String>, target: impl Into<String>) -> Self
Adds a one-to-one relationship (this service has one of target).
Sourcepub fn belongs_to_many(
self,
name: impl Into<String>,
target: impl Into<String>,
) -> Self
pub fn belongs_to_many( self, name: impl Into<String>, target: impl Into<String>, ) -> Self
Adds a many-to-many relationship (this service belongs to many of target).
Sourcepub fn intent_hint(self, hint: IntentHint) -> Self
pub fn intent_hint(self, hint: IntentHint) -> Self
Adds an intent hint for overriding structural derivation.
Sourcepub fn state_machine(self, machine: StateMachine) -> Self
pub fn state_machine(self, machine: StateMachine) -> Self
Sets the state machine definition for this service.
Sourcepub fn from_model(meta: &ModelMetadata) -> Self
pub fn from_model(meta: &ModelMetadata) -> Self
Derives a ServiceDef from model metadata.
Infers DataType from column type strings and FieldMeaning from field names.
System fields (id, created_at, updated_at, primary keys) are marked read-only.
Actions, state machines, and relationships are not derived.
Sourcepub fn validate(&self) -> Result<Vec<Warning>, Error>
pub fn validate(&self) -> Result<Vec<Warning>, Error>
Validates the service definition and returns warnings for potential issues.
This is the single validation entry point that subsumes StateMachine::validate().
Guard names form a shared pool referenced from transitions and action preconditions.
Returns Err for fatal issues (undefined guard references, unmatched triggers).
Returns Ok(warnings) for structural concerns (unused guards, missing state machine).
Trait Implementations§
Source§impl Clone for ServiceDef
impl Clone for ServiceDef
Source§fn clone(&self) -> ServiceDef
fn clone(&self) -> ServiceDef
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ServiceDef
impl Debug for ServiceDef
Source§impl<'de> Deserialize<'de> for ServiceDef
impl<'de> Deserialize<'de> for ServiceDef
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl JsonSchema for ServiceDef
impl JsonSchema for ServiceDef
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreSource§impl PartialEq for ServiceDef
impl PartialEq for ServiceDef
Source§fn eq(&self, other: &ServiceDef) -> bool
fn eq(&self, other: &ServiceDef) -> bool
self and other values to be equal, and is used by ==.