Data model¶
AutoCRUD is built around a single idea:
ResourceManager is the only place you manipulate resources.
You should not write SQL, touch S3, or talk to blob storage directly. Everything goes through ResourceManager, which coordinates:
IStorage: metadata + revision data- Blob store: binary payload offloading (optional, but usually enabled)
Conceptually:
ResourceManager
├── IStorage
│ ├── meta store (ResourceMeta)
│ └── revision store (RevisionInfo + data bytes per revision)
└── blob store (Binary payload)
Resource¶
At the API layer, a resource is returned as:
datais your domain object (msgspec.Structrecommended)infois revision-level metadata for the returned revision
Resource-level metadata (ResourceMeta) is accessed via dedicated endpoints (or included in list/get responses via returns=meta).
IDs¶
resource_id¶
- A UUID string
- Created at
create()time
revision_id¶
AutoCRUD uses a human-readable revision identifier:
revision_id = "{resource_id}:{n}"
Example:
f1b2...:1f1b2...:2
Revision graph and branching¶
Revisions behave like Git commits:
update()always creates a new revision (a new node)switch()moves the resource "HEAD" pointer to an existing revision- updating after a switch can create branches
Example:
After switching to r2:
After updating from r2:
So AutoCRUD maintains a revision DAG, not just a linear history.
Revision status: draft vs stable¶
AutoCRUD uses RevisionStatus to support draft workflows:
draft: editable in-place (viamodify()), no restrictionsstable: immutable data by default (data cannot be modified in-place)
Rules:
stablecannotmodify(data)but it can be converted todraft(usingmodify(status=draft)), and then edited.drafthas no restrictions: it can beupdate()(new revision) and can bemodify()(in-place)
This gives you a clean workflow:
- Use
update()when you want a new revision in history - Use
modify()when you want to mutate a draft without growing history
ResourceMeta vs RevisionInfo¶
AutoCRUD stores two levels of metadata:
Resource-level meta: ResourceMeta¶
ResourceMeta describes the resource as a whole:
resource_idcurrent_revision_id(HEAD pointer)schema_version(current schema version for this resource)total_revision_count- audit fields (
created_*,updated_*) is_deletedindexed_data(for search)
Revision-level meta: RevisionInfo¶
RevisionInfo describes a specific revision:
revision_idparent_revision_idschema_versionandparent_schema_versionstatus(draft/stable)- audit fields (
created_*,updated_*) - optional
data_hash
Important: updated_time may differ from created_time only when a revision is modified in place (draft modify()).
Timestamp semantics¶
update() (new revision)¶
ResourceMeta.created_time: unchangedRevisionInfo.created_time: newRevisionInfo.updated_time: equals created_time (new revision)ResourceMeta.updated_time: equals the new revision’s created/updated time
modify() (in-place revision)¶
revision_id: unchangedparent_revision_id: unchangedRevisionInfo.created_time: unchangedRevisionInfo.updated_time: updatedResourceMeta.created_time: unchangedResourceMeta.updated_time: updated (matchesRevisionInfo.updated_time)
Soft delete / restore¶
delete()¶
AutoCRUD uses soft delete:
- Only flips
ResourceMeta.is_deleted = True - Does not create a new revision
- Revision history is preserved
- Updates
ResourceMeta.updated_time/updated_by
restore()¶
- Sets
ResourceMeta.is_deleted = Falseif it was deleted - Does not create a new revision
Binary payloads (blob store)¶
AutoCRUD supports efficient binary storage via Binary fields:
- On
create()/update()/modify(),ResourceManagerscans the data object -
Any
Binary(data=...)is: -
extracted
- stored in the blob store
- replaced in the stored resource data with a reference (
file_id,size,content_type) datais cleared (not persisted in the resource payload)
This keeps resource payloads small and makes blobs independently addressable.
Migration is a ResourceManager concern¶
Migration happens at the ResourceManager layer (not in storage):
- Stored bytes are migrated to the latest schema version when you run
migrate() -
Resource schema version is tracked on:
-
ResourceMeta.schema_version RevisionInfo.schema_version- Migration updates
indexed_databased on migrated data
If a user requests an old revision, AutoCRUD attempts to decode it using the current schema. If decoding fails, the revision is ignored (not returned as 404). Use migration APIs to fix it.