Schema and Types¶
The formfiller-schema package is the central element of the FormFiller system - it defines the structural composition of elements achievable by the low-code platform.
The Role of Schema¶
Low-Code Definition Language¶
The schema can essentially be interpreted as a declarative programming language. A single JSON structure defines:
- Data structure: Fields, types, relationships
- Display: Forms, grids, tree structures
- Behavior: Validations, conditional logic, events
- Business rules: ComputedRules, cross-field validation
flowchart TB
subgraph schema["SCHEMA DEFINITION"]
DATA["Data<br/>structure"]
UI["Display<br/>(UI)"]
LOGIC["Behavior<br/>(Logic)"]
end
DATA --> SSOT
UI --> SSOT
LOGIC --> SSOT
SSOT["Single Source<br/>of Truth"]
SSOT --> FE["Frontend<br/>Rendering"]
SSOT --> BE["Backend<br/>API"]
SSOT --> VAL["Validator<br/>Engine"]
style SSOT fill:#ccffcc,stroke:#00cc00
style schema fill:#e6f3ff,stroke:#0066cc
Single Source of Truth¶
Unlike traditional MVC architectures where the data model, display, and validation must be defined separately and redundantly:
| Traditional MVC | FormFiller Schema |
|---|---|
| Model definition (backend) | Single schema |
| Database migration | defines all |
| API endpoints | layers at once |
| Frontend form components | |
| Frontend validation | |
| Backend validation |
Advantages: - No redundancy - modifying in one place applies everywhere - Guaranteed consistency - frontend and backend use the same definition - Faster development - no need to implement each layer separately - Fewer errors - no discrepancies between layers - AI compatibility - easily processable and generatable by artificial intelligence
AI Compatibility¶
One of the less obvious but extremely valuable advantages of the schema structure is its compatibility with AI technologies.
Important: The AI interface is a currently working, production feature in the FormFiller system, not a future plan!
Why Is It Ideal for AI Processing?¶
The schema defines clear, declarative rules:
| Property | AI Advantage |
|---|---|
| Structured JSON format | Easily parseable, generatable |
| Finite type set | AI knows exactly what elements exist |
| Explicit rules | No hidden logic, everything is declared |
| Hierarchical structure | Natural tree structure for AI |
| Validatable output | AI-generated schema can be verified |
AI Generated Forms¶
FormFiller's built-in AI function can generate working forms from natural language descriptions:
flowchart LR
U["👤 User<br/>'Create an employee data sheet<br/>with personal data...'"]
AI["🤖 AI processing"]
SG["📝 Schema generation"]
V["✅ Validation"]
F["📋 Working form"]
U --> AI --> SG --> V --> F
How it works:
- Prompt interpretation: AI understands the user need
- Schema generation: AI generates JSON according to schema rules
- Validation: Generated schema is automatically validated
- Fine-tuning: User can modify, AI can regenerate
Example AI Generated Schema:
// User request: "Simple contact form"
{
"type": "form",
"title": "Contact",
"items": [
{ "name": "name", "title": "Name", "type": "text",
"validationRules": [{"type": "required"}] },
{ "name": "email", "title": "Email", "type": "text",
"validationRules": [{"type": "required"}, {"type": "email"}] },
{ "name": "subject", "title": "Subject", "type": "text" },
{ "name": "message", "title": "Message", "type": "textarea",
"validationRules": [{"type": "required"}] }
],
"preferences": { "addSaveBtn": true }
}
AI Advantages in Development¶
| Feature | Description |
|---|---|
| Quick prototype | Working form from natural language in minutes |
| Iterative refinement | "Add a phone number field too" |
| Complex structures | AI handles nested groups, conditions |
| Best practices | AI generates according to schema rules |
| Error-free output | Validatable, type-correct output |
Drastic Time Savings¶
The working AI interface radically reduces development time:
| Method | Average Time | Savings |
|---|---|---|
| Traditional coding (MVC) | 4-8 hours | - |
| Manual JSON schema writing | 30-60 minutes | ~85% |
| AI generation | 2-5 minutes | ~98% |
Non-Form Applications¶
The AI interface is not limited to forms. FormFiller's declarative schema language is suitable for describing any structured data:
| Application | Example |
|---|---|
| Workflow definitions | Approval processes, state machines |
| Data structures | CRM, ERP entity models |
| System configurations | Settings, parameters |
| Business rules | Pricing, discounts, permissions |
| Report definitions | Report structures, dashboards |
📚 Detailed documentation: AI Interface
Comparison with Traditional Code¶
| Traditional Code | FormFiller Schema | |
|---|---|---|
| AI generation | Difficult - syntax sensitive | Simple - structured JSON |
| Validation | Must run the code | JSON Schema validation |
| Error rate | High (syntax errors) | Low (type checking) |
| Interpretation | Hard for AI to understand | Explicit, declarative |
The declarative nature of schema thus not only simplifies development but opens new possibilities for AI-based development tools.
Schema + Workflow = Complete Application¶
The schema combined with Workflow schema can describe almost any typical business application:
flowchart LR
subgraph SCHEMA
S1["Data structure"]
S2["UI definition"]
S3["Validation"]
S4["Events"]
end
subgraph WORKFLOW
W1["Processes"]
W2["States"]
W3["Transitions"]
W4["Automation"]
end
SCHEMA --> APP["Complete<br/>Application"]
WORKFLOW --> APP
style APP fill:#ccffcc,stroke:#00cc00
Example: Webshop operation in FormFiller
| Function | Schema element | Workflow element |
|---|---|---|
| Product catalog | Grid config + lookup | - |
| Cart management | Nested grid + computedRules (sum) | - |
| Order form | Form config + validation | - |
| Order processing | - | Status transitions |
| Notifications | - | Email workflow steps |
| Inventory update | - | Automatic workflow |
Other implementable systems: - CRM system - Project management - HR administration - Customer service (ticketing) - Inventory management - Document workflow - Examination system
Path-Based Field Management¶
One of FormFiller's unique and extremely useful features is path-based field management, which enables storing data in complex, hierarchical structures.
Path Syntax¶
simple field: name → { "name": "..." }
group field: address.city → { "address": { "city": "..." } }
deep nesting: customer.billing.zipCode → { "customer": { "billing": { "zipCode": "..." } } }
grid row: items[0].quantity → { "items": [{ "quantity": ... }] }
all grid rows: items[*].total → (total field of every row)
Advantages¶
| Advantage | Description |
|---|---|
| Semantic structure | Data hierarchy carries meaning - e.g. billing.address vs shipping.address |
| Logical grouping | Related fields stored together in database |
| Form-data correspondence | Data structure reflects form's logical layout |
| MongoDB compatibility | Native embedded document storage, no joins needed |
| Easier querying | Path-based search and aggregation ("customer.billing.city": "Budapest") |
| Meaningful content | Data is self-describing, structure itself carries information |
Example: Order Form Data Structure¶
// Schema definition
{
"type": "form",
"items": [
{
"type": "group",
"name": "customer",
"items": [
{ "name": "name", "type": "text" },
{
"type": "group",
"name": "billing",
"items": [
{ "name": "address", "type": "text" },
{ "name": "zipCode", "type": "text" }
]
},
{
"type": "group",
"name": "shipping",
"items": [
{ "name": "address", "type": "text" },
{ "name": "zipCode", "type": "text" }
]
}
]
},
{
"name": "items",
"type": "grid",
"gridConfig": {
"columns": [
{ "dataField": "product", "type": "text" },
{ "dataField": "quantity", "dataType": "number" },
{ "dataField": "price", "dataType": "number" }
]
}
}
]
}
Data saved based on the above schema:
{
"customer": {
"name": "John Smith",
"billing": {
"address": "123 Main St, New York",
"zipCode": "10001"
},
"shipping": {
"address": "456 Oak Ave, Boston",
"zipCode": "02101"
}
},
"items": [
{ "product": "Laptop", "quantity": 1, "price": 1200 },
{ "product": "Mouse", "quantity": 2, "price": 25 }
]
}
Comparison with Flat Structure¶
| Flat structure | Hierarchical (FormFiller) |
|---|---|
billingAddress, shippingAddress |
billing.address, shipping.address |
| Must group manually | Automatic grouping |
| No semantic meaning | Structure itself carries meaning |
| Hard to extend | Easily extendable with new levels |
| JOIN required (relational DB) | Embedded document (MongoDB) |
MongoDB Query Advantages¶
// With flat structure
db.orders.find({ billingCity: "Budapest" });
// With FormFiller hierarchical structure
db.orders.find({ "customer.billing.city": "Budapest" });
// Aggregation on nested array
db.orders.aggregate([
{ $unwind: "$items" },
{ $group: { _id: "$customer.name", total: { $sum: "$items.price" } } }
]);
Path-based structure thus not only improves schema readability but data gains meaningful content, and storage reflects business logic.
Concise Program Code¶
A complex form that would be hundreds of lines in traditional code can be described concisely in schema:
{
"type": "form",
"title": "Order",
"items": [
{
"itemType": "group",
"caption": "Customer Data",
"items": [
{ "name": "customerName", "type": "text", "validationRules": [{"type": "required"}] },
{ "name": "email", "type": "text", "validationRules": [{"type": "email"}] }
]
},
{
"name": "orderItems",
"type": "grid",
"gridConfig": {
"columns": [
{ "dataField": "product", "lookup": { "dataSource": "/api/products" } },
{ "dataField": "quantity", "dataType": "number" },
{ "dataField": "unitPrice", "dataType": "number" },
{ "dataField": "lineTotal", "dataType": "number", "calculateValue": "quantity * unitPrice" }
]
}
}
],
"computedRules": [
{ "targetField": "orderTotal", "formula": "sum(orderItems[*].lineTotal)" }
]
}
This ~30-line JSON description includes: - Data structure (fields, types) - UI (grouping, grid, form) - Validation (required, email format) - Business logic (line total, grand total) - Data relationships (product lookup)
Main Types¶
FieldConfig¶
Field configuration type:
interface FieldConfig {
name: string; // Field identifier
title?: string; // Display title
type: FieldType; // Field type
dataType?: DataType; // Data type
editorOptions?: EditorOptions; // Editor settings
validationRules?: ValidationRule[]; // Validation rules
visibleIf?: ConditionalRule; // Conditional visibility
disabledIf?: ConditionalRule; // Conditional disable
requiredIf?: ConditionalRule; // Conditional required
lookup?: LookupConfig; // Lookup configuration
}
FieldType¶
Supported field types:
type FieldType =
| 'text' | 'number' | 'date' | 'datetime' | 'boolean'
| 'lookup' | 'tagbox' | 'textarea' | 'html'
| 'file' | 'image' | 'signature'
| 'group' | 'tabbed' | 'tab'
| 'grid' | 'tree' | 'form';
ValidationRule¶
DevExtreme-compatible validation rules:
interface ValidationRule {
type: ValidationType;
message?: string;
// Type-specific fields
min?: number;
max?: number;
pattern?: string;
// ...
}
type ValidationType =
| 'required' | 'email' | 'numeric'
| 'stringLength' | 'range' | 'pattern'
| 'compare' | 'custom';
ItemConfig¶
View configuration (grid, tree, form):
interface ItemConfig {
id: string;
title: string;
type: 'grid' | 'tree' | 'form';
items: FieldConfig[];
preferences?: FormPreferences;
}
Usage¶
Frontend¶
import {
FieldConfig,
ItemConfig,
validateField
} from 'formfiller-schema';
// Typed configuration
const field: FieldConfig = {
name: 'email',
title: 'Email address',
type: 'text',
validationRules: [
{ type: 'required' },
{ type: 'email' }
]
};
// Validation
const result = validateField(field);
Backend¶
import {
ViewConfig,
validateConfig,
SchemaValidator
} from 'formfiller-schema';
// Config model with TypeScript interface
const config: ViewConfig = req.body.config;
// Validation
const validator = new SchemaValidator();
const result = validator.validate(config, schema);
if (!result.valid) {
return res.status(400).json({ errors: result.errors });
}
SchemaValidator¶
Multi-level validation support:
import { SchemaValidator, ValidationLevel } from 'formfiller-schema';
const validator = new SchemaValidator();
// STRICT - for production
const strictResult = validator.validate(config, schema, {
level: ValidationLevel.STRICT
});
// LOOSE - for staging
const looseResult = validator.validate(config, schema, {
level: ValidationLevel.LOOSE
});
// DEVELOPMENT - for development
const devResult = validator.validate(config, schema, {
level: ValidationLevel.DEVELOPMENT
});
SchemaCache¶
Cached validators:
import { getSchemaCache } from 'formfiller-schema';
const cache = getSchemaCache();
const validator = cache.getValidator('configSchema', schema);
// Multiple uses - from cache
validator(config1);
validator(config2);
// Statistics
console.log(`Hit rate: ${cache.getHitRate() * 100}%`);
Development¶
Modifying Schema¶
- Modify types in the
formfiller-schemaproject - Run build:
npm run build - Distribute:
npm run distribute - Restart backend and frontend projects
Adding New Field Type¶
- Add to the
FieldTypeunion - Define type-specific interface
- Implement validation
- Implement frontend rendering