Offer Banner Architecture
This document explains the technical architecture and data flow of the ROfferBanner component.
Configuration Architecture
The component now uses a global singleton pattern for simplified configuration:
Global Singleton Configuration Flow
graph LR
A[reachu-config.json] --> B[ConfigurationLoader]
B --> C[ReachuConfiguration.shared]
C --> D[LiveShowConfiguration.campaignId]
D --> E[ComponentManager.shared]
E --> F[ROfferBannerDynamic]
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fff3e0
style F fill:#e1f5fe
Singleton Benefits
Global Singleton Pattern: - Zero Configuration - No parameters needed anywhere
- Global Access - Available from any view with
ComponentManager.shared - Centralized Management - All configuration in one file
- Consistent Behavior - Same campaign ID across the entire app
- Easy Updates - Change campaign ID without code changes
- Auto-Connection - Automatically connects on app startup
- Reduced Errors - No risk of passing wrong campaign ID
- Simplified Integration - Just use
ROfferBannerDynamic()anywhere
Component Architecture
graph TB
subgraph "iOS App"
A[ROfferBannerDynamic] --> B[ComponentManager]
B --> C[ROfferBanner]
C --> D[CountdownView]
C --> E[AsyncImage]
C --> F[CTA Button]
end
subgraph "Backend Services"
G[REST API] --> H[Active Components]
I[WebSocket Server] --> J[Real-time Updates]
end
subgraph "Data Flow"
K[Campaign ID] --> B
B --> L[API Call]
L --> G
G --> M[Component Config]
M --> B
B --> N[Published State]
N --> C
C --> O[UI Rendering]
P[WebSocket Connection] --> B
B --> I
I --> Q[Status Updates]
Q --> B
B --> R[State Update]
R --> N
end
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style G fill:#fff3e0
style I fill:#fff3e0
Data Flow Diagram
sequenceDiagram
participant App as iOS App
participant Manager as ComponentManager.shared
participant API as REST API
participant WS as WebSocket
participant Banner as ROfferBanner
App->>Manager: Access ComponentManager.shared
Manager->>Manager: Auto-initialize with config campaignId
Manager->>Manager: Auto-connect()
Manager->>API: GET /api/campaigns/{id}/active-components
API-->>Manager: Active Components Response
Manager->>WS: Connect to WebSocket
WS-->>Manager: Connection Established
Manager->>Banner: Update activeBanner state
Banner->>Banner: Render banner with config
Note over Banner: Banner displays with skeleton loading
Banner->>Banner: Load images asynchronously
Banner->>Banner: Start countdown timer
Note over WS: Real-time updates
WS->>Manager: Component status changed
Manager->>Banner: Update configuration
Banner->>Banner: Re-render with new config
Note over WS: Campaign ends
WS->>Manager: Campaign ended
Manager->>Banner: Clear activeBanner
Banner->>Banner: Hide banner
Note over Manager: Global singleton manages lifecycle automatically
Manager->>Manager: Auto-cleanup resources
Component Hierarchy
graph TD
A[ROfferBannerContainer] --> B[ComponentManager]
A --> C[ROfferBanner]
B --> D[WebSocketManager]
B --> E[API Client]
B --> F[State Management]
C --> G[Background Layer]
C --> H[Content Layer]
C --> I[Overlay Layer]
G --> J[AsyncImage - Background]
H --> K[Logo]
H --> L[Title & Subtitle]
H --> M[CountdownView]
H --> N[Discount Badge]
H --> O[CTA Button]
I --> P[Dark Overlay]
M --> Q[TimeUnit Components]
style A fill:#e1f5fe
style B fill:#f3e5f5
style C fill:#e8f5e8
style D fill:#fff3e0
style E fill:#fff3e0
State Management
stateDiagram-v2
[*] --> Initializing
Initializing --> Connecting
Connecting --> Connected
Connecting --> Failed
Connected --> FetchingComponents
FetchingComponents --> ComponentsLoaded
FetchingComponents --> FetchFailed
ComponentsLoaded --> BannerActive
ComponentsLoaded --> NoBanner
BannerActive --> BannerInactive
BannerInactive --> BannerActive
BannerActive --> CampaignEnded
BannerInactive --> CampaignEnded
NoBanner --> CampaignEnded
CampaignEnded --> [*]
Failed --> [*]
FetchFailed --> [*]
note right of BannerActive
Banner is visible with
countdown timer running
end note
note right of BannerInactive
Banner is hidden but
connection remains active
end note
Error Handling Flow
flowchart TD
A[Component Initialization] --> B{API Available?}
B -->|Yes| C[Fetch Components]
B -->|No| D[Show Error State]
C --> E{Components Found?}
E -->|Yes| F[Display Banner]
E -->|No| G[Show Empty State]
F --> H{WebSocket Connected?}
H -->|Yes| I[Listen for Updates]
H -->|No| J[Retry Connection]
I --> K{Update Received?}
K -->|Yes| L[Update Banner]
K -->|No| M[Maintain Current State]
J --> N{Max Retries?}
N -->|No| H
N -->|Yes| O[Fallback to Static State]
L --> P{Valid Config?}
P -->|Yes| Q[Render New Banner]
P -->|No| R[Log Error & Keep Current]
style D fill:#ffebee
style G fill:#fff3e0
style O fill:#fff3e0
style R fill:#ffebee
Performance Considerations
Memory Management
- Automatic cleanupof WebSocket connections
- Timer invalidationon component disposal
- Image cachingfor frequently used assets
- State observationcleanup in deinit
Network Optimization
- Exponential backofffor failed connections
- Connection poolingfor API requests
- Compressed WebSocket messages - Efficient state updatesto minimize re-renders
UI Performance
- Lazy loadingof images
- Skeleton statesto prevent layout jumps
- Efficient countdown updates(1-second intervals)
- Minimal re-rendersthrough proper state management
Security Considerations
- HTTPS/WSSconnections only
- API key validationon backend
- Input sanitizationfor all configuration data
- XSS preventionin dynamic content
- Secure image loadingwith URL validation
Scalability Features
- Multiple campaign supportthrough different IDs
- Horizontal scalingvia load balancers
- Caching layersfor frequently accessed data
- Rate limitingto prevent abuse
- Graceful degradationunder high load