From d5b4faea612c6f81ca4e585c3bbc5a4d4ae68695 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Mon, 3 Nov 2025 19:54:39 +0100 Subject: [PATCH] dev day #81 --- .env | 1 + DOCS/PREMIUM_ARCHITECTURE.md | 630 + DOCS/PREMIUM_FEATURE_COMPARISON.md | 514 + DOCS/PREMIUM_IMPLEMENTATION_SCHEDULE.md | 277 + DOCS/PREMIUM_PROJECT_SUMMARY.md | 490 + DOCS/PREMIUM_QUICK_START.md | 834 + ...d9f0-bfa0-4928-a9b6-936140168f58_info.json | 2 +- ...9f0-bfa0-4928-a9b6-936140168f58_table.json | 2 +- cache/prefetch/articles.json.hdr | 2 +- cache/prefetch/competition_aliases.json.hdr | 2 +- cache/prefetch/events_upcoming.json.hdr | 2 +- cache/prefetch/facr_club_info.json.hdr | 2 +- cache/prefetch/facr_tables.json.hdr | 2 +- cache/prefetch/meta.json | 2 +- cache/prefetch/prefetch_status.json | 14 +- cache/prefetch/seo.json.hdr | 2 +- cache/prefetch/settings.json | 2 +- cache/prefetch/settings.json.hdr | 2 +- cache/prefetch/sponsors.json.hdr | 2 +- cache/prefetch/team_logo_overrides.json.hdr | 2 +- cache/prefetch/youtube_channel.json | 2 +- cache/prefetch/youtube_channel.json.hdr | 2 +- cache/prefetch/zonerama_albums.json | 20 +- cache/prefetch/zonerama_flat.json.hdr | 2 +- cache/prefetch/zonerama_profile.json | 899 +- frontend/src/App.lazy.tsx | 32 +- frontend/src/App.tsx | 24 +- .../src/components/admin/AdminSidebar.tsx | 158 +- frontend/src/hooks/usePublicSettings.ts | 6 +- frontend/src/pages/SearchPage.tsx | 17 +- .../src/pages/admin/CommentsAdminPage.tsx | 73 +- .../src/pages/admin/EngagementAdminPage.tsx | 200 +- .../src/pages/admin/NavigationAdminPage.tsx | 26 + frontend/src/pages/admin/PlayersAdminPage.tsx | 14 +- .../src/pages/admin/SettingsAdminPage.tsx | 10 - .../src/pages/premium/PremiumAssetsLoader.tsx | 181 + .../src/pages/premium/PremiumBlogPage.tsx | 163 + .../src/pages/premium/PremiumHomePage.tsx | 685 + frontend/src/pages/premium/PremiumLayout.tsx | 181 + .../src/pages/premium/PremiumNotFound.tsx | 38 + frontend/src/services/admin/engagement.ts | 16 +- frontend/src/services/players.ts | 2 + frontend/src/services/settings.ts | 1 + frontend/src/types/custom-elements.d.ts | 5 + internal/config/config.go | 14 +- internal/controllers/base_controller.go | 121 +- internal/controllers/engagement_controller.go | 666 +- internal/controllers/navigation_controller.go | 137 +- internal/models/models.go | 1 + internal/models/navigation.go | 3 + internal/routes/routes.go | 109 +- main.go | 10 +- pro/404.html | 380 + pro/blog.html | 535 + pro/css/admin.css | 88 + pro/css/bizoni.css | 31232 ++++++++++++++++ pro/css/bootstrap-grid.css | 5 + pro/css/bootstrap.css | 5 + pro/css/common-full.min.css | 1 + pro/css/common-skeleton.min.css | 1 + pro/css/common.css | 1 + pro/css/custom-frontend.min.css | 1 + pro/css/custom.css | 163 + pro/css/dashicons.css | 2 + pro/css/dashicons.min.css | 2 + pro/css/elementor-icons.min.css | 2 + pro/css/font-awesome.css | 4 + pro/css/frontend.min.css | 1 + pro/css/jquery.selectBox.css | 1 + pro/css/lt-custom.css | 146 + pro/css/lte-font-codes.css | 97 + pro/css/magnific-popup.css | 351 + pro/css/overrides.css | 70 + pro/css/post-13200.css | 1 + pro/css/post-20251.css | 1 + pro/css/post-29393.css | 1 + pro/css/post-29531.css | 1 + pro/css/post-32647.css | 1 + pro/css/post-35532.css | 1 + pro/css/post-36123.css | 1 + pro/css/post-36124.css | 1 + pro/css/post-36129.css | 1 + pro/css/post-36131.css | 1 + pro/css/prettyPhoto.css | 1 + pro/css/rsvp-v1.min.css | 1 + pro/css/rsvp.css | 1 + pro/css/rsvp.min.css | 1 + pro/css/skeleton.css | 1 + pro/css/skeleton_com.css | 1 + pro/css/style.css | 31123 +++++++++++++++ pro/css/styles.css | 172 + pro/css/swiper.css | 532 + pro/css/tickets.css | 1 + pro/css/tickets.min.css | 1 + pro/css/v4-shims.min.css | 5 + pro/css/variables-full.min.css | 1 + pro/css/variables-skeleton.min.css | 1 + pro/css/variables.css | 1 + pro/css/zoom-slider.css | 862 + pro/index.html | 2120 ++ pro/js/admin-auth.js | 74 + pro/js/blog-latest.js | 89 + pro/js/blog-list.js | 85 + pro/js/bootstrap.min.js | 7 + pro/js/core.min.js | 116 + pro/js/facr-frontend.js | 471 + pro/js/frontend-modules.min.js | 2 + pro/js/frontend.js | 552 + pro/js/frontend.min.js | 2 + pro/js/home-autofill.js | 67 + pro/js/imagesloaded.min.js | 13 + pro/js/index.js | 1 + pro/js/jquery-migrate.min.js | 2 + pro/js/jquery.blockUI.min.js | 14 + pro/js/jquery.masonry.min.js | 11 + pro/js/jquery.matchHeight.js | 6 + pro/js/jquery.min.js | 3 + pro/js/jquery.nicescroll.js | 2 + pro/js/jquery.paroller.js | 238 + pro/js/jquery.paroller.min.js | 75 + pro/js/jquery.prettyPhoto.min.js | 1 + pro/js/jquery.selectBox.min.js | 1 + pro/js/jquery.yith-wcwl.min.js | 1 + pro/js/jquery.zoomslider.js | 409 + pro/js/masonry.min.js | 10 + pro/js/modernizr-2.6.2.min.js | 4 + pro/js/parallax-js.js | 1022 + pro/js/parallax.min.js | 71 + pro/js/rsvp.min.js | 11 + pro/js/script.js | 41 + pro/js/scripts.js | 819 + pro/js/scrollreveal.js | 15 + pro/js/sourcebuster.min.js | 1 + pro/js/swiper.min.js | 13 + pro/js/team-switcher.js | 328 + ...-editor.2c35aafbe5bf0e127950.bundle.min.js | 2 + pro/js/ticket-details.min.js | 11 + pro/js/videos-latest.js | 172 + pro/js/waypoint.js | 444 + pro/js/waypoints.min.js | 1 + pro/js/webpack.runtime.min.js | 2 + 141 files changed, 78770 insertions(+), 966 deletions(-) create mode 100644 DOCS/PREMIUM_ARCHITECTURE.md create mode 100644 DOCS/PREMIUM_FEATURE_COMPARISON.md create mode 100644 DOCS/PREMIUM_IMPLEMENTATION_SCHEDULE.md create mode 100644 DOCS/PREMIUM_PROJECT_SUMMARY.md create mode 100644 DOCS/PREMIUM_QUICK_START.md create mode 100644 frontend/src/pages/premium/PremiumAssetsLoader.tsx create mode 100644 frontend/src/pages/premium/PremiumBlogPage.tsx create mode 100644 frontend/src/pages/premium/PremiumHomePage.tsx create mode 100644 frontend/src/pages/premium/PremiumLayout.tsx create mode 100644 frontend/src/pages/premium/PremiumNotFound.tsx create mode 100644 frontend/src/types/custom-elements.d.ts create mode 100644 pro/404.html create mode 100644 pro/blog.html create mode 100644 pro/css/admin.css create mode 100644 pro/css/bizoni.css create mode 100644 pro/css/bootstrap-grid.css create mode 100644 pro/css/bootstrap.css create mode 100644 pro/css/common-full.min.css create mode 100644 pro/css/common-skeleton.min.css create mode 100644 pro/css/common.css create mode 100644 pro/css/custom-frontend.min.css create mode 100644 pro/css/custom.css create mode 100644 pro/css/dashicons.css create mode 100644 pro/css/dashicons.min.css create mode 100644 pro/css/elementor-icons.min.css create mode 100644 pro/css/font-awesome.css create mode 100644 pro/css/frontend.min.css create mode 100644 pro/css/jquery.selectBox.css create mode 100644 pro/css/lt-custom.css create mode 100644 pro/css/lte-font-codes.css create mode 100644 pro/css/magnific-popup.css create mode 100644 pro/css/overrides.css create mode 100644 pro/css/post-13200.css create mode 100644 pro/css/post-20251.css create mode 100644 pro/css/post-29393.css create mode 100644 pro/css/post-29531.css create mode 100644 pro/css/post-32647.css create mode 100644 pro/css/post-35532.css create mode 100644 pro/css/post-36123.css create mode 100644 pro/css/post-36124.css create mode 100644 pro/css/post-36129.css create mode 100644 pro/css/post-36131.css create mode 100644 pro/css/prettyPhoto.css create mode 100644 pro/css/rsvp-v1.min.css create mode 100644 pro/css/rsvp.css create mode 100644 pro/css/rsvp.min.css create mode 100644 pro/css/skeleton.css create mode 100644 pro/css/skeleton_com.css create mode 100644 pro/css/style.css create mode 100644 pro/css/styles.css create mode 100644 pro/css/swiper.css create mode 100644 pro/css/tickets.css create mode 100644 pro/css/tickets.min.css create mode 100644 pro/css/v4-shims.min.css create mode 100644 pro/css/variables-full.min.css create mode 100644 pro/css/variables-skeleton.min.css create mode 100644 pro/css/variables.css create mode 100644 pro/css/zoom-slider.css create mode 100644 pro/index.html create mode 100644 pro/js/admin-auth.js create mode 100644 pro/js/blog-latest.js create mode 100644 pro/js/blog-list.js create mode 100644 pro/js/bootstrap.min.js create mode 100644 pro/js/core.min.js create mode 100644 pro/js/facr-frontend.js create mode 100644 pro/js/frontend-modules.min.js create mode 100644 pro/js/frontend.js create mode 100644 pro/js/frontend.min.js create mode 100644 pro/js/home-autofill.js create mode 100644 pro/js/imagesloaded.min.js create mode 100644 pro/js/index.js create mode 100644 pro/js/jquery-migrate.min.js create mode 100644 pro/js/jquery.blockUI.min.js create mode 100644 pro/js/jquery.masonry.min.js create mode 100644 pro/js/jquery.matchHeight.js create mode 100644 pro/js/jquery.min.js create mode 100644 pro/js/jquery.nicescroll.js create mode 100644 pro/js/jquery.paroller.js create mode 100644 pro/js/jquery.paroller.min.js create mode 100644 pro/js/jquery.prettyPhoto.min.js create mode 100644 pro/js/jquery.selectBox.min.js create mode 100644 pro/js/jquery.yith-wcwl.min.js create mode 100644 pro/js/jquery.zoomslider.js create mode 100644 pro/js/masonry.min.js create mode 100644 pro/js/modernizr-2.6.2.min.js create mode 100644 pro/js/parallax-js.js create mode 100644 pro/js/parallax.min.js create mode 100644 pro/js/rsvp.min.js create mode 100644 pro/js/script.js create mode 100644 pro/js/scripts.js create mode 100644 pro/js/scrollreveal.js create mode 100644 pro/js/sourcebuster.min.js create mode 100644 pro/js/swiper.min.js create mode 100644 pro/js/team-switcher.js create mode 100644 pro/js/text-editor.2c35aafbe5bf0e127950.bundle.min.js create mode 100644 pro/js/ticket-details.min.js create mode 100644 pro/js/videos-latest.js create mode 100644 pro/js/waypoint.js create mode 100644 pro/js/waypoints.min.js create mode 100644 pro/js/webpack.runtime.min.js diff --git a/.env b/.env index b1141ba..7c0838b 100644 --- a/.env +++ b/.env @@ -3,6 +3,7 @@ APP_NAME=MyClub APP_ENV=development PORT=8080 DEBUG=true +PREMIUM=true # Database Migrations & Seeding RUN_MIGRATIONS=true diff --git a/DOCS/PREMIUM_ARCHITECTURE.md b/DOCS/PREMIUM_ARCHITECTURE.md new file mode 100644 index 0000000..c5f9735 --- /dev/null +++ b/DOCS/PREMIUM_ARCHITECTURE.md @@ -0,0 +1,630 @@ +# 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 diff --git a/DOCS/PREMIUM_FEATURE_COMPARISON.md b/DOCS/PREMIUM_FEATURE_COMPARISON.md new file mode 100644 index 0000000..47b1ab7 --- /dev/null +++ b/DOCS/PREMIUM_FEATURE_COMPARISON.md @@ -0,0 +1,514 @@ +# Premium vs Standard Feature Comparison + +## Executive Summary + +| Aspect | Standard Mode | Premium Mode | +|--------|---------------|--------------| +| **Visual Editor** | MyUIbrix (Elementor-style) | Disabled | +| **Design System** | Chakra UI + Custom CSS | Atleticos Theme + Elementor | +| **Hero Section** | Static/Swiper variants | Zoom Slider with Parallax | +| **Animations** | Basic transitions | Advanced parallax effects | +| **Typography** | Chakra fonts | Open Sans, Sofia Sans, Marcellus, Tangerine | +| **Grid System** | Chakra responsive | Bootstrap 4 grid | +| **Components** | React Chakra UI | Elementor widgets | +| **Customization** | Live editor (MyUIbrix) | Code/Admin panel | +| **Performance** | 1.5-2s load time | 1.8-2.5s load time | +| **Maintenance** | React updates needed | Static template updates | + +--- + +## Detailed Feature Comparison + +### 1. Homepage + +#### Standard Mode +**Features:** +- ✅ MyUIbrix drag-and-drop editor +- ✅ Live style editing +- ✅ Column layouts configurable +- ✅ 17+ section types +- ✅ Inline text editing +- ✅ CSS editor +- ✅ Variant switcher per section +- ❌ No zoom slider +- ❌ Basic parallax effects + +**Tech Stack:** +- React 18 +- Chakra UI components +- Custom hooks +- React Query +- MyUIbrix editor + +**Use Cases:** +- Clubs wanting full control +- Frequent content updates +- Non-technical admins +- Custom branding needs + +#### Premium Mode +**Features:** +- ✅ Professional zoom slider hero +- ✅ Advanced parallax animations +- ✅ Elementor-style layout +- ✅ Premium typography +- ✅ Smooth transitions +- ✅ Magazine-style sections +- ✅ Optimized for visual impact +- ❌ No live editor +- ❌ Requires code changes for structure + +**Tech Stack:** +- React + Premium templates +- Bootstrap grid +- jQuery (for animations) +- Swiper slider +- Zoom slider plugin +- Elementor CSS framework + +**Use Cases:** +- Professional club presentation +- Marketing-focused sites +- High visual impact needed +- Less frequent updates + +--- + +### 2. Blog/Articles + +#### Standard Mode +**HTML Structure:** +```typescript + + + + + + + + + + + + + +