Models are the foundation of every VeloIQ application. Define a model once in Python and the framework automatically generates a REST API, an SQLAdmin back-office view, and TypeScript schemas for the React frontend — no repetition required.Documentation Index
Fetch the complete documentation index at: https://docs.veloiq.dev/llms.txt
Use this file to discover all available pages before exploring further.
Base classes
VeloIQ provides three base classes. Choose the one that matches your storage requirements; all three are imported directly fromveloiq_framework.
FrameworkModel
FrameworkModel is the minimal base. It provides a single auto-increment integer primary key named id and nothing else — no audit columns, no extra metadata. Use it when you want the UI to show only the fields you declare.
TimestampedModel
TimestampedModel extends FrameworkModel with automatic created_at and updated_at columns. The code generator appends these two fields after all fields you declare, so they appear last in every list, form, and detail view.
StandardModel
StandardModel is for applications that must stay compatible with a CubicWeb database. It uses eid as the Python attribute name, mapped to the cw_eid physical column, and follows cw_ column naming conventions. New greenfield applications should use FrameworkModel or TimestampedModel instead.
Field types
Standard Python and SQLModel types work directly on all base classes. UseOptional[T] for nullable columns and set default=None or any other default value as needed.
Relations with jm_relationship()
Use jm_relationship() to declare SQLModel relationships. The function is a thin wrapper around SQLModel’s Relationship that attaches cardinality metadata — the frontend reads this to render required/optional indicators and pagination hints.
One-to-many
Declare the collection on the parent and the scalar reference on the child, each pointing back at the other withback_populates.
Self-referential
A model can reference itself to represent hierarchies such as tasks with subtasks. Self-referential relationships automatically trigger Miller column rendering in the frontend — clicking a row drills into its children in an adjacent column.jm_relationship() parameters
| Parameter | Type | Description |
|---|---|---|
back_populates | str | Attribute name on the related model that points back to this one |
min_items | int | Minimum cardinality (default 0) |
max_items | int | None | Maximum cardinality; None means unbounded (default None) |
required | bool | Whether the relation is required in UI forms (default False) |
sa_relationship_kwargs | dict | Extra keyword arguments forwarded to SQLAlchemy’s relationship() |
Field options with veloiq_field()
Use veloiq_field() in place of a plain Field() to add per-role read and write restrictions to individual columns. For example, to allow only Admins to read or change an employee’s salary:
veloiq_field() accepts all the same keyword arguments as pydantic.Field. See Access Control for the full details on read_roles, write_roles, and how field-level restrictions interact with the broader RBAC system.
Code generation
After defining or changing your models, runveloiq generate from the backend directory:
backend/app/modules/{module}/api.py— CRUD REST endpoints (do not edit)frontend/src/pages/{module}/{module}Schema.gen.ts— TypeScript field definitions (do not edit)
veloiq generate every time you add, rename, or remove a field or model.
Modules
Understand how modules are structured and auto-loaded
Access Control
Apply RBAC and ReBAC to your models and fields