# API Cockpit ADV — `api.sctex.fr`

## Présentation

API REST légère hébergée sur `api.sctex.fr` (mutualisé OVH), servant d'intermédiaire entre l'application Electron **Cockpit ADV** et la base de données MySQL `colipf_stk` hébergée sur `sql.pim.sctex.fr`.

Elle a été mise en place pour contourner le blocage du port MySQL 3306 sur le réseau interne Sioen, tout en apportant une couche de sécurité supplémentaire (authentification par clé API, whitelist de colonnes, logs).

---

## Architecture

```
Cockpit ADV (Electron)
        │
        │ HTTPS (port 443)
        ▼
api.sctex.fr  (PHP — mutualisé OVH)
        │
        │ MySQL (réseau interne hébergeur)
        ▼
sql.pim.sctex.fr (MySQL — base colipf_stk)
```

---

## Structure des fichiers

```
/api
  ├── .htaccess           ← Sécurité : bloque l'accès direct aux fichiers sensibles
  ├── config.php          ← Credentials MySQL + clés API (ne jamais exposer)
  ├── auth.php            ← Authentification + connexion PDO MySQL
  ├── logger.php          ← Enregistrement des logs
  ├── search.php          ← GET  — Recherche articles
  ├── get.php             ← GET  — Récupère un article par code SAP
  ├── sync.php            ← POST — Met à jour un article dans MySQL
  └── logs/
        └── api.log       ← Fichier de log (protégé par .htaccess)
```

---

## Authentification

Toutes les requêtes doivent inclure une clé API valide.

**Deux méthodes acceptées :**

### Header HTTP (recommandé en production)
```
X-Api-Key: votre_clé
```

### Paramètre URL (pratique pour les tests)
```
?api_key=votre_clé
```

### Clés disponibles

Les clés sont définies dans `config.php` :

| Application | Clé |
|---|---|
| `cockpit` | Clé de l'application Electron Cockpit ADV |
| `cron` | Clé pour le script de synchronisation nightly |

> Pour générer une nouvelle clé : [uuidgenerator.net](https://www.uuidgenerator.net/)

---

## Endpoints

### `GET /search.php`

Recherche des articles par désignation ou code SAP.

**Paramètres :**
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| `q` | string | ✅ | Texte recherché (min. 2 caractères) |
| `api_key` | string | Si pas de header | Clé API |

**Exemple :**
```
GET https://api.sctex.fr/search.php?q=dico&api_key=xxx
```

**Réponse succès :**
```json
{
  "ok": true,
  "results": [
    {
      "code_sap": "75504699",
      "default_designation": "DICOPLAN ORA 7444 0550 060 VPF1"
    }
  ]
}
```

**Limites :** 50 résultats maximum.

---

### `GET /get.php`

Récupère tous les champs d'un article par son code SAP.

**Paramètres :**
| Paramètre | Type | Obligatoire | Description |
|---|---|---|---|
| `code` | string | ✅ | Code SAP de l'article |
| `api_key` | string | Si pas de header | Clé API |

**Exemple :**
```
GET https://api.sctex.fr/get.php?code=75504699&api_key=xxx
```

**Réponse succès :**
```json
{
  "ok": true,
  "product": {
    "id": 1,
    "code_sap": "75504699",
    "default_designation": "DICOPLAN ORA 7444 0550 060 VPF1",
    "sales_width": 2500,
    "commercial_sqm_weight": 680,
    "...": "..."
  }
}
```

**Réponse si article non trouvé :**
```json
{
  "ok": true,
  "product": null
}
```

---

### `POST /sync.php`

Met à jour les champs d'un article dans MySQL à partir des données SAP.

**Headers requis :**
```
Content-Type: application/json
X-Api-Key: votre_clé  (ou ?api_key= en paramètre URL)
```

**Body JSON :**
```json
{
  "code_sap": "75504699",
  "fields": {
    "sales_width": 2500,
    "commercial_sqm_weight": 680,
    "style": "S-2635",
    "last_synced_at": "2026-06-10 10:00:00"
  }
}
```

**Réponse succès :**
```json
{
  "ok": true,
  "affectedRows": 1,
  "updatedFields": ["sales_width", "commercial_sqm_weight", "style", "last_synced_at"]
}
```

**Whitelist des colonnes autorisées :**

Seules les colonnes suivantes peuvent être mises à jour via l'API (protection contre les injections) :

```
planned_length, sales_width, laize_production, style,
min_length, max_length, color_reference, color_description,
thickness, roll_winding, tube_diameter, tube_type,
flame_retardant_fabric, grain, coated_side, web_short_label,
pack_type, commercial_sqm_weight, catalog_item_flag, coating_type,
fr_class, support_type, prod_source, long_description,
default_designation, article_type, base_uom, product_family,
last_synced_at
```

---

## Codes de réponse HTTP

| Code | Signification |
|---|---|
| `200` | Succès |
| `204` | Preflight CORS (OPTIONS) |
| `401` | Clé API manquante |
| `403` | Clé API invalide |
| `405` | Méthode HTTP non autorisée |
| `500` | Erreur serveur / MySQL |

---

## Logs

Les accès et erreurs sont enregistrés dans `logs/api.log`.

**Format d'une ligne de log :**
```
2026-06-10 10:23:45 | cockpit | 10.128.20.109 | search.php | OK | q=dico rows=12
2026-06-10 10:23:46 | cockpit | 10.128.20.109 | get.php | OK | code=75504699 found=1
2026-06-10 10:23:47 | cockpit | 10.128.20.109 | sync.php | OK | code=75504699 fields=sales_width,style
2026-06-10 10:23:48 | unknown | 81.45.12.33   | search.php | DENIED | Clé invalide
```

**Rotation automatique :** le fichier est archivé automatiquement quand il dépasse 5 MB.

---

## Sécurité

- **`.htaccess`** bloque l'accès direct à `config.php`, `auth.php`, `logger.php` et au dossier `logs/`
- **Authentification** par clé API sur tous les endpoints
- **Whitelist** des colonnes MySQL modifiables dans `sync.php`
- **PDO** avec requêtes préparées — protection contre les injections SQL
- **SSL** activé sur `api.sctex.fr` (certificat OVH)

---

## Intégration Cockpit ADV

L'API est appelée depuis `services/db.service.js` dans l'application Electron. La clé API `cockpit` est stockée dans ce fichier.

Les trois fonctions exposées :

| Fonction | Endpoint appelé |
|---|---|
| `searchProducts(q)` | `GET /search.php` |
| `getProduct(codeSap)` | `GET /get.php` |
| `updateProduct(codeSap, fields)` | `POST /sync.php` |

---

## Évolutions prévues

- Endpoint `sync-all` pour la synchronisation bulk (cron nightly)
- Ajout des champs MRP (`mrp_controller`, `planning_strategy`, `is_enduit`)
- Authentification du cron avec compte de service SAP dédié
- Suppression du paramètre `?api_key=` en URL (header uniquement en production)
