> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Page Layouts & PF-32 Conditional Field Logic Integration

> Version: 1.0.0 Status: 📝 Planned Last Updated: 2025-12-19 Constitution Reference: Section 1.3 (Integration Patterns)

**Version:** 1.0.0\
**Status:** 📝 Planned\
**Last Updated:** 2025-12-19\
**Constitution Reference:** Section 1.3 (Integration Patterns)

This document explains how PF-31 (Page Layouts) and PF-32 (Conditional Field Logic) work together, along with their relationship to PF-16 (Custom Field Definitions) and PF-17 (Entity Field Configuration).

***

## Overview

The Platform Foundation provides a layered approach to form and page configuration:

| Feature          | PF-16                | PF-17                    | PF-31                 | PF-32                    |
| ---------------- | -------------------- | ------------------------ | --------------------- | ------------------------ |
| **Purpose**      | Define custom fields | Configure field behavior | Define static layouts | Dynamic visibility logic |
| **Scope**        | Field metadata       | Field-level settings     | Page structure        | Conditional rules        |
| **When Applied** | Design time          | Configuration time       | Render time           | Runtime                  |

***

## Architecture Overview

```mermaid theme={null}
graph TB
    subgraph "Design Time"
        PF16[PF-16: Custom Field Definitions]
    end
    
    subgraph "Configuration Time"
        PF17[PF-17: Entity Field Configuration]
        PF31[PF-31: Page Layouts]
    end
    
    subgraph "Runtime"
        PF32[PF-32: Conditional Field Logic]
        UI[Form/Page UI]
    end
    
    PF16 --> PF17
    PF17 --> PF31
    PF17 --> PF32
    PF31 --> UI
    PF32 --> UI
    
    style PF16 fill:#e1f5fe
    style PF17 fill:#fff3e0
    style PF31 fill:#e8f5e9
    style PF32 fill:#fce4ec
    style UI fill:#f5f5f5
```

### Layer Responsibilities

1. **PF-16 (Custom Field Definitions)**: Defines *what fields exist* - field types, validation rules, default values
2. **PF-17 (Entity Field Configuration)**: Configures *how fields behave* - visibility, editability, simple conditional rules
3. **PF-31 (Page Layouts)**: Defines *static UI structure* - sections, ordering, column spans, role-based visibility
4. **PF-32 (Conditional Field Logic)**: Provides *dynamic runtime behavior* - compound conditions, cross-field validation, conditional required

***

## Feature Responsibility Matrix

| Concern                     | PF-17                        | PF-31                    | PF-32                |
| --------------------------- | ---------------------------- | ------------------------ | -------------------- |
| **Field visibility**        | ✅ Basic role-based           | ✅ Per-layout role-based  | ✅ Dynamic conditions |
| **Field ordering**          | ✅ `display_order`            | ✅ Section-based ordering | ❌ Not responsible    |
| **Sectioning**              | ✅ Basic `section` property   | ✅ Full section support   | ❌ Not responsible    |
| **Column spans**            | ❌                            | ✅ Full support           | ❌ Not responsible    |
| **Conditional show/hide**   | ✅ Simple (`showIf`/`hideIf`) | ❌                        | ✅ Compound (AND/OR)  |
| **Conditional required**    | ❌                            | ❌                        | ✅ Full support       |
| **Cross-field validation**  | ❌                            | ❌                        | ✅ Full support       |
| **Role-based layouts**      | ❌                            | ✅ `applicable_roles`     | ❌                    |
| **Multi-layout per object** | ❌                            | ✅ Named layouts          | ❌                    |

***

## Integration Patterns

### Pattern A: Static Layout + Simple Conditions

**Use when:** Basic forms with straightforward visibility logic

```mermaid theme={null}
sequenceDiagram
    participant User
    participant LayoutRenderer
    participant PF31 as PF-31 Layout
    participant PF17 as PF-17 Config
    
    User->>LayoutRenderer: Load form
    LayoutRenderer->>PF31: Fetch layout (sections, fields)
    PF31-->>LayoutRenderer: Layout structure
    LayoutRenderer->>PF17: Fetch field configs
    PF17-->>LayoutRenderer: Simple conditional rules
    LayoutRenderer->>User: Render form with conditions
```

**Example:**

```typescript theme={null}
import { LayoutRenderer } from '@/platform/page-layouts';

<LayoutRenderer
  objectName="hr_employees"
  viewContext="edit_form"
  data={employee}
  onSubmit={handleSubmit}
/>
```

### Pattern B: Static Layout + Advanced Conditions

**Use when:** Complex forms requiring AND/OR logic, conditional required fields

```mermaid theme={null}
sequenceDiagram
    participant User
    participant LayoutRenderer
    participant PF31 as PF-31 Layout
    participant PF32 as PF-32 Conditions
    
    User->>LayoutRenderer: Load form
    LayoutRenderer->>PF31: Fetch layout
    PF31-->>LayoutRenderer: Layout structure
    LayoutRenderer->>PF32: Fetch conditional rules
    PF32-->>LayoutRenderer: Advanced conditions
    
    User->>LayoutRenderer: Change field value
    LayoutRenderer->>PF32: Evaluate conditions
    PF32-->>LayoutRenderer: Updated visibility/required states
    LayoutRenderer->>User: Re-render affected fields
```

**Example:**

```typescript theme={null}
import { LayoutRenderer } from '@/platform/page-layouts';
import { useConditionalLogic } from '@/platform/conditional-logic';

function AdvancedForm({ employee }) {
  const { evaluateConditions, fieldStates } = useConditionalLogic({
    objectName: 'hr_employees',
    data: employee,
  });

  return (
    <LayoutRenderer
      objectName="hr_employees"
      viewContext="edit_form"
      data={employee}
      fieldStates={fieldStates}
      onFieldChange={(field, value) => {
        evaluateConditions({ ...employee, [field]: value });
      }}
    />
  );
}
```

### Pattern C: Full Integration (Recommended)

**Use when:** Maximum flexibility needed

```mermaid theme={null}
sequenceDiagram
    participant User
    participant Form as ConfigurableForm
    participant PF31 as PF-31 Layout
    participant PF17 as PF-17 Config
    participant PF32 as PF-32 Conditions
    
    User->>Form: Load form
    Form->>PF31: pf_get_effective_layout()
    PF31-->>Form: Layout with sections/fields
    Form->>PF17: Fetch field configs
    PF17-->>Form: Base field settings
    Form->>PF32: Fetch conditional rules
    PF32-->>Form: Advanced conditions
    
    Note over Form: Merge all configurations
    Form->>User: Render integrated form
    
    User->>Form: Update field
    Form->>PF32: Evaluate all conditions
    PF32-->>Form: New field states
    Form->>User: Update UI
```

***

## Precedence Rules

When multiple systems configure the same field, the following precedence applies:

### Visibility Precedence (Highest to Lowest)

1. **PF-32 Dynamic Condition** → If a V2 rule evaluates to "hide", field is hidden
2. **PF-31 Role-Based Visibility** → If layout excludes field for role, field is hidden
3. **PF-17 Simple Condition** → `showIf`/`hideIf` evaluated
4. **PF-17 Base Visibility** → `is_visible` setting

### Required Precedence (Highest to Lowest)

1. **PF-32 Conditional Required** → Dynamic required based on conditions
2. **PF-17 Base Required** → Static `is_required` setting
3. **PF-16 Field Definition** → Default required from field definition

### Example Scenario

```typescript theme={null}
// Field: emergency_contact_phone
// PF-17: is_visible = true, is_required = false
// PF-31: included in layout for role 'staff'
// PF-32: required_if: { emergency_contact_name: { isNotEmpty: true } }

// Result when emergency_contact_name is filled:
// - Visible: true (PF-31 allows, PF-17 allows)
// - Required: true (PF-32 condition met)

// Result when emergency_contact_name is empty:
// - Visible: true (same as above)
// - Required: false (PF-32 condition not met, falls back to PF-17)
```

***

## Data Flow Diagram

```mermaid theme={null}
flowchart TD
    subgraph Load["Page Load"]
        A[Start] --> B{Layout exists?}
        B -->|Yes| C[Fetch PF-31 Layout]
        B -->|No| D[Use PF-17 ordering]
        C --> E[Fetch PF-17 Configs]
        D --> E
        E --> F[Fetch PF-32 Rules]
        F --> G[Merge configurations]
        G --> H[Render form]
    end
    
    subgraph Runtime["User Interaction"]
        H --> I[User changes field]
        I --> J[PF-32 evaluates conditions]
        J --> K{State changed?}
        K -->|Yes| L[Update field states]
        K -->|No| M[No update needed]
        L --> H
        M --> I
    end
    
    style Load fill:#e3f2fd
    style Runtime fill:#fff8e1
```

***

## Database Relationship Diagram

```mermaid theme={null}
erDiagram
    pf_custom_field_definitions ||--o{ pf_entity_field_configs : "defines fields"
    pf_entity_field_configs ||--o{ pf_page_layout_fields : "configures"
    pf_page_layouts ||--o{ pf_page_layout_sections : "contains"
    pf_page_layout_sections ||--o{ pf_page_layout_fields : "contains"
    pf_entity_field_configs {
        uuid id PK
        uuid organization_id FK
        text entity_type
        text field_name
        boolean is_visible
        boolean is_required
        boolean is_editable
        jsonb conditional_rules "V1 simple rules"
        integer display_order
    }
    pf_page_layouts {
        uuid id PK
        uuid organization_id FK
        text object_name
        text layout_name
        text view_context
        text[] applicable_roles
        boolean is_default
        boolean is_active
    }
    pf_page_layout_sections {
        uuid id PK
        uuid layout_id FK
        text section_name
        integer display_order
        integer columns
        boolean is_collapsible
    }
    pf_page_layout_fields {
        uuid id PK
        uuid section_id FK
        text field_name
        integer display_order
        integer column_span
        text[] visible_to_roles
        text[] editable_by_roles
    }
    pf_custom_field_definitions {
        uuid id PK
        uuid organization_id FK
        text entity_type
        text field_key
        text field_type
        jsonb field_options
    }
```

***

## Code Examples

### Using Platform Imports

```typescript theme={null}
// ✅ CORRECT: Import from platform layers
import { LayoutRenderer, usePageLayout } from '@/platform/page-layouts';
import { useConditionalLogic } from '@/platform/conditional-logic';
import { ConfigurableForm } from '@/platform/field-config';

// ❌ WRONG: Direct imports from cores
import { LayoutRenderer } from '@/cores/pf/layouts';
```

### Integrated Form Component

```typescript theme={null}
import { usePageLayout } from '@/platform/page-layouts';
import { useConditionalLogic } from '@/platform/conditional-logic';
import { useEntityFieldConfigs } from '@/platform/field-config';

export function IntegratedForm({ 
  objectName, 
  viewContext, 
  data, 
  onSubmit 
}: IntegratedFormProps) {
  const { user } = useCurrentUser();
  
  // PF-31: Get layout structure
  const { layout, sections, fields } = usePageLayout({
    objectName,
    viewContext,
    userRole: user?.role,
  });
  
  // PF-17: Get field configurations
  const { configs } = useEntityFieldConfigs({
    entityType: objectName,
    organizationId: user?.organizationId,
  });
  
  // PF-32: Get conditional logic
  const { fieldStates, evaluateConditions } = useConditionalLogic({
    objectName,
    data,
    configs,
  });
  
  // Merge all configurations
  const mergedFields = useMemo(() => {
    return mergeFieldConfigurations(fields, configs, fieldStates);
  }, [fields, configs, fieldStates]);
  
  return (
    <Form onSubmit={onSubmit}>
      {sections.map(section => (
        <FormSection 
          key={section.id} 
          section={section}
          fields={mergedFields.filter(f => f.sectionId === section.id)}
          data={data}
          onChange={(field, value) => {
            evaluateConditions({ ...data, [field]: value });
          }}
        />
      ))}
    </Form>
  );
}
```

### Conditional Required Field

```typescript theme={null}
// PF-32 rule definition (stored in database)
const conditionalRule = {
  field_name: 'emergency_phone',
  rule_type: 'required_if',
  conditions: {
    operator: 'AND',
    conditions: [
      { field: 'has_emergency_contact', operator: 'equals', value: true },
      { field: 'emergency_name', operator: 'isNotEmpty' }
    ]
  }
};

// Runtime evaluation
const isRequired = useConditionalRequired({
  fieldName: 'emergency_phone',
  formData: currentFormData,
  rules: conditionalRules,
});

<FormField
  name="emergency_phone"
  required={isRequired}
  label={isRequired ? 'Emergency Phone *' : 'Emergency Phone'}
/>
```

***

## Implementation Timeline

| Phase         | Feature                        | Status     | Target      |
| ------------- | ------------------------------ | ---------- | ----------- |
| PF-31 Phase 1 | Database schema                | ✅ Complete | 2025-12-19  |
| PF-31 Phase 2 | TypeScript types & hooks       | 📝 Planned | Week 2      |
| PF-31 Phase 3 | Layout Editor UI               | 📝 Planned | Week 3      |
| PF-31 Phase 4 | LayoutRenderer component       | 📝 Planned | Week 4      |
| PF-31 Phase 5 | Platform integration layer     | 📝 Planned | Week 5      |
| PF-31 Phase 6 | Core module adoption           | 📝 Planned | Week 6-7    |
| PF-32 Phase 1 | Conditional rules schema       | 📝 Planned | After PF-31 |
| PF-32 Phase 2 | Condition Builder UI           | 📝 Planned | After PF-31 |
| PF-32 Phase 3 | Runtime evaluator              | 📝 Planned | After PF-31 |
| Integration   | Full PF-31 + PF-32 integration | 📝 Planned | After both  |

***

## Testing Strategy

### Unit Tests

```typescript theme={null}
describe('LayoutRenderer with Conditional Logic', () => {
  it('should hide field when PF-32 condition evaluates to hide', () => {
    const { queryByTestId } = render(
      <LayoutRenderer
        objectName="hr_employees"
        data={{ employment_type: 'contractor' }}
        fieldStates={{ benefits_enrollment: { visible: false } }}
      />
    );
    expect(queryByTestId('field-benefits_enrollment')).not.toBeInTheDocument();
  });
  
  it('should mark field required when PF-32 condition met', () => {
    const { getByTestId } = render(
      <LayoutRenderer
        objectName="hr_employees"
        data={{ has_emergency_contact: true }}
        fieldStates={{ emergency_phone: { required: true } }}
      />
    );
    expect(getByTestId('field-emergency_phone')).toHaveAttribute('required');
  });
});
```

### Integration Tests

```typescript theme={null}
describe('PF-31 + PF-32 Integration', () => {
  it('should load layout and apply conditional rules', async () => {
    // Setup: Create layout and conditional rules in test database
    await createTestLayout('hr_employees', 'edit_form');
    await createConditionalRule('hr_employees', 'emergency_phone', 'required_if');
    
    // Act: Render form with data that triggers condition
    const { getByTestId } = render(
      <IntegratedForm 
        objectName="hr_employees" 
        viewContext="edit_form"
        data={{ has_emergency_contact: true, emergency_name: 'John' }}
      />
    );
    
    // Assert: Field should be required
    await waitFor(() => {
      expect(getByTestId('field-emergency_phone')).toHaveAttribute('required');
    });
  });
});
```

### RLS Tests

```typescript theme={null}
describe('Layout RLS', () => {
  it('should only return layouts for user organization', async () => {
    const { data } = await supabase
      .from('pf_page_layouts')
      .select('*');
    
    data.forEach(layout => {
      expect(layout.organization_id).toBe(testOrganizationId);
    });
  });
});
```

***

## Related Documentation

* **Specs:**
  * [PF-31 Page Layouts Spec](../../../specs/pf/specs/PF-31-page-layouts.md)
  * [PF-32 Conditional Field Logic Spec](../../../specs/pf/specs/PF-32-conditional-field-logic.md)
  * [PF-17 Entity Field Configuration Spec](../../../specs/pf/specs/PF-17-entity-field-configuration.md)
  * [PF-16 Custom Field Definitions Spec](../../../specs/pf/specs/PF-16-custom-field-definitions.md)

* **Implementation:**
  * [Platform Field Config](../../../src/platform/field-config/README.md)
  * [Platform Custom Fields](../../../src/platform/custom-fields/README.md)

* **Architecture:**
  * [Platform Integration Layers](./PLATFORM_INTEGRATION_LAYERS.md)
  * [Constitution Section 1.3](../../../constitution.md)

***

**Next Review:** After PF-31 Phase 2 completion
