Skip to content

Commit be70745

Browse files
authored
Merge pull request #241 from objectstack-ai/copilot/review-and-modify-metadata
2 parents 5bb51d0 + 5dbaa34 commit be70745

14 files changed

Lines changed: 154 additions & 167 deletions

File tree

ROADMAP.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
| Studio Builder Configs | 4 (Interface Builder, Page Builder, Canvas Snap, Element Palette) |
6666
| Navigation Areas | 3 (header, sidebar, utility bar) |
6767
| Packages Registered in Root Config | 13 of 13 (all packages registered) |
68-
| Test Files | 194 files, 3813 tests (all passing) |
68+
| Test Files | 195 files, 3817 tests (all passing) |
6969
| TypeScript Compliance | 100% (zero type errors) |
7070
| Protocol Compliance | 100% (all objects pass ObjectSchema.create()) |
7171
| Spec Schema Adoption | ~95 of ~95 application-level schemas used (~100%) |
@@ -203,13 +203,15 @@ These items were deferred during Phase 13 and have been completed:
203203
- [ ] **Legacy API cleanup (Phase 2)** — Remove `db.ts` exports entirely once all consumers migrated to broker/ObjectQL
204204
- [ ] **E2E test coverage** — Build API-layer end-to-end tests for Feed API / MCP API
205205
- [ ] **FormView `as any` cleanup** — Remove `as any` casts once `@objectstack/spec` aligns FormView column types
206+
- [x] **Events metadata schema validation** — Added `EventTypeDefinitionSchema.parse()` to all 9 `*.events.ts` files; all metadata now validated against spec schemas
206207

207208
---
208209

209210
## Version Upgrade History
210211

211212
| Date | From | To | Breaking Changes | Tests |
212213
|------|------|----|-----------------|-------|
214+
| 2026-02-26 | v3.0.8 | v3.0.8 | None (Phase 15: Added EventTypeDefinitionSchema validation to all 9 events.ts files; 100% metadata schema compliance) | 3817 ✅ |
213215
| 2026-02-25 | v3.0.8 | v3.0.8 | None (Phase 15: Fixed tsconfig.json path aliases for node16 ESM module resolution — changed directory paths to explicit index.ts files) | 3813 ✅ |
214216
| 2026-02-21 | v3.0.8 | v3.0.8 | None (Phase 15 continued: Structured pino logging across 154 files, CacheManager test isolation, db.ts deprecation annotations, emoji removal from logs) | 3813 ✅ |
215217
| 2026-02-21 | v3.0.8 | v3.0.8 | None (Phase 15: Repository quality improvements — hook `any` type migration, CI typecheck, ESLint version alignment, documentation updates, code-quality workflow fixes) | 3799 ✅ |

content/docs/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ Explore the six business clouds that power every stage of the customer lifecycle
9090
| **Server-Side Hooks** | 121+ hooks enforcing business logic |
9191
| **Integration Connectors** | 10 (Stripe, DocuSign, Slack, Gmail, Teams, PayPal, Adobe Sign, Outlook, QuickBooks, LinkedIn) |
9292
| **AI Agent Workflows** | 13 AI agents + 6 autonomous workflows |
93-
| **Tests** | 3,707 passing across 188 test files |
93+
| **Tests** | 3,817 passing across 195 test files |
9494

9595
## 📚 Resources
9696

content/docs/roadmap.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ HotCRM has completed **16 development phases** (1–14 including 10.5, 10.6, 12A
7171
| Seed Data Files | 39 across 14 packages |
7272
| Seed Data Validation | ✅ All seed files validated with cross-package relationship tests |
7373
| Dependency Graph | 14 packages with topological load order validation |
74-
| Test Files | 192 files, 3,799 tests (all passing) |
74+
| Test Files | 195 files, 3,817 tests (all passing) |
7575
| TypeScript Compliance | 100% (zero type errors) |
7676
| Spec Schema Adoption | ~95 / ~95 (~100%) |
7777

packages/analytics/src/analytics.events.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,23 @@
44
* Defines the event contracts for cross-package communication.
55
* Other plugins can subscribe to these events to react to Analytics domain changes.
66
*/
7+
import { EventTypeDefinitionSchema } from '@objectstack/spec/kernel';
78

89
export const AnalyticsEvents = {
9-
reportExecuted: {
10+
reportExecuted: EventTypeDefinitionSchema.parse({
1011
name: 'analytics.report.executed',
11-
type: 'domain' as const,
1212
description: 'Fired when a report is executed and results are generated',
13-
},
14-
dashboardRefreshed: {
13+
}),
14+
dashboardRefreshed: EventTypeDefinitionSchema.parse({
1515
name: 'analytics.dashboard.refreshed',
16-
type: 'domain' as const,
1716
description: 'Fired when a dashboard is refreshed with updated data',
18-
},
19-
kpiThresholdBreached: {
17+
}),
18+
kpiThresholdBreached: EventTypeDefinitionSchema.parse({
2019
name: 'analytics.kpi.threshold_breached',
21-
type: 'domain' as const,
2220
description: 'Fired when a KPI value crosses a warning or critical threshold',
23-
},
24-
dataSourceSynced: {
21+
}),
22+
dataSourceSynced: EventTypeDefinitionSchema.parse({
2523
name: 'analytics.data_source.synced',
26-
type: 'domain' as const,
2724
description: 'Fired when a data source completes a sync operation',
28-
},
25+
}),
2926
};

packages/community/src/community.events.ts

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,23 @@
44
* Defines the event contracts for cross-package communication.
55
* Other plugins can subscribe to these events to react to Community domain changes.
66
*/
7+
import { EventTypeDefinitionSchema } from '@objectstack/spec/kernel';
78

89
export const CommunityEvents = {
9-
topicCreated: {
10+
topicCreated: EventTypeDefinitionSchema.parse({
1011
name: 'community.topic.created',
11-
type: 'domain' as const,
1212
description: 'Fired when a new topic is created in the forum',
13-
},
14-
replyPosted: {
13+
}),
14+
replyPosted: EventTypeDefinitionSchema.parse({
1515
name: 'community.reply.posted',
16-
type: 'domain' as const,
1716
description: 'Fired when a reply is posted to a topic',
18-
},
19-
ideaSubmitted: {
17+
}),
18+
ideaSubmitted: EventTypeDefinitionSchema.parse({
2019
name: 'community.idea.submitted',
21-
type: 'domain' as const,
2220
description: 'Fired when a new idea is submitted for consideration',
23-
},
24-
badgeAwarded: {
21+
}),
22+
badgeAwarded: EventTypeDefinitionSchema.parse({
2523
name: 'community.badge.awarded',
26-
type: 'domain' as const,
2724
description: 'Fired when a badge is awarded to a community member',
28-
},
25+
}),
2926
};
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { EventTypeDefinitionSchema } from '@objectstack/spec/kernel';
3+
import { CRMEvents } from '../../../src/crm.events';
4+
5+
describe('CRM Events Schema Compliance', () => {
6+
it('should be defined and non-empty', () => {
7+
expect(CRMEvents).toBeDefined();
8+
expect(Object.keys(CRMEvents).length).toBeGreaterThan(0);
9+
});
10+
11+
it('each event should re-validate against EventTypeDefinitionSchema', () => {
12+
for (const [key, event] of Object.entries(CRMEvents)) {
13+
expect(() => EventTypeDefinitionSchema.parse(event), `Event "${key}" failed re-validation`).not.toThrow();
14+
}
15+
});
16+
17+
it('each event should have required properties from schema', () => {
18+
for (const [, event] of Object.entries(CRMEvents)) {
19+
expect(event).toHaveProperty('name');
20+
expect(event).toHaveProperty('description');
21+
expect(event).toHaveProperty('version');
22+
}
23+
});
24+
25+
it('event names should follow domain naming convention', () => {
26+
for (const [, event] of Object.entries(CRMEvents)) {
27+
expect(event.name).toMatch(/^crm\./);
28+
}
29+
});
30+
});

packages/crm/__tests__/unit/schemas/plugin-schema.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ describe('CRM Plugin Schema Compliance', () => {
4646
expect(CRMEvents.leadConverted).toBeDefined();
4747
});
4848

49-
it('each event should have a name and type', () => {
49+
it('each event should have a name and description', () => {
5050
for (const [, event] of Object.entries(CRMEvents)) {
5151
expect(event).toHaveProperty('name');
52-
expect(event).toHaveProperty('type');
52+
expect(event).toHaveProperty('description');
5353
}
5454
});
5555
});

packages/crm/src/crm.events.ts

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,43 @@
44
* Defines the event contracts for cross-package communication.
55
* Other plugins can subscribe to these events to react to CRM domain changes.
66
*/
7+
import { EventTypeDefinitionSchema } from '@objectstack/spec/kernel';
78

89
export const CRMEvents = {
9-
accountCreated: {
10+
accountCreated: EventTypeDefinitionSchema.parse({
1011
name: 'crm.account.created',
11-
type: 'domain' as const,
1212
description: 'Fired when a new account is created',
13-
},
14-
accountUpdated: {
13+
}),
14+
accountUpdated: EventTypeDefinitionSchema.parse({
1515
name: 'crm.account.updated',
16-
type: 'domain' as const,
1716
description: 'Fired when an account record is updated',
18-
},
19-
contactCreated: {
17+
}),
18+
contactCreated: EventTypeDefinitionSchema.parse({
2019
name: 'crm.contact.created',
21-
type: 'domain' as const,
2220
description: 'Fired when a new contact is created',
23-
},
24-
leadConverted: {
21+
}),
22+
leadConverted: EventTypeDefinitionSchema.parse({
2523
name: 'crm.lead.converted',
26-
type: 'domain' as const,
2724
description: 'Fired when a lead is converted to account/contact/opportunity',
28-
},
29-
leadScored: {
25+
}),
26+
leadScored: EventTypeDefinitionSchema.parse({
3027
name: 'crm.lead.scored',
31-
type: 'domain' as const,
3228
description: 'Fired when a lead score is recalculated',
33-
},
34-
opportunityStageChanged: {
29+
}),
30+
opportunityStageChanged: EventTypeDefinitionSchema.parse({
3531
name: 'crm.opportunity.stage_changed',
36-
type: 'domain' as const,
3732
description: 'Fired when an opportunity moves to a new stage',
38-
},
39-
opportunityWon: {
33+
}),
34+
opportunityWon: EventTypeDefinitionSchema.parse({
4035
name: 'crm.opportunity.won',
41-
type: 'domain' as const,
4236
description: 'Fired when an opportunity is closed-won',
43-
},
44-
opportunityLost: {
37+
}),
38+
opportunityLost: EventTypeDefinitionSchema.parse({
4539
name: 'crm.opportunity.lost',
46-
type: 'domain' as const,
4740
description: 'Fired when an opportunity is closed-lost',
48-
},
49-
activityCompleted: {
41+
}),
42+
activityCompleted: EventTypeDefinitionSchema.parse({
5043
name: 'crm.activity.completed',
51-
type: 'domain' as const,
5244
description: 'Fired when an activity or task is marked as completed',
53-
},
45+
}),
5446
};

packages/finance/src/finance.events.ts

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,35 @@
44
* Defines the event contracts for cross-package communication.
55
* Other plugins can subscribe to these events to react to Finance domain changes.
66
*/
7+
import { EventTypeDefinitionSchema } from '@objectstack/spec/kernel';
78

89
export const FinanceEvents = {
9-
invoiceCreated: {
10+
invoiceCreated: EventTypeDefinitionSchema.parse({
1011
name: 'finance.invoice.created',
11-
type: 'domain' as const,
1212
description: 'Fired when a new invoice is created',
13-
},
14-
invoicePaid: {
13+
}),
14+
invoicePaid: EventTypeDefinitionSchema.parse({
1515
name: 'finance.invoice.paid',
16-
type: 'domain' as const,
1716
description: 'Fired when an invoice is fully paid',
18-
},
19-
invoiceOverdue: {
17+
}),
18+
invoiceOverdue: EventTypeDefinitionSchema.parse({
2019
name: 'finance.invoice.overdue',
21-
type: 'domain' as const,
2220
description: 'Fired when an invoice becomes overdue',
23-
},
24-
paymentReceived: {
21+
}),
22+
paymentReceived: EventTypeDefinitionSchema.parse({
2523
name: 'finance.payment.received',
26-
type: 'domain' as const,
2724
description: 'Fired when a payment is received and recorded',
28-
},
29-
contractActivated: {
25+
}),
26+
contractActivated: EventTypeDefinitionSchema.parse({
3027
name: 'finance.contract.activated',
31-
type: 'domain' as const,
3228
description: 'Fired when a contract is activated',
33-
},
34-
contractRenewed: {
29+
}),
30+
contractRenewed: EventTypeDefinitionSchema.parse({
3531
name: 'finance.contract.renewed',
36-
type: 'domain' as const,
3732
description: 'Fired when a contract is renewed',
38-
},
39-
contractExpiring: {
33+
}),
34+
contractExpiring: EventTypeDefinitionSchema.parse({
4035
name: 'finance.contract.expiring',
41-
type: 'domain' as const,
4236
description: 'Fired when a contract is approaching its expiration date',
43-
},
37+
}),
4438
};

packages/hr/src/hr.events.ts

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,35 @@
44
* Defines the event contracts for cross-package communication.
55
* Other plugins can subscribe to these events to react to HR domain changes.
66
*/
7+
import { EventTypeDefinitionSchema } from '@objectstack/spec/kernel';
78

89
export const HREvents = {
9-
employeeOnboarded: {
10+
employeeOnboarded: EventTypeDefinitionSchema.parse({
1011
name: 'hr.employee.onboarded',
11-
type: 'domain' as const,
1212
description: 'Fired when a new employee completes onboarding',
13-
},
14-
employeeTerminated: {
13+
}),
14+
employeeTerminated: EventTypeDefinitionSchema.parse({
1515
name: 'hr.employee.terminated',
16-
type: 'domain' as const,
1716
description: 'Fired when an employee is terminated',
18-
},
19-
candidateHired: {
17+
}),
18+
candidateHired: EventTypeDefinitionSchema.parse({
2019
name: 'hr.candidate.hired',
21-
type: 'domain' as const,
2220
description: 'Fired when a candidate is hired and converted to employee',
23-
},
24-
offerAccepted: {
21+
}),
22+
offerAccepted: EventTypeDefinitionSchema.parse({
2523
name: 'hr.offer.accepted',
26-
type: 'domain' as const,
2724
description: 'Fired when an offer letter is accepted by a candidate',
28-
},
29-
performanceReviewCompleted: {
25+
}),
26+
performanceReviewCompleted: EventTypeDefinitionSchema.parse({
3027
name: 'hr.performance_review.completed',
31-
type: 'domain' as const,
3228
description: 'Fired when a performance review cycle is completed',
33-
},
34-
timeOffApproved: {
29+
}),
30+
timeOffApproved: EventTypeDefinitionSchema.parse({
3531
name: 'hr.time_off.approved',
36-
type: 'domain' as const,
3732
description: 'Fired when a time-off request is approved',
38-
},
39-
payrollProcessed: {
33+
}),
34+
payrollProcessed: EventTypeDefinitionSchema.parse({
4035
name: 'hr.payroll.processed',
41-
type: 'domain' as const,
4236
description: 'Fired when payroll is processed for a pay period',
43-
},
37+
}),
4438
};

0 commit comments

Comments
 (0)