-
Notifications
You must be signed in to change notification settings - Fork 0
Migrate Activity, Quote, and Case objects to TypeScript (Phase 1) #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…ode review Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR migrates three core business objects (Activity, Quote, and Case) from YAML to TypeScript format following the @objectstack/spec v0.6.1 protocol. The migration establishes type-safe object definitions with comprehensive field schemas, validation rules, list views, and AI enhancement capabilities.
Changes:
- Migrated Activity, Quote, and Case objects to TypeScript with 10 activity types, CPQ workflow, and multi-channel case management respectively
- Fixed export pattern from
export *toexport { default as ... }for proper default export re-export in all three packages - Updated package READMEs and created comprehensive MIGRATION_NOTES.md documenting features, breaking changes, and migration path
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/crm/src/activity.object.ts | New TypeScript definition for Activity with 10 types, Who/What polymorphic relationships, recurring tasks, check-in GPS, AI transcription/sentiment, and 9 validation rules |
| packages/crm/src/index.ts | Fixed export pattern from export * to export { default as Activity } and updated for all objects |
| packages/crm/README.md | Updated to reflect Activity migration and corrected import examples |
| packages/products/src/quote.object.ts | New TypeScript definition for Quote with CPQ workflow, multi-currency support, approval workflow, quote versioning, PDF generation, and AI pricing analysis |
| packages/products/src/index.ts | Added Quote export using corrected pattern export { default as Quote } |
| packages/products/README.md | Updated documentation showing Quote as TypeScript definition with usage examples |
| packages/support/src/case.object.ts | New TypeScript definition for Case with 8 origin channels, SLA engine, priority/severity matrix, escalation tracking, CSAT, AI routing, and 7 validation rules |
| packages/support/src/index.ts | Added Case export using pattern export { default as Case } |
| packages/support/README.md | Updated to document Case migration from YAML to TypeScript |
| MIGRATION_NOTES.md | Comprehensive migration documentation with features, validation rules, list views, breaking changes, and next steps |
| { | ||
| name: 'ContactMustBelongToAccount', | ||
| errorMessage: 'Contact must belong to the selected Account', | ||
| formula: 'AND(NOT(ISBLANK(ContactId)), NOT(ISBLANK(AccountId)))' |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation rule formula does not actually validate that the Contact belongs to the selected Account. The current formula 'AND(NOT(ISBLANK(ContactId)), NOT(ISBLANK(AccountId)))' only checks that both fields are populated, but doesn't verify the relationship between them.
To properly validate the relationship, you would need to use a formula like 'AND(NOT(ISBLANK(ContactId)), NOT(ISBLANK(AccountId)), Contact.AccountId != AccountId)' or rely on a backend validation hook that can perform cross-object queries. If this type of reference validation is not supported in the validation rule formula language, consider removing this validation rule and implementing it in a hook instead.
| formula: 'AND(NOT(ISBLANK(ContactId)), NOT(ISBLANK(AccountId)))' | |
| formula: 'AND(NOT(ISBLANK(ContactId)), NOT(ISBLANK(AccountId)), Contact.AccountId != AccountId)' |
| name: 'PrimaryQuoteUnique', | ||
| errorMessage: 'Only one primary quote allowed per opportunity', | ||
| formula: 'AND(IsPrimaryQuote = true, OpportunityId != null)' | ||
| }, | ||
| { |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation rule does not enforce uniqueness of primary quotes per opportunity. The formula 'AND(IsPrimaryQuote = true, OpportunityId != null)' will trigger for EVERY primary quote that has an opportunity, not just when there's a duplicate.
To properly enforce "only one primary quote per opportunity", you would need a formula that can count other primary quotes for the same opportunity, or implement this as a unique constraint at the database level or in a hook. Consider either:
- Implementing this validation in a before-save hook that queries for existing primary quotes on the same opportunity
- Using a database unique constraint on (OpportunityId, IsPrimaryQuote) where IsPrimaryQuote = true
- Removing this validation rule if the enforcement mechanism is not supported
| name: 'PrimaryQuoteUnique', | |
| errorMessage: 'Only one primary quote allowed per opportunity', | |
| formula: 'AND(IsPrimaryQuote = true, OpportunityId != null)' | |
| }, | |
| { |
| { | ||
| name: 'AcceptedQuoteReadOnly', | ||
| errorMessage: 'Accepted quotes cannot be modified', | ||
| formula: 'AND(Status = "Accepted", ISCHANGED(Status) = false)' |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation rule has inverted logic. The formula 'AND(Status = "Accepted", ISCHANGED(Status) = false)' triggers when the Status is "Accepted" AND the Status field has NOT changed, which means it would fire when you modify other fields on an already-accepted quote but NOT when you modify the status itself.
The intention appears to be preventing ANY modifications to accepted quotes. The formula should be 'AND(PRIORVALUE(Status) = "Accepted", NOT(ISNEW()))' to trigger when trying to modify a record that was previously in Accepted status, similar to the ClosedCaseReadOnly validation rule in the Case object (line 534).
| formula: 'AND(Status = "Accepted", ISCHANGED(Status) = false)' | |
| formula: 'AND(PRIORVALUE(Status) = "Accepted", NOT(ISNEW()))' |
| }, | ||
| { | ||
| name: 'ClosedCaseReadOnly', | ||
| errorMessage: 'Closed cases cannot be modified', |
Copilot
AI
Jan 29, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This validation rule only prevents changing the Status FROM "Closed" to another value, but doesn't prevent modifying other fields on a case that remains in Closed status. The error message "Closed cases cannot be modified" suggests broader immutability.
If the intent is to make closed cases completely read-only (no field modifications), the formula should be 'AND(PRIORVALUE(Status) = "Closed", NOT(ISNEW()))' which would trigger on any modification attempt to a previously-closed record. If the current behavior (only preventing status changes) is intentional, consider updating the error message to be more specific, such as "Cannot change status of a closed case".
| errorMessage: 'Closed cases cannot be modified', | |
| errorMessage: 'Cannot change status of a closed case', |
Description
Migrated three core business objects from YAML to TypeScript following @objectstack/spec v0.6.1, establishing type-safe object definitions with comprehensive field schemas, validation rules, and AI enhancement fields.
Type of Change
Changes Made
Activity Object (
packages/crm/src/activity.object.ts)Quote Object (
packages/products/src/quote.object.ts)Case Object (
packages/support/src/case.object.ts)Technical Implementation
Backward Compatibility
MIGRATION_NOTES.mdTesting
npm test)npm run lint)npm run build)Checklist
Additional Notes
Validation Rule Corrections Applied:
NOT(ISNEW())guardCodeQL Security Scan: 0 vulnerabilities detected
Statistics: 1,985 lines added across 10 files (3 object definitions, 3 index exports, 3 READMEs, 1 migration guide)
Original prompt
💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.