## Service Options

Service Options are a core feature of the Xtrem framework that allow you to control which features are available in your application. They provide a flexible way to enable or disable functionality based on business requirements, licensing, or deployment configurations.

### Service Option Declaration

Service options are declared as singleton instances in dedicated files:

```typescript
// Basic Service Option
import { ServiceOption } from '@sage/xtrem-core';

export const showCaseDiscountOption = new ServiceOption({
    __filename,
    status: 'experimental',
    description: 'showCase discount option',
    isSubscribable: false,
    isHidden: false,
});
```

### Service Option Properties

#### Status Levels

Service options can have different status levels that control their availability:

```typescript
// Released - Normal production feature
export const showCaseOption1 = new ServiceOption({
    __filename,
    status: 'released',
    description: "showCaseOption1's description",
    isHidden: true,
    isSubscribable: false,
});

// Experimental - New feature with special UI indicator
export const showCaseExperimentalOption = new ServiceOption({
    __filename,
    status: 'experimental',
    description: 'experimental option',
    isSubscribable: false,
    isHidden: false,
});

// Work In Progress - Development only, cannot be activated by customers
export const showCaseWorkInProgressOption = new ServiceOption({
    __filename,
    status: 'workInProgress',
    description: 'Work in progress options cannot be activated',
    isHidden: false,
    isSubscribable: false,
});
```

#### Configuration Properties

```typescript
export const customer360ViewOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Customer 360 view option',
    isSubscribable: false, // Whether users can subscribe/unsubscribe
    isHidden: false, // Whether visible in admin UI
    isActiveByDefault: true, // Default activation state
});

// Service option with external code reference
export const openItemPageOption = new ServiceOption({
    __filename,
    code: 'isOpenItemPageActive', // External system reference
    status: 'released',
    description: 'Open item page display',
    isSubscribable: false,
    isHidden: true,
});
```

#### High-Level Service Options

Service options can activate other service options automatically:

```typescript
import { showCaseOption1, showCaseOption2 } from './_index';

export const showCaseOptionHighLevel = new ServiceOption({
    __filename,
    status: 'released',
    description: "showCaseOption's high level description",
    isHidden: false,
    isSubscribable: true,
    activates: () => [showCaseOption1, showCaseOption2], // Auto-activates dependencies
});
```

#### Service Option Dependencies

Service options can have complex dependency relationships where certain options cannot be activated without their dependencies being active, and dependencies cannot be deactivated while dependent options remain active.

**Understanding Current Dependency Mechanisms**

The Xtrem framework currently supports basic dependency relationships through the `activates` property, but more complex validation scenarios require custom implementation in the business logic layer.

**Example: Basic Activation Dependencies**

```typescript
// Base service option (dependency)
export const advancedReportingOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Advanced Reporting Core Engine',
    isSubscribable: true,
    isHidden: false,
    isActiveByDefault: false,
});

// Dependent service option that auto-activates its dependency
export const advancedAnalyticsOption = new ServiceOption({
    __filename,
    status: 'experimental',
    description: 'Advanced Analytics Dashboard',
    isSubscribable: true,
    isHidden: false,
    isActiveByDefault: false,
    // This will auto-activate the base option when this option is activated
    activates: () => [advancedReportingOption],
});
```

**Design Decision: Auto-Activation vs Validation Error**

When implementing service option dependencies, developers must first decide the behavior when serviceOptionChild is activated while serviceOptionParent is inactive:

**Option A: Auto-Activation (Recommended for User-Friendly Experience)**

```typescript
// serviceOptionChild automatically activates serviceOptionParent when enabled
export const dependentServiceOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Feature that auto-activates its dependency',
    isSubscribable: true,
    isHidden: false,
    activates: () => [baseServiceOption], // Auto-activates serviceOptionParent
});
```

**Option B: Validation Error (Recommended for Strict Control)**

```typescript
// serviceOptionChild throws error if serviceOptionParent is not already active
export const dependentServiceOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Feature that requires manual dependency activation',
    isSubscribable: true,
    isHidden: false,
    async onEnabled(context: Context) {
        const isBaseActive = await context.isServiceOptionEnabled(baseServiceOption);
        if (!isBaseActive) {
            // Disable this option and throw an error
            await context.application.serviceOptionManager.setServiceOptionActiveState(context, this, false);
            context.setServiceOptionsEnabledFlag(this, false);
            throw new Error('Base Service Option must be enabled first');
        }
    },
});
```

**Decision Criteria:**

- **Use Auto-Activation (Option A) when:**
    - The dependency is always beneficial and has no side effects
    - Users expect seamless feature enablement
    - The dependent feature cannot function without the base feature
    - Example: Analytics dashboard auto-enabling reporting engine

- **Use Validation Error (Option B) when:**
    - The dependency has significant cost, security, or performance implications
    - Explicit user consent is required for the base feature
    - Clear separation of concerns is needed for compliance
    - Example: Advanced security features requiring explicit audit trail activation

**Implementing Custom Dependency Validation**

For scenarios where serviceOptionChild cannot be activated if serviceOptionParent is not active, and serviceOptionParent cannot be disabled if serviceOptionChild is active, you need to implement validation in your business logic:

```typescript
// In your service or manager class that handles service option changes
export class ServiceOptionDependencyManager {
    async validateServiceOptionActivation(context: Context, serviceOption: ServiceOption): Promise<void> {
        // Example: Advanced Analytics requires Advanced Reporting
        if (serviceOption.name === 'advancedAnalyticsOption') {
            const isReportingActive = await context.isServiceOptionEnabled(advancedReportingOption);
            if (!isReportingActive) {
                throw new Error('Advanced Reporting must be enabled before activating Advanced Analytics');
            }
        }

        // Add other dependency validations here
    }

    async validateServiceOptionDeactivation(context: Context, serviceOption: ServiceOption): Promise<void> {
        // Example: Cannot disable Advanced Reporting if Advanced Analytics is active
        if (serviceOption.name === 'advancedReportingOption') {
            const isAnalyticsActive = await context.isServiceOptionEnabled(advancedAnalyticsOption);
            if (isAnalyticsActive) {
                throw new Error('Cannot disable Advanced Reporting while Advanced Analytics is active');
            }
        }

        // Add other dependency validations here
    }
}
```

**Using onEnabled/onDisabled Hooks for Dependencies**

You can use the existing `onEnabled` and `onDisabled` hooks to implement dependency logic:

```typescript
// Base service option with dependency checking on disable
export const baseServiceOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Base functionality required by other features',
    isSubscribable: true,
    isHidden: false,
    async onDisabled(context: Context) {
        // Check if any dependent options are still active
        const isDependentActive = await context.isServiceOptionEnabled(dependentServiceOption);
        if (isDependentActive) {
            // Re-enable this option and throw an error
            await context.application.serviceOptionManager.setServiceOptionActiveState(context, this, true);
            throw new Error('Cannot disable Base Service Option while Dependent Service Option is active');
        }
    },
});

// Dependent service option with dependency checking on enable
export const dependentServiceOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Feature that depends on base functionality',
    isSubscribable: true,
    isHidden: false,
    async onEnabled(context: Context) {
        const isBaseActive = await context.isServiceOptionEnabled(baseServiceOption);
        if (!isBaseActive) {
            // Disable this option and throw an error
            await context.application.serviceOptionManager.setServiceOptionActiveState(context, this, false);
            throw new Error('Base Service Option must be enabled first');
        }
    },
});
```

**Best Practices for Service Option Dependencies**

1. **Use `activates` for Simple Dependencies**: For basic "when A is enabled, also enable B" scenarios
2. **Implement Custom Validation**: For complex scenarios requiring validation before activation/deactivation
3. **Use `onEnabled`/`onDisabled` Hooks**: For dependency checking and automatic cleanup
4. **Provide Clear Error Messages**: Always explain which dependencies are required or blocking
5. **Consider Auto-Resolution**: Optionally auto-enable dependencies or auto-disable dependents
6. **Document Dependencies**: Clearly document dependency relationships in service option descriptions
7. **Test All Scenarios**: Thoroughly test activation, deactivation, and edge cases

### Using Service Options in Properties

Service options can control the availability of node properties:

```typescript
// Property only available when service option is enabled
@decorators.integerProperty<ShowCaseProduct, 'discount'>({
    serviceOptions: () => [showCaseDiscountOption],
    isPublished: true,
    isStored: true,
    isNullable: true,
    defaultValue: 20,
    control(ctx, val) {
        if (val && val > 100) {
            throw new Error('Something bad happened');
        }
    },
})
readonly discount: Promise<integer | null>;

// Decimal property with service option
@decorators.decimalProperty<ShowCaseInvoiceLine, 'priceDiscount'>({
    serviceOptions: () => [showCaseDiscountOption],
    isStored: true,
    isPublished: true,
    dataType: () => defaultDecimalDataType,
    defaultValue() {
        return 0;
    },
})
readonly priceDiscount: Promise<decimal>;
```

### Checking Service Option Status

In pages and business logic, you can check if service options are enabled:

```typescript
@ui.decorators.page<DeveloperApiTest>({
    title: 'Developer API Test',
    isTransient: true,
    module: 'show-case',
    category: 'SHOWCASE',
    menuItem: misc,
    onLoad() {
        const isShowCaseOption1Enabled = this.$.isServiceOptionEnabled('showCaseOption1');
        const isShowCaseOption2Enabled = this.$.isServiceOptionEnabled('showCaseOption2');
        const isShowCaseOption3Enabled = this.$.isServiceOptionEnabled('showCaseOption3');

        this.showCaseOption1.value = isShowCaseOption1Enabled ? 'Enabled' : 'Disabled';
        this.showCaseOption2.value = isShowCaseOption2Enabled ? 'Enabled' : 'Disabled';
        this.showCaseOption3.value = isShowCaseOption3Enabled ? 'Enabled' : 'Disabled';
    },
})
export class DeveloperApiTest extends ui.Page {
    // Page implementation
}
```

### Service Option Management

#### Environment Configuration

Service options can be configured globally in `xtrem-config.yml`:

```yml
serviceOptions:
    level: released # Options: released, experimental, workInProgress
```

This controls which service option status levels are available:

- `released`: Only released service options are displayed and available
- `experimental`: Released and experimental service options are available
- `workInProgress`: All service options are available (development mode)

#### Testing with Service Options

```typescript
// Testing service option behavior
import { nodes, serviceOptions } from '../../lib';

// Test with specific service options enabled
const context = await createTestContext({
    testActiveServiceOptions: [serviceOptions.showCaseDiscountOption],
});

// Check service option status in tests
assert.isFalse(await context.isServiceOptionEnabled(serviceOptions.showCaseDiscountOption));
assert.isTrue(await context.isServiceOptionEnabled(serviceOptions.showCaseWorkInProgressOption));
```

### Common Service Option Patterns

#### Integration Service Options

```typescript
// Integration with external systems
export const sage100DeIntegrationServiceOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Sage 100 DE Integration',
    isHidden: false,
});

// Network connectivity features
export const sageNetworkOption = new ServiceOption({
    __filename,
    status: 'workInProgress',
    description: 'Sage Network',
    isSubscribable: false,
    isHidden: false,
    isActiveByDefault: true,
});
```

#### Business Process Options

```typescript
// Order-to-order functionality
export const orderToOrderOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Order to order option',
    isSubscribable: false,
    isHidden: false,
});

// Synchronization services
export const synchronizationServiceOption = new ServiceOption({
    __filename,
    status: 'released',
    description: 'Synchronization',
    isHidden: false,
    isActiveByDefault: true,
});
```

Service options provide a powerful mechanism for controlling feature availability, managing gradual rollouts, and maintaining flexibility in enterprise deployments.

### Layer Data Management

Layer data in XTREM provides a systematic approach to managing initial data, configuration settings, and setup information for applications. The layer system uses CSV files with semicolon delimiters, where column headers are property names in snake_case format corresponding to the actual node property names.

#### Layer Structure and CSV Format

XTREM layer data is organized in a hierarchical structure within the `data/layers/` directory using CSV files:

```
data/
├── layers/
│   ├── setup/           # Initial setup data (loaded first)
│   │   ├── role.csv
│   │   ├── group-role.csv
│   │   └── import-export-template.csv
│   ├── demo/            # Demo data for testing
│   │   ├── show-case-customer.csv
│   │   ├── show-case-product.csv
│   │   └── show-case-invoice.csv
│   ├── test/            # Test data for automated testing
│   └── production/      # Production-ready data
```

**CSV Format Conventions:**

- Semicolon (`;`) delimited CSV files
- Double-quoted field values
- Headers use snake_case format (e.g., `contact_person` for `contactPerson` property)
- File names match the node class name

#### Setup Layer Data

Setup layer data provides essential configuration and initial data required for the application to function properly.

**Role Configuration Example:**

```csv
// data/layers/setup/role.csv
"id";"_vendor";"is_active";"name"
"showcase-all";"sage";"Y";"{""en"":""Showcase all access""}"
"showcase-none";"sage";"Y";"{""en"":""Showcase no access""}"
```

**Group Role Assignment:**

```csv
// data/layers/setup/group-role.csv
"group_role_site";"_sort_value";"_vendor";"role"
"showcase-all";"100";"sage";"showcase-all"
"showcase-none";"200";"sage";"showcase-none"
```

#### Demo/Test Layer Data

Demo and test layer data provides realistic test data for demonstrations, testing, and development purposes.

**Customer Data Example:**

```csv
// data/layers/test/show-case-customer.csv
"name";"contact_person";"email"
"Littel LLC";"Thain Marzele";"tmarzele0@gnu.org"
"Hagenes Inc";"Jeff Berdale";"jberdale1@telegraph.co.uk"
"Steuber and Sons";"Alla Franzewitch";"afranzewitch2@altervista.org"
"MacGyver-Pollich";"Forbes Northey";"fnorthey3@admin.ch"
```

**Product Data with Complex Properties:**

```csv
// data/layers/test/show-case-product.csv
"_sort_value";"product";"barcode";"description";"hot_product";"list_price";"provider";"email";"release_date";"category";"entries";"qty";"net_price"
"100";"Spinach - Baby";"67715667719163157";"Public-key";"Y";"72.56";"1";;"2019-09-19";"good";"[""one"",""two""]";"2";"84.56"
"200";"Veal Inside - Provimi";"3576845570159216";"zero tolerance";"N";"60.49";"1";"afranzewitch2@altervista.org";"2019-09-20";"awful";"[]";"21";"24.15"
"300";"Ice Cream - Super Sandwich";"3559791389699128";"bottom-line";"Y";"25.31";"1";"rplayer6@aboutads.info";"2019-09-21";"good";"[]";"1";"83.81"
```

#### Property Name Mapping

The CSV headers use snake_case format that corresponds to the actual TypeScript property names:

| TypeScript Property | CSV Header         | Example Value        |
| ------------------- | ------------------ | -------------------- |
| `contactPerson`     | `"contact_person"` | `"John Smith"`       |
| `isActive`          | `"is_active"`      | `"Y"` or `"N"`       |
| `listPrice`         | `"list_price"`     | `"72.56"`            |
| `hotProduct`        | `"hot_product"`    | `"Y"` or `"N"`       |
| `sortValue`         | `"_sort_value"`    | `"100"`              |
| `releaseDate`       | `"release_date"`   | `"2019-09-19"`       |
| `createdAt`         | `"createdAt"`      | (already snake_case) |

#### Special Field Types

**Boolean Fields:**

- Use `"Y"` for true, `"N"` for false
- Examples: `"is_active";"Y"`, `"hot_product";"N"`

**JSON Arrays:**

- Stored as escaped JSON strings
- Example: `"entries";"[""one"",""two""]"`

**Multilingual Fields:**

- Use JSON object format with language codes
- Example: `"name";"{""en"":""Showcase all access"",""fr"":""Accès complet vitrine""}"`

**Date Fields:**

- Use ISO date format: `"YYYY-MM-DD"`
- Example: `"release_date";"2019-09-19"`

**File References:**

- Reference external files with `file:` prefix
- Example: `"csv_template";"file:csv-template--show-case-country.json"`

#### Layer Data Loading

Layer data is automatically loaded during application initialization based on the layer hierarchy. The XTREM framework loads JSON data files in a specific order to ensure dependencies are resolved correctly.

**Layer Loading Configuration:**

```json
// layer-config.json
{
    "loadOrder": ["setup", "demo", "production"],
    "environments": {
        "development": ["setup", "demo"],
        "staging": ["setup", "demo"],
        "production": ["setup", "production"]
    },
    "validation": {
        "required": ["setup"],
        "optional": ["demo", "production"]
    }
}
```

#### Production Layer Data

Production layer data contains real business data that should only be loaded in production environments. This data is typically imported from existing systems or created through the application interface.

**Production Data Example:**

```json
// data/layers/production/FixedAsset.json
[
    {
        "_id": "PROD_ASSET_001",
        "code": "BLDG-HQ-001",
        "description": "Corporate Headquarters Building",
        "category": "BUILDING",
        "acquisitionDate": "2018-06-15",
        "acquisitionMethod": "purchase",
        "acquisitionCost": 5500000,
        "depreciationMethod": "straightLine",
        "usefulLifeYears": 39,
        "salvageValue": 550000,
        "currentBookValue": 4785897.44,
        "accumulatedDepreciation": 714102.56,
        "status": "active",
        "location": "123 Corporate Blvd, Suite 100",
        "notes": "Primary headquarters facility",
        "lastMaintenanceDate": "2024-03-15",
        "nextMaintenanceDate": "2024-09-15",
        "insurancePolicyNumber": "POL-2024-001",
        "custodian": "John Smith"
    }
]
```

#### Data Loading Organization

The XTREM framework automatically loads CSV layer data based on the file structure. Each node type corresponds to a CSV file in the layer directory.

**Loading Hierarchy:**

1. **Setup Layer**: Essential configuration loaded first
2. **Demo/Test Layer**: Sample data for development and testing
3. **Production Layer**: Live business data (production only)

**File Naming Convention:**

- CSV files must match the exact node class name
- Example: `ShowCaseCustomer` node → `show-case-customer.csv` file
- Use kebab-case for file names derived from PascalCase class names

#### Data Dependencies and References

Layer data can reference other data within the same layer or previous layers using foreign key relationships through ID fields.

**Reference Examples:**

```csv
// Group roles reference role IDs
// data/layers/setup/group-role.csv
"group_role_site";"_sort_value";"_vendor";"role"
"showcase-all";"100";"sage";"showcase-all"

// Products reference provider IDs
// data/layers/test/show-case-product.csv
"product";"provider";"category"
"Spinach - Baby";"1";"good"
```

**Complex References:**

```csv
// Import templates with file references
// data/layers/setup/import-export-template.csv
"id";"node_name";"default_parameters";"csv_template"
"ShowCaseCustomer";"ShowCaseCustomer";"file:default-parameters--show-case-customer.json";"file:csv-template--show-case-customer.json"
```

#### Data Validation and Migration

Layer data supports validation and migration between environments using CSV format validation:

**CSV Validation Rules:**

```json
// data/validation/csv-validation.json
{
    "ShowCaseCustomer": {
        "required": ["_id", "name", "contact_person"],
        "fieldTypes": {
            "_id": "string",
            "name": "string",
            "contact_person": "string",
            "email": "email"
        },
        "rules": {
            "_id": {
                "pattern": "^[0-9]+$",
                "message": "ID must be numeric"
            },
            "email": {
                "pattern": "^[\\w\\.-]+@[\\w\\.-]+\\.[a-zA-Z]{2,}$",
                "message": "Must be valid email format"
            }
        }
    },
    "ShowCaseProduct": {
        "required": ["_id", "product", "list_price"],
        "fieldTypes": {
            "_id": "string",
            "product": "string",
            "list_price": "decimal",
            "hot_product": "boolean",
            "entries": "json_array"
        }
    }
}
```

#### Best Practices for CSV Layer Data

**1. CSV Format Standards:**

- Always use semicolon (`;`) delimiters
- Quote all field values with double quotes
- Use snake_case for column headers matching property names
- Maintain consistent file naming (kebab-case from PascalCase node names)

**2. Data Organization:**

- Keep setup data minimal and focused on essential configuration
- Use test/demo data for comprehensive testing scenarios
- Store production data separately with appropriate access controls
- Group related data logically within layer directories

**3. Data Integrity:**

- Validate all CSV data before loading using proper schemas
- Use referential integrity constraints where possible
- Implement proper error handling for data loading failures
- Backup data before migrations or major updates

**4. Property Mapping:**

- Ensure CSV headers exactly match expected snake_case property names
- Use `"Y"`/`"N"` for boolean values consistently
- Format dates as ISO strings (`YYYY-MM-DD`)
- Escape JSON strings properly for complex data types

**5. Performance Considerations:**

- Load only necessary data for each environment
- Use appropriate indexing on frequently queried fields
- Monitor CSV loading performance and optimize file sizes
- Implement streaming for large datasets

#### Layer Data CLI Commands

The XTREM CLI provides commands for managing CSV layer data:

```bash
# Read data from the SQL tables and regenerate the layer's CSV files.
xtrem layers --extract {layer}

# Load specific CSV layer data
xtrem layers --extract {layer}
```

Warning: The `--load` command recreates the `xtrem` SQL schema so any data that you may have in this schema will be lost, unless you extracted it, exported the tenant or backed it up.

#### Layer Data Best Practices

1. **Hierarchical Organization**: Organize data by logical layers (setup, demo, test)
2. **Referential Integrity**: Ensure data references are valid within the layer context
3. **Environment-Specific Loading**: Load appropriate data based on deployment environment
4. **Validation**: Include validation rules to ensure data consistency
5. **Documentation**: Document the purpose and dependencies of each data layer
6. **Versioning**: Version layer data to support upgrades and migrations
7. **Security**: Exclude sensitive data from demo and sample layers
8. **Performance**: Optimize data loading for production environments
