# 📋 Plan: Thematic Loading Overlays (Charon, Coin, & Cerberus)
## 🧐 UX & Context Analysis
**Problem**: When users make configuration changes (create/update/delete proxy hosts, security configs, certificates), Charon applies the new config to Caddy via its admin API. During this reload process (which can take 1-3 seconds, and up to 5-10 seconds with WAF/security features), the Caddy admin API temporarily stops responding on port 2019. Currently, users receive no visual feedback that a reload is happening, and they can attempt to make additional changes before the previous reload completes.
**Desired User Flow**:
1. User submits a configuration change (create/update/delete proxy host, security config, etc.)
2. **NEW**: Thematic loading overlay appears:
- **Coin Theme** (Gold/Spinning Obol): Authentication/Login - "Paying the ferryman"
- **Charon Theme** (Blue/Boat): Proxy hosts, certificates, general config - "Ferrying across the Styx"
- **Cerberus Theme** (Red/Guardian): WAF, CrowdSec, ACL, Rate Limiting - "Guardian stands watch"
3. Backend applies config to Caddy (admin API may restart during this process)
4. Backend returns success/failure response
5. **NEW**: Loading overlay disappears
6. User sees success toast and updated data
7. User can safely make additional changes
**Why This Matters**:
- Prevents race conditions from rapid sequential changes
- Provides clear feedback during potentially slow operations (WAF config reloads can take 5-10s)
- Prevents user confusion when admin API is temporarily unavailable
- **Reinforces Branding**: Complete Greek mythology theme (Charon the ferryman, Cerberus the guardian, obol coin)
- **Visual Distinction**: Three clear themes - Auth (gold), Proxy (blue), Security (red)
- **Perfect Metaphor**: Login = paying Charon for passage into the Underworld (app)
- Matches enterprise-grade UX expectations with personality
## 🤝 Handoff Contract (The Truth)
### Backend Changes: NONE REQUIRED
Backend already handles config reloads correctly and returns appropriate HTTP status codes. The backend sequence is:
1. Save changes to database
2. Call `caddyManager.ApplyConfig(ctx)`
3. Return success (200/201) or error (400/500)
4. If error, rollback database changes
No backend modifications needed - this is a **frontend-only UX enhancement**.
### Frontend API Response Structure (Existing)
```json
// POST /api/v1/proxy-hosts (success)
{
"uuid": "abc-123",
"name": "My Service",
"domain_names": "example.com",
"enabled": true,
"created_at": "2025-12-04T10:00:00Z",
"updated_at": "2025-12-04T10:00:00Z"
}
// Error response (if Caddy reload fails)
{
"error": "Failed to apply configuration: connection refused"
}
```
## 🎨 Phase 1: Frontend Implementation (React)
### 1.1 Create Thematic Loading Animations
**File**: `frontend/src/components/LoadingStates.tsx`
#### A. Charon-Themed Loader (Proxy/General Operations)
**New Component**: `CharonLoader` - Boat on Waves animation (Charon ferrying across the Styx)
```tsx
export function CharonLoader({ size = 'md' }: { size?: 'sm' | 'md' | 'lg' }) {
const sizeClasses = {
sm: 'w-12 h-12',
md: 'w-20 h-20',
lg: 'w-28 h-28',
}
return (
)
}
```
**Why Coin for Authentication**:
- **Mythology Perfect**: In Greek mythology, the dead paid Charon with an obol (coin) to cross the River Styx
- **Metaphor**: User is "paying for passage" into the application
- **Visual Interest**: Spinning coin on Y-axis creates engaging 3D effect
- **Distinct From Other Operations**: Gold/amber vs blue (proxy) or red (security)
#### C. Cerberus-Themed Loader (Security Operations)
**New Component**: `CerberusLoader` - Three-Headed Guardian animation
```tsx
export function CerberusLoader({ size = 'md' }: { size?: 'sm' | 'md' | 'lg' }) {
const sizeClasses = {
sm: 'w-12 h-12',
md: 'w-20 h-20',
lg: 'w-28 h-28',
}
return (
{/* Central body with pulsing shield */}
)
}
```
**Enhancement**: Add overlay components with appropriate theming:
```tsx
export function ConfigReloadOverlay({
message = 'Ferrying configuration...',
submessage = 'Charon is crossing the Styx',
type = 'charon'
}: {
message?: string
submessage?: string
type?: 'charon' | 'coin' | 'cerberus'
}) {
const Loader =
type === 'cerberus' ? CerberusLoader :
type === 'coin' ? CharonCoinLoader :
CharonLoader
const bgColor =
type === 'cerberus' ? 'bg-red-950/90' :
type === 'coin' ? 'bg-amber-950/90' :
'bg-slate-800'
const borderColor =
type === 'cerberus' ? 'border-red-900/50' :
type === 'coin' ? 'border-amber-900/50' :
'border-slate-700'
return (
{message}
{submessage}
)
}
```
**Why Cerberus Theme**:
- **Mythology Match**: Cerberus is the three-headed guard dog of the Underworld gates - perfect for security operations
- **Charon Connection**: Both from Greek mythology, thematically consistent with app branding
- **Visual Distinction**: Red/shield theme vs blue/boat clearly differentiates security vs general operations
- **Three Heads = Three Layers**: WAF, CrowdSec, Rate Limiting (the three security components)
- **Guardian Symbolism**: Emphasizes protective nature of security features
**Why Coin Theme for Login**:
- **Perfect Mythology**: In Greek myth, souls paid Charon an obol (coin) to cross into the Underworld
- **Natural Metaphor**: User "pays for passage" to access the application
- **Thematic Consistency**: Login = entering the realm, coin = the required payment
- **Visual Appeal**: 3D spinning coin effect is engaging and distinct
- **Color Distinction**: Gold/amber distinguishes auth from proxy (blue) and security (red)
**Future Enhancement** (separate issue):
Implement hybrid approach with rotating animations for all three themes:
- **Charon**: Boat (current), Rowing Oar, River Flow
- **Coin/Auth**: Coin Flip (current), Coin Drop, Token Glow, Gate Opening
- **Cerberus**: Three Heads (current), Shield Pulse, Guardian Stance, Chain Links
### 1.2 Update Hook to Expose Mutation States
**File**: `frontend/src/hooks/useProxyHosts.ts`
**Change**: Already exposes `isCreating`, `isUpdating`, `isDeleting`, `isBulkUpdating` - **NO CHANGES NEEDED**.
### 1.3 Add Loading Overlay to UI Pages
**Files to Modify**:
**Charon Theme** (Blue/Boat):
- `frontend/src/pages/ProxyHosts.tsx` - Proxy host CRUD
- `frontend/src/components/ProxyHostForm.tsx` - Form mutations
- `frontend/src/components/CertificateList.tsx` - Certificate operations
**Coin Theme** (Gold/Amber):
- `frontend/src/pages/Login.tsx` - Login authentication
- `frontend/src/context/AuthContext.tsx` - Initial auth check (optional)
**Cerberus Theme** (Red/Guardian):
- `frontend/src/pages/WafConfig.tsx` - WAF ruleset operations
- `frontend/src/pages/Security.tsx` - Security toggle operations
- `frontend/src/pages/CrowdSecConfig.tsx` - CrowdSec configuration
- `frontend/src/pages/AccessLists.tsx` - ACL operations (when implementing rate limiting page)
**Implementation Pattern** (ProxyHosts.tsx example - Charon Theme):
```tsx
import { ConfigReloadOverlay } from '../components/LoadingStates'
export default function ProxyHosts() {
const {
hosts,
loading,
isCreating,
isUpdating,
isDeleting,
isBulkUpdating
} = useProxyHosts()
// Show overlay when ANY mutation is in progress
const isApplyingConfig = isCreating || isUpdating || isDeleting || isBulkUpdating
// Determine contextual message based on operation
const getMessage = () => {
if (isCreating) return {
message: "Ferrying new host...",
submessage: "Charon is crossing the Styx"
}
if (isDeleting) return {
message: "Returning to shore...",
submessage: "Host departure in progress"
}
if (isBulkUpdating) return {
message: "Ferrying souls...",
submessage: "Bulk operation crossing the river"
}
return {
message: "Guiding changes across...",
submessage: "Configuration in transit"
}
}
const { message, submessage } = getMessage()
return (
<>
{isApplyingConfig && (
)}
{/* Existing page content */}