diff --git a/.gitignore b/.gitignore
index 8aae99b..b8c0974 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,3 +26,7 @@ yarn-error.log
/.vscode
/.zed
.DS_Store
+
+**/caddy
+frankenphp
+frankenphp-worker.php
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..a6e4967
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,8 @@
+FROM dunglas/frankenphp
+
+RUN install-php-extensions \
+ pcntl
+
+COPY . /app
+
+ENTRYPOINT ["php", "artisan", "octane:frankenphp"]
diff --git a/app/Http/Controllers/TournamentController.php b/app/Http/Controllers/TournamentController.php
index 462744e..a95041f 100644
--- a/app/Http/Controllers/TournamentController.php
+++ b/app/Http/Controllers/TournamentController.php
@@ -200,4 +200,37 @@ class TournamentController extends Controller
return redirect()->route('home')
->with('success', 'Tournament deleted successfully!');
}
+
+ public function addTeam(Competition $tournament, Request $request)
+ {
+ // Check if user is tournament owner
+ if ($tournament->owner != Auth::id()) {
+ return redirect()->back()->with('error', 'You are not authorized to add a team to this tournament.');
+ }
+
+ // Validate the request data
+ $validator = Validator::make($request->all(), [
+ 'team_id' => 'required|exists:teams,id',
+ ]);
+
+ if ($validator->fails()) {
+ return redirect()->back()->withErrors($validator)->withInput();
+ }
+
+ // Add the team
+ $team = Team::find($request->team_id);
+ // if it doesn't exist, create new team
+ //
+ if (!$team) {
+ $team = new Team();
+ $team->name = $request->team_name;
+ $team->save();
+ }
+ $tournament->teams()->attach($team->id);
+
+
+
+ return redirect()->route('tournaments.show', $tournament->id)
+ ->with('success', 'Team added successfully!');
+ }
}
diff --git a/composer.json b/composer.json
index f1a83c4..b2f93f7 100644
--- a/composer.json
+++ b/composer.json
@@ -12,6 +12,7 @@
"php": "^8.2",
"inertiajs/inertia-laravel": "^2.0.2",
"laravel/framework": "^12.16.0",
+ "laravel/octane": "^2.10",
"laravel/socialite": "^5.21",
"laravel/tinker": "^2.10.1",
"socialiteproviders/keycloak": "^5.3",
diff --git a/composer.lock b/composer.lock
index 5e905e8..2632dcb 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "1a44cdb1a493ed3bfbcf2336ae26c0bf",
+ "content-hash": "bd02b3c2ddadea250049517b0d891770",
"packages": [
{
"name": "brick/math",
@@ -1185,6 +1185,94 @@
},
"time": "2025-04-10T15:08:36+00:00"
},
+ {
+ "name": "laminas/laminas-diactoros",
+ "version": "3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laminas/laminas-diactoros.git",
+ "reference": "b068eac123f21c0e592de41deeb7403b88e0a89f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/b068eac123f21c0e592de41deeb7403b88e0a89f",
+ "reference": "b068eac123f21c0e592de41deeb7403b88e0a89f",
+ "shasum": ""
+ },
+ "require": {
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
+ "psr/http-factory": "^1.1",
+ "psr/http-message": "^1.1 || ^2.0"
+ },
+ "conflict": {
+ "amphp/amp": "<2.6.4"
+ },
+ "provide": {
+ "psr/http-factory-implementation": "^1.0",
+ "psr/http-message-implementation": "^1.1 || ^2.0"
+ },
+ "require-dev": {
+ "ext-curl": "*",
+ "ext-dom": "*",
+ "ext-gd": "*",
+ "ext-libxml": "*",
+ "http-interop/http-factory-tests": "^2.2.0",
+ "laminas/laminas-coding-standard": "~3.0.0",
+ "php-http/psr7-integration-tests": "^1.4.0",
+ "phpunit/phpunit": "^10.5.36",
+ "psalm/plugin-phpunit": "^0.19.0",
+ "vimeo/psalm": "^5.26.1"
+ },
+ "type": "library",
+ "extra": {
+ "laminas": {
+ "module": "Laminas\\Diactoros",
+ "config-provider": "Laminas\\Diactoros\\ConfigProvider"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions/create_uploaded_file.php",
+ "src/functions/marshal_headers_from_sapi.php",
+ "src/functions/marshal_method_from_sapi.php",
+ "src/functions/marshal_protocol_version_from_sapi.php",
+ "src/functions/normalize_server.php",
+ "src/functions/normalize_uploaded_files.php",
+ "src/functions/parse_cookie_header.php"
+ ],
+ "psr-4": {
+ "Laminas\\Diactoros\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "PSR HTTP Message implementations",
+ "homepage": "https://laminas.dev",
+ "keywords": [
+ "http",
+ "laminas",
+ "psr",
+ "psr-17",
+ "psr-7"
+ ],
+ "support": {
+ "chat": "https://laminas.dev/chat",
+ "docs": "https://docs.laminas.dev/laminas-diactoros/",
+ "forum": "https://discourse.laminas.dev",
+ "issues": "https://github.com/laminas/laminas-diactoros/issues",
+ "rss": "https://github.com/laminas/laminas-diactoros/releases.atom",
+ "source": "https://github.com/laminas/laminas-diactoros"
+ },
+ "funding": [
+ {
+ "url": "https://funding.communitybridge.org/projects/laminas-project",
+ "type": "community_bridge"
+ }
+ ],
+ "time": "2025-05-05T16:03:34+00:00"
+ },
{
"name": "laravel/framework",
"version": "v12.19.3",
@@ -1400,6 +1488,96 @@
},
"time": "2025-06-18T12:56:23+00:00"
},
+ {
+ "name": "laravel/octane",
+ "version": "v2.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/octane.git",
+ "reference": "62bf04dcb471e7d91c8aeda9b4e7376a75000ee5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/octane/zipball/62bf04dcb471e7d91c8aeda9b4e7376a75000ee5",
+ "reference": "62bf04dcb471e7d91c8aeda9b4e7376a75000ee5",
+ "shasum": ""
+ },
+ "require": {
+ "laminas/laminas-diactoros": "^3.0",
+ "laravel/framework": "^10.10.1|^11.0|^12.0",
+ "laravel/prompts": "^0.1.24|^0.2.0|^0.3.0",
+ "laravel/serializable-closure": "^1.3|^2.0",
+ "nesbot/carbon": "^2.66.0|^3.0",
+ "php": "^8.1.0",
+ "symfony/console": "^6.0|^7.0",
+ "symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0"
+ },
+ "conflict": {
+ "spiral/roadrunner": "<2023.1.0",
+ "spiral/roadrunner-cli": "<2.6.0",
+ "spiral/roadrunner-http": "<3.3.0"
+ },
+ "require-dev": {
+ "guzzlehttp/guzzle": "^7.6.1",
+ "inertiajs/inertia-laravel": "^1.3.2|^2.0",
+ "laravel/scout": "^10.2.1",
+ "laravel/socialite": "^5.6.1",
+ "livewire/livewire": "^2.12.3|^3.0",
+ "mockery/mockery": "^1.5.1",
+ "nunomaduro/collision": "^6.4.0|^7.5.2|^8.0",
+ "orchestra/testbench": "^8.21|^9.0|^10.0",
+ "phpstan/phpstan": "^2.1.7",
+ "phpunit/phpunit": "^10.4|^11.5",
+ "spiral/roadrunner-cli": "^2.6.0",
+ "spiral/roadrunner-http": "^3.3.0"
+ },
+ "bin": [
+ "bin/roadrunner-worker",
+ "bin/swoole-server"
+ ],
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "aliases": {
+ "Octane": "Laravel\\Octane\\Facades\\Octane"
+ },
+ "providers": [
+ "Laravel\\Octane\\OctaneServiceProvider"
+ ]
+ },
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Laravel\\Octane\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Taylor Otwell",
+ "email": "taylor@laravel.com"
+ }
+ ],
+ "description": "Supercharge your Laravel application's performance.",
+ "keywords": [
+ "frankenphp",
+ "laravel",
+ "octane",
+ "roadrunner",
+ "swoole"
+ ],
+ "support": {
+ "issues": "https://github.com/laravel/octane/issues",
+ "source": "https://github.com/laravel/octane"
+ },
+ "time": "2025-06-16T13:44:31+00:00"
+ },
{
"name": "laravel/prompts",
"version": "v0.3.5",
@@ -5553,6 +5731,89 @@
],
"time": "2025-04-17T09:11:12+00:00"
},
+ {
+ "name": "symfony/psr-http-message-bridge",
+ "version": "v7.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/psr-http-message-bridge.git",
+ "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/03f2f72319e7acaf2a9f6fcbe30ef17eec51594f",
+ "reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/http-message": "^1.0|^2.0",
+ "symfony/http-foundation": "^6.4|^7.0"
+ },
+ "conflict": {
+ "php-http/discovery": "<1.15",
+ "symfony/http-kernel": "<6.4"
+ },
+ "require-dev": {
+ "nyholm/psr7": "^1.1",
+ "php-http/discovery": "^1.15",
+ "psr/log": "^1.1.4|^2|^3",
+ "symfony/browser-kit": "^6.4|^7.0",
+ "symfony/config": "^6.4|^7.0",
+ "symfony/event-dispatcher": "^6.4|^7.0",
+ "symfony/framework-bundle": "^6.4|^7.0",
+ "symfony/http-kernel": "^6.4|^7.0"
+ },
+ "type": "symfony-bridge",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Bridge\\PsrHttpMessage\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "PSR HTTP message bridge",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr-17",
+ "psr-7"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-26T08:57:56+00:00"
+ },
{
"name": "symfony/routing",
"version": "v7.3.0",
diff --git a/config/octane.php b/config/octane.php
new file mode 100644
index 0000000..8cfba01
--- /dev/null
+++ b/config/octane.php
@@ -0,0 +1,224 @@
+ env('OCTANE_SERVER', 'roadrunner'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Force HTTPS
+ |--------------------------------------------------------------------------
+ |
+ | When this configuration value is set to "true", Octane will inform the
+ | framework that all absolute links must be generated using the HTTPS
+ | protocol. Otherwise your links may be generated using plain HTTP.
+ |
+ */
+
+ 'https' => env('OCTANE_HTTPS', false),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Octane Listeners
+ |--------------------------------------------------------------------------
+ |
+ | All of the event listeners for Octane's events are defined below. These
+ | listeners are responsible for resetting your application's state for
+ | the next request. You may even add your own listeners to the list.
+ |
+ */
+
+ 'listeners' => [
+ WorkerStarting::class => [
+ EnsureUploadedFilesAreValid::class,
+ EnsureUploadedFilesCanBeMoved::class,
+ ],
+
+ RequestReceived::class => [
+ ...Octane::prepareApplicationForNextOperation(),
+ ...Octane::prepareApplicationForNextRequest(),
+ //
+ ],
+
+ RequestHandled::class => [
+ //
+ ],
+
+ RequestTerminated::class => [
+ // FlushUploadedFiles::class,
+ ],
+
+ TaskReceived::class => [
+ ...Octane::prepareApplicationForNextOperation(),
+ //
+ ],
+
+ TaskTerminated::class => [
+ //
+ ],
+
+ TickReceived::class => [
+ ...Octane::prepareApplicationForNextOperation(),
+ //
+ ],
+
+ TickTerminated::class => [
+ //
+ ],
+
+ OperationTerminated::class => [
+ FlushOnce::class,
+ FlushTemporaryContainerInstances::class,
+ // DisconnectFromDatabases::class,
+ // CollectGarbage::class,
+ ],
+
+ WorkerErrorOccurred::class => [
+ ReportException::class,
+ StopWorkerIfNecessary::class,
+ ],
+
+ WorkerStopping::class => [
+ CloseMonologHandlers::class,
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Warm / Flush Bindings
+ |--------------------------------------------------------------------------
+ |
+ | The bindings listed below will either be pre-warmed when a worker boots
+ | or they will be flushed before every new request. Flushing a binding
+ | will force the container to resolve that binding again when asked.
+ |
+ */
+
+ 'warm' => [
+ ...Octane::defaultServicesToWarm(),
+ ],
+
+ 'flush' => [
+ //
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Octane Swoole Tables
+ |--------------------------------------------------------------------------
+ |
+ | While using Swoole, you may define additional tables as required by the
+ | application. These tables can be used to store data that needs to be
+ | quickly accessed by other workers on the particular Swoole server.
+ |
+ */
+
+ 'tables' => [
+ 'example:1000' => [
+ 'name' => 'string:1000',
+ 'votes' => 'int',
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Octane Swoole Cache Table
+ |--------------------------------------------------------------------------
+ |
+ | While using Swoole, you may leverage the Octane cache, which is powered
+ | by a Swoole table. You may set the maximum number of rows as well as
+ | the number of bytes per row using the configuration options below.
+ |
+ */
+
+ 'cache' => [
+ 'rows' => 1000,
+ 'bytes' => 10000,
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | File Watching
+ |--------------------------------------------------------------------------
+ |
+ | The following list of files and directories will be watched when using
+ | the --watch option offered by Octane. If any of the directories and
+ | files are changed, Octane will automatically reload your workers.
+ |
+ */
+
+ 'watch' => [
+ 'app',
+ 'bootstrap',
+ 'config/**/*.php',
+ 'database/**/*.php',
+ 'public/**/*.php',
+ 'resources/**/*.php',
+ 'routes',
+ 'composer.lock',
+ '.env',
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | Garbage Collection Threshold
+ |--------------------------------------------------------------------------
+ |
+ | When executing long-lived PHP scripts such as Octane, memory can build
+ | up before being cleared by PHP. You can force Octane to run garbage
+ | collection if your application consumes this amount of megabytes.
+ |
+ */
+
+ 'garbage' => 50,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Maximum Execution Time
+ |--------------------------------------------------------------------------
+ |
+ | The following setting configures the maximum execution time for requests
+ | being handled by Octane. You may set this value to 0 to indicate that
+ | there isn't a specific time limit on Octane request execution time.
+ |
+ */
+
+ 'max_execution_time' => 30,
+
+];
diff --git a/database/migrations/2025_06_22_121731_create_user_permission_table.php b/database/migrations/2025_06_22_121731_create_user_permission_table.php
deleted file mode 100644
index 4eba26b..0000000
--- a/database/migrations/2025_06_22_121731_create_user_permission_table.php
+++ /dev/null
@@ -1,31 +0,0 @@
-id();
- $table->foreignId('user_id')->constrained()->onDelete('cascade');
- $table->foreignId('permission_id')->constrained()->onDelete('cascade');
- $table->timestamps();
-
- $table->unique(['user_id', 'permission_id']);
- });
- }
-
- /**
- * Reverse the migrations.
- */
- public function down(): void
- {
- Schema::dropIfExists('user_permission');
- }
-};
diff --git a/database/migrations/2025_06_22_141254_create_permission_user_table.php b/database/migrations/2025_06_22_141254_create_permission_user_table.php
index 7515b98..81e3b8c 100644
--- a/database/migrations/2025_06_22_141254_create_permission_user_table.php
+++ b/database/migrations/2025_06_22_141254_create_permission_user_table.php
@@ -14,7 +14,7 @@ return new class extends Migration
Schema::create('permission_user', function (Blueprint $table) {
$table->id();
$table->foreignId('permission_id')->constrained()->cascadeOnDelete();
- $table->foreignId('user_id')->constrained()->cascadeOnDelete();
+ $table->foreignUuid('user_id')->constrained()->cascadeOnDelete();
$table->boolean('granted')->default(false);
$table->timestamps();
});
diff --git a/package.json b/package.json
index c49a064..b849a87 100644
--- a/package.json
+++ b/package.json
@@ -64,5 +64,5 @@
"@tailwindcss/oxide-linux-x64-gnu": "^4.1.8",
"lightningcss-linux-x64-gnu": "^1.30.1"
},
- "packageManager": "pnpm@10.12.3+sha512.467df2c586056165580ad6dfb54ceaad94c5a30f80893ebdec5a44c5aa73c205ae4a5bb9d5ed6bb84ea7c249ece786642bbb49d06a307df218d03da41c317417"
+ "packageManager": "pnpm@10.12.4+sha512.5ea8b0deed94ed68691c9bad4c955492705c5eeb8a87ef86bc62c74a26b037b08ff9570f108b2e4dbd1dd1a9186fea925e527f141c648e85af45631074680184"
}
diff --git a/phpunit.xml b/phpunit.xml
index 61c031c..c09b5bc 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -22,8 +22,7 @@