Skip to content

feat(orm): BaseModel CreatedUid/UpdatedUid/DeletedUid audit columns - #265

Merged
buke merged 9 commits into
mainfrom
feat/basemodel-audit-uid
Aug 10, 2026
Merged

feat(orm): BaseModel CreatedUid/UpdatedUid/DeletedUid audit columns#265
buke merged 9 commits into
mainfrom
feat/basemodel-audit-uid

Conversation

@buke

@buke buke commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add CreatedUid / UpdatedUid / DeletedUid to TS BaseModel (ManyToOneRef → auth.User) and Go pkg/meta.BaseModel.
  • Stamp actor uids on Create / Update / soft-delete; restore (DeletedAt: null) clears DeletedUid and refreshes UpdatedUid; strip client CreatedUid writes.
  • Fold SavedFilter’s model-local CreateUid into BaseModel CreatedUid (bootstrap RR, FE useSavedFilters, SF11); keep orphan ids on User delete (no CASCADE). No legacy create_uid rename migration.

Test plan

  • go test ./pkg/meta/ ./internal/module/evolution/schema/ -count=1
  • ./choysum test typecheck core web base
  • ./choysum test unit core --be (timestamp / audit uid / soft-delete stamp / FieldsGet / field-rule system fields)
  • ./choysum test unit base --be --pattern 'soft_delete|audit_uid'
  • ./choysum test unit web --be --pattern 'SavedFilter|SF11|AU9|SF13'
  • ./choysum test unit web --fe --pattern 'useSavedFilters'
  • CI green on PR

Summary by CodeRabbit

  • New Features

    • Added creator, updater, and deleter identity tracking to records.
    • Audit identities are automatically populated during create, update, restore, and soft-delete actions.
    • Saved filters now consistently use creator identity tracking.
  • Bug Fixes

    • Corrected saved-filter ownership rules and removed reliance on the legacy creator field.
    • Prevented client updates from modifying protected audit identities.
    • Ensured audit fields are cleared or preserved correctly when appropriate.

- Add matching Go pkg/meta.BaseModel columns and SavedFilter create_uid rename migration.
- Stamp actor uids on Create/Update/soft-delete/restore via TimestampUtils and soft-delete writes.
- Fold SavedFilter CreateUid into BaseModel CreatedUid across RR, FE, and SF11 tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d45affb4-d3fc-4cb1-a7f9-eb143ec8ad09

📥 Commits

Reviewing files that changed from the base of the PR and between b07570a and 000da49.

📒 Files selected for processing (7)
  • modules/core/service/orm/model/model_internal_public_bridge.test.ts
  • modules/core/service/orm/repository/write/tests/create_helpers.test.ts
  • modules/core/service/orm/repository/write/tests/update.test.ts
  • modules/core/service/orm/utils/audit_uid.test.ts
  • modules/core/service/orm/utils/audit_uid.ts
  • modules/web/web/composables/search/savedFilterDefaults.ts
  • modules/web/web/composables/search/useSavedFilters.ts
📝 Walkthrough

Walkthrough

The PR adds CreatedUid, UpdatedUid, and DeletedUid audit fields across model and Go metadata. Repository writes now stamp actor identities. SavedFilter replaces CreateUid with CreatedUid.

Changes

Audit UID model contract

Layer / File(s) Summary
Audit UID fields and system metadata
modules/core/service/orm/model/..., pkg/meta/..., modules/core/service/orm/repository/authz/..., internal/module/artifact/...
BaseModel exposes nullable audit-user references. Go metadata and test schemas define matching columns. Authorization and copy rules treat the fields as system fields.

Audit UID persistence flow

Layer / File(s) Summary
Repository audit stamping
modules/core/service/orm/utils/..., modules/core/service/orm/repository/write/...
AuditUidUtils stamps actor IDs for creates, updates, restores, and soft deletes. Repository preparation applies these fields before validation and encoding.
Persistence behavior tests
modules/core/service/orm/utils/*test.ts, modules/core/service/orm/repository/write/tests/*
Tests cover actor and no-actor behavior, protected client fields, timestamps, restoration, soft deletion, validation, encoding, and database writes.

Model and SavedFilter integration

Layer / File(s) Summary
Model write flow
modules/core/service/orm/model/..., modules/base/service/tests/..., modules/core/service/orm/repository/repository.test.ts
Model create and update paths stop assigning timestamps directly. Repository preparation supplies timestamps and audit UIDs for related, bulk, attachment, and parent updates.
SavedFilter creator migration
modules/web/service/..., modules/web/web/composables/search/..., modules/web/data/bootstrap.json
SavedFilter validation, queries, record rules, composables, and fixtures use CreatedUid instead of CreateUid. Tests verify creator immutability and persistence after creator deletion.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RequestContext
  participant ModelWriteFlow
  participant AuditUidUtils
  participant Repository
  participant Database
  RequestContext->>ModelWriteFlow: submit create or update
  ModelWriteFlow->>Repository: prepare write payload
  Repository->>AuditUidUtils: apply actor audit fields
  AuditUidUtils-->>Repository: return stamped payload
  Repository->>Database: validate, encode, and persist payload
  Database-->>Repository: return write result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding BaseModel audit columns for created, updated, and deleted user identities.
Description check ✅ Passed The description explains the changes, integration scope, and test plan, and it identifies that CI is not yet green.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/basemodel-audit-uid

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 PR contains tests
🔒 No security concerns identified
⚡ No major issues detected

@github-actions

Copy link
Copy Markdown

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Security
Sanitize update audit fields without actor

When no actor context is present, client-provided update fields are not sanitized.
Delete value.UpdatedUid before assigning the current actor to prevent untrusted
client input from writing to UpdatedUid.

modules/core/service/orm/utils/timestamp.ts [81-85]

+delete value.UpdatedUid;
 const actor = resolveActorUid();
 if (actor) {
   value.UpdatedUid = actor;
 }
 return value;
Suggestion importance[1-10]: 8

__

Why: Deleting value.UpdatedUid before setting it ensures client-provided UpdatedUid values are always stripped, preventing untrusted input from overriding audit fields when no request actor is present.

Medium

- Skip legacy create_uid → created_uid compatibility; fresh CreatedUid columns are enough.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

buke and others added 4 commits August 10, 2026 13:32
- Keep TimestampUtils for *At columns only; add AuditUidUtils for *Uid create/update/soft-delete.
- Wire Create/Update/instance/soft-delete paths through the new helper.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Move CreatedAt/UpdatedAt and audit uid stamping from the model layer into create/update repository prepare so soft-delete cascade and other write enrich share one path.

- Keep soft-delete SET stamping in place and update write tests plus util/SavedFilter comments for the new call sites.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Add created_uid/updated_uid/deleted_uid to auth_role_ui_resource Go test tables so GORM inserts match BaseModel.

- Stop expecting model Create follow-up updates to set UpdatedAt; repository prepare owns the stamp.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Relax create/update orchestration assertions so validate and SQL payloads may include repository-prepare CreatedAt/UpdatedAt.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
modules/web/web/composables/search/useSavedFilters.ts (1)

79-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add CreatedUid to SavedFilterRow.

SavedFilterRow does not declare CreatedUid, but these lines request and read it through (r as any). The cast prevents TypeScript from checking the creator identity used for shared-filter deletion eligibility.

Proposed fix
 export type SavedFilterRow = {
   Id?: string;
   Name?: string;
   Condition?: any;
   IsDefault?: boolean;
   UserId?: string | null;
+  CreatedUid?: string | null;
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modules/web/web/composables/search/useSavedFilters.ts` around lines 79 - 87,
Update the SavedFilterRow type to declare the CreatedUid field, then access
CreatedUid directly in the saved-filter mapping logic instead of casting each
row to any. Preserve the existing trimming and fallback behavior used when
deriving createUid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modules/core/service/orm/model/model_create.ts`:
- Around line 256-259: Update the relevant build and test workflow
configuration, not the model creation logic around repository.create: make
prepare-root-node-modules depend on prepare-embedded-assets, then enforce the
sequence of CLI build, test typecheck core, and test unit core, followed by
impact-routed E2E jobs. Locate the workflow job definitions and dependency
configuration for these named steps and preserve the existing impact routing
behavior.

In `@modules/core/service/orm/utils/audit_uid.ts`:
- Around line 27-33: The create preparation logic in addCreateUids must ignore
any client-provided CreatedUid, remove it before stamping, and set CreatedUid to
the current actor whenever one exists; update
modules/core/service/orm/utils/audit_uid.ts lines 27-33 accordingly. Update
modules/core/service/orm/utils/audit_uid.test.ts lines 15-25 and
modules/core/service/orm/repository/write/tests/create_helpers.test.ts lines
350-357 to expect U-ACTOR for CreatedUid.

---

Nitpick comments:
In `@modules/web/web/composables/search/useSavedFilters.ts`:
- Around line 79-87: Update the SavedFilterRow type to declare the CreatedUid
field, then access CreatedUid directly in the saved-filter mapping logic instead
of casting each row to any. Preserve the existing trimming and fallback behavior
used when deriving createUid.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a4a1f17-67c1-4052-b583-5a3674f83298

📥 Commits

Reviewing files that changed from the base of the PR and between 71074e1 and b07570a.

📒 Files selected for processing (30)
  • internal/module/artifact/build/web/webBuilder_test.go
  • modules/base/service/tests/basemodel_audit_uid.test.ts
  • modules/core/service/orm/model/basemodel_audit_uid_fields.test.ts
  • modules/core/service/orm/model/model.ts
  • modules/core/service/orm/model/model_copy.test.ts
  • modules/core/service/orm/model/model_create.ts
  • modules/core/service/orm/model/model_instance.ts
  • modules/core/service/orm/model/model_internal_public_bridge.test.ts
  • modules/core/service/orm/model/model_update.ts
  • modules/core/service/orm/repository/authz/field_rule_helpers.ts
  • modules/core/service/orm/repository/authz/tests/field_rule_helpers.test.ts
  • modules/core/service/orm/repository/repository.test.ts
  • modules/core/service/orm/repository/write/create_helpers.ts
  • modules/core/service/orm/repository/write/delete.ts
  • modules/core/service/orm/repository/write/tests/create.test.ts
  • modules/core/service/orm/repository/write/tests/create_helpers.test.ts
  • modules/core/service/orm/repository/write/tests/delete.test.ts
  • modules/core/service/orm/repository/write/tests/update.test.ts
  • modules/core/service/orm/repository/write/update.ts
  • modules/core/service/orm/utils/audit_uid.test.ts
  • modules/core/service/orm/utils/audit_uid.ts
  • modules/core/service/orm/utils/timestamp.test.ts
  • modules/core/service/orm/utils/timestamp.ts
  • modules/web/data/bootstrap.json
  • modules/web/service/models/saved_filter.ts
  • modules/web/service/tests/saved_filter.test.ts
  • modules/web/web/composables/search/useSavedFilters.test.ts
  • modules/web/web/composables/search/useSavedFilters.ts
  • pkg/meta/model.go
  • pkg/meta/model_test.go

Comment thread modules/core/service/orm/model/model_create.ts
Comment thread modules/core/service/orm/utils/audit_uid.ts
…tedUid

- Always strip client UpdatedUid on update prepare, then stamp from actor when present, so no-actor requests cannot forge write_uid.

- Keep create CreatedUid setdefault per design; force UpdatedUid from actor; type SavedFilterRow.CreatedUid and drop as-any reads.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codereviewbot-ai

codereviewbot-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown

LGTM! The addition of CreatedUid, UpdatedUid, and DeletedUid to BaseModel and shifting timestamp/audit-UID stamping down to the repository prepare layer (create_helpers, update, delete) is clean, secure, and thoroughly tested.


🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does.

- Exercise addCreateUids/addUpdateUid with non-object input so asObjectRecord fallbacks are covered.

- Hit UpdateOperations empty repository.update when attachment clear has no scalar payload.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codereviewbot-ai

codereviewbot-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Summary

The changes successfully introduce CreatedUid, UpdatedUid, and DeletedUid audit user fields on BaseModel and centralize timestamp and audit UID stamping within the repository layer (create_helpers.ts, update.ts, delete.ts).

Key Observations:

  1. Audit UIDs on BaseModel: Defined as ManyToOneRef to auth.User with copy: false, keeping metadata decoupled from direct module imports.
  2. Repository-Layer Preparation: Centralizing CreatedAt, UpdatedAt, CreatedUid, and UpdatedUid in repository write preparation ensures audit stamping happens before authorization checks (validateRepositoryMutationPayload) and encoding.
  3. Authz Exemptions: FIELD_RULE_SYSTEM_FIELDS in field_rule_helpers.ts correctly includes CreatedUid, UpdatedUid, and DeletedUid.

One minor issue was found in AuditUidUtils.applyOnUpdate regarding soft deletion via Update: when soft-deleting by setting DeletedAt to a non-null timestamp in Update, DeletedUid is deleted from the payload instead of stamped with the active actor. An inline comment with a suggested fix has been posted.


🤖 Reviewed by codereviewbot.ai - Catch bugs before your team does.

Comment thread modules/core/service/orm/utils/audit_uid.ts Outdated
- When applyOnUpdate sees a non-null DeletedAt, set DeletedUid from the actor (and strip client values without an actor), matching restore clearing and Delete soft-delete SET semantics.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codereviewbot-ai

Copy link
Copy Markdown

🤖 Review skipped: Repository rate limit exceeded. Free accounts are limited to 2 reviews per 4 hours per repository. Upgrade to a paid plan for unlimited reviews.

@buke
buke merged commit 5302e50 into main Aug 10, 2026
43 checks passed
@buke
buke deleted the feat/basemodel-audit-uid branch August 10, 2026 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant