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

19 KiB
Raw Permalink Blame History

🎨 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

Fonte Secundária: Poppins

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

@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)

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)

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)

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)

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

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)

sm: '640px'
md: '768px'
lg: '1024px'
xl: '1280px'
2xl: '1536px'

Safe Area (Flutter)

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:

.button {
  @apply transition-all duration-150 ease-in-out;
}

.button:hover {
  @apply scale-105 shadow-md;
}

Flutter

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

Documentação


💾 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! 🎯