Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 6 additions & 12 deletions examples/crm/objectstack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default App.create({
label: 'CRM App',
description: 'Comprehensive CRM example demonstrating all ObjectStack Protocol features',
version: '2.0.0',
icon: 'briefcase',

// All objects in the app
objects: [
Expand Down Expand Up @@ -85,17 +86,10 @@ export default App.create({
// Reports
reports: Object.values(CrmReports),

// App-level settings
settings: {
theme: {
primaryColor: '#4169E1',
logo: '/assets/crm-logo.png',
},
features: {
enableGlobalSearch: true,
enableNotifications: true,
enableMobileApp: true,
enableOfflineMode: true,
}
// App-level branding
branding: {
primaryColor: '#4169E1',
logo: '/assets/crm-logo.png',
favicon: '/assets/crm-favicon.ico',
}
});
52 changes: 33 additions & 19 deletions examples/crm/src/domains/crm/account.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const Account = ObjectSchema.create({
pluralLabel: 'Accounts',
icon: 'building',
description: 'Companies and organizations doing business with us',
nameField: 'name',

fields: {
// AutoNumber field - Unique account identifier
Expand All @@ -23,19 +24,17 @@ export const Account = ObjectSchema.create({
}),

// Select fields with custom options
type: {
type: 'select',
type: Field.select({
label: 'Account Type',
options: [
{ label: 'Prospect', value: 'prospect', color: '#FFA500', default: true },
{ label: 'Customer', value: 'customer', color: '#00AA00' },
{ label: 'Partner', value: 'partner', color: '#0000FF' },
{ label: 'Former Customer', value: 'former', color: '#999999' },
]
},
}),

industry: {
type: 'select',
industry: Field.select({
label: 'Industry',
options: [
{ label: 'Technology', value: 'technology' },
Expand All @@ -45,7 +44,7 @@ export const Account = ObjectSchema.create({
{ label: 'Manufacturing', value: 'manufacturing' },
{ label: 'Education', value: 'education' },
]
},
}),

// Number fields
annual_revenue: Field.currency({
Expand All @@ -69,12 +68,18 @@ export const Account = ObjectSchema.create({
label: 'Website',
}),

// Address fields
billing_street: Field.textarea({ label: 'Billing Street' }),
billing_city: Field.text({ label: 'Billing City' }),
billing_state: Field.text({ label: 'Billing State/Province' }),
billing_postal_code: Field.text({ label: 'Billing Postal Code' }),
billing_country: Field.text({ label: 'Billing Country' }),
// Structured Address field (new field type)
billing_address: Field.address({
label: 'Billing Address',
addressFormat: 'international',
}),

// Office Location (new field type)
office_location: Field.location({
label: 'Office Location',
displayMap: true,
allowGeocoding: true,
}),

// Relationship fields
owner: Field.lookup('user', {
Expand Down Expand Up @@ -104,18 +109,27 @@ export const Account = ObjectSchema.create({
readonly: true,
}),

// Formula field - combines first and last name
full_address: Field.formula({
label: 'Full Billing Address',
expression: 'CONCAT(billing_street, ", ", billing_city, ", ", billing_state, " ", billing_postal_code, ", ", billing_country)',
// Brand color (new field type)
brand_color: Field.color({
label: 'Brand Color',
colorFormat: 'hex',
presetColors: ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF'],
}),
},

// Database indexes for performance
indexes: [
{ fields: ['name'], unique: false },
{ fields: ['owner'], unique: false },
{ fields: ['type', 'is_active'], unique: false },
],

// Enable advanced features
enable: {
trackHistory: true, // Track field changes
searchable: true, // Include in global search
apiEnabled: true, // Expose via REST/GraphQL
apiMethods: ['get', 'list', 'create', 'update', 'delete', 'search', 'export'], // Whitelist allowed API operations
files: true, // Allow file attachments
feedEnabled: true, // Enable activity feed/chatter
trash: true, // Recycle bin support
Expand Down Expand Up @@ -176,12 +190,12 @@ export const Account = ObjectSchema.create({
{
label: 'Contact Details',
columns: 2,
fields: ['phone', 'website']
fields: ['phone', 'website', 'brand_color']
},
{
label: 'Billing Address',
label: 'Location & Address',
columns: 2,
fields: ['billing_street', 'billing_city', 'billing_state', 'billing_postal_code', 'billing_country', 'full_address']
fields: ['billing_address', 'office_location']
},
{
label: 'Additional Information',
Expand Down
32 changes: 23 additions & 9 deletions examples/crm/src/domains/crm/case.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ export const Case = ObjectSchema.create({
}),

// Case Management
status: {
type: 'select',
status: Field.select({
label: 'Status',
required: true,
options: [
Expand All @@ -51,10 +50,9 @@ export const Case = ObjectSchema.create({
{ label: 'Resolved', value: 'resolved', color: '#00AA00' },
{ label: 'Closed', value: 'closed', color: '#006400' },
]
},
}),

priority: {
type: 'select',
priority: Field.select({
label: 'Priority',
required: true,
options: [
Expand All @@ -63,7 +61,7 @@ export const Case = ObjectSchema.create({
{ label: 'High', value: 'high', color: '#FF4500' },
{ label: 'Critical', value: 'critical', color: '#FF0000' },
]
},
}),

type: Field.select(['Question', 'Problem', 'Feature Request', 'Bug'], {
label: 'Case Type',
Expand Down Expand Up @@ -133,14 +131,21 @@ export const Case = ObjectSchema.create({
}),

// Customer satisfaction
customer_rating: Field.select(['⭐ Very Dissatisfied', '⭐⭐ Dissatisfied', '⭐⭐⭐ Neutral', '⭐⭐⭐⭐ Satisfied', '⭐⭐⭐⭐⭐ Very Satisfied'], {
label: 'Customer Rating',
customer_rating: Field.rating(5, {
label: 'Customer Satisfaction',
description: 'Customer satisfaction rating (1-5 stars)',
}),

customer_feedback: Field.textarea({
label: 'Customer Feedback',
}),

// Customer signature (for case resolution acknowledgment)
customer_signature: Field.signature({
label: 'Customer Signature',
description: 'Digital signature acknowledging case resolution',
}),

// Internal notes
internal_notes: Field.markdown({
label: 'Internal Notes',
Expand All @@ -155,6 +160,15 @@ export const Case = ObjectSchema.create({
}),
},

// Database indexes for performance
indexes: [
{ fields: ['case_number'], unique: true },
{ fields: ['account'], unique: false },
{ fields: ['owner'], unique: false },
{ fields: ['status'], unique: false },
{ fields: ['priority'], unique: false },
],

enable: {
trackHistory: true,
searchable: true,
Expand Down Expand Up @@ -245,7 +259,7 @@ export const Case = ObjectSchema.create({
{
label: 'Resolution',
columns: 1,
fields: ['resolution', 'customer_rating', 'customer_feedback'],
fields: ['resolution', 'customer_rating', 'customer_feedback', 'customer_signature'],
},
{
label: 'SLA & Metrics',
Expand Down
64 changes: 36 additions & 28 deletions examples/crm/src/domains/crm/lead.object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ export const Lead = ObjectSchema.create({
}),

// Lead Qualification
status: {
type: 'select',
status: Field.select({
label: 'Lead Status',
required: true,
options: [
Expand All @@ -78,17 +77,13 @@ export const Lead = ObjectSchema.create({
{ label: 'Unqualified', value: 'unqualified', color: '#FF0000' },
{ label: 'Converted', value: 'converted', color: '#00AA00' },
]
},
}),

rating: {
type: 'select',
label: 'Rating',
options: [
{ label: 'Hot', value: 'hot', color: '#FF0000' },
{ label: 'Warm', value: 'warm', color: '#FFA500' },
{ label: 'Cold', value: 'cold', color: '#4169E1' },
]
},
rating: Field.rating(5, {
label: 'Lead Score',
description: 'Lead quality score (1-5 stars)',
allowHalf: true,
}),

lead_source: Field.select(['Web', 'Referral', 'Event', 'Partner', 'Advertisement', 'Cold Call'], {
label: 'Lead Source',
Expand Down Expand Up @@ -127,12 +122,11 @@ export const Lead = ObjectSchema.create({
readonly: true,
}),

// Address
street: Field.textarea({ label: 'Street' }),
city: Field.text({ label: 'City' }),
state: Field.text({ label: 'State/Province' }),
postal_code: Field.text({ label: 'Postal Code' }),
country: Field.text({ label: 'Country' }),
// Address (using new address field type)
address: Field.address({
label: 'Address',
addressFormat: 'international',
}),

// Additional Info
annual_revenue: Field.currency({
Expand All @@ -148,6 +142,12 @@ export const Lead = ObjectSchema.create({
label: 'Description',
}),

// Custom notes with rich text formatting
notes: Field.richtext({
label: 'Notes',
description: 'Rich text notes with formatting',
}),

// Flags
do_not_call: Field.boolean({
label: 'Do Not Call',
Expand All @@ -160,6 +160,14 @@ export const Lead = ObjectSchema.create({
}),
},

// Database indexes for performance
indexes: [
{ fields: ['email'], unique: true },
{ fields: ['owner'], unique: false },
{ fields: ['status'], unique: false },
{ fields: ['company'], unique: false },
],

enable: {
trackHistory: true,
searchable: true,
Expand Down Expand Up @@ -193,11 +201,11 @@ export const Lead = ObjectSchema.create({
sort: [{ field: 'created_date', order: 'desc' }],
},
hot_leads: {
label: 'Hot Leads',
label: 'High Score Leads',
type: 'grid',
columns: ['full_name', 'company', 'email', 'phone', 'status', 'owner'],
columns: ['full_name', 'company', 'email', 'phone', 'status', 'rating', 'owner'],
filter: [
['rating', '=', 'hot'],
['rating', '>=', 4],
['is_converted', '=', false],
],
},
Expand Down Expand Up @@ -235,13 +243,13 @@ export const Lead = ObjectSchema.create({
{
label: 'Address',
columns: 2,
fields: ['street', 'city', 'state', 'postal_code', 'country'],
fields: ['address'],
},
{
label: 'Additional Information',
columns: 2,
collapsible: true,
fields: ['do_not_call', 'email_opt_out', 'description'],
fields: ['do_not_call', 'email_opt_out', 'description', 'notes'],
},
{
label: 'Conversion Information',
Expand Down Expand Up @@ -273,10 +281,10 @@ export const Lead = ObjectSchema.create({

workflows: [
{
name: 'auto_qualify_hot_leads',
name: 'auto_qualify_high_score_leads',
objectName: 'lead',
triggerType: 'on_create_or_update',
criteria: 'rating = "hot" AND status = "new"',
criteria: 'rating >= 4 AND status = "new"',
active: true,
actions: [
{
Expand All @@ -288,16 +296,16 @@ export const Lead = ObjectSchema.create({
],
},
{
name: 'notify_owner_on_hot_lead',
name: 'notify_owner_on_high_score_lead',
objectName: 'lead',
triggerType: 'on_create_or_update',
criteria: 'ISCHANGED(rating) AND rating = "hot"',
criteria: 'ISCHANGED(rating) AND rating >= 4.5',
active: true,
actions: [
{
name: 'email_owner',
type: 'email_alert',
template: 'hot_lead_notification',
template: 'high_score_lead_notification',
recipients: ['{owner.email}'],
}
],
Expand Down
Loading
Loading