# Runbook — Déploiement du lot 0 (fondations stock / mode restauration)

**Concerne :** MR !32, migrations `2026_10_12_100001` à `2026_10_12_100006` et `2026_10_13_100001`
**Décisions :** ADR-006, ADR-007, ADR-008
**Durée estimée :** 20 à 40 minutes, vérifications comprises (la migration elle-même : quelques secondes à quelques minutes selon le volume)
**Exécutant :** la personne qui déclenche `deploy-production`, avec un accès SSH au serveur

---

## 1. Ce qui change en base

| Migration | Effet | Risque |
|---|---|---|
| `100001_convert_stock_quantities_to_decimal` | 9 colonnes `float(8,2)` / `int` → `decimal(14,3)` sur `product_details`, `order_items`, `orders`, `stock_adjustments`, `stock_history` | **Élevé** : `MODIFY COLUMN` recopie chaque table et bloque les écritures pendant la copie |
| `100002_add_typed_movement_columns_to_stock_adjustments` | 6 colonnes, 1 index, 1 contrainte unique, 1 clé étrangère ; renseigne `movement_date` des lignes existantes | Moyen (copie de `stock_adjustments`) |
| `100003_create_stock_period_locks_table` | Nouvelle table | Faible |
| `100004_add_inventory_restaurant_features_and_company_modules` | 2 colonnes sur `plans`, nouvelle table `company_modules` | Faible |
| `100005_seed_inventory_restaurant_permissions` | 10 permissions, attachées aux rôles admin et personnel de **tous** les tenants | Faible |
| `100006` et `2026_10_13_100001` | Traductions | Nul |

Aucune fonctionnalité visible n'est activée par le déploiement : `has_inventory` et `has_restaurant` valent `false` sur tous les plans existants.

### Écart au playbook WES, accepté sous condition

`playbooks/database-migration.md` demande l'expand-contract pour tout changement de type. La migration `100001` fait un `MODIFY COLUMN` direct. Ce choix n'est valable **que si le volume le permet** (étape 2). Au-delà du seuil, on ne déploie pas en l'état : on découpe `100001` en expand-contract, ou on l'exécute avec `pt-online-schema-change`.

---

## 2. Avant le déploiement (la veille)

### 2.1 Mesurer le volume en production

```sql
SELECT table_name, table_rows, ROUND((data_length + index_length) / 1024 / 1024, 1) AS taille_mo
FROM information_schema.tables
WHERE table_schema = DATABASE()
  AND table_name IN ('order_items', 'orders', 'product_details', 'stock_adjustments', 'stock_history');
```

| Résultat | Décision |
|---|---|
| Toutes les tables < 500 000 lignes | Déploiement normal, en heure creuse (étape 3) |
| Une table entre 500 000 et 5 millions de lignes | Mode maintenance obligatoire (`php artisan down`) pendant la migration ; mesurer la durée en staging d'abord |
| Une table > 5 millions de lignes | **Ne pas déployer en l'état.** Réécrire `100001` en expand-contract ou passer par `pt-online-schema-change` |

### 2.2 Relever les sommes de contrôle

À conserver pour la vérification après migration (étape 4.2) :

```sql
SELECT 'order_items' t, COUNT(*) n, ROUND(SUM(quantity), 2) s FROM order_items
UNION ALL SELECT 'orders', COUNT(*), ROUND(SUM(total_quantity), 2) FROM orders
UNION ALL SELECT 'product_details', COUNT(*), ROUND(SUM(current_stock), 2) FROM product_details
UNION ALL SELECT 'stock_adjustments', COUNT(*), ROUND(SUM(quantity), 2) FROM stock_adjustments
UNION ALL SELECT 'stock_history', COUNT(*), ROUND(SUM(quantity), 2) FROM stock_history;
```

### 2.3 Répéter en staging

1. Restaurer en staging une copie récente de la base de production.
2. Déployer la branche, puis chronométrer : `time php artisan migrate --force`.
3. Refaire les sommes de contrôle : elles doivent être identiques.
4. Tester le retour arrière : `php artisan migrate:rollback --step=7 --force`, puis `php artisan migrate --force`. Les deux sens ont été validés deux fois sur la base de test.

Prérequis connu : le chemin de staging (`/home/welely/public_html/staging.gestionstock.welely.com`) n'existe pas encore sur le serveur. Le job `deploy-staging` échoue tant qu'il n'a pas été cloné et configuré (`.env`, `vendor/`), comme le décrit `.gitlab-ci.yml`.

---

## 3. Déploiement

1. **Heure creuse** : la nuit, hors service des restaurants pilotes.
2. **Sauvegarde** sur le serveur, puis vérifier que le fichier n'est pas vide :
   ```bash
   mysqldump --single-transaction --routines -u <user> -p <base> | gzip > ~/backups/gestionstock_avant_lot0_$(date +%Y%m%d_%H%M).sql.gz
   ls -lh ~/backups/
   ```
3. **Mode maintenance**, recommandé quel que soit le volume. Le job de déploiement remet le code à jour **avant** de lancer les migrations : pendant quelques secondes, le nouveau code tournerait sans les nouvelles colonnes.
   ```bash
   cd <PRODUCTION_DEPLOY_PATH> && php artisan down --retry=60
   ```
4. **Lancer** le job manuel `deploy-production` du pipeline `master` dans GitLab.
5. **Sortir de maintenance** dès que le job est vert : `php artisan up`.

---

## 4. Vérifications après déploiement

### 4.1 Migrations
```bash
php artisan migrate:status | tail -8   # les 7 migrations du lot doivent être « Ran »
```

### 4.2 Données intactes
Relancer la requête de l'étape 2.2 : les nombres de lignes et les sommes doivent être identiques.

Types attendus :
```sql
SELECT table_name, column_name, column_type FROM information_schema.columns
WHERE table_schema = DATABASE() AND column_name IN ('quantity', 'current_stock', 'opening_stock', 'stock_quantitiy_alert', 'total_quantity', 'old_quantity')
  AND table_name IN ('order_items', 'orders', 'product_details', 'stock_adjustments', 'stock_history');
-- toutes en decimal(14,3)
```

### 4.3 Parcours fonctionnel (5 minutes, sur un tenant réel)
- Connexion admin, tableau de bord : les quantités s'affichent comme avant (nombres, pas « 10.000 »).
- Une vente en caisse, puis un achat reçu : le stock bouge comme prévu.
- Superadmin → Plans : les interrupteurs « Inventaire et écarts » et « Mode restauration » s'affichent, désactivés.
- Logs (`storage/logs`, Sentry) : aucune nouvelle erreur.

---

## 5. Retour arrière

**Déclencheurs :** une somme de contrôle diverge, la caisse ou les achats sont en erreur, ou des erreurs 500 apparaissent en série après le déploiement.

1. `php artisan down`
2. Revenir au commit précédent par le pipeline, ou par `git reset --hard <sha précédent>` sur le serveur.
3. Choisir selon l'ancienneté du déploiement :
   - **Juste après le déploiement** : `php artisan migrate:rollback --step=7 --force`. Testé deux fois. La troisième décimale disparaît au passage, mais aucune donnée existante n'en a.
   - **Après usage réel** des mouvements typés ou du mode restauration : le rollback de `100002` supprime les colonnes `reason`, `movement_date`, `unit_cost`, et donc ces données. Restaurer plutôt la sauvegarde de l'étape 3.2 et rejouer les écritures intervenues depuis, ou corriger vers l'avant.
4. `php artisan up`, puis refaire les vérifications 4.2 et 4.3.
