# Compliance Map
## PharmData Design System - Acessibilidade & Segurança

> **Objetivo**: Checklist incremental para garantir conformidade WCAG AAA e práticas de segurança

---

## Índice

1. [Visão Geral](#visão-geral)
2. [Acessibilidade (WCAG AAA)](#acessibilidade-wcag-aaa)
3. [Segurança](#segurança)
4. [Performance](#performance)
5. [SEO e Semântica](#seo-e-semântica)
6. [Ferramentas de Teste](#ferramentas-de-teste)

---

## Visão Geral

### O que o Design System declara

O PharmData Design System estabelece os seguintes compromissos:

| Área | Padrão | Meta |
|------|--------|------|
| **Contraste de Cores** | WCAG AAA | Mínimo 7:1 para texto normal |
| **Navegação por Teclado** | 100% acessível | Todos os componentes |
| **Screen Readers** | NVDA + JAWS | Semântica HTML + ARIA |
| **Segurança** | OWASP Top 10 | Proteção contra XSS, CSRF, SQL Injection |
| **Logging** | Auditoria completa | Todas as ações de curadoria |

### Responsabilidades

| Responsabilidade | Design System | Desenvolvedor |
|------------------|---------------|---------------|
| Cores com contraste adequado | ✅ Definido | ✅ Aplicar |
| HTML semântico | ✅ Exemplos | ✅ Implementar |
| ARIA attributes | ✅ Exemplos | ✅ Implementar |
| Focus states | ✅ CSS pronto | ✅ Não sobrescrever |
| Validação server-side | ❌ N/A | ✅ Implementar |
| Rate limiting | ❌ N/A | ✅ Implementar |
| HTTPS | ❌ N/A | ✅ Infraestrutura |

---

## Acessibilidade (WCAG AAA)

### 1. Contraste de Cores

#### O que o DS fornece

Todas as cores do DS já atendem WCAG AAA:

| Combinação | Contraste | Status |
|------------|-----------|--------|
| `graphite-depth` (#1F2937) em `cloud` (#F9FAFB) | 10.5:1 | ✅ AAA |
| `soft-steel` (#374151) em `cloud` (#F9FAFB) | 8.1:1 | ✅ AAA |
| Texto branco em `emerald-abyss` (#0B2D2A) | 12:1 | ✅ AAA |
| Texto branco em `teal-intense` (#2AA198) | 4.8:1 | ✅ AA (botões) |

#### Checklist de Implementação

- [ ] Usar apenas cores do DS para texto
- [ ] Nunca usar `text-soft-steel` em backgrounds claros que não sejam `cloud`
- [ ] Testar contraste com ferramenta (WebAIM Contrast Checker)
- [ ] Para texto customizado, garantir mínimo 7:1 (AAA) ou 4.5:1 (AA para large text)

#### Snippet de Teste

```html
<!-- ✅ CORRETO: Contraste AAA -->
<p class="text-graphite-depth bg-cloud">Texto legível</p>

<!-- ❌ EVITAR: Contraste insuficiente -->
<p class="text-soft-steel bg-arctic-mist">Pode não atingir AAA</p>
```

---

### 2. Navegação por Teclado

#### O que o DS fornece

- Focus rings visíveis em todos os componentes interativos
- Estilos `focus:ring-2 focus:ring-teal-intense focus:ring-offset-2`

#### Checklist de Implementação

##### Botões e Links

- [ ] Todos os `<button>` e `<a>` são alcançáveis via Tab
- [ ] Ordem de tabulação segue ordem visual (não usar `tabindex` positivo)
- [ ] Focus ring nunca removido (`outline: none` apenas se substituído por alternativa)
- [ ] Ações via Enter/Space funcionam em botões customizados

```html
<!-- ✅ CORRETO -->
<button class="btn-primary focus:ring-2 focus:ring-teal-intense">
  Salvar
</button>

<!-- ❌ EVITAR -->
<div onclick="save()" class="btn-primary">Salvar</div>
```

##### Forms

- [ ] Todos os inputs têm `<label>` associado via `for`/`id`
- [ ] Campos obrigatórios marcados com `aria-required="true"` ou `required`
- [ ] Mensagens de erro associadas via `aria-describedby`

```html
<!-- ✅ CORRETO -->
<div>
  <label for="substance-name">Nome <span class="text-error">*</span></label>
  <input
    id="substance-name"
    type="text"
    required
    aria-required="true"
    aria-describedby="name-error"
  />
  <p id="name-error" class="text-error" role="alert">Campo obrigatório</p>
</div>
```

##### Modais e Overlays

- [ ] Focus trap: Tab não escapa do modal enquanto aberto
- [ ] Fechar modal com Esc
- [ ] Focus retorna ao elemento que abriu o modal após fechar

```javascript
// Exemplo de focus trap
const modal = document.getElementById('modal');
const focusableElements = modal.querySelectorAll('button, a, input, [tabindex]:not([tabindex="-1"])');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];

modal.addEventListener('keydown', (e) => {
  if (e.key === 'Tab') {
    if (e.shiftKey && document.activeElement === firstElement) {
      e.preventDefault();
      lastElement.focus();
    } else if (!e.shiftKey && document.activeElement === lastElement) {
      e.preventDefault();
      firstElement.focus();
    }
  }

  if (e.key === 'Escape') {
    closeModal();
  }
});
```

---

### 3. Screen Readers

#### O que o DS fornece

- Exemplos com HTML semântico correto
- ARIA labels em componentes que precisam

#### Checklist de Implementação

##### Semântica HTML

- [ ] Usar elementos corretos: `<button>`, `<nav>`, `<main>`, `<article>`, etc.
- [ ] Não usar `<div>` para elementos clicáveis
- [ ] Headers (`<h1>`, `<h2>`, `<h3>`) em ordem hierárquica

```html
<!-- ✅ CORRETO -->
<main>
  <h1>Substâncias</h1>
  <article>
    <h2>Paracetamol</h2>
    <p>Descrição...</p>
  </article>
</main>

<!-- ❌ EVITAR -->
<div>
  <div class="text-h1">Substâncias</div>
  <div>
    <div class="text-h2">Paracetamol</div>
    <div>Descrição...</div>
  </div>
</div>
```

##### ARIA Attributes

- [ ] `aria-label` em botões icon-only
- [ ] `aria-describedby` para associar ajuda contextual
- [ ] `aria-live` para notificações dinâmicas (toasts)
- [ ] `role="alert"` para mensagens de erro

```html
<!-- Icon button -->
<button aria-label="Editar substância">
  <i class="fas fa-edit"></i>
</button>

<!-- Toast notification -->
<div id="toast" role="status" aria-live="polite" aria-atomic="true">
  Substância salva com sucesso
</div>

<!-- Error message -->
<p id="error-msg" role="alert" class="text-error">
  Fórmula molecular inválida
</p>
```

##### Landmarks

- [ ] Usar `<header>`, `<nav>`, `<main>`, `<aside>`, `<footer>`
- [ ] Se múltiplas `<nav>`, usar `aria-label` para diferenciar

```html
<header>
  <nav aria-label="Navegação principal">...</nav>
</header>

<main>
  <aside aria-label="Filtros">...</aside>
</main>
```

---

### 4. Texto Alternativo para Imagens

- [ ] Todas as imagens têm `alt`
- [ ] Imagens decorativas: `alt=""` (vazio, não omitir)
- [ ] Imagens informativas: `alt` descritivo

```html
<!-- Imagem informativa -->
<img src="molecular-structure.png" alt="Estrutura molecular do Paracetamol (C8H9NO2)" />

<!-- Imagem decorativa -->
<img src="logo-decoration.svg" alt="" />
```

---

### 5. Animações e Movimento

#### O que o DS fornece

```css
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
  }
}
```

#### Checklist de Implementação

- [ ] Respeitar `prefers-reduced-motion`
- [ ] Animações nunca são essenciais para compreensão
- [ ] Autoplay de vídeos/carrosséis pode ser pausado

---

## Segurança

### 1. Validação de Dados

#### Server-Side (Flask)

**Checklist**:

- [ ] **NUNCA confiar em dados do cliente**
- [ ] Validar TODOS os inputs no servidor
- [ ] Usar WTForms ou Marshmallow para validação
- [ ] Sanitizar dados antes de inserir no banco

**Exemplo**:

```python
from flask_wtf import FlaskForm
from wtforms import StringField, validators

class SubstanceForm(FlaskForm):
    name = StringField('Nome', [
        validators.DataRequired(message='Nome obrigatório'),
        validators.Length(min=2, max=200, message='Nome deve ter entre 2 e 200 caracteres'),
        validators.Regexp(r'^[A-Za-z0-9\s\-]+$', message='Apenas letras, números, espaços e hífens')
    ])

    cas_number = StringField('CAS Number', [
        validators.Optional(),
        validators.Regexp(r'^\d{2,7}-\d{2}-\d$', message='Formato CAS inválido')
    ])

@bp.route('/substances', methods=['POST'])
def create_substance():
    form = SubstanceForm()

    if not form.validate():
        return jsonify({'errors': form.errors}), 400

    # Sanitize
    name = bleach.clean(form.name.data)
    cas = bleach.clean(form.cas_number.data)

    # Insert into DB usando ORM (proteção contra SQL injection)
    substance = Substance(name=name, cas_number=cas)
    db.session.add(substance)
    db.session.commit()

    return jsonify({'id': substance.id}), 201
```

---

### 2. Proteção contra XSS

**Checklist**:

- [ ] Usar template engine com auto-escape (Jinja2 ✅)
- [ ] NUNCA usar `| safe` sem sanitizar antes
- [ ] Sanitizar HTML com `bleach` se necessário aceitar HTML

**Exemplo**:

```html
<!-- ✅ CORRETO: Auto-escaped -->
<p>{{ substance.name }}</p>

<!-- ❌ PERIGOSO: Se substance.description vier de usuário -->
<div>{{ substance.description | safe }}</div>

<!-- ✅ CORRETO: Sanitizado no backend -->
<div>{{ substance.description_sanitized | safe }}</div>
```

```python
import bleach

ALLOWED_TAGS = ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li']
ALLOWED_ATTRIBUTES = {}

def sanitize_html(dirty_html):
    return bleach.clean(
        dirty_html,
        tags=ALLOWED_TAGS,
        attributes=ALLOWED_ATTRIBUTES,
        strip=True
    )
```

---

### 3. Proteção contra CSRF

**Checklist**:

- [ ] Usar Flask-WTF com CSRF protection
- [ ] Incluir `{{ form.csrf_token }}` em todos os forms
- [ ] Para HTMX, incluir token em meta tag

**Setup Flask**:

```python
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
csrf = CSRFProtect(app)
```

**Template base**:

```html
<head>
  <meta name="csrf-token" content="{{ csrf_token() }}">
</head>

<body hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'>
```

**Form**:

```html
<form method="POST">
  {{ form.csrf_token }}
  <!-- fields -->
</form>
```

---

### 4. Proteção contra SQL Injection

**Checklist**:

- [ ] SEMPRE usar ORM (SQLAlchemy)
- [ ] NUNCA concatenar strings para queries
- [ ] Se SQL raw necessário, usar parameterized queries

```python
# ✅ CORRETO: ORM
Substance.query.filter_by(name=user_input).first()

# ✅ CORRETO: Parameterized
db.session.execute(
    text("SELECT * FROM substances WHERE name = :name"),
    {"name": user_input}
)

# ❌ PERIGOSO: Concatenação
db.session.execute(f"SELECT * FROM substances WHERE name = '{user_input}'")
```

---

### 5. Rate Limiting

**Checklist**:

- [ ] Limitar requisições por IP (Flask-Limiter)
- [ ] Especialmente em: login, registro, APIs públicas

**Exemplo**:

```python
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)

@bp.route('/login', methods=['POST'])
@limiter.limit("5 per minute")
def login():
    # ...
```

---

### 6. HTTPS e Cookies Seguros

**Checklist**:

- [ ] Forçar HTTPS em produção
- [ ] Cookies com flags: `Secure`, `HttpOnly`, `SameSite`

```python
app.config.update(
    SESSION_COOKIE_SECURE=True,      # Apenas HTTPS
    SESSION_COOKIE_HTTPONLY=True,    # Inacessível via JS
    SESSION_COOKIE_SAMESITE='Lax',   # CSRF protection
)
```

---

### 7. Logging e Auditoria

**Checklist**:

- [ ] Log todas as ações de curadoria (create, update, delete)
- [ ] Log tentativas de acesso negado
- [ ] Armazenar: timestamp, usuário, ação, dados alterados

**Exemplo**:

```python
import logging
from datetime import datetime

audit_logger = logging.getLogger('audit')

def log_curation_action(user_id, action, substance_id, changes):
    audit_logger.info({
        'timestamp': datetime.utcnow().isoformat(),
        'user_id': user_id,
        'action': action,  # 'create', 'update', 'approve'
        'substance_id': substance_id,
        'changes': changes,
        'ip': request.remote_addr
    })

@bp.route('/substances/<id>', methods=['PUT'])
def update_substance(id):
    # ... validação e update ...

    log_curation_action(
        user_id=current_user.id,
        action='update',
        substance_id=id,
        changes={'name': {'old': old_name, 'new': new_name}}
    )
```

---

## Performance

**Checklist**:

- [ ] Minificar CSS/JS em produção
- [ ] Lazy load de imagens: `loading="lazy"`
- [ ] Usar CDN para assets estáticos
- [ ] Compressão gzip/brotli no servidor
- [ ] Cache de assets estáticos (1 ano)

```html
<!-- Lazy loading -->
<img src="large-image.jpg" loading="lazy" alt="..." />
```

---

## SEO e Semântica

**Checklist**:

- [ ] Todas as páginas têm `<title>` único
- [ ] Meta description em páginas principais
- [ ] Headings em ordem hierárquica (H1 → H2 → H3)
- [ ] Links descritivos (evitar "clique aqui")

```html
<head>
  <title>Paracetamol (SUB-082615) - PharmData</title>
  <meta name="description" content="Dados completos sobre Paracetamol: estrutura molecular, propriedades físico-químicas, classificações ATC e SNOMED CT">
</head>
```

---

## Ferramentas de Teste

### Acessibilidade

| Ferramenta | Uso | Link |
|------------|-----|------|
| **axe DevTools** | Extensão browser para testes automáticos | [Chrome](https://chrome.google.com/webstore/detail/axe-devtools-web-accessib/lhdoppojpmngadmnindnejefpokejbdd) |
| **WAVE** | Avaliação visual de acessibilidade | [wave.webaim.org](https://wave.webaim.org/) |
| **Lighthouse** | Auditoria completa (Chrome DevTools) | Built-in Chrome |
| **WebAIM Contrast Checker** | Testar contraste de cores | [webaim.org/resources/contrastchecker](https://webaim.org/resources/contrastchecker/) |
| **NVDA** | Screen reader gratuito (Windows) | [nvaccess.org](https://www.nvaccess.org/) |
| **VoiceOver** | Screen reader built-in (macOS/iOS) | Built-in |

### Segurança

| Ferramenta | Uso |
|------------|-----|
| **OWASP ZAP** | Scan de vulnerabilidades |
| **Bandit** | Static analysis para Python |
| **Safety** | Check de dependências vulneráveis |

```bash
# Check de dependências vulneráveis
pip install safety
safety check

# Static analysis
pip install bandit
bandit -r app/
```

### Performance

| Ferramenta | Uso |
|------------|-----|
| **Lighthouse** | Performance score |
| **WebPageTest** | Análise detalhada de loading |
| **Chrome DevTools** | Network tab, Performance tab |

---

## Checklist Resumido

### Antes de Deploy

#### Acessibilidade
- [ ] Contraste de cores testado (WCAG AAA)
- [ ] Navegação por teclado funcional em todos os componentes
- [ ] Testado com screen reader (NVDA/VoiceOver)
- [ ] Todas as imagens têm `alt`
- [ ] Formulários com labels corretos
- [ ] Focus states visíveis

#### Segurança
- [ ] Validação server-side em todos os inputs
- [ ] CSRF protection ativa
- [ ] XSS protection (auto-escape ativo)
- [ ] SQL injection prevenida (ORM)
- [ ] Rate limiting configurado
- [ ] HTTPS forçado em produção
- [ ] Cookies com flags seguras
- [ ] Logging de auditoria ativo

#### Performance
- [ ] CSS/JS minificados
- [ ] Imagens otimizadas
- [ ] Lazy loading ativo
- [ ] Cache configurado

#### SEO
- [ ] Títulos únicos
- [ ] Meta descriptions
- [ ] Headings hierárquicos
- [ ] Links descritivos

---

**Ferramentas de CI/CD**:

```yaml
# .github/workflows/accessibility-check.yml
name: Accessibility Check

on: [push, pull_request]

jobs:
  a11y:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Run axe
        uses: dequelabs/axe-action@v1
        with:
          urls: |
            http://localhost:5000/substances
            http://localhost:5000/substances/082615
```

---

## Recursos Adicionais

- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/)
- [OWASP Top 10](https://owasp.org/www-project-top-ten/)
- [Flask Security Best Practices](https://flask.palletsprojects.com/en/2.3.x/security/)
- [ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)
