Files
todolist-fullstack/docs/instrucoes-design.md
Erik Silva 35272b8f87 initial: Backend Auth Module + Design System + Complete Documentation
- Setup NestJS with TypeScript, ConfigModule, JWT authentication
- Implemented Auth Module with signup, login, logout endpoints
- Created DTOs with validation (SignupDto, LoginDto)
- JWT Strategy with Passport integration for token validation
- JwtAuthGuard for route protection with Bearer tokens
- CurrentUser decorator for dependency injection
- Supabase integration for user management and auth
- Complete API documentation (API.md) with all endpoints
- Design System for Web (Next.js + Tailwind) and Mobile (Flutter)
- Comprehensive project documentation and roadmap
- Environment configuration with Joi schema validation
- Ready for Tasks Module and RLS implementation
2025-12-01 01:17:00 -03:00

774 lines
19 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 🎨 TASK MANAGER - Design System & Guia de Interface
## 🌈 Paleta de Cores
### Cores Principais
- **Primary (Azul)**: `#2563EB` - Ações principais, links, seleção
- **Primary Dark**: `#1D4ED8` - Estados hover/ativo
- **Primary Light**: `#DBEAFE` - Backgrounds, estados desabilitados
- **White**: `#FFFFFF` - Backgrounds principal
- **Black**: `#000000` - Texto principal, contrastes fortes
- **Gray 50**: `#F9FAFB` - Backgrounds secundários
- **Gray 100**: `#F3F4F6` - Borders leves
- **Gray 200**: `#E5E7EB` - Borders padrão
- **Gray 400**: `#9CA3AF` - Texto secundário, placeholders
- **Gray 600**: `#4B5563` - Texto terciário
### Cores de Status
- **Success**: `#10B981` - Tarefas concluídas
- **Warning**: `#F59E0B` - Alertas
- **Error**: `#EF4444` - Erros, deletar
- **Info**: `#06B6D4` - Informações
---
## 🔤 Tipografia (Google Fonts)
### Fonte Principal: **Inter**
- Link: https://fonts.google.com/specimen/Inter
- Uso: Corpo de texto, UI, labels
### Fonte Secundária: **Poppins**
- Link: https://fonts.google.com/specimen/Poppins
- Uso: Títulos, headings, destaque
### Escala Tipográfica
| Nome | Tamanho | Weight | Line Height | Letra-espaçamento | Uso |
|------|---------|--------|-------------|------------------|-----|
| **H1** | 32px | 700 (Bold) | 40px | -0.5px | Títulos principais |
| **H2** | 24px | 700 (Bold) | 32px | -0.3px | Subtítulos |
| **H3** | 18px | 600 (SemiBold) | 28px | -0.2px | Seções |
| **Body Large** | 16px | 400 (Regular) | 24px | 0px | Texto principal |
| **Body Normal** | 14px | 400 (Regular) | 22px | 0px | Descrições |
| **Body Small** | 12px | 400 (Regular) | 18px | 0.2px | Ajuda, captions |
| **Label** | 12px | 600 (SemiBold) | 18px | 0.5px | Labels de campos |
| **Button** | 14px | 600 (SemiBold) | 20px | 0.5px | Texto de botões |
### Importação no CSS/Next.js
```css
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Poppins:wght@600;700&display=swap');
:root {
--font-inter: 'Inter', sans-serif;
--font-poppins: 'Poppins', sans-serif;
}
```
---
## 🎯 Espaçamento (8px Base)
Seguindo o padrão Material Design + Tailwind, usando múltiplos de 8px:
| Token | Valor | Uso |
|-------|-------|-----|
| **xs** | 4px | Micro-espaçamentos |
| **sm** | 8px | Padding pequeno |
| **md** | 12px | Padding padrão |
| **lg** | 16px | Espaçamento interno |
| **xl** | 24px | Separação entre elementos |
| **2xl** | 32px | Separação entre seções |
| **3xl** | 48px | Grandes divisores |
| **4xl** | 64px | Muito grandes |
### Exemplos de Aplicação
- **Padding de Botão**: 12px (vertical) × 16px (horizontal)
- **Padding de Card**: 24px
- **Gap entre inputs**: 16px
- **Margin entre seções**: 32px
---
## 🎨 Componentes - Design System
### 1⃣ **BOTÕES**
#### Botão Primary (Padrão)
```
Tamanho: 48px altura
Padding: 12px vertical × 16px horizontal
Background: #2563EB
Text: White, 14px Bold
Border Radius: 8px
Font Weight: 600
```
**Estados:**
- **Default**: Background #2563EB
- **Hover**: Background #1D4ED8, Sombra leve
- **Active**: Background #1D4ED8, sem sombra
- **Disabled**: Background #E5E7EB, Text #9CA3AF, sem cursor
#### Botão Secondary
```
Background: #F3F4F6
Text: #000000, 14px Bold
Border: 1px #E5E7EB
Border Radius: 8px
```
#### Botão Tertiary (Text only)
```
Background: transparent
Text: #2563EB, 14px Bold
Padding: 12px 16px
```
#### Botão Danger
```
Background: #EF4444
Text: White, 14px Bold
Sombra: 0px 4px 12px rgba(239, 68, 68, 0.2)
```
#### Botão com Ícone
```
Spacing entre ícone e texto: 8px
Ícone tamanho: 20px × 20px
```
---
### 2⃣ **CAMPOS DE ENTRADA (Inputs)**
#### Input Padrão
```
Altura: 44px
Padding: 12px 16px
Border: 1px #E5E7EB
Border Radius: 8px
Font: Inter 14px
Background: #FFFFFF
```
**Estados:**
- **Default**: Border #E5E7EB, Background #FFFFFF
- **Focus**: Border #2563EB (2px), Background #FFFFFF, Box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1)
- **Filled**: Border #2563EB
- **Error**: Border #EF4444, Background #FEF2F2
- **Disabled**: Border #E5E7EB, Background #F9FAFB, Text #9CA3AF
#### Placeholder
```
Color: #9CA3AF
Font Style: Regular
```
#### Label
```
Font: Poppins 12px SemiBold
Color: #000000
Margin Bottom: 8px
Required indicator (*): Color #EF4444
```
#### Help Text
```
Font: Inter 12px Regular
Color: #6B7280
Margin Top: 4px
```
#### Error Message
```
Font: Inter 12px Regular
Color: #EF4444
Icon: 16px × 16px (⚠️)
Margin Top: 4px
```
---
### 3⃣ **CARDS**
```
Background: #FFFFFF
Border: 1px #E5E7EB
Border Radius: 12px
Padding: 24px
Box Shadow: 0px 1px 3px rgba(0, 0, 0, 0.1)
```
**Hover (Interactive):**
```
Box Shadow: 0px 4px 12px rgba(0, 0, 0, 0.08)
Transition: 150ms
```
#### Task Card
```
Padding: 16px
Border Radius: 12px
Background: #FFFFFF
Border: 1px #E5E7EB
Estrutura:
├── Checkbox (20px × 20px)
├── Conteúdo (Flex: 1)
│ ├── Título: 14px Bold, #000000
│ └── Descrição: 13px Regular, #6B7280
└── Menu/Delete: 24px × 24px (Right)
Spacing: 12px entre elementos
```
---
### 4⃣ **CHECKBOX & RADIO**
#### Checkbox
```
Tamanho: 20px × 20px
Border: 2px #E5E7EB
Border Radius: 4px
Background: #FFFFFF
Padding: 2px (interno)
```
**Estados:**
- **Unchecked**: Border #E5E7EB, Background #FFFFFF
- **Checked**: Border #2563EB, Background #2563EB, Ícone ✓ branco
- **Focus**: Box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1)
- **Disabled**: Border #E5E7EB, Background #F3F4F6
---
### 5⃣ **TABS**
```
Height: 48px
Font: Inter 14px SemiBold
Color: #6B7280 (inactive), #2563EB (active)
Border Bottom: 2px #2563EB (active)
Padding: 16px horizontal
```
---
### 6⃣ **MODALS/DIALOGS**
```
Background: #FFFFFF
Border Radius: 16px
Padding: 32px
Width: 90% (mobile), 520px (desktop)
Max Height: 90vh
Box Shadow: 0px 20px 25px rgba(0, 0, 0, 0.15)
Overlay: rgba(0, 0, 0, 0.5)
```
**Estrutura:**
```
├── Header
│ ├── Título: H2
│ └── Close button: 24px (top right)
├── Content
│ └── Padding: 24px 0
└── Footer (Actions)
├── Button Secondary (Cancel): Left
└── Button Primary (Confirm): Right
└── Spacing: 12px entre botões
```
---
### 7⃣ **ÍCONES (Google Icons)**
Link: https://fonts.google.com/icons
**Tamanhos Padrão:**
- **Small**: 16px - Lado de inputs, help text
- **Normal**: 20px - Ícones em botões, menus
- **Large**: 24px - Ícones principais, headers
- **XL**: 32px - Ícones de estado vazio, sucesso
**Cor Principal**: #2563EB
**Cor Secundária**: #6B7280
**Cor Erro**: #EF4444
**Ícones Recomendados:**
- check_circle (Concluído)
- radio_button_unchecked (Não concluído)
- delete (Deletar)
- edit (Editar)
- close (Fechar)
- menu (Menu)
- search (Buscar)
- add (Adicionar)
- logout (Sair)
- login (Entrar)
- person (Perfil)
- error (Erro)
- warning (Aviso)
- info (Info)
---
## 📱 **NEXT.JS - Estrutura de Componentes**
### Diretório
```
frontend-next/
├── src/
│ ├── components/
│ │ ├── ui/
│ │ │ ├── Button.tsx
│ │ │ ├── Input.tsx
│ │ │ ├── Card.tsx
│ │ │ ├── Checkbox.tsx
│ │ │ ├── Modal.tsx
│ │ │ ├── Toast.tsx
│ │ │ └── Spinner.tsx
│ │ ├── forms/
│ │ │ ├── TaskForm.tsx
│ │ │ ├── LoginForm.tsx
│ │ │ └── SignupForm.tsx
│ │ ├── tasks/
│ │ │ ├── TaskItem.tsx
│ │ │ ├── TaskList.tsx
│ │ │ └── TaskFilters.tsx
│ │ ├── layout/
│ │ │ ├── Header.tsx
│ │ │ ├── Sidebar.tsx
│ │ │ └── Footer.tsx
│ │ └── common/
│ │ ├── EmptyState.tsx
│ │ └── LoadingState.tsx
│ ├── lib/
│ │ ├── styles/
│ │ │ ├── colors.ts
│ │ │ ├── spacing.ts
│ │ │ ├── typography.ts
│ │ │ └── shadows.ts
│ │ └── utils.ts
│ ├── app/
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.tsx
│ │ ├── (auth)/
│ │ │ ├── login/page.tsx
│ │ │ └── signup/page.tsx
│ │ └── (dashboard)/
│ │ └── tasks/page.tsx
│ └── styles/
│ └── tailwind.config.ts
```
### Configuração Tailwind (tailwind.config.ts)
```typescript
import type { Config } from 'tailwindcss'
export default {
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#2563EB',
dark: '#1D4ED8',
light: '#DBEAFE',
},
gray: {
50: '#F9FAFB',
100: '#F3F4F6',
200: '#E5E7EB',
400: '#9CA3AF',
600: '#4B5563',
},
status: {
success: '#10B981',
warning: '#F59E0B',
error: '#EF4444',
info: '#06B6D4',
},
},
fontFamily: {
inter: ['var(--font-inter)', 'sans-serif'],
poppins: ['var(--font-poppins)', 'sans-serif'],
},
fontSize: {
'h1': ['32px', { lineHeight: '40px', fontWeight: '700', letterSpacing: '-0.5px' }],
'h2': ['24px', { lineHeight: '32px', fontWeight: '700', letterSpacing: '-0.3px' }],
'h3': ['18px', { lineHeight: '28px', fontWeight: '600', letterSpacing: '-0.2px' }],
'body-lg': ['16px', { lineHeight: '24px', fontWeight: '400' }],
'body': ['14px', { lineHeight: '22px', fontWeight: '400' }],
'body-sm': ['12px', { lineHeight: '18px', fontWeight: '400', letterSpacing: '0.2px' }],
'label': ['12px', { lineHeight: '18px', fontWeight: '600', letterSpacing: '0.5px' }],
'btn': ['14px', { lineHeight: '20px', fontWeight: '600', letterSpacing: '0.5px' }],
},
spacing: {
'xs': '4px',
'sm': '8px',
'md': '12px',
'lg': '16px',
'xl': '24px',
'2xl': '32px',
'3xl': '48px',
'4xl': '64px',
},
borderRadius: {
'sm': '4px',
'md': '8px',
'lg': '12px',
'xl': '16px',
},
boxShadow: {
'sm': '0px 1px 3px rgba(0, 0, 0, 0.1)',
'md': '0px 4px 12px rgba(0, 0, 0, 0.08)',
'lg': '0px 20px 25px rgba(0, 0, 0, 0.15)',
'focus': '0 0 0 3px rgba(37, 99, 235, 0.1)',
},
},
},
plugins: [],
} satisfies Config
```
---
## 🚀 **FLUTTER - Design System**
### Diretório
```
mobile/
├── lib/
│ ├── config/
│ │ ├── theme.dart
│ │ ├── colors.dart
│ │ ├── typography.dart
│ │ └── spacing.dart
│ ├── widgets/
│ │ ├── buttons/
│ │ │ ├── primary_button.dart
│ │ │ ├── secondary_button.dart
│ │ │ └── tertiary_button.dart
│ │ ├── inputs/
│ │ │ ├── text_input.dart
│ │ │ ├── checkbox_input.dart
│ │ │ └── form_field.dart
│ │ ├── cards/
│ │ │ ├── task_card.dart
│ │ │ └── card.dart
│ │ ├── common/
│ │ │ ├── modal.dart
│ │ │ ├── empty_state.dart
│ │ │ └── loading_state.dart
│ │ └── app/
│ │ ├── app_bar.dart
│ │ └── bottom_nav.dart
│ ├── screens/
│ │ ├── auth/
│ │ │ ├── login_screen.dart
│ │ │ └── signup_screen.dart
│ │ ├── tasks/
│ │ │ ├── tasks_screen.dart
│ │ │ ├── task_detail_screen.dart
│ │ │ └── create_task_screen.dart
│ │ └── profile/
│ │ └── profile_screen.dart
│ └── main.dart
```
### Colors (colors.dart)
```dart
abstract class AppColors {
// Primary
static const Color primary = Color(0xFF2563EB);
static const Color primaryDark = Color(0xFF1D4ED8);
static const Color primaryLight = Color(0xFFDBEAFE);
// Base
static const Color white = Color(0xFFFFFFFF);
static const Color black = Color(0xFF000000);
// Gray
static const Color gray50 = Color(0xFFF9FAFB);
static const Color gray100 = Color(0xFFF3F4F6);
static const Color gray200 = Color(0xFFE5E7EB);
static const Color gray400 = Color(0xFF9CA3AF);
static const Color gray600 = Color(0xFF4B5563);
// Status
static const Color success = Color(0xFF10B981);
static const Color warning = Color(0xFFF59E0B);
static const Color error = Color(0xFFEF4444);
static const Color info = Color(0xFF06B6D4);
}
```
### Theme (theme.dart)
```dart
import 'package:flutter/material.dart';
import 'colors.dart';
final ThemeData appTheme = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme(
brightness: Brightness.light,
primary: AppColors.primary,
onPrimary: AppColors.white,
secondary: AppColors.gray600,
onSecondary: AppColors.white,
error: AppColors.error,
onError: AppColors.white,
background: AppColors.white,
onBackground: AppColors.black,
surface: AppColors.white,
onSurface: AppColors.black,
),
fontFamily: 'Inter',
textTheme: TextTheme(
displayLarge: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w700,
letterSpacing: -0.5,
fontFamily: 'Poppins',
),
displayMedium: TextStyle(
fontSize: 24,
fontWeight: FontWeight.w700,
letterSpacing: -0.3,
fontFamily: 'Poppins',
),
headlineSmall: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
letterSpacing: -0.2,
fontFamily: 'Poppins',
),
bodyLarge: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
height: 1.5,
),
bodyMedium: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
height: 1.57,
),
bodySmall: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w400,
letterSpacing: 0.2,
height: 1.5,
),
labelMedium: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
letterSpacing: 0.5,
),
),
);
```
### Spacing (spacing.dart)
```dart
abstract class AppSpacing {
static const double xs = 4.0;
static const double sm = 8.0;
static const double md = 12.0;
static const double lg = 16.0;
static const double xl = 24.0;
static const double xxl = 32.0;
static const double xxxl = 48.0;
static const double xxxxl = 64.0;
}
```
### Exemplo de Componente - Primary Button
```dart
class PrimaryButton extends StatelessWidget {
final String label;
final VoidCallback onPressed;
final bool isLoading;
final bool isEnabled;
final IconData? icon;
const PrimaryButton({
required this.label,
required this.onPressed,
this.isLoading = false,
this.isEnabled = true,
this.icon,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: isEnabled && !isLoading ? onPressed : null,
style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary,
disabledBackgroundColor: AppColors.gray200,
padding: EdgeInsets.symmetric(
vertical: AppSpacing.md,
horizontal: AppSpacing.lg,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
elevation: 0,
),
child: isLoading
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation<Color>(
isEnabled ? AppColors.white : AppColors.gray400,
),
),
)
: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (icon != null) ...[
Icon(icon, size: 20),
SizedBox(width: AppSpacing.sm),
],
Text(label),
],
),
);
}
}
```
---
## 🎯 **PADRÕES DE LAYOUT**
### Responsividade Next.js
```
Mobile: < 640px (default)
Tablet: 640px - 1024px
Desktop: > 1024px
```
### Breakpoints (Tailwind)
```typescript
sm: '640px'
md: '768px'
lg: '1024px'
xl: '1280px'
2xl: '1536px'
```
### Safe Area (Flutter)
```dart
Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: EdgeInsets.all(AppSpacing.lg),
child: YourContent(),
),
),
)
```
---
## 📐 **ANIMAÇÕES & TRANSIÇÕES**
### Next.js (Tailwind)
```
Duration padrão: 150ms
Easing: cubic-bezier(0.4, 0, 0.2, 1)
Propriedades: transform, opacity, color, box-shadow
```
**Exemplo:**
```css
.button {
@apply transition-all duration-150 ease-in-out;
}
.button:hover {
@apply scale-105 shadow-md;
}
```
### Flutter
```dart
Duration animationDuration = Duration(milliseconds: 150);
Curve animationCurve = Curves.easeInOut;
```
---
## ✅ **ACESSIBILIDADE**
### Contraste de Cores (WCAG AA)
- Ratio mínimo: 4.5:1 para textos normais
- Ratio mínimo: 3:1 para textos grandes
### Next.js
- Usar `<label htmlFor="">` para inputs
- Alt text em imagens
- Semantic HTML (button, form, etc)
### Flutter
- Semantics widget para leitura de tela
- Sufficient touch targets (mínimo 48x48 dp)
---
## 📋 **CHECKLIST DE DESIGN**
- [ ] Cores aplicadas conforme paleta
- [ ] Tipografia usando Inter e Poppins
- [ ] Espaçamento em múltiplos de 8px
- [ ] Componentes com 4 estados (default, hover, active, disabled)
- [ ] Ícones do Google Icons (20px padrão)
- [ ] Botões com altura mínima de 48px
- [ ] Inputs com altura de 44px
- [ ] Cards com border-radius 12px
- [ ] Box shadows consistentes
- [ ] Responsive design funcional
- [ ] Acessibilidade testada
- [ ] Loading states em todas as ações
- [ ] Error states claros
- [ ] Empty states amigáveis
---
## 🔗 **REFERÊNCIAS & RECURSOS**
### Ferramentas
- **Figma**: Para prototipar (opcional)
- **Google Fonts**: https://fonts.google.com
- **Google Icons**: https://fonts.google.com/icons
- **Color Checker**: https://webaim.org/resources/contrastchecker/
### Documentação
- **Tailwind CSS**: https://tailwindcss.com/docs
- **Next.js**: https://nextjs.org/docs
- **Flutter**: https://flutter.dev/docs
- **Material Design 3**: https://m3.material.io/
---
## 💾 **IMPLEMENTAÇÃO IMEDIATA**
### Next.js - Setup Inicial
1. Configurar Tailwind config com tokens
2. Criar componentes base (Button, Input, Card)
3. Importar Google Fonts em globals.css
4. Testar componentes em storybook (opcional)
### Flutter - Setup Inicial
1. Adicionar Google Fonts package
2. Criar arquivos de theme
3. Implementar componentes customizados
4. Testar em multiple devices
---
**Mantém Fidelidade ao Design em TODAS as screens! 🎯**