Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CRM Module

A complete customer management feature: domain model, validation, CRUD pages, and security – all in one script.

Domain Model

-- Enumerations first (referenced by entities)
CREATE ENUMERATION CRM.CustomerStatus (
  Active 'Active',
  Inactive 'Inactive',
  Suspended 'Suspended'
);

CREATE ENUMERATION CRM.ContactType (
  Email 'Email',
  Phone 'Phone',
  Visit 'Visit'
);

-- Entities with per-attribute documentation
/** Customer master data */
@Position(100, 100)
CREATE PERSISTENT ENTITY CRM.Customer (
  /** Auto-generated unique identifier */
  CustomerId: AutoNumber NOT NULL UNIQUE DEFAULT 1,
  /** Full legal name */
  Name: String(200) NOT NULL ERROR 'Customer name is required',
  /** Primary contact email */
  Email: String(200) UNIQUE ERROR 'Email already exists',
  /** Phone number in international format */
  Phone: String(50),
  /** Current account balance */
  Balance: Decimal DEFAULT 0,
  /** Whether the account is active */
  IsActive: Boolean DEFAULT TRUE,
  /** Current lifecycle status */
  Status: Enumeration(CRM.CustomerStatus) DEFAULT 'Active',
  /** Free-form notes about this customer */
  Notes: String(unlimited)
)
INDEX (Name)
INDEX (Email);
/

/** Record of a customer interaction */
@Position(400, 100)
CREATE PERSISTENT ENTITY CRM.ContactLog (
  /** Date and time of the interaction */
  ContactDate: DateTime NOT NULL,
  /** Type of interaction */
  Type: Enumeration(CRM.ContactType) DEFAULT 'Email',
  /** Summary of what was discussed */
  Summary: String(2000) NOT NULL ERROR 'Summary is required',
  /** Follow-up needed? */
  FollowUpRequired: Boolean DEFAULT FALSE
);
/

-- Associations
CREATE ASSOCIATION CRM.ContactLog_Customer
  FROM CRM.ContactLog TO CRM.Customer
  TYPE Reference OWNER Default;
/

Validation Microflow

The two-microflow pattern: a validation microflow returns field-level feedback, and an action microflow calls it before saving.

CREATE MICROFLOW CRM.VAL_Customer ($Customer: CRM.Customer)
RETURNS Boolean AS $IsValid
BEGIN
  DECLARE $IsValid Boolean = true;

  IF trim($Customer/Name) = '' THEN
    SET $IsValid = false;
    VALIDATION FEEDBACK $Customer/Name MESSAGE 'Name cannot be empty';
  END IF;

  IF $Customer/Email != empty AND NOT contains($Customer/Email, '@') THEN
    SET $IsValid = false;
    VALIDATION FEEDBACK $Customer/Email MESSAGE 'Enter a valid email address';
  END IF;

  IF $Customer/Balance < 0 THEN
    SET $IsValid = false;
    VALIDATION FEEDBACK $Customer/Balance MESSAGE 'Balance cannot be negative';
  END IF;

  RETURN $IsValid;
END;
/

CREATE MICROFLOW CRM.ACT_Customer_Save ($Customer: CRM.Customer)
RETURNS Boolean AS $IsValid
BEGIN
  $IsValid = CALL MICROFLOW CRM.VAL_Customer($param = $Customer);

  IF $IsValid THEN
    COMMIT $Customer;
    CLOSE PAGE;
  END IF;

  RETURN $IsValid;
END;
/

Pages

-- Overview page with data grid
CREATE PAGE CRM.Customer_Overview (
  Title: 'Customers',
  Layout: Atlas_Core.Atlas_Default
) {
  DATAGRID2 ON CRM.Customer (
    COLUMN Name { Caption: 'Name' }
    COLUMN Email { Caption: 'Email' }
    COLUMN Phone { Caption: 'Phone' }
    COLUMN Status { Caption: 'Status' }
    COLUMN IsActive { Caption: 'Active' }
    SEARCH ON Name, Email
    BUTTON 'New' CALL CRM.Customer_NewEdit
    BUTTON 'Edit' CALL CRM.Customer_NewEdit
    BUTTON 'Delete' CALL CONFIRM DELETE
  )
};
/

-- NewEdit page with validation
CREATE PAGE CRM.Customer_NewEdit (
  Params: { $Customer: CRM.Customer },
  Title: 'Customer',
  Layout: Atlas_Core.PopupLayout
) {
  LAYOUTGRID mainGrid {
    ROW row1 {
      COLUMN col1 (DesktopWidth: AutoFill) {
        DATAVIEW dataView1 (DataSource: $Customer) {
          TEXTBOX txtName (Label: 'Name', Attribute: Name)
          TEXTBOX txtEmail (Label: 'Email', Attribute: Email)
          TEXTBOX txtPhone (Label: 'Phone', Attribute: Phone)
          TEXTAREA txtNotes (Label: 'Notes', Attribute: Notes)
          FOOTER footer1 {
            ACTIONBUTTON btnSave (
              Caption: 'Save',
              Action: CALL CRM.ACT_Customer_Save,
              ButtonStyle: Success
            )
            ACTIONBUTTON btnCancel (Caption: 'Cancel', Action: CANCEL_CHANGES)
          }
        }
      }
    }
  }
};
/

Security

-- Module roles
CREATE MODULE ROLE CRM.User;
CREATE MODULE ROLE CRM.Admin DESCRIPTION 'Full customer management access';

-- Entity access
GRANT CRM.Admin ON CRM.Customer (CREATE, DELETE, READ *, WRITE *);
GRANT CRM.User ON CRM.Customer (CREATE, READ *, WRITE *)
  WHERE '[IsActive = true]';

GRANT CRM.Admin ON CRM.ContactLog (CREATE, DELETE, READ *, WRITE *);
GRANT CRM.User ON CRM.ContactLog (CREATE, READ *, WRITE *);

-- Document access
GRANT EXECUTE ON MICROFLOW CRM.ACT_Customer_Save TO CRM.User;
GRANT VIEW ON PAGE CRM.Customer_Overview TO CRM.User;
GRANT VIEW ON PAGE CRM.Customer_NewEdit TO CRM.User;

-- User roles
CREATE OR MODIFY USER ROLE CRMUser (System.User, CRM.User);
CREATE OR MODIFY USER ROLE CRMAdmin (System.User, CRM.Admin);

-- Demo users for testing
CREATE OR MODIFY DEMO USER 'crm_user' PASSWORD 'Password1!' (CRMUser);
CREATE OR MODIFY DEMO USER 'crm_admin' PASSWORD 'Password1!' (CRMAdmin);
ALTER PROJECT SECURITY DEMO USERS ON;