# Design Review Checklist - xFarma v1.1

> Comprehensive checklist for the `design-review-specialist` agent.
> Last updated: 2025-12-27

---

## Quick Review (5 minutes)

Use for small PRs or hotfixes:

```
[ ] No "--" placeholders visible
[ ] All text in Spanish
[ ] Currency format: €1.234,56
[ ] No console errors (F12)
[ ] No horizontal scroll at 768px
```

---

## Full Review Checklist

### Phase 0: Preparation & Auth

**Authentication Flow:**
```
1. Navigate to http://localhost:8050
2. Credentials: Check frontend/tests/e2e/README.md
3. Login → Redirects to /home (success) or stays on / (failure)
4. Look for 401 errors in console = auth broken
```

**Playwright Setup:**
```python
# Initial navigation
mcp__playwright__browser_navigate(url="http://localhost:8050")

# Configure viewport (desktop first)
mcp__playwright__browser_resize(width=1440, height=900)

# Take baseline screenshot
mcp__playwright__browser_take_screenshot(filename="00-initial-state.png")
```

---

### Phase 1: xFarma Standards (REGLA #0, #5)

#### REGLA #0: Verificación Visual Obligatoria

| Check | Pass | Fail |
|-------|------|------|
| KPI cards show numbers | `€12.345,67` | `--` or `€0,00` when data exists |
| Charts render data | Bars/lines visible | "Cargando..." stuck >3s |
| Tables populated | Rows with data | Empty or perpetual skeleton |
| Dates formatted | "27 de diciembre de 2025" | "2025-12-27" or "December 27" |

#### REGLA #5: Design System Integrity

| Token | Value | Usage |
|-------|-------|-------|
| `SPACING['xs']` | 4px | Icon margins |
| `SPACING['s']` | 8px | Minimum breathing room |
| `SPACING['m']` | 16px | Component internal padding |
| `SPACING['l']` | 24px | Card padding (MANDATORY) |
| `SPACING['xl']` | 32px | Section gaps (MANDATORY) |

**Code Validation:**
```bash
# Check for hardcoded colors (should return 0 results in new code)
grep -rn "#[0-9A-Fa-f]\{6\}" frontend/layouts/ frontend/callbacks/ --include="*.py"

# Validate callbacks
python frontend/utils/validate_callbacks.py

# Check Dash anti-patterns
python frontend/utils/dash_component_validator.py --all
```

#### Spanish Localization

| Type | Correct | Incorrect |
|------|---------|-----------|
| Currency | `€1.234,56` | `1,234.56€` or `$1,234.56` |
| Numbers | `1.234,56` | `1,234.56` |
| Dates | "27 de diciembre de 2025" | "December 27, 2025" |
| Percentages | `12,5%` | `12.5%` |

**Common Spanish Terms:**
- Sales → Ventas
- Upload → Subir archivo
- Download → Descargar
- Save → Guardar
- Cancel → Cancelar
- Loading → Cargando...
- Error → Error (same)
- Success → Éxito
- Pharmacy → Farmacia
- Products → Productos
- Generics → Genéricos

---

### Phase 2: Visual Harmony

#### 8px Grid System

```
Card structure:
┌─────────────────────────────┐
│ ← 24px padding (LG) →       │
│  ┌─────────────────────┐    │
│  │ Content             │    │
│  └─────────────────────┘    │
│                             │
└─────────────────────────────┘
         ↕ 32px gap (XL)
┌─────────────────────────────┐
│ Next card                   │
└─────────────────────────────┘
```

#### Typography Hierarchy

| Element | Font Size | Line Height | Weight |
|---------|-----------|-------------|--------|
| H1 | 2rem (32px) | 1.2 | 700 |
| H2 | 1.5rem (24px) | 1.2 | 600 |
| H3 | 1.25rem (20px) | 1.2 | 600 |
| Body | 1rem (16px) | 1.5 | 400 |
| Small | 0.875rem (14px) | 1.5 | 400 |

#### Chart Legibility

- Pie charts: Slices <5% use external labels or "Otros" grouping
- Bar charts: X-axis labels rotated 45° if >6 categories
- Line charts: Max 5 series, distinct colors from `COLORS` tokens
- All charts: `config={'responsive': True, 'displayModeBar': False}`

---

### Phase 3: Interaction & Dash Robustness

#### Console Error Patterns

```javascript
// BLOCKER errors (F12 → Console)
"Duplicate callback outputs"     // Same Output in 2+ callbacks
"Circular dependencies"          // Import cycle
"Already has an output"         // Callback conflict
"nonexistent component"         // Missing component ID

// WARNING (investigate)
"Property ... was not found"    // Typo in property name
"Callback error updating"       // Runtime callback failure
```

**Playwright Console Check:**
```python
mcp__playwright__browser_console_messages(onlyErrors=True)
```

#### Interactive States

| State | Visual Feedback | Timing |
|-------|-----------------|--------|
| Hover | Background lighten 5% | 150ms transition |
| Active/Pressed | Background darken 10% | Immediate |
| Disabled | 50% opacity, cursor: not-allowed | N/A |
| Loading | Spinner or skeleton | Show after 200ms |
| Focus | 2px solid #0066CC, 2px offset | Immediate |

#### Edge Case Testing

```python
# Empty state
# Navigate to feature with no data uploaded
# Expected: Friendly message, not empty table

# Large dataset (10k+ records)
# Check: No browser freeze, pagination works, charts responsive

# Long text overflow
# Test with: "Farmacia María del Carmen González-Fernández S.L."
# Expected: Truncate with ellipsis, full text on hover
```

---

### Phase 4: Responsiveness

#### Viewport Commands

```python
# Desktop (primary)
mcp__playwright__browser_resize(width=1440, height=900)
mcp__playwright__browser_take_screenshot(filename="viewport-desktop-1440.png")

# Tablet
mcp__playwright__browser_resize(width=768, height=1024)
mcp__playwright__browser_take_screenshot(filename="viewport-tablet-768.png")
```

#### Responsive Behavior Matrix

| Component | Desktop 1440px | Tablet 768px |
|-----------|---------------|--------------|
| Sidebar | Fixed 280px | Collapsed (hamburger) |
| KPI cards | 4 columns | 2 columns |
| Charts | Full width | Full width, smaller height |
| DataTables | Horizontal scroll OK | Horizontal scroll OK |
| Forms | 2 columns | 1 column |

#### Forbidden at ALL Viewports (>=768px)
- ❌ Horizontal page scroll
- ❌ Text overflow without ellipsis
- ❌ Buttons cut off
- ❌ Overlapping elements

---

### Phase 5: Accessibility (WCAG 2.1 AA)

#### Contrast Requirements

| Element | Minimum Ratio | Tool |
|---------|---------------|------|
| Normal text (<18px) | 4.5:1 | DevTools → Accessibility |
| Large text (>=18px bold) | 3:1 | |
| UI components | 3:1 | |

#### Keyboard Navigation

```python
# Test Tab order
mcp__playwright__browser_press_key(key="Tab")  # Repeat to traverse

# Expected: Logical order (top→bottom, left→right)
# Focus ring: 2px solid #0066CC, 2px offset
```

#### Semantic HTML Checklist

```
[ ] html.Nav for navigation menus
[ ] html.Main for primary content
[ ] html.Section for grouped content
[ ] html.Article for self-contained content
[ ] All html.Img have alt text
[ ] All dbc.Input have dbc.Label or aria-label
[ ] Icons have aria-label (DashIconify)
```

---

## Network Validation

```python
# Check for API errors
mcp__playwright__browser_network_requests()

# Look for:
# - 401 Unauthorized → Auth broken
# - 404 Not Found → Missing /api/v1/ prefix
# - 500 Internal Server Error → Backend bug
# - Slow requests (>2s) → Performance issue
```

---

## Screenshot Conventions

| Filename | When |
|----------|------|
| `00-initial-state.png` | After login, before interaction |
| `01-feature-loaded.png` | Feature page fully rendered |
| `02-interaction-result.png` | After user action |
| `03-error-state.png` | Error condition captured |
| `viewport-desktop-1440.png` | Desktop responsive check |
| `viewport-tablet-768.png` | Tablet responsive check |
| `console-errors.png` | If console errors found |

Save to: `.playwright-mcp/` directory

---

## Report Template

```markdown
# Design Review: [Feature Name] (Issue #XXX)

**Date:** YYYY-MM-DD
**Reviewer:** design-review-specialist
**Environment:** localhost:8050
**Viewports:** 1440px, 768px

---

## Executive Summary

**Verdict:** ✅ READY / ⚠️ CONDITIONAL / ❌ NOT READY

**Achievements:**
- ✅ [What works well]

**Blockers:**
- ❌ [Critical issues]

---

## xFarma Standards Compliance

| Standard | Status | Notes |
|----------|--------|-------|
| REGLA #0: No "--" placeholders | ✅/❌ | |
| REGLA #5: Design tokens | ✅/❌ | |
| Spanish localization | ✅/❌ | |
| 8px grid system | ✅/❌ | |
| Accessibility WCAG AA | ✅/❌ | |

---

## Critical Findings

### [BLOCKER] Issue Title
**Impact:** [User impact description]
**Evidence:** [Screenshot filename]
**Fix:** [Recommended approach]

### [HIGH] Issue Title
...

---

## Action Plan

### Immediate (Blockers)
1. [ ] Fix X
2. [ ] Fix Y

### Before Production (High)
3. [ ] Improve Z

### Post-Deployment (Medium)
4. [ ] Polish W

---

## Evidence

| Screenshot | Description |
|------------|-------------|
| `00-initial-state.png` | Initial page load |
| `viewport-tablet-768.png` | Tablet responsive |

---

*Generated by design-review-specialist*
```

---

## Reference Files

### Design System (READ FIRST)
| File | Content | Priority |
|------|---------|----------|
| `context/style-guide.md` | Colors, typography, spacing, components | **Required** |
| `context/design-principles.md` | UX philosophy, visual harmony principles | **Required** |
| `frontend/styles/design_tokens.py` | Python token values (COLORS, SPACING) | **Required** |
| `frontend/styles/README.md` | Design system overview | Recommended |
| `frontend/components/base/README.md` | BaseCard, BaseButton usage | Recommended |

### Code & Patterns
| File | Content |
|------|---------|
| `frontend/docs/CALLBACK_PATTERNS.md` | Dash callback best practices |
| `frontend/tests/e2e/README.md` | Test credentials and setup |
| `CLAUDE.md` | Project rules (REGLA #0, #5, #11) |

### Quick Token Values

> ⚠️ **FUENTE DE VERDAD**: Siempre verificar valores actuales en `frontend/styles/design_tokens.py`

```python
# SPACING - Nota: usa 's', 'm', 'l' (no 'sm', 'md', 'lg')
SPACING = {
    'xs': '4px',   # Espaciado mínimo entre iconos/texto
    's': '8px',    # Margen interno botones pequeños (style-guide: SM)
    'm': '16px',   # Espaciado entre campos formulario (style-guide: MD)
    'l': '24px',   # Padding interno Cards (style-guide: LG) - OBLIGATORIO
    'xl': '32px',  # Espaciado entre secciones - OBLIGATORIO
    '2xl': '48px', # Margen superior página (style-guide: XXL)
}

# COLORS - Bootstrap standard (alineado con style-guide.md)
COLORS = {
    'primary': '#0066CC',       # Primary Blue - CTAs, acciones principales
    'secondary': '#6C757D',     # Professional Gray
    'success': '#28A745',       # Pharmacy Green - uploads OK, genéricos
    'danger': '#DC3545',        # Red - errores, sync fallido
    'warning': '#FFC107',       # Amber - estados pendientes
    'info': '#17A2B8',          # Teal - mensajes informativos
    'text_primary': '#343A40',  # Dark Gray - texto principal
    'text_secondary': '#6C757D', # Professional Gray - texto secundario
    'bg_primary': '#FFFFFF',    # Fondo cards
    'bg_secondary': '#F8F9FA',  # Fondo página
    'border_medium': '#DEE2E6', # Bordes cards
}

# SHADOWS - Bootstrap standard
SHADOWS = {
    'sm': '0 0.125rem 0.25rem rgba(0, 0, 0, 0.075)',
    'md': '0 0.5rem 1rem rgba(0, 0, 0, 0.15)',
    'lg': '0 1rem 3rem rgba(0, 0, 0, 0.175)',
}
```
