Add CMFRT naming conventions, object ID ranges, and patterns documentation

- Introduced guidelines for using the "CMFRT" prefix in object names, fields, and procedures to avoid naming collisions and ensure clarity.
- Established rules for object ID ranges to prevent conflicts with other extensions and maintain historical integrity.
- Documented best practices and anti-patterns for various coding patterns, including case statements, interface injection, label usage, and validation methods.
- Implemented a standards review skill to evaluate AL source changes against CMFRT company standards, ensuring compliance with naming, permissions, and architectural patterns.
This commit is contained in:
BeytullahCengiz88 2026-07-14 14:09:04 +02:00
parent d6ac005173
commit afb1fa2883
53 changed files with 1288 additions and 0 deletions

View file

@ -0,0 +1,33 @@
table 55008 "CMFRT AQ Setup"
{
fields
{
field(55011; "CMFRT AQ FS Jnl. Template Name"; Code[10])
{
Caption = 'FS Journal Template Name'; // missing CMFRT AQ prefix
DataClassification = CustomerContent;
}
}
}
page 55020 "CMFRT AQ Setup"
{
layout
{
area(Content)
{
field("CMFRT AQ FS Jnl. Template Name"; Rec."CMFRT AQ FS Jnl. Template Name")
{
ApplicationArea = All;
// Page-level overrides duplicate the table definition and drift apart.
Caption = 'FS Journal Template Name';
ToolTip = 'Specifies the Job Journal Template used for material lines created by the Field Service API.';
}
}
}
}
enum 55040 "CMFRT AQ Buffer Status"
{
value(55000; "CMFRT AQ Pending") { Caption = 'Pending'; } // missing prefix
}

View file

@ -0,0 +1,32 @@
table 55008 "CMFRT AQ Setup"
{
fields
{
field(55011; "CMFRT AQ FS Jnl. Template Name"; Code[10])
{
Caption = 'CMFRT AQ FS Journal Template Name';
ToolTip = 'Specifies the Job Journal Template used for material lines created by the Field Service API.';
DataClassification = CustomerContent;
}
}
}
page 55020 "CMFRT AQ Setup"
{
layout
{
area(Content)
{
field("CMFRT AQ FS Jnl. Template Name"; Rec."CMFRT AQ FS Jnl. Template Name")
{
ApplicationArea = All; // Caption and ToolTip inherited from the table field
}
}
}
}
enum 55040 "CMFRT AQ Buffer Status"
{
value(55000; "CMFRT AQ Pending") { Caption = 'CMFRT AQ Pending'; }
value(55001; "CMFRT AQ Processed") { Caption = 'CMFRT AQ Processed'; }
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: naming
keywords: [caption, prefix, enum-value, field-caption, tooltip, table-level, page-override, translation]
technologies: [al]
countries: [w1]
application-area: [all]
---
# CMFRT caption prefix and table-level captions
## Description
Captions in a CMFRT extension follow the same prefix rule as names: every field caption and every enum value caption carries the `CMFRT <ABBR>` prefix — for example `Caption = 'CMFRT AQ FS Journal Template Name'` on a field and `Caption = 'CMFRT AQ Pending'` on an enum value. Captions and tooltips are defined once, on the table field (or enum value), never overridden on pages. Pages inherit the table-level `Caption` and `ToolTip`, so the text is maintained in one place and every page showing the field stays consistent.
## Best Practice
Set `Caption` with the full `CMFRT <ABBR>` prefix and `ToolTip` on the table field definition. On pages, declare only `ApplicationArea` for the field — no `Caption`, no `ToolTip`. Give every enum value a prefixed caption matching its prefixed value name.
See sample: `cmfrt-caption-prefix.good.al`.
## Anti Pattern
An unprefixed caption (`Caption = 'Pending'`, `Caption = 'FS Journal Template Name'`), or a page field that repeats or overrides the table-level `Caption`/`ToolTip`. Unprefixed captions are indistinguishable from base-application text for users and translators, and duplicated page-level text drifts from the table definition the first time either copy is edited.
See sample: `cmfrt-caption-prefix.bad.al`.

View file

@ -0,0 +1,29 @@
// Object names without the CMFRT prefix collide with other extensions.
pageextension 2045661 "Job Card Extension" extends "Job Card"
{
}
// Unprefixed fields are indistinguishable from base application fields.
tableextension 2045660 "Job Extension" extends Job
{
fields
{
field(2045081; "POI ID"; Guid)
{
DataClassification = CustomerContent;
Caption = 'POI ID';
}
}
}
// Unprefixed procedures have no ownership signal for reviewers.
codeunit 2045700 "Job Management"
{
procedure LinkJobToPOI(JobNo: Code[20]; POIId: Guid)
begin
end;
local procedure ValidatePOIExists(POIId: Guid): Boolean
begin
end;
}

View file

@ -0,0 +1,29 @@
// Objects use "CMFRT <ABBR> <Name>" with spaces.
pageextension 2045661 "CMFRT GD Job" extends "Job Card"
{
}
// Fields use "CMFRT <ABBR> <FieldName>" with spaces.
tableextension 2045660 "CMFRT GD Job Ext" extends Job
{
fields
{
field(2045081; "CMFRT GD POI ID"; Guid)
{
DataClassification = CustomerContent;
Caption = 'POI ID';
}
}
}
// Procedures use CMFRT<ABBR><ProcedureName> concatenated, no spaces.
codeunit 2045700 "CMFRT GD Job Mgmt"
{
procedure CMFRTGDLinkJobToPOI(JobNo: Code[20]; POIId: Guid)
begin
end;
local procedure CMFRTGDValidatePOIExists(POIId: Guid): Boolean
begin
end;
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: naming
keywords: [naming, prefix, cmfrt, object-name, procedure-name, field-name, abbreviation]
technologies: [al]
countries: [w1]
application-area: [all]
---
# CMFRT naming prefix
## Description
Every object, field, and procedure in a CMFRT extension must carry the `CMFRT XXX` prefix, where `XXX` is the product or customer abbreviation (for example `GD` for Geodynamics, `BA` for Batch Automation, `JO` for Jobs). The prefix applies to tables, table extensions, pages, page extensions, codeunits, interfaces, reports, enum values, and to all global and local procedures. Object and field names use the three-part form `CMFRT <ABBR> <Descriptive Name>` with spaces. Procedure names use the concatenated form `CMFRT<ABBR><ProcedureName>` with no spaces.
## Best Practice
Name every object `"CMFRT <ABBR> <Name>"` — for example `"CMFRT GD Job"` or `"CMFRT GD POI"`. Name every field `"CMFRT <ABBR> <FieldName>"` — for example `"CMFRT GD POI ID"`. Name every procedure `CMFRT<ABBR><ProcedureName>` — for example `CMFRTGDCalculatePOIDistance`. The procedure name must be self-describing: a reader must understand what the procedure does without reading its body. Local procedures follow the same rule.
See sample: `cmfrt-naming-prefix.good.al`.
## Anti Pattern
Naming objects, fields, or procedures without the CMFRT prefix — for example `procedure CalculateDiscount()` or `field(50000; "Amount"; Decimal)`. Unprefixed members collide with base application fields, break the reviewer's ability to identify extension-owned members, and violate the astena naming convention enforced across all CMFRT extensions.
See sample: `cmfrt-naming-prefix.bad.al`.

View file

@ -0,0 +1,25 @@
// ID 50000 is outside both defined CMFRT ranges and will conflict with
// other extensions that follow the standard AppSource free range.
table 50000 "CMFRT GD POI"
{
Caption = 'POI';
DataClassification = CustomerContent;
fields
{
field(1; "Code"; Code[20]) { DataClassification = CustomerContent; }
}
}
// ID 2045081 was previously assigned to a removed object.
// Reusing it causes silent conflicts with historical telemetry and upgrade codeunits.
table 2045081 "CMFRT GD New Feature"
{
Caption = 'New Feature';
DataClassification = CustomerContent;
fields
{
field(1; "Code"; Code[20]) { DataClassification = CustomerContent; }
}
}

View file

@ -0,0 +1,24 @@
// Product extension IDs are within the product range 2045081..2046580.
table 2045081 "CMFRT GD POI"
{
Caption = 'POI';
DataClassification = CustomerContent;
fields
{
field(2045081; "Code"; Code[20]) { DataClassification = CustomerContent; }
field(2045082; "Description"; Text[100]) { DataClassification = CustomerContent; }
}
}
// Customer extension IDs are within the customer range 55000..55999.
table 55000 "CMFRT JO Customer Site"
{
Caption = 'Customer Site';
DataClassification = CustomerContent;
fields
{
field(55000; "Code"; Code[20]) { DataClassification = CustomerContent; }
}
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: naming
keywords: [object-id, id-range, numbering, product-extension, customer-extension, range, field-id, enum-value-id]
technologies: [al]
countries: [w1]
application-area: [all]
---
# CMFRT object ID ranges
## Description
CMFRT object IDs are partitioned into two non-overlapping numeric ranges by deployment scope. Product extensions — features delivered to all customers under the CMFRT product — use IDs from `2045081` to `2046580`. Customer-specific extensions — functionality tailored to a single customer deployment — use IDs from `55000` to `55999`. The range applies to member IDs as well as object IDs: table fields and enum values declared by the extension take IDs from the same licensed range (for example `field(55011; ...)`, `value(55000; ...)`), even on tables the extension owns. Always pick the next free ID in the correct range. A removed object's ID must never be recycled; the platform retains historical references to deleted object IDs and recycling causes silent conflicts with upgrade and telemetry systems.
## Best Practice
Before adding any AL object, identify whether the feature is product-wide or customer-specific, look up the highest currently allocated ID in the correct range across the extension's source, and assign the next sequential ID. Record ID allocations in the pull request description so reviewers can confirm the range and sequence without scanning all object files.
See sample: `cmfrt-object-id-ranges.good.al`.
## Anti Pattern
Assigning an ID outside both ranges, choosing a round-number ID that has no relation to the next free slot, reusing an ID from a previously removed object, or numbering table fields or enum values outside the licensed range (for example `field(10; ...)` on a customer-range table). ID conflicts between extensions produce runtime application errors that are difficult to reproduce and trace, because the conflict may only manifest when both extensions are installed in the same environment.
See sample: `cmfrt-object-id-ranges.bad.al`.