# Deploiement Docker — Lesstime

## Pre-requis

### Docker

```bash
# Ubuntu
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo usermod -aG docker $USER
```

Se deconnecter/reconnecter pour que le groupe `docker` prenne effet.

### Nginx

```bash
sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx
```

### PostgreSQL

PostgreSQL tourne dans un conteneur Docker separe (voir le repo `infra-postgres`).
Il doit etre installe et accessible avant de deployer Lesstime.

Creer la base de donnees pour Lesstime :

```bash
cd /var/www/postgres
docker compose exec postgres psql -U admin
```

```sql
-- Si le user n'existe pas encore
CREATE USER malio WITH PASSWORD 'motdepasse';

-- Creer la base
CREATE DATABASE lesstime_prod OWNER malio;
\q
```

---

## Premiere installation (nouvelle machine)

Guide complet pour mettre en ligne Lesstime sur une machine vierge. Inclut les pre-requis, la BDD et l'app.

### 1. Installer les pre-requis

Installer Docker, Nginx et PostgreSQL (voir section Pre-requis ci-dessus).

### 2. Creer le dossier de deploiement

```bash
sudo mkdir -p /var/www/lesstime
sudo chown -R $(whoami):$(whoami) /var/www/lesstime
cd /var/www/lesstime
```

### 3. Se connecter au registry Docker de Gitea

```bash
docker login gitea.malio.fr
```

- **Username** : le nom d'utilisateur du compte organisation Gitea `MALIO`
- **Password** : le token REGISTRY_TOKEN dispo dans le bitwarden

Le login est sauvegarde dans `~/.docker/config.json`, pas besoin de le refaire a chaque deploiement.

### 4. Creer les fichiers de deploiement

Creer `docker-compose.yml` :

```yaml
services:
  app:
    image: gitea.malio.fr/malio-dev/lesstime:${LESSTIME_IMAGE_TAG:-latest}
    container_name: lesstime-app
    env_file: .env
    ports:
      - "8080:80"
    volumes:
      - ./config/jwt:/var/www/html/config/jwt:ro
      - ./uploads:/var/www/html/var/uploads
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: unless-stopped
```

Creer `deploy.sh` :

```bash
#!/usr/bin/env bash
set -euo pipefail

cd "$(dirname "$0")"

TAG="${1:-latest}"
export LESSTIME_IMAGE_TAG="$TAG"

echo "==> Deploying lesstime:${TAG}..."

echo "==> Enabling maintenance mode..."
touch maintenance.on

echo "==> Pulling image..."
sudo docker compose pull

echo "==> Starting container..."
sudo docker compose up -d

echo "==> Waiting for container to be ready..."
sleep 3

echo "==> Extracting maintenance page..."
mkdir -p public
sudo docker compose cp app:/var/www/html/public/maintenance.html public/maintenance.html

echo "==> Running migrations..."
sudo docker compose exec -T -u www-data app php bin/console doctrine:migrations:migrate --no-interaction

echo "==> Seeding RBAC system roles (idempotent)..."
sudo docker compose exec -T -u www-data app php bin/console app:seed-rbac

echo "==> Syncing RBAC permissions catalog..."
sudo docker compose exec -T -u www-data app php bin/console app:sync-permissions

echo "==> Clearing cache..."
sudo docker compose exec -T -u www-data app php bin/console cache:clear --env=prod
sudo docker compose exec -T -u www-data app php bin/console cache:warmup --env=prod

echo "==> Disabling maintenance mode..."
rm -f maintenance.on

VERSION=$(sudo docker compose exec -T app cat config/version.yaml | grep 'app.version' | awk -F"'" '{print $2}')
echo "==> Deployed v${VERSION}"
```

Rendre executable :

```bash
chmod +x deploy.sh
```

### 5. Configurer l'environnement

Creer `.env` avec les variables suivantes :

```env
# Symfony
APP_ENV=prod
APP_DEBUG=0
APP_SECRET=<generer avec: openssl rand -hex 32>

# Database (host.docker.internal = la machine hote, ou le PG tourne en Docker)
DATABASE_URL="postgresql://malio:password@host.docker.internal:5432/lesstime_prod?serverVersion=16&charset=utf8"

# JWT
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
JWT_PASSPHRASE=<generer avec: openssl rand -hex 32>
JWT_COOKIE_SECURE=1
JWT_COOKIE_SAMESITE=lax
JWT_TOKEN_TTL=86400
JWT_COOKIE_TTL=86400

# CORS
CORS_ALLOW_ORIGIN='^https?://project\.malio-dev\.fr$'

# App
DEFAULT_URI=https://project.malio-dev.fr
```

### 6. Generer les cles JWT

```bash
mkdir -p config/jwt
openssl genpkey -algorithm RSA -out config/jwt/private.pem -pkeyopt rsa_keygen_bits:4096
openssl rsa -pubout -in config/jwt/private.pem -out config/jwt/public.pem
```

Rendre les cles lisibles par le conteneur (www-data = uid 33) :

```bash
sudo chown 33:33 config/jwt/private.pem config/jwt/public.pem
sudo chmod 644 config/jwt/private.pem config/jwt/public.pem
```

### 7. Creer le dossier uploads

```bash
mkdir -p uploads
```

### 8. Configurer Nginx systeme

Creer `/etc/nginx/sites-available/lesstime.conf` :

```nginx
server {
    listen 80;
    listen [::]:80;
    server_name project.malio-dev.fr;

    root /var/www/lesstime/public;

    # Maintenance mode
    if (-f /var/www/lesstime/maintenance.on) {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }

    location = /maintenance.html {
        internal;
    }

    location / {
        proxy_pass http://127.0.0.1:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 55m;
    }
}
```

Activer le site :

```bash
sudo ln -sf /etc/nginx/sites-available/lesstime.conf /etc/nginx/sites-enabled/lesstime.conf
sudo nginx -t && sudo systemctl reload nginx
```

### 9. Deployer

```bash
./deploy.sh
```

### 10. Importer les donnees (optionnel)

Si tu as un dump SQL a importer :

```bash
# Depuis ton PC, envoyer le dump vers le serveur
scp lesstime.sql user@serveur:/tmp/lesstime.sql

# Sur le serveur, vider la base puis importer
cd /var/www/postgres
docker compose exec -T postgres psql -U malio lesstime_prod -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
docker compose exec -T postgres psql -U malio lesstime_prod < /tmp/lesstime.sql

# Creer les tables manquantes (si le dump a des erreurs de syntaxe)
cd /var/www/lesstime
docker compose exec -u www-data app php bin/console doctrine:schema:update --force --env=prod

# Nettoyer
rm /tmp/lesstime.sql
```

### Structure finale du dossier

```
/var/www/lesstime/
├── docker-compose.yml
├── deploy.sh
├── .env
├── config/jwt/
│   ├── private.pem
│   └── public.pem
├── public/
│   └── maintenance.html    # extrait automatiquement par deploy.sh
└── uploads/
```

---

## Deployer une nouvelle version

Quand l'app est deja installee, deployer une mise a jour :

```bash
cd /var/www/lesstime
./deploy.sh           # deploie la derniere version (latest)
./deploy.sh v0.3.13   # deploie une version specifique
```

C'est tout. Le script pull l'image, redemarre le conteneur, lance les migrations, seed les roles
systeme RBAC, synchronise le catalogue des permissions et vide le cache.

---

## RBAC : roles & permissions (post-deploiement)

Le module RBAC (entites `Role` / `Permission`) repose sur des donnees qui ne sont **pas**
inserees par les migrations (celles-ci creent uniquement les tables). Deux commandes idempotentes
les peuplent, integrees au `deploy.sh` :

| Commande | Effet |
|----------|-------|
| `app:seed-rbac` | Cree les **roles systeme** `admin` (Administrateur) et `user` (Utilisateur). Idempotent : ne recree rien si deja present. |
| `app:sync-permissions` | (Re)synchronise le **catalogue des permissions** a partir des modules actifs. A relancer a chaque ajout de permission dans le code. |

Symptome si elles n'ont pas tourne : la page d'admin **Roles** affiche « Aucun role trouve ».

Correctif manuel sur une prod deja deployee (sans relancer un deploiement complet) :

```bash
cd /var/www/lesstime
sudo docker compose exec -T -u www-data app php bin/console app:seed-rbac
sudo docker compose exec -T -u www-data app php bin/console app:sync-permissions
```

---

## Rollback

### Image seule (pas de changement de schema BDD)

```bash
./deploy.sh v0.3.12
```

### Avec rollback de migration

```bash
# 1. Rollback schema (pendant que la version actuelle tourne encore)
docker compose exec -T -u www-data app php bin/console doctrine:migrations:migrate prev --no-interaction
# 2. Deployer l'ancienne version
./deploy.sh v0.3.12
```

---

## CI/CD

Le workflow `.gitea/workflows/build-docker.yml` se declenche automatiquement sur push de tag `v*` :
1. Build l'image multi-stage
2. Push vers `gitea.malio.fr/malio-dev/lesstime:<tag>` et `:latest`

Combine avec `auto-tag-develop.yml`, chaque push sur `develop` cree automatiquement un tag → build → image disponible.

---

## Voir les logs

```bash
cd /var/www/lesstime
docker compose logs -f            # tous les logs
docker compose logs -f --tail=100 # 100 dernieres lignes
```

Logs Symfony :

```bash
docker compose exec app cat var/log/prod.log
```

---

## Migration depuis l'ancien deploiement (bare-metal)

Si l'application tourne deja en bare metal :

1. Installer Docker (voir pre-requis)
2. Creer le dossier `/var/www/lesstime-docker/` (ne pas ecraser l'ancien)
3. Copier les fichiers existants :
   ```bash
   cp /var/www/lesstime/.env /var/www/lesstime-docker/.env
   cp -a /var/www/lesstime/config/jwt /var/www/lesstime-docker/config/jwt
   cp -a /var/www/lesstime/var/uploads /var/www/lesstime-docker/uploads
   ```
4. Creer `docker-compose.yml` et `deploy.sh` dans `/var/www/lesstime-docker/` (voir etape 4 ci-dessus)
5. Editer `/var/www/lesstime-docker/.env` : changer `DATABASE_URL` pour utiliser `host.docker.internal` au lieu de `127.0.0.1`
6. Se connecter au registry Gitea (voir etape 3 ci-dessus)
7. Mettre a jour Nginx systeme avec la conf reverse proxy (voir etape 8 ci-dessus)
8. Arreter l'ancien PHP-FPM : `sudo systemctl stop php8.4-fpm`
9. Deployer : `cd /var/www/lesstime-docker && ./deploy.sh`
10. Verifier que tout marche, puis renommer le dossier : `mv /var/www/lesstime-docker /var/www/lesstime`
