> For the complete documentation index, see [llms.txt](https://doc.sysdevmobile.com/mss-extensibility/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://doc.sysdevmobile.com/mss-extensibility/mss-5.1/myteam.md).

# myTeam

O myTeam disponibiliza dois mecanismos de extensibilidade que permitem integrar conteúdos externos diretamente na aplicação:

* **Extensibilidade de Tabs** — Adiciona separadores personalizados dentro de ecrãs existentes (ex.: ficha de entidade, monitor de vendas).
* **Extensibilidade de Menu** — Adiciona entradas de menu na barra lateral que abrem páginas externas dentro da aplicação.

Ambos os mecanismos partilham o mesmo modelo de comunicação: o myTeam faz um pedido **HTTP POST** ao URL externo configurado, enviando dados de autenticação e contexto. O serviço externo valida a autenticação, processa o pedido e devolve uma página HTML completa que é apresentada num iframe dentro do myTeam.

O serviço externo pode ser implementado em **qualquer linguagem ou framework web** (ASP.NET, Node.js, PHP, Python, Java, etc.), desde que consiga receber pedidos HTTP POST e devolver HTML.

### Exemplos Práticos

Para exemplos práticos de payloads para cada cenário, consulte:

* [Entities Tab](/mss-extensibility/mss-5.1/myteam/entities-tab.md) - Payloads para a ficha de entidade (ENTD)
* [Monitors Tab](/mss-extensibility/mss-5.1/myteam/monitors-tab.md) - Payloads para monitores de vendas (MVND) e encomendas (MENC)
* [Menu Extensibility](/mss-extensibility/mss-5.1/myteam/menu-extensibility.md) - Payloads para extensibilidade de menu

### Arquitetura Geral

O fluxo de comunicação entre o myTeam e o serviço externo:

1. O utilizador interage com o myTeam (clica num tab ou entrada de menu).
2. O browser envia um **HTTP POST** (via JavaScript) ao URL externo configurado.
3. O serviço externo recebe o pedido, valida a autenticação e processa os dados.
4. O serviço externo devolve uma página HTML completa (status 200).
5. O myTeam apresenta o HTML devolvido dentro de um iframe.

```
┌──────────────────────────────────────────────────┐
│               myTeam (Browser)                   │
│                                                  │
│   Utilizador clica num tab / menu                │
│         │                                        │
│         ▼                                        │
│   JavaScript envia HTTP POST                     │
│         │                                        │
│   ┌─────────────────────────────────────────┐    │
│   │              iframe                     │    │
│   │  HTML devolvido pelo serviço externo    │    │
│   └─────────────────────────────────────────┘    │
└──────────────────────────────────────────────────┘
              │ HTTP POST (payload)
              ▼
┌──────────────────────────────────────────────────┐
│          Serviço Externo (Parceiro)              │
│                                                  │
│   1. Recebe payload (autenticação + filtros)     │
│   2. Valida credenciais                          │
│   3. Processa dados de negócio                   │
│   4. Devolve página HTML (status 200)            │
└──────────────────────────────────────────────────┘
```

### Protocolo de Comunicação

#### Pedido (POST)

#### Estrutura do Payload

```json
{
  "authentication": {
    "user": "admin",
    "hash": "a1b2c3d4..."
  },
  "filter": {
    "chave1": "valor1",
    "chave2": "valor2"
  }
}
```

#### Campo `authentication`

| Campo  | Tipo   | Descrição                                                      |
| ------ | ------ | -------------------------------------------------------------- |
| `user` | string | Código do utilizador com sessão ativa no myTeam (campo USRUSR) |
| `hash` | string | Hash da password do utilizador (campo USRPWD da tabela MSUSR)  |

#### Campo `filter`

Contém pares chave-valor com informação de contexto. Os filtros variam consoante o tipo de extensibilidade e a configuração. Consulte as secções específicas para detalhes:

**Extensibilidade de Tabs:**

<table><thead><tr><th width="245.20001220703125">Módulo</th><th width="143.4000244140625">Código</th><th>Filtros disponíveis</th></tr></thead><tbody><tr><td>Ficha de Entidade</td><td>ENTD</td><td><code>entityId</code></td></tr><tr><td>Monitor de Vendas</td><td>MVND</td><td><code>currentStartDate</code>, <code>currentEndDate</code>, <code>previousStartDate</code>, <code>previousEndDate</code>, <code>relativeData</code></td></tr><tr><td>Monitor de Encomendas</td><td>MENC</td><td>Iguais ao Monitor de Vendas</td></tr></tbody></table>

**Extensibilidade de Menu:**

A extensibilidade de menu não envia filtros adicionais — o campo `filter` é sempre um objeto vazio `{}`. A identificação do utilizador é feita através do campo `authentication`, e o serviço externo pode consultar a tabela `MSUSR` para obter qualquer informação adicional sobre o utilizador (nome, código de vendedor, etc.).

### Resposta

O serviço externo deve devolver:

| Elemento     | Requisito                                               |
| ------------ | ------------------------------------------------------- |
| Status code  | `200 OK` para sucesso                                   |
| Content-Type | `text/html`                                             |
| Body         | Página HTML completa (com `<html>`, `<head>`, `<body>`) |

O HTML devolvido deve ser **autocontido** — com os seus próprios estilos CSS, scripts e referências a recursos.

{% hint style="info" %}
O myTeam injeta automaticamente uma tag `<base>` no HTML devolvido, apontando para o diretório do URL externo. Isto permite que referências relativas a CSS, imagens e scripts sejam resolvidas corretamente.
{% endhint %}

### Tratamento de Erros

O myTeam trata automaticamente os seguintes cenários:

| Cenário                 | Comportamento                        |
| ----------------------- | ------------------------------------ |
| Status 401 / 403        | Mensagem de erro de autenticação     |
| Status 4xx / 5xx        | Mensagem de erro genérica do serviço |
| Resposta vazia (200)    | Mensagem de "sem resposta"           |
| Timeout (> 30 segundos) | Mensagem de timeout                  |
| Serviço indisponível    | Mensagem de erro de ligação          |

***

### Autenticação

O serviço externo é responsável por validar a autenticação em **cada pedido** (modelo stateless):

1. Extrair `user` e `hash` do campo `authentication` do payload.
2. Consultar a tabela `MSUSR` da base de dados do myTeam.
3. Verificar que existe um registo com `USRUSR = user` e `USRPWD = hash`.

Se a validação falhar, o serviço deve devolver um **status HTTP 401**.

#### Acesso à Base de Dados

O serviço externo necessita de acesso de **leitura** à base de dados do myTeam para:

* Validar credenciais (tabela `MSUSR`).
* Consultar dados de negócio conforme necessário (tabelas `STMSCLI`, `STMSDCC`, etc.).

A connection string deve ser configurada no serviço externo e apontar para a mesma base de dados utilizada pelo myTeam.

***

### Extensibilidade de Tabs

Permite adicionar separadores personalizados dentro de ecrãs existentes. Cada tab carrega conteúdo externo via iframe quando o utilizador o seleciona.

#### Módulos Disponíveis

<table><thead><tr><th width="227.800048828125">Módulo</th><th width="164.2000732421875">Código</th><th>Filtros enviados</th></tr></thead><tbody><tr><td>Ficha de Entidade</td><td>ENTD</td><td><code>entityId</code> — Código da entidade aberta</td></tr><tr><td>Monitor de Vendas</td><td>MVND</td><td><code>currentStartDate</code>, <code>currentEndDate</code>, <code>previousStartDate</code>, <code>previousEndDate</code>, <code>relativeData</code></td></tr><tr><td>Monitor de Encomendas</td><td>MENC</td><td>Iguais ao Monitor de Vendas</td></tr></tbody></table>

### Configuração

Ecrã de administração **"Extensibilidade de tabs"** (Módulo 161):

1. Criar um novo tab, selecionando o módulo destino (ENTD, MVND ou MENC).
2. Definir o URL do serviço externo.
3. Definir o nome do tab (com traduções para os idiomas: PT, EN, ES, FR).
4. Definir a ordem de apresentação.
5. Ativar ou desativar o tab conforme necessário.

### Comportamento

* O tab aparece como separador adicional dentro do ecrã configurado.
* Ao clicar no tab, o myTeam faz POST ao URL externo com autenticação e filtros de contexto da página.
* O conteúdo devolvido é carregado no iframe do tab.
* O tab é carregado apenas quando selecionado (lazy loading).

***

### Extensibilidade de Menu

Permite adicionar entradas na barra lateral de navegação do myTeam. Ao clicar, o utilizador navega para uma página dedicada dentro da aplicação que apresenta o conteúdo externo em iframe.

#### Configuração

Ecrã de administração **"Menu de extensibilidade"** (Módulo 89):

1. Criar uma nova entrada de menu com nome, URL, posição e ícone (opcional).
2. Atribuir utilizadores com acesso à entrada, ou definir como disponível para todos.

#### Payload

Na extensibilidade de menu, o campo `filter` é sempre um objeto vazio `{}`. A identificação do utilizador é feita exclusivamente pelo campo `authentication`. O serviço externo pode consultar a tabela `MSUSR` para obter dados adicionais do utilizador (nome, código de vendedor, etc.).

#### Comportamento

* A entrada aparece na barra lateral de navegação, com ícone e nome configurados.
* Ao clicar, o utilizador navega para uma página dentro do myTeam.
* A página apresenta o conteúdo externo em iframe de ecrã inteiro.
* O nome da entrada é apresentado no cabeçalho da página.
* A navegação do browser (voltar/avançar) funciona normalmente.
* O acesso é protegido por permissões — apenas utilizadores autorizados podem aceder.

***

### CORS

Como o pedido é feito pelo browser via JavaScript (`fetch`), o serviço externo deve permitir pedidos cross-origin:

| Header                         | Valor                                                       |
| ------------------------------ | ----------------------------------------------------------- |
| `Access-Control-Allow-Origin`  | Origem do myTeam (ex.: `https://myteam.empresa.com`) ou `*` |
| `Access-Control-Allow-Methods` | `POST`                                                      |
| `Access-Control-Allow-Headers` | `Content-Type`                                              |

### Guia de Implementação

#### 1. Criar o Endpoint

Criar um endpoint HTTP que aceite **POST** e leia o parâmetro `payload` do body:

```
FUNÇÃO HandleRequest(pedido):

    // 1. Ler payload do body
    payloadJson = pedido.FormData["payload"]
    payload = JSON.Parse(payloadJson)

    // 2. Validar autenticação
    utilizador = ConsultarBD(
        "SELECT * FROM MSUSR WHERE USRUSR = ? AND USRPWD = ?",
        payload.authentication.user,
        payload.authentication.hash
    )

    SE utilizador == null:
        DEVOLVER StatusCode(401)

    // 3. Ler filtros de contexto (apenas para extensibilidade de tabs)
    entityId = payload.filter["entityId"]

    // 4. Processar dados de negócio
    dados = ConsultarDados(entityId, ...)

    // 5. Devolver página HTML
    html = GerarPaginaHTML(dados)
    DEVOLVER StatusCode(200), ContentType("text/html"), Body(html)
```

#### 2. Estruturar o HTML de Resposta

A página HTML devolvida deve ser autocontida:

```html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <style>
        body { font-family: sans-serif; margin: 16px; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 8px; border: 1px solid #e0e0e0; }
        th { background: #f5f5f5; }
    </style>
</head>
<body>
    <h3>Informação do Cliente</h3>
    <table>
        <tr><th>Código</th><td>CLI001</td></tr>
        <tr><th>Nome</th><td>Empresa Exemplo, Lda.</td></tr>
        <tr><th>NIF</th><td>123456789</td></tr>
    </table>
</body>
</html>
```

#### 3. Configurar CORS

Garantir que o serviço permite pedidos cross-origin com o header `Access-Control-Allow-Origin` adequado.

#### 4. Registar no myTeam

Utilizar o ecrã de administração correspondente para registar o URL do endpoint e atribuir permissões.

#### 5. Testar

* Verificar que o endpoint responde corretamente a um POST com payload de teste.
* No myTeam, aceder ao tab ou entrada de menu configurada.
* Confirmar que o conteúdo é apresentado corretamente dentro da aplicação.
* Testar cenários de erro: serviço indisponível, credenciais inválidas, resposta vazia.

***

### Comparação entre Tab e Menu

| Aspeto              | Extensibilidade de Tab                | Extensibilidade de Menu                     |
| ------------------- | ------------------------------------- | ------------------------------------------- |
| Onde aparece        | Separador dentro de um ecrã existente | Entrada na barra lateral de navegação       |
| Módulos disponíveis | ENTD, MVND, MENC                      | Qualquer (entrada independente)             |
| Filtros de contexto | Específicos do ecrã (entityId, datas) | Nenhum (filter vazio)                       |
| Configuração        | Módulo 161 — Extensibilidade de tabs  | Módulo 89 — Menu de extensibilidade         |
| Comportamento       | Carrega dentro do ecrã atual          | Navega para nova página dentro da aplicação |
| Multi-idioma        | Sim (nome do tab traduzido)           | Não (nome único)                            |

### Requisitos Técnicos

<table><thead><tr><th width="109">#</th><th width="244.60003662109375">Requisito</th><th>Detalhe</th></tr></thead><tbody><tr><td>1</td><td>Endpoint HTTP POST</td><td>Capaz de receber <code>application/x-www-form-urlencoded</code> com o parâmetro <code>payload</code></td></tr><tr><td>2</td><td>Parsing de JSON</td><td>Para extrair autenticação e filtros do payload</td></tr><tr><td>3</td><td>Acesso à BD do myTeam</td><td>Leitura da tabela MSUSR (mínimo para autenticação) e restantes tabelas conforme necessidade</td></tr><tr><td>4</td><td>Resposta HTML</td><td>Página completa, autocontida, com status 200</td></tr><tr><td>5</td><td>CORS</td><td>Headers de permissão para pedidos cross-origin</td></tr><tr><td>6</td><td>HTTPS</td><td>Recomendado em ambientes de produção</td></tr></tbody></table>
