| name | mas-data-model |
| description | Define backend data modeling standards for Python services. Use when designing or refactoring models in app/models (schema/config/task), normalizing shared fields, choosing types/defaults/validation strategy, and evolving model contracts with backward compatibility. |
MAS Data Model
Objective
Build backend data models that are explicit, consistent, and evolution-friendly.
Scope
Apply to model definitions under app/models:
- API contract models (
schema)
- persisted/runtime config models (
config, ConfigBase)
- task/runtime state models (
task)
Model Ownership
schema models define external API contracts only.
config models define persisted configuration structure and validation behavior.
task models define runtime execution state and orchestration-facing status.
- Do not mix transport, persistence, and runtime concerns in one model class.
ConfigBase subclasses define real persisted config templates; every ConfigItem must be declared before super().__init__() to be indexed, settable, and saved.
MultipleConfig represents a dictionary-like collection of ConfigBase instances and must be declared with all allowed concrete config classes.
Structure And Types
- Use nested group models for meaningful domains (
Info, Run, Notify, Data).
- Keep shared semantics aligned with
mas-schema-naming.
- Keep domain-specific fields inside dedicated domain blocks.
- Keep index items and payload models separated.
- Prefer concrete types over
Any.
- Use
Literal or explicit enums for bounded value sets.
- Use optional types only when missing value has real business meaning.
- Avoid stringly-typed booleans/numbers in new model fields.
- Keep datetime/time fields format-stable and documented.
- When a field is optional by omission, prefer absence over sentinel values that violate the declared type.
Defaults And Validation
- Use safe defaults for collection fields (
default_factory when mutable).
- Use
None defaults only for truly optional semantics.
- Avoid hidden execution-policy changes in defaults.
- Keep validation close to model definition.
- Keep correction/normalization deterministic.
- Do not encode high-level business workflow in low-level field validators.
- Do not duplicate validation already guaranteed by config manager or collection base classes; validate only the invariant still at risk, such as referenced
uuid existence.
- Favor validators that reject or normalize one missing invariant, not "just in case" fallbacks for impossible states.
- Treat config validators as auto-correction behavior, not just passive checks:
RangeValidator, OptionsValidator, BoolValidator, path validators, EncryptValidator, VirtualConfigValidator, and MultipleUIDValidator can rewrite stored values.
- Use
VirtualConfigValidator(function) for computed display/config fields that should be read through normal config access but must not be set or persisted as user input.
Relationships And Sensitive Data
- Keep IDs typed consistently as strings in API-facing schema unless migration is planned.
- Keep relation fields explicit (
scriptId, userId, queueId).
- Keep index models lightweight and independent of heavy payload models.
- Avoid duplicating relationship semantics with synonym fields.
- Mark and isolate sensitive fields clearly (
password, token, key).
- Avoid exposing sensitive values in response models unless explicitly required.
- Keep encryption/decryption policy out of schema contracts and in proper model/service layers.
Evolution And Compatibility
- Prefer additive model changes over breaking removals.
- Keep backward read compatibility during rename migrations.
- Keep API conversion logic explicit when old/new fields coexist.
- Avoid adding a second config field for the same user choice.
- If modes are mutually exclusive, merge them into one selector and make downstream toggling explicit.
- If modes are not mutually exclusive, keep one existing selector as the source of truth.
- Do not introduce future raw-config save fields or detailed-mode markers until persistence, UI, and runtime consumption all exist.
- Do not add placeholders for a future config surface when the product still lacks the corresponding edit entry or consumer.
Anti-Patterns
- One model serving unrelated responsibilities across layers.
- New fields duplicating existing semantics with different names.
- Validator logic performing network/file/process side effects.
- Unbounded
Dict[str, Any] replacing known structured fields.
- Large domain policies hidden in model defaults.
- Defensive validators re-checking invariants enforced by lower-level config containers.
- Separate config options forcing users to choose the same domain concept twice.
- Optional fields represented by invalid placeholder values instead of omission or a correct union type.
- Defining config fields after
super().__init__() and expecting them to participate in normal config load/save behavior.
- Adding a config class to one layer while forgetting the corresponding
GlobalConfig collection, CLASS_BOOK/registry entry, schema type, or API handling.
Review Checklist
- Model belongs to the correct layer (
schema/config/task).
- Field naming aligns with canonical shared semantics.
- Types and optionality express real business meaning.
- Defaults are safe and behaviorally stable.
- Constraints are explicit and deterministic.
- Sensitive fields are protected from accidental exposure.
- Change is backward-compatible or includes migration handling.
- Placement follows
mas-module-boundary and API usage follows mas-api-contract.
- New validators check only missing invariants, not guarantees already provided by base containers.
- New config fields do not duplicate an existing selector or tab/mode choice.
- Optionality is expressed by the type system or field absence, not by values that conflict with the declared type.
- Config classes document every
ConfigItem with nearby comments and are grouped by Info, Run, Task, Data, Notify, or the local domain grouping used by neighbors.
- New multi-config relationships include the allowed classes in
MultipleConfig([...]) and any needed UID-reference field points at the owning collection.