Skip to content

Commit a0293ae

Browse files
os-zhuangclaude
andcommitted
refactor(examples): author metadata via defineX factories (#2035)
Migrates every example authoring file across crm/showcase/todo from bare output-type literals (`: Page`, `: UI.ActionInput`, …) to the corresponding defineX factory. The factory accepts input-shape config and validates each definition at module load, so a malformed metadata object now fails loudly at authoring time instead of silently passing as `any` (#2023). Covers 36 files / 16 domains — including files the *.{domain}.ts filename scan missed (reports/index.ts, actions/index.ts, security/sales-roles.ts, …), which the new lint guard surfaced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6e64a05 commit a0293ae

36 files changed

Lines changed: 185 additions & 185 deletions

examples/app-crm/src/actions/convert-lead.action.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type * as UI from '@objectstack/spec/ui';
3+
import { defineAction } from '@objectstack/spec/ui';
44

55
/**
66
* Row-level action on crm_lead — launches the Convert Lead screen flow wizard.
77
* Shown as a button in the lead list row menu and in the lead record header.
88
*/
9-
export const ConvertLeadAction: UI.ActionInput = {
9+
export const ConvertLeadAction = defineAction({
1010
name: 'crm_convert_lead',
1111
label: 'Convert Lead',
1212
icon: 'ArrowRightCircle',
@@ -20,4 +20,4 @@ export const ConvertLeadAction: UI.ActionInput = {
2020
// hitting the flow's "already converted" guard screen. The flow keeps that
2121
// guard as a server-side backstop.
2222
visible: 'record.status != "converted"',
23-
};
23+
});

examples/app-crm/src/actions/park-lead.action.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type * as UI from '@objectstack/spec/ui';
3+
import { defineAction } from '@objectstack/spec/ui';
44

55
/**
66
* Row-level action on crm_lead — reassign the lead's owner.
@@ -11,7 +11,7 @@ import type * as UI from '@objectstack/spec/ui';
1111
* UndoManager — Ctrl+Z works too). Prompts for the new owner via one param
1212
* (pre-filled with "Triage Queue").
1313
*/
14-
export const ParkLeadAction: UI.ActionInput = {
14+
export const ParkLeadAction = defineAction({
1515
name: 'crm_park_lead',
1616
label: 'Reassign Lead',
1717
icon: 'UserPlus',
@@ -32,4 +32,4 @@ export const ParkLeadAction: UI.ActionInput = {
3232
],
3333
undoable: true,
3434
successMessage: 'Lead reassigned.',
35-
};
35+
});

examples/app-crm/src/analytics/crm.cube.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { Cube } from '@objectstack/spec/data';
3+
import { defineCube } from '@objectstack/spec/data';
44

55
/**
66
* Opportunity Pipeline Cube — revenue metrics broken down by stage,
77
* owner, and account for the CRM sales dashboard.
88
*/
9-
export const PipelineCube: Cube = {
9+
export const PipelineCube = defineCube({
1010
name: 'crm_pipeline',
1111
title: 'CRM Pipeline',
1212
description: 'Revenue and deal-count analytics across the sales pipeline.',
@@ -71,12 +71,12 @@ export const PipelineCube: Cube = {
7171
every: '1 hour',
7272
},
7373
public: false,
74-
};
74+
});
7575

7676
/**
7777
* Lead funnel cube — conversion metrics from lead to opportunity.
7878
*/
79-
export const LeadFunnelCube: Cube = {
79+
export const LeadFunnelCube = defineCube({
8080
name: 'crm_lead_funnel',
8181
title: 'CRM Lead Funnel',
8282
description: 'Lead volume and conversion rate analytics.',
@@ -119,4 +119,4 @@ export const LeadFunnelCube: Cube = {
119119
every: '30 minutes',
120120
},
121121
public: false,
122-
};
122+
});

examples/app-crm/src/connectors/crm-connectors.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { ConnectorInput } from '@objectstack/spec/integration';
3+
import { defineConnector } from '@objectstack/spec/integration';
44

55
/**
66
* HubSpot connector — sync contacts and deals bi-directionally.
77
* Uses OAuth2 for authentication; actual credentials come from environment.
88
*/
9-
export const HubSpotConnector: ConnectorInput = {
9+
export const HubSpotConnector = defineConnector({
1010
name: 'hubspot_crm',
1111
label: 'HubSpot CRM',
1212
type: 'saas',
@@ -86,12 +86,12 @@ export const HubSpotConnector: ConnectorInput = {
8686
requestTimeoutMs: 30000,
8787
status: 'inactive',
8888
enabled: true,
89-
};
89+
});
9090

9191
/**
9292
* Slack connector — post notifications to channels.
9393
*/
94-
export const SlackConnector: ConnectorInput = {
94+
export const SlackConnector = defineConnector({
9595
name: 'slack_notifications',
9696
label: 'Slack',
9797
type: 'api',
@@ -123,4 +123,4 @@ export const SlackConnector: ConnectorInput = {
123123
},
124124
status: 'inactive',
125125
enabled: true,
126-
};
126+
});

examples/app-crm/src/data/crm-mappings.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { Mapping } from '@objectstack/spec/data';
3+
import { defineMapping } from '@objectstack/spec/data';
44

55
/**
66
* CSV import mapping for bulk lead upload.
77
* Maps common CRM export column names to crm_lead fields.
88
*/
9-
export const LeadCsvImportMapping: Mapping = {
9+
export const LeadCsvImportMapping = defineMapping({
1010
name: 'csv_import_leads',
1111
label: 'CSV Import: Leads',
1212
sourceFormat: 'csv',
@@ -51,12 +51,12 @@ export const LeadCsvImportMapping: Mapping = {
5151
],
5252
errorPolicy: 'skip',
5353
batchSize: 500,
54-
};
54+
});
5555

5656
/**
5757
* JSON import mapping for contact sync from external systems (HubSpot, etc.).
5858
*/
59-
export const ContactJsonSyncMapping: Mapping = {
59+
export const ContactJsonSyncMapping = defineMapping({
6060
name: 'json_sync_contacts',
6161
label: 'JSON Sync: Contacts from HubSpot',
6262
sourceFormat: 'json',
@@ -72,4 +72,4 @@ export const ContactJsonSyncMapping: Mapping = {
7272
],
7373
errorPolicy: 'skip',
7474
batchSize: 250,
75-
};
75+
});
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { DatasourceInput } from '@objectstack/spec/data';
3+
import { defineDatasource } from '@objectstack/spec/data';
44

55
/**
66
* Primary CRM datasource — in-memory SQLite for the example.
77
* In production, swap `driver` to 'postgres' and supply real `config`.
88
*/
9-
export const CrmDatasource: DatasourceInput = {
9+
export const CrmDatasource = defineDatasource({
1010
name: 'crm_primary',
1111
label: 'CRM Primary Database',
1212
driver: 'sqlite',
@@ -18,12 +18,12 @@ export const CrmDatasource: DatasourceInput = {
1818
max: 5,
1919
},
2020
active: true,
21-
};
21+
});
2222

2323
/**
2424
* Read-replica for analytics queries — demonstrates datasource routing.
2525
*/
26-
export const CrmAnalyticsDatasource: DatasourceInput = {
26+
export const CrmAnalyticsDatasource = defineDatasource({
2727
name: 'crm_analytics',
2828
label: 'CRM Analytics Read Replica',
2929
driver: 'sqlite',
@@ -32,4 +32,4 @@ export const CrmAnalyticsDatasource: DatasourceInput = {
3232
readOnly: true,
3333
},
3434
active: true,
35-
};
35+
});

examples/app-crm/src/emails/deal-won.email.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { EmailTemplateDefinitionInput } from '@objectstack/spec/system';
3+
import { defineEmailTemplateDefinition } from '@objectstack/spec/system';
44

55
/**
66
* Sent when an opportunity moves to Closed Won.
77
* Referenced by the `notify_owner_deal_won` workflow action.
88
*/
9-
export const DealWonEmail: EmailTemplateDefinitionInput = {
9+
export const DealWonEmail = defineEmailTemplateDefinition({
1010
name: 'crm.deal_won',
1111
label: 'Deal Won — Owner Congrats',
1212
category: 'workflow',
@@ -33,4 +33,4 @@ Nice work!`,
3333
],
3434
active: true,
3535
description: 'Internal congrats email fired by the High-Value Deal workflow when stage = Closed Won.',
36-
};
36+
});

examples/app-crm/src/emails/lead-follow-up.email.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { EmailTemplateDefinitionInput } from '@objectstack/spec/system';
3+
import { defineEmailTemplateDefinition } from '@objectstack/spec/system';
44

55
/**
66
* Follow-up nudge sent by the Stale Opportunity workflow when no
77
* activity has been logged on a Lead for the configured threshold.
88
*/
9-
export const LeadFollowUpEmail: EmailTemplateDefinitionInput = {
9+
export const LeadFollowUpEmail = defineEmailTemplateDefinition({
1010
name: 'crm.lead_followup',
1111
label: 'Lead — Follow-Up Reminder',
1212
category: 'notification',
@@ -35,4 +35,4 @@ Follow up: {{lead_url}}`,
3535
],
3636
active: true,
3737
description: 'Internal reminder fired by the Stale Opportunity workflow.',
38-
};
38+
});

examples/app-crm/src/emails/welcome.email.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { EmailTemplateDefinitionInput } from '@objectstack/spec/system';
3+
import { defineEmailTemplateDefinition } from '@objectstack/spec/system';
44

55
/**
66
* Welcome email sent to a Contact after it's added to the CRM.
77
* Demonstrates marketing-category templates with a clear CTA.
88
*/
9-
export const WelcomeEmail: EmailTemplateDefinitionInput = {
9+
export const WelcomeEmail = defineEmailTemplateDefinition({
1010
name: 'crm.welcome',
1111
label: 'Welcome — New Contact',
1212
category: 'marketing',
@@ -36,4 +36,4 @@ Open your portal: {{portal_url}}`,
3636
replyTo: 'support@acme.example',
3737
active: true,
3838
description: 'Marketing welcome email sent on contact creation.',
39-
};
39+
});

examples/app-crm/src/extensions/contact.extension.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
22

3-
import type { ObjectExtensionInput } from '@objectstack/spec/data';
3+
import { defineObjectExtension } from '@objectstack/spec/data';
44

55
/**
66
* Extends the built-in crm_contact object with social-media fields.
77
* Demonstrates ObjectExtension — additive fields without re-declaring the
88
* whole object schema.
99
*/
10-
export const ContactExtension: ObjectExtensionInput = {
10+
export const ContactExtension = defineObjectExtension({
1111
extend: 'crm_contact',
1212
label: 'Contact (CRM Extended)',
1313
fields: {
@@ -35,4 +35,4 @@ export const ContactExtension: ObjectExtensionInput = {
3535
},
3636
},
3737
priority: 210,
38-
};
38+
});

0 commit comments

Comments
 (0)