Skip to content

feat(orm,web): add image field upload and dimension limits (PR-P2-F3) - #224

Open
buke wants to merge 6 commits into
mainfrom
feat/orm-image-limits-p2-f3
Open

feat(orm,web): add image field upload and dimension limits (PR-P2-F3)#224
buke wants to merge 6 commits into
mainfrom
feat/orm-image-limits-p2-f3

Conversation

@buke

@buke buke commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

  • Add @Field({ type: 'image'|'binary', maxUploadBytes?, maxWidth?, maxHeight? }) through FieldMetadata, IR/codegen, and FieldsGet (wire keys only; no silent resize).
  • Cap field maxUploadBytes against document.attachment.maxUploadBytes default (DEFAULT_GLOBAL_MAX_UPLOAD_BYTES = 20 MiB); FE OImageField and BE bindAttachment reject oversize bytes/dimensions.
  • Shared constant lives in core; document re-exports it. Design §6/D2 updated locally under .dev/ (gitignored) to name the config key.

Test plan

  • go test ./internal/parser/backendtsparser/ ./internal/module/artifact/generate/ -count=1
  • ./choysum test unit core --be (decorator / FieldsGet image limits)
  • ./choysum test unit web --fe (OImageField / imageFieldLimits)
  • ./choysum test unit document --be (bind field limits)
  • ./choysum test typecheck core / web / document
  • CI green on this PR

Made with Cursor


PR Type

Enhancement, Tests


Description

  • Go Core: Add maxUploadBytes, maxWidth, and maxHeight to field IR metadata, TS parser, and web API store generator.

  • TypeScript Modules: Enforce upload and dimension limits in @Field decorators, FieldsGet facade, document attachment bindings, and web OImageField.

  • SPDX & Licensing: Added 4 new TypeScript source/test files with SPDX Apache-2.0 headers, maintaining clean module boundaries.

  • Test Coverage: Expanded Go parser unit tests, TS ORM decorator/FieldsGet tests, document binding limit tests, and web Vue component tests.


File Walkthrough

Relevant files
Enhancement
14 files
webapistore.go
Add upload limit fields to generated metadata                       
+15/-0   
webapistore.ts.tpl
Emit upload limit fields in web API store template             
+3/-0     
field_resolved.go
Parse upload and dimension limits from field options         
+18/-0   
meta_field.go
Add upload limit fields to field IR struct                             
+10/-0   
field.ts
Validate upload and dimension limits in Field decorator   
+52/-0   
field.ts
Add upload limit properties to FieldMetadata types             
+39/-1   
model_fields_get_facade.ts
Expose upload limit metadata in FieldsGet payload               
+12/-0   
upload_limits.ts
Define global default max upload byte constant                     
+9/-0     
_attachment_binding_ops.ts
Validate attachment content against field upload limits   
+100/-0 
_upload.ts
Re-export global max upload byte limit constant                   
+4/-1     
imageFieldLimits.ts
Add frontend image dimension and byte limit validators     
+109/-0 
OImageField.vue
Validate image upload dimensions and size before selection
+35/-0   
fieldsGet.ts
Include upload limit attributes in FieldsGet requests       
+3/-0     
modelStore.ts
Add upload limit fields to WebFieldMetadata interface       
+6/-0     
Tests
4 files
parser_migration_test.go
Add Go parser tests for image limit metadata                         
+59/-0   
field.test.ts
Add unit tests for Field upload limit options                       
+61/-0   
attachment_binding_limits.test.ts
Add unit tests for attachment binding limit validation     
+72/-0   
OImageField.test.ts
Add unit tests for frontend image validation helpers         
+41/-0   
Documentation
2 files
web.pot
Add i18n translation keys for image upload limit errors   
+15/-0   
zh_CN.po
Add Chinese translations for image limit error messages   
+15/-0   
Additional files
2 files
model_fields_get.test.ts +40/-0   
fieldsGet.test.ts +1/-1     

Summary by CodeRabbit

  • New Features

    • Added configurable upload-size limits for binary and image fields.
    • Added image width and height limits.
    • Field metadata now exposes configured upload constraints across model and web interfaces.
    • Added a shared 20 MiB global upload cap.
  • Bug Fixes

    • Invalid files are rejected before upload or attachment binding.
    • Added validation messages for oversized files and images exceeding dimension limits.
    • Improved localized messages for upload validation errors.

- Allow @field image/binary maxUploadBytes/maxWidth/maxHeight wired through FieldsGet/codegen.

- Reject oversized uploads in OImageField and Bind against document.attachment.maxUploadBytes default.

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

coderabbitai Bot commented Jul 31, 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: 34 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: 507e54d9-cf9d-436a-8706-ccf72ab1b319

📥 Commits

Reviewing files that changed from the base of the PR and between 8d169e5 and e1ec5e6.

📒 Files selected for processing (4)
  • internal/parser/backendtsparser/field_resolved.go
  • internal/parser/backendtsparser/parser_migration_test.go
  • modules/document/service/models/_attachment_binding_ops.ts
  • modules/web/web/components/field/OImageField.test.ts
📝 Walkthrough

Walkthrough

The change adds per-field upload-byte and image-dimension limits. It validates and stores these limits, propagates them through parser and metadata APIs, enforces them during attachment binding, and validates image uploads in the web component.

Changes

Per-field upload limits

Layer / File(s) Summary
Field limit contracts and persistence
modules/core/service/orm/metadata/field.ts, modules/core/service/orm/upload_limits.ts, pkg/meta/meta_field.go
Field options and metadata now support upload-byte, width, and height limits. A shared 20 MiB global upload cap is exported.
Parser and generated metadata
internal/parser/backendtsparser/field_resolved.go, internal/parser/backendtsparser/parser_migration_test.go, internal/module/artifact/generate/*
Parser and artifact generation preserve positive upload and image dimension limits and omit unset values.
Decorator validation and FieldsGet projection
modules/core/service/orm/decorator/field.ts, modules/core/service/orm/model/*
Decorators validate limits by field type and global cap. FieldsGet returns positive limits when requested.
Attachment binding enforcement
modules/document/service/models/*, modules/document/service/tests/attachment_binding_limits.test.ts, modules/document/i18n/*
Attachment binding enforces effective byte, width, and height limits. Related validation messages and translations are updated.
Web metadata and image validation
modules/web/web/components/field/*, modules/web/web/stores/*, modules/web/i18n/*
Web metadata requests include the new limits. OImageField validates file size and natural dimensions before updating field state.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OImageField
  participant FieldsGet
  participant imageFieldLimits
  participant AttachmentBinding
  OImageField->>FieldsGet: request field limit metadata
  FieldsGet-->>OImageField: return maxUploadBytes, maxWidth, maxHeight
  OImageField->>imageFieldLimits: validate selected image
  imageFieldLimits-->>OImageField: return validation result
  OImageField->>AttachmentBinding: submit valid attachment
  AttachmentBinding-->>OImageField: accept or reject field limits
Loading

Possibly related PRs

Suggested labels: Review effort 3/5

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.81% 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 image field upload and dimension limits across ORM and web components.
Description check ✅ Passed The description provides a detailed summary, implementation scope, file walkthrough, and test plan relevant to the pull request.
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/orm-image-limits-p2-f3

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

- Keep a single DEFAULT_GLOBAL_MAX_UPLOAD_BYTES import via _upload re-export.

Co-authored-by: Cursor <cursoragent@cursor.com>
@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 ✨

No code suggestions found for the PR.

- Extract Bind validation messages into document.pot.
- Add zh_CN translations for maxUploadBytes/maxWidth/maxHeight errors.

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

codecov Bot commented Jul 31, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.40828% with 1 line in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...dules/web/web/components/field/imageFieldLimits.ts 98.5% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

buke and others added 2 commits July 31, 2026 21:27
- Cover webapistore MaxUploadBytes/Width/Height metadata emission.
- Expand imageFieldLimits and OImageField gate unit tests to full branches.
- Broaden attachment binding field-limit validation cases and simplify effective byte cap.

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

- Keep OImageField msgid literals extractable via imageFieldLimits _t calls.
- Move limit source resolution out of the Vue SFC to drop the remaining partial.
- Cover missing model metadata and non-numeric dimension probes on Bind validation.

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: 1

🧹 Nitpick comments (3)
modules/web/web/components/field/OImageField.test.ts (1)

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

Import the shared upload cap constant instead of duplicating its value.

Line 20 hardcodes 20 * 1024 * 1024 as a local DEFAULT_GLOBAL_MAX_UPLOAD_BYTES. The sibling test attachment_binding_limits.test.ts imports the same constant from @/core/service/orm/upload_limits. If the shared constant changes, this duplicated value goes stale and the assertions at lines 110-112 silently validate the wrong cap.

♻️ Proposed refactor to import the shared constant
-const DEFAULT_GLOBAL_MAX_UPLOAD_BYTES = 20 * 1024 * 1024;
+import { DEFAULT_GLOBAL_MAX_UPLOAD_BYTES } from '`@/core/service/orm/upload_limits`';
🤖 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/components/field/OImageField.test.ts` at line 20, Replace the
locally duplicated DEFAULT_GLOBAL_MAX_UPLOAD_BYTES value in OImageField.test.ts
with an import of the shared constant from `@/core/service/orm/upload_limits`, and
keep the existing assertions using that imported symbol.
modules/document/service/models/_attachment_binding_ops.ts (2)

556-557: 🧹 Nitpick | 🔵 Trivial

LGTM!

For future work: since the field-specific check only runs at bind time, content that fits the global cap but exceeds a stricter field limit is fully uploaded and stored before rejection. If this becomes a storage-cost concern, consider surfacing field-specific limits earlier in the upload/finalize flow as well.

🤖 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/document/service/models/_attachment_binding_ops.ts` around lines 556
- 557, For future work, consider moving the field-specific validation currently
performed by validateAttachmentContentFieldLimits in the attachment binding flow
earlier into the upload or finalize path, so content exceeding the
ownerModel/fieldName limit is rejected before full storage while preserving the
existing global cap validation.

85-134: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove unnecessary as any casts on typed AttachmentContent fields.

attachmentContent is typed as AttachmentContent, and that model already declares SizeBytes, ImageWidth, and ImageHeight as typed fields. Casting to any at lines 87, 104, and 105 bypasses type checking for no functional reason. Access the fields directly to keep type safety on this validation path.

♻️ Proposed refactor to drop the `as any` casts
-    const sizeBytes = Number((attachmentContent as any).SizeBytes ?? 0);
+    const sizeBytes = Number(attachmentContent.SizeBytes ?? 0);
-    const imageWidth = (attachmentContent as any).ImageWidth;
-    const imageHeight = (attachmentContent as any).ImageHeight;
+    const imageWidth = attachmentContent.ImageWidth;
+    const imageHeight = attachmentContent.ImageHeight;

Please confirm that the AttachmentContent type used in this file's imports actually exposes SizeBytes, ImageWidth, and ImageHeight without further casting, since the type is not fully shown in the reviewed excerpt.

🤖 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/document/service/models/_attachment_binding_ops.ts` around lines 85 -
134, In the attachment validation logic, remove the unnecessary any casts from
accesses to attachmentContent.SizeBytes, attachmentContent.ImageWidth, and
attachmentContent.ImageHeight. Confirm the imported AttachmentContent type
exposes these fields directly, then preserve the existing fallback and
dimension-validation behavior while relying on compile-time type checking.
🤖 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 `@internal/parser/backendtsparser/field_resolved.go`:
- Around line 779-787: Clear the MaxUploadBytes, MaxWidth, and MaxHeight fields
to 0 before the conditional checks that reapply them from spec.Structural. This
ensures that when a developer removes these constraints from the source, the
previously persisted values do not stick around on the next parse. Apply the
same clear-before-reapply pattern already established for the FieldHelp and
HelpText fields (visible just below in the same function) to prevent stale
upload-limit values from flowing into convertFieldToMetadata and affecting
generated Web API metadata.

---

Nitpick comments:
In `@modules/document/service/models/_attachment_binding_ops.ts`:
- Around line 556-557: For future work, consider moving the field-specific
validation currently performed by validateAttachmentContentFieldLimits in the
attachment binding flow earlier into the upload or finalize path, so content
exceeding the ownerModel/fieldName limit is rejected before full storage while
preserving the existing global cap validation.
- Around line 85-134: In the attachment validation logic, remove the unnecessary
any casts from accesses to attachmentContent.SizeBytes,
attachmentContent.ImageWidth, and attachmentContent.ImageHeight. Confirm the
imported AttachmentContent type exposes these fields directly, then preserve the
existing fallback and dimension-validation behavior while relying on
compile-time type checking.

In `@modules/web/web/components/field/OImageField.test.ts`:
- Line 20: Replace the locally duplicated DEFAULT_GLOBAL_MAX_UPLOAD_BYTES value
in OImageField.test.ts with an import of the shared constant from
`@/core/service/orm/upload_limits`, and keep the existing assertions using that
imported symbol.
🪄 Autofix (Beta)

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: 509d7a4b-af57-4a4a-b491-e8b5be5c9a86

📥 Commits

Reviewing files that changed from the base of the PR and between e104e8a and 8d169e5.

📒 Files selected for processing (25)
  • internal/module/artifact/generate/webapistore.go
  • internal/module/artifact/generate/webapistore.ts.tpl
  • internal/module/artifact/generate/webapistore_test.go
  • internal/parser/backendtsparser/field_resolved.go
  • internal/parser/backendtsparser/parser_migration_test.go
  • modules/core/service/orm/decorator/field.test.ts
  • modules/core/service/orm/decorator/field.ts
  • modules/core/service/orm/metadata/field.ts
  • modules/core/service/orm/model/model_fields_get.test.ts
  • modules/core/service/orm/model/model_fields_get_facade.ts
  • modules/core/service/orm/upload_limits.ts
  • modules/document/i18n/document.pot
  • modules/document/i18n/zh_CN.po
  • modules/document/service/models/_attachment_binding_ops.ts
  • modules/document/service/models/_upload.ts
  • modules/document/service/tests/attachment_binding_limits.test.ts
  • modules/web/i18n/web.pot
  • modules/web/i18n/zh_CN.po
  • modules/web/web/components/field/OImageField.test.ts
  • modules/web/web/components/field/OImageField.vue
  • modules/web/web/components/field/imageFieldLimits.ts
  • modules/web/web/stores/fieldsGet.test.ts
  • modules/web/web/stores/fieldsGet.ts
  • modules/web/web/stores/modelStore.ts
  • pkg/meta/meta_field.go

Comment thread internal/parser/backendtsparser/field_resolved.go
- Reset MaxUploadBytes/MaxWidth/MaxHeight before reapply so removed options do not stick.
- Drop unnecessary AttachmentContent any casts and import the shared upload cap in FE tests.
- Cover empty leaf resolution and missing URL when probing image dimensions.

Co-authored-by: Cursor <cursoragent@cursor.com>
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