Morten Sæther

← Blog

Episode 17: Site Settings & Configuration

27 April 2026

Mastering Global Portal Management and Environment Configuration

Introduction

Professional portal deployment requires sophisticated configuration management that supports multiple environments, feature toggles, and global behavior settings. Site settings and configuration management form the backbone of enterprise-grade Power Pages implementations, enabling controlled deployments, A/B testing, and environment-specific customizations while maintaining consistency across development, staging, and production environments.

Key Concepts

Learning Objectives

By the end of this episode, you will be able to:

Why Site Settings & Configuration Matter

Enterprise portals require sophisticated configuration management to support controlled deployments, environment-specific behaviors, and global feature management. Proper configuration architecture enables rapid deployment cycles, reduces configuration drift, supports A/B testing, and provides the foundation for scalable portal operations across complex organizational structures.

Step-by-Step Guide

1. Advanced Configuration Architecture

Hierarchical Configuration Management:

// Global Configuration Structure
{
  "environment": {
    "name": "production",
    "debug_mode": false,
    "logging_level": "error",
    "performance_monitoring": true
  },
  "features": {
    "advanced_search": {
      "enabled": true,
      "version": "2.1",
      "rollout_percentage": 100,
      "user_segments": ["premium", "enterprise"]
    },
    "new_dashboard": {
      "enabled": false,
      "version": "3.0",
      "rollout_percentage": 0,
      "user_segments": ["beta_testers"]
    },
    "payment_integration": {
      "enabled": true,
      "provider": "stripe",
      "test_mode": false,
      "webhook_url": "https://portal.company.com/webhooks/payment"
    }
  },
  "integrations": {
    "crm": {
      "provider": "dynamics365",
      "endpoint": "https://company.crm.dynamics.com",
      "api_version": "9.2",
      "timeout": 30000,
      "retry_count": 3
    },
    "email_service": {
      "provider": "sendgrid",
      "template_version": "v2",
      "tracking_enabled": true,
      "bounce_handling": true
    }
  },
  "security": {
    "session_timeout": 3600,
    "password_policy": {
      "min_length": 12,
      "require_special_chars": true,
      "require_numbers": true,
      "require_uppercase": true
    },
    "rate_limiting": {
      "api_calls_per_minute": 100,
      "login_attempts_per_hour": 5
    }
  },
  "content": {
    "default_language": "en-US",
    "supported_languages": ["en-US", "es-ES", "fr-FR", "de-DE"],
    "content_versioning": true,
    "auto_translation": false
  }
}

Environment-Specific Configuration Implementation:

<!-- Environment Detection and Configuration Loading -->
{% assign environment = site.environment | default: 'development' %}
{% assign config = site.data.configurations[environment] %}

<!-- Debug Information (Development Only) -->
{% if config.environment.debug_mode %}
    <div class="debug-panel" style="position: fixed; bottom: 0; right: 0; background: #000; color: #fff; padding: 10px; z-index: 9999;">
        <h4>Debug Information</h4>
        <p>Environment: {{ environment }}</p>
        <p>Debug Mode: {{ config.environment.debug_mode }}</p>
        <p>User ID: {{ user.id }}</p>
        <p>Session ID: {{ session.id }}</p>
        <p>Current Language: {{ request.language }}</p>
        <p>User Roles: {{ user.roles | join: ', ' }}</p>
        <p>Performance Monitoring: {{ config.environment.performance_monitoring }}</p>
        
        <details>
            <summary>Active Features</summary>
            <ul>
                {% for feature in config.features %}
                    {% if feature.enabled %}
                        <li>{{ feature.name }} - v{{ feature.version }}</li>
                    {% endif %}
                {% endfor %}
            </ul>
        </details>
        
        <details>
            <summary>Configuration Details</summary>
            <pre>{{ config | json }}</pre>
        </details>
    </div>
{% endif %}

<!-- Performance Monitoring Integration -->
{% if config.environment.performance_monitoring %}
    <script>
        // Initialize performance monitoring
        (function() {
            const performanceConfig = {
                environment: '{{ environment }}',
                userId: '{{ user.id }}',
                sessionId: '{{ session.id }}',
                buildVersion: '{{ site.build_version }}',
                enabledFeatures: {{ config.features | where: 'enabled', true | map: 'name' | json }}
            };
            
            // Track page load performance
            window.addEventListener('load', function() {
                const loadTime = performance.timing.loadEventEnd - performance.timing.navigationStart;
                trackMetric('page_load_time', loadTime, performanceConfig);
            });
            
            // Track feature usage
            function trackFeatureUsage(featureName, action, metadata = {}) {
                trackEvent('feature_usage', {
                    feature: featureName,
                    action: action,
                    ...metadata,
                    ...performanceConfig
                });
            }
            
            window.trackFeatureUsage = trackFeatureUsage;
        })();
    </script>
{% endif %}

<!-- Error Logging Configuration -->
{% assign logging_level = config.environment.logging_level | default: 'warn' %}
<script>
    window.LOGGING_CONFIG = {
        level: '{{ logging_level }}',
        environment: '{{ environment }}',
        userId: '{{ user.id }}',
        endpoint: '/api/logging'
    };
    
    // Custom error handler
    window.onerror = function(message, source, lineno, colno, error) {
        if (window.LOGGING_CONFIG.level === 'error' || window.LOGGING_CONFIG.level === 'debug') {
            logError({
                message: message,
                source: source,
                line: lineno,
                column: colno,
                error: error ? error.stack : null,
                userAgent: navigator.userAgent,
                url: window.location.href,
                timestamp: new Date().toISOString()
            });
        }
    };
</script>

2. Advanced Feature Toggle System

Dynamic Feature Management:

<!-- Feature Toggle Engine -->
{% assign user_segments = user.segments | default: array %}
{% assign user_id_hash = user.id | sha256 | slice: 0, 8 %}

<!-- Feature Availability Checker -->
{% capture check_feature_availability %}
    {% assign feature_name = include.feature %}
    {% assign feature_config = config.features[feature_name] %}
    {% assign is_available = false %}
    
    {% if feature_config.enabled %}
        <!-- Check user segment eligibility -->
        {% assign segment_match = false %}
        {% for segment in feature_config.user_segments %}
            {% if user_segments contains segment %}
                {% assign segment_match = true %}
                {% break %}
            {% endif %}
        {% endfor %}
        
        {% if segment_match or feature_config.user_segments.size == 0 %}
            <!-- Check rollout percentage -->
            {% assign user_hash_decimal = user_id_hash | hex_to_decimal %}
            {% assign user_percentage = user_hash_decimal | modulo: 100 %}
            
            {% if user_percentage < feature_config.rollout_percentage %}
                {% assign is_available = true %}
            {% endif %}
        {% endif %}
    {% endif %}
    
    {{ is_available }}
{% endcapture %}

<!-- Advanced Search Feature Implementation -->
{% include 'check_feature_availability', feature: 'advanced_search' %}
{% assign advanced_search_enabled = check_feature_availability %}

{% if advanced_search_enabled == 'true' %}
    <div class="advanced-search-container">
        <h3>Advanced Search</h3>
        <form class="advanced-search-form" method="get" action="/search">
            <div class="search-fields">
                <div class="field-group">
                    <label for="keywords">Keywords:</label>
                    <input type="text" id="keywords" name="q" value="{{ request.params.q }}">
                </div>
                
                <div class="field-group">
                    <label for="category">Category:</label>
                    <select id="category" name="category">
                        <option value="">All Categories</option>
                        {% for category in search_categories %}
                            <option value="{{ category.value }}" 
                                    {% if request.params.category == category.value %}selected{% endif %}>
                                {{ category.label }}
                            </option>
                        {% endfor %}
                    </select>
                </div>
                
                <div class="field-group">
                    <label for="date_range">Date Range:</label>
                    <select id="date_range" name="date_range">
                        <option value="">Any Time</option>
                        <option value="last_week">Last Week</option>
                        <option value="last_month">Last Month</option>
                        <option value="last_year">Last Year</option>
                    </select>
                </div>
                
                <div class="field-group">
                    <label for="content_type">Content Type:</label>
                    <select id="content_type" name="content_type">
                        <option value="">All Types</option>
                        <option value="articles">Articles</option>
                        <option value="documents">Documents</option>
                        <option value="videos">Videos</option>
                    </select>
                </div>
            </div>
            
            <div class="search-actions">
                <button type="submit" class="btn btn-primary">Search</button>
                <button type="button" class="btn btn-secondary" onclick="clearAdvancedSearch()">Clear</button>
            </div>
        </form>
        
        <!-- Advanced Search Analytics -->
        <script>
            if (window.trackFeatureUsage) {
                document.querySelector('.advanced-search-form').addEventListener('submit', function(e) {
                    window.trackFeatureUsage('advanced_search', 'search_performed', {
                        has_category: e.target.category.value !== '',
                        has_date_range: e.target.date_range.value !== '',
                        has_content_type: e.target.content_type.value !== ''
                    });
                });
            }
        </script>
    </div>
{% else %}
    <!-- Fallback to Basic Search -->
    <div class="basic-search-container">
        <form class="search-form" method="get" action="/search">
            <div class="search-input-group">
                <input type="text" name="q" placeholder="Search..." value="{{ request.params.q }}">
                <button type="submit" class="btn btn-primary">Search</button>
            </div>
        </form>
    </div>
{% endif %}

<!-- New Dashboard Feature with Beta Access -->
{% include 'check_feature_availability', feature: 'new_dashboard' %}
{% assign new_dashboard_enabled = check_feature_availability %}

{% if new_dashboard_enabled == 'true' %}
    <div class="beta-feature-notice">
        <div class="notice-header">
            <span class="beta-badge">BETA</span>
            <h4>New Dashboard Experience</h4>
        </div>
        <p>You're seeing our new dashboard design. <a href="/feedback/dashboard">Share your feedback</a></p>
    </div>
    
    <!-- Enhanced Dashboard Content -->
    <div class="dashboard-v3">
        <div class="dashboard-grid">
            <!-- Modern dashboard implementation -->
            <div class="dashboard-card analytics-card">
                <h3>Analytics Overview</h3>
                <div class="metrics-grid">
                    <div class="metric">
                        <span class="metric-value">{{ user.activity.page_views }}</span>
                        <span class="metric-label">Page Views</span>
                    </div>
                    <div class="metric">
                        <span class="metric-value">{{ user.activity.downloads }}</span>
                        <span class="metric-label">Downloads</span>
                    </div>
                </div>
            </div>
            
            <div class="dashboard-card tasks-card">
                <h3>Quick Actions</h3>
                <div class="actions-list">
                    <a href="/upload" class="action-item">
                        <span class="action-icon">📁</span>
                        <span class="action-text">Upload Document</span>
                    </a>
                    <a href="/requests/new" class="action-item">
                        <span class="action-icon">📝</span>
                        <span class="action-text">New Request</span>
                    </a>
                </div>
            </div>
        </div>
    </div>
    
    <script>
        // Track beta dashboard usage
        if (window.trackFeatureUsage) {
            window.trackFeatureUsage('new_dashboard', 'viewed');
            
            // Track interactions with dashboard elements
            document.querySelectorAll('.dashboard-card').forEach(card => {
                card.addEventListener('click', function() {
                    window.trackFeatureUsage('new_dashboard', 'card_interaction', {
                        card_type: this.className.includes('analytics') ? 'analytics' : 'actions'
                    });
                });
            });
        }
    </script>
{% else %}
    <!-- Standard Dashboard -->
    <div class="dashboard-v2">
        <h2>Dashboard</h2>
        <div class="dashboard-summary">
            <div class="summary-item">
                <h4>Recent Activity</h4>
                <p>{{ user.activity.recent_count }} recent actions</p>
            </div>
            <div class="summary-item">
                <h4>Notifications</h4>
                <p>{{ user.notifications.unread_count }} unread messages</p>
            </div>
        </div>
    </div>
{% endif %}

3. Integration Configuration Management

Dynamic Integration Settings:

<!-- CRM Integration Configuration -->
{% assign crm_config = config.integrations.crm %}

<script>
    // CRM Integration Setup
    window.CRM_CONFIG = {
        provider: '{{ crm_config.provider }}',
        endpoint: '{{ crm_config.endpoint }}',
        apiVersion: '{{ crm_config.api_version }}',
        timeout: {{ crm_config.timeout }},
        retryCount: {{ crm_config.retry_count }}
    };
    
    // CRM API Client
    class CRMClient {
        constructor(config) {
            this.config = config;
            this.baseUrl = config.endpoint;
        }
        
        async makeRequest(endpoint, options = {}) {
            const url = `${this.baseUrl}${endpoint}`;
            const defaultOptions = {
                headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                    'OData-MaxVersion': '4.0',
                    'OData-Version': '4.0'
                },
                timeout: this.config.timeout
            };
            
            const requestOptions = { ...defaultOptions, ...options };
            
            for (let attempt = 0; attempt < this.config.retryCount; attempt++) {
                try {
                    const response = await fetch(url, requestOptions);
                    
                    if (!response.ok) {
                        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
                    }
                    
                    return await response.json();
                } catch (error) {
                    if (attempt === this.config.retryCount - 1) {
                        throw error;
                    }
                    
                    // Exponential backoff
                    await new Promise(resolve => 
                        setTimeout(resolve, Math.pow(2, attempt) * 1000)
                    );
                }
            }
        }
        
        async getContact(contactId) {
            return this.makeRequest(`/api/data/v${this.config.apiVersion}/contacts(${contactId})`);
        }
        
        async updateContact(contactId, data) {
            return this.makeRequest(`/api/data/v${this.config.apiVersion}/contacts(${contactId})`, {
                method: 'PATCH',
                body: JSON.stringify(data)
            });
        }
    }
    
    // Initialize CRM client
    window.crmClient = new CRMClient(window.CRM_CONFIG);
</script>

<!-- Email Service Configuration -->
{% assign email_config = config.integrations.email_service %}

<script>
    // Email Service Configuration
    window.EMAIL_CONFIG = {
        provider: '{{ email_config.provider }}',
        templateVersion: '{{ email_config.template_version }}',
        trackingEnabled: {{ email_config.tracking_enabled }},
        bounceHandling: {{ email_config.bounce_handling }}
    };
    
    // Email Service Integration
    class EmailService {
        constructor(config) {
            this.config = config;
        }
        
        async sendEmail(templateId, recipientEmail, templateData = {}) {
            const emailData = {
                template_id: templateId,
                template_version: this.config.templateVersion,
                recipient: recipientEmail,
                template_data: templateData,
                tracking_enabled: this.config.trackingEnabled,
                bounce_handling: this.config.bounceHandling
            };
            
            try {
                const response = await fetch('/api/email/send', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify(emailData)
                });
                
                if (!response.ok) {
                    throw new Error(`Email send failed: ${response.statusText}`);
                }
                
                return await response.json();
            } catch (error) {
                console.error('Email sending error:', error);
                throw error;
            }
        }
        
        async getEmailStatus(messageId) {
            const response = await fetch(`/api/email/status/${messageId}`);
            return response.json();
        }
    }
    
    // Initialize email service
    window.emailService = new EmailService(window.EMAIL_CONFIG);
</script>

4. Security Configuration Implementation

Advanced Security Settings:

<!-- Security Configuration -->
{% assign security_config = config.security %}

<!-- Session Management -->
<script>
    // Session Configuration
    window.SESSION_CONFIG = {
        timeout: {{ security_config.session_timeout }},
        warningTime: {{ security_config.session_timeout | minus: 300 }}, // 5 minutes before timeout
        renewEndpoint: '/api/session/renew',
        logoutEndpoint: '/api/session/logout'
    };
    
    // Session Management System
    class SessionManager {
        constructor(config) {
            this.config = config;
            this.warningShown = false;
            this.timeoutTimer = null;
            this.warningTimer = null;
            this.lastActivity = Date.now();
            
            this.setupActivityTracking();
            this.startTimers();
        }
        
        setupActivityTracking() {
            const events = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart'];
            
            events.forEach(event => {
                document.addEventListener(event, () => {
                    this.updateActivity();
                }, { passive: true });
            });
        }
        
        updateActivity() {
            this.lastActivity = Date.now();
            this.resetTimers();
        }
        
        startTimers() {
            // Warning timer
            this.warningTimer = setTimeout(() => {
                this.showSessionWarning();
            }, this.config.warningTime * 1000);
            
            // Timeout timer
            this.timeoutTimer = setTimeout(() => {
                this.logoutUser();
            }, this.config.timeout * 1000);
        }
        
        resetTimers() {
            clearTimeout(this.warningTimer);
            clearTimeout(this.timeoutTimer);
            this.warningShown = false;
            this.startTimers();
        }
        
        showSessionWarning() {
            if (this.warningShown) return;
            this.warningShown = true;
            
            const timeLeft = Math.floor((this.config.timeout * 1000 - (Date.now() - this.lastActivity)) / 1000);
            
            if (confirm(`Your session will expire in ${Math.floor(timeLeft / 60)} minutes. Would you like to extend your session?`)) {
                this.renewSession();
            }
        }
        
        async renewSession() {
            try {
                const response = await fetch(this.config.renewEndpoint, {
                    method: 'POST',
                    credentials: 'same-origin'
                });
                
                if (response.ok) {
                    this.resetTimers();
                } else {
                    throw new Error('Session renewal failed');
                }
            } catch (error) {
                console.error('Session renewal error:', error);
                this.logoutUser();
            }
        }
        
        logoutUser() {
            window.location.href = this.config.logoutEndpoint;
        }
    }
    
    // Initialize session manager
    document.addEventListener('DOMContentLoaded', function() {
        window.sessionManager = new SessionManager(window.SESSION_CONFIG);
    });
</script>

<!-- Password Policy Enforcement -->
{% assign password_policy = security_config.password_policy %}

<script>
    // Password Policy Configuration
    window.PASSWORD_POLICY = {
        minLength: {{ password_policy.min_length }},
        requireSpecialChars: {{ password_policy.require_special_chars }},
        requireNumbers: {{ password_policy.require_numbers }},
        requireUppercase: {{ password_policy.require_uppercase }}
    };
    
    // Password Validation
    function validatePassword(password) {
        const policy = window.PASSWORD_POLICY;
        const errors = [];
        
        if (password.length < policy.minLength) {
            errors.push(`Password must be at least ${policy.minLength} characters long`);
        }
        
        if (policy.requireSpecialChars && !/[!@#$%^&*(),.?":{}|<>]/.test(password)) {
            errors.push('Password must contain at least one special character');
        }
        
        if (policy.requireNumbers && !/\d/.test(password)) {
            errors.push('Password must contain at least one number');
        }
        
        if (policy.requireUppercase && !/[A-Z]/.test(password)) {
            errors.push('Password must contain at least one uppercase letter');
        }
        
        return {
            isValid: errors.length === 0,
            errors: errors
        };
    }
    
    // Apply password validation to forms
    document.addEventListener('DOMContentLoaded', function() {
        const passwordFields = document.querySelectorAll('input[type="password"]');
        
        passwordFields.forEach(field => {
            if (field.name === 'new_password' || field.name === 'password') {
                field.addEventListener('input', function() {
                    const validation = validatePassword(this.value);
                    const feedbackElement = this.parentNode.querySelector('.password-feedback');
                    
                    if (feedbackElement) {
                        feedbackElement.innerHTML = validation.errors.map(error => 
                            `<div class="error">${error}</div>`
                        ).join('');
                    }
                });
            }
        });
    });
</script>

<!-- Rate Limiting Display -->
{% assign rate_limiting = security_config.rate_limiting %}

<script>
    // Rate Limiting Configuration
    window.RATE_LIMITING = {
        apiCallsPerMinute: {{ rate_limiting.api_calls_per_minute }},
        loginAttemptsPerHour: {{ rate_limiting.login_attempts_per_hour }}
    };
    
    // Rate limiting feedback
    function handleRateLimitResponse(response) {
        if (response.status === 429) {
            const retryAfter = response.headers.get('Retry-After');
            const message = retryAfter 
                ? `Rate limit exceeded. Please try again in ${retryAfter} seconds.`
                : 'Rate limit exceeded. Please try again later.';
            
            showMessage(message, 'warning');
            return true;
        }
        return false;
    }
    
    // Apply rate limiting handling to API calls
    const originalFetch = window.fetch;
    window.fetch = function(...args) {
        return originalFetch.apply(this, args).then(response => {
            handleRateLimitResponse(response);
            return response;
        });
    };
</script>

5. Content Configuration Management

Multi-Language Content Settings:

<!-- Content Configuration -->
{% assign content_config = config.content %}

<!-- Language Management -->
<div class="content-configuration">
    <div class="language-settings">
        <h3>Language Configuration</h3>
        
        <div class="current-language">
            <strong>Current Language:</strong> {{ content_config.default_language }}
        </div>
        
        <div class="supported-languages">
            <strong>Supported Languages:</strong>
            <ul>
                {% for language in content_config.supported_languages %}
                    <li>
                        <span class="language-code">{{ language }}</span>
                        {% if language == content_config.default_language %}
                            <span class="default-badge">Default</span>
                        {% endif %}
                    </li>
                {% endfor %}
            </ul>
        </div>
        
        {% if content_config.content_versioning %}
            <div class="versioning-info">
                <h4>Content Versioning</h4>
                <p>Content versioning is enabled. All content changes are tracked and can be reverted.</p>
                
                <div class="version-controls">
                    <button class="btn btn-outline-secondary" onclick="showVersionHistory()">
                        View Version History
                    </button>
                    <button class="btn btn-outline-secondary" onclick="showContentDiff()">
                        Compare Versions
                    </button>
                </div>
            </div>
        {% endif %}
        
        {% if content_config.auto_translation %}
            <div class="auto-translation-info">
                <h4>Automatic Translation</h4>
                <p>Automatic translation is enabled for supported content types.</p>
                
                <div class="translation-status">
                    <div class="status-item">
                        <span class="status-label">Translation Provider:</span>
                        <span class="status-value">{{ content_config.translation_provider | default: 'Azure Translator' }}</span>
                    </div>
                    <div class="status-item">
                        <span class="status-label">Quality Threshold:</span>
                        <span class="status-value">{{ content_config.translation_quality_threshold | default: 85 }}%</span>
                    </div>
                </div>
            </div>
        {% endif %}
    </div>
</div>

<!-- Content Management Scripts -->
<script>
    // Content Configuration Management
    window.CONTENT_CONFIG = {
        defaultLanguage: '{{ content_config.default_language }}',
        supportedLanguages: {{ content_config.supported_languages | json }},
        versioningEnabled: {{ content_config.content_versioning }},
        autoTranslation: {{ content_config.auto_translation }}
    };
    
    // Version Management Functions
    function showVersionHistory() {
        // Implementation for showing content version history
        window.open('/admin/content/versions', '_blank');
    }
    
    function showContentDiff() {
        // Implementation for content comparison
        window.open('/admin/content/compare', '_blank');
    }
    
    // Content Editor Enhancement
    function enhanceContentEditor() {
        const editors = document.querySelectorAll('.content-editor');
        
        editors.forEach(editor => {
            // Add auto-save functionality
            let saveTimeout;
            editor.addEventListener('input', function() {
                clearTimeout(saveTimeout);
                saveTimeout = setTimeout(() => {
                    autoSaveContent(this);
                }, 2000);
            });
            
            // Add translation suggestions if auto-translation is enabled
            if (window.CONTENT_CONFIG.autoTranslation) {
                addTranslationSuggestions(editor);
            }
        });
    }
    
    function autoSaveContent(editor) {
        const contentId = editor.dataset.contentId;
        const content = editor.value || editor.innerHTML;
        
        fetch('/api/content/autosave', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                contentId: contentId,
                content: content,
                language: window.CONTENT_CONFIG.defaultLanguage
            })
        }).then(response => {
            if (response.ok) {
                showAutoSaveIndicator();
            }
        });
    }
    
    function showAutoSaveIndicator() {
        const indicator = document.querySelector('.autosave-indicator');
        if (indicator) {
            indicator.textContent = 'Auto-saved at ' + new Date().toLocaleTimeString();
            indicator.style.opacity = '1';
            setTimeout(() => {
                indicator.style.opacity = '0.5';
            }, 2000);
        }
    }
    
    // Initialize content management features
    document.addEventListener('DOMContentLoaded', function() {
        enhanceContentEditor();
    });
</script>

Practical Example: Multi-Environment Portal Configuration

Let’s implement a complete configuration management system for a corporate portal:

<!-- environment-specific-portal.html -->
{% assign env = site.environment %}
{% assign config = site.data.configurations[env] %}

<!DOCTYPE html>
<html lang="{{ config.content.default_language }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ site.title }} - {{ config.environment.name | capitalize }} Environment</title>
    
    <!-- Environment-Specific Stylesheets -->
    {% if env == 'development' %}
        <link rel="stylesheet" href="/assets/css/app.css">
        <link rel="stylesheet" href="/assets/css/debug.css">
    {% elsif env == 'staging' %}
        <link rel="stylesheet" href="/assets/css/app.min.css">
        <link rel="stylesheet" href="/assets/css/staging-banner.css">
    {% else %}
        <link rel="stylesheet" href="/assets/css/app.min.css">
        {% if config.features.cdn_assets.enabled %}
            <link rel="preconnect" href="{{ config.features.cdn_assets.domain }}">
        {% endif %}
    {% endif %}
    
    <!-- Performance Monitoring -->
    {% if config.environment.performance_monitoring %}
        <script>
            window.performance.mark('head-start');
        </script>
    {% endif %}
</head>
<body class="env-{{ env }}">
    <!-- Environment Banner -->
    {% unless env == 'production' %}
        <div class="environment-banner {{ env }}">
            <div class="banner-content">
                <span class="env-label">{{ env | upcase }} ENVIRONMENT</span>
                <span class="env-warning">This is not the live site</span>
                {% if config.environment.debug_mode %}
                    <span class="debug-indicator">DEBUG MODE ENABLED</span>
                {% endif %}
            </div>
        </div>
    {% endunless %}
    
    <!-- Main Navigation with Feature Toggles -->
    <nav class="main-navigation">
        <div class="nav-container">
            <div class="nav-brand">
                <a href="/">{{ site.title }}</a>
            </div>
            
            <div class="nav-links">
                <a href="/">Home</a>
                <a href="/products">Products</a>
                <a href="/support">Support</a>
                
                <!-- Feature-Gated Navigation Items -->
                {% include 'check_feature_availability', feature: 'advanced_search' %}
                {% if check_feature_availability == 'true' %}
                    <a href="/search/advanced">Advanced Search</a>
                {% endif %}
                
                {% include 'check_feature_availability', feature: 'new_dashboard' %}
                {% if check_feature_availability == 'true' %}
                    <a href="/dashboard/v3" class="beta-link">
                        Dashboard
                        <span class="beta-badge">BETA</span>
                    </a>
                {% else %}
                    <a href="/dashboard">Dashboard</a>
                {% endif %}
                
                <!-- User-Specific Navigation -->
                {% if user %}
                    <div class="user-menu">
                        <a href="/profile">{{ user.fullname }}</a>
                        <div class="dropdown">
                            <a href="/profile">Profile</a>
                            <a href="/settings">Settings</a>
                            {% if user.roles contains 'Administrator' %}
                                <a href="/admin">Administration</a>
                            {% endif %}
                            <a href="/logout">Logout</a>
                        </div>
                    </div>
                {% else %}
                    <a href="/login">Login</a>
                {% endif %}
            </div>
        </div>
    </nav>
    
    <!-- Main Content Area -->
    <main class="main-content">
        <!-- Feature Toggle Configuration Panel (Admin Only) -->
        {% if user.roles contains 'Administrator' and config.environment.debug_mode %}
            <div class="admin-feature-panel">
                <h4>Feature Toggle Panel</h4>
                <div class="feature-toggles">
                    {% for feature in config.features %}
                        <div class="feature-toggle">
                            <label>
                                <input type="checkbox" 
                                       data-feature="{{ feature[0] }}"
                                       {% if feature[1].enabled %}checked{% endif %}
                                       onchange="toggleFeature(this)">
                                {{ feature[0] | replace: '_', ' ' | capitalize }}
                            </label>
                            <span class="rollout-info">{{ feature[1].rollout_percentage }}% rollout</span>
                        </div>
                    {% endfor %}
                </div>
            </div>
        {% endif %}
        
        <!-- Dynamic Content Based on Configuration -->
        <div class="content-area">
            <h1>Welcome to {{ site.title }}</h1>
            
            <!-- Environment-Specific Messaging -->
            {% case env %}
                {% when 'development' %}
                    <div class="dev-notice">
                        <h3>Development Environment</h3>
                        <p>This environment is for development and testing purposes.</p>
                        <ul>
                            <li>Debug mode: {{ config.environment.debug_mode }}</li>
                            <li>Performance monitoring: {{ config.environment.performance_monitoring }}</li>
                            <li>Logging level: {{ config.environment.logging_level }}</li>
                        </ul>
                    </div>
                {% when 'staging' %}
                    <div class="staging-notice">
                        <h3>Staging Environment</h3>
                        <p>This environment mirrors production for final testing.</p>
                        <p>Data may be reset periodically.</p>
                    </div>
                {% when 'production' %}
                    <!-- Production-specific content -->
                    <div class="welcome-section">
                        <p>Your trusted partner for digital solutions.</p>
                    </div>
            {% endcase %}
            
            <!-- Integration Status Dashboard -->
            <div class="integration-status">
                <h3>System Status</h3>
                <div class="status-grid">
                    <div class="status-item">
                        <span class="status-label">CRM Integration:</span>
                        <span class="status-indicator" data-service="crm">
                            <span class="loading">Checking...</span>
                        </span>
                    </div>
                    <div class="status-item">
                        <span class="status-label">Email Service:</span>
                        <span class="status-indicator" data-service="email">
                            <span class="loading">Checking...</span>
                        </span>
                    </div>
                    <div class="status-item">
                        <span class="status-label">Payment Gateway:</span>
                        <span class="status-indicator" data-service="payment">
                            <span class="loading">Checking...</span>
                        </span>
                    </div>
                </div>
            </div>
            
            <!-- Content Preview with Versioning -->
            {% if config.content.content_versioning %}
                <div class="content-preview">
                    <div class="content-header">
                        <h3>Latest Content Updates</h3>
                        <button class="btn btn-outline-primary" onclick="showContentVersions()">
                            View All Versions
                        </button>
                    </div>
                    
                    <div class="content-items">
                        {% assign recent_content = site.data.content_updates | sort: 'updated_date' | reverse | limit: 5 %}
                        {% for content_item in recent_content %}
                            <div class="content-item">
                                <h4>{{ content_item.title }}</h4>
                                <p class="content-meta">
                                    Updated: {{ content_item.updated_date | date: "%B %d, %Y" }}
                                    | Version: {{ content_item.version }}
                                    | Language: {{ content_item.language }}
                                </p>
                                <p>{{ content_item.summary }}</p>
                            </div>
                        {% endfor %}
                    </div>
                </div>
            {% endif %}
        </div>
    </main>
    
    <!-- Configuration-Driven JavaScript -->
    <script>
        // Global Configuration
        window.PORTAL_CONFIG = {
            environment: '{{ env }}',
            debug: {{ config.environment.debug_mode }},
            features: {{ config.features | json }},
            integrations: {
                crm: {
                    provider: '{{ config.integrations.crm.provider }}',
                    timeout: {{ config.integrations.crm.timeout }}
                },
                email: {
                    provider: '{{ config.integrations.email_service.provider }}'
                }
            },
            security: {
                sessionTimeout: {{ config.security.session_timeout }}
            }
        };
        
        // Feature Toggle Management (Admin Only)
        {% if user.roles contains 'Administrator' %}
            function toggleFeature(checkbox) {
                const featureName = checkbox.dataset.feature;
                const enabled = checkbox.checked;
                
                fetch('/api/admin/features/toggle', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        feature: featureName,
                        enabled: enabled,
                        environment: '{{ env }}'
                    })
                }).then(response => {
                    if (response.ok) {
                        showMessage(`Feature ${featureName} ${enabled ? 'enabled' : 'disabled'}`, 'success');
                        // Optionally reload page to reflect changes
                        if (confirm('Reload page to see changes?')) {
                            location.reload();
                        }
                    } else {
                        showMessage('Failed to toggle feature', 'error');
                        checkbox.checked = !enabled; // Revert checkbox
                    }
                });
            }
        {% endif %}
        
        // Integration Health Checks
        async function checkIntegrationHealth() {
            const services = ['crm', 'email', 'payment'];
            
            for (const service of services) {
                try {
                    const response = await fetch(`/api/health/${service}`);
                    const status = response.ok ? 'healthy' : 'unhealthy';
                    updateStatusIndicator(service, status);
                } catch (error) {
                    updateStatusIndicator(service, 'error');
                }
            }
        }
        
        function updateStatusIndicator(service, status) {
            const indicator = document.querySelector(`[data-service="${service}"]`);
            if (indicator) {
                const statusText = {
                    'healthy': '✅ Operational',
                    'unhealthy': '⚠️ Issues Detected',
                    'error': '❌ Offline'
                };
                
                indicator.innerHTML = statusText[status] || '❓ Unknown';
                indicator.className = `status-indicator ${status}`;
            }
        }
        
        // Content Version Management
        function showContentVersions() {
            window.open('/admin/content/versions', '_blank');
        }
        
        // Initialize application
        document.addEventListener('DOMContentLoaded', function() {
            // Check integration health
            checkIntegrationHealth();
            
            // Set up environment-specific features
            if (window.PORTAL_CONFIG.debug) {
                console.log('Portal Configuration:', window.PORTAL_CONFIG);
            }
            
            // Initialize session management
            if (window.sessionManager) {
                window.sessionManager.init();
            }
        });
        
        // Environment-specific error handling
        {% if env == 'production' %}
            window.onerror = function(message, source, lineno, colno, error) {
                // Send to error tracking service
                fetch('/api/errors/report', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({
                        message, source, lineno, colno,
                        stack: error ? error.stack : null,
                        userAgent: navigator.userAgent,
                        url: location.href,
                        timestamp: new Date().toISOString()
                    })
                });
            };
        {% else %}
            window.onerror = function(message, source, lineno, colno, error) {
                console.error('Error:', { message, source, lineno, colno, error });
            };
        {% endif %}
    </script>
    
    <!-- Environment-Specific Analytics -->
    {% if env == 'production' and config.environment.performance_monitoring %}
        <script>
            // Production analytics tracking
            (function() {
                // Track page performance
                window.addEventListener('load', function() {
                    const loadTime = performance.timing.loadEventEnd - performance.timing.navigationStart;
                    gtag('event', 'page_load_time', {
                        'value': loadTime,
                        'custom_parameter': 'milliseconds'
                    });
                });
                
                // Track feature usage
                window.trackFeatureUsage = function(feature, action, metadata = {}) {
                    gtag('event', 'feature_usage', {
                        'feature_name': feature,
                        'action': action,
                        'custom_parameters': metadata
                    });
                };
            })();
        </script>
    {% elsif env == 'development' %}
        <script>
            // Development analytics (console only)
            window.trackFeatureUsage = function(feature, action, metadata = {}) {
                console.log('Feature Usage:', { feature, action, metadata });
            };
        </script>
    {% endif %}
</body>
</html>

Troubleshooting Common Issues

Configuration Management Debugging:

  1. Environment Detection Issues: Verify environment variables and configuration file paths
  2. Feature Toggle Conflicts: Check for conflicting feature dependencies and rollout percentages
  3. Integration Failures: Implement comprehensive health checks and fallback mechanisms
  4. Configuration Drift: Establish automated configuration validation and sync processes
  5. Performance Impact: Monitor configuration loading and feature toggle evaluation overhead

Configuration Management Best Practices

Establishing Robust Configuration Governance:

  1. Version Control: Track all configuration changes through version control systems
  2. Environment Parity: Maintain consistency between development, staging, and production
  3. Automated Testing: Validate configuration changes through automated test suites
  4. Rollback Procedures: Implement quick rollback mechanisms for configuration issues
  5. Documentation: Maintain comprehensive documentation of all configuration options

Key Takeaways

Site settings and configuration management form the foundation of enterprise-grade Power Pages implementations. Focus on hierarchical configuration architecture, robust feature toggle systems, comprehensive integration management, and strong governance processes to build scalable, maintainable portal solutions that support complex organizational requirements and controlled deployment strategies.

In the next episode, you’ll learn about JavaScript Frameworks Integration to enhance your portal with modern front-end technologies and create rich, interactive user experiences.

4. Documentation and Maintenance

Set yourself up for long-term success:

Practical Example

Consider implementing this episode’s techniques for a customer portal where users need enhanced functionality beyond basic templates. The implementation should:

Apply the specific techniques from this episode while following the general principles of good portal development.

Common Implementation Patterns

Pattern When to Use Benefits Considerations
Progressive Enhancement Adding advanced features Ensures basic functionality always works Requires careful planning
Responsive Design Multi-device support Consistent experience across devices May increase complexity
Modular Development Complex customizations Easier maintenance and updates Requires good architecture
Performance Monitoring All implementations Early detection of issues Ongoing effort required

Troubleshooting Tips

Advanced Considerations

As you implement these intermediate techniques, consider:

Summary

Advanced site configuration enables enterprise-grade portals that perform well, scale effectively, and integrate seamlessly with your IT infrastructure. Document your configurations thoroughly and implement proper change management processes. Next, you’ll add powerful search functionality to help users find information quickly.