# CourtKulture PHP 7.4-8.2 Compatibility Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Downgrade CourtKulture from Laravel 12 / PHP 8.2 to a Laravel 8-based codebase that runs on both PHP 7.4 and PHP 8.2 while preserving the current core product behavior.

**Architecture:** This migration is a platform downgrade, not a feature task. The work is split into platform skeleton, syntax compatibility, auth/tooling compatibility, application repair, and cross-runtime verification. The compatibility line should be built in isolation first, then merged only after PHP 7.4 and PHP 8.2 verification both pass.

**Tech Stack:** Laravel 8.83.x, PHP 7.4-8.2, Blade, Bootstrap 5, Eloquent, PHPUnit 9.6, Composer 2, Laravel Mix or a Laravel 8-compatible asset pipeline.

---

## File Structure

### Core dependency and bootstrap files

- Modify: `composer.json`
- Replace/regenerate: `composer.lock`
- Modify: `bootstrap/app.php`
- Create or restore: `app/Http/Kernel.php`
- Create or restore if missing: `app/Exceptions/Handler.php`
- Modify if required by downgrade: `config/app.php`

### Auth and routing files

- Modify: `routes/web.php`
- Modify: `routes/auth.php`
- Modify as needed: `app/Http/Controllers/Auth/RegisteredUserController.php`
- Modify as needed: `app/Http/Controllers/Auth/AuthenticatedSessionController.php`

### Application compatibility files

- Modify:
  - `app/Services/*.php`
  - `app/Http/Controllers/**/*.php`
  - `app/Http/Requests/**/*.php`
  - `app/Models/*.php`
  - `database/factories/*.php`
  - `tests/**/*.php`

### Frontend/build files

- Modify or replace:
  - `package.json`
  - `vite.config.js`
  - `webpack.mix.js` (likely create)
  - `resources/css/app.css`
  - `resources/js/app.js`
  - Blade layouts that assume Vite

### Verification files

- Modify if needed:
  - `.env.example`
  - `phpunit.xml`
  - `README.md`

---

### Task 1: Create the isolated compatibility workspace

**Files:**
- Modify: none in repo content yet
- Verify: `.git`, current worktree state

- [ ] **Step 1: Check the current branch and worktree state**

Run:

```powershell
git branch --show-current
git status --short
```

Expected:
- current branch name is printed
- existing unrelated changes are visible and understood before starting compatibility work

- [ ] **Step 2: Create or switch to an isolated compatibility branch/worktree**

Run one of:

```powershell
git switch -c php74-compat
```

or, if using a worktree:

```powershell
git worktree add ..\courtkulture-php74 php74-compat
```

Expected:
- compatibility work is isolated from the current Laravel 12 line

- [ ] **Step 3: Record the baseline dependency state**

Run:

```powershell
Get-Content composer.json
```

Expected:
- current Laravel 12 and PHP 8.2 constraints are visible before editing

- [ ] **Step 4: Commit the isolated starting point**

Run:

```powershell
git add -A
git commit -m "chore: checkpoint before php74 compatibility migration"
```

Expected:
- there is a clean rollback point for the migration line

---

### Task 2: Downgrade Composer constraints to a Laravel 8-compatible platform

**Files:**
- Modify: `composer.json`
- Replace: `composer.lock`

- [ ] **Step 1: Write the failing compatibility expectation down in composer.json**

Update `composer.json` from:

```json
"require": {
    "php": "^8.2",
    "laravel/framework": "^12.0",
    "laravel/tinker": "^2.10.1"
},
"require-dev": {
    "fakerphp/faker": "^1.23",
    "laravel/breeze": "^2.4",
    "laravel/pail": "^1.2.2",
    "laravel/pint": "^1.24",
    "laravel/sail": "^1.41",
    "mockery/mockery": "^1.6",
    "nunomaduro/collision": "^8.6",
    "phpunit/phpunit": "^11.5.50"
}
```

to this target shape:

```json
"require": {
    "php": "^7.4 || ^8.0",
    "laravel/framework": "^8.83",
    "laravel/tinker": "^2.8"
},
"require-dev": {
    "fakerphp/faker": "^1.23",
    "laravel/breeze": "^1.29",
    "mockery/mockery": "^1.5",
    "nunomaduro/collision": "^5.11",
    "phpunit/phpunit": "^9.6"
}
```

Also remove packages that are likely migration friction for Laravel 8 / PHP 7.4:

```json
"laravel/pail"
```

and, if necessary during dependency resolution:

```json
"laravel/pint",
"laravel/sail"
```

- [ ] **Step 2: Run Composer update to verify the current lockfile is intentionally broken before regeneration**

Run:

```powershell
composer validate
composer update --with-all-dependencies --no-interaction
```

Expected:
- the first attempt may fail due to Laravel 12-generated lockfile constraints or package conflicts
- capture the exact blockers before adjusting versions

- [ ] **Step 3: Resolve package blockers conservatively**

Use the following version policy if blockers appear:

```text
laravel/framework      ^8.83
laravel/breeze         ^1.29
nunomaduro/collision   ^5.11
phpunit/phpunit        ^9.6
laravel/tinker         ^2.8
```

If a dev package still blocks PHP 7.4, remove it rather than forcing a newer platform.

- [ ] **Step 4: Re-run Composer update until a Laravel 8 lockfile is generated**

Run:

```powershell
composer update --with-all-dependencies --no-interaction
```

Expected:
- `composer.lock` is regenerated against Laravel 8-compatible dependencies
- no package in the resolved graph requires PHP 8.1+ or 8.2+

- [ ] **Step 5: Commit the dependency downgrade**

Run:

```powershell
git add composer.json composer.lock
git commit -m "chore: downgrade dependencies for laravel 8 compatibility"
```

---

### Task 3: Restore Laravel 8 bootstrap and kernel structure

**Files:**
- Modify: `bootstrap/app.php`
- Create: `app/Http/Kernel.php`
- Create/modify: `app/Exceptions/Handler.php`

- [ ] **Step 1: Write the failing bootstrap verification**

Run:

```powershell
php artisan --version
```

Expected:
- failure due to Laravel 12-style bootstrap or missing kernel contracts after the dependency downgrade

- [ ] **Step 2: Replace Laravel 12 bootstrap wiring with Laravel 8 bootstrap**

Replace `bootstrap/app.php` contents with Laravel 8-style bootstrap:

```php
<?php

$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

return $app;
```

- [ ] **Step 3: Restore `app/Http/Kernel.php` with middleware alias support**

Create or restore this Laravel 8-compatible kernel skeleton and preserve the custom `staff` alias:

```php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \Fruitcake\Cors\HandleCors::class,
        \App\Http\Middleware\PreventRequestsDuringMaintenance::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    ];

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];

    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'staff' => \App\Http\Middleware\EnsureStaff::class,
    ];
}
```

- [ ] **Step 4: Ensure `app/Exceptions/Handler.php` exists and matches Laravel 8 expectations**

If the downgrade leaves it missing or incompatible, restore the standard Laravel 8 handler skeleton:

```php
<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;

class Handler extends ExceptionHandler
{
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    public function register()
    {
        //
    }
}
```

- [ ] **Step 5: Verify Artisan boots**

Run:

```powershell
php artisan --version
```

Expected:
- Laravel version prints successfully

- [ ] **Step 6: Commit bootstrap recovery**

Run:

```powershell
git add bootstrap/app.php app/Http/Kernel.php app/Exceptions/Handler.php
git commit -m "refactor: restore laravel 8 bootstrap and kernel"
```

---

### Task 4: Make application code PHP 7.4-safe

**Files:**
- Modify: `app/Services/*.php`
- Modify: `app/Http/Controllers/**/*.php`
- Modify: `app/Http/Requests/**/*.php`
- Modify: `routes/web.php`
- Modify: `tests/**/*.php`

- [ ] **Step 1: Write the failing syntax scan**

Run:

```powershell
rg -n "readonly|match\\s*\\(|\\?->" app routes tests
```

Expected:
- hits appear across services, routes, and tests

- [ ] **Step 2: Replace constructor-promoted readonly properties with PHP 7.4 properties**

Convert patterns like:

```php
public function __construct(private readonly QueueService $queueService)
{
}
```

to:

```php
/** @var QueueService */
private $queueService;

public function __construct(QueueService $queueService)
{
    $this->queueService = $queueService;
}
```

Apply this to all controllers and services using promoted readonly properties.

- [ ] **Step 3: Replace nullsafe operators with explicit null handling**

Convert patterns like:

```php
if ($player?->status === 'checked_out') {
    return null;
}
```

to:

```php
if ($player !== null && $player->status === 'checked_out') {
    return null;
}
```

Convert patterns like:

```php
if (request()->user()?->is_staff) {
```

to:

```php
$user = request()->user();

if ($user && $user->is_staff) {
```

- [ ] **Step 4: Replace `match` expressions with `switch` or lookup arrays**

Convert patterns like:

```php
return match ($mode) {
    'mixed_doubles' => $this->selectMixedDoubles($session),
    default => $this->selectWaitingPlayers($session, $requiredPlayers),
};
```

to:

```php
switch ($mode) {
    case 'mixed_doubles':
        return $this->selectMixedDoubles($session);
    default:
        return $this->selectWaitingPlayers($session, $requiredPlayers);
}
```

- [ ] **Step 5: Replace PHP 8-only helper usage if needed**

Convert:

```php
str_contains($value, '@')
```

to a Laravel/PHP 7.4-safe form if the final dependency set does not expose it reliably:

```php
\Illuminate\Support\Str::contains($value, '@')
```

- [ ] **Step 6: Re-run the syntax scan until no 8-only language constructs remain**

Run:

```powershell
rg -n "readonly|match\\s*\\(|\\?->" app routes tests
```

Expected:
- no results

- [ ] **Step 7: Lint representative files**

Run:

```powershell
php -l bootstrap/app.php
php -l routes/web.php
php -l app/Services/MatchGenerationService.php
php -l app/Services/PlayerPortalService.php
```

Expected:
- no syntax errors

- [ ] **Step 8: Commit the PHP 7.4 compatibility pass**

Run:

```powershell
git add app routes tests bootstrap
git commit -m "refactor: rewrite php 8 syntax for php74 compatibility"
```

---

### Task 5: Settle auth scaffolding and route behavior on Laravel 8

**Files:**
- Modify: `routes/auth.php`
- Modify: `routes/web.php`
- Modify: `app/Http/Controllers/Auth/*.php`
- Modify: `resources/views/auth/*.blade.php`

- [ ] **Step 1: Write the failing auth route verification**

Run:

```powershell
php artisan route:list
```

Expected:
- auth route wiring may fail or diverge after the framework downgrade

- [ ] **Step 2: Keep the existing product route contract where possible**

Preserve these route groups and names:

```text
/
/dashboard
/player/*
/staff/*
/live/{publicToken}
```

and preserve auth entry points:

```text
/login
/register
/logout
```

- [ ] **Step 3: Downgrade auth scaffolding without redesigning the experience**

If Breeze 1.x integrates cleanly, keep it. If not, manually preserve the existing Blade auth views and the current controller/form-request flow rather than replacing the UX.

Required behaviors:

- public player registration stays available
- authenticated player dashboard stays available
- staff login redirects to staff dashboard
- staff route protection stays enforced

- [ ] **Step 4: Verify routes load**

Run:

```powershell
php artisan route:list
```

Expected:
- player, staff, auth, and public live routes all appear

- [ ] **Step 5: Commit auth compatibility**

Run:

```powershell
git add routes app/Http/Controllers/Auth resources/views/auth
git commit -m "refactor: restore auth flow on laravel 8"
```

---

### Task 6: Replace or simplify the frontend asset pipeline for Laravel 8

**Files:**
- Modify: `package.json`
- Create: `webpack.mix.js`
- Modify/remove: `vite.config.js`
- Modify: Blade layouts using `@vite`

- [ ] **Step 1: Write the failing frontend build verification**

Run:

```powershell
cmd /c npm run build
```

Expected:
- current Vite-era configuration may fail or remain coupled to Laravel 12 assumptions

- [ ] **Step 2: Move to Laravel Mix if that is the shortest stable Laravel 8 path**

Target `package.json` scripts:

```json
"scripts": {
  "dev": "npm run development",
  "development": "mix",
  "watch": "mix watch",
  "prod": "npm run production",
  "production": "mix --production"
}
```

Target `webpack.mix.js`:

```js
const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
   .postCss('resources/css/app.css', 'public/css', [
       require('postcss-import'),
       require('autoprefixer'),
   ])
   .version();
```

- [ ] **Step 3: Replace `@vite(...)` with Mix asset references where necessary**

Convert Blade patterns like:

```blade
@vite(['resources/css/app.css', 'resources/js/app.js'])
```

to Laravel 8-safe Mix patterns like:

```blade
<link rel="stylesheet" href="{{ mix('/css/app.css') }}">
<script src="{{ mix('/js/app.js') }}" defer></script>
```

Apply this to layouts and public pages that rely on the build manifest.

- [ ] **Step 4: Install compatible frontend dependencies**

Run:

```powershell
cmd /c npm install
```

Expected:
- lockfile and packages align to the chosen Laravel 8-compatible build chain

- [ ] **Step 5: Verify production build**

Run:

```powershell
cmd /c npm run production
```

Expected:
- frontend assets compile successfully on the downgraded stack

- [ ] **Step 6: Commit the frontend pipeline migration**

Run:

```powershell
git add package.json package-lock.json webpack.mix.js resources public
git commit -m "build: migrate asset pipeline for laravel 8 compatibility"
```

---

### Task 7: Downgrade the test stack and repair test compatibility

**Files:**
- Modify: `phpunit.xml`
- Modify: `tests/**/*.php`

- [ ] **Step 1: Write the failing test-run verification**

Run:

```powershell
php artisan test
```

Expected:
- failures caused by downgraded framework APIs, PHPUnit version changes, or auth/bootstrap changes

- [ ] **Step 2: Keep the suite on PHPUnit 9.6-compatible assertions and syntax**

Preserve existing behavioral coverage for:

- queue service
- match generation service
- match result service
- staff dashboard
- player registration
- player portal
- public live session

Adjust tests only when they rely on Laravel 12-specific assumptions.

- [ ] **Step 3: Repair failing tests by behavior area**

Use focused commands such as:

```powershell
php artisan test tests\Unit\Services\QueueServiceTest.php
php artisan test tests\Unit\Services\MatchGenerationServiceTest.php
php artisan test tests\Feature\Auth\RegistrationTest.php
php artisan test tests\Feature\PlayerPortalTest.php
php artisan test tests\Feature\StaffDashboardTest.php
```

Expected:
- failures are isolated and repaired incrementally

- [ ] **Step 4: Run the full suite**

Run:

```powershell
php artisan test
```

Expected:
- all tests pass on the Laravel 8 / PHP 7.4-safe codebase

- [ ] **Step 5: Commit the test compatibility pass**

Run:

```powershell
git add tests phpunit.xml
git commit -m "test: restore test suite on laravel 8 stack"
```

---

### Task 8: Repair runtime regressions in application behavior

**Files:**
- Modify as needed:
  - `app/Services/*.php`
  - `app/Http/Controllers/**/*.php`
  - `app/Http/Requests/**/*.php`
  - `resources/views/**/*.blade.php`

- [ ] **Step 1: Smoke test staff flow**

Verify manually or with feature tests:

```text
staff login
create session
add/check-in player
generate match
record result
```

- [ ] **Step 2: Smoke test player flow**

Verify:

```text
player registration
player login
player profile view/update
player session join/leave
```

- [ ] **Step 3: Smoke test public flow**

Verify:

```text
public live session view loads by token
```

- [ ] **Step 4: Repair regressions conservatively**

When regressions are found, prefer behavior-preserving fixes inside the existing services/controllers instead of broad rewrites.

- [ ] **Step 5: Re-run the relevant focused tests after each repair**

Example:

```powershell
php artisan test tests\Feature\StaffDashboardTest.php
php artisan test tests\Feature\PlayerPortalTest.php
php artisan test tests\Feature\PublicLiveSessionTest.php
```

- [ ] **Step 6: Commit runtime repairs**

Run:

```powershell
git add app resources routes
git commit -m "fix: repair application behavior after compatibility downgrade"
```

---

### Task 9: Verify on PHP 7.4 and PHP 8.2

**Files:**
- Modify if needed: `.env.example`, `README.md`

- [ ] **Step 1: Verify Composer install on PHP 7.4**

Run in the PHP 7.4 environment:

```powershell
composer install --no-interaction
php artisan --version
php artisan test
cmd /c npm run production
```

Expected:
- install succeeds
- Artisan boots
- tests pass
- assets build

- [ ] **Step 2: Verify the same on PHP 8.2**

Run in the PHP 8.2 environment:

```powershell
composer install --no-interaction
php artisan --version
php artisan test
cmd /c npm run production
```

Expected:
- both runtimes are supported by the same codebase

- [ ] **Step 3: Document runtime requirements and caveats**

Update `README.md` or deployment notes with:

```text
supported PHP versions
required Node/npm expectations
build commands
deployment commands
known compatibility caveats
```

- [ ] **Step 4: Commit the verification and docs**

Run:

```powershell
git add README.md .env.example
git commit -m "docs: record php74 to php82 compatibility requirements"
```

---

### Task 10: Final acceptance verification

**Files:**
- Modify: none unless a last-mile fix is needed

- [ ] **Step 1: Run the full backend verification one final time**

Run:

```powershell
php artisan test
```

Expected:
- all tests pass on the final compatibility line

- [ ] **Step 2: Run the final frontend verification**

Run:

```powershell
cmd /c npm run production
```

Expected:
- build succeeds cleanly

- [ ] **Step 3: Run a route verification**

Run:

```powershell
php artisan route:list
```

Expected:
- auth, player, staff, and live routes are present

- [ ] **Step 4: Confirm acceptance criteria**

Checklist:

```text
app boots on PHP 7.4
app boots on PHP 8.2
staff workflow works
player workflow works
public live view works
tests pass
assets build
```

- [ ] **Step 5: Commit final stabilization**

Run:

```powershell
git add -A
git commit -m "chore: finalize php74 to php82 compatibility migration"
```

---

## Spec Coverage Check

- Platform downgrade: covered in Tasks 1-3
- PHP syntax compatibility: covered in Task 4
- Auth/tooling migration: covered in Tasks 5-6
- Application behavior preservation: covered in Task 8
- Cross-runtime verification: covered in Tasks 9-10

## Placeholder Scan

- No `TODO`, `TBD`, or “implement later” placeholders remain
- Each task includes exact files, commands, and expected outcomes

## Type Consistency Check

- Runtime target stays `PHP 7.4 through PHP 8.2`
- Framework target stays `Laravel 8.83.x`
- Test target stays `PHPUnit 9.6`
- Frontend target stays Laravel 8-compatible build tooling
