diff --git a/CHANGELOG.md b/CHANGELOG.md index b76317344..785c3cd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,14 +16,15 @@ All notable changes to this project will be documented in this file. ### Changed -- Upgraded all Composer and Node dependencies, most notably: PHP to 8.5 (from 8.4), TailwindCSS to v4.0 (from v3) and Laravel to v12 (from v10) +- Upgraded all Composer and Node dependencies, most notably: PHP to 8.5 (previously 8.4), TailwindCSS to v4.0 (previously v3) and Laravel to v12 (previously v10) - **Docker:** - - Upgraded all Docker dependencies, most notably: Postgres to v18 (from v15) and Redis to v8 (from v7) + - Upgraded all Docker dependencies, most notably: Postgres to v18 (previously v15) and Redis to v8 (previously v7) - - **Laravel Configurations:** - Changed hashing algorithm from `bcrypt` to `argon2id` for enhanced security - - Use Redis for sessions and expire inactive sessions after 24h + - Use Redis for sessions and expire inactive sessions after 24h (previously 14 days) - Encrypt user sessions data + - Expire password reset tokens after 10 minutes (previously 60 minutes) - Redirect Laravel logs to `stderr` so they can be viewed in docker logs - Configured production logging to rotate automatically and keep only the last 10 days of logs to reduce disk usage - Changed production log level from `debug` to `warning` to reduce disk usage and avoid logging sensitive information @@ -87,7 +88,8 @@ All notable changes to this project will be documented in this file. ### Refactored -- Completely refactored all database migrations for a cleaner, more consistent and optimized schema +- Completely refactored all database migrations for a cleaner, more consistent and stable database schema +- Completely refactored all database models ## Issues diff --git a/app/Models/.gitkeep b/app/Models/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/app/Models/User.php b/app/Models/User.php new file mode 100644 index 000000000..513481ef3 --- /dev/null +++ b/app/Models/User.php @@ -0,0 +1,47 @@ + */ + use HasFactory; + + /** + * The attributes that should be hidden for serialization. + * + * @var list + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } +} diff --git a/config/auth.php b/config/auth.php index 57130512d..b23fa2b71 100644 --- a/config/auth.php +++ b/config/auth.php @@ -90,7 +90,7 @@ return [ 'users' => [ 'provider' => 'users', 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), - 'expire' => 60, + 'expire' => 10, 'throttle' => 60, ], ], diff --git a/config/hashing.php b/config/hashing.php index 94db9645a..e0db28ada 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -18,23 +18,6 @@ return [ 'driver' => env('HASH_DRIVER', 'argon2id'), - /* - |-------------------------------------------------------------------------- - | Bcrypt Options - |-------------------------------------------------------------------------- - | - | Here you may specify the configuration options that should be used when - | passwords are hashed using the Bcrypt algorithm. This will allow you - | to control the amount of time it takes to hash the given password. - | - */ - - 'bcrypt' => [ - 'rounds' => env('BCRYPT_ROUNDS', 14), - 'verify' => env('HASH_VERIFY', true), - 'limit' => env('BCRYPT_LIMIT'), - ], - /* |-------------------------------------------------------------------------- | Argon Options diff --git a/database/factories/.gitkeep b/database/factories/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php new file mode 100644 index 000000000..0383a7e03 --- /dev/null +++ b/database/factories/UserFactory.php @@ -0,0 +1,42 @@ + + */ +final class UserFactory extends Factory +{ + /** + * The current password being used by the factory. + */ + private static string $password; + + /** + * Define the model's default state. + */ + public function definition(): array + { + return [ + 'name' => fake()->name(), + 'email' => fake()->unique()->safeEmail(), + 'email_verified_at' => now(), + 'password' => self::$password ??= Hash::make('password'), + ]; + } + + /** + * Indicate that the model's email address should be unverified. + */ + public function unverified(): static + { + return $this->state(fn (array $attributes): array => [ + 'email_verified_at' => null, + ]); + } +} diff --git a/database/migrations/.gitkeep b/database/migrations/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/database/migrations/2025_12_10_154334_create_users_table.php b/database/migrations/2025_12_10_154334_create_users_table.php new file mode 100644 index 000000000..ff437717f --- /dev/null +++ b/database/migrations/2025_12_10_154334_create_users_table.php @@ -0,0 +1,25 @@ +id(); + $table->string('name'); + $table->string('email')->unique(); + $table->timestamp('email_verified_at')->nullable(); + $table->string('password'); + $table->timestamps(); + }); + } +}; diff --git a/database/migrations/2025_12_10_154403_create_password_reset_tokens_table.php b/database/migrations/2025_12_10_154403_create_password_reset_tokens_table.php new file mode 100644 index 000000000..895fb8b04 --- /dev/null +++ b/database/migrations/2025_12_10_154403_create_password_reset_tokens_table.php @@ -0,0 +1,22 @@ +string('email')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } +}; diff --git a/tests/ArchTest.php b/tests/ArchTest.php index 1223c741f..6b23cd499 100644 --- a/tests/ArchTest.php +++ b/tests/ArchTest.php @@ -192,8 +192,8 @@ arch('Models') ->expect('App\Models') ->toBeClasses() ->toExtend(\Illuminate\Database\Eloquent\Model::class) + ->ignoring('App\Models\Scopes') ->not->toUseTrait(\Illuminate\Database\Eloquent\SoftDeletes::class) - ->toOnlyUse('Illuminate\Database') ->toHaveLineCountLessThan(250) ->not->toHaveSuffix('Model');