spec.yaml Format¶
Main structure¶
# spec.yaml - Complete module specification
module:
name: "GavonaService" # PascalCase name
version: "1.0.0" # Semantic versioning
description: "Service module for managing interventions"
dependencies:
- "AutoCRM >= 1.0"
- "Sales >= 1.0"
entities:
ServiceRequest:
# ... entity definition
workflows:
ServiceRequestAssignment:
# ... workflow definition
integrations:
pohodaExport:
# ... integration definition
Entity Definition¶
entities:
ServiceRequest:
# Basic metadata
label: "Service request"
labelPlural: "Service requests"
type: "Base" # Base|BasePlus|Event|Person|Company
table: "service_request" # snake_case
iconClass: "fas fa-wrench"
color: "#e74c3c"
# Field definitions
fields:
number:
type: "autoincrement"
pattern: "SRV-{YYYY}-{0000}"
label: "Request number"
required: true
readonly: true
account:
type: "link"
entity: "Account"
label: "Account"
required: true
audited: true # Log changes
priority:
type: "enum"
options:
- value: "Critical"
label: "Critical"
color: "#dc3545"
style:
fontWeight: "bold"
- value: "High"
label: "High"
color: "#fd7e14"
- value: "Normal"
label: "Normal"
color: "#0d6efd"
- value: "Low"
label: "Low"
color: "#6c757d"
default: "Normal"
required: true
status:
type: "enum"
options:
- "New"
- "Assigned"
- "InProgress"
- "WaitingParts"
- "Completed"
- "Invoiced"
- "Cancelled"
default: "New"
required: true
audited: true
description:
type: "text"
label: "Issue description"
required: true
rowsMin: 3
rowsMax: 10
estimatedHours:
type: "float"
label: "Estimated hours"
min: 0
decimalPlaces: 1
# Relations to other entities
links:
account:
type: "belongsTo"
entity: "Account"
foreign: "serviceRequests"
assignedUser:
type: "belongsTo"
entity: "User"
foreign: "assignedServiceRequests"
trips:
type: "hasMany"
entity: "ServiceTrip"
foreign: "serviceRequestId"
# UI Layouts
layouts:
detail:
- panel: "default"
label: "Basic information"
rows:
- ["number", "status"]
- ["account", "priority"]
- ["assignedUser", "estimatedHours"]
- panel: "description"
label: "Description"
rows:
- ["description"]
list:
columns:
- name: "number"
width: 120
link: true
- name: "account"
width: 200
- name: "priority"
width: 100
- name: "status"
width: 120
- name: "assignedUser"
width: 150
filters:
- "status"
- "priority"
- "assignedUser"
- "account"
# Database indexes
indexes:
- fields: ["accountId", "status"]
- fields: ["assignedUserId", "status"]
- fields: ["createdAt"]
Workflow Definition¶
workflows:
ServiceRequestAutoAssignment:
trigger: "afterSave"
entity: "ServiceRequest"
isActive: true
conditions:
- type: "fieldEquals"
field: "status"
value: "New"
- type: "fieldIsEmpty"
field: "assignedUserId"
- type: "formula"
formula: "entity.get('priority') == 'Critical'"
actions:
- type: "notification"
target: "role:Dispatcher"
template: "critical_service_request"
message: "New critical request: {entity.number}"
- type: "createTask"
entity: "Task"
data:
name: "Assign technician: {entity.number}"
assignedUserId: "role:Dispatcher"
dateEnd: "{dateAdd(now, 1, 'hour')}"
priority: "Urgent"
- type: "updateEntity"
field: "status"
value: "Assigned"
when: "assignedUserId IS NOT NULL"
ServiceRequestCompletion:
trigger: "afterSave"
entity: "ServiceRequest"
conditions:
- type: "fieldChanged"
field: "status"
- type: "fieldEquals"
field: "status"
value: "Completed"
actions:
- type: "sendEmail"
to: "{entity.account.emailAddress}"
template: "service_completed"
- type: "executeFormula"
formula: |
entity.set('completedAt', datetime.now());
entity.set('completedById', user.id);
➡️ Continue to Acceptance criteria.