# Rally API Integration

Sistema de integração com as APIs de Rally da Anube, com suporte a **gravação e replay** de provas em tempo real.

## Índice

- [Características](#características)
- [Instalação](#instalação)
- [Configuração](#configuração)
- [Sistema de Gravação e Replay](#sistema-de-gravação-e-replay)
- [Endpoints da API](#endpoints-da-api)
- [Arquitetura](#arquitetura)
- [Documentação Completa](DOCUMENTATION.md)

---

## Características

- **Proxy para APIs da Anube** — race, itineraries, specials, participants, chronos2, classification, penalizations
- **Enriquecimento de dados** — combina timing + GPS + dados de participantes num único endpoint
- **Cache inteligente** — dados estáticos em cache por 12h, GPS sempre em tempo real
- **Configuração manual de rally** — introduz o Rally ID diretamente; configuração persistida em ficheiro
- **Gravação completa de provas** — snapshots a cada minuto com todos os dados em tempo real
- **Replay com controlo total** — play, pause, seek, velocidade (1x, 2x, 5x, 10x)
- **Replay transparente** — os mesmos endpoints retornam dados gravados quando replay está ativo, incluindo endpoints genéricos `/:rallyId`
- **Autenticação** — sessão para a interface web, API key para endpoints externos

---

## Instalação

**Pré-requisitos:** Node.js v14+

```bash
npm install
npm start
# Para desenvolvimento com auto-reload:
npm run dev
```

O servidor fica disponível em `http://localhost:10200`

---

## Configuração

### Via Interface Web

1. Acede a `http://localhost:10200`
2. Faz login (credenciais definidas no `.env`)
3. Introduz o **Rally ID** manualmente
4. Seleciona o itinerário e a especial (PEC)
5. Clica em "Guardar Configuração"

A configuração é persistida em `recordings/config.json` e restaurada automaticamente ao reiniciar o servidor ou ao fazer refresh da página.

### Via API

```bash
# Guardar configuração completa
POST /api/config
{
  "rallyId": "312",
  "subId": "456",
  "itineraryId": "789",
  "pecId": "101",
  "rallyName": "Rally de Portugal",
  "specialName": "SS1",
  "mode": "manual",
  "gpsToken": ""        # opcional
}

# Atualizar apenas a especial ativa
POST /api/config/pec
{ "pecId": "102" }

# Obter configuração atual
GET /api/config
```

### Variáveis de Ambiente (.env)

| Variável | Descrição | Default |
|---|---|---|
| `PORT` | Porta do servidor | `10200` |
| `API_KEY` | Chave para endpoints externos | — |
| `WEB_USERNAME` | Utilizador da interface web | `admin` |
| `WEB_PASSWORD` | Password da interface web | `admin` |
| `SESSION_SECRET` | Segredo para sessões | valor padrão |
| `CORS_ORIGIN` | Origens com direito ao cookie de sessão (a leitura é aberta a todas) | `http://localhost:10200` |
| `OWM_API_KEY` | Chave do OpenWeatherMap (meteorologia no /api/info) | — |
| `NODE_ENV` | `production` activa o cookie de sessão Secure | — |
| `HTTP_TIMEOUT_MS` | Timeout de todas as chamadas a APIs externas | `15000` |
| `PARTICIPANTS_TTL_MS` | Frescura da lista de inscritos | `60000` |
| `IN_RACE_TTL_S` | Cache do flag `in_race` (0 desliga) | `5` |

---

## Sistema de Gravação e Replay

### Gravação

O sistema captura snapshots a cada 60 segundos das APIs originais da Anube:

- **Dados estáticos** (gravados uma vez): race, itineraries, specials, participants
- **Dados dinâmicos** (cada minuto): GPS/tracking, penalizations, chronos2 e classification por especial ativa

```bash
# Iniciar gravação (requer API key)
POST /api/recording/start

# Verificar estado
GET /api/recording/status

# Parar gravação
POST /api/recording/stop

# Listar gravações
GET /api/recording/list

# Eliminar gravação
DELETE /api/recording/:recordingId
```

### Replay

Quando o replay está ativo, **todos os endpoints** — tanto `/selected.json` como `/:rallyId.json` — retornam automaticamente os dados gravados em vez de ir à API da Anube. O frontend não precisa de qualquer modificação.

A condição é: o `rallyId` pedido tem de coincidir com o `rallyId` da gravação em replay.

```bash
# Carregar uma gravação
POST /api/replay/start
{ "recordingId": "race_312_2024-01-15T10-30-00", "startMinute": 0 }

# Reproduzir
POST /api/replay/play

# Pausar
POST /api/replay/pause

# Saltar para minuto específico
POST /api/replay/seek
{ "minute": 30 }

# Definir velocidade (1, 2, 5, 10)
POST /api/replay/speed
{ "speed": 2 }

# Selecionar especial no replay
POST /api/replay/select-special
{ "specialId": "101" }

# Estado do replay
GET /api/replay/status

# Parar replay
POST /api/replay/stop
```

---

## Endpoints da API

### Autenticação

| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| POST | `/api/auth/login` | — | Login (sessão web) |
| POST | `/api/auth/logout` | — | Logout |
| GET | `/api/auth/check` | — | Verificar sessão |

### Configuração

| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| GET | `/api/config` | — | Obter configuração atual |
| POST | `/api/config` | Sessão | Guardar configuração completa |
| POST | `/api/config/pec` | Sessão | Atualizar apenas a especial (PEC) |

### Dados de Rally — Selecionado (com cache e replay)

| Método | Endpoint | Replay | Cache | Descrição |
|---|---|---|---|---|
| GET | `/api/race/selected.json` | Sim | 12h | Info da prova |
| GET | `/api/itineraries/selected.json` | Sim | 12h | Itinerários |
| GET | `/api/specials/selected.json` | Sim | 12h | Especiais/etapas |
| GET | `/api/participants/selected.json` | Sim | 12h + GPS live | Participantes + GPS + in_race |
| GET | `/api/sections/selected.json` | Sim | — | Scorings por secção |
| GET | `/api/gps/selected.json` | Sim | — | GPS em tempo real |
| GET | `/api/penalizations/selected.json` | Sim | — | Penalizações |
| GET | `/api/classification/selected.json` | Sim | — | Classificação |
| GET | `/api/chronos2/selected.json` | Sim | — | Chronos enriquecido (timing + GPS + sections) |
| GET | `/api/tracks/selected.json` | — | 12h | Traçado GPS dos troços marcados na Anube (filtrado) |
| GET | `/distance?ident=X` | Sim | 12h (traçado) + GPS live | Troço mais próximo do GPS, distância lateral e % do traçado percorrida (`/api/distance` é o mesmo) |
| GET | `/health` | — | — | Estado do processo (uptime, rally activo, gravação, replay) |

Query params disponíveis em `chronos2/selected.json`: `?ident=1` ou `?participant_id=123`

### Dados de Rally — Genéricos (por rallyId)

Quando replay está ativo e o `rallyId` coincide com a gravação, estes endpoints também retornam dados gravados.

| Método | Endpoint | Replay | Descrição |
|---|---|---|---|
| GET | `/api/race/:rallyId.json` | Sim | Info da prova |
| GET | `/api/itineraries/:rallyId.json` | Sim | Itinerários |
| GET | `/api/specials/:rallyId.json?itinerary_id=X` | Sim | Especiais |
| GET | `/api/participants/:rallyId.json` | Sim | Participantes + GPS |
| GET | `/api/penalizations/:rallyId.json` | Sim | Penalizações |
| GET | `/api/classification/:rallyId.json?itinerary_id=X&special_id=Y` | Sim | Classificação |
| GET | `/api/chronos2/:rallyId.json?special_id=X` | Sim | Chronos enriquecido |
| GET | `/api/tracks/:rallyId.json?sub_id=X` | — | Traçado GPS dos troços (`sub_id` opcional; `?summary=1`, `?format=geojson`) |
| GET | `/api/distance?ident=X&rallyid=Y` | Sim | Posição do participante no traçado, para uma prova específica |

### Gravação

| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| POST | `/api/recording/start` | API key | Iniciar gravação |
| POST | `/api/recording/stop` | API key | Parar gravação |
| GET | `/api/recording/status` | — | Estado atual |
| GET | `/api/recording/list` | — | Listar gravações |
| DELETE | `/api/recording/:recordingId` | API key | Eliminar gravação |
| POST | `/api/recording/auto-start/enable` | API key | Ativar gravação automática |
| POST | `/api/recording/auto-start/disable` | API key | Desativar gravação automática |
| GET | `/api/recording/auto-start/status` | — | Estado do auto-start |

### Replay

| Método | Endpoint | Auth | Descrição |
|---|---|---|---|
| POST | `/api/replay/start` | API key | Carregar gravação |
| POST | `/api/replay/stop` | API key | Parar replay |
| POST | `/api/replay/play` | API key | Reproduzir |
| POST | `/api/replay/pause` | API key | Pausar |
| POST | `/api/replay/seek` | API key | Saltar para minuto |
| POST | `/api/replay/speed` | API key | Definir velocidade |
| POST | `/api/replay/select-special` | API key | Selecionar especial |
| GET | `/api/replay/status` | — | Estado do replay |

### Documentação

| Método | Endpoint | Descrição |
|---|---|---|
| GET | `/docs/readme` | README |
| GET | `/docs/documentation` | Documentação completa |

---

## Arquitetura

```
APIs Anube (rest3.anube.es / rest.anube.es)
         │
         ▼
    server.js  ──────────── recorder.js
    (Express)               (gravação / snapshots)
         │                        │
         │                        ▼
         │                   storage.js
         │                   (ficheiros JSON)
         │                        │
         │                        ▼
         └─────────────── replay.js
                          (playback / seek / speed)
                                  │
                                  ▼
                             Frontend
                          (public/index.html)
```

### Módulos

| Ficheiro | Responsabilidade |
|---|---|
| `server.js` | Servidor Express, todos os endpoints, cache, auth |
| `recorder.js` | Lógica de gravação (timer, detecção de especiais, snapshots) |
| `replay.js` | Motor de replay (play, pause, seek, velocidade) |
| `storage.js` | I/O de ficheiros (criar, guardar, carregar gravações) |
| `public/index.html` | Interface web |

### Estrutura de Ficheiros

```
api/
├── server.js
├── recorder.js
├── replay.js
├── storage.js
├── public/
│   └── index.html
├── recordings/
│   ├── config.json              # Configuração persistida
│   ├── index.json               # Índice de gravações
│   └── races/
│       └── race_{rallyId}_{ts}/
│           ├── metadata.json
│           ├── static/
│           │   ├── race.json
│           │   ├── itineraries.json
│           │   ├── specials.json
│           │   └── participants.json
│           └── timeline/
│               ├── {ts}_000.json
│               ├── {ts}_001.json
│               └── ...
```

---

## Scripts

```bash
npm start      # Iniciar servidor
npm run dev    # Iniciar com nodemon (auto-reload)
```

---

Desenvolvido para a comunidade de Rally.
