1. Define the data model

In this chapter you create the three models that the rest of the tutorial builds on.

ModelPurpose
LeadInbound prospect, not yet qualified
AccountQualified customer organisation
OpportunityA specific deal attached to an Account, with stage and amount

Estimated time: 20 minutes.

1.1 Create the Lead model

Open Studio → Models → New model. Fill in:

  • Code: crm_lead
  • Display name: Lead
  • Tenant: your tenant
  • Storage: standard (auto-creates the mt_crm_lead table)

Add the following fields:

CodeTypeRequiredNotes
namestring(80)Contact name
emailstring(120)Unique index
phonestring(32)
sourceenumvalues: web / referral / event / cold
scoreinteger0–100
statusenumvalues: new / qualified / disqualified (default new)
notestext

All Field Types — sample of every field renderer

Save and publish. The platform will create the dynamic table automatically (see Models & Fields).

1.2 Create the Account model

# DSL snippet — for reference, you can edit this in Studio.
model:
  code: crm_account
  fields:
    - { code: name,    type: string(120), required: true, unique: true }
    - { code: domain,  type: string(80) }
    - { code: tier,    type: enum, values: [strategic, growth, smb] }
    - { code: owner,   type: ref, target: sys_user }

1.3 Create the Opportunity model

Opportunity references Account and has stage + amount.

model:
  code: crm_opportunity
  fields:
    - { code: title,    type: string(160), required: true }
    - { code: account,  type: ref, target: crm_account, required: true, onDelete: restrict }
    - { code: stage,    type: enum, values: [prospect, qualified, proposal, won, lost], default: prospect }
    - { code: amount,   type: decimal(14,2) }
    - { code: close_at, type: date }
    - { code: owner,    type: ref, target: sys_user }

1.4 Validation rules

Add these constraints in Studio → Models → Validation:

  • Lead.email — unique within tenant
  • Opportunity.amount — non-negative
  • Opportunity.close_at — must be in the future when stage != won|lost

1.5 Verify

Open Data → Tables and confirm:

  • mt_crm_lead, mt_crm_account, mt_crm_opportunity exist
  • Each row has id (snowflake) and pid (ULID) populated automatically
  • The reference column crm_opportunity.account_id has a foreign key to mt_crm_account.id

Model Management — Lead/Account/Opportunity

If any of these are missing, re-publish the model and re-check; the platform calls SchemaManagementServiceImpl.createTableByModel on publish.

Next

Chapter 2 → Design the pages