laravel running

This commit is contained in:
2026-07-02 15:52:13 +02:00
parent 2c6eda0db9
commit 5c667fd1cf
62 changed files with 12937 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4
+48
View File
@@ -0,0 +1,48 @@
APP_NAME=Nexus
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_URL=https://nexus.local
APP_LOCALE=de
APP_FALLBACK_LOCALE=de
APP_FAKER_LOCALE=de_DE
APP_MAINTENANCE_DRIVER=file
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=nexus
DB_USERNAME=root
DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
VITE_APP_NAME="${APP_NAME}"
+11
View File
@@ -0,0 +1,11 @@
* text=auto eol=lf
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
.styleci.yml export-ignore
+21
View File
@@ -0,0 +1,21 @@
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/storage/pail
/vendor
.env
.env.backup
.env.production
.phpactor.json
auth.json
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.nova
/.vscode
Generated
+1
View File
@@ -10,6 +10,7 @@
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.5" />
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
+9
View File
@@ -0,0 +1,9 @@
.PHONY: setup frontend
setup:
rm -f docker-compose.yaml
cp docker-compose.dev docker-compose.yaml
docker-compose up -d
frontend:
npm run watch
@@ -0,0 +1,17 @@
<?php
namespace App\Domains\Dashboard\Controllers;
use App\Providers\InertiaProvider;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class DashboardController
{
public function __invoke(Request $request): Response
{
$inertiaProvider = new InertiaProvider('Dashboard/Dashboard', []);
return $inertiaProvider->render();
}
}
+3
View File
@@ -0,0 +1,3 @@
<?php
use Illuminate\Support\Facades\Route;
+6
View File
@@ -0,0 +1,6 @@
<?php
use App\Domains\Dashboard\Controllers\DashboardController;
use Illuminate\Support\Facades\Route;
Route::get('/', DashboardController::class)->name('dashboard');
+12
View File
@@ -0,0 +1,12 @@
<script setup>
import AppLayout from '@/layouts/AppLayout.vue'
import { ref } from 'vue'
const message = ref('Hallo Welt')
</script>
<template>
<AppLayout title="Dashboard">
<h2>{{ message }}</h2>
</AppLayout>
</template>
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
protected $fillable = [
'name',
'email',
'password',
];
protected $hidden = [
'password',
'remember_token',
];
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\Providers;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}
public function boot(): void
{
URL::forceScheme('https');
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace App\Providers;
use App\Models\Tenant;
use App\Models\User;
use App\Resources\UserResource;
use Inertia\Inertia;
use Inertia\Response;
final class InertiaProvider
{
private string $vueFile;
private array $props;
private ?User $user;
public function __construct(string $vueFile, array $props) {
$this->user = auth()->user();
$this->vueFile = $vueFile;
$this->props = $props;
}
public function render() : Response {
return Inertia::render(
str_replace('/', '/Views/', $this->vueFile),
$this->props
);
}
}
+15
View File
@@ -0,0 +1,15 @@
#!/usr/bin/env php
<?php
use Symfony\Component\Console\Input\ArgvInput;
define('LARAVEL_START', microtime(true));
// Register the Composer autoloader...
require __DIR__.'/vendor/autoload.php';
// Bootstrap Laravel and handle the command...
$status = (require_once __DIR__.'/bootstrap/app.php')
->handleCommand(new ArgvInput);
exit($status);
+19
View File
@@ -0,0 +1,19 @@
<?php
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
return Application::configure(basePath: dirname(__DIR__))
->withRouting(
web: __DIR__.'/../routes/web.php',
commands: __DIR__.'/../routes/console.php',
api: __DIR__.'/../routes/api.php',
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
})
->withExceptions(function (Exceptions $exceptions): void {
//
})->create();
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+5
View File
@@ -0,0 +1,5 @@
<?php
return [
App\Providers\AppServiceProvider::class,
];
+86
View File
@@ -0,0 +1,86 @@
{
"$schema": "https://getcomposer.org/schema.json",
"name": "laravel/laravel",
"type": "project",
"description": "The skeleton application for the Laravel framework.",
"keywords": ["laravel", "framework"],
"license": "MIT",
"require": {
"php": "^8.5",
"inertiajs/inertia-laravel": "^2.0",
"laravel/framework": "^13.0"
},
"require-dev": {
"fakerphp/faker": "^1.23",
"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.3"
},
"autoload": {
"psr-4": {
"App\\": "app/",
"Database\\Factories\\": "database/factories/",
"Database\\Seeders\\": "database/seeders/"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
},
"scripts": {
"setup": [
"composer install",
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
"@php artisan key:generate",
"@php artisan migrate --force",
"npm install",
"npm run build"
],
"dev": [
"Composer\\Config::disableProcessTimeout",
"npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --timeout=0\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
],
"test": [
"@php artisan config:clear --ansi",
"@php artisan test"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi"
],
"post-update-cmd": [
"@php artisan vendor:publish --tag=laravel-assets --ansi --force"
],
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate --ansi",
"@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
"@php artisan migrate --graceful --ansi"
],
"pre-package-uninstall": [
"Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
]
},
"extra": {
"laravel": {
"dont-discover": []
}
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true,
"allow-plugins": {
"pestphp/pest-plugin": true,
"php-http/discovery": true
}
},
"minimum-stability": "stable",
"prefer-stable": true
}
Generated
+8311
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
<?php
return [
'name' => env('APP_NAME', 'Nexus'),
'env' => env('APP_ENV', 'production'),
'debug' => (bool) env('APP_DEBUG', false),
'url' => env('APP_URL', 'http://localhost'),
'timezone' => 'Europe/Berlin',
'locale' => env('APP_LOCALE', 'de'),
'fallback_locale' => env('APP_FALLBACK_LOCALE', 'de'),
'faker_locale' => env('APP_FAKER_LOCALE', 'de_DE'),
'cipher' => 'AES-256-CBC',
'key' => env('APP_KEY'),
'previous_keys' => [
...array_filter(
explode(',', env('APP_PREVIOUS_KEYS', ''))
),
],
'maintenance' => [
'driver' => env('APP_MAINTENANCE_DRIVER', 'file'),
'store' => env('APP_MAINTENANCE_STORE', 'database'),
],
];
+35
View File
@@ -0,0 +1,35 @@
<?php
return [
'defaults' => [
'guard' => env('AUTH_GUARD', 'web'),
'passwords' => env('AUTH_PASSWORD_BROKER', 'users'),
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => env('AUTH_MODEL', App\Models\User::class),
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'),
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800),
];
+40
View File
@@ -0,0 +1,40 @@
<?php
use Illuminate\Support\Str;
return [
'default' => env('CACHE_STORE', 'database'),
'stores' => [
'array' => [
'driver' => 'array',
'serialize' => false,
],
'database' => [
'driver' => 'database',
'connection' => env('DB_CACHE_CONNECTION'),
'table' => env('DB_CACHE_TABLE', 'cache'),
'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'),
'lock_table' => env('DB_CACHE_LOCK_TABLE'),
],
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
'lock_path' => storage_path('framework/cache/data'),
],
'redis' => [
'driver' => 'redis',
'connection' => env('REDIS_CACHE_CONNECTION', 'cache'),
'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'),
],
],
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'nexus'), '_').'_cache_'),
];
+73
View File
@@ -0,0 +1,73 @@
<?php
use Illuminate\Support\Str;
return [
'default' => env('DB_CONNECTION', 'mysql'),
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'url' => env('DB_URL'),
'database' => env('DB_DATABASE', database_path('database.sqlite')),
'prefix' => '',
'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
'busy_timeout' => null,
'journal_mode' => null,
'synchronous' => null,
],
'mysql' => [
'driver' => 'mysql',
'url' => env('DB_URL'),
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'nexus'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
'options' => extension_loaded('pdo_mysql') ? array_filter([
Pdo\Mysql::ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
]) : [],
],
],
'migrations' => [
'table' => 'migrations',
'update_date_on_publish' => true,
],
'redis' => [
'client' => env('REDIS_CLIENT', 'phpredis'),
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DB', '0'),
],
'cache' => [
'url' => env('REDIS_URL'),
'host' => env('REDIS_HOST', '127.0.0.1'),
'username' => env('REDIS_USERNAME'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_CACHE_DB', '1'),
],1
],
];
+32
View File
@@ -0,0 +1,32 @@
<?php
return [
'default' => env('FILESYSTEM_DISK', 'local'),
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'serve' => true,
'throw' => false,
'report' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
'report' => false,
],
],
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
+60
View File
@@ -0,0 +1,60 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\Processor\PsrLogMessageProcessor;
return [
'default' => env('LOG_CHANNEL', 'stack'),
'deprecations' => [
'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'),
'trace' => env('LOG_DEPRECATIONS_TRACE', false),
],
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => explode(',', env('LOG_STACK', 'single')),
'ignore_exceptions' => false,
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'replace_placeholders' => true,
],
'daily' => [
'driver' => 'daily',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'days' => env('LOG_DAILY_DAYS', 14),
'replace_placeholders' => true,
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => ['stream' => 'php://stderr'],
'processors' => [PsrLogMessageProcessor::class],
],
'null' => [
'driver' => 'monolog',
'handler' => NullHandler::class,
],
'emergency' => [
'path' => storage_path('logs/laravel.log'),
],
],
];
+37
View File
@@ -0,0 +1,37 @@
<?php
return [
'default' => env('MAIL_MAILER', 'log'),
'mailers' => [
'smtp' => [
'transport' => 'smtp',
'scheme' => env('MAIL_SCHEME'),
'url' => env('MAIL_URL'),
'host' => env('MAIL_HOST', '127.0.0.1'),
'port' => env('MAIL_PORT', 2525),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)),
],
'log' => [
'transport' => 'log',
'channel' => env('MAIL_LOG_CHANNEL'),
],
'array' => [
'transport' => 'array',
],
],
'from' => [
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
'name' => env('MAIL_FROM_NAME', 'Nexus'),
],
];
+35
View File
@@ -0,0 +1,35 @@
<?php
return [
'default' => env('QUEUE_CONNECTION', 'database'),
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'connection' => env('DB_QUEUE_CONNECTION'),
'table' => env('DB_QUEUE_TABLE', 'jobs'),
'queue' => env('DB_QUEUE', 'default'),
'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90),
'after_commit' => false,
],
],
'batching' => [
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'job_batches',
],
'failed' => [
'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'),
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],
];
+26
View File
@@ -0,0 +1,26 @@
<?php
return [
'postmark' => [
'token' => env('POSTMARK_TOKEN'),
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
],
'resend' => [
'key' => env('RESEND_KEY'),
],
'slack' => [
'notifications' => [
'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'),
'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'),
],
],
];
+24
View File
@@ -0,0 +1,24 @@
<?php
use Illuminate\Support\Str;
return [
'driver' => env('SESSION_DRIVER', 'database'),
'lifetime' => env('SESSION_LIFETIME', 120),
'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false),
'encrypt' => env('SESSION_ENCRYPT', false),
'files' => storage_path('framework/sessions'),
'connection' => env('SESSION_CONNECTION'),
'table' => env('SESSION_TABLE', 'sessions'),
'store' => env('SESSION_STORE'),
'lottery' => [2, 100],
'cookie' => env('SESSION_COOKIE', Str::slug(env('APP_NAME', 'nexus'), '_').'_session'),
'path' => env('SESSION_PATH', '/'),
'domain' => env('SESSION_DOMAIN'),
'secure' => env('SESSION_SECURE_COOKIE'),
'http_only' => env('SESSION_HTTP_ONLY', true),
'same_site' => env('SESSION_SAME_SITE', 'lax'),
'partitioned' => env('SESSION_PARTITIONED_COOKIE', false),
];
+3
View File
@@ -0,0 +1,3 @@
*.sqlite
*.sqlite-shm
*.sqlite-wal
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
protected static ?string $password;
public function definition(): array
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),
'remember_token' => Str::random(10),
];
}
public function unverified(): static
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
@@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
});
Schema::create('sessions', function (Blueprint $table) {
$table->string('id')->primary();
$table->foreignId('user_id')->nullable()->index();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->longText('payload');
$table->integer('last_activity')->index();
});
}
public function down(): void
{
Schema::dropIfExists('users');
Schema::dropIfExists('password_reset_tokens');
Schema::dropIfExists('sessions');
}
};
@@ -0,0 +1,29 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('cache', function (Blueprint $table) {
$table->string('key')->primary();
$table->mediumText('value');
$table->integer('expiration');
});
Schema::create('cache_locks', function (Blueprint $table) {
$table->string('key')->primary();
$table->string('owner');
$table->integer('expiration');
});
}
public function down(): void
{
Schema::dropIfExists('cache');
Schema::dropIfExists('cache_locks');
}
};
@@ -0,0 +1,51 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('jobs', function (Blueprint $table) {
$table->id();
$table->string('queue')->index();
$table->longText('payload');
$table->unsignedTinyInteger('attempts');
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
});
Schema::create('job_batches', function (Blueprint $table) {
$table->string('id')->primary();
$table->string('name');
$table->integer('total_jobs');
$table->integer('pending_jobs');
$table->integer('failed_jobs');
$table->longText('failed_job_ids');
$table->mediumText('options')->nullable();
$table->integer('cancelled_at')->nullable();
$table->integer('created_at');
$table->integer('finished_at')->nullable();
});
Schema::create('failed_jobs', function (Blueprint $table) {
$table->id();
$table->string('uuid')->unique();
$table->text('connection');
$table->text('queue');
$table->longText('payload');
$table->longText('exception');
$table->timestamp('failed_at')->useCurrent();
});
}
public function down(): void
{
Schema::dropIfExists('jobs');
Schema::dropIfExists('job_batches');
Schema::dropIfExists('failed_jobs');
}
};
+13
View File
@@ -0,0 +1,13 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
public function run(): void
{
//
}
}
+51
View File
@@ -0,0 +1,51 @@
app := "nexus-nexus-app-1"
composer := "php /usr/bin/composer"
# Docker
up:
docker compose up -d
down:
docker compose down
build:
docker compose build
rebuild:
docker compose down
docker compose build --no-cache
docker compose up -d
logs:
docker compose logs -f
shell:
docker exec -it {{app}} bash
# Laravel
artisan *args:
docker exec -it {{app}} php artisan {{args}}
composer *args:
docker exec -it {{app}} {{composer}} {{args}}
migrate:
docker exec -it {{app}} php artisan migrate
migrate-fresh:
docker exec -it {{app}} php artisan migrate:fresh --seed
tinker:
docker exec -it {{app}} php artisan tinker
test:
docker exec -it {{app}} php artisan test
# Setup
setup:
docker exec {{app}} {{composer}} install
docker exec {{app}} sh -c "[ -f .env ] || cp .env.example .env"
docker exec -it {{app}} php artisan key:generate
docker exec -it {{app}} php artisan migrate --force
docker exec nexus-frontend npm install
docker exec nexus-frontend npm run build
+3108
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
{
"$schema": "https://www.schemastore.org/package.json",
"private": true,
"type": "module",
"scripts": {
"build": "vite build",
"dev": "vite",
"watch": "vite build --watch"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0",
"@vitejs/plugin-vue": "^6.0.3",
"autoprefixer": "^10.4.24",
"axios": "^1.11.0",
"concurrently": "^9.0.1",
"laravel-vite-plugin": "^2.0.0",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.18",
"vite": "^7.0.7"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^7.1.0",
"@fortawesome/free-solid-svg-icons": "^7.1.0",
"@fortawesome/vue-fontawesome": "^3.1.3",
"@inertiajs/progress": "^0.1.2",
"@inertiajs/vue3": "^2.3.12",
"date-fns": "^4.1.0",
"vue": "^3.5.27",
"vue3-toastify": "^0.2.8"
}
}
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="APP_MAINTENANCE_DRIVER" value="array"/>
<env name="BCRYPT_ROUNDS" value="1"/>
<env name="CACHE_STORE" value="array"/>
<env name="DB_CONNECTION" value="sqlite"/>
<env name="DB_DATABASE" value=":memory:"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
+21
View File
@@ -0,0 +1,21 @@
<IfModule mod_rewrite.c>
<IfModule mod_negotiation.c>
Options -MultiViews -Indexes
</IfModule>
RewriteEngine On
# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# Redirect Trailing Slashes If Not A Folder...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} (.+)/$
RewriteRule ^ %1 [L,R=301]
# Send Requests To Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
+17
View File
@@ -0,0 +1,17 @@
<?php
use Illuminate\Http\Request;
define('LARAVEL_START', microtime(true));
// Determine if the application is in maintenance mode...
if (file_exists($maintenance = __DIR__.'/../storage/framework/maintenance.php')) {
require $maintenance;
}
// Register the Composer autoloader...
require __DIR__.'/../vendor/autoload.php';
// Bootstrap Laravel and handle the request...
(require_once __DIR__.'/../bootstrap/app.php')
->handleRequest(Request::capture());
+2
View File
@@ -0,0 +1,2 @@
User-agent: *
Disallow:
+9
View File
@@ -0,0 +1,9 @@
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
+56
View File
@@ -0,0 +1,56 @@
import '../css/app.css'
import './bootstrap.js'
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { InertiaProgress } from '@inertiajs/progress'
import Vue3Toastify, { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css'
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { faUser, faTrash, faCheck, faGear, faHouse } from '@fortawesome/free-solid-svg-icons'
library.add(faUser, faTrash, faCheck, faGear, faHouse)
InertiaProgress.init()
createInertiaApp({
resolve: name => {
const pages = import.meta.glob('@domains/**/*.vue')
const key = Object.keys(pages).find(k =>
k.endsWith(`/${name}.vue`) || k.endsWith(`/${name}/index.vue`)
)
if (!key) throw new Error(`Page not found: ${name}`)
return pages[key]()
},
setup({ el, App, props, plugin }) {
const vueApp = createApp({ render: () => h(App, props) })
vueApp.use(plugin)
vueApp.component('font-awesome-icon', FontAwesomeIcon)
vueApp.use(Vue3Toastify, {
autoClose: 10000,
position: 'bottom-right',
pauseOnHover: true,
hideProgressBar: false,
toastDefaults: {
success: {
style: { background: '#4caf50', color: '#fff' },
progressStyle: { background: '#2e7d32', height: '4px' },
},
error: {
style: { background: '#f44336', color: '#fff' },
progressStyle: { background: '#c62828', height: '4px' },
},
},
})
vueApp.config.globalProperties.$toast = toast
vueApp.mount(el)
},
})
+4
View File
@@ -0,0 +1,4 @@
import axios from 'axios'
window.axios = axios
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'
+293
View File
@@ -0,0 +1,293 @@
<script setup>
import { ref } from 'vue'
const props = defineProps({
title: { type: String, default: 'Nexus' },
})
const sidebarOpen = ref(false)
function toggleSidebar() {
sidebarOpen.value = !sidebarOpen.value
}
function closeSidebar() {
sidebarOpen.value = false
}
</script>
<template>
<div class="app-layout">
<div class="sidebar-overlay" :class="{ active: sidebarOpen }" @click="closeSidebar"></div>
<div class="main">
<div class="header">
<button class="hamburger-btn" @click="toggleSidebar" aria-label="Menü öffnen">
<span></span>
<span></span>
<span></span>
</button>
<div class="left-side">
<h1>{{ props.title }}</h1>
</div>
<div class="header-actions">
<a href="/logout" class="header-link-logout" title="Abmelden">Abmelden</a>
</div>
</div>
<div class="flexbox">
<div class="sidebar" :class="{ 'sidebar-open': sidebarOpen }">
<div class="logo">
<span class="logo-text">Nexus</span>
</div>
<nav class="nav">
<ul class="nav-links">
<li><a href="/" @click="closeSidebar">Dashboard</a></li>
</ul>
</nav>
</div>
<div class="content-area">
<div class="content">
<slot />
</div>
</div>
</div>
<footer class="footer">
<div class="footer-inner">
<span>Nexus</span>
<span>&copy; {{ new Date().getFullYear() }}</span>
</div>
</footer>
</div>
</div>
</template>
<style scoped>
.app-layout {
display: flex;
height: 100vh;
background: #f0f2f5;
font-family: sans-serif;
overflow: hidden;
}
.main {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
margin: 20px;
box-shadow: 20px 20px 15px rgba(0, 0, 0, 0.1);
border-radius: 0 10px 0 0;
}
.header {
display: flex;
align-items: center;
height: 80px;
background: #ffffff;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
padding: 0;
position: relative;
z-index: 50;
flex-shrink: 0;
}
.left-side {
flex: 1;
padding: 0 20px;
}
.left-side h1 {
margin: 0;
font-size: 1.4rem;
}
.header-actions {
display: flex;
align-items: center;
padding: 0 20px;
flex-shrink: 0;
}
.header-link-logout {
color: #000;
font-weight: bold;
text-decoration: none;
padding: 10px 20px;
}
.header-link-logout:hover {
background-color: #ff0000;
color: #fff;
}
.hamburger-btn {
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 5px;
width: 50px;
height: 80px;
border: none;
background: transparent;
cursor: pointer;
flex-shrink: 0;
padding: 0 12px;
}
.hamburger-btn span {
display: block;
width: 24px;
height: 3px;
background-color: #333;
border-radius: 2px;
}
.flexbox {
display: flex;
flex: 1;
background-color: #fafafb;
overflow: hidden;
gap: 1px;
}
.sidebar {
flex-basis: 275px;
flex-shrink: 0;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
background-color: #ffffff;
overflow-y: auto;
transition: transform 0.3s ease;
}
.sidebar-overlay {
display: none;
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 99;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
padding: 30px 0;
height: 120px;
}
.logo-text {
font-size: 2rem;
font-weight: bold;
color: #1d4899;
}
.nav {
flex: 1;
}
.nav ul {
list-style: none;
padding: 0;
margin: 0;
border-bottom: 1px solid #ddd;
}
.nav-links li a {
color: #b6b6b6;
background-color: #fff;
padding: 16px 25px;
display: block;
text-decoration: none;
font-weight: bold;
}
.nav-links li a:hover {
background-color: #1d4899;
color: #fff;
}
.content-area {
flex: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
overflow-x: hidden;
}
.content {
padding: 30px 20px;
flex: 1;
}
.footer {
background: #666666;
border-top: 1px solid #ddd;
color: #fff;
padding: 10px 15px;
font-size: 11pt;
font-weight: bold;
flex-shrink: 0;
}
.footer-inner {
display: flex;
flex-wrap: wrap;
gap: 10px 20px;
justify-content: space-between;
align-items: center;
}
@media (max-width: 1023px) {
.main {
margin: 0;
border-radius: 0;
box-shadow: none;
}
.hamburger-btn {
display: flex;
}
.sidebar {
position: fixed;
left: 0;
top: 0;
bottom: 0;
z-index: 100;
transform: translateX(-100%);
width: 260px;
flex-basis: 260px;
}
.sidebar.sidebar-open {
transform: translateX(0);
}
.sidebar-overlay.active {
display: block;
}
}
@media (max-width: 639px) {
.header {
height: 60px;
}
.hamburger-btn {
height: 60px;
}
.content {
padding: 15px 10px;
}
}
</style>
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title inertia>{{ config('app.name', 'Nexus') }}</title>
@vite(['resources/js/app.js'])
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
+5
View File
@@ -0,0 +1,5 @@
<?php
use Illuminate\Support\Facades\Route;
require_once __DIR__.'/../app/Domains/Dashboard/Routes/api.php';
+8
View File
@@ -0,0 +1,8 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote');
+5
View File
@@ -0,0 +1,5 @@
<?php
use Illuminate\Support\Facades\Route;
require_once __DIR__.'/../app/Domains/Dashboard/Routes/web.php';
+3
View File
@@ -0,0 +1,3 @@
*
!public/
!.gitignore
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+2
View File
@@ -0,0 +1,2 @@
*
!.gitignore
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
//
}
+26
View File
@@ -0,0 +1,26 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import laravel from 'laravel-vite-plugin'
import path from 'path'
export default defineConfig({
base: '',
plugins: [
laravel({
input: 'resources/js/app.js',
refresh: true,
}),
vue(),
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'resources/js'),
'@domains': path.resolve(__dirname, 'app/Domains'),
},
},
server: {
host: true,
strictPort: true,
cors: true,
},
})