ADR-017 — PlanDetails Field Visibility Map & Guard Pattern

Prev Next

Context

All plan types, except FREE have planDetails that share many fields but differ in economic model and feature requirements.

Rendering conditional fields inline (e.g., if (type === SVOD)) inside sections risks:

  • Scattered branching logic
  • Reduced readability
  • Increased maintenance burden
  • Hard-to-track plan-type conditionals

A centralized visibility strategy was required without introducing a dynamic schema engine.

Decision

We introduced a PlanDetails field visibility configuration map:

export const PlanDetailsFieldMap = {
  fieldName: [AllowedPlanTypes],
};

This map:

  • Defines which fields are visible for which plan types
  • Contains no rendering metadata
  • Contains no validation logic
  • Controls visibility only

A pure helper:

shouldShowField(fieldId, planType);

And a small UI guard component:

<PlanFieldGuard fieldId="..." planType={type}>
  {children}
</PlanFieldGuard>

were introduced to centralize field branching.

Sections now declare fields declaratively, and visibility is controlled by the guard.

Consequences

Positive

  • Eliminates inline plan-type conditionals
  • Centralizes visibility logic
  • Improves JSX readability
  • Prevents conditional sprawl
  • Adding new fields requires updating only:
    1. The section
    2. The field map

Negative

  • Small additional abstraction layer
  • Requires discipline to ensure all type-sensitive fields use the guard

Notes

  • This approach intentionally avoids building a dynamic form schema system.
  • Monetisation is considered stable, and this solution balances clarity and maintainability without over-engineering.
  • The field visibility map must remain strictly limited to:
    • field → allowed plan types
    • No additional responsibilities should be added.