# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://doc.sysdevmobile.com/mss-extensibility/mss-5.1/myteam.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
