Building MobX models with proper architecture, BaseModel patterns, Store usage, and validation
ALWAYS use #ui_code_tools to scaffold new models - never create manually
BaseModel → StoreModel (lifecycle metadata + MobX)Store.asset.create() - NEVER new Model()APIStore registered in Store.ts for caching and hydrationpackages/models/src/models/<entity>/
├── _constants/ # Enums and status values
├── model/
│ ├── <Entity>BaseModel.ts # Pure API fields with @attr
│ └── <Entity>Model.ts # Computed logic and helpers
├── services/ # Complex workflows
└── constants.ts # Re-export constants
@attr decorated fields that mirror the backend API{readOnly: true} joined datastring, number, decimal, uuid, jsonreadOnly so serialization skips them// BaseModel - Pure API data only
export class AssetBaseModel extends BaseModel {
@attr("string") name: string = "";
@attr("uuid") organization_id: string = "";
@attr("number") status: number = 1;
@attr("json", { readOnly: true }) organization?: Organization;
}
this.addObserve(this) in constructor for MobX trackingValidationClass, use addObserve(child, this, "field")export class AssetModel extends AssetBaseModel {
constructor() {
super();
this.addObserve(this);
}
get statusConst(): IConstant {
return findConstant(constants.asset.status, this.status);
}
get statusStr(): string {
return this.statusConst.label;
}
get validationRules() {
return assetValidationRules;
}
}
// Lists
Store.asset.query({ organization_id: "123" });
// Single record
Store.asset.get("asset-id");
// Custom routes
Store.asset.queryRecord("/custom-endpoint");
// Force fresh data
Store.asset.get("id", { skipCache: true });
// Update directly - MobX tracks changes
model.name = "Updated";
// Save (auto POST/PUT based on isNew)
await model.save();
// Discard changes
model.rollback();
Always create helper getters for constants:
get asset_typeConst(): IConstant {
return findConstant(constants.asset.asset_type, this.asset_type);
}
get asset_typeStr(): string {
return this.asset_typeConst.label;
}
<entity>/validation_rules.ts using ValidationRulesType<Model>get validationRules() in derived modelnew Model() directly - use Store methods_loaded_attributes or _dirtyAttributes manually