diff --git a/CLAUDE.md b/CLAUDE.md index a34fee8..ca1ca07 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -660,7 +660,7 @@ Six specialized checks for Amazon marketing asset compliance. Originally based o | `amazon_typography` | Ember Modern Standard Display font, size ratios, leading/tracking, ligatures, **headline-to-date spacing** (cramped = fail) | | `amazon_headline_layout` | Left-aligned, largest element, natural line splits. Prepositions at line end ("di", "of") are acceptable. One word per line OK in tall formats | | `amazon_margins` | Visual margin assessment (not pixel-level). Headline breathing room from edges. **Left alignment consistency** between headline, date, and logo/branding | -| `amazon_box_placement` | Box position (right for landscape, centre OK for portrait). **Tape/flaps** = branded coloured strips on box edges — must not be cropped by asset edge | +| `amazon_element_placement` | Element placement (box, bag, logo). Box position (right for landscape, centre OK for portrait). **Tape/flaps** = branded coloured strips on box edges — must not be cropped by asset edge | #### Amazon Prompt Tuning History (2026-03-30) Prompts were refined based on testing with 9 assets (5 correct, 4 incorrect with known single defects): @@ -677,7 +677,7 @@ Prompts were refined based on testing with 9 assets (5 correct, 4 incorrect with | IE_BrightSide_576x1152 copy | Headline too large/close to left edge, not aligned with logo | Headline scaled down for proper margins and left-alignment | **Key prompt refinements made**: -1. **Box Placement**: Tape described as branded coloured strips (not plain packing tape). Format-aware positioning (centre OK for portrait). Only fail tape if cropped by asset edge. +1. **Element Placement**: Tape described as branded coloured strips (not plain packing tape). Format-aware positioning (centre OK for portrait). Only fail tape if cropped by asset edge. 2. **Required Elements**: Subhead demoted to optional. OOH/DOOH formats don't need separate subhead. 3. **Logo Country**: Country/language match is the primary scoring factor. Logo colour is secondary. 4. **Margins**: Visual assessment approach (not pixel calculations). Added left-alignment consistency check between headline and logo. diff --git a/backend/CLAUDE.md b/backend/CLAUDE.md index 92d61ae..2d99873 100644 --- a/backend/CLAUDE.md +++ b/backend/CLAUDE.md @@ -610,7 +610,7 @@ Six specialized checks for Amazon Sale Day design compliance, with guidelines fr | `amazon_typography` | Ember Modern Standard Display font, leading/tracking, size ratios (subhead 30-60%, date 20-45%), ligatures | | `amazon_headline_layout` | Headline left-aligned, largest element, natural line splits | | `amazon_margins` | 7% shortest side (10% wide, 20%/10% very wide+small formats) | -| `amazon_box_placement` | Box on right side, cropping rules (tape NEVER cropped) | +| `amazon_element_placement` | Element placement (box, bag, logo), positioning rules, cropping rules (tape NEVER cropped) | ### Client-Scoped Reporting Dashboard Reporting has been moved from the Settings modal into a dedicated "Reporting" tab within each client's main view: diff --git a/backend/profiles/amazon_static.json b/backend/profiles/amazon_static.json index 45a62ca..46fd2d8 100644 --- a/backend/profiles/amazon_static.json +++ b/backend/profiles/amazon_static.json @@ -1,6 +1,6 @@ { "name": "Amazon Static", - "description": "Amazon ASD 2025 design guidelines QC profile for static marketing assets. Evaluates layout elements, typography, margins, box placement, and logo correctness per country.", + "description": "Amazon ASD 2025 design guidelines QC profile for static marketing assets. Evaluates layout elements, typography, margins, element placement, and logo correctness per country.", "checks": { "amazon_required_elements": { "enabled": true, @@ -32,11 +32,11 @@ "llm": "Gemini", "description": "Validates Amazon margin rules: 7% of shortest side, 10% for wide banners, special rules for very wide and small formats" }, - "amazon_box_placement": { + "amazon_element_placement": { "enabled": true, "weight": 1.67, "llm": "Gemini", - "description": "Checks box sits to right side, cropping rules (right crop OK but never tape, never bottom), and box overlap constraints" + "description": "Checks element placement (box, bag, logo), positioning rules, cropping rules (right crop OK but never tape, never bottom), and overlap constraints" } } } diff --git a/backend/visual_qc_apps/amazon_box_placement/app.py b/backend/visual_qc_apps/amazon_element_placement/app.py similarity index 97% rename from backend/visual_qc_apps/amazon_box_placement/app.py rename to backend/visual_qc_apps/amazon_element_placement/app.py index c4d2e73..0dfd30b 100644 --- a/backend/visual_qc_apps/amazon_box_placement/app.py +++ b/backend/visual_qc_apps/amazon_element_placement/app.py @@ -6,10 +6,10 @@ sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath( from visual_qc_apps.flask_app_template import FlaskAppTemplate -class AmazonBoxPlacementApp(FlaskAppTemplate): +class AmazonElementPlacementApp(FlaskAppTemplate): """ - Amazon ASD 2025 - Box Placement & Cropping Check - Verifies box positioning (right side) and cropping rules. + Amazon ASD 2025 - Element Placement & Cropping Check + Verifies element positioning (box, bag, logo) and cropping rules. """ def __init__(self): @@ -132,5 +132,5 @@ Format your response as JSON: # Run the app if executed directly if __name__ == "__main__": - app_instance = AmazonBoxPlacementApp() + app_instance = AmazonElementPlacementApp() app_instance.run() diff --git a/web_ui.html b/web_ui.html index b913540..0257319 100644 --- a/web_ui.html +++ b/web_ui.html @@ -4038,32 +4038,96 @@ } } + let authCheckInterval = null; // Periodic auth check timer + async function checkAuthStatus() { try { showAuthLoading(); - + const response = await fetch(`${BASE_PATH}auth/status`); const status = await response.json(); - + if (status.authenticated && status.user) { currentUser = status.user; isAuthenticated = true; updateAuthUI(); + // Start periodic auth check if not already running + startPeriodicAuthCheck(); } else { isAuthenticated = false; + stopPeriodicAuthCheck(); showAuthRequired(); } - + return isAuthenticated; - + } catch (error) { console.error('Auth status check failed:', error); isAuthenticated = false; + stopPeriodicAuthCheck(); showAuthRequired(); return false; } } + // Silent auth check - runs periodically without showing loading indicators + async function silentAuthCheck() { + try { + const response = await fetch(`${BASE_PATH}auth/status`); + const status = await response.json(); + + if (!status.authenticated || !status.user) { + console.warn('Session expired - prompting re-authentication'); + isAuthenticated = false; + currentUser = null; + stopPeriodicAuthCheck(); + showSessionExpiredPrompt(); + } + } catch (error) { + console.error('Silent auth check failed:', error); + // Don't immediately log out on network errors - wait for next check + } + } + + function startPeriodicAuthCheck() { + if (authCheckInterval) return; // Already running + // Check every 5 minutes (300000ms) + authCheckInterval = setInterval(silentAuthCheck, 5 * 60 * 1000); + console.log('Periodic auth check started (every 5 minutes)'); + } + + function stopPeriodicAuthCheck() { + if (authCheckInterval) { + clearInterval(authCheckInterval); + authCheckInterval = null; + console.log('Periodic auth check stopped'); + } + } + + function showSessionExpiredPrompt() { + // Hide main app content + document.getElementById('mainApp').style.display = 'none'; + document.getElementById('userInfo').style.display = 'none'; + + // Show auth required screen with expired message + const authRequired = document.getElementById('authRequired'); + authRequired.style.display = 'block'; + + // Show a session expired message if not already present + let expiredMsg = document.getElementById('sessionExpiredMsg'); + if (!expiredMsg) { + expiredMsg = document.createElement('div'); + expiredMsg.id = 'sessionExpiredMsg'; + expiredMsg.style.cssText = 'background: #fff3cd; color: #856404; border: 1px solid #ffc107; border-radius: 8px; padding: 16px; margin: 16px auto; max-width: 500px; text-align: center; font-size: 14px;'; + expiredMsg.innerHTML = 'Session Expired
Your authentication session has timed out. Please sign in again to continue.'; + authRequired.insertBefore(expiredMsg, authRequired.firstChild); + } + expiredMsg.style.display = 'block'; + + // Show login button + showLoginButton(); + } + // UI update functions function showAuthLoading() { document.getElementById('authLoading').style.display = 'block';