trading-platform/docs/02-definicion-modulos/OQI-003-trading-charts/historias-usuario/US-TRD-016-modo-oscuro-chart.md
rckrdmrd a7cca885f0 feat: Major platform documentation and architecture updates
Changes include:
- Updated architecture documentation
- Enhanced module definitions (OQI-001 to OQI-008)
- ML integration documentation updates
- Trading strategies documentation
- Orchestration and inventory updates
- Docker configuration updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 05:33:35 -06:00

434 lines
13 KiB
Markdown

---
id: "US-TRD-016"
title: "Cambiar Tema del Chart"
type: "User Story"
status: "Done"
priority: "Baja"
epic: "OQI-003"
story_points: 2
created_date: "2025-12-05"
updated_date: "2026-01-04"
---
# US-TRD-016: Cambiar Tema del Chart (Claro/Oscuro)
## Metadata
| Campo | Valor |
|-------|-------|
| **ID** | US-TRD-016 |
| **Épica** | OQI-003 - Trading y Charts |
| **Módulo** | trading |
| **Prioridad** | P2 |
| **Story Points** | 2 |
| **Sprint** | Sprint 6 |
| **Estado** | Pendiente |
| **Asignado a** | Por asignar |
---
## Historia de Usuario
**Como** usuario de la plataforma,
**quiero** cambiar entre tema claro y oscuro para el chart de trading,
**para** adaptar la visualización a mis preferencias y reducir fatiga visual en sesiones largas.
## Descripción Detallada
El usuario debe poder alternar entre un tema claro y un tema oscuro para el chart de trading. El tema oscuro es especialmente útil para trading nocturno o sesiones prolongadas, reduciendo la fatiga visual. La preferencia debe persistir entre sesiones.
## Mockups/Wireframes
```
TEMA CLARO:
┌─────────────────────────────────────────────────────────────────┐
│ BTCUSDT $97,234.50 +2.34% ▲ [☀ Light] │
├─────────────────────────────────────────────────────────────────┤
│ Background: #FFFFFF │
│ Grid: #E0E0E0 │
│ Text: #000000 │
│ Candles Up: #26A69A (Green) │
│ Candles Down: #EF5350 (Red) │
│ Volume: #757575 (Gray) │
│ Crosshair: #000000 │
│ │
│ ████ (Green candles on white background) │
│ ████ ████ │
│ ████ ════ (SMA - Blue line on white) │
│ │
└─────────────────────────────────────────────────────────────────┘
TEMA OSCURO:
┌─────────────────────────────────────────────────────────────────┐
│ BTCUSDT $97,234.50 +2.34% ▲ [🌙 Dark] │
├─────────────────────────────────────────────────────────────────┤
│ Background: #1E222D │
│ Grid: #363C4E │
│ Text: #D1D4DC │
│ Candles Up: #26A69A (Green) │
│ Candles Down: #EF5350 (Red) │
│ Volume: #757575 (Gray) │
│ Crosshair: #FFFFFF │
│ │
│ ████ (Green candles on dark background) │
│ ████ ████ │
│ ████ ════ (SMA - Blue line on dark) │
│ │
└─────────────────────────────────────────────────────────────────┘
CONTROL DE TEMA:
┌─────────────────────────┐
│ [☀ Light] [🌙 Dark] │
│ └─Active (Blue) │
└─────────────────────────┘
```
---
## Criterios de Aceptación
**Escenario 1: Cambiar a tema oscuro**
```gherkin
DADO que el usuario está viendo el chart en tema claro
CUANDO hace click en el botón "Dark"
ENTONCES el chart cambia a tema oscuro inmediatamente
Y el fondo cambia a #1E222D
Y el texto cambia a color claro (#D1D4DC)
Y la grid cambia a #363C4E
Y las velas mantienen sus colores (verde/rojo)
Y el botón "Dark" se marca como activo
```
**Escenario 2: Cambiar a tema claro**
```gherkin
DADO que el usuario está viendo el chart en tema oscuro
CUANDO hace click en el botón "Light"
ENTONCES el chart cambia a tema claro
Y el fondo cambia a #FFFFFF
Y el texto cambia a color oscuro (#000000)
Y el botón "Light" se marca como activo
```
**Escenario 3: Persistencia de preferencia**
```gherkin
DADO que el usuario selecciona tema oscuro
CUANDO cierra sesión y vuelve a iniciar sesión
ENTONCES el chart se carga automáticamente en tema oscuro
Y la preferencia se mantiene
```
**Escenario 4: Sincronización con tema del sistema**
```gherkin
DADO que el usuario tiene preferencia "Auto"
CUANDO el sistema operativo está en modo oscuro
ENTONCES el chart usa tema oscuro automáticamente
CUANDO el sistema cambia a modo claro
ENTONCES el chart cambia a tema claro
```
**Escenario 5: Indicadores en ambos temas**
```gherkin
DADO que el usuario tiene indicadores SMA y RSI activos
CUANDO cambia entre temas
ENTONCES los indicadores mantienen sus colores distintivos
Y son visibles en ambos temas
Y los colores contrastan correctamente con el fondo
```
**Escenario 6: Keyboard shortcut**
```gherkin
DADO que el usuario está en el chart
CUANDO presiona "Ctrl + D" (o "Cmd + D" en Mac)
ENTONCES el tema alterna entre claro y oscuro
```
## Criterios Adicionales
- [ ] Transición suave entre temas (200ms)
- [ ] Aplicar tema también a paneles laterales
- [ ] Opción "Auto" que sigue el tema del sistema
- [ ] Previsualización de temas antes de aplicar
- [ ] Temas personalizados (futuro)
---
## Tareas Técnicas
**Database:**
- [ ] DB-TRD-025: Añadir campo theme a user_preferences
- Valores: 'light', 'dark', 'auto'
**Backend:**
- [ ] BE-TRD-092: Crear endpoint PATCH /users/preferences/theme
- [ ] BE-TRD-093: Implementar UserPreferencesService.updateTheme()
**Frontend:**
- [ ] FE-TRD-086: Crear componente ThemeToggle.tsx
- [ ] FE-TRD-087: Definir paletas de colores para cada tema
- [ ] FE-TRD-088: Implementar hook useTheme
- [ ] FE-TRD-089: Aplicar tema a Lightweight Charts
- [ ] FE-TRD-090: Implementar detección de tema del sistema
- [ ] FE-TRD-091: Añadir transiciones CSS
- [ ] FE-TRD-092: Implementar keyboard shortcut
**Tests:**
- [ ] TEST-TRD-043: Test unitario cambio de tema
- [ ] TEST-TRD-044: Test integración persistencia de tema
- [ ] TEST-TRD-045: Test E2E alternancia de temas
---
## Dependencias
**Depende de:**
- [ ] US-TRD-001: Ver chart - Estado: Pendiente
**Bloquea:**
- Ninguna
---
## Notas Técnicas
**Endpoints involucrados:**
| Método | Endpoint | Descripción |
|--------|----------|-------------|
| PATCH | /users/preferences/theme | Actualizar preferencia de tema |
| GET | /users/preferences | Obtener preferencias (incluye tema) |
**Entidades/Tablas:**
```sql
ALTER TABLE auth.user_preferences
ADD COLUMN theme VARCHAR(10) DEFAULT 'light';
-- Valores: 'light', 'dark', 'auto'
```
**Componentes UI:**
- `ThemeToggle`: Botones de alternancia de tema
- `ThemeProvider`: Context provider de tema
**Theme Palettes:**
```typescript
const LIGHT_THEME = {
chart: {
background: '#FFFFFF',
textColor: '#000000',
gridColor: '#E0E0E0',
crosshairColor: '#000000',
},
candles: {
upColor: '#26A69A', // Verde
downColor: '#EF5350', // Rojo
borderUpColor: '#26A69A',
borderDownColor: '#EF5350',
wickUpColor: '#26A69A',
wickDownColor: '#EF5350',
},
volume: {
upColor: 'rgba(38, 166, 154, 0.5)',
downColor: 'rgba(239, 83, 80, 0.5)',
},
indicators: {
sma: '#2962FF', // Azul
ema: '#FF6D00', // Naranja
rsi: '#9C27B0', // Púrpura
macd: '#00C853', // Verde oscuro
},
ui: {
background: '#FAFAFA',
cardBackground: '#FFFFFF',
border: '#E0E0E0',
text: '#000000',
textSecondary: '#757575',
}
};
const DARK_THEME = {
chart: {
background: '#1E222D',
textColor: '#D1D4DC',
gridColor: '#363C4E',
crosshairColor: '#FFFFFF',
},
candles: {
upColor: '#26A69A',
downColor: '#EF5350',
borderUpColor: '#26A69A',
borderDownColor: '#EF5350',
wickUpColor: '#26A69A',
wickDownColor: '#EF5350',
},
volume: {
upColor: 'rgba(38, 166, 154, 0.5)',
downColor: 'rgba(239, 83, 80, 0.5)',
},
indicators: {
sma: '#5E81F4',
ema: '#FF9800',
rsi: '#BA68C8',
macd: '#66BB6A',
},
ui: {
background: '#131722',
cardBackground: '#1E222D',
border: '#363C4E',
text: '#D1D4DC',
textSecondary: '#898E9C',
}
};
```
**Request Body:**
```typescript
{
theme: "dark" // "light", "dark", "auto"
}
```
**Response:**
```typescript
{
theme: "dark",
updatedAt: "2025-12-05T10:00:00Z"
}
```
**Frontend Implementation:**
```typescript
// Theme Context
const ThemeContext = createContext<ThemeContextType>(null);
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState<'light' | 'dark' | 'auto'>('light');
const [resolvedTheme, setResolvedTheme] = useState<'light' | 'dark'>('light');
// Load theme from user preferences
useEffect(() => {
loadUserTheme().then(setTheme);
}, []);
// Listen to system theme changes
useEffect(() => {
if (theme === 'auto') {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const updateResolvedTheme = () => {
setResolvedTheme(mediaQuery.matches ? 'dark' : 'light');
};
updateResolvedTheme();
mediaQuery.addEventListener('change', updateResolvedTheme);
return () => mediaQuery.removeEventListener('change', updateResolvedTheme);
} else {
setResolvedTheme(theme as 'light' | 'dark');
}
}, [theme]);
const toggleTheme = async () => {
const newTheme = resolvedTheme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
await saveUserTheme(newTheme);
};
return (
<ThemeContext.Provider value={{ theme, resolvedTheme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Apply theme to chart
function applyChartTheme(chart, theme) {
const palette = theme === 'dark' ? DARK_THEME : LIGHT_THEME;
chart.applyOptions({
layout: {
background: { color: palette.chart.background },
textColor: palette.chart.textColor,
},
grid: {
vertLines: { color: palette.chart.gridColor },
horzLines: { color: palette.chart.gridColor },
},
crosshair: {
vertLine: { color: palette.chart.crosshairColor },
horzLine: { color: palette.chart.crosshairColor },
},
});
candleSeries.applyOptions({
upColor: palette.candles.upColor,
downColor: palette.candles.downColor,
borderUpColor: palette.candles.borderUpColor,
borderDownColor: palette.candles.borderDownColor,
wickUpColor: palette.candles.wickUpColor,
wickDownColor: palette.candles.wickDownColor,
});
}
// Keyboard shortcut
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.ctrlKey || e.metaKey) && e.key === 'd') {
e.preventDefault();
toggleTheme();
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [toggleTheme]);
```
**CSS Transitions:**
```css
.chart-container {
transition: background-color 200ms ease-in-out;
}
.theme-toggle {
transition: all 200ms ease-in-out;
}
.theme-toggle.active {
background-color: #2962FF;
color: white;
}
```
---
## Definition of Ready (DoR)
- [x] Historia claramente escrita
- [x] Criterios de aceptación definidos
- [x] Story points estimados
- [x] Dependencias identificadas
- [x] Sin bloqueadores
- [ ] Diseño/mockup disponible
- [ ] API spec disponible
## Definition of Done (DoD)
- [ ] Código implementado según criterios
- [ ] Tests unitarios escritos y pasando
- [ ] Tests de integración pasando
- [ ] Code review aprobado
- [ ] Documentación actualizada
- [ ] QA aprobado
- [ ] Desplegado en ambiente de pruebas
---
## Historial de Cambios
| Fecha | Cambio | Autor |
|-------|--------|-------|
| 2025-12-05 | Creación | Requirements-Analyst |
---
**Creada por:** Requirements-Analyst
**Fecha:** 2025-12-05
**Última actualización:** 2025-12-05