diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md
index 9c6a2200a68a8fb886b86f2b5155bf25f9dad9e0..9eab4487e4f5435875b427723c1c4f0eaba9bb8c 100644
--- a/STYLEGUIDE.md
+++ b/STYLEGUIDE.md
@@ -27,8 +27,8 @@
 - [Testing Practices](#testing-practices)
 - [Deployment and Environment Configuration](#deployment-and-environment-configuration)
 
-
 ## General Principles
+
 * Consistency: Maintain consistent coding styles and conventions across the entire codebase.
 * Readability: Write clear and understandable code with meaningful names and comments where necessary.
 * Modularity: Keep code modular to promote reusability and ease of maintenance.
@@ -39,6 +39,7 @@
 ## Project Structure
 
 ### Laravel Directory Structure
+
 * app/: Core application code (Models, Controllers, Services).
 * resources/views/: Minimal Blade templates, primarily for initial page loads.
 * routes/: Define application routes (web.php, api.php).
@@ -46,6 +47,7 @@
 * public/: Public assets (images, scripts, styles).
 
 ### Inertia.js with SSR React Structure
+
 * resources/js/: All JavaScript and React code.
   * components/: Reusable React components.
   * layouts/: Layout components for different page structures.
@@ -180,7 +182,6 @@ $greeting = "Hi, I am {$name}.";
 $greeting = 'Hi, I am ' . $name . '.';
 ```
 
-
 ## Ternary operators
 
 Every portion of a ternary expression should be on its own line unless it's a really short expression.
@@ -229,7 +230,6 @@ if (! $goodCondition) {
 // do work
 ```
 
-
 ```php
 // Bad
 
@@ -278,12 +278,10 @@ else {
 }
 ```
 
-
 ### Compound ifs
 
 In general, separate `if` statements should be preferred over a compound condition. This makes debugging code easier.
 
-
 ```php
 // Good
 if (! $conditionA) {
@@ -308,8 +306,6 @@ if ($conditionA && $conditionB && $conditionC) {
 }
 ```
 
-
-
 ## Comments
 
 Comments should be avoided as much as possible by writing expressive code. If you do need to use a comment, format it like this:
@@ -592,7 +588,6 @@ public function rules()
 }
 ```
 
-
 All custom validation rules must use snake_case:
 
 ```php
@@ -713,57 +708,65 @@ Policy (required)
 
 Observer (as needed)
 
-
-
 * Define $fillable or $guarded properties explicitly.
 * Use query scopes for reusable query logic.
 * Name relationships clearly (e.g., public function orders()).
 
 ### Middleware
+
 * Use middleware for cross-cutting concerns (authentication, logging).
 * Name middleware descriptively (e.g., EnsureUserIsAdmin).
 
 ## Inertia.js and React Standards
 
 ### Component Structure
+
 * Use function components with React Hooks.
 * Organize components logically within components/, layouts/, and pages/.
 * Keep components small and focused on a single responsibility.
 
 ### Naming Conventions
+
 * Components: PascalCase (e.g., UserProfile).
 * Props and State: camelCase (e.g., isLoading).
 * Hooks: Start custom hooks with use (e.g., useFetchData).
 
 ### State Management
+
 * @todo TBD contextapi or redux
 * Use useReducer for complex state logic.
 
 ### SSR Considerations
+
 * Ensure components are isomorphic when possible.
 * Avoid accessing browser-specific APIs during server-side rendering.
 * Handle hydration issues by matching server and client-rendered content.
 
 ### Styling
+
 * Use CSS Modules, Styled Components, or Tailwind CSS for styling.
 * Follow consistent naming conventions for CSS classes.
 * Avoid inline styles unless necessary.
 
 ### API Calls
+
 * Use Inertia’s methods for navigation and form submissions.
 * Handle API responses and errors gracefully.
 * Show loading indicators during asynchronous operations.
 
 ### Props and State Management
+
 * Use PropTypes or TypeScript interfaces for type checking.
 * Pass only necessary props to components.
 * Avoid unnecessary re-renders by using React.memo and useCallback where appropriate.
 
 ### Translation with i18n
+
 * i18n package enables use to translate the app in different languages.
 * Language files are stored in the i18n/locale folder(en, fr, sw, ...)
 * Usage.
 * Add the key value pairs in the language files.
+
 ```js
     {
         "app" : {
@@ -771,30 +774,36 @@ Observer (as needed)
         }
     }
 ```
+
 * Then access it in components.
+
 ```js
     import { useTranslation } from 'react-i18next';
-    
+  
     const { t } = useTranslation();
-    
+  
     <p>{t('app.appLogoAlt')}</p>
 ```
+
 * Use camelCase for the keys that hold the translated strings.
 * All relevant strings should be translated.
 
 ## Database Conventions (PostgreSQL)
 
 ### Migrations
+
 * Use descriptive names for migration files (e.g., 2023_01_01_000000_create_users_table.php).
 * Always write a down method to reverse migrations. Stub method with comment justification in lieu of omitting entirely.
 * Use appropriate data types and constraints.
 
 ### Schema Design
+
 * Use snake_case for table and column names.
 * Normalize data where appropriate but consider performance implications.
 * Define foreign keys and indexes explicitly.
 
 ### Eloquent Relationships
+
 * Define all relationships using Eloquent methods (hasOne, belongsToMany, etc.).
 * Use consistent naming for relationship methods.
 * Leverage eager loading to prevent N+1 query problems but be wary of eager loading on the model directly.
@@ -802,43 +811,51 @@ Observer (as needed)
 ## Caching and Queueing (Redis)
 
 ### Caching
+
 * Use Redis for caching frequently accessed data.
 * Implement cache invalidation strategies when data changes.
 * Use cache tags and keys that reflect the cached data’s purpose.
 
 ### Queueing
+
 * Use Redis as the queue driver for background jobs.
 * Name queues based on functionality (e.g., emails, notifications).
 * Handle failed jobs by implementing retries and logging.
 
 ### Session Management
+
 * Store sessions in Redis for scalability.
 * Configure session lifetimes appropriately.
 
 ## Testing Practices
 
 ### Backend Testing (PHPUnit)
+
 * Write unit tests for models, services, and controllers.
 * Use feature tests to simulate HTTP requests and responses.
 * Mock external services and dependencies.
 
 ### Frontend Testing (Jest, React Testing Library)
+
 * Write unit tests for React components.
 * Test user interactions and component rendering.
 * Avoid testing implementation details; focus on output and behavior.
 
 ### Code Coverage
+
 * Aim for comprehensive test coverage, focusing on critical code paths.
 * Do not compromise code readability for the sake of coverage percentages.
 
 ## Deployment and Environment Configuration
 
 ### Environment Variables
+
 * Use .env files for environment-specific settings.
 * Never commit .env files to version control unless it's encrypted
 * Access environment variables using Laravel’s env() helper only in config files. To access value in codebase, use laravel `config90` helper.
 
 ### Configuration Files
+
 * Keep all configuration in the config/ directory.
 * Use environment variables within config files for sensitive data.
 * Document any custom configuration options.
diff --git a/application/app/DataTransferObjects/UserData.php b/application/app/DataTransferObjects/UserData.php
new file mode 100644
index 0000000000000000000000000000000000000000..8031edf46407b64dc2385dab1377f89242f83eae
--- /dev/null
+++ b/application/app/DataTransferObjects/UserData.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace App\DataTransferObjects;
+
+use Spatie\LaravelData\Data;
+use Spatie\TypeScriptTransformer\Attributes\TypeScript;
+
+#[TypeScript]
+class UserData extends Data
+{
+  public function __construct(
+    public int $id,
+
+    public string $name,
+
+    public string $email,
+
+    public string $profile_photo_url,
+
+    public string $email_verified_at
+  ) {}
+}
diff --git a/application/app/Enums/PermissionEnum.php b/application/app/Enums/PermissionEnum.php
new file mode 100644
index 0000000000000000000000000000000000000000..86912ba5f4687b56079da1700ec1d989d8ddf17c
--- /dev/null
+++ b/application/app/Enums/PermissionEnum.php
@@ -0,0 +1,64 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Enums;
+
+use Spatie\Enum\Laravel\Enum;
+
+/**
+ * @method static self create_catalyst_communities()
+ * @method static self create_catalyst_groups()
+ * @method static self create_ideascale_profiles()
+ * @method static self create_events()
+ * @method static self create_funds()
+ * @method static self create_links()
+ * @method static self create_proposals()
+ * @method static self create_ratings()
+ * @method static self create_reviews()
+ * @method static self create_rewards()
+ * @method static self create_roles()
+ * @method static self create_users()
+ * @method static self create_votes()
+ * @method static self read_catalyst_communities()
+ * @method static self read_catalyst_groups()
+ * @method static self read_ideascale_profiles()
+ * @method static self read_funds()
+ * @method static self read_media()
+ * @method static self read_permissions()
+ * @method static self read_proposals()
+ * @method static self read_ratings()
+ * @method static self read_reviews()
+ * @method static self read_roles()
+ * @method static self read_users()
+ * @method static self update_catalyst_communities()
+ * @method static self update_catalyst_groups()
+ * @method static self update_ideascale_profiles()
+ * @method static self update_admins()
+ * @method static self update_funds()
+ * @method static self update_media()
+ * @method static self update_proposals()
+ * @method static self update_ratings()
+ * @method static self update_reviews()
+ * @method static self update_roles()
+ * @method static self update_users()
+ * @method static self delete_catalyst_communities()
+ * @method static self delete_catalyst_groups()
+ * @method static self delete_catalyst_users()
+ * @method static self delete_admins()
+ * @method static self delete_funds()
+ * @method static self delete_permissions()
+ * @method static self delete_proposals()
+ * @method static self delete_ratings()
+ * @method static self delete_reviews()
+ * @method static self delete_rewards()
+ * @method static self delete_roles()
+ * @method static self delete_users()
+ */
+final class PermissionEnum extends Enum
+{
+    protected static function values(): \Closure
+    {
+        return fn(string $name): string|int => str_replace('_', ' ', mb_strtolower($name));
+    }
+}
diff --git a/application/app/Enums/RoleEnum.php b/application/app/Enums/RoleEnum.php
new file mode 100644
index 0000000000000000000000000000000000000000..7385757e57119920f64ada93da000dccce0c4453
--- /dev/null
+++ b/application/app/Enums/RoleEnum.php
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Enums;
+
+use Spatie\Enum\Laravel\Enum;
+
+/**
+ * @method static self contributor()
+ * @method static self viewer()
+ * @method static self editor()
+ * @method static self admin()
+ * @method static self super_admin()
+ */
+final class RoleEnum extends Enum
+{
+    protected static function values(): \Closure
+    {
+        return fn(string $name): string|int => str_replace('_', ' ', mb_strtolower($name));
+    }
+}
diff --git a/application/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/application/app/Http/Controllers/Auth/AuthenticatedSessionController.php
index 9b4b92d6eec6ec6c87c1038408155cdad34539d4..4d8ae46c3cca3aa4fa6e765bdc0b141c8c1dec7e 100644
--- a/application/app/Http/Controllers/Auth/AuthenticatedSessionController.php
+++ b/application/app/Http/Controllers/Auth/AuthenticatedSessionController.php
@@ -8,7 +8,6 @@
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
 use Illuminate\Support\Facades\Route;
-use Laravolt\Avatar\Facade as Avatar;
 use Inertia\Inertia;
 use Inertia\Response;
 
@@ -34,12 +33,6 @@ public function store(LoginRequest $request): RedirectResponse
 
         $request->session()->regenerate();
 
-        $user = Auth::user();
-
-        $avatar = Avatar::create($user->name)->toBase64();
-
-        $request->session()->put('avatar', $avatar);
-
         return redirect()->intended(route('dashboard', absolute: false));
 
     }
diff --git a/application/app/Http/Middleware/HandleInertiaRequests.php b/application/app/Http/Middleware/HandleInertiaRequests.php
index 3cfcd34618f0632b432192bc18c2e0de9703a445..17ab36dc3d4be20483f35f7abcc100d5c6e2dd40 100644
--- a/application/app/Http/Middleware/HandleInertiaRequests.php
+++ b/application/app/Http/Middleware/HandleInertiaRequests.php
@@ -4,6 +4,7 @@
 
 namespace App\Http\Middleware;
 
+use App\DataTransferObjects\UserData;
 use Illuminate\Http\Request;
 use Inertia\Middleware;
 
@@ -34,8 +35,7 @@ public function share(Request $request): array
         return [
             ...parent::share($request),
             'auth' => [
-                'user' => $request->user(),
-                'avatar' => $request->session()->get('avatar')
+                'user' => $request->user() ? UserData::from($request->user()) : null,
             ],
         ];
     }
diff --git a/application/app/Models/Model.php b/application/app/Models/Model.php
new file mode 100644
index 0000000000000000000000000000000000000000..03f87af0b0ae0c62f497d277407d814a2d4d2331
--- /dev/null
+++ b/application/app/Models/Model.php
@@ -0,0 +1,13 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Model as EloquentModel;
+
+class Model extends EloquentModel
+{
+    use HasFactory;
+}
diff --git a/application/app/Models/Proposal.php b/application/app/Models/Proposal.php
index 8f167f4fbebb428e69467067c583cfbd7d7bf01a..665e8b0eb4797e96393ea2d879e3ab6fc13580f7 100644
--- a/application/app/Models/Proposal.php
+++ b/application/app/Models/Proposal.php
@@ -1,10 +1,12 @@
 <?php
 
+declare(strict_types=1);
+
 namespace App\Models;
 
+use App\Models\Model;
 use App\Enums\CatalystCurrencies;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
-use Illuminate\Database\Eloquent\Model;
 
 class Proposal extends Model
 {
diff --git a/application/app/Models/User.php b/application/app/Models/User.php
index 7d4ed6e1632239d1df8e39b3dfbff09d56c940f4..49705091f9ae7b4def56cac72cf1a54538f9dae9 100644
--- a/application/app/Models/User.php
+++ b/application/app/Models/User.php
@@ -4,13 +4,21 @@
 
 namespace App\Models;
 
+use Laravolt\Avatar\Facade as Avatar;
+use Spatie\MediaLibrary\HasMedia;
+use Illuminate\Auth\MustVerifyEmail;
+use Spatie\Image\Enums\CropPosition;
+use Spatie\Permission\Traits\HasRoles;
+use Illuminate\Notifications\Notifiable;
+use Spatie\MediaLibrary\InteractsWithMedia;
+use Illuminate\Database\Eloquent\Casts\Attribute;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Spatie\MediaLibrary\MediaCollections\Models\Media;
 use Illuminate\Foundation\Auth\User as Authenticatable;
-use Illuminate\Notifications\Notifiable;
 
-class User extends Authenticatable
+class User extends Authenticatable implements HasMedia
 {
-    use HasFactory, Notifiable;
+    use HasFactory, Notifiable, HasRoles, InteractsWithMedia, MustVerifyEmail;
 
     /**
      * The attributes that are mass assignable.
@@ -45,4 +53,38 @@ protected function casts(): array
             'password' => 'hashed',
         ];
     }
+
+    public function gravatar(): Attribute
+    {
+        return Attribute::make(
+            get: fn() => Avatar::create($this->email)->toGravatar()
+        );
+    }
+
+    public function profilePhotoUrl(): Attribute
+    {
+        return Attribute::make(
+            get: fn() => count($this->getMedia('profile')) ? $this->getMedia('profile')[0]->getFullUrl() : $this->gravatar
+        );
+    }
+
+    public function registerMediaConversions(?Media $media = null): void
+    {
+        $this->addMediaConversion('thumbnail')
+            ->width(150)
+            ->height(150)
+            ->withResponsiveImages()
+            ->crop(150, 150, CropPosition::Top)
+            ->performOnCollections('profile')
+            ->useFallbackUrl($this->gravatar);
+
+        $this->addMediaConversion('large')
+            ->width(1080)
+            ->height(1350)
+            ->crop(1080, 1350, CropPosition::Top)
+            ->withResponsiveImages()
+            ->performOnCollections('profile')
+            ->useFallbackUrl($this->gravatar);
+    }
+
 }
diff --git a/application/app/Observers/ProposalObserver.php b/application/app/Observers/ProposalObserver.php
index e575fa5953083d540f135fb902020a90eefb0a94..d78707478199798fe5d08f1f3804ec99dddc213d 100644
--- a/application/app/Observers/ProposalObserver.php
+++ b/application/app/Observers/ProposalObserver.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace App\Observers;
 
 use App\Models\Proposal;
diff --git a/application/app/Policies/AppPolicy.php b/application/app/Policies/AppPolicy.php
new file mode 100644
index 0000000000000000000000000000000000000000..7eafe7ed9b69bb083d768ef9ab4903403c72f15e
--- /dev/null
+++ b/application/app/Policies/AppPolicy.php
@@ -0,0 +1,119 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Policies;
+
+use App\Models\User;
+use App\Models\Model;
+use App\Enums\RoleEnum;
+use Illuminate\Auth\Access\HandlesAuthorization;
+
+class AppPolicy
+{
+    use HandlesAuthorization;
+
+    /**
+     * Perform pre-authorization checks.
+     */
+    public function before(User $user, string $ability): bool
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can view any models.
+     */
+    public function canViewAny(User $user): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can view the model.
+     * @throws \Exception
+     */
+    public function canView(User $user, $model): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]) || $this->ownsModel($user, $model);
+    }
+
+    /**
+     * Determine whether the user can create models.
+     */
+    public function canCreate(User $user): bool
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can update the model.
+     */
+    public function canUpdate(User $user, $model): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]) || $this->ownsModel($user, $model);
+    }
+
+    /** Determine whether the user can update the model.*/
+    public function canUpdateAny(User $user): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can delete the model.
+     */
+    public function canDelete(User $user, $model): bool
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]) || $this->ownsModel($user, $model);
+    }
+
+    /**
+     * Determine whether the user can delete the model.
+     */
+    public function canDeleteAny(User $user): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can delete the model.
+     */
+    public function canForceDelete(User $user, $model): bool
+    {
+        return $user->hasAnyRole([RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can delete the model.
+     */
+    public function canForceDeleteAny(User $user): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can delete the model.
+     */
+    public function forceDelete(User $user, Model $model): mixed
+    {
+        return $user->hasAnyRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    /**
+     * Determine whether the user can restore the model.
+     */
+    public function restore(User $user, User $model): bool
+    {
+        return $user->hasRole([RoleEnum::admin()->value, RoleEnum::super_admin()->value]);
+    }
+
+    protected function ownsModel(User $user, $model): bool
+    {
+        if ($model instanceof User) {
+            return $user->id === $model->id;
+        }
+
+        return $user->id === $model->user_id;
+    }
+}
diff --git a/application/app/Policies/UserPolicy.php b/application/app/Policies/UserPolicy.php
new file mode 100644
index 0000000000000000000000000000000000000000..83866d517fdbdc0409929f978cc81212827db239
--- /dev/null
+++ b/application/app/Policies/UserPolicy.php
@@ -0,0 +1,53 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Policies;
+
+use App\Models\User;
+use App\Enums\RoleEnum;
+use App\Enums\PermissionEnum;
+use Illuminate\Auth\Access\Response;
+
+class UserPolicy extends AppPolicy
+{
+    /**
+     * Determine whether the user can view any models.
+     */
+    public function viewAny(User $user): bool
+    {
+        return parent::canViewAny($user) || $user->hasAnyPermission([PermissionEnum::read_users()->value]);
+    }
+
+    /**
+     * Determine whether the user can view the model.
+     */
+    public function view(User $user, User $model): bool
+    {
+        return parent::canView($user, $model) || $user->hasAnyPermission([PermissionEnum::read_users()->value]);
+    }
+
+    /**
+     * Determine whether the user can create models.
+     */
+    public function create(User $user): bool
+    {
+        return parent::canCreate($user) || $user->hasAnyPermission([PermissionEnum::create_users()->value]);
+    }
+
+    /**
+     * Determine whether the user can update the model.
+     */
+    public function update(User $user, User $model): bool
+    {
+        return parent::canUpdate($user, $model) || $user->hasAnyPermission([PermissionEnum::update_users()->value]);
+    }
+
+    /**
+     * Determine whether the user can delete the model.
+     */
+    public function delete(User $user, User $model): bool
+    {
+        return parent::canDelete($user, $model) || $user->hasAnyPermission([PermissionEnum::delete_users()->value]);
+    }
+}
diff --git a/application/app/Repositories/ProposalRepository.php b/application/app/Repositories/ProposalRepository.php
index 25c3197ac2eb42c9e7132e52046224502cfc5604..75573951ae8831ae8c02f73ba32f4f1eb502c845 100644
--- a/application/app/Repositories/ProposalRepository.php
+++ b/application/app/Repositories/ProposalRepository.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace App\Repositories;
 
 use App\Models\Proposal;
diff --git a/application/app/Repositories/Repository.php b/application/app/Repositories/Repository.php
index 45c441e9b1ca415442d00b4659f43640700bcf80..babc578d42e011a74732a810c0334b391ba59c9f 100644
--- a/application/app/Repositories/Repository.php
+++ b/application/app/Repositories/Repository.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace App\Repositories;
 
 use App\Scopes\LimitScope;
diff --git a/application/app/Repositories/RepositoryInterface.php b/application/app/Repositories/RepositoryInterface.php
index 66a7d98154bc9f09701422d01e62bd9438a99a21..2aabd2930a86c45a35bc36225e939c4f915bcf4b 100644
--- a/application/app/Repositories/RepositoryInterface.php
+++ b/application/app/Repositories/RepositoryInterface.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace App\Repositories;
 
 interface RepositoryInterface
diff --git a/application/app/Scopes/LimitScope.php b/application/app/Scopes/LimitScope.php
index 146465188f4af1912e593ab4bd9ba2313f62ff37..0ee54566242ed044abcbbe337c689afd5d632060 100644
--- a/application/app/Scopes/LimitScope.php
+++ b/application/app/Scopes/LimitScope.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace App\Scopes;
 
 use Illuminate\Database\Eloquent\Builder;
diff --git a/application/composer.json b/application/composer.json
index cf70280415db81d96a7d9c50192206bb3780e8d8..6cfecd213d3a48079da6a7ed916ee553b2f7cc9f 100644
--- a/application/composer.json
+++ b/application/composer.json
@@ -14,6 +14,9 @@
         "laravel/tinker": "^2.9",
         "laravolt/avatar": "^6.0",
         "spatie/laravel-data": "^4.11",
+        "spatie/laravel-enum": "^3.1",
+        "spatie/laravel-medialibrary": "^11.9",
+        "spatie/laravel-permission": "^6.10",
         "spatie/laravel-typescript-transformer": "^2.5",
         "tightenco/ziggy": "^2.0"
     },
diff --git a/application/composer.lock b/application/composer.lock
index 794f089fdb686974853896c5a557d9fa776b53f2..d5744224eba141060dc8d62935600e1dd5f131fe 100644
--- a/application/composer.lock
+++ b/application/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "12182aba8ac451efd365c7c9bd97324c",
+    "content-hash": "4fdd26c781ec96df3d4a35da294ccbe1",
     "packages": [
         {
             "name": "amphp/amp",
@@ -994,6 +994,87 @@
             ],
             "time": "2024-02-09T16:56:22+00:00"
         },
+        {
+            "name": "composer/semver",
+            "version": "3.4.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/composer/semver.git",
+                "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+                "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.3.2 || ^7.0 || ^8.0"
+            },
+            "require-dev": {
+                "phpstan/phpstan": "^1.11",
+                "symfony/phpunit-bridge": "^3 || ^7"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "3.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Composer\\Semver\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nils Adermann",
+                    "email": "naderman@naderman.de",
+                    "homepage": "http://www.naderman.de"
+                },
+                {
+                    "name": "Jordi Boggiano",
+                    "email": "j.boggiano@seld.be",
+                    "homepage": "http://seld.be"
+                },
+                {
+                    "name": "Rob Bast",
+                    "email": "rob.bast@gmail.com",
+                    "homepage": "http://robbast.nl"
+                }
+            ],
+            "description": "Semver library that offers utilities, version constraint parsing and validation.",
+            "keywords": [
+                "semantic",
+                "semver",
+                "validation",
+                "versioning"
+            ],
+            "support": {
+                "irc": "ircs://irc.libera.chat:6697/composer",
+                "issues": "https://github.com/composer/semver/issues",
+                "source": "https://github.com/composer/semver/tree/3.4.3"
+            },
+            "funding": [
+                {
+                    "url": "https://packagist.com",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-09-19T14:15:21+00:00"
+        },
         {
             "name": "daverandom/libdns",
             "version": "v2.1.0",
@@ -3641,6 +3722,83 @@
             ],
             "time": "2024-03-23T07:42:40+00:00"
         },
+        {
+            "name": "maennchen/zipstream-php",
+            "version": "3.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/maennchen/ZipStream-PHP.git",
+                "reference": "6187e9cc4493da94b9b63eb2315821552015fca9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/6187e9cc4493da94b9b63eb2315821552015fca9",
+                "reference": "6187e9cc4493da94b9b63eb2315821552015fca9",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "ext-zlib": "*",
+                "php-64bit": "^8.1"
+            },
+            "require-dev": {
+                "ext-zip": "*",
+                "friendsofphp/php-cs-fixer": "^3.16",
+                "guzzlehttp/guzzle": "^7.5",
+                "mikey179/vfsstream": "^1.6",
+                "php-coveralls/php-coveralls": "^2.5",
+                "phpunit/phpunit": "^10.0",
+                "vimeo/psalm": "^5.0"
+            },
+            "suggest": {
+                "guzzlehttp/psr7": "^2.4",
+                "psr/http-message": "^2.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "ZipStream\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paul Duncan",
+                    "email": "pabs@pablotron.org"
+                },
+                {
+                    "name": "Jonatan Männchen",
+                    "email": "jonatan@maennchen.ch"
+                },
+                {
+                    "name": "Jesse Donat",
+                    "email": "donatj@gmail.com"
+                },
+                {
+                    "name": "András Kolesár",
+                    "email": "kolesar@kolesar.hu"
+                }
+            ],
+            "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
+            "keywords": [
+                "stream",
+                "zip"
+            ],
+            "support": {
+                "issues": "https://github.com/maennchen/ZipStream-PHP/issues",
+                "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.1"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/maennchen",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-10-10T12:33:01+00:00"
+        },
         {
             "name": "monolog/monolog",
             "version": "3.7.0",
@@ -5293,6 +5451,210 @@
             },
             "time": "2023-11-30T05:34:44+00:00"
         },
+        {
+            "name": "spatie/enum",
+            "version": "3.13.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/enum.git",
+                "reference": "f1a0f464ba909491a53e60a955ce84ad7cd93a2c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/enum/zipball/f1a0f464ba909491a53e60a955ce84ad7cd93a2c",
+                "reference": "f1a0f464ba909491a53e60a955ce84ad7cd93a2c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "php": "^8.0"
+            },
+            "require-dev": {
+                "fakerphp/faker": "^1.9.1",
+                "larapack/dd": "^1.1",
+                "phpunit/phpunit": "^9.0",
+                "vimeo/psalm": "^4.3"
+            },
+            "suggest": {
+                "fakerphp/faker": "To use the enum faker provider",
+                "phpunit/phpunit": "To use the enum assertions"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\Enum\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Brent Roose",
+                    "email": "brent@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Tom Witkowski",
+                    "email": "dev@gummibeer.de",
+                    "homepage": "https://gummibeer.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "PHP Enums",
+            "homepage": "https://github.com/spatie/enum",
+            "keywords": [
+                "enum",
+                "enumerable",
+                "spatie"
+            ],
+            "support": {
+                "docs": "https://docs.spatie.be/enum",
+                "issues": "https://github.com/spatie/enum/issues",
+                "source": "https://github.com/spatie/enum"
+            },
+            "funding": [
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-04-22T08:51:55+00:00"
+        },
+        {
+            "name": "spatie/image",
+            "version": "3.7.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/image.git",
+                "reference": "d72d1ae07f91a3c1230e064acd4fd8c334ab237b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/image/zipball/d72d1ae07f91a3c1230e064acd4fd8c334ab237b",
+                "reference": "d72d1ae07f91a3c1230e064acd4fd8c334ab237b",
+                "shasum": ""
+            },
+            "require": {
+                "ext-exif": "*",
+                "ext-json": "*",
+                "ext-mbstring": "*",
+                "php": "^8.2",
+                "spatie/image-optimizer": "^1.7.5",
+                "spatie/temporary-directory": "^2.2",
+                "symfony/process": "^6.4|^7.0"
+            },
+            "require-dev": {
+                "ext-gd": "*",
+                "ext-imagick": "*",
+                "laravel/sail": "^1.34",
+                "pestphp/pest": "^2.28",
+                "phpstan/phpstan": "^1.10.50",
+                "spatie/pest-plugin-snapshots": "^2.1",
+                "spatie/pixelmatch-php": "^1.0",
+                "spatie/ray": "^1.40.1",
+                "symfony/var-dumper": "^6.4|7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\Image\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Manipulate images with an expressive API",
+            "homepage": "https://github.com/spatie/image",
+            "keywords": [
+                "image",
+                "spatie"
+            ],
+            "support": {
+                "source": "https://github.com/spatie/image/tree/3.7.4"
+            },
+            "funding": [
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-10-07T09:03:34+00:00"
+        },
+        {
+            "name": "spatie/image-optimizer",
+            "version": "1.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/image-optimizer.git",
+                "reference": "4fd22035e81d98fffced65a8c20d9ec4daa9671c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/image-optimizer/zipball/4fd22035e81d98fffced65a8c20d9ec4daa9671c",
+                "reference": "4fd22035e81d98fffced65a8c20d9ec4daa9671c",
+                "shasum": ""
+            },
+            "require": {
+                "ext-fileinfo": "*",
+                "php": "^7.3|^8.0",
+                "psr/log": "^1.0 | ^2.0 | ^3.0",
+                "symfony/process": "^4.2|^5.0|^6.0|^7.0"
+            },
+            "require-dev": {
+                "pestphp/pest": "^1.21",
+                "phpunit/phpunit": "^8.5.21|^9.4.4",
+                "symfony/var-dumper": "^4.2|^5.0|^6.0|^7.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\ImageOptimizer\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Easily optimize images using PHP",
+            "homepage": "https://github.com/spatie/image-optimizer",
+            "keywords": [
+                "image-optimizer",
+                "spatie"
+            ],
+            "support": {
+                "issues": "https://github.com/spatie/image-optimizer/issues",
+                "source": "https://github.com/spatie/image-optimizer/tree/1.8.0"
+            },
+            "time": "2024-11-04T08:24:54+00:00"
+        },
         {
             "name": "spatie/laravel-data",
             "version": "4.11.1",
@@ -5377,6 +5739,207 @@
             ],
             "time": "2024-10-23T07:14:53+00:00"
         },
+        {
+            "name": "spatie/laravel-enum",
+            "version": "3.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/laravel-enum.git",
+                "reference": "423128aea07601873722940d3055dc9a2364a737"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/laravel-enum/zipball/423128aea07601873722940d3055dc9a2364a737",
+                "reference": "423128aea07601873722940d3055dc9a2364a737",
+                "shasum": ""
+            },
+            "require": {
+                "ext-json": "*",
+                "illuminate/console": "^8.0 || ^9.43 || ^10.0 || ^11.0",
+                "illuminate/contracts": "^8.0 || ^9.43 || ^10.0 || ^11.0",
+                "illuminate/database": "^8.0 || ^9.43 || ^10.0 || ^11.0",
+                "illuminate/http": "^8.0 || ^9.43 || ^10.0 || ^11.0",
+                "illuminate/support": "^8.0 || ^9.43 || ^10.0 || ^11.0",
+                "php": "^8.0",
+                "spatie/enum": "^3.9"
+            },
+            "conflict": {
+                "bensampo/laravel-enum": "*"
+            },
+            "require-dev": {
+                "fakerphp/faker": "^1.16",
+                "mockery/mockery": "^1.4.0",
+                "orchestra/testbench": "^6.0 || ^7.0 || ^8.0 || ^9.0",
+                "phpunit/phpunit": "^9.5 || ^10.0",
+                "vimeo/psalm": "^4.0 || ^5.0"
+            },
+            "suggest": {
+                "fzaninotto/faker": "^1.9.1"
+            },
+            "type": "library",
+            "extra": {
+                "laravel": {
+                    "providers": [
+                        "Spatie\\Enum\\Laravel\\EnumServiceProvider"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\Enum\\Laravel\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Brent Roose",
+                    "email": "brent@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                },
+                {
+                    "name": "Tom Witkowski",
+                    "email": "dev@gummibeer.de",
+                    "homepage": "https://gummibeer.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Laravel Enum support",
+            "homepage": "https://github.com/spatie/laravel-enum",
+            "keywords": [
+                "enum",
+                "laravel",
+                "laravel-enum",
+                "spatie"
+            ],
+            "support": {
+                "issues": "https://github.com/spatie/laravel-enum/issues",
+                "source": "https://github.com/spatie/laravel-enum/tree/3.1.0"
+            },
+            "funding": [
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-06-12T08:02:01+00:00"
+        },
+        {
+            "name": "spatie/laravel-medialibrary",
+            "version": "11.9.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/laravel-medialibrary.git",
+                "reference": "6a39eca52236bc1e1261f366d4022996521ae843"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/laravel-medialibrary/zipball/6a39eca52236bc1e1261f366d4022996521ae843",
+                "reference": "6a39eca52236bc1e1261f366d4022996521ae843",
+                "shasum": ""
+            },
+            "require": {
+                "composer/semver": "^3.4",
+                "ext-exif": "*",
+                "ext-fileinfo": "*",
+                "ext-json": "*",
+                "illuminate/bus": "^10.0|^11.0",
+                "illuminate/conditionable": "^10.0|^11.0",
+                "illuminate/console": "^10.0|^11.0",
+                "illuminate/database": "^10.0|^11.0",
+                "illuminate/pipeline": "^10.0|^11.0",
+                "illuminate/support": "^10.0|^11.0",
+                "maennchen/zipstream-php": "^3.1",
+                "php": "^8.2",
+                "spatie/image": "^3.3.2",
+                "spatie/laravel-package-tools": "^1.16.1",
+                "spatie/temporary-directory": "^2.2",
+                "symfony/console": "^6.4.1|^7.0"
+            },
+            "conflict": {
+                "php-ffmpeg/php-ffmpeg": "<0.6.1"
+            },
+            "require-dev": {
+                "aws/aws-sdk-php": "^3.293.10",
+                "ext-imagick": "*",
+                "ext-pdo_sqlite": "*",
+                "ext-zip": "*",
+                "guzzlehttp/guzzle": "^7.8.1",
+                "larastan/larastan": "^2.7",
+                "league/flysystem-aws-s3-v3": "^3.22",
+                "mockery/mockery": "^1.6.7",
+                "orchestra/testbench": "^7.0|^8.17|^9.0",
+                "pestphp/pest": "^2.28",
+                "phpstan/extension-installer": "^1.3.1",
+                "spatie/laravel-ray": "^1.33",
+                "spatie/pdf-to-image": "^2.2|^3.0",
+                "spatie/pest-plugin-snapshots": "^2.1"
+            },
+            "suggest": {
+                "league/flysystem-aws-s3-v3": "Required to use AWS S3 file storage",
+                "php-ffmpeg/php-ffmpeg": "Required for generating video thumbnails",
+                "spatie/pdf-to-image": "Required for generating thumbnails of PDFs and SVGs"
+            },
+            "type": "library",
+            "extra": {
+                "laravel": {
+                    "providers": [
+                        "Spatie\\MediaLibrary\\MediaLibraryServiceProvider"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\MediaLibrary\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Associate files with Eloquent models",
+            "homepage": "https://github.com/spatie/laravel-medialibrary",
+            "keywords": [
+                "cms",
+                "conversion",
+                "downloads",
+                "images",
+                "laravel",
+                "laravel-medialibrary",
+                "media",
+                "spatie"
+            ],
+            "support": {
+                "issues": "https://github.com/spatie/laravel-medialibrary/issues",
+                "source": "https://github.com/spatie/laravel-medialibrary/tree/11.9.2"
+            },
+            "funding": [
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-10-18T14:24:58+00:00"
+        },
         {
             "name": "spatie/laravel-package-tools",
             "version": "1.16.5",
@@ -5437,6 +6000,89 @@
             ],
             "time": "2024-08-27T18:56:10+00:00"
         },
+        {
+            "name": "spatie/laravel-permission",
+            "version": "6.10.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/laravel-permission.git",
+                "reference": "2444bb914a52c570c00ae8c94e096a58e01b2317"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/2444bb914a52c570c00ae8c94e096a58e01b2317",
+                "reference": "2444bb914a52c570c00ae8c94e096a58e01b2317",
+                "shasum": ""
+            },
+            "require": {
+                "illuminate/auth": "^8.12|^9.0|^10.0|^11.0",
+                "illuminate/container": "^8.12|^9.0|^10.0|^11.0",
+                "illuminate/contracts": "^8.12|^9.0|^10.0|^11.0",
+                "illuminate/database": "^8.12|^9.0|^10.0|^11.0",
+                "php": "^8.0"
+            },
+            "require-dev": {
+                "larastan/larastan": "^1.0|^2.0",
+                "laravel/passport": "^11.0|^12.0",
+                "orchestra/testbench": "^6.23|^7.0|^8.0|^9.0",
+                "phpunit/phpunit": "^9.4|^10.1"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "6.x-dev",
+                    "dev-master": "6.x-dev"
+                },
+                "laravel": {
+                    "providers": [
+                        "Spatie\\Permission\\PermissionServiceProvider"
+                    ]
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/helpers.php"
+                ],
+                "psr-4": {
+                    "Spatie\\Permission\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Freek Van der Herten",
+                    "email": "freek@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Permission handling for Laravel 8.0 and up",
+            "homepage": "https://github.com/spatie/laravel-permission",
+            "keywords": [
+                "acl",
+                "laravel",
+                "permission",
+                "permissions",
+                "rbac",
+                "roles",
+                "security",
+                "spatie"
+            ],
+            "support": {
+                "issues": "https://github.com/spatie/laravel-permission/issues",
+                "source": "https://github.com/spatie/laravel-permission/tree/6.10.0"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-11-05T17:30:49+00:00"
+        },
         {
             "name": "spatie/laravel-typescript-transformer",
             "version": "2.5.0",
@@ -5598,6 +6244,67 @@
             ],
             "time": "2024-08-29T10:43:45+00:00"
         },
+        {
+            "name": "spatie/temporary-directory",
+            "version": "2.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/spatie/temporary-directory.git",
+                "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/spatie/temporary-directory/zipball/76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a",
+                "reference": "76949fa18f8e1a7f663fd2eaa1d00e0bcea0752a",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^8.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Spatie\\TemporaryDirectory\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Alex Vanderbist",
+                    "email": "alex@spatie.be",
+                    "homepage": "https://spatie.be",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Easily create, use and destroy temporary directories",
+            "homepage": "https://github.com/spatie/temporary-directory",
+            "keywords": [
+                "php",
+                "spatie",
+                "temporary-directory"
+            ],
+            "support": {
+                "issues": "https://github.com/spatie/temporary-directory/issues",
+                "source": "https://github.com/spatie/temporary-directory/tree/2.2.1"
+            },
+            "funding": [
+                {
+                    "url": "https://spatie.be/open-source/support-us",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/spatie",
+                    "type": "github"
+                }
+            ],
+            "time": "2023-12-25T11:46:58+00:00"
+        },
         {
             "name": "spatie/typescript-transformer",
             "version": "2.4.0",
@@ -11200,6 +11907,6 @@
     "platform": {
         "php": "^8.2"
     },
-    "platform-dev": [],
+    "platform-dev": {},
     "plugin-api-version": "2.6.0"
 }
diff --git a/application/config/data.php b/application/config/data.php
index 3be386d1b9fc0ead24e056ea100633e82ec46659..4e80b2087cdd3a8dc1f41d33439b530bacf1c693 100644
--- a/application/config/data.php
+++ b/application/config/data.php
@@ -173,7 +173,7 @@
              * so the default 'Data` will end up as '\App\Data', and generated Data classes will be placed in the
              * app/Data/ folder. Data classes can live anywhere, but this is where `make:data` will put them.
              */
-            'namespace' => 'Data',
+            'namespace' => 'DataTransferObjects',
 
             /**
              * This suffix will be appended to all data classes generated by make:data, so that they are less likely
diff --git a/application/config/media-library.php b/application/config/media-library.php
new file mode 100644
index 0000000000000000000000000000000000000000..8823bb2ae785478fc27a85a302001f4f2a0fccef
--- /dev/null
+++ b/application/config/media-library.php
@@ -0,0 +1,280 @@
+<?php
+
+return [
+
+    /*
+     * The disk on which to store added files and derived images by default. Choose
+     * one or more of the disks you've configured in config/filesystems.php.
+     */
+    'disk_name' => env('MEDIA_DISK', 'public'),
+
+    /*
+     * The maximum file size of an item in bytes.
+     * Adding a larger file will result in an exception.
+     */
+    'max_file_size' => 1024 * 1024 * 10, // 10MB
+
+    /*
+     * This queue connection will be used to generate derived and responsive images.
+     * Leave empty to use the default queue connection.
+     */
+    'queue_connection_name' => env('QUEUE_CONNECTION', 'sync'),
+
+    /*
+     * This queue will be used to generate derived and responsive images.
+     * Leave empty to use the default queue.
+     */
+    'queue_name' => env('MEDIA_QUEUE', ''),
+
+    /*
+     * By default all conversions will be performed on a queue.
+     */
+    'queue_conversions_by_default' => env('QUEUE_CONVERSIONS_BY_DEFAULT', true),
+
+    /*
+     * Should database transactions be run after database commits?
+     */
+    'queue_conversions_after_database_commit' => env('QUEUE_CONVERSIONS_AFTER_DB_COMMIT', true),
+
+    /*
+     * The fully qualified class name of the media model.
+     */
+    'media_model' => Spatie\MediaLibrary\MediaCollections\Models\Media::class,
+
+    /*
+     * When enabled, media collections will be serialised using the default
+     * laravel model serialization behaviour.
+     *
+     * Keep this option disabled if using Media Library Pro components (https://medialibrary.pro)
+     */
+    'use_default_collection_serialization' => false,
+
+    /*
+     * The fully qualified class name of the model used for temporary uploads.
+     *
+     * This model is only used in Media Library Pro (https://medialibrary.pro)
+     */
+    'temporary_upload_model' => Spatie\MediaLibraryPro\Models\TemporaryUpload::class,
+
+    /*
+     * When enabled, Media Library Pro will only process temporary uploads that were uploaded
+     * in the same session. You can opt to disable this for stateless usage of
+     * the pro components.
+     */
+    'enable_temporary_uploads_session_affinity' => true,
+
+    /*
+     * When enabled, Media Library pro will generate thumbnails for uploaded file.
+     */
+    'generate_thumbnails_for_temporary_uploads' => true,
+
+    /*
+     * This is the class that is responsible for naming generated files.
+     */
+    'file_namer' => Spatie\MediaLibrary\Support\FileNamer\DefaultFileNamer::class,
+
+    /*
+     * The class that contains the strategy for determining a media file's path.
+     */
+    'path_generator' => Spatie\MediaLibrary\Support\PathGenerator\DefaultPathGenerator::class,
+
+    /*
+     * The class that contains the strategy for determining how to remove files.
+     */
+    'file_remover_class' => Spatie\MediaLibrary\Support\FileRemover\DefaultFileRemover::class,
+
+    /*
+     * Here you can specify which path generator should be used for the given class.
+     */
+    'custom_path_generators' => [
+        // Model::class => PathGenerator::class
+        // or
+        // 'model_morph_alias' => PathGenerator::class
+    ],
+
+    /*
+     * When urls to files get generated, this class will be called. Use the default
+     * if your files are stored locally above the site root or on s3.
+     */
+    'url_generator' => Spatie\MediaLibrary\Support\UrlGenerator\DefaultUrlGenerator::class,
+
+    /*
+     * Moves media on updating to keep path consistent. Enable it only with a custom
+     * PathGenerator that uses, for example, the media UUID.
+     */
+    'moves_media_on_update' => false,
+
+    /*
+     * Whether to activate versioning when urls to files get generated.
+     * When activated, this attaches a ?v=xx query string to the URL.
+     */
+    'version_urls' => false,
+
+    /*
+     * The media library will try to optimize all converted images by removing
+     * metadata and applying a little bit of compression. These are
+     * the optimizers that will be used by default.
+     */
+    'image_optimizers' => [
+        Spatie\ImageOptimizer\Optimizers\Jpegoptim::class => [
+            '-m85', // set maximum quality to 85%
+            '--force', // ensure that progressive generation is always done also if a little bigger
+            '--strip-all', // this strips out all text information such as comments and EXIF data
+            '--all-progressive', // this will make sure the resulting image is a progressive one
+        ],
+        Spatie\ImageOptimizer\Optimizers\Pngquant::class => [
+            '--force', // required parameter for this package
+        ],
+        Spatie\ImageOptimizer\Optimizers\Optipng::class => [
+            '-i0', // this will result in a non-interlaced, progressive scanned image
+            '-o2', // this set the optimization level to two (multiple IDAT compression trials)
+            '-quiet', // required parameter for this package
+        ],
+        Spatie\ImageOptimizer\Optimizers\Svgo::class => [
+            '--disable=cleanupIDs', // disabling because it is known to cause troubles
+        ],
+        Spatie\ImageOptimizer\Optimizers\Gifsicle::class => [
+            '-b', // required parameter for this package
+            '-O3', // this produces the slowest but best results
+        ],
+        Spatie\ImageOptimizer\Optimizers\Cwebp::class => [
+            '-m 6', // for the slowest compression method in order to get the best compression.
+            '-pass 10', // for maximizing the amount of analysis pass.
+            '-mt', // multithreading for some speed improvements.
+            '-q 90', //quality factor that brings the least noticeable changes.
+        ],
+        Spatie\ImageOptimizer\Optimizers\Avifenc::class => [
+            '-a cq-level=23', // constant quality level, lower values mean better quality and greater file size (0-63).
+            '-j all', // number of jobs (worker threads, "all" uses all available cores).
+            '--min 0', // min quantizer for color (0-63).
+            '--max 63', // max quantizer for color (0-63).
+            '--minalpha 0', // min quantizer for alpha (0-63).
+            '--maxalpha 63', // max quantizer for alpha (0-63).
+            '-a end-usage=q', // rate control mode set to Constant Quality mode.
+            '-a tune=ssim', // SSIM as tune the encoder for distortion metric.
+        ],
+    ],
+
+    /*
+     * These generators will be used to create an image of media files.
+     */
+    'image_generators' => [
+        Spatie\MediaLibrary\Conversions\ImageGenerators\Image::class,
+        Spatie\MediaLibrary\Conversions\ImageGenerators\Webp::class,
+        Spatie\MediaLibrary\Conversions\ImageGenerators\Avif::class,
+        Spatie\MediaLibrary\Conversions\ImageGenerators\Pdf::class,
+        Spatie\MediaLibrary\Conversions\ImageGenerators\Svg::class,
+        Spatie\MediaLibrary\Conversions\ImageGenerators\Video::class,
+    ],
+
+    /*
+     * The path where to store temporary files while performing image conversions.
+     * If set to null, storage_path('media-library/temp') will be used.
+     */
+    'temporary_directory_path' => storage_path('media-library/temp'),
+
+    /*
+     * The engine that should perform the image conversions.
+     * Should be either `gd` or `imagick`.
+     */
+    'image_driver' => env('IMAGE_DRIVER', 'gd'),
+
+    /*
+     * FFMPEG & FFProbe binaries paths, only used if you try to generate video
+     * thumbnails and have installed the php-ffmpeg/php-ffmpeg composer
+     * dependency.
+     */
+    'ffmpeg_path' => env('FFMPEG_PATH', '/usr/bin/ffmpeg'),
+    'ffprobe_path' => env('FFPROBE_PATH', '/usr/bin/ffprobe'),
+
+    /*
+     * Here you can override the class names of the jobs used by this package. Make sure
+     * your custom jobs extend the ones provided by the package.
+     */
+    'jobs' => [
+        'perform_conversions' => Spatie\MediaLibrary\Conversions\Jobs\PerformConversionsJob::class,
+        'generate_responsive_images' => Spatie\MediaLibrary\ResponsiveImages\Jobs\GenerateResponsiveImagesJob::class,
+    ],
+
+    /*
+     * When using the addMediaFromUrl method you may want to replace the default downloader.
+     * This is particularly useful when the url of the image is behind a firewall and
+     * need to add additional flags, possibly using curl.
+     */
+    'media_downloader' => Spatie\MediaLibrary\Downloaders\DefaultDownloader::class,
+
+    /*
+     * When using the addMediaFromUrl method the SSL is verified by default.
+     * This is option disables SSL verification when downloading remote media.
+     * Please note that this is a security risk and should only be false in a local environment.
+     */
+    'media_downloader_ssl' => env('MEDIA_DOWNLOADER_SSL', true),
+
+    'remote' => [
+        /*
+         * Any extra headers that should be included when uploading media to
+         * a remote disk. Even though supported headers may vary between
+         * different drivers, a sensible default has been provided.
+         *
+         * Supported by S3: CacheControl, Expires, StorageClass,
+         * ServerSideEncryption, Metadata, ACL, ContentEncoding
+         */
+        'extra_headers' => [
+            'CacheControl' => 'max-age=604800',
+        ],
+    ],
+
+    'responsive_images' => [
+        /*
+         * This class is responsible for calculating the target widths of the responsive
+         * images. By default we optimize for filesize and create variations that each are 30%
+         * smaller than the previous one. More info in the documentation.
+         *
+         * https://docs.spatie.be/laravel-medialibrary/v9/advanced-usage/generating-responsive-images
+         */
+        'width_calculator' => Spatie\MediaLibrary\ResponsiveImages\WidthCalculator\FileSizeOptimizedWidthCalculator::class,
+
+        /*
+         * By default rendering media to a responsive image will add some javascript and a tiny placeholder.
+         * This ensures that the browser can already determine the correct layout.
+         * When disabled, no tiny placeholder is generated.
+         */
+        'use_tiny_placeholders' => true,
+
+        /*
+         * This class will generate the tiny placeholder used for progressive image loading. By default
+         * the media library will use a tiny blurred jpg image.
+         */
+        'tiny_placeholder_generator' => Spatie\MediaLibrary\ResponsiveImages\TinyPlaceholderGenerator\Blurred::class,
+    ],
+
+    /*
+     * When enabling this option, a route will be registered that will enable
+     * the Media Library Pro Vue and React components to move uploaded files
+     * in a S3 bucket to their right place.
+     */
+    'enable_vapor_uploads' => env('ENABLE_MEDIA_LIBRARY_VAPOR_UPLOADS', false),
+
+    /*
+     * When converting Media instances to response the media library will add
+     * a `loading` attribute to the `img` tag. Here you can set the default
+     * value of that attribute.
+     *
+     * Possible values: 'lazy', 'eager', 'auto' or null if you don't want to set any loading instruction.
+     *
+     * More info: https://css-tricks.com/native-lazy-loading/
+     */
+    'default_loading_attribute_value' => null,
+
+    /*
+     * You can specify a prefix for that is used for storing all media.
+     * If you set this to `/my-subdir`, all your media will be stored in a `/my-subdir` directory.
+     */
+    'prefix' => env('MEDIA_PREFIX', ''),
+
+    /*
+     * When forcing lazy loading, media will be loaded even if you don't eager load media and you have
+     * disabled lazy loading globally in the service provider.
+     */
+    'force_lazy_loading' => env('FORCE_MEDIA_LIBRARY_LAZY_LOADING', true),
+];
diff --git a/application/config/permission.php b/application/config/permission.php
new file mode 100644
index 0000000000000000000000000000000000000000..2a520f351290b9df0faeb25c58c8e190bde5d02c
--- /dev/null
+++ b/application/config/permission.php
@@ -0,0 +1,186 @@
+<?php
+
+return [
+
+    'models' => [
+
+        /*
+         * When using the "HasPermissions" trait from this package, we need to know which
+         * Eloquent model should be used to retrieve your permissions. Of course, it
+         * is often just the "Permission" model but you may use whatever you like.
+         *
+         * The model you want to use as a Permission model needs to implement the
+         * `Spatie\Permission\Contracts\Permission` contract.
+         */
+
+        'permission' => Spatie\Permission\Models\Permission::class,
+
+        /*
+         * When using the "HasRoles" trait from this package, we need to know which
+         * Eloquent model should be used to retrieve your roles. Of course, it
+         * is often just the "Role" model but you may use whatever you like.
+         *
+         * The model you want to use as a Role model needs to implement the
+         * `Spatie\Permission\Contracts\Role` contract.
+         */
+
+        'role' => Spatie\Permission\Models\Role::class,
+
+    ],
+
+    'table_names' => [
+
+        /*
+         * When using the "HasRoles" trait from this package, we need to know which
+         * table should be used to retrieve your roles. We have chosen a basic
+         * default value but you may easily change it to any table you like.
+         */
+
+        'roles' => 'roles',
+
+        /*
+         * When using the "HasPermissions" trait from this package, we need to know which
+         * table should be used to retrieve your permissions. We have chosen a basic
+         * default value but you may easily change it to any table you like.
+         */
+
+        'permissions' => 'permissions',
+
+        /*
+         * When using the "HasPermissions" trait from this package, we need to know which
+         * table should be used to retrieve your models permissions. We have chosen a
+         * basic default value but you may easily change it to any table you like.
+         */
+
+        'model_has_permissions' => 'model_has_permissions',
+
+        /*
+         * When using the "HasRoles" trait from this package, we need to know which
+         * table should be used to retrieve your models roles. We have chosen a
+         * basic default value but you may easily change it to any table you like.
+         */
+
+        'model_has_roles' => 'model_has_roles',
+
+        /*
+         * When using the "HasRoles" trait from this package, we need to know which
+         * table should be used to retrieve your roles permissions. We have chosen a
+         * basic default value but you may easily change it to any table you like.
+         */
+
+        'role_has_permissions' => 'role_has_permissions',
+    ],
+
+    'column_names' => [
+        /*
+         * Change this if you want to name the related pivots other than defaults
+         */
+        'role_pivot_key' => null, //default 'role_id',
+        'permission_pivot_key' => null, //default 'permission_id',
+
+        /*
+         * Change this if you want to name the related model primary key other than
+         * `model_id`.
+         *
+         * For example, this would be nice if your primary keys are all UUIDs. In
+         * that case, name this `model_uuid`.
+         */
+
+        'model_morph_key' => 'model_id',
+
+        /*
+         * Change this if you want to use the teams feature and your related model's
+         * foreign key is other than `team_id`.
+         */
+
+        'team_foreign_key' => 'team_id',
+    ],
+
+    /*
+     * When set to true, the method for checking permissions will be registered on the gate.
+     * Set this to false if you want to implement custom logic for checking permissions.
+     */
+
+    'register_permission_check_method' => true,
+
+    /*
+     * When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered
+     * this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated
+     * NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it.
+     */
+    'register_octane_reset_listener' => false,
+
+    /*
+     * Teams Feature.
+     * When set to true the package implements teams using the 'team_foreign_key'.
+     * If you want the migrations to register the 'team_foreign_key', you must
+     * set this to true before doing the migration.
+     * If you already did the migration then you must make a new migration to also
+     * add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions'
+     * (view the latest version of this package's migration file)
+     */
+
+    'teams' => false,
+
+    /*
+     * Passport Client Credentials Grant
+     * When set to true the package will use Passports Client to check permissions
+     */
+
+    'use_passport_client_credentials' => false,
+
+    /*
+     * When set to true, the required permission names are added to exception messages.
+     * This could be considered an information leak in some contexts, so the default
+     * setting is false here for optimum safety.
+     */
+
+    'display_permission_in_exception' => false,
+
+    /*
+     * When set to true, the required role names are added to exception messages.
+     * This could be considered an information leak in some contexts, so the default
+     * setting is false here for optimum safety.
+     */
+
+    'display_role_in_exception' => false,
+
+    /*
+     * By default wildcard permission lookups are disabled.
+     * See documentation to understand supported syntax.
+     */
+
+    'enable_wildcard_permission' => false,
+
+    /*
+     * The class to use for interpreting wildcard permissions.
+     * If you need to modify delimiters, override the class and specify its name here.
+     */
+    // 'permission.wildcard_permission' => Spatie\Permission\WildcardPermission::class,
+
+    /* Cache-specific settings */
+
+    'cache' => [
+
+        /*
+         * By default all permissions are cached for 24 hours to speed up performance.
+         * When permissions or roles are updated the cache is flushed automatically.
+         */
+
+        'expiration_time' => \DateInterval::createFromDateString('24 hours'),
+
+        /*
+         * The cache key used to store all permissions.
+         */
+
+        'key' => 'spatie.permission.cache',
+
+        /*
+         * You may optionally indicate a specific cache driver to use for permission and
+         * role caching using any of the `store` drivers listed in the cache.php config
+         * file. Using 'default' here means to use the `default` set in cache.php.
+         */
+
+        'store' => 'default',
+    ],
+];
diff --git a/application/database/migrations/2024_11_06_182434_create_permission_tables.php b/application/database/migrations/2024_11_06_182434_create_permission_tables.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c7044b46e1e838f5bf6cc9ae0ed41343c673c0d
--- /dev/null
+++ b/application/database/migrations/2024_11_06_182434_create_permission_tables.php
@@ -0,0 +1,140 @@
+<?php
+
+use Illuminate\Support\Facades\Schema;
+use Illuminate\Database\Schema\Blueprint;
+use Illuminate\Database\Migrations\Migration;
+
+return new class extends Migration
+{
+    /**
+     * Run the migrations.
+     */
+    public function up(): void
+    {
+        $teams = config('permission.teams');
+        $tableNames = config('permission.table_names');
+        $columnNames = config('permission.column_names');
+        $pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
+        $pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
+
+        if (empty($tableNames)) {
+            throw new \Exception('Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
+        }
+        if ($teams && empty($columnNames['team_foreign_key'] ?? null)) {
+            throw new \Exception('Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
+        }
+
+        Schema::create($tableNames['permissions'], function (Blueprint $table) {
+            //$table->engine('InnoDB');
+            $table->bigIncrements('id'); // permission id
+            $table->string('name');       // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
+            $table->string('guard_name'); // For MyISAM use string('guard_name', 25);
+            $table->timestamps();
+
+            $table->unique(['name', 'guard_name']);
+        });
+
+        Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) {
+            //$table->engine('InnoDB');
+            $table->bigIncrements('id'); // role id
+            if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
+                $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
+                $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
+            }
+            $table->string('name');       // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
+            $table->string('guard_name'); // For MyISAM use string('guard_name', 25);
+            $table->timestamps();
+            if ($teams || config('permission.testing')) {
+                $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
+            } else {
+                $table->unique(['name', 'guard_name']);
+            }
+        });
+
+        Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
+            $table->unsignedBigInteger($pivotPermission);
+
+            $table->string('model_type');
+            $table->unsignedBigInteger($columnNames['model_morph_key']);
+            $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
+
+            $table->foreign($pivotPermission)
+                ->references('id') // permission id
+                ->on($tableNames['permissions'])
+                ->onDelete('cascade');
+            if ($teams) {
+                $table->unsignedBigInteger($columnNames['team_foreign_key']);
+                $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
+
+                $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
+                    'model_has_permissions_permission_model_type_primary');
+            } else {
+                $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
+                    'model_has_permissions_permission_model_type_primary');
+            }
+
+        });
+
+        Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
+            $table->unsignedBigInteger($pivotRole);
+
+            $table->string('model_type');
+            $table->unsignedBigInteger($columnNames['model_morph_key']);
+            $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
+
+            $table->foreign($pivotRole)
+                ->references('id') // role id
+                ->on($tableNames['roles'])
+                ->onDelete('cascade');
+            if ($teams) {
+                $table->unsignedBigInteger($columnNames['team_foreign_key']);
+                $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
+
+                $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
+                    'model_has_roles_role_model_type_primary');
+            } else {
+                $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
+                    'model_has_roles_role_model_type_primary');
+            }
+        });
+
+        Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
+            $table->unsignedBigInteger($pivotPermission);
+            $table->unsignedBigInteger($pivotRole);
+
+            $table->foreign($pivotPermission)
+                ->references('id') // permission id
+                ->on($tableNames['permissions'])
+                ->onDelete('cascade');
+
+            $table->foreign($pivotRole)
+                ->references('id') // role id
+                ->on($tableNames['roles'])
+                ->onDelete('cascade');
+
+            $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
+        });
+
+        app('cache')
+            ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
+            ->forget(config('permission.cache.key'));
+    }
+
+    /**
+     * Reverse the migrations.
+     */
+    public function down(): void
+    {
+        $tableNames = config('permission.table_names');
+
+        if (empty($tableNames)) {
+            throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
+        }
+
+        Schema::drop($tableNames['role_has_permissions']);
+        Schema::drop($tableNames['model_has_roles']);
+        Schema::drop($tableNames['model_has_permissions']);
+        Schema::drop($tableNames['roles']);
+        Schema::drop($tableNames['permissions']);
+    }
+};
diff --git a/application/database/migrations/2024_11_07_042703_create_media_table.php b/application/database/migrations/2024_11_07_042703_create_media_table.php
new file mode 100644
index 0000000000000000000000000000000000000000..47a4be987d7bd92ad89a2ea2750baff2d6302010
--- /dev/null
+++ b/application/database/migrations/2024_11_07_042703_create_media_table.php
@@ -0,0 +1,32 @@
+<?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('media', function (Blueprint $table) {
+            $table->id();
+
+            $table->morphs('model');
+            $table->uuid()->nullable()->unique();
+            $table->string('collection_name');
+            $table->string('name');
+            $table->string('file_name');
+            $table->string('mime_type')->nullable();
+            $table->string('disk');
+            $table->string('conversions_disk')->nullable();
+            $table->unsignedBigInteger('size');
+            $table->json('manipulations');
+            $table->json('custom_properties');
+            $table->json('generated_conversions');
+            $table->json('responsive_images');
+            $table->unsignedInteger('order_column')->nullable()->index();
+
+            $table->nullableTimestamps();
+        });
+    }
+};
diff --git a/application/database/seeders/DatabaseSeeder.php b/application/database/seeders/DatabaseSeeder.php
index d158806bb7a6d44db3dbabdfea14ef26347258d0..7624e1b99ee6d8bd794f5f7e19bad2f377ea8837 100644
--- a/application/database/seeders/DatabaseSeeder.php
+++ b/application/database/seeders/DatabaseSeeder.php
@@ -1,5 +1,7 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Database\Seeders;
 
 use App\Models\User;
diff --git a/application/database/seeders/RoleSeeder.php b/application/database/seeders/RoleSeeder.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f0bde033bc1eb53013974533de856eeb322ad95
--- /dev/null
+++ b/application/database/seeders/RoleSeeder.php
@@ -0,0 +1,24 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Database\Seeders;
+
+use App\Enums\RoleEnum;
+use Illuminate\Database\Seeder;
+use Spatie\Permission\Models\Role;
+use Illuminate\Database\Console\Seeds\WithoutModelEvents;
+
+class RoleSeeder extends Seeder
+{
+    /**
+     * Run the database seeds.
+     */
+    public function run(): void
+    {
+        collect(array_keys(RoleEnum::toArray()))
+            ->each(
+                fn($role) => Role::findOrCreate($role)
+            );
+    }
+}
diff --git a/application/database/seeders/Traits/GetImageLink.php b/application/database/seeders/Traits/GetImageLink.php
new file mode 100644
index 0000000000000000000000000000000000000000..16d61ab482a03ac87d801f923418bd1da7b08721
--- /dev/null
+++ b/application/database/seeders/Traits/GetImageLink.php
@@ -0,0 +1,22 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Database\Seeders\Traits;
+
+trait GetImageLink
+{
+    /** @throws \Exception */
+    public function getRandomImageLink(int $width = 640, int $height = 480): null|string
+    {
+        $url = "https://picsum.photos/{$width}/{$height}";
+
+        $headers = get_headers($url, true);
+
+        if ($headers && isset($headers['Content-Type']) && str_contains($headers['Content-Type'], 'image')) {
+            return $url;
+        }
+
+        return null;
+    }
+}
diff --git a/application/database/seeders/UserSeeder.php b/application/database/seeders/UserSeeder.php
index a4dfc1e4b5cba4b3c29c06b299d8e50339c4cb29..56019031ae9e4ef4f212a4f076fe2416614de0a9 100644
--- a/application/database/seeders/UserSeeder.php
+++ b/application/database/seeders/UserSeeder.php
@@ -1,22 +1,39 @@
 <?php
 
+declare(strict_types=1);
+
 namespace Database\Seeders;
 
 use App\Models\User;
-use Illuminate\Database\Console\Seeds\WithoutModelEvents;
+use App\Enums\RoleEnum;
 use Illuminate\Database\Seeder;
+use Spatie\Permission\Models\Role;
+use Illuminate\Support\Facades\Hash;
+use Database\Seeders\Traits\GetImageLink;
+use Illuminate\Database\Console\Seeds\WithoutModelEvents;
 
 class UserSeeder extends Seeder
 {
+    use GetImageLink;
+
     /**
      * Run the database seeds.
      */
     public function run(): void
     {
-        User::factory()->count(10)->create(); 
-        User::factory()->create([
-            'name' => 'Test User',
-            'email' => 'test@example.com',
-        ]);
+        User::factory([
+            'name' => 'Explorer Dora',
+            'email' => 'admin@catalystexplorer.com',
+            'password' => Hash::make('ofnXIFbZ0JOuGBqx-'),
+        ])->hasAttached(Role::where('name', RoleEnum::super_admin())->first())
+            ->create();
+
+        User::factory(7)->create()->each(
+            function (User $user) {
+                if ($imageLink = $this->getRandomImageLink()) {
+                    $user->addMediaFromUrl($imageLink)->toMediaCollection('profile');
+                }
+            }
+        );
     }
 }
diff --git a/application/package.json b/application/package.json
index bb664be34c2f27738c1a3aa9666c1496d35facda..5463c99368299f50f8a82f9afde7b425346e9209 100644
--- a/application/package.json
+++ b/application/package.json
@@ -28,7 +28,7 @@
         "postcss": "^8.4.31",
         "prettier": "^3.3.0",
         "prettier-plugin-organize-imports": "^4.0.0",
-        "prettier-plugin-tailwindcss": "^0.6.5",
+        "prettier-plugin-tailwindcss": "^0.6.8",
         "react": "^18.2.0",
         "react-dom": "^18.2.0",
         "sass": "^1.80.5",
diff --git a/application/resources/js/Components/Dropdown.tsx b/application/resources/js/Components/Dropdown.tsx
index 105564220134826ee3f1908b102be84603cc97b0..29207040df8391c3f50d2db6811dc33cfaaf46de 100644
--- a/application/resources/js/Components/Dropdown.tsx
+++ b/application/resources/js/Components/Dropdown.tsx
@@ -53,7 +53,7 @@ const Trigger = ({ children }: PropsWithChildren) => {
 const Content = ({
     align = 'right',
     width = '48',
-    contentClasses = 'py-1 bg-white dark:bg-gray-700',
+    contentClasses = 'py-1 bg-background-primary',
     children,
 }: PropsWithChildren<{
     align?: 'left' | 'right';
@@ -114,7 +114,7 @@ const DropdownLink = ({
         <Link
             {...props}
             className={
-                'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:bg-gray-100 focus:outline-none dark:text-gray-300 dark:hover:bg-gray-800 dark:focus:bg-gray-800 ' +
+                'block w-full px-4 py-2 text-start text-sm leading-5 text-content-primary transition duration-150 ease-in-out hover:bg-background-secondary focus:outline-none  focus:bg-background-secondary ' +
                 className
             }
         >
diff --git a/application/resources/js/Components/InputLabel.tsx b/application/resources/js/Components/InputLabel.tsx
index c51c0161b80e2856fb0e34c4b7250ed74707ddc7..b83c1134c16f4dc70df2f6d358b52ba7ec7b0b16 100644
--- a/application/resources/js/Components/InputLabel.tsx
+++ b/application/resources/js/Components/InputLabel.tsx
@@ -10,8 +10,7 @@ export default function InputLabel({
         <label
             {...props}
             className={
-                `block text-sm font-medium text-gray-700 dark:text-gray-300 ` +
-                className
+                `block text-sm font-medium text-content-tertiary ` + className
             }
         >
             {value ? value : children}
diff --git a/application/resources/js/Components/NavLink.tsx b/application/resources/js/Components/NavLink.tsx
index a756359424e5ced2ba3877584aa8117e5dd7f0b1..e138dc96139d13aa8abe4d01502f503191ead988 100644
--- a/application/resources/js/Components/NavLink.tsx
+++ b/application/resources/js/Components/NavLink.tsx
@@ -10,10 +10,10 @@ export default function NavLink({
         <Link
             {...props}
             className={
-                'inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium leading-5 transition duration-150 ease-in-out focus:outline-none ' +
+                'inline-flex items-center border-b-2 px-1 pt-1 text-sm font-medium leading-5 text-content-primary transition duration-150 ease-in-out focus:outline-none ' +
                 (active
-                    ? 'border-indigo-400 text-gray-900 focus:border-indigo-700 dark:border-indigo-600 dark:text-gray-100'
-                    : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700 focus:border-gray-300 focus:text-gray-700 dark:text-gray-400 dark:hover:border-gray-700 dark:hover:text-gray-300 dark:focus:border-gray-700 dark:focus:text-gray-300') +
+                    ? 'border-gray-200 focus:border-indigo-700 dark:border-indigo-600'
+                    : 'border-transparent hover:border-gray-300 hover:text-gray-700 focus:border-gray-300 focus:text-gray-700 dark:text-gray-400 dark:hover:border-gray-700') +
                 className
             }
         >
diff --git a/application/resources/js/Components/PrimaryButton.tsx b/application/resources/js/Components/PrimaryButton.tsx
index 479897426191a02a55305c2f0dab2cb2d2d614e2..d6b57038e6807a3f9858564729e928dfe0d724e2 100644
--- a/application/resources/js/Components/PrimaryButton.tsx
+++ b/application/resources/js/Components/PrimaryButton.tsx
@@ -10,7 +10,7 @@ export default function PrimaryButton({
         <button
             {...props}
             className={
-                `inline-flex items-center rounded-md border border-transparent bg-gray-800 px-4 py-2 text-xs font-semibold uppercase tracking-widest text-white transition duration-150 ease-in-out hover:bg-gray-700 focus:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 active:bg-gray-900 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-white dark:focus:bg-white dark:focus:ring-offset-gray-800 dark:active:bg-gray-300 ${
+                `inline-flex items-center rounded-md border border-transparent bg-background-primary px-4 py-2 text-xs font-semibold uppercase tracking-widest text-white transition duration-150 ease-in-out hover:bg-gray-700 focus:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 active:bg-gray-900 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-white dark:focus:bg-white dark:focus:ring-offset-gray-800 dark:active:bg-gray-300 ${
                     disabled && 'opacity-25'
                 } ` + className
             }
diff --git a/application/resources/js/Components/SecondaryButton.tsx b/application/resources/js/Components/SecondaryButton.tsx
index 4ad249dd6a99fedbef20cdb687e30799061e8d59..d4f62d1b638be80587d84ed1950beae0438a9de1 100644
--- a/application/resources/js/Components/SecondaryButton.tsx
+++ b/application/resources/js/Components/SecondaryButton.tsx
@@ -12,7 +12,7 @@ export default function SecondaryButton({
             {...props}
             type={type}
             className={
-                `inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-xs font-semibold uppercase tracking-widest text-gray-700 shadow-sm transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 dark:border-gray-500 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 dark:focus:ring-offset-gray-800 ${
+                `inline-flex items-center rounded-md border border-gray-300 bg-background-secondary px-4 py-2 text-xs font-semibold uppercase tracking-widest text-gray-700 shadow-sm transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25 dark:border-gray-500 dark:bg-gray-800 dark:text-gray-300 dark:hover:bg-gray-700 dark:focus:ring-offset-gray-800 ${
                     disabled && 'opacity-25'
                 } ` + className
             }
diff --git a/application/resources/js/Components/TextInput.tsx b/application/resources/js/Components/TextInput.tsx
index 2dd01037eb58278076e979d87a430fef6afcd357..93ede93727e24f4561e8130b76fabf2705681a9e 100644
--- a/application/resources/js/Components/TextInput.tsx
+++ b/application/resources/js/Components/TextInput.tsx
@@ -32,7 +32,7 @@ export default forwardRef(function TextInput(
             {...props}
             type={type}
             className={
-                'rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:focus:border-indigo-600 dark:focus:ring-indigo-600 ' +
+                'bg-primary rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 dark:border-gray-700 dark:text-gray-300 dark:focus:border-indigo-600 dark:focus:ring-indigo-600 ' +
                 className
             }
             ref={localRef}
diff --git a/application/resources/js/Components/layout/DesktopSidebar.tsx b/application/resources/js/Components/layout/DesktopSidebar.tsx
index 8f8628178cdabe864137b1f93f63466037c9fe94..4be3702a82c5bc6bc1fc4a049d0a28498097ed8c 100644
--- a/application/resources/js/Components/layout/DesktopSidebar.tsx
+++ b/application/resources/js/Components/layout/DesktopSidebar.tsx
@@ -5,6 +5,7 @@ import AppNavigation from './AppNavigation';
 import ThemeSwitcher from './ThemeSwitcher';
 import UserDetails from './UserDetails';
 import UserNavigation from './UserNavigation';
+import User = App.DataTransferObjects.UserData;
 
 
 function DesktopSidebar() {
@@ -25,7 +26,7 @@ function DesktopSidebar() {
             <section className="flex flex-col gap-6 px-4 pb-8">
                 <ThemeSwitcher />
                 <UserNavigation />
-                <UserDetails name={auth?.user?.name} email={auth?.user?.email} avatar={auth?.avatar}/>
+                <UserDetails user={auth?.user as User} />
             </section>
         </aside>
     );
diff --git a/application/resources/js/Components/layout/MobileNavigation.tsx b/application/resources/js/Components/layout/MobileNavigation.tsx
index 5b61bb6766d7907b7fcab37058da47d48f4b87fc..42e69b9f9e0f164343d7b509104f074ca5c0fdfe 100644
--- a/application/resources/js/Components/layout/MobileNavigation.tsx
+++ b/application/resources/js/Components/layout/MobileNavigation.tsx
@@ -5,6 +5,7 @@ import ThemeSwitcher from './ThemeSwitcher';
 import UserDetails from './UserDetails';
 import UserNavigation from './UserNavigation';
 import { usePage } from '@inertiajs/react';
+import User = App.DataTransferObjects.UserData;
 
 function MobileNavigation() {
     const { t } = useTranslation();
@@ -26,7 +27,7 @@ function MobileNavigation() {
                     <section className="flex flex-col gap-6 px-4 pb-8">
                         <ThemeSwitcher />
                         <UserNavigation />
-                        <UserDetails name={auth?.user?.name} email={auth?.user?.email} avatar={auth?.avatar}/>
+                        <UserDetails user={auth.user as User} />
                     </section>
                 </aside>
             </DialogPanel>
diff --git a/application/resources/js/Components/layout/UserDetails.tsx b/application/resources/js/Components/layout/UserDetails.tsx
index 32009b98b4b78d3e61605f9862708ecde7b08cc9..904bcf25aea471fbb4ed9d19f90be50a1c5a29cf 100644
--- a/application/resources/js/Components/layout/UserDetails.tsx
+++ b/application/resources/js/Components/layout/UserDetails.tsx
@@ -1,59 +1,79 @@
-import { useTranslation } from 'react-i18next';
-import LogOutIcon from '../svgs/LogOut';
 import { Link } from '@inertiajs/react';
 import axios from 'axios';
+import { useTranslation } from 'react-i18next';
 import { route } from '../../../../vendor/tightenco/ziggy/src/js';
+import LogOutIcon from '../svgs/LogOut';
+import User = App.DataTransferObjects.UserData;
 
 
-export interface UserDetailsProps {
-    name: string,
-    email: string,
-    avatar: string
+interface UserDetailsProps {
+    user: App.DataTransferObjects.UserData; 
 }
 
-const UserDetails: React.FC<UserDetailsProps> = ({ name, email, avatar }) => {
+const UserDetails: React.FC<UserDetailsProps> = ({user}) => {
     const { t } = useTranslation();
 
     const logout = () => {
-        axios.post(route('logout')).then((response) => {
-            console.log(response)
-            window.location.href = '/'
-        }).catch((error) => {
-            console.log(error)
-        })
-    }
+        axios
+            .post(route('logout'))
+            .then((response) => {
+                console.log(response);
+                window.location.href = '/';
+            })
+            .catch((error) => {
+                console.log(error);
+            });
+    };
 
     return (
         <div className="flex items-center justify-between border-t border-gray-200 pt-6">
             <div className="flex gap-3">
-                <div className="h-9 w-9 rounded-full bg-gray-400">
-                    {name && email ? <img src={avatar} alt='avatar' /> : ''}
+                <div className="size-9 rounded-full bg-gray-400">
+                    {user?.name && user?.email ? (
+                        <img
+                            src={user.profile_photo_url}
+                            alt="avatar"
+                            className="size-9 rounded-full"
+                        />
+                    ) : (
+                        ''
+                    )}
                 </div>
                 <div className="flex flex-col">
-                    {name && email ? (
-                        <Link href='/dashboard' className="text-sm font-semibold text-content-primary">
-                            {name}
+                    {user?.name && user?.email ? (
+                        <Link
+                            href="/dashboard"
+                            className="text-sm font-semibold text-content-primary"
+                        >
+                            {user?.name}
                         </Link>
-                    ) : <p className="text-sm font-semibold text-content-primary">{t('app.name')}</p>}
+                    ) : (
+                        <p className="text-sm font-semibold text-content-primary">
+                            {t('app.name')}
+                        </p>
+                    )}
 
                     <p className="text-xs text-content-primary">
-                        {email || t('app.contactEmail')}
+                        {user?.email || t('app.contactEmail')}
                     </p>
-                    {name && email && (
-                        <Link href='/profile' className="text-xs font-semibold text-primary-100">
+                    {user?.name && user?.email && (
+                        <Link
+                            href="/profile"
+                            className="text-xs font-semibold text-primary-100"
+                        >
                             Edit profile
                         </Link>
                     )}
                 </div>
             </div>
             <LogOutIcon
-                className="text-content-tertiary cursor-pointer"
+                className="cursor-pointer text-content-tertiary"
                 width={20}
                 height={20}
-                onClick={()=>logout()}
+                onClick={() => logout()}
             />
         </div>
     );
-}
+};
 
 export default UserDetails;
diff --git a/application/resources/js/Layouts/AuthenticatedLayout.tsx b/application/resources/js/Layouts/AuthenticatedLayout.tsx
index cb449b2a918929e479b313fda9b0d7b09834cfc9..7ada531add19e56593e8d693fc6db98a2e1c20d8 100644
--- a/application/resources/js/Layouts/AuthenticatedLayout.tsx
+++ b/application/resources/js/Layouts/AuthenticatedLayout.tsx
@@ -15,14 +15,14 @@ export default function Authenticated({
         useState(false);
 
     return (
-        <div className="min-h-screen bg-gray-100 dark:bg-gray-900">
-            <nav className="border-b border-gray-100 bg-white dark:border-gray-700 dark:bg-gray-800">
+        <div className="bg-gray-primary min-h-screen">
+            <nav className="border-b border-gray-100 bg-background-primary">
                 <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
                     <div className="flex h-16 justify-between">
                         <div className="flex">
                             <div className="flex shrink-0 items-center">
                                 <Link href="/">
-                                    <ApplicationLogo className="block h-9 w-auto fill-current text-gray-800 dark:text-gray-200" />
+                                    <ApplicationLogo className="block h-9 w-auto fill-current text-content-primary" />
                                 </Link>
                             </div>
 
@@ -43,7 +43,7 @@ export default function Authenticated({
                                         <span className="inline-flex rounded-md">
                                             <button
                                                 type="button"
-                                                className="inline-flex items-center rounded-md border border-transparent bg-white px-3 py-2 text-sm font-medium leading-4 text-gray-500 transition duration-150 ease-in-out hover:text-gray-700 focus:outline-none dark:bg-gray-800 dark:text-gray-400 dark:hover:text-gray-300"
+                                                className="false inline-flex items-center rounded-md border border-transparent bg-background-secondary px-4 py-2 text-xs font-semibold uppercase tracking-widest text-white transition duration-150 ease-in-out hover:bg-gray-700 focus:bg-gray-700 focus:outline-none  focus:ring-offset-2 active:bg-gray-900 dark:bg-gray-200 dark:text-gray-800 dark:hover:bg-white dark:focus:bg-white dark:focus:ring-offset-gray-800 dark:active:bg-gray-300"
                                             >
                                                 {user.name}
 
@@ -139,9 +139,9 @@ export default function Authenticated({
                         </ResponsiveNavLink>
                     </div>
 
-                    <div className="border-t border-gray-200 pb-1 pt-4 dark:border-gray-600">
+                    <div className="border-t border-gray-200 pb-1 pt-4">
                         <div className="px-4">
-                            <div className="text-base font-medium text-gray-800 dark:text-gray-200">
+                            <div className="text-base font-medium text-gray-800">
                                 {user.name}
                             </div>
                             <div className="text-sm font-medium text-gray-500">
@@ -166,7 +166,7 @@ export default function Authenticated({
             </nav>
 
             {header && (
-                <header className="bg-white shadow dark:bg-gray-800">
+                <header className="bg-background-primary shadow">
                     <div className="mx-auto max-w-7xl px-4 py-6 sm:px-6 lg:px-8">
                         {header}
                     </div>
diff --git a/application/resources/js/Pages/Dashboard.tsx b/application/resources/js/Pages/Profile/Dashboard.tsx
similarity index 75%
rename from application/resources/js/Pages/Dashboard.tsx
rename to application/resources/js/Pages/Profile/Dashboard.tsx
index 5ff157f8ff0437e3ed145af282d7a759a7dac4cc..909028b9feb4af8e269fc240c1f61d4137af0440 100644
--- a/application/resources/js/Pages/Dashboard.tsx
+++ b/application/resources/js/Pages/Profile/Dashboard.tsx
@@ -5,7 +5,7 @@ export default function Dashboard() {
     return (
         <AuthenticatedLayout
             header={
-                <h2 className="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
+                <h2 className="text-xl font-semibold leading-tight text-content-primary">
                     Dashboard
                 </h2>
             }
@@ -14,8 +14,8 @@ export default function Dashboard() {
 
             <div className="py-12">
                 <div className="mx-auto max-w-7xl sm:px-6 lg:px-8">
-                    <div className="overflow-hidden bg-white shadow-sm sm:rounded-lg dark:bg-[#112A3B]">
-                        <div className="p-6 text-gray-900 dark:text-gray-100">
+                    <div className="overflow-hidden bg-background-primary shadow-sm sm:rounded-lg">
+                        <div className="p-6 text-content-primary">
                             You're logged in!
                         </div>
                     </div>
diff --git a/application/resources/js/Pages/Profile/Edit.tsx b/application/resources/js/Pages/Profile/Edit.tsx
index eeda6110f74e2bdf5e12ea4c3b308a75217d9db6..6bc4b1dfce4eba7f378c8ef714314b689d9c26e0 100644
--- a/application/resources/js/Pages/Profile/Edit.tsx
+++ b/application/resources/js/Pages/Profile/Edit.tsx
@@ -12,7 +12,7 @@ export default function Edit({
     return (
         <AuthenticatedLayout
             header={
-                <h2 className="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
+                <h2 className="text-xl font-semibold leading-tight text-content-primary">
                     Profile
                 </h2>
             }
@@ -21,7 +21,7 @@ export default function Edit({
 
             <div className="py-12">
                 <div className="mx-auto max-w-7xl space-y-6 sm:px-6 lg:px-8">
-                    <div className="bg-white p-4 shadow sm:rounded-lg sm:p-8 dark:bg-gray-800">
+                    <div className="bg-background-primary p-4 shadow sm:rounded-lg sm:p-8">
                         <UpdateProfileInformationForm
                             mustVerifyEmail={mustVerifyEmail}
                             status={status}
@@ -29,11 +29,11 @@ export default function Edit({
                         />
                     </div>
 
-                    <div className="bg-white p-4 shadow sm:rounded-lg sm:p-8 dark:bg-gray-800">
+                    <div className="bg-background-primary p-4 shadow sm:rounded-lg sm:p-8">
                         <UpdatePasswordForm className="max-w-xl" />
                     </div>
 
-                    <div className="bg-white p-4 shadow sm:rounded-lg sm:p-8 dark:bg-gray-800">
+                    <div className="bg-background-primary p-4 shadow sm:rounded-lg sm:p-8">
                         <DeleteUserForm className="max-w-xl" />
                     </div>
                 </div>
diff --git a/application/resources/js/Pages/Profile/Partials/DeleteUserForm.tsx b/application/resources/js/Pages/Profile/Partials/DeleteUserForm.tsx
index 33ab4c95f7e8594a6daba6a946eba954274d604a..540150b1870beeee439e50a5ffea32c463cd6004 100644
--- a/application/resources/js/Pages/Profile/Partials/DeleteUserForm.tsx
+++ b/application/resources/js/Pages/Profile/Partials/DeleteUserForm.tsx
@@ -52,11 +52,11 @@ export default function DeleteUserForm({
     return (
         <section className={`space-y-6 ${className}`}>
             <header>
-                <h2 className="text-lg font-medium text-gray-900 dark:text-gray-100">
+                <h2 className="text-lg font-medium text-content-primary">
                     Delete Account
                 </h2>
 
-                <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
+                <p className="mt-1 text-sm text-content-primary">
                     Once your account is deleted, all of its resources and data
                     will be permanently deleted. Before deleting your account,
                     please download any data or information that you wish to
diff --git a/application/resources/js/Pages/Profile/Partials/UpdatePasswordForm.tsx b/application/resources/js/Pages/Profile/Partials/UpdatePasswordForm.tsx
index 585c2ff69339cdcb1b7f9300dd0d310ba0c4d097..8172781f889f5b3c5df2c6706629dd7bd539825e 100644
--- a/application/resources/js/Pages/Profile/Partials/UpdatePasswordForm.tsx
+++ b/application/resources/js/Pages/Profile/Partials/UpdatePasswordForm.tsx
@@ -51,11 +51,11 @@ export default function UpdatePasswordForm({
     return (
         <section className={className}>
             <header>
-                <h2 className="text-lg font-medium text-gray-900 dark:text-gray-100">
+                <h2 className="text-lg font-medium text-content-primary">
                     Update Password
                 </h2>
 
-                <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
+                <p className="mt-1 text-sm text-content-primary">
                     Ensure your account is using a long, random password to stay
                     secure.
                 </p>
diff --git a/application/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.tsx b/application/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.tsx
index ea1751fb3f57f086ad5c5b8e907e823434fc3aba..9f71db3d55da9ffec930448bbffe031c13aef941 100644
--- a/application/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.tsx
+++ b/application/resources/js/Pages/Profile/Partials/UpdateProfileInformationForm.tsx
@@ -32,11 +32,11 @@ export default function UpdateProfileInformation({
     return (
         <section className={className}>
             <header>
-                <h2 className="text-lg font-medium text-gray-900 dark:text-gray-100">
+                <h2 className="text-lg font-medium text-content-primary">
                     Profile Information
                 </h2>
 
-                <p className="mt-1 text-sm text-gray-600 dark:text-gray-400">
+                <p className="mt-1 text-sm text-content-primary">
                     Update your account's profile information and email address.
                 </p>
             </header>
@@ -76,13 +76,13 @@ export default function UpdateProfileInformation({
 
                 {mustVerifyEmail && user.email_verified_at === null && (
                     <div>
-                        <p className="mt-2 text-sm text-gray-800 dark:text-gray-200">
+                        <p className="mt-2 text-sm text-content-primary">
                             Your email address is unverified.
                             <Link
                                 href={route('verification.send')}
                                 method="post"
                                 as="button"
-                                className="rounded-md text-sm text-gray-600 underline hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:text-gray-400 dark:hover:text-gray-100 dark:focus:ring-offset-gray-800"
+                                className="rounded-md text-sm text-content-primary underline hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 dark:text-gray-400 dark:hover:text-gray-100 dark:focus:ring-offset-gray-800"
                             >
                                 Click here to re-send the verification email.
                             </Link>
diff --git a/application/resources/js/app.tsx b/application/resources/js/app.tsx
index c96ed67e4e94f016485ac28415b4e30ec180903e..6c70f0dd798767cb9b2202805a4ed5cd85b967c2 100644
--- a/application/resources/js/app.tsx
+++ b/application/resources/js/app.tsx
@@ -1,9 +1,10 @@
 import '../scss/app.scss';
 import './bootstrap';
-import './utils/i18n'
+import './utils/i18n';
 
 import { createInertiaApp } from '@inertiajs/react';
 import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
+import { StrictMode } from 'react';
 import { createRoot } from 'react-dom/client';
 import AppLayout from './Layouts/AppLayout';
 
@@ -14,17 +15,23 @@ createInertiaApp({
     resolve: (name) => {
         const page = resolvePageComponent(
             `./Pages/${name}.tsx`,
-            import.meta.glob("./Pages/**/*.tsx")
+            import.meta.glob('./Pages/**/*.tsx'),
         );
         page.then((module: any) => {
-            module.default.layout = module.default.layout || ((module: any) => <AppLayout children={module}/>);
+            module.default.layout =
+                module.default.layout ||
+                ((module: any) => <AppLayout children={module} />);
         });
         return page;
     },
-    setup({el, App, props}) {
+    setup({ el, App, props }) {
         const root = createRoot(el);
 
-        root.render(<App {...props} />);
+        root.render(
+            <StrictMode>
+                <App {...props} />
+            </StrictMode>,
+        );
     },
     progress: {
         color: '#4B5563',
diff --git a/application/resources/js/types/index.d.ts b/application/resources/js/types/index.d.ts
index aa704cba0f5664802ded79812e9f4aa17cdd18f9..ef849bce4ff569e7de02bcf9341f8823bde328ad 100644
--- a/application/resources/js/types/index.d.ts
+++ b/application/resources/js/types/index.d.ts
@@ -10,6 +10,5 @@ export type PageProps<
 > = T & {
     auth: {
         user: User;
-        avatar: string;
     };
 };
diff --git a/application/resources/types/generated.d.ts b/application/resources/types/generated.d.ts
index 03e10d9c72c6e19f5b1ecb86f6506df590487b21..9ffa96fc5c21701ae49cee0ae88516ffea34eef5 100644
--- a/application/resources/types/generated.d.ts
+++ b/application/resources/types/generated.d.ts
@@ -36,4 +36,11 @@ ranking_total?: number;
 quickpitch?: string;
 quickpitch_length?: number;
 };
+export type UserData = {
+id: number;
+name: string;
+email: string;
+profile_photo_url: string;
+email_verified_at: string;
+};
 }
diff --git a/application/routes/auth.php b/application/routes/auth.php
index aa8292106cb7c24decc91857201737ed650ea7e5..0b9fbf95da08cbed73a93870dc3f9278c1026997 100644
--- a/application/routes/auth.php
+++ b/application/routes/auth.php
@@ -1,16 +1,17 @@
 <?php
 
-use App\Http\Controllers\Auth\AuthenticatedSessionController;
-use App\Http\Controllers\Auth\ConfirmablePasswordController;
-use App\Http\Controllers\Auth\EmailVerificationNotificationController;
-use App\Http\Controllers\Auth\EmailVerificationPromptController;
-use App\Http\Controllers\Auth\NewPasswordController;
+use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\ProfileController;
 use App\Http\Controllers\Auth\PasswordController;
-use App\Http\Controllers\Auth\PasswordResetLinkController;
-use App\Http\Controllers\Auth\RegisteredUserController;
+use App\Http\Controllers\Auth\NewPasswordController;
 use App\Http\Controllers\Auth\VerifyEmailController;
-use App\Http\Controllers\ProfileController;
-use Illuminate\Support\Facades\Route;
+use App\Http\Controllers\Auth\RegisteredUserController;
+use App\Http\Controllers\Auth\PasswordResetLinkController;
+use App\Http\Controllers\Auth\ConfirmablePasswordController;
+use App\Http\Controllers\Auth\AuthenticatedSessionController;
+use App\Http\Controllers\Auth\EmailVerificationPromptController;
+use App\Http\Controllers\Auth\EmailVerificationNotificationController;
+
 
 Route::middleware('auth')->group(function () {
     Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
diff --git a/application/routes/dashboard.php b/application/routes/dashboard.php
index 55d80fe389452bf8b5f32ae903364608242a0aba..1a92bd999397bfd7de6582702d8fe1ad60bd318f 100644
--- a/application/routes/dashboard.php
+++ b/application/routes/dashboard.php
@@ -4,6 +4,6 @@
 use Inertia\Inertia;
 
 Route::get('/dashboard', function () {
-    return Inertia::render('Dashboard');
+    return Inertia::render('Profile/Dashboard');
 })->middleware(['auth', 'verified'])
     ->name('dashboard');
diff --git a/application/storage/app/.gitignore b/application/storage/app/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/app/private/.gitignore b/application/storage/app/private/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/app/public/.gitignore b/application/storage/app/public/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/framework/.gitignore b/application/storage/framework/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/framework/cache/.gitignore b/application/storage/framework/cache/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/framework/cache/data/.gitignore b/application/storage/framework/cache/data/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/framework/sessions/.gitignore b/application/storage/framework/sessions/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/framework/testing/.gitignore b/application/storage/framework/testing/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/framework/views/.gitignore b/application/storage/framework/views/.gitignore
old mode 100644
new mode 100755
diff --git a/application/storage/logs/.gitignore b/application/storage/logs/.gitignore
old mode 100644
new mode 100755
diff --git a/application/tsconfig.json b/application/tsconfig.json
index 37071140a8b87ebd9e4a4bc85df5867fcfd0b956..83b904b36eeda19d4ec2352cdc4d03ac93e62a5f 100644
--- a/application/tsconfig.json
+++ b/application/tsconfig.json
@@ -12,9 +12,23 @@
         "skipLibCheck": true,
         "noEmit": true,
         "paths": {
-            "@/*": ["./resources/js/*"],
-            "ziggy-js": ["./vendor/tightenco/ziggy"]
-        }
+            "@/*": [
+                "./resources/js/*"
+            ],
+            "ziggy-js": [
+                "./vendor/tightenco/ziggy"
+            ]
+        },
+        "typeRoots": [
+            "./node_modules/@types",
+            "resources/js/types",
+            "resources/types"
+        ],
     },
-    "include": ["resources/js/**/*.ts", "resources/js/**/*.tsx", "resources/js/**/*.d.ts"]
-}
+    "include": [
+        "resources/js/**/*.ts",
+        "resources/js/**/*.tsx",
+        "resources/js/**/*.d.ts",
+        "resources/types/*.d.ts"
+    ]
+}
\ No newline at end of file
diff --git a/application/yarn.lock b/application/yarn.lock
index ec29045a4f6a9270b0a722fdaea23b9156ea262f..cb5c88164cc9ea6b76cc03552f020d6eeb0d43e7 100644
--- a/application/yarn.lock
+++ b/application/yarn.lock
@@ -2656,7 +2656,7 @@ prettier-plugin-organize-imports@^4.0.0:
   resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz#f3d3764046a8e7ba6491431158b9be6ffd83b90f"
   integrity sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==
 
-prettier-plugin-tailwindcss@^0.6.5:
+prettier-plugin-tailwindcss@^0.6.8:
   version "0.6.8"
   resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.8.tgz#8a178e1679e3f941cc9de396f109c6cffea676d8"
   integrity sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==
diff --git a/docker/Dockerfile.base b/docker/Dockerfile.base
index 01d3ff5e77ca66cf226970c8b8d7e1583dd9d6ee..e053ff4d22e405c3dbafe7fab6b85eb761f37b13 100644
--- a/docker/Dockerfile.base
+++ b/docker/Dockerfile.base
@@ -6,6 +6,8 @@ ARG WWWGROUP
 ARG NODE_VERSION=20
 ARG MYSQL_CLIENT="mysql-client"
 ARG POSTGRES_VERSION=15
+ARG FRANKENPHP_VERSION=1.2.5
+ARG FRANKENPHP_ARCH=linux-aarch64
 
 WORKDIR /var/www/html
 
@@ -54,9 +56,12 @@ RUN apt-get update && apt-get upgrade -y \
     && apt-get -y autoremove \
     && apt-get clean \
     && apt-get install -y netcat  \
-    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
-
-
+    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
+    && curl -L# "https://github.com/dunglas/frankenphp/releases/download/v${FRANKENPHP_VERSION}/frankenphp-${FRANKENPHP_ARCH}" -o /var/wwwfrankenphp \
+    && chmod +x /var/wwwfrankenphp \
+    && apt-get install jpegoptim optipng pngquant gifsicle libavif-bin\
+    && npm install -g svgo
+    
 
 RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.3
 
diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev
index 31f87073b8822cd2041385010cb87b5ce7e87ffe..115d5212a2d7d7bfc8bfbc31e1b96946a1c1d4e9 100644
--- a/docker/Dockerfile.dev
+++ b/docker/Dockerfile.dev
@@ -6,6 +6,8 @@ ARG WWWGROUP
 ARG NODE_VERSION=20
 ARG MYSQL_CLIENT="mysql-client"
 ARG POSTGRES_VERSION=15
+ARG FRANKENPHP_VERSION=1.2.5
+ARG FRANKENPHP_ARCH=linux-aarch64
 
 WORKDIR /var/www/html
 
@@ -22,7 +24,7 @@ RUN echo "Acquire::http::Pipeline-Depth 0;" > /etc/apt/apt.conf.d/99custom && \
 
 RUN apt-get update && apt-get upgrade -y \
     && mkdir -p /etc/apt/keyrings \
-    && apt-get install -y gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils librsvg2-bin fswatch ffmpeg nano  \
+    && apt-get install -y jpegoptim optipng pngquant gifsicle libavif-bin gnupg gosu curl ca-certificates zip unzip git supervisor sqlite3 libcap2-bin libpng-dev python2 dnsutils librsvg2-bin fswatch ffmpeg nano  \
     && curl -sS 'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x14aa40ec0831756756d7f66c4f4ea0aae5267a6c' | gpg --dearmor | tee /etc/apt/keyrings/ppa_ondrej_php.gpg > /dev/null \
     && echo "deb [signed-by=/etc/apt/keyrings/ppa_ondrej_php.gpg] https://ppa.launchpadcontent.net/ondrej/php/ubuntu jammy main" > /etc/apt/sources.list.d/ppa_ondrej_php.list \
     && apt-get update \
@@ -43,6 +45,7 @@ RUN apt-get update && apt-get upgrade -y \
     && npm install -g npm \
     && npm install -g pnpm \
     && npm install -g bun \
+    && npm install -g svgo \
     && curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | tee /etc/apt/keyrings/yarn.gpg >/dev/null \
     && echo "deb [signed-by=/etc/apt/keyrings/yarn.gpg] https://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list \
     && curl -sS https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/keyrings/pgdg.gpg >/dev/null \
@@ -53,7 +56,9 @@ RUN apt-get update && apt-get upgrade -y \
     && apt-get install -y postgresql-client-$POSTGRES_VERSION \
     && apt-get -y autoremove \
     && apt-get clean \
-    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 
+
+
 
 RUN setcap "cap_net_bind_service=+ep" /usr/bin/php8.3
 
@@ -70,4 +75,5 @@ EXPOSE 8000
 
 WORKDIR /var/www
 
+
 ENTRYPOINT ["start-container"]