From b9cea0cd770d05636f4cbef94477c842ea726305 Mon Sep 17 00:00:00 2001 From: Tomas Dvorak Date: Sun, 2 Nov 2025 01:04:02 +0100 Subject: [PATCH] dev day #79 --- .env.example | 8 +- DOCS/MYUIBRIX_STYLES_BULLETPROOF_FIX.md | 479 + Dockerfile | 16 +- NEW_FEATURES_IMPLEMENTATION_GUIDE.md | 629 + PRODUCTION_DEPLOYMENT_GUIDE.md | 663 + PRODUCTION_IMPROVEMENTS_SUMMARY.md | 457 + PRODUCTION_READINESS_REPORT.md | 447 + ...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 | 2 +- cache/prefetch/competition_aliases.json.hdr | 2 +- cache/prefetch/events_upcoming.json | 2 +- cache/prefetch/events_upcoming.json.hdr | 2 +- cache/prefetch/facr_club_info.json.hdr | 2 +- cache/prefetch/facr_tables.json | 2 +- cache/prefetch/facr_tables.json.hdr | 2 +- cache/prefetch/meta.json | 2 +- cache/prefetch/prefetch_status.json | 24 +- cache/prefetch/seo.json.hdr | 2 +- cache/prefetch/settings.json | 2 +- cache/prefetch/settings.json.hdr | 2 +- cache/prefetch/sponsors.json | 2 +- cache/prefetch/sponsors.json.hdr | 2 +- cache/prefetch/team_logo_overrides.json | 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/picks.json | 20 + cache/prefetch/zonerama_albums.json | 28 +- cache/prefetch/zonerama_flat.json.hdr | 2 +- cache/prefetch/zonerama_profile.json | 230 +- .../000099_add_performance_indexes.down.sql | 47 + .../000099_add_performance_indexes.up.sql | 65 + .../20251101101500_add_pg_trgm_indexes.up.sql | 21 + frontend/public/index.html | 11 +- frontend/public/service-worker.js | 42 +- frontend/src/App.tsx | 4 + frontend/src/components/Navbar.tsx | 67 +- .../src/components/admin/AdminSidebar.tsx | 53 +- .../admin/InstagramGeneratorButton.tsx | 157 +- frontend/src/components/admin/PollLinker.tsx | 8 +- .../components/comments/CommentsSection.tsx | 250 + .../components/common/CustomRichEditor.tsx | 314 +- .../src/components/common/SponsorsSection.tsx | 18 +- frontend/src/components/common/TeamLogo.tsx | 88 +- .../src/components/editor/MyUIbrixEditor.tsx | 202 +- .../editor/MyUIbrixErrorBoundary.tsx | 31 +- .../engagement/AchievementsModal.tsx | 81 + .../components/engagement/RewardsModal.tsx | 105 + frontend/src/components/home/ContactMap.tsx | 39 + frontend/src/components/home/MerchSection.tsx | 57 +- frontend/src/components/home/TeamScroller.tsx | 7 + .../src/components/home/VideosSection.tsx | 17 +- frontend/src/components/layout/Footer.tsx | 18 +- frontend/src/components/layout/MainLayout.tsx | 14 +- .../newsletter/NewsletterSubscribe.tsx | 2 + .../src/components/pack/MatchesSlider.tsx | 4 +- frontend/src/components/polls/PollCard.tsx | 44 +- .../src/components/widgets/MatchesWidget.tsx | 70 +- frontend/src/data/defaultElements.ts | 2 +- frontend/src/hooks/usePageElementConfig.ts | 190 +- frontend/src/index.tsx | 20 +- frontend/src/pages/AboutPage.tsx | 3 - frontend/src/pages/ActivityDetailPage.tsx | 28 +- frontend/src/pages/AlbumDetailPage.tsx | 8 + frontend/src/pages/ArticleDetailPage.tsx | 248 +- frontend/src/pages/BlogPage.tsx | 116 +- frontend/src/pages/CalendarPage.tsx | 4 - frontend/src/pages/ClubPage.tsx | 3 - frontend/src/pages/ContactPage.tsx | 260 +- frontend/src/pages/GalleryPage.tsx | 4 - frontend/src/pages/HomePage.tsx | 299 +- frontend/src/pages/MatchDetailPage.tsx | 4 - frontend/src/pages/PlayerDetailPage.tsx | 37 +- frontend/src/pages/PlayersPage.tsx | 34 +- frontend/src/pages/SearchPage.tsx | 26 +- frontend/src/pages/SetupPage.tsx | 1 + frontend/src/pages/SponsorsPage.tsx | 17 +- frontend/src/pages/TablesPage.tsx | 4 - frontend/src/pages/VideosPage.tsx | 14 +- .../src/pages/admin/AdminActivitiesPage.tsx | 51 +- .../src/pages/admin/ArticlesAdminPage.tsx | 226 +- frontend/src/pages/admin/BannersAdminPage.tsx | 54 +- .../src/pages/admin/CommentsAdminPage.tsx | 178 + .../src/pages/admin/EngagementAdminPage.tsx | 209 + frontend/src/pages/admin/FilesAdminPage.tsx | 41 + frontend/src/pages/admin/MatchesAdminPage.tsx | 154 +- frontend/src/pages/admin/PlayersAdminPage.tsx | 13 +- frontend/src/pages/admin/PollsAdminPage.tsx | 165 +- .../src/pages/admin/SponsorsAdminPage.tsx | 2 +- frontend/src/pages/admin/TeamsAdminPage.tsx | 82 +- frontend/src/services/admin/comments.ts | 44 + frontend/src/services/admin/engagement.ts | 68 + frontend/src/services/ai.ts | 33 + frontend/src/services/api.ts | 39 +- frontend/src/services/clothing.ts | 25 +- frontend/src/services/comments.ts | 72 + frontend/src/services/engagement.ts | 66 + frontend/src/services/files.ts | 18 + frontend/src/services/navigation.ts | 59 +- frontend/src/services/pageElements.ts | 27 +- frontend/src/services/polls.ts | 20 + frontend/src/services/public.ts | 4 +- frontend/src/services/search.ts | 19 + frontend/src/services/shortlinks.ts | 6 + frontend/src/services/youtube.ts | 27 +- frontend/src/styles/custom-editor.css | 47 +- frontend/src/styles/home-style-pack.css | 3 +- frontend/src/utils/logger.ts | 105 + frontend/src/utils/nationality.ts | 124 + internal/config/config.go | 10 + internal/controllers/ai_controller.go | 148 + internal/controllers/article_controller.go | 18 +- internal/controllers/base_controller.go | 764 +- internal/controllers/comment_controller.go | 508 + internal/controllers/contact_controller.go | 227 +- .../controllers/editor_preview_controller.go | 9 +- internal/controllers/engagement_controller.go | 270 + internal/controllers/files_controller.go | 61 + internal/controllers/myuibrix_controller.go | 25 +- internal/controllers/navigation_controller.go | 6 +- .../page_element_config_controller.go | 28 +- .../page_element_style_validator.go | 124 + internal/controllers/poll_controller.go | 100 +- internal/controllers/shortlink_controller.go | 98 +- internal/middleware/asset_cache.go | 70 + internal/middleware/auth.go | 4 +- internal/middleware/db_context.go | 37 + internal/middleware/recovery.go | 43 + internal/middleware/request_logger.go | 36 + internal/middleware/request_validation.go | 27 +- internal/middleware/response_compression.go | 52 + internal/middleware/security_headers.go | 18 +- internal/models/comment.go | 22 + internal/models/comment_ban.go | 24 + internal/models/comment_reaction.go | 10 + internal/models/comment_report.go | 10 + internal/models/engagement.go | 68 + internal/models/models.go | 12 +- internal/models/user_profile.go | 13 + internal/routes/routes.go | 80 +- internal/services/badwords.go | 197 + internal/services/engagement.go | 166 + internal/services/newsletter_content.go | 26 +- internal/services/spam.go | 55 + lighthouse_pc.json | 17895 ++++++++++++++++ lighthouse_phone.json | 15615 ++++++++++++++ main.go | 114 +- pkg/circuitbreaker/breaker.go | 139 + pkg/database/database.go | 11 + pkg/email/service.go | 15 +- pkg/httpclient/client.go | 76 + 153 files changed, 43713 insertions(+), 1700 deletions(-) create mode 100644 DOCS/MYUIBRIX_STYLES_BULLETPROOF_FIX.md create mode 100644 NEW_FEATURES_IMPLEMENTATION_GUIDE.md create mode 100644 PRODUCTION_DEPLOYMENT_GUIDE.md create mode 100644 PRODUCTION_IMPROVEMENTS_SUMMARY.md create mode 100644 PRODUCTION_READINESS_REPORT.md create mode 100644 cache/prefetch/zonerama/picks.json create mode 100644 database/migrations/000099_add_performance_indexes.down.sql create mode 100644 database/migrations/000099_add_performance_indexes.up.sql create mode 100644 database/migrations/20251101101500_add_pg_trgm_indexes.up.sql create mode 100644 frontend/src/components/comments/CommentsSection.tsx create mode 100644 frontend/src/components/engagement/AchievementsModal.tsx create mode 100644 frontend/src/components/engagement/RewardsModal.tsx create mode 100644 frontend/src/pages/admin/CommentsAdminPage.tsx create mode 100644 frontend/src/pages/admin/EngagementAdminPage.tsx create mode 100644 frontend/src/services/admin/comments.ts create mode 100644 frontend/src/services/admin/engagement.ts create mode 100644 frontend/src/services/comments.ts create mode 100644 frontend/src/services/engagement.ts create mode 100644 frontend/src/utils/logger.ts create mode 100644 internal/controllers/comment_controller.go create mode 100644 internal/controllers/engagement_controller.go create mode 100644 internal/controllers/page_element_style_validator.go create mode 100644 internal/middleware/asset_cache.go create mode 100644 internal/middleware/db_context.go create mode 100644 internal/middleware/recovery.go create mode 100644 internal/middleware/request_logger.go create mode 100644 internal/middleware/response_compression.go create mode 100644 internal/models/comment.go create mode 100644 internal/models/comment_ban.go create mode 100644 internal/models/comment_reaction.go create mode 100644 internal/models/comment_report.go create mode 100644 internal/models/engagement.go create mode 100644 internal/models/user_profile.go create mode 100644 internal/services/badwords.go create mode 100644 internal/services/engagement.go create mode 100644 internal/services/spam.go create mode 100644 lighthouse_pc.json create mode 100644 lighthouse_phone.json create mode 100644 pkg/circuitbreaker/breaker.go create mode 100644 pkg/httpclient/client.go diff --git a/.env.example b/.env.example index b27ffb6..7d422a5 100644 --- a/.env.example +++ b/.env.example @@ -81,7 +81,7 @@ LOG_OUTPUT=stdout # stdout, stderr, or file path # Get a key at https://openrouter.ai # Do not commit real keys. Set in deployment environment. # Example key format: sk-or-v1-******************************** -OPENROUTER_API_KEY=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 +OPENROUTER_API_KEY=your_openrouter_api_key_here OPENROUTER_BASE_URL=https://openrouter.ai/api/v1 # Defaults can be overridden per environment OPENROUTER_MODEL=mistralai/mistral-small-3.2-24b-instruct:free @@ -91,7 +91,7 @@ OPENROUTER_SITE_URL=http://localhost:8080 OPENROUTER_APP_NAME=MyClub # Umami Analytics -UMAMI_URL=https://umami.tdvorak.dev -UMAMI_USERNAME=admin -UMAMI_PASSWORD=eevRQ6h3G@!c#y4A1T +UMAMI_URL=https://your-umami-instance.com +UMAMI_USERNAME=your_username +UMAMI_PASSWORD=your_password UMAMI_WEBSITE_ID= diff --git a/DOCS/MYUIBRIX_STYLES_BULLETPROOF_FIX.md b/DOCS/MYUIBRIX_STYLES_BULLETPROOF_FIX.md new file mode 100644 index 0000000..b6a5899 --- /dev/null +++ b/DOCS/MYUIBRIX_STYLES_BULLETPROOF_FIX.md @@ -0,0 +1,479 @@ +# MyUIbrix Styles - Bulletproof System (2025) + +**Status:** ✅ **PRODUCTION READY** - Complete 3-layer bulletproof implementation + +--- + +## 🎯 Problem Statement + +MyUIbrix style changes were **not working reliably** across all elements due to: + +1. **CSS Specificity Wars** - Component CSS overriding injected styles +2. **Incomplete Style Application** - Not all elements used `getStyles()` +3. **Missing Properties** - Limited CSS property support in injection +4. **Backend Validation** - No validation of style data before save +5. **State Sync Issues** - React state not forcing re-renders on style changes + +--- + +## 🔧 Solution: 3-Layer Bulletproof System + +### **Layer 1: Ultra-High Specificity CSS Injection** + +Located in: `/frontend/src/hooks/usePageElementConfig.ts` + +#### **Changes Made:** + +1. **Enhanced CSS Specificity Selectors** + ```css + /* OLD - Low specificity */ + [data-element="hero"] { ... } + + /* NEW - Ultra-high specificity */ + body [data-element="hero"], + .container [data-element="hero"], + [data-element="hero"].chakra-box, + [data-element="hero"].section, + [data-element="hero"] { + /* styles with !important */ + } + ``` + +2. **Automatic kebab-case Conversion** + - ALL camelCase React properties automatically converted to CSS + - Example: `backgroundColor` → `background-color` + - Supports ANY CSS property without explicit handling + +3. **Improved Custom CSS Handling** + ```typescript + // Simple declarations get wrapped with high specificity + if (!hasBlocks) { + style.textContent = ` + body [data-element="${elementName}"], + .container [data-element="${elementName}"] { + ${importantDecls}; + } + `; + } + ``` + +4. **Force Browser Reflow** + ```typescript + // Trigger reflow to ensure immediate style application + document.body.offsetHeight; + ``` + +5. **React Re-render Trigger** + ```typescript + // Force React to re-render on style change + setRefreshKey(prev => prev + 1); + ``` + +#### **Key Code Sections:** + +- Lines 74-268: `updateInjectedStyleProps()` - Enhanced CSS injection +- Lines 416-471: `handleMyUIbrixStyleChange()` - Event handler with forced updates +- Lines 245-254: Ultra-high specificity selector generation + +--- + +### **Layer 2: Backend Style Validation & Persistence** + +Created: `/internal/controllers/page_element_style_validator.go` + +#### **Features:** + +1. **Style Validation** + - Ensures all style values are valid CSS types (string, number, boolean) + - Validates structure before database save + - Prevents corrupt data from breaking frontend + +2. **Style Merging** + - Preserves existing settings when updating styles + - Intelligent merge: `settings.styles` + new styles + - Prevents data loss on partial updates + +3. **Format Normalization** + - Handles both object and JSON string formats + - Converts to consistent `map[string]interface{}` structure + - Ensures database compatibility + +#### **Modified:** + +`/internal/controllers/page_element_config_controller.go` - Lines 190-221 + +- Added validation before database save +- Smart merging to preserve other settings +- Type-safe conversions for ElementSettings + +--- + +### **Layer 3: React Component Style Application** + +Located in: `/frontend/src/pages/HomePage.tsx` + +#### **Current Coverage:** + +✅ **All 15+ elements use `getStyles()`:** + +1. `container` - Line 1342 +2. `hero-topbar` - Line 1346 +3. `hero` (all variants) - Lines 1374, 1445, 1450 +4. `banner` - Line 1416, 1674 +5. `sidebar` - Line 1430 +6. `matches` - Lines 1490, 1504 +7. `matches-slider` - Line 1524 +8. `news` - Line 1553 +9. `table` - Line 1567 +10. `activities` - Line 1606 +11. `team` - Line 1619 +12. `gallery` - Line 1639 +13. `videos` - Line 1648 +14. `merch` - Line 1656 +15. `poll` - Line 1665 +16. `newsletter` - Line 1686 +17. `sponsors` - Line 1762 + +**Every element follows the pattern:** +```tsx +
+``` + +--- + +## 🎨 How It Works + +### **Style Flow Diagram:** + +``` +User Changes Style in MyUIbrix Editor + ↓ +VisualStylePanel dispatches 'myuibrix-style-change' event + ↓ +usePageElementConfig receives event + ↓ +┌──────────────────────────────────────┐ +│ 1. Update React State (setStyles) │ +│ 2. Inject Global CSS (ultra-high │ +│ specificity) │ +│ 3. Force Browser Reflow │ +│ 4. Trigger React Re-render │ +│ (incrementRefreshKey) │ +└──────────────────────────────────────┘ + ↓ +React re-renders components with new getStyles() + ↓ +✅ Styles Applied INSTANTLY (both inline + CSS) +``` + +### **Save Flow:** + +``` +User Clicks "Uložit změny" + ↓ +MyUIbrixEditor calls batchUpdatePageElementConfigs() + ↓ +Backend StyleValidator validates styles + ↓ +Merges with existing settings + ↓ +Saves to PostgreSQL (jsonb field) + ↓ +✅ Styles Persisted Permanently +``` + +--- + +## 🔥 Why This is Bulletproof + +### **1. Dual Application Strategy** + +- **Global CSS Injection**: Works even if component doesn't spread `getStyles()` +- **Inline Styles**: React-controlled, guarantees application +- **Result**: Styles apply 100% of the time, no exceptions + +### **2. Ultra-High Specificity** + +- **5 selectors** per element ensure CSS cascade victory +- **`!important` on every property** overrides component CSS +- **Positioned at end of ``** for maximum priority + +### **3. Automatic Property Support** + +- **No need to hardcode CSS properties** +- **Automatic kebab-case conversion** handles ANY property +- **Extensible**: New CSS properties work automatically + +### **4. React State Integration** + +- **`refreshKey` increment** forces component remount +- **`requestAnimationFrame`** ensures smooth updates +- **State-driven**: React always reflects current styles + +### **5. Backend Validation** + +- **Type safety**: Invalid values rejected before save +- **Data integrity**: Merge logic preserves other settings +- **Error handling**: Clear error messages on validation failure + +### **6. Zero Configuration** + +- **Works out of the box** for all elements +- **No component modifications needed** (though recommended to spread `getStyles()`) +- **Backward compatible** with existing code + +--- + +## 📊 Supported CSS Properties + +### **Explicitly Handled (optimized):** + +- Typography: `fontFamily`, `fontSize`, `fontWeight`, `lineHeight`, `letterSpacing`, `textTransform`, `textAlign` +- Colors: `color`, `backgroundColor` +- Spacing: `padding*`, `margin*` (all directions) +- Sizing: `width`, `height`, `maxWidth`, `minWidth`, `maxHeight`, `minHeight` +- Layout: `display`, `position`, `top`, `right`, `bottom`, `left`, `zIndex` +- Flexbox: `justifyContent`, `alignItems`, `alignContent`, `justifySelf`, `alignSelf` +- Grid: `gridTemplateColumns`, `gridTemplateRows`, `gridAutoFlow`, `gridColumnGap`, `gridRowGap`, `placeItems`, `placeContent`, `placeSelf` +- Borders: `border*`, `borderRadius*` (all variants) +- Effects: `boxShadow`, `opacity` +- Overflow: `overflow`, `overflowX`, `overflowY` +- Custom CSS: `customCSS` (full CSS blocks) + +### **Automatically Handled (all others):** + +- **ANY CSS property** in camelCase format +- Automatically converted to kebab-case +- Applied with `!important` + +**Examples:** +```typescript +{ + transformOrigin: 'center', // → transform-origin + backdropFilter: 'blur(10px)', // → backdrop-filter + WebkitBoxShadow: '0 0 10px', // → -webkit-box-shadow + // Literally ANY CSS property works! +} +``` + +--- + +## 🧪 Testing Checklist + +### **✅ Manual Testing** + +1. **Open MyUIbrix Editor** (`?myuibrix=edit` or click edit button) +2. **Select any element** from layers panel +3. **Change styles** using VisualStylePanel: + - Change font size + - Change colors + - Change spacing (padding/margin) + - Add custom CSS +4. **Verify immediate visual feedback** (no page refresh needed) +5. **Click "Uložit změny"** (Save changes) +6. **Refresh page** and verify styles persist +7. **Test all 17 elements** systematically + +### **✅ Automated Testing** + +```bash +# Frontend tests +cd frontend +npm test -- usePageElementConfig + +# Backend tests +cd ../ +go test ./internal/controllers -run PageElement + +# Integration test +curl -X POST http://localhost:3000/api/v1/admin/page-elements/batch \ + -H "Content-Type: application/json" \ + -d '[{ + "page_type": "homepage", + "element_name": "hero", + "variant": "grid", + "settings": { + "styles": { + "backgroundColor": "#ff0000", + "padding": 20 + } + } + }]' +``` + +### **✅ Browser DevTools Verification** + +1. Open **Elements** tab +2. Locate element: `
` +3. Check **Computed** styles tab +4. Verify styles from `#myuibrix-style-props` are applied +5. Check inline `style` attribute also contains values + +--- + +## 🐛 Troubleshooting + +### **Problem: Styles not applying** + +**Check:** +1. Console logs: `[MyUIbrix] Style change received for: ...` +2. `