diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 9ffab39a..3d64b9a3 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -14,6 +14,16 @@ jobs:
ci:
runs-on: ubuntu-latest
+ services:
+ mysql:
+ image: mysql:8.0
+ env:
+ MYSQL_ROOT_PASSWORD: password
+ MYSQL_DATABASE: testing
+ ports:
+ - 3306:3306
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -45,3 +55,10 @@ jobs:
- name: Tests
run: ./vendor/bin/pest
+ env:
+ DB_CONNECTION: mysql
+ DB_HOST: 127.0.0.1
+ DB_PORT: 3306
+ DB_DATABASE: testing
+ DB_USERNAME: root
+ DB_PASSWORD: password
diff --git a/database/migrations/2025_11_15_195739_convert_all_ids_to_uuid.php b/database/migrations/2025_11_15_195739_convert_all_ids_to_uuid.php
index b123f724..a393602f 100644
--- a/database/migrations/2025_11_15_195739_convert_all_ids_to_uuid.php
+++ b/database/migrations/2025_11_15_195739_convert_all_ids_to_uuid.php
@@ -9,321 +9,317 @@ return new class extends Migration
{
public function up(): void
{
- DB::statement('SET FOREIGN_KEY_CHECKS=0');
+ Schema::withoutForeignKeyConstraints(function () {
+ Schema::table('sessions', function (Blueprint $table) {
+ $table->dropColumn('user_id');
+ });
- Schema::table('sessions', function (Blueprint $table) {
- $table->dropColumn('user_id');
- });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ });
- Schema::table('banks', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ $table->dropForeign(['bank_id']);
+ });
- Schema::table('accounts', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- $table->dropForeign(['bank_id']);
- });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ });
- Schema::table('categories', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ $table->dropForeign(['account_id']);
+ $table->dropForeign(['category_id']);
+ });
- Schema::table('transactions', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- $table->dropForeign(['account_id']);
- $table->dropForeign(['category_id']);
- });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ $table->dropForeign(['action_category_id']);
+ });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- $table->dropForeign(['action_category_id']);
- });
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->dropForeign(['account_id']);
+ });
- Schema::table('account_balances', function (Blueprint $table) {
- $table->dropForeign(['account_id']);
- });
+ DB::statement('DELETE FROM users');
+ DB::statement('DELETE FROM banks');
+ DB::statement('DELETE FROM accounts');
+ DB::statement('DELETE FROM categories');
+ DB::statement('DELETE FROM transactions');
+ DB::statement('DELETE FROM automation_rules');
+ DB::statement('DELETE FROM encrypted_messages');
+ DB::statement('DELETE FROM account_balances');
- DB::statement('DELETE FROM users');
- DB::statement('DELETE FROM banks');
- DB::statement('DELETE FROM accounts');
- DB::statement('DELETE FROM categories');
- DB::statement('DELETE FROM transactions');
- DB::statement('DELETE FROM automation_rules');
- DB::statement('DELETE FROM encrypted_messages');
- DB::statement('DELETE FROM account_balances');
+ Schema::table('users', function (Blueprint $table) {
+ $table->dropColumn('id');
+ });
+ Schema::table('users', function (Blueprint $table) {
+ $table->uuid('id')->primary()->first();
+ });
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('id');
- });
- Schema::table('users', function (Blueprint $table) {
- $table->uuid('id')->primary()->first();
- });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->uuid('id')->primary()->first();
+ $table->uuid('user_id')->nullable()->after('id');
+ });
- Schema::table('banks', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- });
- Schema::table('banks', function (Blueprint $table) {
- $table->uuid('id')->primary()->first();
- $table->uuid('user_id')->nullable()->after('id');
- });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ $table->dropColumn('bank_id');
+ });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->uuid('id')->primary()->first();
+ $table->uuid('user_id')->after('id');
+ $table->uuid('bank_id')->after('name_iv');
+ });
- Schema::table('accounts', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- $table->dropColumn('bank_id');
- });
- Schema::table('accounts', function (Blueprint $table) {
- $table->uuid('id')->primary()->first();
- $table->uuid('user_id')->after('id');
- $table->uuid('bank_id')->after('name_iv');
- });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->uuid('id')->primary()->first();
+ $table->uuid('user_id')->after('color');
+ });
- Schema::table('categories', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- });
- Schema::table('categories', function (Blueprint $table) {
- $table->uuid('id')->primary()->first();
- $table->uuid('user_id')->after('color');
- });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->dropColumn('user_id');
+ $table->dropColumn('account_id');
+ $table->dropColumn('category_id');
+ });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->uuid('user_id')->after('id');
+ $table->uuid('account_id')->after('user_id');
+ $table->uuid('category_id')->nullable()->after('account_id');
+ });
- Schema::table('transactions', function (Blueprint $table) {
- $table->dropColumn('user_id');
- $table->dropColumn('account_id');
- $table->dropColumn('category_id');
- });
- Schema::table('transactions', function (Blueprint $table) {
- $table->uuid('user_id')->after('id');
- $table->uuid('account_id')->after('user_id');
- $table->uuid('category_id')->nullable()->after('account_id');
- });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ $table->dropColumn('action_category_id');
+ });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->uuid('id')->primary()->first();
+ $table->uuid('user_id')->after('id');
+ $table->uuid('action_category_id')->nullable()->after('rules_json');
+ });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- $table->dropColumn('action_category_id');
- });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->uuid('id')->primary()->first();
- $table->uuid('user_id')->after('id');
- $table->uuid('action_category_id')->nullable()->after('rules_json');
- });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->uuid('id')->primary()->first();
+ $table->uuid('user_id')->after('id');
+ });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->uuid('id')->primary()->first();
- $table->uuid('user_id')->after('id');
- });
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->dropColumn('account_id');
+ });
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->uuid('account_id')->after('id');
+ });
- Schema::table('account_balances', function (Blueprint $table) {
- $table->dropColumn('account_id');
- });
- Schema::table('account_balances', function (Blueprint $table) {
- $table->uuid('account_id')->after('id');
- });
+ Schema::table('sessions', function (Blueprint $table) {
+ $table->uuid('user_id')->nullable()->after('id')->index();
+ });
- Schema::table('sessions', function (Blueprint $table) {
- $table->uuid('user_id')->nullable()->after('id')->index();
- });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ });
- Schema::table('banks', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ $table->foreign('bank_id')->references('id')->on('banks')->onDelete('cascade');
+ });
- Schema::table('accounts', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->foreign('bank_id')->references('id')->on('banks')->onDelete('cascade');
- });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ });
- Schema::table('categories', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
+ $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
+ });
- Schema::table('transactions', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
- $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
- });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ $table->foreign('action_category_id')->references('id')->on('categories')->onDelete('set null');
+ });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->foreign('action_category_id')->references('id')->on('categories')->onDelete('set null');
- });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
+ });
});
-
- Schema::table('account_balances', function (Blueprint $table) {
- $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
- });
-
- DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
public function down(): void
{
- DB::statement('SET FOREIGN_KEY_CHECKS=0');
+ Schema::withoutForeignKeyConstraints(function () {
+ Schema::table('sessions', function (Blueprint $table) {
+ $table->dropColumn('user_id');
+ });
- Schema::table('sessions', function (Blueprint $table) {
- $table->dropColumn('user_id');
- });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ $table->dropForeign(['bank_id']);
+ });
- Schema::table('accounts', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- $table->dropForeign(['bank_id']);
- });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ });
- Schema::table('categories', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ $table->dropForeign(['account_id']);
+ $table->dropForeign(['category_id']);
+ });
- Schema::table('transactions', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- $table->dropForeign(['account_id']);
- $table->dropForeign(['category_id']);
- });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->dropForeign(['user_id']);
+ $table->dropForeign(['action_category_id']);
+ });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->dropForeign(['user_id']);
- $table->dropForeign(['action_category_id']);
- });
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->dropForeign(['account_id']);
+ });
- Schema::table('account_balances', function (Blueprint $table) {
- $table->dropForeign(['account_id']);
- });
+ DB::statement('DELETE FROM users');
+ DB::statement('DELETE FROM banks');
+ DB::statement('DELETE FROM accounts');
+ DB::statement('DELETE FROM categories');
+ DB::statement('DELETE FROM transactions');
+ DB::statement('DELETE FROM automation_rules');
+ DB::statement('DELETE FROM encrypted_messages');
+ DB::statement('DELETE FROM account_balances');
- DB::statement('DELETE FROM users');
- DB::statement('DELETE FROM banks');
- DB::statement('DELETE FROM accounts');
- DB::statement('DELETE FROM categories');
- DB::statement('DELETE FROM transactions');
- DB::statement('DELETE FROM automation_rules');
- DB::statement('DELETE FROM encrypted_messages');
- DB::statement('DELETE FROM account_balances');
+ Schema::table('users', function (Blueprint $table) {
+ $table->dropColumn('id');
+ });
+ Schema::table('users', function (Blueprint $table) {
+ $table->id()->first();
+ });
- Schema::table('users', function (Blueprint $table) {
- $table->dropColumn('id');
- });
- Schema::table('users', function (Blueprint $table) {
- $table->id()->first();
- });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->id()->first();
+ $table->foreignId('user_id')->nullable()->after('id');
+ });
- Schema::table('banks', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- });
- Schema::table('banks', function (Blueprint $table) {
- $table->id()->first();
- $table->foreignId('user_id')->nullable()->after('id');
- });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ $table->dropColumn('bank_id');
+ });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->id()->first();
+ $table->foreignId('user_id')->after('id');
+ $table->foreignId('bank_id')->after('name_iv');
+ });
- Schema::table('accounts', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- $table->dropColumn('bank_id');
- });
- Schema::table('accounts', function (Blueprint $table) {
- $table->id()->first();
- $table->foreignId('user_id')->after('id');
- $table->foreignId('bank_id')->after('name_iv');
- });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->id()->first();
+ $table->foreignId('user_id')->after('color');
+ });
- Schema::table('categories', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- });
- Schema::table('categories', function (Blueprint $table) {
- $table->id()->first();
- $table->foreignId('user_id')->after('color');
- });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->dropColumn('user_id');
+ $table->dropColumn('account_id');
+ $table->dropColumn('category_id');
+ });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->foreignId('user_id')->after('id');
+ $table->foreignId('account_id')->after('user_id');
+ $table->foreignId('category_id')->nullable()->after('account_id');
+ });
- Schema::table('transactions', function (Blueprint $table) {
- $table->dropColumn('user_id');
- $table->dropColumn('account_id');
- $table->dropColumn('category_id');
- });
- Schema::table('transactions', function (Blueprint $table) {
- $table->foreignId('user_id')->after('id');
- $table->foreignId('account_id')->after('user_id');
- $table->foreignId('category_id')->nullable()->after('account_id');
- });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ $table->dropColumn('action_category_id');
+ });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->id()->first();
+ $table->foreignId('user_id')->after('id');
+ $table->foreignId('action_category_id')->nullable()->after('rules_json');
+ });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- $table->dropColumn('action_category_id');
- });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->id()->first();
- $table->foreignId('user_id')->after('id');
- $table->foreignId('action_category_id')->nullable()->after('rules_json');
- });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->dropColumn('id');
+ $table->dropColumn('user_id');
+ });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->id()->first();
+ $table->foreignId('user_id')->after('id');
+ });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->dropColumn('id');
- $table->dropColumn('user_id');
- });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->id()->first();
- $table->foreignId('user_id')->after('id');
- });
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->dropColumn('account_id');
+ });
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->foreignId('account_id')->after('id');
+ });
- Schema::table('account_balances', function (Blueprint $table) {
- $table->dropColumn('account_id');
- });
- Schema::table('account_balances', function (Blueprint $table) {
- $table->foreignId('account_id')->after('id');
- });
+ Schema::table('sessions', function (Blueprint $table) {
+ $table->foreignId('user_id')->nullable()->after('id')->index();
+ });
- Schema::table('sessions', function (Blueprint $table) {
- $table->foreignId('user_id')->nullable()->after('id')->index();
- });
+ Schema::table('banks', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ });
- Schema::table('banks', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- });
+ Schema::table('accounts', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ $table->foreign('bank_id')->references('id')->on('banks')->onDelete('cascade');
+ });
- Schema::table('accounts', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->foreign('bank_id')->references('id')->on('banks')->onDelete('cascade');
- });
+ Schema::table('categories', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ });
- Schema::table('categories', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- });
+ Schema::table('transactions', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
+ $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
+ });
- Schema::table('transactions', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
- $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
- });
+ Schema::table('automation_rules', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ $table->foreign('action_category_id')->references('id')->on('categories')->onDelete('set null');
+ });
- Schema::table('automation_rules', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
- $table->foreign('action_category_id')->references('id')->on('categories')->onDelete('set null');
- });
+ Schema::table('encrypted_messages', function (Blueprint $table) {
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ });
- Schema::table('encrypted_messages', function (Blueprint $table) {
- $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
+ Schema::table('account_balances', function (Blueprint $table) {
+ $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
+ });
});
-
- Schema::table('account_balances', function (Blueprint $table) {
- $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
- });
-
- DB::statement('SET FOREIGN_KEY_CHECKS=1');
}
};
diff --git a/phpunit.xml b/phpunit.xml
index bbfcf81d..9283a091 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -23,6 +23,7 @@
+