# Premium Version - Technical Architecture ## Overview This document describes the architecture for implementing a premium/pro version toggle system that allows switching between: - **Standard Mode**: Current React + MyUIbrix system - **Premium Mode**: Professional Elementor-style templates ## System Design ### Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────┐ │ User Request │ └────────────────────────┬────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ Nginx / Reverse Proxy │ │ Routes: /premium/* → Static Assets │ │ /api/* → Backend │ │ /* → Frontend React App │ └────────────────────────┬────────────────────────────────────┘ │ ┌──────────────┴──────────────┐ │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ Backend (Go) │ │ Frontend (React)│ │ │ │ │ │ Middleware: │◄─────────►│ Check Settings: │ │ - Premium Mode │ API │ premium_mode_ │ │ - Feature Flags │ │ active │ │ │ │ │ │ Routes: │ │ Conditional │ │ /premium/css/* │ │ Render: │ │ /premium/js/* │ │ - Standard │ │ /premium/img/* │ │ - Premium │ └──────────────────┘ └──────────────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ PostgreSQL │ │ Browser │ │ │ │ │ │ settings table: │ │ Loads: │ │ - premium_mode_ │ │ - Premium CSS │ │ active │ │ - Premium JS │ │ - premium_ │ │ - Club Theme │ │ features │ │ │ └──────────────────┘ └──────────────────┘ ``` --- ## Component Architecture ### Backend Components #### 1. Configuration Layer **File:** `internal/config/config.go` ```go type Config struct { // Existing fields... // Premium Mode Configuration PremiumMode bool `env:"PREMIUM_MODE" envDefault:"false"` PremiumHomepage bool `env:"PREMIUM_HOMEPAGE" envDefault:"false"` PremiumBlog bool `env:"PREMIUM_BLOG" envDefault:"false"` Premium404 bool `env:"PREMIUM_404" envDefault:"false"` DisableMyUIbrix bool `env:"PREMIUM_DISABLE_MYUIBRIX" envDefault:"false"` PremiumAssetsPath string `env:"PREMIUM_ASSETS_PATH" envDefault:"./pro"` } func (c *Config) IsPremiumActive(pageType string) bool { if !c.PremiumMode { return false } switch pageType { case "homepage": return c.PremiumHomepage case "blog": return c.PremiumBlog case "404": return c.Premium404 default: return false } } ``` #### 2. Middleware Layer **File:** `internal/middleware/premium_mode.go` ```go func PremiumModeMiddleware(cfg *config.Config) gin.HandlerFunc { return func(c *gin.Context) { // Set premium context c.Set("premium_mode", cfg.PremiumMode) c.Set("disable_myuibrix", cfg.DisableMyUIbrix) // Add premium features to context premiumFeatures := map[string]bool{ "homepage": cfg.PremiumHomepage, "blog": cfg.PremiumBlog, "404": cfg.Premium404, } c.Set("premium_features", premiumFeatures) // Log premium mode status if cfg.PremiumMode { log.Debug("Premium mode active for request: %s", c.Request.URL.Path) } c.Next() } } ``` #### 3. Settings Extension **File:** `internal/models/settings.go` ```go type Settings struct { // Existing fields... PremiumModeActive bool `json:"premium_mode_active" gorm:"default:false"` PremiumFeatures string `json:"premium_features" gorm:"type:text"` // JSON PremiumThemeVariant string `json:"premium_theme_variant" gorm:"default:'default'"` } type PremiumFeatures struct { Homepage bool `json:"homepage"` Blog bool `json:"blog"` Error404 bool `json:"404"` } func (s *Settings) GetPremiumFeatures() (*PremiumFeatures, error) { if s.PremiumFeatures == "" { return &PremiumFeatures{}, nil } var features PremiumFeatures err := json.Unmarshal([]byte(s.PremiumFeatures), &features) return &features, err } ``` #### 4. Controller Extension **File:** `internal/controllers/base_controller.go` ```go func (ctrl *BaseController) GetPublicSettings(c *gin.Context) { settings, err := ctrl.DB.GetSettings() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } // Add premium mode info from environment cfg := config.GetConfig() settings.PremiumModeActive = cfg.PremiumMode if cfg.PremiumMode { features, _ := settings.GetPremiumFeatures() c.JSON(http.StatusOK, gin.H{ "settings": settings, "premium": gin.H{ "enabled": true, "features": features, "disable_myuibrix": cfg.DisableMyUIbrix, }, }) } else { c.JSON(http.StatusOK, gin.H{ "settings": settings, "premium": gin.H{ "enabled": false, }, }) } } ``` --- ### Frontend Components #### 1. Premium Layout System **File:** `frontend/src/layouts/PremiumLayout.tsx` ```typescript import React, { useEffect, useState } from 'react'; import { Helmet } from 'react-helmet'; import { loadPremiumAssets, cleanupPremiumAssets } from '../utils/premiumAssets'; interface PremiumLayoutProps { children: React.ReactNode; pageType: 'home' | 'blog' | '404'; settings?: any; } export const PremiumLayout: React.FC = ({ children, pageType, settings }) => { const [assetsLoaded, setAssetsLoaded] = useState(false); useEffect(() => { // Load premium assets loadPremiumAssets(pageType) .then(() => setAssetsLoaded(true)) .catch(err => console.error('Failed to load premium assets:', err)); // Cleanup on unmount return () => { cleanupPremiumAssets(); }; }, [pageType]); if (!assetsLoaded) { return
Loading premium theme...
; } return ( <>
{children}
); }; ``` #### 2. Asset Loader Utility **File:** `frontend/src/utils/premiumAssets.ts` ```typescript interface AssetConfig { css: string[]; js: string[]; fonts: string[]; } const assetConfig: Record = { home: { css: [ '/premium/css/bootstrap.css', '/premium/css/bizoni.css', '/premium/css/elementor-frontend.min.css', '/premium/css/zoom-slider.css', '/premium/css/swiper.css', '/premium/css/post-32647.css', ], js: [ '/premium/js/jquery.min.js', '/premium/js/jquery-migrate.min.js', '/premium/js/modernizr-2.6.2.min.js', '/premium/js/swiper.min.js', '/premium/js/jquery.zoomslider.js', '/premium/js/parallax-js.js', '/premium/js/script.js', '/premium/js/webpack.runtime.min.js', '/premium/js/frontend-modules.min.js', '/premium/js/frontend.min.js', ], fonts: [ 'https://fonts.googleapis.com/css?family=Open+Sans:400,400i,600,700|Sofia+Sans+Extra+Condensed:800,300i', 'https://fonts.googleapis.com/icon?family=Material+Icons', ], }, blog: { css: [ '/premium/css/bootstrap.css', '/premium/css/bizoni.css', '/premium/css/elementor-frontend.min.css', '/premium/css/post-29393.css', ], js: [ '/premium/js/jquery.min.js', '/premium/js/scripts.js', ], fonts: [], }, '404': { css: [ '/premium/css/bootstrap.css', '/premium/css/bizoni.css', ], js: [ '/premium/js/jquery.min.js', ], fonts: [], }, }; const loadedAssets: Set = new Set(); export const loadCSS = (href: string): Promise => { if (loadedAssets.has(href)) { return Promise.resolve(); } return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = href; link.onload = () => { loadedAssets.add(href); resolve(); }; link.onerror = () => reject(new Error(`Failed to load CSS: ${href}`)); document.head.appendChild(link); }); }; export const loadJS = (src: string): Promise => { if (loadedAssets.has(src)) { return Promise.resolve(); } return new Promise((resolve, reject) => { const script = document.createElement('script'); script.src = src; script.async = false; // Maintain load order script.onload = () => { loadedAssets.add(src); resolve(); }; script.onerror = () => reject(new Error(`Failed to load JS: ${src}`)); document.body.appendChild(script); }); }; export const loadPremiumAssets = async (pageType: string): Promise => { const config = assetConfig[pageType]; if (!config) { throw new Error(`Unknown page type: ${pageType}`); } try { // Load CSS first await Promise.all(config.css.map(loadCSS)); // Load fonts await Promise.all(config.fonts.map(loadCSS)); // Load JS in order for (const src of config.js) { await loadJS(src); } } catch (error) { console.error('Failed to load premium assets:', error); throw error; } }; export const cleanupPremiumAssets = (): void => { // Remove all premium CSS document.querySelectorAll('link[href^="/premium/"]').forEach(el => el.remove()); // Remove all premium JS document.querySelectorAll('script[src^="/premium/"]').forEach(el => el.remove()); // Clear loaded assets cache loadedAssets.clear(); }; ``` #### 3. Theme Hook **File:** `frontend/src/hooks/usePremiumTheme.ts` ```typescript import { useEffect } from 'react'; import { useSettings } from './useSettings'; export const usePremiumTheme = () => { const { settings } = useSettings(); useEffect(() => { if (!settings) return; const root = document.documentElement; // Inject club colors into premium CSS variables root.style.setProperty('--lte-main-color', settings.primary_color || '#e63946'); root.style.setProperty('--lte-secondary-color', settings.secondary_color || '#1d3557'); root.style.setProperty('--lte-text-on-primary', settings.text_on_primary || '#ffffff'); root.style.setProperty('--lte-text-on-secondary', settings.text_on_secondary || '#f1faee'); root.style.setProperty('--lte-accent-color', settings.accent_color || '#a8dadc'); // Typography root.style.setProperty('--lte-font-primary', "'Open Sans', sans-serif"); root.style.setProperty('--lte-font-display', "'Sofia Sans Extra Condensed', sans-serif"); // Cleanup return () => { root.style.removeProperty('--lte-main-color'); root.style.removeProperty('--lte-secondary-color'); // ... other cleanup }; }, [settings]); return { settings }; }; ``` #### 4. Routing Logic **File:** `frontend/src/App.tsx` ```typescript import { useSettings } from './hooks/useSettings'; import { PremiumHomePage } from './pages/PremiumHomePage'; import { PremiumBlogPage } from './pages/PremiumBlogPage'; import { PremiumNotFoundPage } from './pages/PremiumNotFoundPage'; import HomePage from './pages/HomePage'; import BlogPage from './pages/BlogPage'; import NotFoundPage from './pages/NotFoundPage'; const App: React.FC = () => { const { settings, isLoading } = useSettings(); if (isLoading) { return ; } const isPremiumMode = settings?.premium_mode_active; return ( {/* Conditional homepage */} : } /> {/* Conditional blog */} : } /> {/* Other routes stay standard */} } /> } /> {/* Conditional 404 */} : } /> ); }; ``` --- ## Data Flow ### 1. Standard Mode (PREMIUM_MODE=false) ``` Request → Backend → Settings API → Frontend → Render: HomePage → MyUIbrix: Enabled ``` ### 2. Premium Mode (PREMIUM_MODE=true) ``` Request → Backend → Settings API → Frontend → Check: premium_mode_active=true → Load: Premium Assets → Inject: Club Colors → Render: PremiumHomePage → MyUIbrix: Disabled ``` ### 3. Asset Loading Sequence ``` 1. React App Loads 2. Check Settings API 3. If Premium Mode: a. Load Core CSS (bootstrap, bizoni) b. Load Component CSS (zoom-slider, swiper) c. Load Fonts (Google Fonts) d. Load Core JS (jQuery, modernizr) e. Load Libraries (swiper, parallax) f. Load Elementor JS (webpack, frontend) g. Initialize Premium Components h. Inject Club Theme 4. Render Premium Page ``` --- ## Performance Optimization ### Code Splitting Strategy ```typescript // Lazy load premium components const PremiumHomePage = React.lazy(() => import('./pages/PremiumHomePage')); const PremiumBlogPage = React.lazy(() => import('./pages/PremiumBlogPage')); // Use Suspense for loading states }> ``` ### Asset Optimization 1. **CSS Minification**: All premium CSS files minified 2. **JS Bundle Splitting**: Separate bundles for homepage, blog, 404 3. **Image Lazy Loading**: Premium images load on scroll 4. **Font Subsetting**: Load only used glyphs 5. **Resource Hints**: Preload critical assets ### Caching Strategy ```nginx # Nginx configuration location /premium/ { expires 1y; add_header Cache-Control "public, immutable"; } ``` --- ## Security Considerations ### 1. Asset Isolation - Premium assets served from separate directory - No cross-contamination with standard mode ### 2. Feature Toggles - Environment-based (server-side control) - Cannot be manipulated by client ### 3. Content Security Policy ```typescript ``` --- ## Rollback Strategy ### Quick Rollback ```bash # Set environment variable PREMIUM_MODE=false # Restart backend docker-compose restart backend # Clear cache redis-cli FLUSHALL ``` ### Database Rollback ```sql -- Revert settings UPDATE settings SET premium_mode_active = FALSE; -- Run down migration migrate -path database/migrations -database "postgres://..." down 1 ``` --- ## Monitoring & Logging ### Key Metrics - Premium mode activation rate - Asset load times - Error rates (CSS/JS loading failures) - User engagement (premium vs standard) - Performance metrics (Lighthouse scores) ### Logging ```go log.Info("Premium mode activated", map[string]interface{}{ "user_id": userID, "page_type": pageType, "assets_loaded": len(loadedAssets), "load_time_ms": loadTime, }) ``` --- ## Migration Path ### Phase 1: Add Premium Support (No Breaking Changes) - Add environment variables - Extend Settings model - Create premium components - Keep standard mode as default ### Phase 2: Test Premium Mode (Opt-In) - Enable for specific users/teams - Collect feedback - Fix bugs - Optimize performance ### Phase 3: Production Rollout - Enable premium mode globally - Monitor metrics - Gradual migration - Keep rollback option ### Phase 4: Sunset Standard Mode (Optional) - After 3-6 months of stable premium operation - Remove MyUIbrix dependencies - Simplify codebase