Initialer Laravel Commit für BetiX
This commit is contained in:
1
database/.gitignore
vendored
Normal file
1
database/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*.sqlite*
|
||||
60
database/factories/UserFactory.php
Normal file
60
database/factories/UserFactory.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
*/
|
||||
class UserFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The current password being used by the factory.
|
||||
*/
|
||||
protected static ?string $password;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'username' => fake()->unique()->userName(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
'remember_token' => Str::random(10),
|
||||
'two_factor_secret' => null,
|
||||
'two_factor_recovery_codes' => null,
|
||||
'two_factor_confirmed_at' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model's email address should be unverified.
|
||||
*/
|
||||
public function unverified(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'email_verified_at' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the model has two-factor authentication configured.
|
||||
*/
|
||||
public function withTwoFactor(): static
|
||||
{
|
||||
return $this->state(fn (array $attributes) => [
|
||||
'two_factor_secret' => encrypt('secret'),
|
||||
'two_factor_recovery_codes' => encrypt(json_encode(['recovery-code-1'])),
|
||||
'two_factor_confirmed_at' => now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
35
database/migrations/0001_01_01_000001_create_cache_table.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('cache', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->mediumText('value');
|
||||
$table->integer('expiration')->index();
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->integer('expiration')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
57
database/migrations/0001_01_01_000002_create_jobs_table.php
Normal file
57
database/migrations/0001_01_01_000002_create_jobs_table.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
112
database/migrations/2026_01_01_000001_create_users_table.php
Normal file
112
database/migrations/2026_01_01_000001_create_users_table.php
Normal file
@@ -0,0 +1,112 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// USERS (all columns consolidated from scattered add_* migrations)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
// --- Public Identity ---
|
||||
$table->string('username')->unique();
|
||||
$table->string('username_index')->unique(); // Blind index for case-insensitive lookups
|
||||
$table->string('name');
|
||||
|
||||
// --- Private Identity (Encrypted) ---
|
||||
$table->text('email'); // Encrypted via SafeEncryptedString cast
|
||||
$table->string('email_index')->unique(); // Blind index for login lookups
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
|
||||
// --- Role & Status ---
|
||||
$table->string('role')->default('user'); // admin | mod | streamer | user
|
||||
$table->string('clan_tag')->nullable();
|
||||
$table->string('avatar_url')->nullable(); // OAuth / external avatar
|
||||
$table->string('avatar')->nullable(); // Uploaded avatar
|
||||
$table->string('banner')->nullable(); // Uploaded banner
|
||||
$table->text('bio')->nullable();
|
||||
$table->boolean('is_public')->default(false);
|
||||
$table->boolean('is_adult')->default(false);
|
||||
$table->boolean('is_banned')->default(false);
|
||||
|
||||
// --- VIP & Balance ---
|
||||
$table->integer('vip_level')->default(0);
|
||||
$table->string('preferred_locale', 8)->nullable();
|
||||
$table->decimal('balance', 16, 4)->default(0); // BTX main balance
|
||||
$table->string('currency', 3)->default('EUR');
|
||||
|
||||
// --- Vault ---
|
||||
$table->decimal('vault_balance', 16, 4)->default(0); // BTX vault balance (plaintext decimal)
|
||||
$table->text('vault_balances')->nullable(); // JSON map for multi-currency vault
|
||||
$table->string('vault_pin_hash')->nullable();
|
||||
$table->timestamp('vault_pin_set_at')->nullable();
|
||||
$table->unsignedSmallInteger('vault_pin_attempts')->default(0);
|
||||
$table->timestamp('vault_pin_locked_until')->nullable();
|
||||
$table->timestamp('withdraw_cooldown_until')->nullable();
|
||||
|
||||
// --- Personal Details (Encrypted PII) ---
|
||||
$table->text('first_name')->nullable();
|
||||
$table->text('last_name')->nullable();
|
||||
$table->text('birthdate')->nullable();
|
||||
$table->text('gender')->nullable();
|
||||
$table->text('phone')->nullable();
|
||||
|
||||
// --- Address (Encrypted PII) ---
|
||||
$table->text('country')->nullable();
|
||||
$table->text('address_line1')->nullable();
|
||||
$table->text('address_line2')->nullable();
|
||||
$table->text('city')->nullable();
|
||||
$table->text('state')->nullable();
|
||||
$table->text('postal_code')->nullable();
|
||||
|
||||
// --- 2FA ---
|
||||
$table->text('two_factor_secret')->nullable();
|
||||
$table->text('two_factor_recovery_codes')->nullable();
|
||||
$table->timestamp('two_factor_confirmed_at')->nullable();
|
||||
|
||||
// --- Security & Tracking ---
|
||||
$table->timestamp('last_login_at')->nullable();
|
||||
$table->text('last_login_ip')->nullable();
|
||||
$table->text('last_login_user_agent')->nullable();
|
||||
$table->string('registration_ip', 45)->nullable();
|
||||
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PASSWORD RESET TOKENS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
$table->string('email')->primary();
|
||||
$table->string('token');
|
||||
$table->timestamp('created_at')->nullable();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// SESSIONS
|
||||
// ---------------------------------------------------------------
|
||||
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('sessions');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('users');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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('user_stats', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
|
||||
$table->unsignedBigInteger('total_logins')->default(0);
|
||||
|
||||
// Stored as TEXT to support Laravel encryption cast
|
||||
$table->text('total_wagered')->nullable();
|
||||
$table->text('total_won')->nullable();
|
||||
$table->text('total_lost')->nullable();
|
||||
$table->text('biggest_win')->nullable();
|
||||
$table->string('biggest_win_game')->nullable();
|
||||
|
||||
$table->unsignedInteger('total_wins')->default(0);
|
||||
$table->unsignedInteger('vip_level')->default(1);
|
||||
$table->unsignedBigInteger('vip_points')->default(0);
|
||||
$table->timestamp('last_activity')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('user_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_stats');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// FRIENDS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('friends', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('friend_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->enum('status', ['pending', 'accepted', 'blocked'])->default('pending');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'friend_id']);
|
||||
$table->index(['friend_id', 'status']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PROFILE LIKES
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('profile_likes', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete(); // The liker
|
||||
$table->foreignId('profile_id')->constrained('users')->cascadeOnDelete(); // The profile owner
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'profile_id']);
|
||||
$table->index('profile_id');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PROFILE COMMENTS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('profile_comments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete(); // The commenter
|
||||
$table->foreignId('profile_id')->constrained('users')->cascadeOnDelete(); // The profile owner
|
||||
$table->text('content');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['profile_id', 'created_at']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PROFILE REPORTS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('profile_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('reporter_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->foreignId('profile_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('reason');
|
||||
$table->text('details')->nullable();
|
||||
$table->json('snapshot')->nullable();
|
||||
$table->string('screenshot_path', 500)->nullable();
|
||||
$table->enum('status', ['pending', 'reviewed', 'dismissed'])->default('pending');
|
||||
$table->text('admin_note')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['profile_id', 'status']);
|
||||
$table->index('reporter_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('profile_reports');
|
||||
Schema::dropIfExists('profile_comments');
|
||||
Schema::dropIfExists('profile_likes');
|
||||
Schema::dropIfExists('friends');
|
||||
}
|
||||
};
|
||||
69
database/migrations/2026_01_01_000004_create_chat_tables.php
Normal file
69
database/migrations/2026_01_01_000004_create_chat_tables.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// CHAT MESSAGES
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('chat_messages', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('reply_to_id')->nullable()->constrained('chat_messages')->nullOnDelete();
|
||||
$table->text('message'); // Stored encrypted
|
||||
$table->boolean('is_deleted')->default(false);
|
||||
$table->unsignedBigInteger('deleted_by')->nullable(); // user_id of moderator/admin
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['created_at']);
|
||||
$table->index('reply_to_id');
|
||||
$table->index(['user_id', 'created_at']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// CHAT MESSAGE REACTIONS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('chat_message_reactions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('message_id')->constrained('chat_messages')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('emoji', 16);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['message_id', 'user_id', 'emoji'], 'uniq_reaction');
|
||||
$table->index(['message_id', 'user_id']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// CHAT MESSAGE REPORTS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('chat_message_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('reporter_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('message_id');
|
||||
$table->text('message_text');
|
||||
$table->unsignedBigInteger('sender_id')->nullable();
|
||||
$table->string('sender_username')->nullable();
|
||||
$table->string('reason')->nullable();
|
||||
$table->json('context_messages')->nullable(); // Previous messages for context
|
||||
$table->enum('status', ['pending', 'reviewed', 'dismissed'])->default('pending');
|
||||
$table->text('admin_note')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('reporter_id');
|
||||
$table->index('status');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('chat_message_reports');
|
||||
Schema::dropIfExists('chat_message_reactions');
|
||||
Schema::dropIfExists('chat_messages');
|
||||
}
|
||||
};
|
||||
@@ -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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// GUILDS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('guilds', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('owner_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('name', 64)->unique();
|
||||
$table->string('tag', 6)->unique();
|
||||
$table->string('logo_url')->nullable();
|
||||
$table->string('invite_code', 16)->unique();
|
||||
$table->string('description', 500)->nullable();
|
||||
$table->unsignedInteger('points')->default(0);
|
||||
$table->unsignedInteger('members_count')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['owner_id']);
|
||||
$table->index(['points', 'members_count']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// GUILD MEMBERS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('guild_members', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('guild_id')->constrained('guilds')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('role', 16)->default('member'); // owner | officer | member
|
||||
$table->timestamp('joined_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['guild_id', 'user_id']);
|
||||
$table->index('user_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('guild_members');
|
||||
Schema::dropIfExists('guilds');
|
||||
}
|
||||
};
|
||||
36
database/migrations/2026_01_01_000006_create_kyc_table.php
Normal file
36
database/migrations/2026_01_01_000006_create_kyc_table.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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('kyc_documents', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('category', 24); // identity | address | payment
|
||||
$table->string('type', 32); // passport | driver_license | id_card | bank_statement | utility_bill | other
|
||||
$table->string('status', 16)->default('pending'); // pending | approved | rejected
|
||||
$table->string('rejection_reason', 255)->nullable();
|
||||
$table->string('file_path');
|
||||
$table->string('mime', 100);
|
||||
$table->unsignedBigInteger('size');
|
||||
$table->timestamp('submitted_at')->nullable();
|
||||
$table->timestamp('reviewed_at')->nullable();
|
||||
$table->foreignId('reviewed_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'status']);
|
||||
$table->index('category');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('kyc_documents');
|
||||
}
|
||||
};
|
||||
122
database/migrations/2026_01_01_000007_create_wallet_tables.php
Normal file
122
database/migrations/2026_01_01_000007_create_wallet_tables.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// PERSONAL ACCESS TOKENS (Sanctum)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('personal_access_tokens', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->morphs('tokenable');
|
||||
$table->text('name');
|
||||
$table->string('token', 64)->unique();
|
||||
$table->text('abilities')->nullable();
|
||||
$table->timestamp('last_used_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable()->index();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// WALLETS (per-currency balance per user)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('wallets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('currency', 10); // BTC | ETH | SOL | BTX | EUR
|
||||
$table->decimal('balance', 20, 8)->default(0);
|
||||
$table->string('deposit_address')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'currency']);
|
||||
$table->index(['user_id', 'currency']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// WALLET TRANSFERS (main balance <-> vault, audit log)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('wallet_transfers', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->enum('type', ['deposit', 'withdraw']); // deposit = main->vault, withdraw = vault->main
|
||||
$table->decimal('amount', 20, 4);
|
||||
$table->decimal('balance_before', 20, 4);
|
||||
$table->decimal('balance_after', 20, 4);
|
||||
$table->decimal('vault_before', 20, 4);
|
||||
$table->decimal('vault_after', 20, 4);
|
||||
$table->string('currency', 10)->default('BTX');
|
||||
$table->string('idempotency_key', 64)->nullable();
|
||||
$table->json('meta')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'created_at']);
|
||||
$table->index(['user_id', 'type']);
|
||||
$table->unique(['user_id', 'idempotency_key']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// VAULT TRANSFERS (encrypted audit trail)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('vault_transfers', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('direction', 16); // to_vault | from_vault
|
||||
$table->text('amount'); // Encrypted
|
||||
$table->text('main_balance_before'); // Encrypted
|
||||
$table->text('main_balance_after'); // Encrypted
|
||||
$table->text('vault_balance_before'); // Encrypted
|
||||
$table->text('vault_balance_after'); // Encrypted
|
||||
$table->string('idempotency_key', 64)->nullable();
|
||||
$table->string('source', 16)->default('web'); // web | api
|
||||
$table->unsignedBigInteger('created_by')->nullable();
|
||||
$table->text('metadata')->nullable(); // Encrypted
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'created_at']);
|
||||
$table->index(['user_id', 'direction']);
|
||||
$table->unique(['user_id', 'idempotency_key']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// CRYPTO PAYMENTS (NOWPayments / on-chain deposits)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('crypto_payments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->uuid('order_id')->unique();
|
||||
$table->string('invoice_id')->unique();
|
||||
$table->string('payment_id')->unique();
|
||||
$table->string('pay_currency', 20);
|
||||
$table->decimal('pay_amount', 36, 18)->nullable();
|
||||
$table->decimal('actually_paid', 36, 18)->nullable();
|
||||
$table->string('pay_address')->nullable();
|
||||
$table->decimal('price_amount', 20, 8)->nullable();
|
||||
$table->string('price_currency', 10)->default('USD');
|
||||
$table->decimal('exchange_rate_at_payment', 28, 12)->nullable();
|
||||
$table->string('status', 40)->index(); // waiting | confirming | finished | failed | expired | partially_paid
|
||||
$table->unsignedInteger('confirmations')->nullable();
|
||||
$table->json('tx_hash')->nullable();
|
||||
$table->decimal('fee', 36, 18)->nullable();
|
||||
$table->json('raw_payload')->nullable();
|
||||
$table->decimal('credited_btx', 20, 8)->nullable();
|
||||
$table->timestamp('credited_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'status']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('crypto_payments');
|
||||
Schema::dropIfExists('vault_transfers');
|
||||
Schema::dropIfExists('wallet_transfers');
|
||||
Schema::dropIfExists('wallets');
|
||||
Schema::dropIfExists('personal_access_tokens');
|
||||
}
|
||||
};
|
||||
129
database/migrations/2026_01_01_000008_create_bonus_tables.php
Normal file
129
database/migrations/2026_01_01_000008_create_bonus_tables.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// VIP REWARDS (claimed level-up rewards)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('vip_rewards', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->integer('level');
|
||||
$table->decimal('amount', 10, 2);
|
||||
$table->timestamp('claimed_at');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'level']); // Prevent double-claiming
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// BONUSES (admin-created bonus campaigns)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('bonuses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('title');
|
||||
$table->string('type')->nullable(); // welcome | reload | spins
|
||||
$table->decimal('amount_value', 18, 8)->nullable();
|
||||
$table->string('amount_unit', 32)->nullable(); // USD | BTC | PERCENT | SPINS
|
||||
$table->decimal('min_deposit', 18, 8)->nullable();
|
||||
$table->decimal('max_amount', 18, 8)->nullable();
|
||||
$table->string('currency', 16)->nullable();
|
||||
$table->string('code')->nullable();
|
||||
$table->string('status')->default('draft'); // draft | active | paused | expired
|
||||
$table->timestamp('starts_at')->nullable();
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->json('rules')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->foreignId('created_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['status', 'starts_at', 'expires_at']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PROMOS (promo code system)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('promos', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('code')->unique(); // Uppercase normalized
|
||||
$table->string('description')->nullable();
|
||||
$table->decimal('bonus_amount', 16, 4)->default(0);
|
||||
$table->unsignedInteger('wager_multiplier')->default(0);
|
||||
$table->unsignedInteger('per_user_limit')->default(1);
|
||||
$table->unsignedInteger('global_limit')->nullable();
|
||||
$table->timestamp('starts_at')->nullable();
|
||||
$table->timestamp('ends_at')->nullable();
|
||||
$table->decimal('min_deposit', 16, 4)->nullable();
|
||||
$table->unsignedInteger('bonus_expires_days')->nullable();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['is_active', 'starts_at', 'ends_at']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PROMO USAGES (per-use audit)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('promo_usages', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('promo_id')->constrained('promos')->cascadeOnDelete();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->timestamp('used_at');
|
||||
$table->string('ip', 45)->nullable();
|
||||
$table->text('user_agent')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['promo_id', 'user_id', 'used_at']);
|
||||
$table->index(['user_id', 'promo_id']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// PROMO CLAIMS (anti-abuse: one entry per user per promo)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('promo_claims', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->foreignId('promo_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('ip_address')->nullable();
|
||||
$table->string('device_hash')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'promo_id']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// USER BONUSES (active bonus progress per user)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('user_bonuses', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->foreignId('promo_id')->nullable()->constrained('promos')->nullOnDelete();
|
||||
$table->decimal('amount', 16, 4);
|
||||
$table->decimal('wager_required', 16, 4)->default(0);
|
||||
$table->decimal('wager_progress', 16, 4)->default(0);
|
||||
$table->timestamp('expires_at')->nullable();
|
||||
$table->boolean('is_active')->default(true);
|
||||
$table->timestamp('completed_at')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'is_active']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_bonuses');
|
||||
Schema::dropIfExists('promo_claims');
|
||||
Schema::dropIfExists('promo_usages');
|
||||
Schema::dropIfExists('promos');
|
||||
Schema::dropIfExists('bonuses');
|
||||
Schema::dropIfExists('vip_rewards');
|
||||
}
|
||||
};
|
||||
91
database/migrations/2026_01_01_000009_create_game_tables.php
Normal file
91
database/migrations/2026_01_01_000009_create_game_tables.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// GAME BETS (bet history)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('game_bets', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('game_name');
|
||||
$table->decimal('wager_amount', 16, 8)->default(0);
|
||||
$table->decimal('payout_multiplier', 8, 4)->default(0);
|
||||
$table->decimal('payout_amount', 16, 8)->default(0);
|
||||
$table->string('currency', 32)->default('BTX');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['user_id', 'created_at']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// USER FAVORITES (saved / bookmarked games)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('user_favorites', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('game_slug', 128);
|
||||
$table->string('game_name', 255)->nullable();
|
||||
$table->string('game_image', 512)->nullable();
|
||||
$table->string('game_provider', 100)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'game_slug']);
|
||||
$table->index('user_id');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// USER ACHIEVEMENTS
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('user_achievements', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('achievement_key', 64); // e.g. first_bet | big_winner
|
||||
$table->timestamp('unlocked_at');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['user_id', 'achievement_key']);
|
||||
$table->index('user_id');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// USER FEEDBACK (UX ratings & comments)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('user_feedback', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->string('category', 30)->default('general'); // general | ux | mobile | feature | complaint
|
||||
$table->unsignedTinyInteger('overall_rating')->nullable(); // 1-5
|
||||
$table->unsignedTinyInteger('ux_rating')->nullable(); // 1-5
|
||||
$table->unsignedTinyInteger('comfort_rating')->nullable(); // 1-5
|
||||
$table->unsignedTinyInteger('mobile_rating')->nullable(); // 1-5
|
||||
$table->boolean('uses_mobile')->nullable();
|
||||
$table->unsignedTinyInteger('nps_score')->nullable(); // 1-10
|
||||
$table->text('ux_comment')->nullable();
|
||||
$table->text('mobile_comment')->nullable();
|
||||
$table->text('feature_request')->nullable();
|
||||
$table->text('improvements')->nullable();
|
||||
$table->text('general_comment')->nullable();
|
||||
$table->enum('status', ['new', 'read'])->default('new');
|
||||
$table->text('admin_note')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['status', 'created_at']);
|
||||
$table->index('user_id');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('user_feedback');
|
||||
Schema::dropIfExists('user_achievements');
|
||||
Schema::dropIfExists('user_favorites');
|
||||
Schema::dropIfExists('game_bets');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,79 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// APP SETTINGS (key-value store for site configuration)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('app_settings', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('key')->unique();
|
||||
$table->json('value');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// USER RESTRICTIONS (bans, chat bans, etc.)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('user_restrictions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('type', 64); // account_ban | chat_ban | deposit_block | withdrawal_block | support_block
|
||||
$table->string('reason', 255)->nullable();
|
||||
$table->text('notes')->nullable();
|
||||
$table->foreignId('imposed_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->timestamp('starts_at')->nullable();
|
||||
$table->timestamp('ends_at')->nullable();
|
||||
$table->boolean('active')->default(true);
|
||||
$table->string('source', 64)->nullable(); // api | admin_panel | system
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index(['user_id', 'type', 'active']);
|
||||
$table->index(['user_id', 'active']);
|
||||
$table->index('ends_at');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// TIPS (peer-to-peer balance transfers)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('tips', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('from_user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->foreignId('to_user_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->string('currency', 10);
|
||||
$table->decimal('amount', 20, 8);
|
||||
$table->string('note', 140)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['from_user_id', 'to_user_id']);
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// NOTIFICATIONS (Laravel default notification table)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('notifications', function (Blueprint $table) {
|
||||
$table->uuid('id')->primary();
|
||||
$table->string('type');
|
||||
$table->morphs('notifiable');
|
||||
$table->text('data');
|
||||
$table->timestamp('read_at')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('notifications');
|
||||
Schema::dropIfExists('tips');
|
||||
Schema::dropIfExists('user_restrictions');
|
||||
Schema::dropIfExists('app_settings');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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
|
||||
{
|
||||
// ---------------------------------------------------------------
|
||||
// OPERATOR CASINOS (B2B license key management)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('operator_casinos', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('license_key_hash', 64)->unique(); // SHA-256 of plaintext key (never store plaintext)
|
||||
$table->string('status', 20)->default('active'); // active | inactive | suspended
|
||||
$table->json('ip_whitelist')->nullable();
|
||||
$table->json('domain_whitelist')->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('status');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// OPERATOR SESSIONS (provably-fair game sessions)
|
||||
// ---------------------------------------------------------------
|
||||
Schema::create('operator_sessions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->uuid('session_token')->unique();
|
||||
$table->foreignId('operator_casino_id')->constrained()->cascadeOnDelete();
|
||||
$table->string('player_id', 255); // Casino's internal player ID
|
||||
$table->string('game_slug', 50);
|
||||
$table->string('currency', 10)->default('EUR');
|
||||
$table->decimal('start_balance', 20, 4)->default(0);
|
||||
$table->decimal('current_balance', 20, 4)->default(0);
|
||||
$table->text('server_seed'); // Encrypted via Laravel encrypt()
|
||||
$table->string('server_seed_hash', 64); // SHA-256 shown to player for provably-fair
|
||||
$table->string('client_seed', 255)->nullable();
|
||||
$table->string('status', 20)->default('active'); // active | expired | ended
|
||||
$table->timestamp('expires_at');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['operator_casino_id', 'player_id']);
|
||||
$table->index('status');
|
||||
$table->index('expires_at');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('operator_sessions');
|
||||
Schema::dropIfExists('operator_casinos');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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('direct_messages', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('sender_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->foreignId('receiver_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->text('message');
|
||||
$table->boolean('is_read')->default(false);
|
||||
$table->boolean('is_deleted')->default(false);
|
||||
$table->foreignId('deleted_by')->nullable()->constrained('users')->nullOnDelete();
|
||||
$table->foreignId('reply_to_id')->nullable()->constrained('direct_messages')->nullOnDelete();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['sender_id', 'receiver_id', 'created_at']);
|
||||
$table->index(['receiver_id', 'is_read']);
|
||||
});
|
||||
|
||||
Schema::create('direct_message_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('reporter_id')->constrained('users')->cascadeOnDelete();
|
||||
$table->foreignId('message_id')->constrained('direct_messages')->cascadeOnDelete();
|
||||
$table->string('reason', 64);
|
||||
$table->text('details')->nullable();
|
||||
$table->enum('status', ['pending', 'reviewed', 'dismissed'])->default('pending');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['reporter_id', 'message_id']);
|
||||
$table->index('status');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('direct_message_reports');
|
||||
Schema::dropIfExists('direct_messages');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?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('guild_messages', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('guild_id');
|
||||
$table->unsignedBigInteger('user_id');
|
||||
$table->string('type')->default('message'); // 'message' | 'system'
|
||||
$table->text('message');
|
||||
$table->unsignedBigInteger('reply_to_id')->nullable();
|
||||
$table->boolean('is_deleted')->default(false);
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('guild_id')->references('id')->on('guilds')->onDelete('cascade');
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->index(['guild_id', 'created_at']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('guild_messages');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
<?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::table('operator_sessions', function (Blueprint $table) {
|
||||
// Covers the session-reuse lookup and the stale-session expiration query:
|
||||
// WHERE player_id = ? AND game_slug = ? AND status = ? AND expires_at > ?
|
||||
$table->index(['player_id', 'game_slug', 'status', 'expires_at'], 'os_player_game_status_expires');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('operator_sessions', function (Blueprint $table) {
|
||||
$table->dropIndex('os_player_game_status_expires');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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::table('game_bets', function (Blueprint $table) {
|
||||
$table->string('session_token', 36)->nullable()->after('currency');
|
||||
$table->unsignedInteger('round_number')->nullable()->after('session_token');
|
||||
$table->string('server_seed_hash', 64)->nullable()->after('round_number');
|
||||
|
||||
$table->index('session_token');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('game_bets', function (Blueprint $table) {
|
||||
$table->dropIndex(['session_token']);
|
||||
$table->dropColumn(['session_token', 'round_number', 'server_seed_hash']);
|
||||
});
|
||||
}
|
||||
};
|
||||
23
database/seeders/DatabaseSeeder.php
Normal file
23
database/seeders/DatabaseSeeder.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Seeders;
|
||||
|
||||
use App\Models\User;
|
||||
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// User::factory(10)->create();
|
||||
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user