Initial PHP rebuild of the app
This commit is contained in:
690 files changed
+33944
-12046
No files matched your search
@@ -0,0 +1,54 @@
|
||||
<?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('User', function (Blueprint $table) {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('name')->nullable();
|
||||
$table->string('email')->nullable()->unique();
|
||||
$table->dateTime('emailVerified')->nullable();
|
||||
$table->string('phone')->nullable()->unique();
|
||||
$table->dateTime('phoneVerified')->nullable();
|
||||
$table->string('image')->nullable();
|
||||
$table->string('passwordHash')->nullable();
|
||||
$table->boolean('isSuperAdmin')->default(false);
|
||||
$table->string('remember_token')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('User');
|
||||
Schema::dropIfExists('password_reset_tokens');
|
||||
Schema::dropIfExists('sessions');
|
||||
}
|
||||
};
|
||||
@@ -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->bigInteger('expiration')->index();
|
||||
});
|
||||
|
||||
Schema::create('cache_locks', function (Blueprint $table) {
|
||||
$table->string('key')->primary();
|
||||
$table->string('owner');
|
||||
$table->bigInteger('expiration')->index();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('cache');
|
||||
Schema::dropIfExists('cache_locks');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
<?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->unsignedSmallInteger('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->string('connection');
|
||||
$table->string('queue');
|
||||
$table->longText('payload');
|
||||
$table->longText('exception');
|
||||
$table->timestamp('failed_at')->useCurrent();
|
||||
|
||||
$table->index(['connection', 'queue', 'failed_at']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('jobs');
|
||||
Schema::dropIfExists('job_batches');
|
||||
Schema::dropIfExists('failed_jobs');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,214 @@
|
||||
<?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('Business', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('slug')->unique();
|
||||
$table->string('name');
|
||||
$table->string('shortName')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->string('logoUrl')->nullable();
|
||||
$table->string('coverImageUrl')->nullable();
|
||||
$table->string('faviconUrl')->nullable();
|
||||
$table->string('appIconUrl')->nullable();
|
||||
$table->string('themeColor')->nullable();
|
||||
$table->string('backgroundColor')->nullable();
|
||||
$table->string('phone')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('website')->nullable();
|
||||
$table->string('instagramUrl')->nullable();
|
||||
$table->string('facebookUrl')->nullable();
|
||||
$table->string('timezone')->default('Europe/London');
|
||||
$table->string('currency', 3)->default('GBP');
|
||||
$table->string('locale')->default('en-GB');
|
||||
$table->boolean('bottomNavShowLabels')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
});
|
||||
|
||||
Schema::create('business_domains', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('hostname')->unique();
|
||||
$table->boolean('isPrimary')->default(false);
|
||||
$table->boolean('isActive')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->index('businessId');
|
||||
});
|
||||
|
||||
Schema::create('BusinessLocation', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('name')->default('Main Location');
|
||||
$table->string('addressLine1');
|
||||
$table->string('addressLine2')->nullable();
|
||||
$table->string('city');
|
||||
$table->string('region')->nullable();
|
||||
$table->string('postalCode');
|
||||
$table->string('country', 2)->default('GB');
|
||||
$table->decimal('latitude', 9, 6)->nullable();
|
||||
$table->decimal('longitude', 9, 6)->nullable();
|
||||
$table->boolean('isPrimary')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->index('businessId');
|
||||
});
|
||||
|
||||
Schema::create('BusinessHours', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('dayOfWeek');
|
||||
$table->boolean('isClosed')->default(false);
|
||||
$table->unsignedSmallInteger('opensAtMinutes')->nullable();
|
||||
$table->unsignedSmallInteger('closesAtMinutes')->nullable();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->unique(['businessId', 'dayOfWeek']);
|
||||
});
|
||||
|
||||
Schema::create('BusinessSettings', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191)->unique();
|
||||
$table->text('cancellationPolicy')->nullable();
|
||||
$table->text('lateArrivalPolicy')->nullable();
|
||||
$table->text('bookingTerms')->nullable();
|
||||
$table->string('privacyPolicyUrl')->nullable();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
});
|
||||
|
||||
Schema::create('BookingRule', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191)->unique();
|
||||
$table->unsignedInteger('minNoticeMinutes')->default(120);
|
||||
$table->unsignedInteger('maxAdvanceDays')->default(60);
|
||||
$table->unsignedInteger('cancellationWindowHours')->default(24);
|
||||
$table->unsignedInteger('rescheduleWindowHours')->default(24);
|
||||
$table->unsignedInteger('slotIntervalMinutes')->default(30);
|
||||
$table->unsignedInteger('bufferBeforeMinutes')->default(0);
|
||||
$table->unsignedInteger('bufferAfterMinutes')->default(5);
|
||||
$table->unsignedInteger('maxAppointmentsPerDay')->nullable();
|
||||
$table->unsignedInteger('maxAppointmentsPerStaffPerDay')->nullable();
|
||||
$table->boolean('customerCanChooseStaff')->default(true);
|
||||
$table->boolean('allowGuestBooking')->default(false);
|
||||
$table->boolean('requireApproval')->default(false);
|
||||
$table->boolean('requireDeposit')->default(false);
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
});
|
||||
|
||||
Schema::create('Role', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('name');
|
||||
$table->boolean('isSystem')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->unique(['businessId', 'name']);
|
||||
});
|
||||
|
||||
Schema::create('RolePermission', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('roleId', 191);
|
||||
$table->string('permission');
|
||||
$table->foreign('roleId')->references('id')->on('Role')->cascadeOnDelete();
|
||||
$table->unique(['roleId', 'permission']);
|
||||
});
|
||||
|
||||
Schema::create('StaffProfile', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('userId', 191);
|
||||
$table->string('businessId', 191);
|
||||
$table->string('roleId', 191);
|
||||
$table->text('bio')->nullable();
|
||||
$table->string('status')->default('ACTIVE');
|
||||
$table->boolean('isBookableOnline')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('userId')->references('id')->on('User')->cascadeOnDelete();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('roleId')->references('id')->on('Role')->restrictOnDelete();
|
||||
$table->unique(['businessId', 'userId']);
|
||||
$table->index('businessId');
|
||||
});
|
||||
|
||||
Schema::create('CustomerProfile', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('userId', 191)->nullable();
|
||||
$table->string('firstName');
|
||||
$table->string('lastName');
|
||||
$table->string('email');
|
||||
$table->string('phone')->nullable();
|
||||
$table->boolean('isGuest')->default(true);
|
||||
$table->string('preferredBarberId', 191)->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('userId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->foreign('preferredBarberId')->references('id')->on('StaffProfile')->nullOnDelete();
|
||||
$table->index(['businessId', 'email']);
|
||||
$table->index(['businessId', 'phone']);
|
||||
});
|
||||
|
||||
Schema::create('ServiceCategory', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('name');
|
||||
$table->unsignedInteger('displayOrder')->default(0);
|
||||
$table->boolean('isActive')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->index('businessId');
|
||||
});
|
||||
|
||||
Schema::create('Service', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('categoryId', 191);
|
||||
$table->string('name');
|
||||
$table->text('description')->nullable();
|
||||
$table->string('imageUrl')->nullable();
|
||||
$table->unsignedInteger('durationMinutes');
|
||||
$table->decimal('price', 10, 2);
|
||||
$table->unsignedInteger('bufferBeforeMinutes')->default(0);
|
||||
$table->unsignedInteger('bufferAfterMinutes')->default(0);
|
||||
$table->boolean('isActive')->default(true);
|
||||
$table->boolean('allowOnlineBooking')->default(true);
|
||||
$table->unsignedInteger('displayOrder')->default(0);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('categoryId')->references('id')->on('ServiceCategory')->cascadeOnDelete();
|
||||
$table->index(['businessId', 'categoryId']);
|
||||
});
|
||||
|
||||
Schema::create('StaffService', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('staffId', 191);
|
||||
$table->string('serviceId', 191);
|
||||
$table->decimal('priceOverride', 10, 2)->nullable();
|
||||
$table->unsignedInteger('durationOverrideMinutes')->nullable();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
$table->foreign('serviceId')->references('id')->on('Service')->cascadeOnDelete();
|
||||
$table->unique(['staffId', 'serviceId']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (['StaffService', 'Service', 'ServiceCategory', 'CustomerProfile', 'StaffProfile', 'RolePermission', 'Role', 'BookingRule', 'BusinessSettings', 'BusinessHours', 'BusinessLocation', 'business_domains', 'Business'] as $table) {
|
||||
Schema::dropIfExists($table);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
<?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('WorkingHours', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('staffId', 191);
|
||||
$table->string('dayOfWeek');
|
||||
$table->boolean('isOff')->default(false);
|
||||
$table->unsignedSmallInteger('startMinutes')->nullable();
|
||||
$table->unsignedSmallInteger('endMinutes')->nullable();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
$table->unique(['staffId', 'dayOfWeek']);
|
||||
});
|
||||
|
||||
Schema::create('Break', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('staffId', 191);
|
||||
$table->string('label');
|
||||
$table->unsignedSmallInteger('startMinutes');
|
||||
$table->unsignedSmallInteger('endMinutes');
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
$table->index('staffId');
|
||||
});
|
||||
|
||||
Schema::create('BreakDay', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('breakId', 191);
|
||||
$table->string('dayOfWeek');
|
||||
$table->foreign('breakId')->references('id')->on('Break')->cascadeOnDelete();
|
||||
$table->unique(['breakId', 'dayOfWeek']);
|
||||
});
|
||||
|
||||
Schema::create('TimeOff', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('staffId', 191);
|
||||
$table->date('startDate');
|
||||
$table->date('endDate');
|
||||
$table->string('reason')->nullable();
|
||||
$table->string('status')->default('APPROVED');
|
||||
$table->unsignedSmallInteger('startMinutes')->nullable();
|
||||
$table->unsignedSmallInteger('endMinutes')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
$table->index(['staffId', 'startDate', 'endDate']);
|
||||
});
|
||||
|
||||
Schema::create('Appointment', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('customerId', 191);
|
||||
$table->string('staffId', 191);
|
||||
$table->string('status')->default('CONFIRMED');
|
||||
$table->dateTime('startAt');
|
||||
$table->dateTime('endAt');
|
||||
$table->text('notes')->nullable();
|
||||
$table->string('createdByUserId', 191)->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('customerId')->references('id')->on('CustomerProfile')->cascadeOnDelete();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->restrictOnDelete();
|
||||
$table->foreign('createdByUserId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->index(['staffId', 'startAt']);
|
||||
$table->index(['businessId', 'startAt']);
|
||||
$table->index('customerId');
|
||||
});
|
||||
|
||||
Schema::create('AppointmentService', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('appointmentId', 191);
|
||||
$table->string('serviceId', 191);
|
||||
$table->decimal('priceAtBooking', 10, 2);
|
||||
$table->unsignedInteger('durationAtBookingMinutes');
|
||||
$table->foreign('appointmentId')->references('id')->on('Appointment')->cascadeOnDelete();
|
||||
$table->foreign('serviceId')->references('id')->on('Service')->restrictOnDelete();
|
||||
$table->index('appointmentId');
|
||||
});
|
||||
|
||||
Schema::create('GuestAppointmentAccessToken', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('appointmentId', 191)->unique();
|
||||
$table->string('tokenHash', 64)->unique();
|
||||
$table->dateTime('expiresAt');
|
||||
$table->dateTime('revokedAt')->nullable();
|
||||
$table->dateTime('lastUsedAt')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('appointmentId')->references('id')->on('Appointment')->cascadeOnDelete();
|
||||
$table->index('expiresAt');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (['GuestAppointmentAccessToken', 'AppointmentService', 'Appointment', 'TimeOff', 'BreakDay', 'Break', 'WorkingHours'] as $table) {
|
||||
Schema::dropIfExists($table);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,374 @@
|
||||
<?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('Business', function (Blueprint $table): void {
|
||||
$table->string('icon192Url')->nullable();
|
||||
$table->string('icon512Url')->nullable();
|
||||
$table->string('maskableIcon192Url')->nullable();
|
||||
$table->string('maskableIcon512Url')->nullable();
|
||||
$table->json('splashScreens')->nullable();
|
||||
$table->string('welcomeBackgroundDesktopUrl')->nullable();
|
||||
$table->string('welcomeBackgroundMobileUrl')->nullable();
|
||||
$table->string('googlePlaceId')->nullable();
|
||||
$table->decimal('googleRating', 2, 1)->nullable();
|
||||
$table->unsignedInteger('googleRatingCount')->nullable();
|
||||
});
|
||||
|
||||
Schema::table('BusinessSettings', function (Blueprint $table): void {
|
||||
$table->unsignedTinyInteger('reviewsMinRating')->nullable();
|
||||
$table->boolean('reviewsExcludeRatingOnly')->default(false);
|
||||
});
|
||||
|
||||
Schema::table('Appointment', function (Blueprint $table): void {
|
||||
$table->decimal('discountAmount', 10, 2)->nullable();
|
||||
$table->string('cancellationReason')->nullable();
|
||||
$table->timestamp('cancelledAt')->nullable();
|
||||
$table->string('cancelledByUserId', 191)->nullable();
|
||||
$table->foreign('cancelledByUserId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->index('cancelledByUserId');
|
||||
});
|
||||
|
||||
Schema::create('MediaAsset', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('url', 500);
|
||||
$table->string('originalFilename')->nullable();
|
||||
$table->string('mimeType');
|
||||
$table->unsignedBigInteger('sizeBytes');
|
||||
$table->unsignedInteger('width')->nullable();
|
||||
$table->unsignedInteger('height')->nullable();
|
||||
$table->string('category')->nullable();
|
||||
$table->string('uploadedByUserId', 191)->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('uploadedByUserId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->index(['businessId', 'category']);
|
||||
});
|
||||
|
||||
Schema::create('BusinessGalleryImage', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('placement');
|
||||
$table->string('mediaAssetId', 191)->nullable();
|
||||
$table->string('imageUrl', 500);
|
||||
$table->string('category')->nullable();
|
||||
$table->string('caption')->nullable();
|
||||
$table->unsignedInteger('displayOrder')->default(0);
|
||||
$table->boolean('isActive')->default(true);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('mediaAssetId')->references('id')->on('MediaAsset')->nullOnDelete();
|
||||
$table->index(['businessId', 'placement', 'displayOrder']);
|
||||
});
|
||||
|
||||
Schema::create('Review', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('externalId');
|
||||
$table->string('authorName');
|
||||
$table->string('authorPhotoUrl')->nullable();
|
||||
$table->unsignedTinyInteger('rating');
|
||||
$table->text('text')->nullable();
|
||||
$table->string('relativeTimeDescription')->nullable();
|
||||
$table->dateTime('publishedAt')->nullable();
|
||||
$table->boolean('isHidden')->default(false);
|
||||
$table->dateTime('fetchedAt');
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->unique(['businessId', 'externalId']);
|
||||
$table->index(['businessId', 'isHidden']);
|
||||
});
|
||||
|
||||
Schema::create('ApplicationInstallation', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('status')->default('NOT_INSTALLED');
|
||||
$table->dateTime('installedAt')->nullable();
|
||||
$table->string('installedVersion')->nullable();
|
||||
$table->string('initialAdminUserId', 191)->nullable();
|
||||
$table->string('primaryBusinessId', 191)->nullable();
|
||||
$table->json('metadata')->nullable();
|
||||
$table->text('failureReason')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('initialAdminUserId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->foreign('primaryBusinessId')->references('id')->on('Business')->nullOnDelete();
|
||||
});
|
||||
|
||||
Schema::create('StaffInvitation', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('staffId', 191)->unique();
|
||||
$table->string('email');
|
||||
$table->string('token')->unique();
|
||||
$table->string('invitedByUserId', 191)->nullable();
|
||||
$table->dateTime('expiresAt');
|
||||
$table->dateTime('acceptedAt')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
$table->foreign('invitedByUserId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->index('businessId');
|
||||
});
|
||||
|
||||
Schema::create('StaffCalendarConnection', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('staffId', 191)->unique();
|
||||
$table->string('provider')->default('GOOGLE');
|
||||
$table->string('externalAccountId');
|
||||
$table->string('accountEmail');
|
||||
$table->text('encryptedAccessToken')->nullable();
|
||||
$table->text('encryptedRefreshToken');
|
||||
$table->dateTime('tokenExpiresAt')->nullable();
|
||||
$table->string('selectedCalendarId');
|
||||
$table->string('selectedCalendarName');
|
||||
$table->dateTime('connectedAt');
|
||||
$table->dateTime('lastSyncAt')->nullable();
|
||||
$table->text('lastSyncError')->nullable();
|
||||
$table->dateTime('revokedAt')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
});
|
||||
|
||||
Schema::create('AppointmentCalendarEvent', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('appointmentId', 191);
|
||||
$table->string('connectionId', 191);
|
||||
$table->string('providerEventId');
|
||||
$table->string('providerCalendarId');
|
||||
$table->string('status')->default('SYNCED');
|
||||
$table->dateTime('lastSyncedAt');
|
||||
$table->text('lastSyncError')->nullable();
|
||||
$table->unsignedInteger('sourceVersion')->default(1);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('appointmentId')->references('id')->on('Appointment')->cascadeOnDelete();
|
||||
$table->foreign('connectionId')->references('id')->on('StaffCalendarConnection')->cascadeOnDelete();
|
||||
$table->unique(['appointmentId', 'connectionId']);
|
||||
$table->index('connectionId');
|
||||
});
|
||||
|
||||
Schema::create('LoyaltyProgramme', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191)->unique();
|
||||
$table->boolean('isEnabled')->default(false);
|
||||
$table->unsignedTinyInteger('stampsRequired')->default(10);
|
||||
$table->string('rewardPosition')->default('AFTER_ALL_STAMPS');
|
||||
$table->string('rewardType')->default('PERCENTAGE');
|
||||
$table->decimal('rewardValue', 10, 2)->nullable();
|
||||
$table->string('rewardLabel')->nullable();
|
||||
$table->decimal('maxRewardValue', 10, 2)->nullable();
|
||||
$table->string('freeServiceId', 191)->nullable();
|
||||
$table->boolean('autoApplyReward')->default(true);
|
||||
$table->boolean('requiresStaffApproval')->default(false);
|
||||
$table->unsignedInteger('stampsExpireAfterDays')->nullable();
|
||||
$table->unsignedInteger('rewardExpiresAfterDays')->nullable();
|
||||
$table->boolean('earnOnCancelled')->default(false);
|
||||
$table->boolean('earnOnNoShow')->default(false);
|
||||
$table->string('cardBackgroundColor')->nullable();
|
||||
$table->string('cardBackgroundImageUrl')->nullable();
|
||||
$table->string('stampIcon')->nullable();
|
||||
$table->string('termsLine')->nullable();
|
||||
$table->string('cardTitleText')->nullable();
|
||||
$table->string('cardFont')->default('SANS');
|
||||
$table->string('cardTitleTextSize')->default('MD');
|
||||
$table->string('cardTitleTextColor')->nullable();
|
||||
$table->string('cardBorderColor')->nullable();
|
||||
$table->string('cardMemberNumberColor')->nullable();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('freeServiceId')->references('id')->on('Service')->nullOnDelete();
|
||||
});
|
||||
|
||||
Schema::create('LoyaltyEligibleService', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('loyaltyProgrammeId', 191);
|
||||
$table->string('serviceId', 191);
|
||||
$table->foreign('loyaltyProgrammeId')->references('id')->on('LoyaltyProgramme')->cascadeOnDelete();
|
||||
$table->foreign('serviceId')->references('id')->on('Service')->cascadeOnDelete();
|
||||
$table->unique(['loyaltyProgrammeId', 'serviceId']);
|
||||
});
|
||||
|
||||
Schema::create('LoyaltyEligibleStaff', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('loyaltyProgrammeId', 191);
|
||||
$table->string('staffId', 191);
|
||||
$table->foreign('loyaltyProgrammeId')->references('id')->on('LoyaltyProgramme')->cascadeOnDelete();
|
||||
$table->foreign('staffId')->references('id')->on('StaffProfile')->cascadeOnDelete();
|
||||
$table->unique(['loyaltyProgrammeId', 'staffId']);
|
||||
});
|
||||
|
||||
Schema::create('LoyaltyAccount', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('customerId', 191);
|
||||
$table->string('loyaltyProgrammeId', 191);
|
||||
$table->unsignedInteger('currentStamps')->default(0);
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('customerId')->references('id')->on('CustomerProfile')->cascadeOnDelete();
|
||||
$table->foreign('loyaltyProgrammeId')->references('id')->on('LoyaltyProgramme')->cascadeOnDelete();
|
||||
$table->unique(['customerId', 'loyaltyProgrammeId']);
|
||||
});
|
||||
|
||||
Schema::create('LoyaltyTransaction', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('loyaltyAccountId', 191);
|
||||
$table->string('type');
|
||||
$table->integer('amount');
|
||||
$table->string('reason')->nullable();
|
||||
$table->string('appointmentId', 191)->nullable();
|
||||
$table->string('authoredByStaffId', 191)->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('loyaltyAccountId')->references('id')->on('LoyaltyAccount')->cascadeOnDelete();
|
||||
$table->foreign('appointmentId')->references('id')->on('Appointment')->nullOnDelete();
|
||||
$table->foreign('authoredByStaffId')->references('id')->on('StaffProfile')->nullOnDelete();
|
||||
$table->index('loyaltyAccountId');
|
||||
});
|
||||
|
||||
Schema::create('LoyaltyReward', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('loyaltyAccountId', 191);
|
||||
$table->string('rewardType');
|
||||
$table->decimal('value', 10, 2)->nullable();
|
||||
$table->string('label');
|
||||
$table->string('status')->default('AVAILABLE');
|
||||
$table->string('appliedToAppointmentId', 191)->nullable();
|
||||
$table->dateTime('redeemedAt')->nullable();
|
||||
$table->string('redeemedByStaffId', 191)->nullable();
|
||||
$table->dateTime('expiresAt')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('loyaltyAccountId')->references('id')->on('LoyaltyAccount')->cascadeOnDelete();
|
||||
$table->foreign('appliedToAppointmentId')->references('id')->on('Appointment')->nullOnDelete();
|
||||
$table->foreign('redeemedByStaffId')->references('id')->on('StaffProfile')->nullOnDelete();
|
||||
$table->index('loyaltyAccountId');
|
||||
});
|
||||
|
||||
Schema::create('Notification', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('recipientUserId', 191)->nullable();
|
||||
$table->string('recipientCustomerId', 191)->nullable();
|
||||
$table->string('type');
|
||||
$table->string('appointmentId', 191)->nullable();
|
||||
$table->string('loyaltyRewardId', 191)->nullable();
|
||||
$table->string('subject')->nullable();
|
||||
$table->text('bodyText');
|
||||
$table->string('deepLinkPath')->nullable();
|
||||
$table->string('idempotencyKey')->unique();
|
||||
$table->dateTime('readAt')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('recipientUserId')->references('id')->on('User')->cascadeOnDelete();
|
||||
$table->foreign('recipientCustomerId')->references('id')->on('CustomerProfile')->cascadeOnDelete();
|
||||
$table->foreign('appointmentId')->references('id')->on('Appointment')->nullOnDelete();
|
||||
$table->foreign('loyaltyRewardId')->references('id')->on('LoyaltyReward')->nullOnDelete();
|
||||
$table->index(['businessId', 'createdAt']);
|
||||
$table->index(['recipientUserId', 'readAt']);
|
||||
$table->index('recipientCustomerId');
|
||||
$table->index('appointmentId');
|
||||
});
|
||||
|
||||
Schema::create('NotificationDelivery', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('notificationId', 191);
|
||||
$table->string('channel');
|
||||
$table->string('status')->default('PENDING');
|
||||
$table->dateTime('scheduledFor')->nullable();
|
||||
$table->unsignedInteger('attemptCount')->default(0);
|
||||
$table->dateTime('lastAttemptedAt')->nullable();
|
||||
$table->string('providerName')->nullable();
|
||||
$table->string('providerMessageId')->nullable();
|
||||
$table->string('failureReason')->nullable();
|
||||
$table->dateTime('sentAt')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('notificationId')->references('id')->on('Notification')->cascadeOnDelete();
|
||||
$table->unique(['notificationId', 'channel']);
|
||||
$table->index(['status', 'scheduledFor']);
|
||||
});
|
||||
|
||||
Schema::create('NotificationPreference', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('userId', 191);
|
||||
$table->string('type');
|
||||
$table->string('channel');
|
||||
$table->boolean('isEnabled')->default(true);
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('userId')->references('id')->on('User')->cascadeOnDelete();
|
||||
$table->unique(['businessId', 'userId', 'type', 'channel']);
|
||||
});
|
||||
|
||||
Schema::create('PushSubscription', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191);
|
||||
$table->string('userId', 191)->nullable();
|
||||
$table->string('customerId', 191)->nullable();
|
||||
$table->string('endpoint', 500)->unique();
|
||||
$table->string('p256dhKey');
|
||||
$table->string('authKey');
|
||||
$table->string('deviceLabel')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->dateTime('lastUsedAt')->nullable();
|
||||
$table->dateTime('revokedAt')->nullable();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->cascadeOnDelete();
|
||||
$table->foreign('userId')->references('id')->on('User')->cascadeOnDelete();
|
||||
$table->foreign('customerId')->references('id')->on('CustomerProfile')->cascadeOnDelete();
|
||||
$table->index('userId');
|
||||
$table->index('customerId');
|
||||
});
|
||||
|
||||
Schema::create('CustomerNote', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('customerId', 191);
|
||||
$table->string('authorStaffId', 191);
|
||||
$table->text('body');
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->timestamp('updatedAt')->useCurrent()->useCurrentOnUpdate();
|
||||
$table->foreign('customerId')->references('id')->on('CustomerProfile')->cascadeOnDelete();
|
||||
$table->foreign('authorStaffId')->references('id')->on('StaffProfile')->restrictOnDelete();
|
||||
$table->index('customerId');
|
||||
});
|
||||
|
||||
Schema::create('AuditLog', function (Blueprint $table): void {
|
||||
$table->string('id', 191)->primary();
|
||||
$table->string('businessId', 191)->nullable();
|
||||
$table->string('actorUserId', 191)->nullable();
|
||||
$table->string('action');
|
||||
$table->string('entityType');
|
||||
$table->string('entityId');
|
||||
$table->json('metadata')->nullable();
|
||||
$table->timestamp('createdAt')->useCurrent();
|
||||
$table->foreign('businessId')->references('id')->on('Business')->nullOnDelete();
|
||||
$table->foreign('actorUserId')->references('id')->on('User')->nullOnDelete();
|
||||
$table->index(['entityType', 'entityId']);
|
||||
$table->index('actorUserId');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
foreach (['AuditLog', 'CustomerNote', 'PushSubscription', 'NotificationPreference', 'NotificationDelivery', 'Notification', 'LoyaltyReward', 'LoyaltyTransaction', 'LoyaltyAccount', 'LoyaltyEligibleStaff', 'LoyaltyEligibleService', 'LoyaltyProgramme', 'AppointmentCalendarEvent', 'StaffCalendarConnection', 'StaffInvitation', 'ApplicationInstallation', 'Review', 'BusinessGalleryImage', 'MediaAsset'] as $table) {
|
||||
Schema::dropIfExists($table);
|
||||
}
|
||||
Schema::table('Appointment', function (Blueprint $table): void {
|
||||
$table->dropForeign(['cancelledByUserId']);
|
||||
$table->dropIndex(['cancelledByUserId']);
|
||||
$table->dropColumn(['discountAmount', 'cancellationReason', 'cancelledAt', 'cancelledByUserId']);
|
||||
});
|
||||
Schema::table('BusinessSettings', function (Blueprint $table): void {
|
||||
$table->dropColumn(['reviewsMinRating', 'reviewsExcludeRatingOnly']);
|
||||
});
|
||||
Schema::table('Business', function (Blueprint $table): void {
|
||||
$table->dropColumn(['icon192Url', 'icon512Url', 'maskableIcon192Url', 'maskableIcon512Url', 'splashScreens', 'welcomeBackgroundDesktopUrl', 'welcomeBackgroundMobileUrl', 'googlePlaceId', 'googleRating', 'googleRatingCount']);
|
||||
});
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user