Repository: djaiss/peopleOS
Pull request #161: feat: manage templates
Author: login: djaiss
Created: 2025-03-28T20:46:30Z | Merged: 2025-03-28T21:35:13Z

@coderabbitai summary


Diff:
diff --git a/app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php b/app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
new file mode 100644
index 00000000..69acda58
--- /dev/null
+++ b/app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
@@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Http\Controllers\Administration;
+
+use App\Http\Controllers\Controller;
+use App\Models\JournalTemplate;
+use App\Services\CreateJournalTemplate;
+use App\Services\DestroyJournalTemplate;
+use App\Services\UpdateJournalTemplate;
+use Exception;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
+
+class AdministrationPersonalizationJournalTemplateController extends Controller
+{
+    public function new(): View
+    {
+        return view('administration.personalization.journal-template-add');
+    }
+
+    public function create(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        try {
+            (new CreateJournalTemplate(
+                user: Auth::user(),
+                name: $validated['name'],
+                content: $validated['content'],
+            ))->execute();
+        } catch (Exception $e) {
+            return redirect()->route('administration.personalization.journal-templates.new')
+                ->withInput()
+                ->withErrors(['content' => $e->getMessage()]);
+        }
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template created successfully'));
+    }
+
+    public function edit(Request $request): View
+    {
+        $journalTemplateId = (int) $request->route()->parameter('journalTemplate');
+
+        $journalTemplate = JournalTemplate::findOrFail($journalTemplateId);
+
+        if ($journalTemplate->account_id !== Auth::user()->account_id) {
+            abort(404);
+        }
+
+        return view('administration.personalization.journal-template-edit', [
+            'journalTemplate' => $journalTemplate,
+        ]);
+    }
+
+    public function update(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
+
+        (new UpdateJournalTemplate(
+            user: Auth::user(),
+            journalTemplate: $journalTemplate,
+            name: $validated['name'],
+            content: $validated['content'],
+        ))->execute();
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template updated successfully'));
+    }
+
+    public function destroy(Request $request): RedirectResponse
+    {
+        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
+
+        (new DestroyJournalTemplate(
+            user: Auth::user(),
+            journalTemplate: $journalTemplate,
+        ))->execute();
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template deleted successfully'));
+    }
+}
diff --git a/app/Services/CreateJournalTemplate.php b/app/Services/CreateJournalTemplate.php
index 0104f311..9247ace7 100644
--- a/app/Services/CreateJournalTemplate.php
+++ b/app/Services/CreateJournalTemplate.php
@@ -8,6 +8,7 @@
 use App\Jobs\UpdateUserLastActivityDate;
 use App\Models\JournalTemplate;
 use App\Models\User;
+use Exception;
 
 class CreateJournalTemplate
 {
@@ -21,6 +22,7 @@ public function __construct(
 
     public function execute(): JournalTemplate
     {
+        $this->validate();
         $this->create();
         $this->updateUserLastActivityDate();
         $this->logUserAction();
@@ -28,6 +30,15 @@ public function execute(): JournalTemplate
         return $this->journalTemplate;
     }
 
+    private function validate(): void
+    {
+        $validation = (new ValidateYamlStructure($this->content))->execute();
+
+        if (! $validation['valid']) {
+            throw new Exception($validation['error']);
+        }
+    }
+
     private function create(): void
     {
         $this->journalTemplate = JournalTemplate::create([
diff --git a/app/Services/UpdateJournalTemplate.php b/app/Services/UpdateJournalTemplate.php
index f0493511..eb9bb1e1 100644
--- a/app/Services/UpdateJournalTemplate.php
+++ b/app/Services/UpdateJournalTemplate.php
@@ -34,6 +34,8 @@ private function validate(): void
         if ($this->user->account_id !== $this->journalTemplate->account_id) {
             throw new ModelNotFoundException();
         }
+
+        (new ValidateYamlStructure($this->content))->execute();
     }
 
     private function update(): void
diff --git a/app/Services/ValidateYamlStructure.php b/app/Services/ValidateYamlStructure.php
index 35fa7583..7501f958 100644
--- a/app/Services/ValidateYamlStructure.php
+++ b/app/Services/ValidateYamlStructure.php
@@ -13,10 +13,14 @@ class ValidateYamlStructure
 
     private const int MAX_COLUMNS = 3;
 
-    public function execute(string $yamlContent): array
+    public function __construct(
+        private readonly string $yamlContent,
+    ) {}
+
+    public function execute(): array
     {
         try {
-            $data = Yaml::parse($yamlContent);
+            $data = Yaml::parse($this->yamlContent);
         } catch (ParseException) {
             return ['valid' => false, 'error' => 'Invalid YAML format'];
         }
diff --git a/config/marketing-timestamps.php b/config/marketing-timestamps.php
index 023970bb..a4a0c252 100644
--- a/config/marketing-timestamps.php
+++ b/config/marketing-timestamps.php
@@ -36,22 +36,22 @@
         'marketing.docs.api.introduction' => '2025-03-08T15:31:01-05:00',
         'marketing/docs/api/logs' => '2025-03-07T21:10:04-05:00',
         'marketing.docs.api.logs' => '2025-03-07T21:10:04-05:00',
-        'marketing/docs/api/partials/task-response' => '2025-03-21T19:56:41+00:00',
-        'marketing.docs.api.partials.task-response' => '2025-03-21T19:56:41+00:00',
+        'marketing/docs/api/partials/task-response' => '2025-03-21T19:56:41Z',
+        'marketing.docs.api.partials.task-response' => '2025-03-21T19:56:41Z',
         'marketing/docs/api/profile' => '2025-03-13T21:21:04-04:00',
         'marketing.docs.api.profile' => '2025-03-13T21:21:04-04:00',
-        'marketing/docs/api/task-categories' => '2025-03-21T19:56:41+00:00',
-        'marketing.docs.api.task-categories' => '2025-03-21T19:56:41+00:00',
-        'marketing/docs/api/tasks' => '2025-03-21T19:56:41+00:00',
-        'marketing.docs.api.tasks' => '2025-03-21T19:56:41+00:00',
+        'marketing/docs/api/task-categories' => '2025-03-21T19:56:41Z',
+        'marketing.docs.api.task-categories' => '2025-03-21T19:56:41Z',
+        'marketing/docs/api/tasks' => '2025-03-21T19:56:41Z',
+        'marketing.docs.api.tasks' => '2025-03-21T19:56:41Z',
         'marketing/docs/index' => '2025-03-04T09:10:33-05:00',
         'marketing.docs.index' => '2025-03-04T09:10:33-05:00',
         'marketing/index' => '2025-03-16T17:31:20-04:00',
         'marketing.index' => '2025-03-16T17:31:20-04:00',
         'marketing/partials/footer' => '2025-03-16T15:33:55-04:00',
         'marketing.partials.footer' => '2025-03-16T15:33:55-04:00',
-        'marketing/partials/header' => '2025-03-23T17:57:15+00:00',
-        'marketing.partials.header' => '2025-03-23T17:57:15+00:00',
+        'marketing/partials/header' => '2025-03-23T17:57:15Z',
+        'marketing.partials.header' => '2025-03-23T17:57:15Z',
         'marketing/pricing/index' => '2025-03-16T17:31:20-04:00',
         'marketing.pricing.index' => '2025-03-16T17:31:20-04:00',
         'marketing/why/index' => '2025-03-10T20:51:59-04:00',
diff --git a/resources/views/administration/personalization/journal-template-add.blade.php b/resources/views/administration/personalization/journal-template-add.blade.php
new file mode 100644
index 00000000..9821b326
--- /dev/null
+++ b/resources/views/administration/personalization/journal-template-add.blade.php
@@ -0,0 +1,56 @@
+<?php
+/*
+ * @var array $genders
+ * @var array $taskCategories
+ */
+?>
+
+<x-app-layout>
+  <div class="grid h-[calc(100vh-48px)] grid-cols-1 lg:grid-cols-[240px_1fr]">
+    <!-- sidebar -->
+    @include('administration.partials.sidebar')
+
+    <!-- main content -->
+    <div class="relative bg-gray-50 px-6 pt-8 lg:px-12">
+      <div class="mx-auto max-w-5xl px-2 py-2 sm:px-0">
+        <form action="{{ route('administration.personalization.journal-templates.create') }}" method="POST" class="grid grid-rows-2 gap-4 sm:grid-cols-6 sm:grid-rows-1">
+          @csrf
+
+          <!-- left column -->
+          <div class="col-span-6 overflow-hidden rounded-md border border-gray-200 bg-white sm:col-start-1 sm:col-end-6 sm:rounded-lg dark:bg-gray-800">
+            <div class="border-b border-gray-200 bg-white p-6 lg:p-8 dark:border-gray-700 dark:bg-gray-800 dark:bg-gradient-to-bl dark:from-gray-700/50 dark:via-transparent">
+              <h1 class="mb-2 text-xl font-medium text-gray-900 dark:text-white">{{ __('Add a new journal template') }}</h1>
+
+              <p class="text-gray-500 dark:text-gray-400">{{ __('Think of journal templates as a way to structure journal entries.') }}</p>
+            </div>
+
+            <div class="p-6">
+              <x-input-error :messages="$errors->get('name')" class="mt-2" />
+              <x-input-error :messages="$errors->get('content')" class="mt-2 mb-4" />
+
+              <x-input-label for="name" :value="__('Name')" class="mb-1" />
+              <x-text-input id="name" class="mt-1 mb-4" value="{{ old('name') }}" type="text" name="name" required />
+
+              <x-input-label for="content" :value="__('Content')" class="mb-1" />
+              <x-textarea id="content" name="content" class="w-full" :height="'min-h-[600px]'" required>{{ old('content') }}</x-textarea>
+              <p class="mt-1 text-xs text-gray-600">{{ __('This should be a valid YAML file.') }}</p>
+            </div>
+          </div>
+
+          <!-- right column -->
+          <div class="col-span-6 sm:col-span-1">
+            <div class="flex flex-col items-center space-y-4">
+              <x-button.primary class="w-full">
+                {{ __('Save') }}
+              </x-button.primary>
+
+              <x-button.secondary href="{{ route('administration.personalization.index') }}" class="w-full text-center">
+                {{ __('Cancel') }}
+              </x-button.secondary>
+            </div>
+          </div>
+        </form>
+      </div>
+    </div>
+  </div>
+</x-app-layout>
diff --git a/resources/views/administration/personalization/journal-template-edit.blade.php b/resources/views/administration/personalization/journal-template-edit.blade.php
new file mode 100644
index 00000000..c8153141
--- /dev/null
+++ b/resources/views/administration/personalization/journal-template-edit.blade.php
@@ -0,0 +1,57 @@
+<?php
+/*
+ * @var array $genders
+ * @var array $taskCategories
+ */
+?>
+
+<x-app-layout>
+  <div class="grid h-[calc(100vh-48px)] grid-cols-1 lg:grid-cols-[240px_1fr]">
+    <!-- sidebar -->
+    @include('administration.partials.sidebar')
+
+    <!-- main content -->
+    <div class="relative bg-gray-50 px-6 pt-8 lg:px-12">
+      <div class="mx-auto max-w-5xl px-2 py-2 sm:px-0">
+        <form action="{{ route('administration.personalization.journal-templates.update', $journalTemplate->id) }}" method="POST" class="grid grid-rows-2 gap-4 sm:grid-cols-6 sm:grid-rows-1">
+          @csrf
+          @method('PUT')
+
+          <!-- left column -->
+          <div class="col-span-6 overflow-hidden rounded-md border border-gray-200 bg-white sm:col-start-1 sm:col-end-6 sm:rounded-lg dark:bg-gray-800">
+            <div class="border-b border-gray-200 bg-white p-6 lg:p-8 dark:border-gray-700 dark:bg-gray-800 dark:bg-gradient-to-bl dark:from-gray-700/50 dark:via-transparent">
+              <h1 class="mb-2 text-xl font-medium text-gray-900 dark:text-white">{{ __('Edit journal template') }}</h1>
+
+              <p class="text-gray-500 dark:text-gray-400">{{ __('Think of journal templates as a way to structure journal entries.') }}</p>
+            </div>
+
+            <div class="p-6">
+              <x-input-error :messages="$errors->get('name')" class="mt-2" />
+              <x-input-error :messages="$errors->get('content')" class="mt-2 mb-4" />
+
+              <x-input-label for="name" :value="__('Name')" class="mb-1" />
+              <x-text-input id="name" class="mt-1 mb-4" value="{{ old('name', $journalTemplate->name) }}" type="text" name="name" required />
+
+              <x-input-label for="content" :value="__('Content')" class="mb-1" />
+              <x-textarea id="content" name="content" class="w-full" :height="'min-h-[600px]'" required>{{ old('content', $journalTemplate->content) }}</x-textarea>
+              <p class="mt-1 text-xs text-gray-600">{{ __('This should be a valid YAML file.') }}</p>
+            </div>
+          </div>
+
+          <!-- right column -->
+          <div class="col-span-6 sm:col-span-1">
+            <div class="flex flex-col items-center space-y-4">
+              <x-button.primary class="w-full">
+                {{ __('Save') }}
+              </x-button.primary>
+
+              <x-button.secondary href="{{ route('administration.personalization.index') }}" class="w-full text-center">
+                {{ __('Cancel') }}
+              </x-button.secondary>
+            </div>
+          </div>
+        </form>
+      </div>
+    </div>
+  </div>
+</x-app-layout>
diff --git a/resources/views/administration/personalization/partials/journal-templates.blade.php b/resources/views/administration/personalization/partials/journal-templates.blade.php
index b46d792b..016d7351 100644
--- a/resources/views/administration/personalization/partials/journal-templates.blade.php
+++ b/resources/views/administration/personalization/partials/journal-templates.blade.php
@@ -21,28 +21,28 @@
       <p class="text-sm text-zinc-500">{{ __(':count category(s)', ['count' => $journalTemplates->count()]) }}</p>
     @endif
 
-    <x-button.secondary x-target="add-category-form" href="{{ route('administration.personalization.task-categories.new') }}" class="mr-2 text-sm">
+    <x-button.secondary href="{{ route('administration.personalization.journal-templates.new') }}" class="mr-2 text-sm">
       {{ __('New template') }}
     </x-button.secondary>
   </div>
 
-  <div id="category-list" class="divide-y divide-gray-200">
-    @forelse ($journalTemplates as $taskCategory)
-      <div id="task-category-{{ $taskCategory['id'] }}" class="group flex items-center justify-between p-3 transition-colors duration-200 last:rounded-b-lg">
+  <div id="journal-template-list" class="divide-y divide-gray-200">
+    @forelse ($journalTemplates as $template)
+      <div id="journal-template-{{ $template['id'] }}" class="group flex items-center justify-between p-3 transition-colors duration-200 last:rounded-b-lg">
         <div class="flex items-center gap-2">
-          <div class="{{ $taskCategory['color'] }} h-4 w-4 rounded-full"></div>
-          <p class="border border-transparent py-1 text-sm font-semibold">{{ $taskCategory['name'] }}</p>
+          <p class="border border-transparent py-1 text-sm font-semibold">{{ $template['name'] }}</p>
         </div>
 
         <div class="flex gap-2">
-          <x-button.invisible x-target="task-category-{{ $taskCategory['id'] }}" href="{{ route('administration.personalization.task-categories.edit', $taskCategory['id']) }}" class="hidden text-sm group-hover:block">
+          <x-button.invisible href="{{ route('administration.personalization.journal-templates.edit', $template['id']) }}" class="hidden text-sm group-hover:block">
             {{ __('Edit') }}
           </x-button.invisible>
 
-          <form x-target="task-category-{{ $taskCategory['id'] }}" x-on:ajax:before="
-            confirm('Are you sure you want to proceed? This can not be undone.') ||
-              $event.preventDefault()
-          " action="{{ route('administration.personalization.task-categories.destroy', $taskCategory['id']) }}" method="POST">
+          <form x-target="journal-template-{{ $template['id'] }} journal-template-list" x-on:ajax:before="
+            confirm(
+              '{{ __('Are you sure you want to proceed? This can not be undone.') }}',
+            ) || $event.preventDefault()
+          " action="{{ route('administration.personalization.journal-templates.destroy', $template['id']) }}" method="POST">
             @csrf
             @method('DELETE')
 
diff --git a/resources/views/components/button/secondary.blade.php b/resources/views/components/button/secondary.blade.php
index d106afca..29590dcb 100644
--- a/resources/views/components/button/secondary.blade.php
+++ b/resources/views/components/button/secondary.blade.php
@@ -4,9 +4,9 @@
 ])
 
 @isset($href)
-  <a href="{{ $href }}" {{ $attributes->merge(['class' => 'cursor-pointer inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-1 font-semibold text-gray-700 hover:shadow-xs transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25']) }}>{{ $slot }}</a>
+  <a href="{{ $href }}" {{ $attributes->merge(['class' => 'cursor-pointer inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-1 font-semibold text-gray-700 hover:shadow-xs transition duration-150 ease-in-out text-center hover:bg-gray-50 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25']) }}>{{ $slot }}</a>
 @else
-  <button {{ $attributes->merge(['type' => 'button', 'class' => 'cursor-pointer inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-1 font-semibold text-gray-700 hover:shadow-xs transition duration-150 ease-in-out hover:bg-gray-50 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25']) }}>
+  <button {{ $attributes->merge(['type' => 'button', 'class' => 'cursor-pointer inline-flex items-center rounded-md border border-gray-300 bg-white px-3 py-1 font-semibold text-gray-700 hover:shadow-xs transition duration-150 text-center ease-in-out hover:bg-gray-50 focus:outline-hidden focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 disabled:opacity-25']) }}>
     {{ $slot }}
   </button>
 @endif
diff --git a/resources/views/layouts/handbook.blade.php b/resources/views/layouts/handbook.blade.php
index 07e276c7..f8682786 100644
--- a/resources/views/layouts/handbook.blade.php
+++ b/resources/views/layouts/handbook.blade.php
@@ -18,22 +18,22 @@
       {!!
         $breadcrumb ??
           '
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                              <a href="' .
             route('marketing.index') .
             '" class="text-blue-500 hover:underline">' .
             __('Home') .
             '</a>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                              <span class="text-gray-500">&gt;</span>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                              <a href="' .
             route('marketing.company.index') .
             '" class="text-blue-500 hover:underline">' .
             __('Company') .
             '</a>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-600">' .
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                              <span class="text-gray-500">&gt;</span>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                              <span class="text-gray-600">' .
             __('Handbook') .
             '</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      '
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                              '
       !!}
     </div>
   </div>
diff --git a/routes/web.php b/routes/web.php
index a42816a2..add61921 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -8,6 +8,7 @@
 use App\Http\Controllers\Administration\AdministrationGenderController;
 use App\Http\Controllers\Administration\AdministrationLogsController;
 use App\Http\Controllers\Administration\AdministrationPersonalizationController;
+use App\Http\Controllers\Administration\AdministrationPersonalizationJournalTemplateController;
 use App\Http\Controllers\Administration\AdministrationPruneAccountController;
 use App\Http\Controllers\Administration\AdministrationSecurityController;
 use App\Http\Controllers\Administration\AdministrationTaskCategoryController;
@@ -185,6 +186,13 @@ function (): void {
     Route::put('administration/personalization/task-categories/{taskCategory}', [AdministrationTaskCategoryController::class, 'update'])->name('administration.personalization.task-categories.update');
     Route::delete('administration/personalization/task-categories/{taskCategory}', [AdministrationTaskCategoryController::class, 'destroy'])->name('administration.personalization.task-categories.destroy');
 
+    // journal templates
+    Route::get('administration/personalization/journal-templates/new', [AdministrationPersonalizationJournalTemplateController::class, 'new'])->name('administration.personalization.journal-templates.new');
+    Route::post('administration/personalization/journal-templates', [AdministrationPersonalizationJournalTemplateController::class, 'create'])->name('administration.personalization.journal-templates.create');
+    Route::get('administration/personalization/journal-templates/{journalTemplate}/edit', [AdministrationPersonalizationJournalTemplateController::class, 'edit'])->name('administration.personalization.journal-templates.edit');
+    Route::put('administration/personalization/journal-templates/{journalTemplate}', [AdministrationPersonalizationJournalTemplateController::class, 'update'])->name('administration.personalization.journal-templates.update');
+    Route::delete('administration/personalization/journal-templates/{journalTemplate}', [AdministrationPersonalizationJournalTemplateController::class, 'destroy'])->name('administration.personalization.journal-templates.destroy');
+
     // account
     Route::get('administration/account', [AdministrationAccountController::class, 'index'])->name('administration.account.index');
     Route::put('administration/prune', [AdministrationPruneAccountController::class, 'update'])->name('administration.account.prune');
diff --git a/tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php b/tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php
new file mode 100644
index 00000000..75b46b7b
--- /dev/null
+++ b/tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php
@@ -0,0 +1,162 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Tests\Feature\Controllers\Administration;
+
+use App\Models\Account;
+use App\Models\JournalTemplate;
+use App\Models\User;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
+
+class AdministrationPersonalizationJournalTemplateControllerTest extends TestCase
+{
+    use RefreshDatabase;
+
+    private User $user;
+
+    private Account $account;
+
+    private string $validYaml = <<<'YAML'
+template:
+  name: "Daily Reflection"
+  columns:
+    - name: "Morning"
+      questions:
+        - name: "Sleep quality"
+          answers:
+            type: "range"
+            range: [1, 5]
+            comment_allowed: true
+YAML;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $this->account = Account::factory()->create();
+        $this->user = User::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+    }
+
+    /** @test */
+    public function it_displays_the_new_template_page(): void
+    {
+        $response = $this->actingAs($this->user)
+            ->get(route('administration.personalization.journal-templates.new'));
+
+        $response->assertStatus(200);
+        $response->assertViewIs('administration.personalization.journal-template-add');
+    }
+
+    /** @test */
+    public function it_creates_a_journal_template(): void
+    {
+        $response = $this->actingAs($this->user)
+            ->post(route('administration.personalization.journal-templates.create'), [
+                'name' => 'Test Template',
+                'content' => $this->validYaml,
+            ]);
+
+        $response->assertRedirect(route('administration.personalization.index'));
+        $response->assertSessionHas('success');
+    }
+
+    /** @test */
+    public function it_displays_the_edit_template_page(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->get(route('administration.personalization.journal-templates.edit', $template->id));
+
+        $response->assertStatus(200);
+        $response->assertViewIs('administration.personalization.journal-template-edit');
+        $response->assertViewHas('journalTemplate');
+    }
+
+    /** @test */
+    public function it_cant_edit_template_from_another_account(): void
+    {
+        $anotherAccount = Account::factory()->create();
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $anotherAccount->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->get(route('administration.personalization.journal-templates.edit', $template->id));
+
+        $response->assertStatus(404);
+    }
+
+    /** @test */
+    public function it_updates_a_journal_template(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->put(route('administration.personalization.journal-templates.update', $template->id), [
+                'name' => 'Updated Template',
+                'content' => $this->validYaml,
+            ]);
+
+        $response->assertRedirect(route('administration.personalization.index'));
+        $response->assertSessionHas('success');
+
+        $this->assertDatabaseHas('journal_templates', [
+            'id' => $template->id,
+        ]);
+    }
+
+    /** @test */
+    public function it_deletes_a_journal_template(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->delete(route('administration.personalization.journal-templates.destroy', $template->id));
+
+        $response->assertRedirect(route('administration.personalization.index'));
+        $response->assertSessionHas('success');
+
+        $this->assertDatabaseMissing('journal_templates', [
+            'id' => $template->id,
+        ]);
+    }
+
+    /** @test */
+    public function it_validates_required_fields_when_creating(): void
+    {
+        $response = $this->actingAs($this->user)
+            ->post(route('administration.personalization.journal-templates.create'), [
+                'name' => '',
+                'content' => '',
+            ]);
+
+        $response->assertSessionHasErrors(['name', 'content']);
+    }
+
+    /** @test */
+    public function it_validates_required_fields_when_updating(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->put(route('administration.personalization.journal-templates.update', $template->id), [
+                'name' => '',
+                'content' => '',
+            ]);
+
+        $response->assertSessionHasErrors(['name', 'content']);
+    }
+}
diff --git a/tests/Unit/Services/CreateJournalTemplateTest.php b/tests/Unit/Services/CreateJournalTemplateTest.php
index a6e02684..869ad9c1 100644
--- a/tests/Unit/Services/CreateJournalTemplateTest.php
+++ b/tests/Unit/Services/CreateJournalTemplateTest.php
@@ -28,10 +28,23 @@ public function it_creates_a_journal_template(): void
         $user->account_id = $account->id;
         $user->save();
 
+        $validYaml = <<<'YAML'
+template:
+  name: "Daily Reflection"
+  columns:
+    - name: "Morning"
+      questions:
+        - name: "Sleep quality"
+          answers:
+            type: "range"
+            range: [1, 5]
+            comment_allowed: true
+YAML;
+
         $journalTemplate = (new CreateJournalTemplate(
             user: $user,
             name: 'Test template',
-            content: 'Test content',
+            content: $validYaml,
         ))->execute();
 
         $this->assertDatabaseHas('journal_templates', [
@@ -40,7 +53,7 @@ public function it_creates_a_journal_template(): void
         ]);
 
         $this->assertEquals('Test template', $journalTemplate->name);
-        $this->assertEquals('Test content', $journalTemplate->content);
+        $this->assertEquals($validYaml, $journalTemplate->content);
 
         Queue::assertPushed(UpdateUserLastActivityDate::class);
         Queue::assertPushed(LogUserAction::class, function ($job) {
diff --git a/tests/Unit/Services/UpdateJournalTemplateTest.php b/tests/Unit/Services/UpdateJournalTemplateTest.php
index dd32700f..e6fe0d3a 100644
--- a/tests/Unit/Services/UpdateJournalTemplateTest.php
+++ b/tests/Unit/Services/UpdateJournalTemplateTest.php
@@ -24,6 +24,19 @@ public function it_updates_a_journal_template(): void
     {
         Queue::fake();
 
+        $validYaml = <<<'YAML'
+template:
+  name: "Daily Reflection"
+  columns:
+    - name: "Morning"
+      questions:
+        - name: "Sleep quality"
+          answers:
+            type: "range"
+            range: [1, 5]
+            comment_allowed: true
+YAML;
+
         $user = User::factory()->create();
         $journalTemplate = JournalTemplate::factory()->create([
             'account_id' => $user->account_id,
@@ -35,7 +48,7 @@ public function it_updates_a_journal_template(): void
             user: $user,
             journalTemplate: $journalTemplate,
             name: 'New name',
-            content: 'New content',
+            content: $validYaml,
         ))->execute();
 
         $this->assertDatabaseHas('journal_templates', [
@@ -44,7 +57,7 @@ public function it_updates_a_journal_template(): void
         ]);
 
         $this->assertEquals('New name', $updatedTemplate->name);
-        $this->assertEquals('New content', $updatedTemplate->content);
+        $this->assertEquals($validYaml, $updatedTemplate->content);
 
         Queue::assertPushed(UpdateUserLastActivityDate::class);
         Queue::assertPushed(LogUserAction::class, function ($job) {
diff --git a/tests/Unit/Services/ValidateYamlStructureTest.php b/tests/Unit/Services/ValidateYamlStructureTest.php
index da22656c..444cb968 100644
--- a/tests/Unit/Services/ValidateYamlStructureTest.php
+++ b/tests/Unit/Services/ValidateYamlStructureTest.php
@@ -34,7 +34,7 @@ public function it_validates_valid_yaml_structure(): void
             options: ["High", "Medium", "Low"]
             comment_allowed: false
 YAML;
-        $result = (new ValidateYamlStructure())->execute($this->validYaml);
+        $result = (new ValidateYamlStructure($this->validYaml))->execute();
         $this->assertTrue($result['valid']);
     }
 
@@ -47,7 +47,7 @@ public function it_fails_on_invalid_yaml_syntax(): void
     syntax:
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($invalidYaml);
+        $result = (new ValidateYamlStructure($invalidYaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Invalid YAML format', $result['error']);
     }
@@ -56,7 +56,7 @@ public function it_fails_on_invalid_yaml_syntax(): void
     public function it_fails_without_template_root(): void
     {
         $yaml = 'name: "Test"';
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
 
         $this->assertFalse($result['valid']);
         $this->assertEquals('Missing template root element', $result['error']);
@@ -70,7 +70,7 @@ public function it_fails_without_template_name(): void
   columns: []
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Template name is required', $result['error']);
     }
@@ -104,7 +104,7 @@ public function it_fails_with_more_than_three_columns(): void
             type: "textarea"
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Maximum 3 columns allowed', $result['error']);
     }
@@ -122,7 +122,7 @@ public function it_fails_with_unnamed_column(): void
             type: "textarea"
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Column 1 missing name', $result['error']);
     }
@@ -138,7 +138,7 @@ public function it_fails_with_empty_column(): void
       questions: []
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Column 1 must have at least one question', $result['error']);
     }
@@ -157,7 +157,7 @@ public function it_fails_with_invalid_question_type(): void
             type: "invalid_type"
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals("Invalid answer type 'invalid_type' in column 1, question 1", $result['error']);
     }
@@ -176,7 +176,7 @@ public function it_fails_when_choice_type_missing_options(): void
             type: "choice"
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Choice type requires options array in column 1, question 1', $result['error']);
     }
@@ -195,7 +195,7 @@ public function it_fails_when_range_type_missing_range(): void
             type: "range"
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Range type requires valid range array [min, max] in column 1, question 1', $result['error']);
     }
@@ -215,7 +215,7 @@ public function it_fails_when_range_type_has_invalid_range_format(): void
             range: [1]
 YAML;
 
-        $result = (new ValidateYamlStructure())->execute($yaml);
+        $result = (new ValidateYamlStructure($yaml))->execute();
         $this->assertFalse($result['valid']);
         $this->assertEquals('Range type requires valid range array [min, max] in column 1, question 1', $result['error']);
     }


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>🔭 Outside diff range comments (1)</summary><blockquote>

<details>
<summary>resources/views/administration/personalization/partials/journal-templates.blade.php (1)</summary><blockquote>

`19-22`: _🛠️ Refactor suggestion_

**Text still refers to "categories" instead of "templates".**

The text strings still mention "categories" instead of "templates", which is inconsistent with the rest of the changes.


```diff
    @if ($journalTemplates->isEmpty())
-      <p class="text-sm text-zinc-500">{{ __('No categories created') }}</p>
+      <p class="text-sm text-zinc-500">{{ __('No templates created') }}</p>
    @else
-      <p class="text-sm text-zinc-500">{{ __(':count category(s)', ['count' => $journalTemplates->count()]) }}</p>
+      <p class="text-sm text-zinc-500">{{ __(':count template(s)', ['count' => $journalTemplates->count()]) }}</p>
    @endif
```

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (4)</summary><blockquote>

<details>
<summary>resources/views/administration/personalization/partials/journal-template-add.blade.php (2)</summary><blockquote>

`1-6`: **Remove unused variables in the PHP docblock.**

The docblock declares `$genders` and `$taskCategories` variables, but these aren't used anywhere in the template. Unused variable declarations can lead to confusion during maintenance.


```diff
-<?php
-/*
- * @var array $genders
- * @var array $taskCategories
- */
-?>
+<?php
+/*
+ * Add variables here as needed
+ */
+?>
```

---

`34-36`: **Consider providing YAML schema guidance or examples.**

The textarea for YAML content lacks guidance on the expected structure. Users might struggle with creating valid YAML without examples or schema information.


```diff
               <x-input-label for="content" :value="__('Content')" class="mb-1" />
               <x-textarea id="content" name="content" class="w-full" :height="'min-h-[600px]'" required />
-              <p class="mt-1 text-xs text-gray-600">{{ __('This should be a valid YAML file.') }}</p>
+              <p class="mt-1 text-xs text-gray-600">{{ __('This should be a valid YAML file with the following structure:') }}</p>
+              <pre class="mt-1 text-xs text-gray-600 bg-gray-50 p-2 rounded overflow-auto max-h-40">template:
+  name: "Template Name"
+  columns:
+    - name: "Column Name"
+      questions:
+        - name: "Question Text"
+          answers:
+            type: "choice|range|textarea"
+            # For choice type:
+            options: ["Option 1", "Option 2"]
+            # For range type:
+            range: [1, 5]</pre>
```

</blockquote></details>
<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php (2)</summary><blockquote>

`8-10`: **Remove unused imports.**

The Gender and JournalTemplate models are imported but not used in this controller.

```diff
 use App\Http\Controllers\Controller;
-use App\Models\Gender;
-use App\Models\JournalTemplate;
 use App\Services\CreateJournalTemplate;
```

---

`23-38`: **Create method well-implemented but lacks test coverage.**

The create method follows Laravel best practices with proper validation and error handling. However, this method is not covered by tests according to static analysis.


Would you like me to generate a feature test for this controller to ensure its functionality is properly verified?

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 23-23: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L23
Added line #L23 was not covered by tests

---

[warning] 25-28: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L25-L28
Added lines #L25 - L28 were not covered by tests

---

[warning] 30-34: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L30-L34
Added lines #L30 - L34 were not covered by tests

---

[warning] 36-37: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L36-L37
Added lines #L36 - L37 were not covered by tests

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 16af33cca02571a457325110d313522561a22017 and 084cb5806fcbf62baa6a4bc84c8c1ef023fe47c4.

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php` (1 hunks)
* `app/Services/CreateJournalTemplate.php` (1 hunks)
* `app/Services/UpdateJournalTemplate.php` (1 hunks)
* `app/Services/ValidateYamlStructure.php` (1 hunks)
* `resources/views/administration/personalization/partials/journal-template-add.blade.php` (1 hunks)
* `resources/views/administration/personalization/partials/journal-templates.blade.php` (1 hunks)
* `resources/views/components/button/secondary.blade.php` (1 hunks)
* `resources/views/layouts/handbook.blade.php` (1 hunks)
* `routes/web.php` (2 hunks)
* `tests/Unit/Services/CreateJournalTemplateTest.php` (2 hunks)
* `tests/Unit/Services/UpdateJournalTemplateTest.php` (3 hunks)
* `tests/Unit/Services/ValidateYamlStructureTest.php` (11 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (5)</summary>

<details>
<summary>app/Services/UpdateJournalTemplate.php (1)</summary><blockquote>

<details>
<summary>app/Services/ValidateYamlStructure.php (2)</summary>

* `ValidateYamlStructure` (10-101)
* `execute` (20-54)

</details>

</blockquote></details>
<details>
<summary>tests/Unit/Services/ValidateYamlStructureTest.php (1)</summary><blockquote>

<details>
<summary>app/Services/ValidateYamlStructure.php (2)</summary>

* `ValidateYamlStructure` (10-101)
* `execute` (20-54)

</details>

</blockquote></details>
<details>
<summary>tests/Unit/Services/CreateJournalTemplateTest.php (1)</summary><blockquote>

<details>
<summary>app/Services/CreateJournalTemplate.php (1)</summary>

* `CreateJournalTemplate` (12-59)

</details>

</blockquote></details>
<details>
<summary>routes/web.php (1)</summary><blockquote>

<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php (1)</summary>

* `AdministrationPersonalizationJournalTemplateController` (16-39)

</details>

</blockquote></details>
<details>
<summary>app/Services/ValidateYamlStructure.php (2)</summary><blockquote>

<details>
<summary>app/Services/UpdateJournalTemplate.php (2)</summary>

* `__construct` (15-20)
* `execute` (22-30)

</details>
<details>
<summary>app/Services/CreateJournalTemplate.php (2)</summary>

* `__construct` (16-20)
* `execute` (22-30)

</details>

</blockquote></details>

</details><details>
<summary>🪛 GitHub Check: codecov/patch</summary>

<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php</summary>

[warning] 18-18: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L18
Added line #L18 was not covered by tests

---

[warning] 20-20: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L20
Added line #L20 was not covered by tests

---

[warning] 23-23: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L23
Added line #L23 was not covered by tests

---

[warning] 25-28: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L25-L28
Added lines #L25 - L28 were not covered by tests

---

[warning] 30-34: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L30-L34
Added lines #L30 - L34 were not covered by tests

---

[warning] 36-37: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L36-L37
Added lines #L36 - L37 were not covered by tests

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (19)</summary><blockquote>

<details>
<summary>resources/views/components/button/secondary.blade.php (1)</summary>

`7-9`: **Adding text-center for consistent button text alignment**

Adding the `text-center` class to both anchor and button elements ensures consistent text alignment across different button types. This is a good UI enhancement.

</details>
<details>
<summary>app/Services/UpdateJournalTemplate.php (1)</summary>

`37-38`: **LGTM: Added YAML structure validation**

The addition of YAML structure validation before updating a journal template is an excellent data integrity enhancement. It ensures that only properly formatted templates can be saved.


This change is consistent with the similar validation added to the `CreateJournalTemplate` service, maintaining validation consistency across create and update operations.

</details>
<details>
<summary>tests/Unit/Services/CreateJournalTemplateTest.php (3)</summary>

`31-42`: **Well-structured YAML test data**

The addition of a realistic and well-structured YAML string makes this test more valuable by testing against actual expected data structures rather than a simple string.

---

`47-47`: **Using valid YAML in test parameters**

Good update to use the newly defined YAML structure in the service call.

---

`56-56`: **Updated assertion to match new test data**

The assertion has been correctly updated to match against the new YAML data structure.

</details>
<details>
<summary>tests/Unit/Services/ValidateYamlStructureTest.php (2)</summary>

`37-38`: **LGTM! The test was updated to match the new ValidateYamlStructure constructor.**

The test code correctly reflects the new instantiation pattern for the ValidateYamlStructure class.

---

`50-53`: **LGTM! All test methods were updated consistently.**

All the test methods have been properly updated to use the new instantiation pattern for ValidateYamlStructure.



Also applies to: 59-63, 73-76, 107-110, 125-128, 141-144, 160-163, 179-182, 198-201, 218-221

</details>
<details>
<summary>app/Services/CreateJournalTemplate.php (1)</summary>

`24-25`: **LGTM! Added validation before creating the template.**

Good addition of validation step before creating the journal template.

</details>
<details>
<summary>resources/views/administration/personalization/partials/journal-templates.blade.php (3)</summary>

`24-26`: **LGTM! Correctly updated route for new template button.**

The button now properly links to the journal templates route.

---

`29-33`: **Updated template iteration and IDs.**

The loop now correctly iterates over journal templates with proper ID references.

---

`36-45`: **Updated edit and delete routes for templates.**

The form actions now correctly reference journal template routes.

</details>
<details>
<summary>tests/Unit/Services/UpdateJournalTemplateTest.php (3)</summary>

`27-38`: **Good addition of structured YAML test data.**

The addition of a structured YAML string for testing is a good improvement over the previous hardcoded string. This better represents real-world data and ensures the validation logic is properly tested.

---

`51-52`: **Well-implemented test update.**

Updated the test to use the structured YAML content instead of a simple string, ensuring the service properly handles real-world data.

---

`60-60`: **Assertion properly updated.**

The assertion has been correctly updated to check for the new YAML content format.

</details>
<details>
<summary>routes/web.php (2)</summary>

`11-11`: **LGTM: Controller import added.**

The import for the new journal template controller follows the existing pattern of the codebase.

---

`189-191`: **Journal template routes properly implemented.**

The routes follow RESTful conventions and match the naming pattern of other routes in the application. Both the GET route for displaying the form and the POST route for handling submissions are correctly configured.

</details>
<details>
<summary>app/Services/ValidateYamlStructure.php (3)</summary>

`16-18`: **Good refactoring to constructor-based dependency injection.**

Moving the YAML content to a constructor property is a good design improvement that follows SOLID principles and makes the class more testable.

---

`20-20`: **Method signature appropriately updated.**

The execute method signature has been correctly updated to reflect the constructor-based approach.

---

`23-23`: **Implementation correctly updated.**

Updated to use the class property instead of the method parameter, consistent with the constructor-based approach.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-28T20:50:37Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 7**

<details>
<summary>🧹 Nitpick comments (5)</summary><blockquote>

<details>
<summary>config/marketing-timestamps.php (1)</summary><blockquote>

`39-40`: **Consider standardizing all timestamp formats for consistency.**

You've updated some timestamps to use the UTC 'Z' suffix format, but others still use explicit timezone offsets (e.g., "-04:00"). Consider standardizing all timestamps to use the same format for better consistency throughout the configuration.



Also applies to: 43-46, 53-54

</blockquote></details>
<details>
<summary>resources/views/administration/personalization/journal-template-add.blade.php (2)</summary><blockquote>

`2-5`: **Remove unused variable declarations in the comments.**

The PHP comments mention variables `$genders` and `$taskCategories` that don't appear to be used in this template.

```diff
<?php
-/*
- * @var array $genders
- * @var array $taskCategories
- */
+// Journal template add form
?>
```

---

`34-36`: **Enhance user guidance for YAML content.**

While the form indicates that the content should be valid YAML, it doesn't provide guidance on the expected structure or format of the journal template content. Consider adding more detailed instructions or an example template to help users create valid templates.

You could add a collapsible example or link to documentation:

```diff
<x-input-label for="content" :value="__('Content')" class="mb-1" />
<x-textarea id="content" name="content" class="w-full" :height="'min-h-[600px]'" required>{{ old('content') }}</x-textarea>
-<p class="mt-1 text-xs text-gray-600">{{ __('This should be a valid YAML file.') }}</p>
+<p class="mt-1 text-xs text-gray-600">
+  {{ __('This should be a valid YAML file.') }}
+  <button type="button" class="text-blue-600 hover:underline" 
+    onclick="document.getElementById('yaml-example').classList.toggle('hidden')">
+    {{ __('Show example') }}
+  </button>
+</p>
+<div id="yaml-example" class="mt-2 hidden rounded-md bg-gray-100 p-3 text-xs">
+<pre>template:
+  name: "Daily Reflection"
+  columns:
+    - name: "Morning"
+      questions:
+        - name: "Sleep quality"
+          answers:
+            type: "range"
+            range: [1, 5]
+            comment_allowed: true</pre>
+</div>
```

</blockquote></details>
<details>
<summary>resources/views/administration/personalization/journal-template-edit.blade.php (1)</summary><blockquote>

`3-5`: **Irrelevant variable annotations in the template.**

The template has PHPDoc annotations for `$genders` and `$taskCategories` variables, but these variables are not used in the template. These annotations appear to be copied from another template.

```diff
-<?php
-/*
- * @var array $genders
- * @var array $taskCategories
- */
-?>
+<?php
+/*
+ * @var \App\Models\JournalTemplate $journalTemplate
+ */
+?>
```

</blockquote></details>
<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php (1)</summary><blockquote>

`48-61`: **Improve access control in the edit method.**

While you do check if the journal template belongs to the user's account, consider using Laravel's authorization system (Policies) for more consistent access control.

You could create a JournalTemplatePolicy with a view method:

```php
// In a JournalTemplatePolicy class
public function view(User $user, JournalTemplate $journalTemplate)
{
    return $user->account_id === $journalTemplate->account_id;
}

// Then in your controller
public function edit(Request $request): View
{
    $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
    $this->authorize('view', $journalTemplate);
    
    return view('administration.personalization.journal-template-edit', [
        'journalTemplate' => $journalTemplate,
    ]);
}
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 084cb5806fcbf62baa6a4bc84c8c1ef023fe47c4 and 309f917e2b8df389bc3f31fe2649ce89f9bb4f83.

</details>

<details>
<summary>📒 Files selected for processing (9)</summary>

* `app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php` (1 hunks)
* `app/Services/CreateJournalTemplate.php` (2 hunks)
* `config/marketing-timestamps.php` (1 hunks)
* `resources/views/administration/personalization/journal-template-add.blade.php` (1 hunks)
* `resources/views/administration/personalization/journal-template-edit.blade.php` (1 hunks)
* `resources/views/administration/personalization/partials/journal-templates.blade.php` (1 hunks)
* `resources/views/layouts/handbook.blade.php` (1 hunks)
* `routes/web.php` (2 hunks)
* `tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* resources/views/layouts/handbook.blade.php
* resources/views/administration/personalization/partials/journal-templates.blade.php

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Definitions (1)</summary>

<details>
<summary>tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php (2)</summary><blockquote>

<details>
<summary>app/Services/CreateJournalTemplate.php (1)</summary>

* `create` (42-49)

</details>
<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php (1)</summary>

* `create` (25-46)

</details>

</blockquote></details>

</details><details>
<summary>🪛 GitHub Check: codecov/patch</summary>

<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php</summary>

[warning] 38-41: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L38-L41
Added lines #L38 - L41 were not covered by tests

</details>
<details>
<summary>app/Services/CreateJournalTemplate.php</summary>

[warning] 38-38: app/Services/CreateJournalTemplate.php#L38
Added line #L38 was not covered by tests

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (14)</summary><blockquote>

<details>
<summary>app/Services/CreateJournalTemplate.php (2)</summary>

`11-11`: **Good addition of the Exception import.**

The Exception class import is necessary for the new exception handling in the validate method.

---

`25-25`: **Validation step correctly added to execution flow.**

The validation is now properly called at the beginning of the execution flow, ensuring content is validated before creating the journal template.

</details>
<details>
<summary>resources/views/administration/personalization/journal-template-add.blade.php (1)</summary>

`8-56`: **Overall good implementation of the journal template form.**

The form is well-structured with appropriate error handling, input validation, and clear layout. The responsive design with separate columns for the form and buttons works well.

</details>
<details>
<summary>tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php (3)</summary>

`21-32`: **Good definition of valid YAML for testing.**

The test includes a well-structured YAML example that matches the expected format for journal templates, making tests realistic.

---

`54-65`: **Test happy path for template creation.**

This test correctly verifies that template creation works with valid data, checking for the redirect and success message.

---

`82-94`: **Good access control test.**

This test properly verifies that users cannot access or edit templates from other accounts, which is an important security check.

</details>
<details>
<summary>resources/views/administration/personalization/journal-template-edit.blade.php (5)</summary>

`16-18`: **LGTM! CSRF protection and method spoofing are properly implemented.**

The form correctly uses the PUT method spoofing with `@method('PUT')` and CSRF protection with `@csrf` for the journal template update operation.

---

`28-30`: **LGTM! Proper error display for form validation.**

Error messages for both name and content fields are correctly displayed using the `x-input-error` component.

---

`32-36`: **Form field implementation looks good.**

The implementation properly uses the Laravel text input component with value fallback to old input and default values from the model.

---

`35-37`: **YAML validation message is helpful.**

The note about YAML validity is a good addition to guide users on proper content format.

---

`43-51`: **LGTM! Clear action buttons with proper routing.**

The save and cancel buttons are well implemented with appropriate routes and styling.

</details>
<details>
<summary>routes/web.php (2)</summary>

`11-11`: **LGTM! Controller import added correctly.**

The `AdministrationPersonalizationJournalTemplateController` import is properly added to the imports section.

---

`189-195`: **LGTM! Well-organized route definitions for journal templates.**

The routes for journal templates are well-structured and follow the same pattern as other resource routes in the application:
- Routes for displaying forms (new, edit)
- Routes for processing actions (create, update, destroy)
- Consistent naming convention with the rest of the application

All routes are correctly mapped to the appropriate controller methods.

</details>
<details>
<summary>app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php (1)</summary>

`18-23`: **LGTM! The new() method is correctly implemented.**

The method returns the appropriate view for adding a new journal template.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-28T21:29:07Z

Review comments:
diff_hunk: @@ -18,22 +18,22 @@
       {!!
         $breadcrumb ??
           '
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
             route('marketing.index') .
             '" class="text-blue-500 hover:underline">' .
             __('Home') .
             '</a>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
             route('marketing.company.index') .
             '" class="text-blue-500 hover:underline">' .
             __('Company') .
             '</a>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-600">' .
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-600">' .
             __('Handbook') .
             '</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                      '
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                      '
path: resources/views/layouts/handbook.blade.php
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Fix excessive whitespace in breadcrumb section**

The breadcrumb section contains an excessive amount of whitespace (hundreds of spaces) before HTML content, making the code difficult to read and maintain. This appears to be a formatting issue.

```diff
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
+          <a href="' .
            route('marketing.index') .
            '" class="text-blue-500 hover:underline">' .
            __('Home') .
            '</a>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <a href="' .
+          <span class="text-gray-500">&gt;</span>
+          <a href="' .
            route('marketing.company.index') .
            '" class="text-blue-500 hover:underline">' .
            __('Company') .
            '</a>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-500">&gt;</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                      <span class="text-gray-600">' .
+          <span class="text-gray-500">&gt;</span>
+          <span class="text-gray-600">' .
            __('Handbook') .
            '</span>
-                                                                                                                                                                                                                                                                                                                                                                                                                                                                      '
+          '
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
          <a href="' .
            route('marketing.index') .
            '" class="text-blue-500 hover:underline">' .
            __('Home') .
            '</a>
          <span class="text-gray-500">&gt;</span>
          <a href="' .
            route('marketing.company.index') .
            '" class="text-blue-500 hover:underline">' .
            __('Company') .
            '</a>
          <span class="text-gray-500">&gt;</span>
          <span class="text-gray-600">' .
            __('Handbook') .
            '</span>
          '
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T20:50:36Z
author_association: NONE
diff_hunk: @@ -0,0 +1,56 @@
+<?php
+/*
+ * @var array $genders
+ * @var array $taskCategories
+ */
+?>
+
+<x-app-layout>
+  <div class="grid h-[calc(100vh-48px)] grid-cols-1 lg:grid-cols-[240px_1fr]">
+    <!-- sidebar -->
+    @include('administration.partials.sidebar')
+
+    <!-- main content -->
+    <div class="relative bg-gray-50 px-6 pt-8 lg:px-12">
+      <div class="mx-auto max-w-5xl px-2 py-2 sm:px-0">
+        <form action="{{ route('administration.personalization.journal-templates.create') }}" method="POST" class="grid grid-rows-2 gap-4 sm:grid-cols-6 sm:grid-rows-1">
+          @csrf
+
+          <!-- left column -->
+          <div class="col-span-6 overflow-hidden rounded-md border border-gray-200 bg-white sm:col-start-1 sm:col-end-6 sm:rounded-lg dark:bg-gray-800">
+            <div class="border-b border-gray-200 bg-white p-6 lg:p-8 dark:border-gray-700 dark:bg-gray-800 dark:bg-gradient-to-bl dark:from-gray-700/50 dark:via-transparent">
+              <h1 class="mb-2 text-xl font-medium text-gray-900 dark:text-white">{{ __('Add a new journal template') }}</h1>
+
+              <p class="text-gray-500 dark:text-gray-400">{{ __('Think of journal templates as a way to structure journal entries.') }}</p>
+            </div>
+
+            <div class="p-6">
+              <x-input-error :messages="$errors->get('name')" class="mt-2" />
+              <x-input-error :messages="$errors->get('content')" class="mt-2" />
+
+              <x-input-label for="name" :value="__('Name')" class="mb-1" />
+              <x-text-input id="name" class="mt-1 mb-4" type="text" name="name" required />
+
+              <x-input-label for="content" :value="__('Content')" class="mb-1" />
+              <x-textarea id="content" name="content" class="w-full" :height="'min-h-[600px]'" required />
+              <p class="mt-1 text-xs text-gray-600">{{ __('This should be a valid YAML file.') }}</p>
+            </div>
+          </div>
+
+          <!-- right column -->
+          <div class="col-span-6 sm:col-span-1">
+            <div class="flex flex-col items-center space-y-4">
+              <x-button.primary class="w-full">
+                {{ __('Save') }}
+              </x-button.primary>
+
+              <x-button.secondary class="w-full text-center">
+                {{ __('Cancel') }}
+              </x-button.secondary>
path: resources/views/administration/personalization/partials/journal-template-add.blade.php
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add a href attribute to the Cancel button.**

The Cancel button doesn't specify where it should redirect the user. Without a destination, clicking this button won't do anything.


```diff
-              <x-button.secondary class="w-full text-center">
+              <x-button.secondary href="{{ route('administration.personalization.journal-templates.index') }}" class="w-full text-center">
                 {{ __('Cancel') }}
               </x-button.secondary>
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
              <x-button.secondary href="{{ route('administration.personalization.journal-templates.index') }}" class="w-full text-center">
                {{ __('Cancel') }}
              </x-button.secondary>
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T20:50:36Z
author_association: NONE
diff_hunk: @@ -21,13 +21,19 @@ public function __construct(
 
     public function execute(): JournalTemplate
     {
+        $this->validate();
         $this->create();
         $this->updateUserLastActivityDate();
         $this->logUserAction();
 
         return $this->journalTemplate;
     }
 
+    private function validate(): void
+    {
+        (new ValidateYamlStructure($this->content))->execute();
+    }
path: app/Services/CreateJournalTemplate.php
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Missing error handling in the validate method.**

The `validate()` method calls `execute()` but doesn't check its return value. According to the implementation of `ValidateYamlStructure`, the `execute()` method returns an array with 'valid' and 'error' keys, but this result is ignored. If validation fails, there's no exception thrown, which means invalid YAML could still be saved.


```diff
 private function validate(): void
 {
-    (new ValidateYamlStructure($this->content))->execute();
+    $result = (new ValidateYamlStructure($this->content))->execute();
+    if (!$result['valid']) {
+        throw new \InvalidArgumentException('Invalid YAML content: ' . $result['error']);
+    }
 }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    private function validate(): void
    {
        $result = (new ValidateYamlStructure($this->content))->execute();
        if (!$result['valid']) {
            throw new \InvalidArgumentException('Invalid YAML content: ' . $result['error']);
        }
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commit 309f917
created_at: 2025-03-28T20:50:36Z
author_association: NONE
diff_hunk: @@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Http\Controllers\Administration;
+
+use App\Http\Controllers\Controller;
+use App\Models\Gender;
+use App\Models\JournalTemplate;
+use App\Services\CreateJournalTemplate;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
+
+class AdministrationPersonalizationJournalTemplateController extends Controller
+{
+    public function new(): View
+    {
+        return view('administration.personalization.partials.journal-template-add');
+    }
path: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>❓ Verification inconclusive</summary>

**Controller method looks good, but needs test coverage.**

The new() method is correctly implemented, but static analysis indicates it's not covered by tests.


Consider adding a feature test for this controller to ensure its functionality is verified:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if there are any tests for this controller
fd "AdministrationPersonalizationJournalTemplateController" tests/
```

Length of output: 66

---



</details>

**Action Required: Add Feature Test Coverage for the `new()` Method**

The implementation of the `new()` method in  
`app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php` (lines 18–21) is correct, as it returns the expected view. However, our search did not locate any tests covering this controller, so its behavior isn’t verified by automated tests.

Please do the following:
- **Manually verify** if any test might already exercise this controller (e.g., via an indirect route or integration test). In case such tests exist, confirm they cover the intended functionality.
- If no test is found, add a feature test that calls the `new()` method and asserts that it returns the view `'administration.personalization.partials.journal-template-add'`.

Example suggestion for a test case (conceptual):
```php
public function testNewMethodReturnsExpectedView()
{
    $response = $this->get(route('administration.journal-template.new'));
    $response->assertStatus(200);
    $response->assertViewIs('administration.personalization.partials.journal-template-add');
}
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 18-18: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L18
Added line #L18 was not covered by tests

---

[warning] 20-20: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L20
Added line #L20 was not covered by tests

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T20:50:36Z
author_association: NONE
diff_hunk: @@ -21,13 +22,23 @@
 
     public function execute(): JournalTemplate
     {
+        $this->validate();
         $this->create();
         $this->updateUserLastActivityDate();
         $this->logUserAction();
 
         return $this->journalTemplate;
     }
 
+    private function validate(): void
+    {
+        $validation = (new ValidateYamlStructure($this->content))->execute();
+
+        if (! $validation['valid']) {
+            throw new Exception($validation['error']);
+        }
+    }
path: app/Services/CreateJournalTemplate.php
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Missing import for ValidateYamlStructure class.**

The ValidateYamlStructure class is used but not imported at the top of the file. This could cause a PHP error at runtime.

Add this import at the top of the file:

```diff
use App\Jobs\LogUserAction;
use App\Jobs\UpdateUserLastActivityDate;
use App\Models\JournalTemplate;
use App\Models\User;
use Exception;
+use App\Services\ValidateYamlStructure;
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
use App\Jobs\LogUserAction;
use App\Jobs\UpdateUserLastActivityDate;
use App\Models\JournalTemplate;
use App\Models\User;
use Exception;
use App\Services\ValidateYamlStructure;
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 38-38: app/Services/CreateJournalTemplate.php#L38
Added line #L38 was not covered by tests

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:05Z
author_association: NONE
diff_hunk: @@ -21,13 +22,23 @@
 
     public function execute(): JournalTemplate
     {
+        $this->validate();
         $this->create();
         $this->updateUserLastActivityDate();
         $this->logUserAction();
 
         return $this->journalTemplate;
     }
 
+    private function validate(): void
+    {
+        $validation = (new ValidateYamlStructure($this->content))->execute();
+
+        if (! $validation['valid']) {
+            throw new Exception($validation['error']);
+        }
path: app/Services/CreateJournalTemplate.php
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Consider using a more specific exception type and add test coverage.**

Using a generic Exception is less informative than a more specific exception type. Additionally, static analysis indicates that this exception-throwing code path is not covered by tests.


Consider using a more specific exception type like InvalidArgumentException:

```diff
if (! $validation['valid']) {
-    throw new Exception($validation['error']);
+    throw new \InvalidArgumentException('Invalid YAML content: ' . $validation['error']);
}
```

Run the following script to check if there are tests for the failure case:

---

🏁 Script executed:

```shell
#!/bin/bash
# Check if there are tests that verify the exception is thrown for invalid YAML
rg -A 2 -B 2 "invalid.*YAML|assertThrows|->expectException" tests/
```

Length of output: 21306

---



</details>

**Action Required: Use a Specific Exception and Add Test Coverage**

- Replace the generic `Exception` with a more specific exception, for example:
  ```diff
  if (! $validation['valid']) {
  -    throw new Exception($validation['error']);
  +    throw new \InvalidArgumentException('Invalid YAML content: ' . $validation['error']);
  }
  ```
- There’s no test verifying this failure case in **CreateJournalTemplate**. Please add tests to ensure that invalid YAML content results in the appropriate exception being thrown.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        if (! $validation['valid']) {
            throw new \InvalidArgumentException('Invalid YAML content: ' . $validation['error']);
        }
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 38-38: app/Services/CreateJournalTemplate.php#L38
Added line #L38 was not covered by tests

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:06Z
author_association: NONE
diff_hunk: @@ -0,0 +1,162 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Tests\Feature\Controllers\Administration;
+
+use App\Models\Account;
+use App\Models\JournalTemplate;
+use App\Models\User;
+use Illuminate\Foundation\Testing\RefreshDatabase;
+use Tests\TestCase;
+
+class AdministrationPersonalizationJournalTemplateControllerTest extends TestCase
+{
+    use RefreshDatabase;
+
+    private User $user;
+
+    private Account $account;
+
+    private string $validYaml = <<<'YAML'
+template:
+  name: "Daily Reflection"
+  columns:
+    - name: "Morning"
+      questions:
+        - name: "Sleep quality"
+          answers:
+            type: "range"
+            range: [1, 5]
+            comment_allowed: true
+YAML;
+
+    protected function setUp(): void
+    {
+        parent::setUp();
+
+        $this->account = Account::factory()->create();
+        $this->user = User::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+    }
+
+    /** @test */
+    public function it_displays_the_new_template_page(): void
+    {
+        $response = $this->actingAs($this->user)
+            ->get(route('administration.personalization.journal-templates.new'));
+
+        $response->assertStatus(200);
+        $response->assertViewIs('administration.personalization.journal-template-add');
+    }
+
+    /** @test */
+    public function it_creates_a_journal_template(): void
+    {
+        $response = $this->actingAs($this->user)
+            ->post(route('administration.personalization.journal-templates.create'), [
+                'name' => 'Test Template',
+                'content' => $this->validYaml,
+            ]);
+
+        $response->assertRedirect(route('administration.personalization.index'));
+        $response->assertSessionHas('success');
+    }
+
+    /** @test */
+    public function it_displays_the_edit_template_page(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->get(route('administration.personalization.journal-templates.edit', $template->id));
+
+        $response->assertStatus(200);
+        $response->assertViewIs('administration.personalization.journal-template-edit');
+        $response->assertViewHas('journalTemplate');
+    }
+
+    /** @test */
+    public function it_cant_edit_template_from_another_account(): void
+    {
+        $anotherAccount = Account::factory()->create();
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $anotherAccount->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->get(route('administration.personalization.journal-templates.edit', $template->id));
+
+        $response->assertStatus(404);
+    }
+
+    /** @test */
+    public function it_updates_a_journal_template(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->put(route('administration.personalization.journal-templates.update', $template->id), [
+                'name' => 'Updated Template',
+                'content' => $this->validYaml,
+            ]);
+
+        $response->assertRedirect(route('administration.personalization.index'));
+        $response->assertSessionHas('success');
+
+        $this->assertDatabaseHas('journal_templates', [
+            'id' => $template->id,
+        ]);
+    }
+
+    /** @test */
+    public function it_deletes_a_journal_template(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->delete(route('administration.personalization.journal-templates.destroy', $template->id));
+
+        $response->assertRedirect(route('administration.personalization.index'));
+        $response->assertSessionHas('success');
+
+        $this->assertDatabaseMissing('journal_templates', [
+            'id' => $template->id,
+        ]);
+    }
+
+    /** @test */
+    public function it_validates_required_fields_when_creating(): void
+    {
+        $response = $this->actingAs($this->user)
+            ->post(route('administration.personalization.journal-templates.create'), [
+                'name' => '',
+                'content' => '',
+            ]);
+
+        $response->assertSessionHasErrors(['name', 'content']);
+    }
+
+    /** @test */
+    public function it_validates_required_fields_when_updating(): void
+    {
+        $template = JournalTemplate::factory()->create([
+            'account_id' => $this->account->id,
+        ]);
+
+        $response = $this->actingAs($this->user)
+            ->put(route('administration.personalization.journal-templates.update', $template->id), [
+                'name' => '',
+                'content' => '',
+            ]);
+
+        $response->assertSessionHasErrors(['name', 'content']);
+    }
path: tests/Feature/Controllers/Administration/AdministrationPersonalizationJournalTemplateControllerTest.php
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**The validation tests check for required fields but not invalid YAML content.**

While you test for empty required fields, there's no test for the case where invalid YAML content is provided, which would trigger the exception in the ValidateYamlStructure service.

Consider adding tests for invalid YAML:

```php
/** @test */
public function it_validates_yaml_content_when_creating(): void
{
    $response = $this->actingAs($this->user)
        ->post(route('administration.personalization.journal-templates.create'), [
            'name' => 'Test Template',
            'content' => 'invalid: yaml: content: - missing proper structure',
        ]);

    $response->assertRedirect(route('administration.personalization.journal-templates.new'));
    $response->assertSessionHasErrors(['content']);
}

/** @test */
public function it_validates_yaml_content_when_updating(): void
{
    $template = JournalTemplate::factory()->create([
        'account_id' => $this->account->id,
    ]);

    $response = $this->actingAs($this->user)
        ->put(route('administration.personalization.journal-templates.update', $template->id), [
            'name' => 'Updated Template',
            'content' => 'invalid: yaml: content: - missing proper structure',
        ]);

    $response->assertRedirect(route('administration.personalization.journal-templates.edit', $template->id));
    $response->assertSessionHasErrors(['content']);
}
```

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:06Z
author_association: NONE
diff_hunk: @@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Http\Controllers\Administration;
+
+use App\Http\Controllers\Controller;
+use App\Models\JournalTemplate;
+use App\Services\CreateJournalTemplate;
+use App\Services\DestroyJournalTemplate;
+use App\Services\UpdateJournalTemplate;
+use Exception;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
+
+class AdministrationPersonalizationJournalTemplateController extends Controller
+{
+    public function new(): View
+    {
+        return view('administration.personalization.journal-template-add');
+    }
+
+    public function create(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        try {
+            (new CreateJournalTemplate(
+                user: Auth::user(),
+                name: $validated['name'],
+                content: $validated['content'],
+            ))->execute();
+        } catch (Exception $e) {
+            return redirect()->route('administration.personalization.journal-templates.new')
+                ->withInput()
+                ->withErrors(['content' => $e->getMessage()]);
+        }
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template created successfully'));
+    }
+
+    public function edit(Request $request): View
+    {
+        $journalTemplateId = (int) $request->route()->parameter('journalTemplate');
+
+        $journalTemplate = JournalTemplate::findOrFail($journalTemplateId);
+
+        if ($journalTemplate->account_id !== Auth::user()->account_id) {
+            abort(404);
+        }
+
+        return view('administration.personalization.journal-template-edit', [
+            'journalTemplate' => $journalTemplate,
+        ]);
+    }
+
+    public function update(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
+
+        (new UpdateJournalTemplate(
+            user: Auth::user(),
+            journalTemplate: $journalTemplate,
+            name: $validated['name'],
+            content: $validated['content'],
+        ))->execute();
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template updated successfully'));
+    }
+
+    public function destroy(Request $request): RedirectResponse
+    {
+        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
+
+        (new DestroyJournalTemplate(
+            user: Auth::user(),
+            journalTemplate: $journalTemplate,
+        ))->execute();
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template deleted successfully'));
+    }
path: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Missing access control check in the destroy method.**

Similar to the update method, you're missing the check to ensure the journal template belongs to the user's account in the destroy method.

Add the same access control check:

```diff
 $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));

+if ($journalTemplate->account_id !== Auth::user()->account_id) {
+    abort(404);
+}
```

Or ideally, use Laravel's authorization system for more consistent access control across all methods.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    public function destroy(Request $request): RedirectResponse
    {
        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));

        if ($journalTemplate->account_id !== Auth::user()->account_id) {
            abort(404);
        }

        (new DestroyJournalTemplate(
            user: Auth::user(),
            journalTemplate: $journalTemplate,
        ))->execute();

        return redirect()->route('administration.personalization.index')
            ->with('success', __('Journal template deleted successfully'));
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:06Z
author_association: NONE
diff_hunk: @@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Http\Controllers\Administration;
+
+use App\Http\Controllers\Controller;
+use App\Models\JournalTemplate;
+use App\Services\CreateJournalTemplate;
+use App\Services\DestroyJournalTemplate;
+use App\Services\UpdateJournalTemplate;
+use Exception;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
+
+class AdministrationPersonalizationJournalTemplateController extends Controller
+{
+    public function new(): View
+    {
+        return view('administration.personalization.journal-template-add');
+    }
+
+    public function create(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        try {
+            (new CreateJournalTemplate(
+                user: Auth::user(),
+                name: $validated['name'],
+                content: $validated['content'],
+            ))->execute();
+        } catch (Exception $e) {
+            return redirect()->route('administration.personalization.journal-templates.new')
+                ->withInput()
+                ->withErrors(['content' => $e->getMessage()]);
+        }
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template created successfully'));
+    }
+
+    public function edit(Request $request): View
+    {
+        $journalTemplateId = (int) $request->route()->parameter('journalTemplate');
+
+        $journalTemplate = JournalTemplate::findOrFail($journalTemplateId);
+
+        if ($journalTemplate->account_id !== Auth::user()->account_id) {
+            abort(404);
+        }
+
+        return view('administration.personalization.journal-template-edit', [
+            'journalTemplate' => $journalTemplate,
+        ]);
+    }
+
+    public function update(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
+
+        (new UpdateJournalTemplate(
+            user: Auth::user(),
+            journalTemplate: $journalTemplate,
+            name: $validated['name'],
+            content: $validated['content'],
+        ))->execute();
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template updated successfully'));
+    }
path: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Missing try-catch for YAML validation in update method.**

Similar to the create method, you should catch exceptions from the UpdateJournalTemplate service to handle YAML validation errors. Unlike the create method, there's no exception handling here.

Add a try-catch block similar to the create method:

```diff
 public function update(Request $request): RedirectResponse
 {
     $validated = $request->validate([
         'name' => 'required|string',
         'content' => 'required|string',
     ]);

     $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));

+    try {
         (new UpdateJournalTemplate(
             user: Auth::user(),
             journalTemplate: $journalTemplate,
             name: $validated['name'],
             content: $validated['content'],
         ))->execute();
+    } catch (Exception $e) {
+        return redirect()->route('administration.personalization.journal-templates.edit', $journalTemplate->id)
+            ->withInput()
+            ->withErrors(['content' => $e->getMessage()]);
+    }

     return redirect()->route('administration.personalization.index')
         ->with('success', __('Journal template updated successfully'));
 }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    public function update(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'name' => 'required|string',
            'content' => 'required|string',
        ]);

        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));

        try {
            (new UpdateJournalTemplate(
                user: Auth::user(),
                journalTemplate: $journalTemplate,
                name: $validated['name'],
                content: $validated['content'],
            ))->execute();
        } catch (Exception $e) {
            return redirect()->route('administration.personalization.journal-templates.edit', $journalTemplate->id)
                ->withInput()
                ->withErrors(['content' => $e->getMessage()]);
        }

        return redirect()->route('administration.personalization.index')
            ->with('success', __('Journal template updated successfully'));
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:06Z
author_association: NONE
diff_hunk: @@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Http\Controllers\Administration;
+
+use App\Http\Controllers\Controller;
+use App\Models\JournalTemplate;
+use App\Services\CreateJournalTemplate;
+use App\Services\DestroyJournalTemplate;
+use App\Services\UpdateJournalTemplate;
+use Exception;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
+
+class AdministrationPersonalizationJournalTemplateController extends Controller
+{
+    public function new(): View
+    {
+        return view('administration.personalization.journal-template-add');
+    }
+
+    public function create(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        try {
+            (new CreateJournalTemplate(
+                user: Auth::user(),
+                name: $validated['name'],
+                content: $validated['content'],
+            ))->execute();
+        } catch (Exception $e) {
+            return redirect()->route('administration.personalization.journal-templates.new')
+                ->withInput()
+                ->withErrors(['content' => $e->getMessage()]);
+        }
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template created successfully'));
+    }
+
+    public function edit(Request $request): View
+    {
+        $journalTemplateId = (int) $request->route()->parameter('journalTemplate');
+
+        $journalTemplate = JournalTemplate::findOrFail($journalTemplateId);
+
+        if ($journalTemplate->account_id !== Auth::user()->account_id) {
+            abort(404);
+        }
+
+        return view('administration.personalization.journal-template-edit', [
+            'journalTemplate' => $journalTemplate,
+        ]);
+    }
+
+    public function update(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));
path: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Add access control check in the update method.**

You're missing the check to ensure the journal template belongs to the user's account in the update method.

Add the same access control check as in the edit method:

```diff
 $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));

+if ($journalTemplate->account_id !== Auth::user()->account_id) {
+    abort(404);
+}
```

Or ideally, use Laravel's authorization system as suggested earlier.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
        $journalTemplate = JournalTemplate::findOrFail($request->route()->parameter('journalTemplate'));

        if ($journalTemplate->account_id !== Auth::user()->account_id) {
            abort(404);
        }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:06Z
author_association: NONE
diff_hunk: @@ -0,0 +1,95 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\Http\Controllers\Administration;
+
+use App\Http\Controllers\Controller;
+use App\Models\JournalTemplate;
+use App\Services\CreateJournalTemplate;
+use App\Services\DestroyJournalTemplate;
+use App\Services\UpdateJournalTemplate;
+use Exception;
+use Illuminate\Http\RedirectResponse;
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\View\View;
+
+class AdministrationPersonalizationJournalTemplateController extends Controller
+{
+    public function new(): View
+    {
+        return view('administration.personalization.journal-template-add');
+    }
+
+    public function create(Request $request): RedirectResponse
+    {
+        $validated = $request->validate([
+            'name' => 'required|string',
+            'content' => 'required|string',
+        ]);
+
+        try {
+            (new CreateJournalTemplate(
+                user: Auth::user(),
+                name: $validated['name'],
+                content: $validated['content'],
+            ))->execute();
+        } catch (Exception $e) {
+            return redirect()->route('administration.personalization.journal-templates.new')
+                ->withInput()
+                ->withErrors(['content' => $e->getMessage()]);
+        }
+
+        return redirect()->route('administration.personalization.index')
+            ->with('success', __('Journal template created successfully'));
+    }
path: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php
user: login: coderabbitai[bot]
body: _💡 Verification agent_

<details>
<summary>🧩 Analysis chain</summary>

**Add try-catch for YAML validation in your create action.**

The create method properly validates required fields and uses the CreateJournalTemplate service. However, the static analysis shows that the exception handling block (lines 38-41) is not covered by tests.

---

🏁 Script executed:

```shell
#!/bin/bash
# Check how the CreateJournalTemplate service validates YAML
grep -A 20 "validate" "$(fd "CreateJournalTemplate.php" --type f)"
```

Length of output: 880

---



</details>

**Ensure YAML validation exceptions are tested in your create action.**  
The try-catch block in the create method is correctly in place to handle errors thrown from the YAML validation in the CreateJournalTemplate service. However, our static analysis indicates that the exception handling branch (lines 38–41) isn’t covered by tests. Please add or update tests to simulate a YAML validation failure (e.g., by providing invalid YAML content) and verify that the error handling behaves as expected.  

- Verify that the ValidateYamlStructure service throws an exception for invalid YAML.
- Update tests to ensure that the catch block properly captures and handles these exceptions with the expected error message.

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 GitHub Check: codecov/patch</summary>

[warning] 38-41: app/Http/Controllers/Administration/AdministrationPersonalizationJournalTemplateController.php#L38-L41
Added lines #L38 - L41 were not covered by tests

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-28T21:29:06Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-03-28T20:46:37Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

<details>
<summary>📝 Walkthrough</summary>

## Summary by CodeRabbit

- **New Features**
  - Launched journal template management in the admin panel with capabilities to create, edit, and delete templates using YAML-formatted content. Dedicated pages, forms, and routes have been added to support these operations.

- **Style**
  - Updated UI elements, including button alignment and breadcrumb formatting, to enhance overall consistency and user experience.

- **Tests**
  - Expanded test coverage to ensure reliable validation and functionality for journal template operations.
## Walkthrough

This pull request introduces new functionality for managing journal templates in the administration panel. A new controller is added with methods to display forms and process create, update, and delete operations. The creation and update services now include YAML validation by leveraging a modified validator class. New Blade templates have been introduced for adding and editing journal templates, and existing list views have been updated. Additional routes and tests were added to support these features, and minor UI and configuration adjustments were applied.

## Changes

| File(s) | Change Summary |
|---------|----------------|
| `app/Http/Controllers/.../AdministrationPersonalizationJournalTemplateController.php`<br>`routes/web.php`<br>`tests/Feature/Controllers/.../AdministrationPersonalizationJournalTemplateControllerTest.php` | Introduced a new controller for journal templates with methods for creating, editing, updating, and deleting templates; added corresponding routes and feature tests. |
| `app/Services/CreateJournalTemplate.php`<br>`app/Services/UpdateJournalTemplate.php`<br>`app/Services/ValidateYamlStructure.php` | Enhanced YAML validation: added a private `validate()` method in the creation service, updated the update service’s validation logic, and modified the YAML validator to use a constructor property with an updated execute signature. |
| `resources/views/administration/personalization/partials/journal-templates.blade.php`<br>`resources/views/administration/personalization/journal-template-add.blade.php`<br>`resources/views/administration/personalization/journal-template-edit.blade.php` | Added new Blade templates for adding and editing journal templates and updated the listing view with revised variables, route links, and identifiers. |
| `resources/views/components/button/secondary.blade.php`<br>`resources/views/layouts/handbook.blade.php` | Modified UI elements by adding the `text-center` class to buttons and refining breadcrumb HTML indentation in the handbook layout. |
| `tests/Unit/Services/CreateJournalTemplateTest.php`<br>`tests/Unit/Services/UpdateJournalTemplateTest.php`<br>`tests/Unit/Services/ValidateYamlStructureTest.php` | Updated unit tests to use structured YAML input and reflect the constructor changes for YAML validation. |
| `config/marketing-timestamps.php` | Standardized timestamp formats by replacing timezone offsets with the UTC “Z” suffix in configuration entries. |

</details>

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=djaiss/peopleOS&utm_content=161):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai plan` to trigger planning for file edits and PR creation.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: codecov[bot]
created_at: 2025-03-28T20:47:54Z
body: ## [Codecov](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd) Report
Attention: Patch coverage is `91.37931%` with `5 lines` in your changes missing coverage. Please review.
> Project coverage is 75.97%. Comparing base [(`16af33c`)](https://app.codecov.io/gh/djaiss/peopleOS/commit/16af33cca02571a457325110d313522561a22017?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd) to head [(`309f917`)](https://app.codecov.io/gh/djaiss/peopleOS/commit/309f917e2b8df389bc3f31fe2649ce89f9bb4f83?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd).
> Report is 1 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd) | Patch % | Lines |
|---|---|---|
| [...rationPersonalizationJournalTemplateController.php](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?src=pr&el=tree&filepath=app%2FHttp%2FControllers%2FAdministration%2FAdministrationPersonalizationJournalTemplateController.php&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd#diff-YXBwL0h0dHAvQ29udHJvbGxlcnMvQWRtaW5pc3RyYXRpb24vQWRtaW5pc3RyYXRpb25QZXJzb25hbGl6YXRpb25Kb3VybmFsVGVtcGxhdGVDb250cm9sbGVyLnBocA==) | 91.66% | [4 Missing :warning: ](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd) |
| [app/Services/CreateJournalTemplate.php](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?src=pr&el=tree&filepath=app%2FServices%2FCreateJournalTemplate.php&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd#diff-YXBwL1NlcnZpY2VzL0NyZWF0ZUpvdXJuYWxUZW1wbGF0ZS5waHA=) | 80.00% | [1 Missing :warning: ](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd) |

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff              @@
##               main     #161      +/-   ##
============================================
+ Coverage     75.80%   75.97%   +0.17%     
- Complexity      853      863      +10     
============================================
  Files           190      191       +1     
  Lines          4843     4899      +56     
============================================
+ Hits           3671     3722      +51     
- Misses         1172     1177       +5     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/djaiss/peopleOS/pull/161?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Regis+Freyd).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>
author_association: NONE