togethere.cloud/mds/DISCIPLINE_SETTINGS_IMPLEMENTATION.md

8.5 KiB

🎯 Wdrażanie Endpoint'u Ustawień Dyscyplin

📋 Szybki Start

Wszystkie pliki zostały już stworzone. Aby wdrożyć system:

1. Pliki do wdrażania

✅ private_html/api/DisciplineSettingsModel.php
✅ private_html/api/DisciplineSettingsService.php  
✅ private_html/api/discipline-settings.php
✅ private_html/administration/disciplines/ping-pong/settings/index.php
✅ private_html/administration/disciplines/rock-paper-scissors/settings/index.php
✅ private_html/administration/disciplines/table-football/settings/index.php
✅ private_html/administration/disciplines/ping-pong/index.php (zaktualizowany panel)
✅ private_html/tests/discipline_settings_test.php

2. Baza danych

Tabela settings_disciplines jest automatycznie tworzona na pierwszy GET request.

Jeśli chcesz ją ręcznie stworzyć:

CREATE TABLE IF NOT EXISTS settings_disciplines (
    id INT AUTO_INCREMENT PRIMARY KEY,
    discipline VARCHAR(50) NOT NULL UNIQUE,
    
    -- Reguły gry (logika)
    pointsToWin INT NOT NULL DEFAULT 10,
    setsToWin INT NOT NULL DEFAULT 2,
    serveRotation INT NOT NULL DEFAULT 2,
    specialRules TEXT,
    
    -- Personalizacja UI (nie wpływa na logiką gry)
    customization JSON,
    
    -- Versioning ustawień
    settingsVersion INT NOT NULL DEFAULT 1,
    
    -- Metadane
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    updated_by INT,
    
    INDEX idx_discipline (discipline),
    INDEX idx_version (settingsVersion)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

🧪 Testowanie

Test 1: Uruchom test jednostkowy

cd private_html/tests/
php discipline_settings_test.php

Oczekiwana odpowiedź: 10 testów PASS

Test 2: Pobierz ustawienia (cURL)

# Zaloguj się jako admin
curl -c cookies.txt -X POST \
  "http://localhost/login/login.php" \
  -d "email=admin@example.com&password=hasło"

# Pobierz ustawienia
curl -b cookies.txt \
  "http://localhost/administration/disciplines/ping-pong/settings"

Oczekiwana odpowiedź:

{
  "success": true,
  "data": {
    "discipline": "ping-pong",
    "settingsVersion": 1,
    "rules": { ... },
    "customization": { ... }
  }
}

Test 3: Pobierz snapshot (bez admin)

curl "http://localhost/api/discipline-settings.php?discipline=ping-pong&snapshot=true"

Test 4: Panel administracyjny

Otwórz w przeglądarce:

http://localhost/administration/disciplines/ping-pong/

🚀 Użycie w Grze

JavaScript - pobierz ustawienia na start meczu:

async function loadGameSettings() {
  const response = await fetch(
    '/api/discipline-settings.php?discipline=ping-pong&snapshot=true'
  );
  const result = await response.json();
  
  if (result.success) {
    const snapshot = result.snapshot;
    
    // Uruchom grę z ustawieniami
    const game = new PingPongGame({
      pointsToWin: snapshot.rules.pointsToWin,
      setsToWin: snapshot.rules.setsToWin,
      serveRotation: snapshot.rules.serveRotation,
      settingsVersion: snapshot.settingsVersion
    });
    
    // Stosuj customization
    document.body.style.backgroundColor = snapshot.customization.tableColor;
  }
}

PHP - zapisz snapshot w meczu:

$model = new DisciplineSettingsModel($pdo);
$snapshot = $model->getSnapshot('ping-pong');

// Zapisz w bazie
$stmt = $pdo->prepare(
  "UPDATE matches SET settingsSnapshot = ? WHERE id = ?"
);
$stmt->execute([json_encode($snapshot), $matchId]);

📊 Struktura Odpowiedzi API

GET /administration/disciplines/ping-pong/settings

{
  "success": true,
  "data": {
    "discipline": "ping-pong",
    "settingsVersion": 1,
    "rules": {
      "pointsToWin": 11,
      "setsToWin": 3,
      "serveRotation": 2,
      "specialRules": "Deuce at 10-10..."
    },
    "customization": {
      "tableColor": "#2d5016",
      "ballColor": "#ff6600",
      "paddleColor": "#000000",
      "uiTheme": "dark"
    },
    "metadata": {
      "created_at": "2026-01-28 12:30:45",
      "updated_at": "2026-01-28 12:30:45",
      "updated_by": 1
    },
    "status": "custom"
  }
}

POST /administration/disciplines/ping-pong/settings

{
  "success": true,
  "message": "Settings for ping-pong have been updated successfully",
  "data": { ... }
}

GET /api/discipline-settings.php?snapshot=true

{
  "success": true,
  "snapshot": {
    "discipline": "ping-pong",
    "settingsVersion": 1,
    "rules": {
      "pointsToWin": 11,
      "setsToWin": 3,
      "serveRotation": 2,
      "specialRules": "..."
    },
    "snapshotTimestamp": "2026-01-28 12:35:10"
  }
}

🔐 Bezpieczeństwo

Panel administracyjny (/administration/disciplines/*/settings)

  • Wymaga zalogowania
  • Wymaga roli admin
  • POST zawsze wymaga admin role
  • GET wymaga admin role

API publiczny (/api/discipline-settings.php)

  • Nie wymaga logowania
  • Tylko GET
  • Brak zmian
  • Ratelimiting (opcjonalnie): można dodać w przyszłości

💡 Najlepsze Praktyki

1. Snapshot dla startu meczu

// ❌ ŹLE - ustawienia mogą się zmienić w trakcie meczu
$settings = $model->getSettings('ping-pong');

// ✅ DOBRZE - snapshot z momentu startu
$snapshot = $model->getSnapshot('ping-pong');
saveMatchSnapshot($matchId, $snapshot);

2. Versioning

// Każda zmiana automatycznie zwiększa wersję
// Wersja 1 → 2 → 3 → ...
$updated = $service->validateAndUpdate('ping-pong', $input, $userId);
echo $updated['settingsVersion']; // 2

3. Walidacja

// ✅ Walidacja zawsze w serwisie
try {
    $result = $service->validateAndUpdate('ping-pong', $input, $userId);
} catch (InvalidArgumentException $e) {
    // Błędy walidacji
    echo "Błąd: " . $e->getMessage();
}

🔧 Integracja z Istniejącymi Systemami

1. Z tabelą matches

Dodaj kolumnę do matches:

ALTER TABLE matches ADD COLUMN settingsSnapshot JSON AFTER Score;

2. Z systemem meczy

// Przy starcie meczu pobierz snapshot
$snapshot = $model->getSnapshot($discipline);
$match = createMatch([
    'team1_id' => $team1,
    'team2_id' => $team2,
    'settingsSnapshot' => json_encode($snapshot)
]);

3. Z systemem auditowania

// Log zmian
$before = $service->getSettingsForAPI('ping-pong');
$service->validateAndUpdate('ping-pong', $input, $adminId);
$after = $service->getSettingsForAPI('ping-pong');
$changes = $service->compareVersions($before, $after);
logAuditEvent('settings_updated', [
    'discipline' => 'ping-pong',
    'changes' => $changes,
    'admin_id' => $adminId
]);

📈 Rozszerzenia w Przyszłości

Historia zmian

CREATE TABLE settings_disciplines_history (
    id INT AUTO_INCREMENT PRIMARY KEY,
    discipline VARCHAR(50),
    version INT,
    settings JSON,
    changed_by INT,
    changed_at DATETIME,
    PRIMARY KEY (discipline, version)
);

Scheduled changes

// Zmiana ustawień w określonym czasie
INSERT INTO settings_scheduled_changes (
    discipline, 
    settings_json, 
    scheduled_at
) VALUES ('ping-pong', '...', '2026-02-01 00:00:00');

A/B testing

// Różne ustawienia dla różnych grup graczy
INSERT INTO settings_ab_tests (
    discipline,
    variant_a, 
    variant_b,
    split_percentage
) VALUES ('ping-pong', '...', '...', 50);

⚠️ Troubleshooting

Problem: "Table not found"

Rozwiązanie: Tabela tworzy się automatycznie na pierwszy GET. Jeśli nie działa:

$model = new DisciplineSettingsModel($pdo);
$model->ensureTableExists(); // Ręczne wywołanie

Problem: "Invalid JSON"

Rozwiązanie: Sprawdź czy customization jest poprawnym JSON:

json_validate($input['customization']); // PHP 8.3+
// lub
json_last_error() === JSON_ERROR_NONE

Problem: "Validation failed - odd numbers"

Rozwiązanie: pointsToWin i setsToWin muszą być nieparzyste:

  • Poprawne: 11, 21, 3, 5
  • Błędne: 10, 20, 2, 4

📞 Wsparcie

Jeśli masz problemy:

  1. Sprawdź logi: error_log w PHP
  2. Uruchom testy: php discipline_settings_test.php
  3. Sprawdź logowanie: czy jesteś zalogowany jako admin?
  4. Walidacja: czy dane spełniają wymagania?