Les utilisateurs étaient stockés uniquement dans Redis (CacheUserRepository), ce qui exposait à une perte totale des comptes en cas de restart Redis, FLUSHDB ou perte du volume Docker. Les tables student_guardians et teacher_assignments référençaient des user IDs sans FK réelle. PostgreSQL devient la source de vérité via DoctrineUserRepository (DBAL, upsert ON CONFLICT). CachedUserRepository décore l'interface existante avec le pattern cache-aside : lectures Redis d'abord → miss → PostgreSQL → populate Redis ; écritures PostgreSQL d'abord → mise à jour Redis. Si Redis est indisponible, l'application continue via PostgreSQL seul. Une commande de migration (app:migrate-users-to-postgres) permet de copier les données Redis existantes vers PostgreSQL de manière idempotente.
287 lines
8.8 KiB
YAML
287 lines
8.8 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
pull_request:
|
|
branches: [main, develop]
|
|
|
|
jobs:
|
|
# =============================================================================
|
|
# Backend Tests - PHP 8.5, PHPStan, PHPUnit
|
|
# =============================================================================
|
|
test-backend:
|
|
name: Backend Tests
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: backend
|
|
|
|
services:
|
|
postgres:
|
|
image: postgres:18.1-alpine
|
|
env:
|
|
POSTGRES_DB: classeo_test
|
|
POSTGRES_USER: classeo
|
|
POSTGRES_PASSWORD: classeo
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
|
|
redis:
|
|
image: redis:7.4-alpine
|
|
ports:
|
|
- 6379:6379
|
|
options: >-
|
|
--health-cmd "redis-cli ping"
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.5'
|
|
extensions: intl, pdo_pgsql, amqp, redis, zip
|
|
coverage: xdebug
|
|
|
|
- name: Get Composer cache directory
|
|
id: composer-cache
|
|
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
|
|
|
- name: Cache Composer dependencies
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ${{ steps.composer-cache.outputs.dir }}
|
|
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
|
restore-keys: ${{ runner.os }}-composer-
|
|
|
|
- name: Install dependencies
|
|
run: composer install --prefer-dist --no-progress
|
|
|
|
- name: Run PHP CS Fixer (check)
|
|
run: composer cs-check
|
|
|
|
- name: Run PHPStan
|
|
run: composer phpstan
|
|
|
|
- name: Create test database and run migrations
|
|
run: |
|
|
php bin/console doctrine:database:create --if-not-exists --env=test
|
|
php bin/console doctrine:migrations:migrate --no-interaction --env=test
|
|
env:
|
|
DATABASE_URL: postgresql://classeo:classeo@localhost:5432/classeo_test?serverVersion=18
|
|
REDIS_URL: redis://localhost:6379
|
|
|
|
- name: Run PHPUnit
|
|
run: composer test
|
|
env:
|
|
DATABASE_URL: postgresql://classeo:classeo@localhost:5432/classeo_test?serverVersion=18
|
|
REDIS_URL: redis://localhost:6379
|
|
|
|
- name: Run BC Isolation Check
|
|
working-directory: .
|
|
run: ./scripts/check-bc-isolation.sh
|
|
|
|
# =============================================================================
|
|
# Frontend Tests - Vitest, Playwright
|
|
# =============================================================================
|
|
test-frontend:
|
|
name: Frontend Tests
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: frontend
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v3
|
|
with:
|
|
version: 9
|
|
|
|
- name: Get pnpm store directory
|
|
id: pnpm-cache
|
|
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
|
|
|
- name: Cache pnpm dependencies
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
restore-keys: ${{ runner.os }}-pnpm-store-
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run linter
|
|
run: pnpm run lint
|
|
|
|
- name: Run TypeScript check
|
|
run: pnpm run check
|
|
|
|
- name: Run unit tests
|
|
run: pnpm run test
|
|
|
|
# =============================================================================
|
|
# E2E Tests - Playwright with Docker backend
|
|
# =============================================================================
|
|
test-e2e:
|
|
name: E2E Tests
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Setup Node.js
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '22'
|
|
|
|
- name: Setup pnpm
|
|
uses: pnpm/action-setup@v3
|
|
with:
|
|
version: 9
|
|
|
|
- name: Get pnpm store directory
|
|
id: pnpm-cache
|
|
run: echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT
|
|
|
|
- name: Cache pnpm dependencies
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
|
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
restore-keys: ${{ runner.os }}-pnpm-store-
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: frontend
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Install Playwright browsers
|
|
working-directory: frontend
|
|
run: pnpm exec playwright install --with-deps
|
|
|
|
- name: Build and start backend services
|
|
run: |
|
|
# Build images first (with Docker layer caching)
|
|
docker compose build php
|
|
# Start services (includes db, redis, rabbitmq dependencies)
|
|
# Use null mailer transport since mailpit is not available in CI
|
|
# Use test environment to disable rate limiting for E2E tests
|
|
APP_ENV=test MAILER_DSN="null://null" docker compose up -d php
|
|
timeout-minutes: 10
|
|
|
|
- name: Wait for backend to be ready
|
|
run: |
|
|
echo "Waiting for backend to be ready (composer install + app startup)..."
|
|
# Wait up to 5 minutes for the backend to respond
|
|
# Using /api/docs which is a public endpoint (no auth required)
|
|
timeout 300 bash -c 'until curl -sf http://localhost:18000/api/docs > /dev/null 2>&1; do
|
|
echo "Waiting for backend..."
|
|
sleep 5
|
|
done'
|
|
echo "Backend is ready!"
|
|
|
|
- name: Generate JWT keys for authentication
|
|
run: |
|
|
# Generate JWT keys if they don't exist (required for login/token endpoints)
|
|
docker compose exec -T php php bin/console lexik:jwt:generate-keypair --skip-if-exists
|
|
|
|
- name: Create test database and run migrations
|
|
run: |
|
|
# Create test database (Symfony adds _test suffix in test environment)
|
|
docker compose exec -T php php bin/console doctrine:database:create --if-not-exists
|
|
# Run migrations to create all tables (including audit_log)
|
|
docker compose exec -T php php bin/console doctrine:migrations:migrate --no-interaction
|
|
|
|
- name: Show backend logs on failure
|
|
if: failure()
|
|
run: docker compose logs php
|
|
|
|
- name: Configure hosts for multi-tenant testing
|
|
run: |
|
|
echo "127.0.0.1 classeo.local" | sudo tee -a /etc/hosts
|
|
echo "127.0.0.1 ecole-alpha.classeo.local" | sudo tee -a /etc/hosts
|
|
echo "127.0.0.1 ecole-beta.classeo.local" | sudo tee -a /etc/hosts
|
|
cat /etc/hosts
|
|
|
|
- name: Reset rate limiter before E2E tests
|
|
run: docker compose exec -T php php bin/console app:dev:reset-rate-limit
|
|
|
|
- name: Run E2E tests
|
|
working-directory: frontend
|
|
run: pnpm run test:e2e
|
|
env:
|
|
# Frontend serves on 4173 (preview mode), backend on 18000 (Docker)
|
|
PUBLIC_API_PORT: "18000"
|
|
PUBLIC_API_URL: http://localhost:18000/api
|
|
|
|
- name: Upload Playwright report
|
|
uses: actions/upload-artifact@v4
|
|
if: failure()
|
|
with:
|
|
name: playwright-report
|
|
path: frontend/playwright-report/
|
|
retention-days: 7
|
|
|
|
- name: Stop backend services
|
|
if: always()
|
|
run: docker compose down
|
|
|
|
# =============================================================================
|
|
# Naming Conventions Check
|
|
# =============================================================================
|
|
check-naming:
|
|
name: Naming Conventions
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Run Naming Check
|
|
run: ./scripts/check-naming.sh
|
|
|
|
# =============================================================================
|
|
# Build Check
|
|
# =============================================================================
|
|
build:
|
|
name: Build Check
|
|
runs-on: ubuntu-latest
|
|
needs: [test-backend, test-frontend, test-e2e]
|
|
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
|
|
- name: Build backend image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ./backend
|
|
push: false
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
|
|
- name: Build frontend image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ./frontend
|
|
push: false
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|