bcquality/custom/knowledge/architecture/pages-must-not-contain-business-logic.md
Michael Dieringer 11eab57723 Edison sharpening runde 1: to regler faar skarpe kanter (Type A)
Foerste eval-runde nogensinde (korpus: Jernpladsen @ b7656b1, 36 pages,
77 testprocedurer) fandt to regler med uskarpe graenser:

- pages-must-not-contain-business-logic: undtagelse 3 tilfoejet -
  singleton-init-idiomet paa Cue/Activities-pages (if not Get then
  Init+Insert i OnOpenPage) er praesentations-bootstrap, ikke
  forretningslogik. Basisappen bruger samme moenster paa alle cue-pages.
  Evidens: reglen flagede ScrapDealerActivities; adjudikeret FP.
  Precision som skrevet: 0,67 (2 TP / 1 FP) - de to TP'er staar ved magt.

- test-one-when-per-test: flow-test-graensen defineret. Multi-WHEN er
  tilladt naar navnet deklarerer flowet, hver WHEN er en runde af EET
  scenarie, og THEN asserter den akkumulerede sluttilstand. Unit-tests
  beholder streng een-WHEN. Evidens: 5 bevidst runde-maerkede
  procedurer i SVPartialFlowTests, som reglen ikke kunne doemme.

Scorecards i PR-beskrivelsen. Rute: Edison -> Francis (Type A) ->
Immanuel -> Michael, jf. edison.agent.md Step 6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 08:04:22 +02:00

2.7 KiB

bc-version domain keywords technologies countries application-area
all
architecture
pages
business-logic
codeunit
separation-of-concerns
al
w1
all

CURABIS Architecture: Page Presentation vs. Business Logic

Description

In CURABIS codebases, pages serve exclusively as presentation layers. All business logic—including calculations, validations, and record modifications—must reside in codeunits, not in page triggers or actions. This standard is more rigorous than general Business Central guidance and applies uniformly across all CURABIS PTE applications.

Key Principle

"A page procedure that calculates a value and assigns it to a field, calls Rec.Modify() directly, or implements business rules is an architecture violation even if it compiles."

Permitted Exceptions

Three specific scenarios allow deviation from this rule:

  1. Setup Pages: May directly read and write their own setup records
  2. Conversion Pages: The designated "Run Conversion" page may invoke the conversion codeunit directly
  3. Cue/Activities Pages: The standard singleton-initialization idiom in OnOpenPage — if not Rec.Get() then begin Rec.Init(); Rec.Insert(); end — is permitted. It bootstraps the page's own presentation-state record and is the same pattern Microsoft uses on every base-app cue page; it is not business logic. (Edison eval 2026-07-02, Jernpladsen @ b7656b1: the rule flagged this idiom on an Activities page; adjudicated false positive.)

Anti-Pattern Examples

Pages should not contain:

  • Direct calculations (e.g., Rec."Total Amount" := Rec.Quantity * Rec."Unit Price")
  • Calls to Rec.Modify() within page triggers
  • Business rule validation logic embedded in page triggers

Best Practice Implementation

Pages should delegate to codeunits for all business operations:

  • "The page owns the presentation" while "The codeunit owns the logic"
  • Use codeunit procedures (e.g., SVManagement.RecalculateLine(Rec)) for calculations and modifications
  • Route all validations through codeunits rather than page triggers

This separation ensures maintainability, testability, and consistency across CURABIS applications.

BCApps Reference

Microsoft's own BCApps repository confirms this pattern. In the Performance Toolkit, BCPTSetupCard.Page.al and BCPTSetupList.Page.al contain no business logic — all operations are delegated to BCPTStartTests.Codeunit.al and BCPTHeader.Codeunit.al. This is consistent across all BCApps pages.