Compare commits

...

9 Commits

Author SHA1 Message Date
Naser Mansour 7d762902a2 Bump Nablus workshop flyer size for readability
max-h-40 (160px) was too small to read comfortably; bumped to max-h-56
(224px), between that and the original too-large 256px. Rebuilt frontend
assets and confirmed the class compiled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 00:15:23 +03:00
Naser Mansour 7b708d2fd7 Match Nablus workshop form's background/card styling to the rest of the site
Reused existing, already-compiled design-system pieces instead of ad hoc
inline colors: the login page's auth-pattern background (public/images/
auth-pattern.svg) on the standalone layout, and the reusable <x-ui.card
highlight> component (Warm Gold accent border) for the form card. Replaced
inline style="color: #2D322A" with the text-body token.

Also fixes the actual root cause behind "the picture still looks the same"
from the prior two tasks: public/build's compiled CSS was stale (last built
Jan 17, before this session), so max-h-40/max-h-64 were never in the
generated stylesheet. Rebuilt via npm run build and verified the new classes
compile; production has its own deploy-time build so this shouldn't recur
there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 00:12:07 +03:00
Naser Mansour 4258b5d2e7 Remove logo and shrink flyer further on Nablus workshop form
Logo image removed entirely from the registration page per Naser's request;
flyer capped to max-h-40 (was max-h-64). Pure markup/styling change, no
logic — 7/7 existing tests unchanged and passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 00:03:43 +03:00
Naser Mansour ecdad8dbd2 Shrink oversized flyer image and logo on Nablus workshop form
Flyer capped to max-h-64 (was w-full, ~640x853px dominating the page); logo
reduced to h-10 (was h-16), matching the site's own sm-logo convention.
Pure styling change, no logic — 7/7 existing tests unchanged and passing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 00:00:47 +03:00
Naser Mansour 690c22395f Replace logo with client-supplied artwork; add Nablus workshop registration form
- public/images/logo.png replaced with the client's professionally-designed
  version, cropped to remove excess background margin (used sitewide via
  logo.blade.php / app-logo.blade.php / app-logo-icon.blade.php)
- New standalone, unlinked registration form at /forms/nablus-workshop for a
  one-off workshop Libra is co-hosting with Smart Business Center, replicating
  a ClickUp form the client previously used but with Libra's own branding.
  Submissions email info@libra.adv.ps and redirect to /about. No nav/footer
  link, no DB storage, no captcha (PRD v1.3).
- Tasks 17 (parent), 17-1 (Mailable + email template), 17-2 (page/route/form)
  taken through product-definition -> task-readiness -> dev-implement -> dev-qa,
  all Done. 11 new tests passing; full suite run clean of new regressions
  (69 pre-existing unrelated failures, documented in docs/tasks/17.md).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 23:56:50 +03:00
Naser Mansour 1b66e0b6ff Add full-codebase security report
First full scan (no docs/security-kb.md yet). 2 High, 3 Medium, 3 Low,
4 Informational findings — most notable: national_id stored/exported in
plaintext despite architecture.md claiming encryption, and a confirmed
CVE (CVE-2026-48019, CVSS 8.9) affecting the installed laravel/framework
12.43.1 via the guest-booking form's Mail::to() call. Report only — no
fixes applied, per the security-scan skill's non-capabilities.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 22:13:54 +03:00
Naser Mansour a8316cfc82 Reconcile pipeline docs with manual commits made outside the pipeline (Jan 2026)
Checked all 21 manual commits between abde8698 and 147231f (pre-dating
today's takeover) against the newly-built docs/tasks/ and docs/ux-design.md.
Two real conflicts found and fixed:

- Scholarship Aspiration section (task 16-6) was built, then fully removed
  from /about in production (commit e8c1730, 2026-01-11) — task title and
  ux-design.md corrected to say REMOVED, do not re-implement.
- Two-factor authentication was disabled in config/fortify.php at client
  request (commit f8d9133, 2026-01-17) — CLAUDE.md and ux-design.md
  corrected to say the 2FA code path is dormant, not live.

Everything else in that range (copy edits, mail/SMTP fixes, autorefresh bug
fixes, footer brand wording, php-fpm production notes already captured in
CLAUDE.md) doesn't contradict anything in the pipeline docs — no edit needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 22:08:08 +03:00
Naser Mansour 7f35297025 Mark all libra tasks Done — confirmed live in production ~1 year
Naser confirmed all remaining QA Review / Draft rows (97 subtasks, 16
parent rollups) are done in substance: the site has been in production
for roughly a year. Overrides the conservative QA-Review/Draft mapping
from the prior takeover commit (0f9d12c) at his explicit instruction.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 22:04:04 +03:00
Naser Mansour 0f9d12c3cf Prepare project for pipeline takeover: task tracker, UX doc, CLAUDE.md pointers
Adds docs/tasks/ (16 epics + 102 stories converted to task/subtask files with
statuses.md as the new status source of truth) and docs/ux-design.md
(retrospective design-system reference), and points CLAUDE.md at them.
docs/prd.md and docs/architecture.md are kept as BMAD wrote them; the legacy
docs/stories/, docs/epics/, docs/qa/gates/ and .bmad-core/ stay in place as
historical/traceability records, superseded but not deleted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 22:02:23 +03:00
139 changed files with 4834 additions and 3 deletions
+16 -3
View File
@@ -85,7 +85,17 @@ php artisan make:model ModelName -mf
- `app/Enums/` - UserType, UserStatus, ConsultationType, ConsultationStatus, PaymentStatus, TimelineStatus, PostStatus
- `docs/prd.md` - Full product requirements document
- `docs/architecture.md` - Complete architecture document
- `docs/stories/` - User story specifications
- `docs/ux-design.md` - Design system reference (colors, typography, layout, components — retrospective, written 2026-09-27)
- `docs/tasks/` - **Current task/status tracker** (`statuses.md` is the status source of truth). One row per epic (parent) and per story (subtask), e.g. `3.md` / `3-4.md`.
- `docs/stories/`, `docs/epics/`, `docs/qa/gates/` - **Legacy.** Original BMAD-agent build records (98→102 stories across 16 epics). Kept for implementation history and traceability, no longer the status source — `docs/tasks/statuses.md` superseded them 2026-09-27. `.bmad-core/` and `.claude/commands/BMad/` are the retired BMAD toolchain, also kept but unused.
## Pipeline takeover (2026-09-27)
This project was built by BMAD agents and has been handed to a different pipeline (Jarvis/ElenosLabs
tooling) for any further work. `docs/tasks/statuses.md` is now authoritative for what's open — most
subtasks are `QA Review` (BMAD's "Ready for Review" with no final close-out), a couple are `Draft`
(never started: `3-9` guest booking request, `13-5` auth-page visual QA). Cross-check a task's own
`docs/stories/story-<id>-*.md` file for full history/QA notes before starting new work on it.
### Services
- `app/Services/AvailabilityService.php` - Calculates available time slots for bookings
@@ -113,7 +123,7 @@ Core models in `app/Models/`:
/admin/* - Admin dashboard (requires admin middleware)
/client/* - Client dashboard
/settings/* - User settings (profile, password, 2FA, appearance)
/settings/* - User settings (profile, password, appearance; 2FA route only registers if the feature is re-enabled, see below)
```
### Middleware
@@ -125,7 +135,10 @@ Core models in `app/Models/`:
### Authentication (Fortify)
All auth is handled via Fortify with custom Volt views. Features enabled:
- Email verification, Password reset, Profile/password updates
- Two-factor authentication with QR codes and recovery codes
- Two-factor authentication (QR codes + recovery codes) is **disabled in production** — commented
out in `config/fortify.php` at client request (2026-01-17). `routes/web.php` only registers
`settings/two-factor` when `Features::canManageTwoFactorAuthentication()` is true, so the code
path still exists but is currently dormant. Don't re-enable without confirming with Naser first.
- Note: Public registration is disabled; admin creates all client accounts
### Volt Component Pattern
+59
View File
@@ -0,0 +1,59 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class WorkshopRegistrationMail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(
public string $fullName,
public string $contactNumber,
public ?string $email,
) {}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'تسجيل جديد - ورشة عمل ريادايات نابلس',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'emails.workshop-registration.ar',
with: [
'fullName' => $this->fullName,
'contactNumber' => $this->contactNumber,
'email' => $this->email,
],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
+37
View File
@@ -1105,6 +1105,43 @@ All emails in both Arabic and English based on user preference:
| 1.0 | Nov 26, 2025 | Initial PRD creation | Development Team |
| 1.1 | Dec 20, 2025 | Added brand identity section, clarified booking rules (1/day, 45min), multiple timelines, account management (deactivate/delete), exports, analytics, Terms/Privacy pages | Development Team |
| 1.2 | Jan 3, 2026 | Added guest booking functionality: public booking form at /booking, custom captcha, 1-per-day limit, guest email notifications, admin guest booking management | Development Team |
| 1.3 | Sep 27, 2026 | Added standalone Nablus workshop registration form (unlinked page at /forms/nablus-workshop) — see Update below | Development Team |
---
## Update — Version 1.3
**Date:** 2026-09-27
### New Features Added
**Nablus workshop registration form.** Libra's client is co-hosting a one-off entrepreneurship
workshop ("ورشة متخصصة: القانون، التسويق الرقمي، وإدارة المتاجر الإلكترونية") on 2026-09-30 with
"Smart Business Center." They previously used a generic ClickUp form to collect registrations and
asked for their own branded version instead. Scope, per Naser:
- A single standalone page at `/forms/nablus-workshop`, reachable only by direct link (Naser sends
the URL to the client to forward to attendees) — **not** added to the site's header/nav/footer.
- Replicates the ClickUp form's content and 3 fields: **الاسم الكامل** (full name, required),
**رقم التواصل** (contact number, required), **ايميلك للتواصل** (email, optional).
- Page carries the workshop's own copy (title, description, full agenda paragraph — same text as
the event flyer) and uses Libra's real branding: the current logo (`public/images/logo.png`)
and the workshop flyer image (client-supplied, to be added to the project as a static asset).
Arabic RTL only — no English variant needed for this page.
Page is RTL Arabic, standalone (no site nav/footer chrome), matching Libra's Warm Cream / Dark
Forest Green / Warm Gold palette.
- On submit: send an email containing the submitted values to `info@libra.adv.ps`, then redirect
the visitor to the existing `/about` page. No database storage required — this is a short-lived,
few-days-only registration page for one event; emailing the submission is the only durable
record needed.
- No captcha, no admin UI, no listing of past submissions — intentionally minimal scope.
### Scope Changes
None to existing features. This is additive only.
### Open Questions
None outstanding — all decisions confirmed directly with Naser in the same session.
---
+111
View File
@@ -0,0 +1,111 @@
# Security Report
**Project:** Libra Law Firm
**Scan date:** 2026-09-27
**Scope:** full codebase
---
## Summary
This is a static-analysis-only review of `app/`, `resources/views/livewire/`, `routes/`, `config/`, `database/migrations/`, and `bootstrap/` (excluding `vendor/`, `node_modules/`, `storage/`, `.git/`, `docs/`, `.bmad-core/`). The scan followed the priority order below. The most significant finding is that `national_id` — despite `docs/architecture.md` §13.4 documenting it as encrypted-at-rest — is stored, displayed, exported and audit-logged in **plaintext** throughout the codebase; no encrypted cast exists on the `User` model. No SQL injection was found in the reviewed files (Eloquent/query-builder used consistently with parameter binding). No findings at Critical severity in the files reviewed.
## Scan order followed
1. Authentication & session handling, input validation, injection
2. Authorization & access control (admin/client role checks, IDOR)
3. Sensitive data exposure & cryptography
4. Remaining checklist: XSS, mass assignment, dependencies, misconfiguration, CORS, headers
5. Guest-facing surfaces (booking form, `CaptchaService`)
## Findings
### [HIGH] — `national_id` stored, displayed, exported, and audit-logged in plaintext, contradicting documented encryption
- **File:** `app/Models/User.php:24-47` (fillable/hidden, no cast); `database/migrations/0001_01_01_000000_create_users_table.php:18` (`$table->string('national_id')`); `resources/views/livewire/admin/clients/individual/show.blade.php:64`; `resources/views/livewire/admin/clients/individual/index.blade.php:145`; `resources/views/livewire/admin/users/export-users.blade.php:52`; `resources/views/livewire/admin/clients/individual/edit.blade.php:57,78`; `resources/views/livewire/admin/clients/individual/create.blade.php:61`
- **Severity:** High
- **Confidence:** High
- **Description:** `docs/architecture.md` §13.4 documents an `Attribute::make(get: decrypt, set: encrypt)` cast for `national_id` on `User`. No such cast exists in the actual model — `national_id` is a plain `string` column, mass-assignable, and only excluded from array/JSON serialization via `$hidden` (which doesn't protect direct DB access, backups, or explicit `->only([...])` reads). It is displayed in cleartext in the admin client show/index views, included in CSV user exports, and copied verbatim into `AdminLog.old_values`/`new_values` on every create/update (see next finding) — multiplying the exposure surface for a national ID number (sensitive PII for a law firm's clients) well beyond what the architecture doc claims is protected.
- **Recommendation:** Either implement the encrypted-attribute cast the architecture document already specifies (Laravel's `encrypted` cast type is a one-line change: `'national_id' => 'encrypted'`), or update `docs/architecture.md` to reflect actual practice and add compensating controls (restrict export/display, exclude from audit-log payloads). Decide deliberately — don't leave the documentation and code disagreeing.
### [HIGH] — Guest email address user-supplied to `Mail::to()` on a Laravel version vulnerable to CVE-2026-48019 (CRLF injection in email validation)
- **File:** `resources/views/livewire/pages/booking.blade.php:78,168` (`'guestEmail' => ['required','email',...]` then `Mail::to($this->guestEmail)->queue(...)`); `composer.lock` — `laravel/framework` pinned at `v12.43.1`
- **Severity:** High
- **Confidence:** High
- **Description:** Confirmed via WebSearch: GHSA-5vg9-5847-vvmq / CVE-2026-48019 (CVSS 8.9) is a CRLF injection vulnerability in Laravel's default `email` validation rule, in combination with how Symfony Mailer/Mime handle certain byte sequences, affecting all `laravel/framework` versions below `12.60.0` (fixed in 12.60.0 and 13.10.0). This app's installed version is `12.43.1`, inside the vulnerable range, and the unauthenticated guest booking form passes a user-supplied email address (validated only with Laravel's stock `email` rule) directly into `Mail::to()`. Per the advisory, an unauthenticated attacker may be able to interfere with outbound mail content/recipients under this condition.
- **Recommendation:** Upgrade `laravel/framework` to `^12.60` (or `^13.10` if a major upgrade is in scope) — do not implement a custom mitigation in place of the vendor patch. No `docs/security-kb.md` exists yet to track this class of issue; recommend creating one so future dependency bumps get checked against known advisories systematically rather than ad hoc.
### [MEDIUM] — Timeline "initial note" stored without HTML sanitization, then rendered unescaped to both admin and client
- **File:** `resources/views/livewire/admin/timelines/create.blade.php:87` (`'update_text' => $this->initialNotes` — no `clean()`); rendered raw at `resources/views/livewire/client/timelines/show.blade.php:49`, `resources/views/livewire/admin/timelines/show.blade.php:311`, `resources/views/emails/timeline-update.blade.php:19,44`, `resources/views/emails/timeline/update/{ar,en}.blade.php:17`
- **Severity:** Medium
- **Confidence:** High
- **Description:** Every other `update_text` write path in the codebase runs the value through `clean()` (HTMLPurifier via `mews/purifier`) before saving — see `resources/views/livewire/admin/timelines/show.blade.php:46,84`. The *initial* note created alongside a new timeline (`admin/timelines/create.blade.php`) skips this and stores raw input, which is then output with `{!! !!}` (unescaped) in the client-facing timeline view, the admin timeline view, and outbound emails. Admin is currently the single trusted operator, so this isn't exploitable by an outside attacker directly, but it is an inconsistency in a defense-in-depth control: if the admin's account or session were ever compromised (credential phishing, XSS elsewhere, session hijack — 2FA is currently disabled for this account per `config/fortify.php`, raising the value of protecting this account further), this is the one write path that would let injected markup/script persist and execute in the client's authenticated session, not just the admin's own.
- **Recommendation:** Route `initialNotes` through the same `clean()` call used everywhere else `update_text` is written, for consistency with the rest of the codebase's own sanitization pattern.
### [MEDIUM] — `email_verified_at` / `verified` middleware not enforced on any protected route
- **File:** `routes/web.php` (admin/client/settings groups use `Route::middleware(['auth', 'active'])...` — no `verified`); `docs/architecture.md` §7.1/§9.2 documents `auth, verified, admin` / `auth, verified, active` as the intended stack
- **Severity:** Medium
- **Confidence:** Medium
- **Description:** Fortify's `emailVerification()` feature is enabled (`config/fortify.php:149`), implying email ownership is meant to gate access, and the architecture doc explicitly lists `verified` in the admin and client middleware stacks. The actual `routes/web.php` never applies Laravel's `verified` middleware anywhere — only `auth` and `active`. Since accounts are admin-created (no public registration) impact is reduced, but it means a client account created with a mistyped or attacker-influenced email address is fully usable (dashboard, timelines, consultations) without ever confirming that mailbox, and the documented control isn't actually the one in force. Judgment call on whether this was an intentional simplification or a regression belongs to whoever owns this project's requirements, not to this scan.
- **Recommendation:** Either add `verified` back into the `admin`/`client`/`settings` middleware groups to match the documented design, or update `docs/architecture.md` to state that verification is informational-only for this app and explain why.
### [MEDIUM] — Weak, low-entropy guest-booking captcha combined with per-IP-only rate limiting
- **File:** `app/Services/CaptchaService.php:14-26` (single-digit-sum math question, session-stored); `resources/views/livewire/pages/booking.blade.php:119-126` (`RateLimiter` keyed only on `request()->ip()`, 5/24h)
- **Severity:** Medium
- **Confidence:** Medium
- **Description:** The captcha answer space is tiny (sum of two numbers 1–10, i.e. 2–20, ~19 possible answers) with no image/behavioral challenge, so a scripted client can solve it by brute force without needing OCR — it primarily filters unsophisticated bots, not a determined scripted one. The only additional control is a rate limit keyed solely on `request()->ip()`, which is trivially defeated by rotating source IPs/proxies (common for scripted abuse), and the 1-per-email/day check (`booking.blade.php:92-102`) only limits repeats from the *same* guest email, not overall volume. Together these leave the public, unauthenticated booking form exposed to scripted spam/abuse of the booking calendar and of the guest's own inbox (see next finding).
- **Recommendation:** Consider a higher-entropy or interaction-based challenge (e.g., a proper CAPTCHA/Turnstile) for the public booking form, and/or a global (not just per-email) submission rate limit for guest bookings, independent of the per-IP limiter.
### [LOW] — Guest booking form sends a "confirmation" email to an arbitrary, unauthenticated-supplied address
- **File:** `resources/views/livewire/pages/booking.blade.php:167-170` (`Mail::to($this->guestEmail)->queue(new GuestBookingSubmittedMail($consultation))`)
- **Severity:** Low
- **Confidence:** Medium
- **Description:** `guestEmail` is only validated as a well-formed email address (`'guestEmail' => ['required','email','max:255']`) — it is never confirmed to belong to the submitter. Combined with the weak captcha/rate-limiting above, this lets an attacker cause automated emails (containing a booking confirmation, and the submitted `problemSummary` text) to be delivered to a third party's inbox of the attacker's choosing, at low but nonzero volume (5 submissions per IP per 24h). This is a mail-relay/nuisance vector, not data exposure of an existing account.
- **Recommendation:** Low priority; if this becomes an actual abuse vector in practice, consider requiring email confirmation before dispatching the guest-facing notification, independent of the admin notification.
### [LOW] — No security-headers middleware present despite being documented
- **File:** `app/Http/Middleware/` (only `SetLocale`, `EnsureUserIsAdmin`, `EnsureUserIsClient`, `EnsureUserIsActive` exist); `bootstrap/app.php:16-24`; contrast with `docs/architecture.md` §13.3 (`ContentSecurityPolicy` middleware, CSP/X-Frame-Options/X-Content-Type-Options/Referrer-Policy)
- **Severity:** Low
- **Confidence:** High
- **Description:** The architecture document specifies a `ContentSecurityPolicy` middleware setting CSP, `X-Content-Type-Options`, `X-Frame-Options`, `X-XSS-Protection`, and `Referrer-Policy` headers. No such middleware exists anywhere in `app/Http/Middleware/`, and `bootstrap/app.php`'s middleware registration doesn't reference one. The app currently ships with none of Laravel's non-default security headers set, relying only on framework/browser defaults.
- **Recommendation:** Implement the documented headers middleware (or adopt a maintained package for it) if this level of hardening is still wanted; otherwise correct the architecture doc.
### [LOW] — `.env.example` omits `SESSION_SECURE_COOKIE`, no `config/cors.php` published
- **File:** `.env.example` (no `SESSION_SECURE_COOKIE` key at all); `config/` (no `cors.php` file)
- **Severity:** Low
- **Confidence:** Medium
- **Description:** `docs/architecture.md` §13.1 lists `SESSION_SECURE_COOKIE=true` as a documented security measure, but `.env.example` — the template a deployer copies to build a production `.env` — has no `SESSION_SECURE_COOKIE` line at all, so `config/session.php:172`'s `env('SESSION_SECURE_COOKIE')` silently resolves to `null`/falsy unless someone remembers to add it by hand at deploy time. Separately, no `config/cors.php` is published; since this app has no `/api/*` routes, the practical exposure is minimal (Laravel's built-in `HandleCors` default only applies to `api/*` by default), but its absence should be a deliberate choice, not an oversight, if that ever changes.
- **Recommendation:** Add `SESSION_SECURE_COOKIE=true` to `.env.example` (and confirm the production `.env` on the actual server sets it — out of scope for this static scan, see below). Publish `config/cors.php` explicitly if any API-style routes are ever added.
### [INFORMATIONAL] — Local `.env` reviewed, no live secrets found; not a production file
- **File:** `.env`, `.gitignore:1-3`
- **Severity:** Informational
- **Confidence:** High
- **Description:** `.env` is correctly excluded from git (`.gitignore` lists `.env`, `.env.backup`, `.env.production`). Its contents are local-development values only (`APP_ENV=local`, `APP_DEBUG=true`, root DB user with no password, localhost mail catcher, no AWS/mail credentials populated) — no live secrets are present in this repository checkout. `APP_DEBUG=true` is appropriate for local but must not carry into production; this scan cannot confirm the production server's actual `.env` (out of scope, see below).
- **Recommendation:** None needed for this file as reviewed. Confirm separately (via `infra-ops`/production access, not this scan) that the production `.env` sets `APP_DEBUG=false`.
### [INFORMATIONAL] — IDOR checks manually verified as present on key client-facing record views
- **File:** `resources/views/livewire/client/timelines/show.blade.php:10-13` (`abort_unless($timeline->user_id === auth()->id(), 403)`); `routes/web.php` client consultation-calendar closure (`abort_unless($consultation->user_id === auth()->id(), 403)`); `resources/views/livewire/client/consultations/index.blade.php:15-43` (scoped to `auth()->user()->consultations()`)
- **Severity:** Informational
- **Confidence:** High
- **Description:** Checked specifically for the scenario the task called out — a client viewing another client's consultation/timeline by guessing an ID. All three client-facing record-access paths reviewed do explicitly scope to the authenticated user, either via an `abort_unless` ownership check on route-model-bound records or by querying through the `auth()->user()->consultations()` relation rather than the bare model. No IDOR found in these paths.
- **Recommendation:** None. Noting this as a confirmed-safe pattern so it isn't re-flagged as a gap by a future scan without re-checking.
### [INFORMATIONAL] — XSS output-encoding spot checks passed on other rich-text paths
- **File:** `resources/views/livewire/pages/posts/index.blade.php:25-39` (`highlightSearch()` escapes both text and search term via `e()` before wrapping in `<mark>`); `resources/views/livewire/admin/posts/{create,edit}.blade.php`, `resources/views/livewire/admin/pages/edit.blade.php`, `resources/views/pages/legal.blade.php:6` (all route admin-authored rich text through `clean()` / HTMLPurifier before storage or display)
- **Severity:** Informational
- **Confidence:** High
- **Description:** All other `{!! !!}` (unescaped) output sites reviewed pair the raw output with sanitization at write time (`clean()`) or with pre-escaping (`e()`) before HTML-wrapping, except for the timeline `initial notes` path already flagged above.
- **Recommendation:** None beyond the Medium finding already listed.
---
## What was NOT checked
- **Runtime behavior.** Nothing in this codebase was executed, run, or tested; all findings are static code review only.
- **The live production server / hosting configuration** (69.62.106.94, PHP-FPM config, actual production `.env`, TLS/HTTPS enforcement, firewall, MariaDB hardening). Confirming `APP_DEBUG=false` and `SESSION_SECURE_COOKIE=true` on the real production `.env` is explicitly out of scope here and was not verified.
- **Third-party API/service behavior** — the SMTP provider, any queue worker/Supervisor process behavior, actual mail deliverability.
- **Infrastructure-as-code / deployment scripts** referenced in `docs/architecture.md` §16 (CI pipeline, `deploy.sh`, `rollback.sh`) were not audited as part of this application-code scan.
- **Excluded directories per scope:** `vendor/`, `node_modules/`, `storage/`, `.git/`, `docs/`, `.bmad-core/`.
- **Dependency/CVE coverage is spot-check only, not exhaustive.** No `docs/security-kb.md` exists yet for this project (no prior stack-aware CVE research has been done), so the dependency review above covered only the highest-traffic packages (`laravel/framework`, `mews/purifier`) via targeted WebSearch, not the full `composer.lock`/`package-lock.json` dependency tree. The one CVE cited (CVE-2026-48019 / GHSA-5vg9-5847-vvmq) was independently confirmed via search, not fabricated; no other CVE numbers are claimed in this report. A full dependency audit (building `docs/security-kb.md`) is recommended as separate follow-up work.
- **Frontend/JS dependencies** (`package.json`/`package-lock.json`, Tailwind 4/Vite build) were not cross-checked against advisories.
- **Business-logic abuse beyond IDOR/spam** (e.g., booking-slot race conditions beyond what's visible in the `DB::transaction`/`lockForUpdate` calls already in `booking.blade.php`) was not exhaustively modeled.
+24
View File
@@ -0,0 +1,24 @@
---
id: 1-1
title: 1-1 Project Setup & Database Schema
status: Done
date: 2026-09-27
parent: 1
---
## Description
As a developer, I want the Laravel 12 project configured with all required packages and complete database schema, So that the foundation is established for all subsequent feature development. Full implementation history: docs/stories/story-1.1-project-setup-database-schema.md
## Acceptance Criteria
- [ ] Laravel 12 project created with Livewire 3, Volt, Flux UI
- [ ] Tailwind CSS 4 configured with `@theme` directive
- [ ] Database migrations for all core tables:
- [ ] Model factories created for testing
- [ ] Development environment working (`composer run dev`)
- [ ] SQLite configured for development database
- [ ] All migrations run without errors
- [ ] Factories generate valid test data
- [ ] All database tables have proper indexes
- [ ] Foreign key constraints properly defined
+35
View File
@@ -0,0 +1,35 @@
---
id: 1-2
title: 1-2 Authentication & Role System
status: Done
date: 2026-09-27
parent: 1
---
## Description
As an admin, I want a secure authentication system with Admin/Client roles, So that only authorized users can access the platform with appropriate permissions. Full implementation history: docs/stories/story-1.2-authentication-role-system.md
## Acceptance Criteria
- [ ] Fortify configured with custom Volt views
- [ ] Login page with bilingual support (Arabic/English)
- [ ] Session timeout after 2 hours of inactivity
- [ ] Rate limiting on login attempts (5 attempts per minute)
- [ ] Admin role with full access to all features
- [ ] Client role with restricted access (own data only)
- [ ] Registration feature DISABLED (admin creates all accounts)
- [ ] CSRF protection enabled on all forms
- [ ] Password hashing using bcrypt
- [ ] Custom middleware for admin authorization
- [ ] Secure session configuration
- [ ] Remember me functionality (optional)
- [ ] Login redirects to appropriate dashboard:
- [ ] Logout clears session properly and redirects to login page
- [ ] Admin middleware protects admin-only routes (return 403 for unauthorized)
- [ ] Failed login attempts logged to `admin_logs` table
- [ ] Deactivated users cannot log in
- [ ] Login form validates inputs properly
- [ ] Error messages are clear and bilingual
- [ ] All test scenarios in "Testing" section pass
- [ ] No security vulnerabilities
+39
View File
@@ -0,0 +1,39 @@
---
id: 1-3
title: 1-3 Bilingual Infrastructure (Arabic/English)
status: Done
date: 2026-09-27
parent: 1
---
## Description
As a user (admin or client), I want full bilingual support with Arabic as primary and English as secondary language, So that I can use the platform in my preferred language with proper RTL/LTR layout. Context: Integrates with: Laravel localization, Tailwind CSS, user preferences; Technology: Laravel lang files, Tailwind RTL, Google Fonts; Follows pattern: Laravel localization best practices. Full implementation history: docs/stories/story-1.3-bilingual-infrastructure.md
## Acceptance Criteria
- [ ] Language files for Arabic (ar) and English (en)
- [ ] Language toggle in navigation (visible on all pages)
- [ ] User language preference stored in `users.preferred_language`
- [ ] Guest language stored in session (persists across page loads)
- [ ] RTL layout for Arabic, LTR for English
- [ ] All UI elements translatable via `__()` helper
- [ ] Language switch preserves current page (redirect back to same URL)
- [ ] Form validation messages display in current locale
- [ ] Missing translations fall back to key name (not break page)
- [ ] Arabic: DD/MM/YYYY format
- [ ] English: MM/DD/YYYY format
- [ ] Both: 12-hour time format (AM/PM)
- [ ] Both: Western numerals (123) - no Arabic numerals
- [ ] Arabic fonts: Cairo or Tajawal (Google Fonts)
- [ ] English fonts: Montserrat or Lato (Google Fonts)
- [ ] Font weights: 300, 400, 600, 700
- [ ] font-display: swap for performance
- [ ] Language middleware sets locale from user preference or session
- [ ] Direction attribute (`dir="rtl"` or `dir="ltr"`) on HTML element
- [ ] Tailwind RTL utilities working
- [ ] Forms align correctly in both directions
- [ ] No hardcoded strings in views
- [ ] All translation keys organized by feature
- [ ] Tests verify language switching
- [ ] No layout breaks when switching languages
+50
View File
@@ -0,0 +1,50 @@
---
id: 1-4
title: 1-4 Base UI & Navigation
status: Done
date: 2026-09-27
parent: 1
---
## Description
As a website visitor or logged-in user, I want a professional, responsive navigation system with brand colors, So that I can easily navigate the platform on any device. Context: Integrates with: Flux UI Free, Tailwind CSS 4, bilingual system; Technology: Livewire Volt, Flux UI components, Alpine.js; Follows pattern: Flux UI navbar patterns, mobile-first design. - **Logo SVG:** Required at public/images/logo.svg - **Fallback:** Text "Libra" in gold displayed if logo asset not available - **Logo Specs:** SVG format preferred, min 120px width desktop, 80px mobile - **Note:** Logo asset to be provided by client; use text fallback during development. Full implementation history: docs/stories/story-1.4-base-ui-navigation.md
## Acceptance Criteria
- [ ] Primary: Dark Navy Blue (#0A1F44) - backgrounds, headers
- [ ] Accent: Gold (#D4AF37) - buttons, links, accents
- [ ] Light Gold: #F4E4B8 - hover states
- [ ] Off-White/Cream: #F9F7F4 - cards, content areas
- [ ] Charcoal Gray: #2C3E50 - secondary text
- [ ] Custom Tailwind colors configured via @theme
- [ ] Fixed top position
- [ ] Navy blue background
- [ ] Logo placement: left on desktop, centered on mobile
- [ ] Main menu items: Home, Booking, Posts, Login/Dashboard
- [ ] Language toggle (Arabic/English) visible
- [ ] Responsive mobile hamburger menu
- [ ] Gold text for links, hover effects
- [ ] Full-width dropdown or slide-in
- [ ] Navy background with gold text
- [ ] Touch-friendly targets (44px+ height)
- [ ] Smooth open/close animation
- [ ] Close on outside click or navigation
- [ ] Navy blue background
- [ ] Libra logo (smaller version)
- [ ] Firm contact information
- [ ] Links: Terms of Service, Privacy Policy
- [ ] Copyright notice with current year
- [ ] Sticky footer (always at bottom of viewport)
- [ ] Card-based layouts with proper shadows and border-radius
- [ ] Consistent spacing using Tailwind utilities
- [ ] Container max-width: 1200px, centered
- [ ] WCAG AA contrast compliance verified
- [ ] Flux UI components used where available
- [ ] Works with RTL and LTR layouts
- [ ] Navigation state reflects current page
- [ ] Login/logout state reflected in menu
- [ ] Responsive on all breakpoints (mobile, tablet, desktop)
- [ ] No horizontal scroll on any viewport
- [ ] Fast loading (minimal CSS/JS)
- [ ] Tests verify navigation rendering
+21
View File
@@ -0,0 +1,21 @@
---
id: 1
title: 1 Core Foundation & Infrastructure
status: Done
date: 2026-09-27
---
## Description
Establishes the foundational Laravel 12 application: authentication with Admin/Client roles via Fortify, full bilingual (Arabic/English) infrastructure with RTL/LTR layout switching, and the base UI/navigation shell that every later epic builds on.
## Acceptance Criteria
- [ ] Laravel 12 project configured and running
- [ ] Database schema designed and migrations created
- [ ] Fortify authentication working (login only, no self-registration)
- [ ] Admin and Client roles implemented with proper authorization
- [ ] Bilingual infrastructure (Arabic primary, English secondary)
- [ ] RTL/LTR layout switching functional
- [ ] Base UI framework with brand colors (Navy #0A1F44, Gold #D4AF37)
- [ ] Navigation system with language toggle
+22
View File
@@ -0,0 +1,22 @@
---
id: 10-1
title: 10-1 Core CSS Theme Update
status: Done
date: 2026-09-27
parent: 10
---
## Description
As a developer I want to update the Tailwind CSS theme color variables So that the application uses the new LIBRA for Rights brand palette. - resources/css/app.css - Main theme file. Full implementation history: docs/stories/story-10.1-core-css-theme-update.md
## Acceptance Criteria
- [ ] AC1: Update Color Variables in `resources/css/app.css`: Given the current theme uses Navy Blue + Gold palette; When I update the `@theme` block; Then the following color mappings are applied:
- [ ] AC2: Maintain Backward Compatibility Aliases: Given existing components use `navy`, `gold`, `cream` class names; When the theme is updated; Then aliases are created so existing classes continue to work:
- [ ] AC3: Update Semantic Aliases: Given semantic aliases exist for components; When theme is updated; Then these mappings are correct:
- [ ] AC4: Update Button Styles: Given button classes use gold/navy colors; When theme is updated; Then `.btn-primary` and `.btn-secondary` use new palette:
- [ ] AC5: Update Form Focus States: Given form inputs have gold focus rings; When theme is updated; Then focus states use Warm Gray:
- [ ] AC6: Update Prose Class: Given `.prose-navy` class exists for blog content; When theme is updated; Then rename to `.prose-brand` or update colors:
- [ ] AC7: Status Colors Unchanged: Given status colors serve functional purposes; When theme is updated; Then these remain unchanged:
- [ ] AC8: WCAG AA Contrast Compliance: Given accessibility requirements; When new colors are applied; Then all text/background combinations meet WCAG AA:
+27
View File
@@ -0,0 +1,27 @@
---
id: 10-2
title: 10-2 Blade Component Color Migration
status: Done
date: 2026-09-27
parent: 10
---
## Description
As a developer I want to update all Blade components and pages to use the new color palette So that the entire application has consistent branding. Full implementation history: docs/stories/story-10.2-blade-component-color-migration.md
## Acceptance Criteria
- [ ] AC1: Navigation Component Updated: Given `resources/views/components/navigation.blade.php` uses old colors; When I update the component; Then the following changes are applied:
- [ ] AC2: Footer Component Updated: Given `resources/views/components/footer.blade.php` uses old colors; When I update the component; Then the following changes are applied:
- [ ] AC3: Logo Component Updated: Given `resources/views/components/logo.blade.php` references logo files; When I update the component; Then it references the correct logo variant for the background
- [ ] AC4: Language Toggle Updated: Given `resources/views/components/language-toggle.blade.php` uses old colors; When I update the component; Then colors match new palette
- [ ] AC5: Card Components Updated: Given card components use old colors; When I update `resources/views/components/ui/card.blade.php`; Then the following changes are applied:
- [ ] AC6: Stat Card Component Updated: Given `resources/views/components/ui/stat-card.blade.php` uses old colors; When I update the component; Then colors match new palette
- [ ] AC7: Spinner Component Updated: Given `resources/views/components/spinner.blade.php` uses old colors; When I update the component; Then spinner uses Charcoal or Warm Gray
- [ ] AC8: Toast Component Updated: Given `resources/views/components/toast.blade.php` uses old colors; When I update the component; Then colors match new palette (status colors remain unchanged)
- [ ] AC9: Public Pages Updated: Given public pages use old colors; When I update the following pages; Then they use the new palette:
- [ ] AC10: Post Pages Updated: Given post display pages use old colors; When I update the following pages; Then they use the new palette:
- [ ] AC11: Public Layout Updated: Given `resources/views/components/layouts/public.blade.php` uses old colors; When I update the layout; Then it uses the new palette
- [ ] AC12: RTL Layout Integrity: Given the application supports RTL (Arabic); When colors are updated; Then RTL layout displays correctly with new colors
- [ ] AC13: Responsive Appearance: Given the application is responsive; When colors are updated; Then all breakpoints display correctly (mobile, tablet, desktop)
+22
View File
@@ -0,0 +1,22 @@
---
id: 10-3
title: 10-3 Email Template Color Update
status: Done
date: 2026-09-27
parent: 10
---
## Description
As a developer I want to update email templates to use the new brand colors So that all email communications reflect the new LIBRA for Rights branding. **Theme CSS:** - resources/views/vendor/mail/html/themes/default.css. Full implementation history: docs/stories/story-10.3-email-template-color-update.md
## Acceptance Criteria
- [ ] AC1: Email Theme CSS Updated: Given `resources/views/vendor/mail/html/themes/default.css` uses old colors; When I update the stylesheet; Then the following changes are applied:
- [ ] AC2: Email Header Component Updated: Given `resources/views/vendor/mail/html/header.blade.php` may have inline styles; When I update the component; Then any inline color references use new palette
- [ ] AC3: Email Footer Component Updated: Given `resources/views/vendor/mail/html/footer.blade.php` may have inline styles; When I update the component; Then any inline color references use new palette
- [ ] AC4: Button Component Updated: Given `resources/views/vendor/mail/html/button.blade.php` may have inline styles; When I update the component; Then primary buttons use:
- [ ] AC5: Panel Component Updated: Given `resources/views/vendor/mail/html/panel.blade.php` may have inline styles; When I update the component; Then panel border uses Warm Gray (`#C9C4BA`)
- [ ] AC6: Email Logo Updated: Given email header displays the logo; When emails are sent; Then the logo matches the new brand identity
- [ ] AC7: All Email Templates Tested: Given the application sends various email types; When I test each email template; Then colors display correctly:
- [ ] AC8: Plain Text Fallback Unaffected: Given plain text email templates exist; When colors are updated; Then plain text templates continue to work (no color changes needed)
+22
View File
@@ -0,0 +1,22 @@
---
id: 10-4
title: 10-4 PDF Template Color Update
status: Done
date: 2026-09-27
parent: 10
---
## Description
As a developer I want to update PDF export templates to use the new brand colors So that all exported documents reflect the new LIBRA for Rights branding. **PDF Templates:** - resources/views/pdf/users-export.blade.php - resources/views/pdf/consultations-export.blade.php - resources/views/pdf/timelines-export.blade.php - resources/views/pdf/monthly-report.blade.php. Full implementation history: docs/stories/story-10.4-pdf-template-color-update.md
## Acceptance Criteria
- [ ] AC1: Users Export PDF Updated: Given `resources/views/pdf/users-export.blade.php` uses old colors; When I update the template; Then the following changes are applied:
- [ ] AC2: Consultations Export PDF Updated: Given `resources/views/pdf/consultations-export.blade.php` uses old colors; When I update the template; Then colors match the new brand palette
- [ ] AC3: Timelines Export PDF Updated: Given `resources/views/pdf/timelines-export.blade.php` uses old colors; When I update the template; Then colors match the new brand palette
- [ ] AC4: Monthly Report PDF Updated: Given `resources/views/pdf/monthly-report.blade.php` uses old colors; When I update the template; Then the following changes are applied:
- [ ] AC5: Monthly Report Service Updated: Given `app/Services/MonthlyReportService.php` may contain color references; When I review the service; Then any hardcoded colors are updated to new palette
- [ ] AC6: PDF Logo Updated: Given PDF templates include the logo; When PDFs are generated; Then the logo matches the new brand identity
- [ ] AC7: Print-Friendly Colors: Given PDFs are often printed; When colors are updated; Then they remain legible when printed in grayscale
- [ ] AC8: All PDF Exports Tested: Given the admin can export various data types; When I test each PDF export; Then colors display correctly and documents are professional
+22
View File
@@ -0,0 +1,22 @@
---
id: 10-5
title: 10-5 Logo and SVG Assets Update
status: Done
date: 2026-09-27
parent: 10
---
## Description
As a developer I want to update all logo files and SVG assets to match the new brand So that the application displays the correct LIBRA for Rights logo everywhere. **Logo Files:** - public/images/logo.svg - Primary full-color logo - public/images/logo-reversed.svg - For dark backgrounds - public/images/logo-mono.svg - Single-color version - public/images/logo.png - PNG fallback. Full implementation history: docs/stories/story-10.5-logo-assets-update.md
## Acceptance Criteria
- [ ] AC1: Primary Logo Updated: Given `public/images/logo.svg` contains the old Scales of Justice logo with gold colors; When I update or replace the logo; Then the new botanical/wheat logo is displayed with correct colors:
- [ ] AC2: Reversed Logo Updated: Given `public/images/logo-reversed.svg` is for dark backgrounds; When I update or replace the logo; Then the logo displays correctly on Charcoal backgrounds:
- [ ] AC3: Monochrome Logo Updated: Given `public/images/logo-mono.svg` exists for single-color applications; When I update or replace the logo; Then the logo uses appropriate single color from new palette
- [ ] AC4: PNG Logo Updated: Given `public/images/logo.png` is used in some contexts; When I update or replace the logo; Then the PNG matches the new SVG logo
- [ ] AC5: Favicon Updated: Given the application has a favicon; When I review favicon files; Then they are updated to match new brand (if applicable)
- [ ] AC6: Logo Component References Correct Files: Given `resources/views/components/logo.blade.php` references logo files; When I review the component; Then it uses the correct logo variant based on context (light/dark background)
- [ ] AC7: Logo Displays Correctly Throughout App: Given the logo appears in multiple locations; When logos are updated; Then they display correctly in:
- [ ] AC8: Logo Clear Space Maintained: Given brand guidelines specify clear space around logo; When logo is displayed; Then minimum padding/margin is maintained as per `docs/brand.md`
+21
View File
@@ -0,0 +1,21 @@
---
id: 10-6
title: 10-6 Documentation Update
status: Done
date: 2026-09-27
parent: 10
---
## Description
As a developer I want to update all documentation to reflect the new brand colors So that future development references accurate color information. **Core Documentation:** - CLAUDE.md - docs/prd.md - docs/architecture.md - docs/brand.md (verify accuracy). Full implementation history: docs/stories/story-10.6-documentation-update.md
## Acceptance Criteria
- [ ] AC1: CLAUDE.md Updated: Given `CLAUDE.md` contains color guidance; When I update the file; Then the following sections are updated:
- [ ] AC2: PRD Updated: Given `docs/prd.md` contains detailed color specifications; When I update the document; Then the following sections are updated:
- [ ] AC3: Architecture Document Updated: Given `docs/architecture.md` may contain color references; When I review and update the document; Then any color references are updated to new palette
- [ ] AC4: Epic 9 Stories Referenced as Superseded: Given Epic 9 stories implemented the original Navy+Gold palette; When I review Epic 9 story files; Then a note is added indicating colors were updated in Epic 10:
- [ ] AC5: Epic 10 Document Updated: Given `docs/epics/epic-10-brand-color-refresh.md` exists; When all stories are complete; Then the epic document is updated with completion status
- [ ] AC6: brand.md Verified Accurate: Given `docs/brand.md` defines the new brand; When I review the document; Then it accurately describes:
- [ ] AC7: No Stale Color References: Given documentation should be accurate; When I search all markdown files for old hex values; Then no references to old colors remain:
+28
View File
@@ -0,0 +1,28 @@
---
id: 10
title: 10 Brand Color Refresh
status: Done
date: 2026-09-27
---
## Description
A brownfield color migration replacing the original Navy+Gold palette with a Charcoal + Warm Gray earth-tone palette across the whole application: core CSS theme, all Blade components, email templates, PDF templates, logo/SVG assets, and documentation. Superseded again by Epic 12.
## Acceptance Criteria
- [ ] Story 10.1: Core CSS theme updated with new colors
- [ ] Story 10.2: All Blade components using new palette
- [ ] Story 10.3: Email templates updated
- [ ] Story 10.4: PDF templates updated
- [ ] Story 10.5: Logo files updated/replaced
- [ ] Story 10.6: All documentation updated
- [ ] All pages render correctly with new colors
- [ ] WCAG AA contrast compliance verified
- [ ] RTL layout displays correctly
- [ ] Responsive design intact across breakpoints
- [ ] PDF exports display new branding
- [ ] Email templates display new branding
- [ ] Code formatted with Pint
- [ ] All existing tests passing
- [ ] Visual QA completed on all major pages
+30
View File
@@ -0,0 +1,30 @@
---
id: 11-1
title: 11-1 Database Schema & Model Updates
status: Done
date: 2026-09-27
parent: 11
---
## Description
As a developer, I want to extend the consultation system to support guest bookings, So that consultations can be created for both registered clients and anonymous guests. The existing foreign key consultations_user_id_foreign cascades on delete. With nullable user_id: - Guest consultations won't be affected by user deletions (they have no user) - Client consultations still cascade delete when user is deleted. Full implementation history: docs/stories/story-11.1-database-schema-model-updates.md
## Acceptance Criteria
- [ ] `user_id` column changed to nullable on `consultations` table
- [ ] `guest_name` column added (varchar 255, nullable)
- [ ] `guest_email` column added (varchar 255, nullable)
- [ ] `guest_phone` column added (varchar 50, nullable)
- [ ] Index added on `guest_email` for 1-per-day lookup performance
- [ ] Migration is reversible without data loss
- [ ] Existing consultations with `user_id` unaffected
- [ ] `Consultation` model updated with new fillable fields
- [ ] `isGuest()` helper method returns true when `user_id` is null
- [ ] `getClientName()` helper returns guest_name or user->full_name
- [ ] `getClientEmail()` helper returns guest_email or user->email
- [ ] `getClientPhone()` helper returns guest_phone or user->phone
- [ ] Model validation ensures either user_id OR guest fields are present
- [ ] `ConsultationFactory` updated with `guest()` state
- [ ] Guest state generates fake guest_name, guest_email, guest_phone
- [ ] Guest state sets user_id to null
+45
View File
@@ -0,0 +1,45 @@
---
id: 11-2
title: 11-2 Public Booking Form with Custom Captcha
status: Done
date: 2026-09-27
parent: 11
---
## Description
As a website visitor, I want to request a consultation without creating an account, So that I can easily reach out to the lawyer for legal assistance. Full implementation history: docs/stories/story-11.2-public-booking-form.md
## Acceptance Criteria
- [ ] `/booking` route displays guest booking form for unauthenticated visitors
- [ ] Logged-in users redirected to `/client/consultations/book`
- [ ] Page uses public layout (`x-layouts.public`)
- [ ] Bilingual support (Arabic/English)
- [ ] Mobile responsive design
- [ ] Reuses existing `availability-calendar` Livewire component
- [ ] Shows available time slots (same as client view)
- [ ] Blocked/booked times not selectable
- [ ] Full name field (required, min 3 chars, max 255)
- [ ] Email field (required, valid email format)
- [ ] Phone field (required, valid format)
- [ ] Problem summary field (required, min 20 chars, max 2000)
- [ ] All fields have clear labels and validation messages
- [ ] Form follows Flux UI patterns
- [ ] Math-based captcha (e.g., "What is 7 + 3?")
- [ ] Question generated server-side, answer stored in session
- [ ] User must enter correct answer to submit
- [ ] Refresh button to get new captcha question
- [ ] Captcha validates before form submission
- [ ] Bilingual captcha labels
- [ ] Check if email has pending/approved booking for selected date
- [ ] If limit reached, show error message and prevent submission
- [ ] Clear error message explaining the limit
- [ ] Limit applies per email address per calendar day
- [ ] Maximum 5 booking attempts per IP per 24 hours
- [ ] Rate limit error shown if exceeded
- [ ] Step 1: Select date/time from calendar
- [ ] Step 2: Fill contact info + problem summary + captcha
- [ ] Step 3: Confirmation screen showing all details
- [ ] Step 4: Submit creates guest consultation (status: pending)
- [ ] Success message with instructions to check email
+33
View File
@@ -0,0 +1,33 @@
---
id: 11-3
title: 11-3 Guest Email Notifications & Admin Integration
status: Done
date: 2026-09-27
parent: 11
---
## Description
As a guest who submitted a booking, I want to receive email confirmations about my booking status, So that I know my request was received and can track its progress. As an admin, I want to see guest contact information when reviewing bookings, So that I can contact them and manage their appointments. Full implementation history: docs/stories/story-11.3-guest-notifications-admin.md
## Acceptance Criteria
- [ ] Guest receives confirmation email when booking submitted
- [ ] Guest receives approval email when booking approved (with date/time details)
- [ ] Guest receives rejection email when booking rejected
- [ ] All emails use existing email template/branding
- [ ] Emails sent to guest_email address
- [ ] Bilingual support based on site locale at submission time
- [ ] Guest bookings appear in pending list alongside client bookings
- [ ] Guest bookings show "Guest" badge/indicator
- [ ] Guest name, email, phone displayed in list
- [ ] Click through to booking review shows full guest details
- [ ] Guest contact info displayed prominently
- [ ] Guest name shown instead of user name
- [ ] Guest email shown with mailto link
- [ ] Guest phone shown with tel link
- [ ] Approve/reject workflow works for guest bookings
- [ ] Email notifications sent to guest on status change
- [ ] `NewBookingAdminEmail` updated to handle guest bookings
- [ ] Admin email shows guest contact info for guest bookings
- [ ] Admin email shows client info for client bookings
+28
View File
@@ -0,0 +1,28 @@
---
id: 11-4
title: 11-4 Documentation Updates
status: Done
date: 2026-09-27
parent: 11
---
## Description
As a developer or stakeholder, I want documentation to accurately reflect guest booking functionality, So that future development and maintenance has accurate reference material. Full implementation history: docs/stories/story-11.4-documentation-updates.md
## Acceptance Criteria
- [ ] Section 5.4 (Booking & Consultation System) updated with guest booking flow
- [ ] Guest vs client booking distinction documented
- [ ] 1-per-day limit for guests documented
- [ ] Custom captcha requirement documented
- [ ] Rate limiting rules documented
- [ ] Guest data handling documented
- [ ] Database schema section updated with guest fields
- [ ] Change log entry added
- [ ] CaptchaService documented in Services section
- [ ] Guest booking flow documented
- [ ] Database schema changes noted
- [ ] Any new patterns or services mentioned if needed
- [ ] Epic 11 marked as complete
- [ ] All story checkboxes marked done
+23
View File
@@ -0,0 +1,23 @@
---
id: 11
title: 11 Guest Booking
status: Done
date: 2026-09-27
---
## Description
Extends the booking system to unauthenticated visitors: a public `/booking` form with custom (non-third-party) captcha and a 1-per-day-by-email limit, guest-specific email notifications, and admin visibility/handling of guest requests inside the existing booking review workflow, via new database schema/model support for nullable `user_id`.
## Acceptance Criteria
- [ ] All stories completed with acceptance criteria met
- [ ] Existing client booking tests still pass
- [ ] New tests cover guest booking scenarios
- [ ] Admin can manage guest bookings through existing interface
- [ ] Guest receives appropriate email notifications
- [ ] Custom captcha working correctly
- [ ] 1-per-day limit enforced
- [ ] No regression in existing features
- [ ] Bilingual support (Arabic/English) for guest form and emails
- [ ] PRD and documentation updated
+24
View File
@@ -0,0 +1,24 @@
---
id: 12-1
title: 12-1 Logo Asset Deployment and CSS Layout Updates
status: Done
date: 2026-09-27
parent: 12
---
## Description
As a developer I want to deploy the new square logo with Palestinian tatreez patterns and update CSS layouts So that the application displays the new brand identity correctly throughout the website. **Components:** - resources/views/components/navigation.blade.php - resources/views/components/footer.blade.php - resources/views/components/logo.blade.php - resources/views/components/app-logo.blade.php - resources/views/components/app-logo-icon.blade.php. Full implementation history: docs/stories/story-12.1-logo-asset-deployment.md
## Acceptance Criteria
- [ ] AC1: Logo Files Deployed to Public Directory: Given logo files have been generated in the `logo/` folder; When I deploy them to the public directory; Then the following files are placed correctly:
- [ ] AC2: Navigation Component Updated for Square Logo: Given the navigation uses a horizontal logo layout; When I update `resources/views/components/navigation.blade.php`; Then the following changes are applied:
- [ ] AC3: Footer Component Updated for Square Logo: Given the footer uses the logo; When I update `resources/views/components/footer.blade.php`; Then the following changes are applied:
- [ ] AC4: Logo Blade Component Updated: Given `resources/views/components/logo.blade.php` references logo files; When I update the component; Then it:
- [ ] AC5: Auth Pages Logo Updated: Given auth pages (login, password reset, etc.) display the logo; When I update auth page layouts; Then the square logo displays correctly:
- [ ] AC6: Favicon Displays in Browser Tab: Given the new favicon files are deployed; When I view the application in a browser; Then the botanical design icon appears in:
- [ ] AC7: Mobile App Icons Updated: Given mobile manifest files reference app icons; When I update `public/manifest.json` (if exists) or meta tags; Then mobile icons reference the new files:
- [ ] AC8: Logo Displays Correctly on All Breakpoints: Given the application is responsive; When I test the logo on different screen sizes; Then it displays correctly:
- [ ] AC9: RTL Layout Support: Given the application supports RTL (Arabic); When viewing in Arabic mode; Then the logo displays correctly without mirroring
- [ ] AC10: Old Logo Files Removed: Given old SVG logo files exist; When deployment is complete; Then the following old files are removed or archived:
+23
View File
@@ -0,0 +1,23 @@
---
id: 12-2
title: 12-2 Core CSS Theme Update - Dark Charcoal & Warm Gold Palette
status: Done
date: 2026-09-27
parent: 12
---
## Description
As a developer I want to update the Tailwind CSS theme to use the new dark charcoal and warm gold color palette So that the application reflects the refined LIBRA for Rights brand colors. - resources/css/app.css - Main theme file. Full implementation history: docs/stories/story-12.2-core-css-theme-update.md
## Acceptance Criteria
- [ ] AC1: Update Color Variables in `resources/css/app.css`: Given the current theme uses Olive Green palette; When I update the `@theme` block; Then the following color mappings are applied:
- [ ] AC2: Add Color Variants for UI States: Given the new palette needs hover and active states; When I update the theme; Then these additional variants are defined:
- [ ] AC3: Update Button Styles: Given button classes use the primary/accent colors; When theme is updated; Then `.btn-primary` and `.btn-secondary` use new palette:
- [ ] AC4: Update Form Focus States: Given form inputs have focus rings; When theme is updated; Then focus states use Warm Gold:
- [ ] AC5: Update Link Colors: Given links use accent colors; When theme is updated; Then link colors use warm gold:
- [ ] AC6: Status Colors Unchanged: Given status colors serve functional purposes; When theme is updated; Then these remain unchanged:
- [ ] AC7: WCAG AA Contrast Compliance: Given accessibility requirements; When new colors are applied; Then all text/background combinations meet WCAG AA:
- [ ] AC8: Update Prose Class: Given `.prose-brand` class exists for blog content; When theme is updated; Then prose colors use new palette:
- [ ] AC9: Build Succeeds: Given CSS changes are made; When I run `npm run build`; Then the build completes successfully without errors
+28
View File
@@ -0,0 +1,28 @@
---
id: 12-3
title: 12-3 Blade Component Color Migration - Dark Charcoal & Warm Gold
status: Done
date: 2026-09-27
parent: 12
---
## Description
As a developer I want to update all Blade components and pages to use the new dark charcoal and warm gold palette So that the entire application has consistent branding. Full implementation history: docs/stories/story-12.3-blade-component-color-migration.md
## Acceptance Criteria
- [ ] AC1: Navigation Component Updated: Given `resources/views/components/navigation.blade.php` uses current colors; When I update the component; Then the following changes are applied:
- [ ] AC2: Footer Component Updated: Given `resources/views/components/footer.blade.php` uses current colors; When I update the component; Then the following changes are applied:
- [ ] AC3: Card Components Updated: Given card components use accent colors; When I update `resources/views/components/ui/card.blade.php`; Then the following changes are applied:
- [ ] AC4: Stat Card Component Updated: Given `resources/views/components/ui/stat-card.blade.php` uses colors; When I update the component; Then accent colors use new palette:
- [ ] AC5: Spinner Component Updated: Given `resources/views/components/spinner.blade.php` uses colors; When I update the component; Then spinner uses Warm Gold (`#A68966`)
- [ ] AC6: Toast Component Updated: Given `resources/views/components/toast.blade.php` uses colors; When I update the component; Then default/info toast uses Warm Gold (status colors remain unchanged)
- [ ] AC7: Language Toggle Updated: Given `resources/views/components/language-toggle.blade.php` uses colors; When I update the component; Then :
- [ ] AC8: Public Pages Updated: Given public pages use accent colors; When I update the following pages; Then they use the new palette:
- [ ] AC9: Post Pages Updated: Given post display pages use colors; When I update the following pages; Then they use the new palette:
- [ ] AC10: Admin Dashboard Components Updated: Given admin dashboard uses accent colors; When I update admin components; Then they use new palette:
- [ ] AC11: Client Dashboard Components Updated: Given client dashboard uses accent colors; When I update client components; Then they use new palette consistently
- [ ] AC12: Public Layout Updated: Given `resources/views/components/layouts/public.blade.php` uses colors; When I update the layout; Then it uses the new palette:
- [ ] AC13: RTL Layout Integrity: Given the application supports RTL (Arabic); When colors are updated; Then RTL layout displays correctly with new colors
- [ ] AC14: Responsive Appearance: Given the application is responsive; When colors are updated; Then all breakpoints display correctly (mobile, tablet, desktop)
+22
View File
@@ -0,0 +1,22 @@
---
id: 12-4
title: 12-4 Email Template Color Update - Dark Charcoal & Warm Gold
status: Done
date: 2026-09-27
parent: 12
---
## Description
As a developer I want to update email templates to use the new dark charcoal and warm gold colors So that all email communications reflect the refined LIBRA for Rights branding. **Theme CSS:** - resources/views/vendor/mail/html/themes/default.css. Full implementation history: docs/stories/story-12.4-email-template-color-update.md
## Acceptance Criteria
- [ ] AC1: Email Theme CSS Updated: Given `resources/views/vendor/mail/html/themes/default.css` uses current colors; When I update the stylesheet; Then the following changes are applied:
- [ ] AC2: Email Header Component Updated: Given `resources/views/vendor/mail/html/header.blade.php` has inline styles; When I update the component; Then :
- [ ] AC3: Email Footer Component Updated: Given `resources/views/vendor/mail/html/footer.blade.php` has inline styles; When I update the component; Then any inline color references use new palette:
- [ ] AC4: Button Component Updated: Given `resources/views/vendor/mail/html/button.blade.php` may have inline styles; When I update the component; Then primary buttons use:
- [ ] AC5: Panel Component Updated: Given `resources/views/vendor/mail/html/panel.blade.php` may have inline styles; When I update the component; Then panel border uses Gold Light (`#C4A882`)
- [ ] AC6: All Email Templates Tested: Given the application sends various email types; When I test each email template; Then colors display correctly:
- [ ] AC7: Plain Text Fallback Unaffected: Given plain text email templates exist; When colors are updated; Then plain text templates continue to work (no color changes needed)
- [ ] AC8: Email Client Compatibility: Given emails are viewed in various clients; When I test the templates; Then they render correctly in:
+21
View File
@@ -0,0 +1,21 @@
---
id: 12-5
title: 12-5 PDF Template Color Update - Dark Charcoal & Warm Gold
status: Done
date: 2026-09-27
parent: 12
---
## Description
As a developer I want to update PDF export templates to use the new dark charcoal and warm gold colors So that all exported documents reflect the refined LIBRA for Rights branding. **PDF Templates:** - resources/views/pdf/users-export.blade.php - resources/views/pdf/consultations-export.blade.php - resources/views/pdf/timelines-export.blade.php - resources/views/pdf/monthly-report.blade.php. Full implementation history: docs/stories/story-12.5-pdf-template-color-update.md
## Acceptance Criteria
- [ ] AC1: Users Export PDF Updated: Given `resources/views/pdf/users-export.blade.php` uses current colors; When I update the template; Then the following changes are applied:
- [ ] AC2: Consultations Export PDF Updated: Given `resources/views/pdf/consultations-export.blade.php` uses current colors; When I update the template; Then colors match the new palette:
- [ ] AC3: Timelines Export PDF Updated: Given `resources/views/pdf/timelines-export.blade.php` uses current colors; When I update the template; Then colors match the new palette:
- [ ] AC4: Monthly Report PDF Updated: Given `resources/views/pdf/monthly-report.blade.php` uses current colors; When I update the template; Then the following changes are applied:
- [ ] AC5: Monthly Report Service Updated: Given `app/Services/MonthlyReportService.php` contains color references for charts; When I update the service; Then chart colors use new palette:
- [ ] AC6: Print-Friendly Colors: Given PDFs are often printed; When colors are updated; Then they remain legible when printed:
- [ ] AC7: All PDF Exports Tested: Given the admin can export various data types; When I test each PDF export; Then colors display correctly and documents are professional:
+21
View File
@@ -0,0 +1,21 @@
---
id: 12-6
title: 12-6 Brand Documentation Update - Dark Charcoal & Warm Gold
status: Done
date: 2026-09-27
parent: 12
---
## Description
As a developer I want to update all brand documentation to reflect the new dark charcoal and warm gold color palette So that documentation accurately represents the current brand identity. **Documentation:** - docs/brand.md - Primary brand documentation - CLAUDE.md - Project instructions - docs/architecture.md - Architecture documentation - docs/prd.md - Product requirements. Full implementation history: docs/stories/story-12.6-documentation-update.md
## Acceptance Criteria
- [ ] AC1: Update `docs/brand.md`: Given the brand documentation references old colors; When I update the file; Then the following sections are updated:
- [ ] AC2: Update `CLAUDE.md`: Given CLAUDE.md contains design requirements with old colors; When I update the file; Then the Design Requirements section reflects new palette:
- [ ] AC3: Update `docs/architecture.md` (if applicable): Given architecture docs may reference brand colors; When I review the file; Then any color references are updated to new palette
- [ ] AC4: Update `docs/prd.md` (if applicable): Given PRD may reference brand colors; When I review the file; Then any color references are updated to new palette
- [ ] AC5: Update Test Color Assertions: Given tests may assert specific color values; When I review test files; Then color assertions are updated:
- [ ] AC6: Review and Update Code Comments: Given code comments may reference old color names; When I review key files; Then comments are updated:
- [ ] AC7: Update Logo Generation Instructions (if exists): Given `docs/logo-generation-instructions.md` may exist; When I review the file; Then any color references match new palette
+19
View File
@@ -0,0 +1,19 @@
---
id: 12
title: 12 Branding Refresh (Logo + Color Scheme)
status: Done
date: 2026-09-27
---
## Description
Rolls out the new square LIBRA logo with Palestinian tatreez patterns and a Dark Forest Green + Warm Gold color scheme: logo asset deployment, core CSS theme update, Blade component and email/PDF template color migration, and brand documentation updates. This is the palette that `docs/brand.md` documents as current.
## Acceptance Criteria
- [ ] All stories completed with acceptance criteria met
- [ ] New logo displays correctly across all pages and devices
- [ ] Color scheme is consistent throughout the application
- [ ] Brand documentation is updated
- [ ] No regression in existing features
- [ ] Visual QA completed on major pages
+20
View File
@@ -0,0 +1,20 @@
---
id: 13-1
title: 13-1 Language Toggle Visibility Enhancement
status: Done
date: 2026-09-27
parent: 13
---
## Description
As a user on authentication pages I want to clearly see and interact with the language toggle So that I can easily switch between Arabic and English. - resources/views/components/language-toggle.blade.php. Full implementation history: docs/stories/story-13.1-language-toggle-visibility.md
## Acceptance Criteria
- [ ] AC1: Update Light Variant Text Color: Given the language toggle has a `light` variant for light backgrounds; When viewed on auth pages (white/cream background); Then the inactive language uses `text-primary` (Dark Forest Green #2D3624) instead of `text-body/70`
- [ ] AC2: Update Light Variant Hover State: Given the user hovers over an inactive language option; When the variant is `light`; Then the hover state uses:
- [ ] AC3: Update Light Variant Separator Color: Given the separator `|` between languages; When the variant is `light`; Then it uses `text-primary/50` instead of `text-body/30` for better visibility
- [ ] AC4: Dark Variant Unchanged: Given the language toggle has a `dark` variant for dark backgrounds (navigation bar); When viewed on the public navigation; Then the existing styling remains unchanged:
- [ ] AC5: Active State Unchanged: Given the currently active language; When displayed in either variant; Then it maintains the existing active styling:
- [ ] AC6: Contrast Compliance: Given accessibility requirements; When the light variant is used on Warm Cream background (#F4F1EA); Then the text contrast meets WCAG AA:
+21
View File
@@ -0,0 +1,21 @@
---
id: 13-2
title: 13-2 Auth Layout Split Design Update
status: Done
date: 2026-09-27
parent: 13
---
## Description
As a visitor to the authentication pages I want to see a visually appealing split-screen layout with the LIBRA branding So that the login experience feels professional and aligned with the brand identity. - resources/views/components/layouts/auth/split.blade.php. Full implementation history: docs/stories/story-13.2-auth-split-layout.md
## Acceptance Criteria
- [ ] AC1: Left Panel - Brand Side (Desktop): Given the split layout is viewed on desktop (lg+ breakpoint); When the page loads; Then the left panel displays:
- [ ] AC2: Right Panel - Form Side (Desktop): Given the split layout is viewed on desktop; When the page loads; Then the right panel displays:
- [ ] AC3: Mobile Layout: Given the split layout is viewed on mobile (below lg breakpoint); When the page loads; Then :
- [ ] AC4: RTL (Arabic) Support: Given the user's locale is Arabic; When the split layout renders; Then :
- [ ] AC5: Language Toggle Positioning: Given the language toggle component; When displayed on the split layout; Then :
- [ ] AC6: Remove Inspiring Quotes: Given the existing split layout has inspiring quotes; When the layout is updated; Then the quotes section is removed for a cleaner, branded appearance
- [ ] AC7: Responsive Breakpoints: Given various screen sizes; When the layout responds; Then :
+20
View File
@@ -0,0 +1,20 @@
---
id: 13-3
title: 13-3 Subtle Background Pattern Implementation
status: Done
date: 2026-09-27
parent: 13
---
## Description
As a visitor to the authentication pages I want to see a subtle, elegant background pattern on the form side So that the page feels polished and professionally designed. **Option A: Geometric (Recommended)** - Simple diagonal lines or dots - Clean, modern aesthetic - Easier to create and maintain. Full implementation history: docs/stories/story-13.3-background-pattern.md
## Acceptance Criteria
- [ ] AC1: Create SVG Pattern Asset: Given the need for a subtle background pattern; When the pattern is created; Then :
- [ ] AC2: Pattern Placement: Given the SVG pattern is created; When applied to the auth layout; Then :
- [ ] AC3: Pattern Opacity: Given readability requirements; When the pattern is displayed; Then :
- [ ] AC4: CSS Implementation: Given the pattern asset; When integrated into CSS; Then :
- [ ] AC5: Performance Consideration: Given page load performance; When the pattern loads; Then :
- [ ] AC6: Mobile Compatibility: Given mobile viewport; When pattern is displayed; Then :
+24
View File
@@ -0,0 +1,24 @@
---
id: 13-4
title: 13-4 Auth Pages Migration to Split Layout
status: Done
date: 2026-09-27
parent: 13
---
## Description
As a user accessing any authentication page I want to see the consistent, branded split layout So that all auth pages provide a cohesive, professional experience. Full implementation history: docs/stories/story-13.4-auth-pages-migration.md
## Acceptance Criteria
- [ ] AC1: Login Page Migration: Given the login page at `/login`; When the page loads; Then :
- [ ] AC2: Forgot Password Page Migration: Given the forgot password page at `/forgot-password`; When the page loads; Then :
- [ ] AC3: Reset Password Page Migration: Given the reset password page at `/reset-password/{token}`; When the page loads; Then :
- [ ] AC4: Two-Factor Challenge Page Migration: Given the 2FA challenge page at `/two-factor-challenge`; When the page loads; Then :
- [ ] AC5: Confirm Password Page Migration: Given the confirm password page at `/confirm-password`; When the page loads; Then :
- [ ] AC6: Email Verification Page Migration: Given the email verification page at `/email/verify`; When the page loads; Then :
- [ ] AC7: Update Default Auth Layout: Given the auth layout wrapper (`x-layouts.auth`); When called by auth pages; Then :
- [ ] AC8: RTL Support Verified: Given Arabic language selected; When any auth page loads; Then :
- [ ] AC9: Mobile Responsiveness Verified: Given mobile viewport (below lg breakpoint); When any auth page loads; Then :
- [ ] AC10: Accessibility Maintained: Given accessibility requirements; When auth pages render; Then :
+26
View File
@@ -0,0 +1,26 @@
---
id: 13-5
title: 13-5 Visual QA and Refinement
status: Done
date: 2026-09-27
parent: 13
---
## Description
As a product owner I want to ensure all auth pages look polished and consistent So that users have a professional, trustworthy experience. Full implementation history: docs/stories/story-13.5-visual-qa.md
## Acceptance Criteria
- [ ] AC1: Cross-Browser Testing: Given the updated auth pages; When tested in major browsers; Then all pages render correctly in:
- [ ] AC2: Desktop Viewport Testing: Given desktop viewports; When auth pages are viewed; Then the split layout displays correctly at:
- [ ] AC3: Mobile Viewport Testing: Given mobile viewports; When auth pages are viewed; Then the mobile layout displays correctly at:
- [ ] AC4: RTL Visual Verification: Given Arabic language selected; When all auth pages are viewed; Then :
- [ ] AC5: Logo Visibility Verification: Given the LIBRA logo on the brand panel; When viewed on desktop; Then :
- [ ] AC6: Language Toggle Visibility Verification: Given the language toggle on auth pages; When viewed; Then :
- [ ] AC7: Pattern Subtlety Verification: Given the background pattern; When viewed across all pages; Then :
- [ ] AC8: Form Element Alignment: Given form elements on auth pages; When viewed; Then :
- [ ] AC9: Color Consistency: Given the brand color palette; When auth pages are viewed; Then :
- [ ] AC10: Animation/Transition Polish: Given interactive elements; When interacted with; Then :
- [ ] AC11: Print Stylesheet (Optional): Given a user prints an auth page; When the page is printed; Then :
- [ ] AC12: Fix Any Visual Issues: Given issues discovered during QA; When fixes are needed; Then :
+22
View File
@@ -0,0 +1,22 @@
---
id: 13
title: 13 Authentication Pages Design Enhancement
status: Done
date: 2026-09-27
---
## Description
Redesigns the auth pages (login, forgot/reset password, etc.) from plain layouts into a branded split-screen experience — dark panel with the LIBRA logo on one side, a warm-cream form panel with a subtle background pattern on the other — plus a language-toggle visibility fix, migration of all auth pages to the new layout, and a final cross-browser/viewport visual QA pass.
## Acceptance Criteria
- [ ] All stories completed with acceptance criteria met
- [ ] Language toggle visible and accessible on auth pages
- [ ] Split layout displays correctly on desktop and tablet
- [ ] Mobile layout is functional and attractive
- [ ] RTL (Arabic) layout mirrors correctly
- [ ] Pattern is subtle and professional
- [ ] No regression in auth functionality
- [ ] Visual QA completed on major browsers (Chrome, Firefox, Safari)
- [ ] Accessibility audit passed (contrast ratios, focus states)
+21
View File
@@ -0,0 +1,21 @@
---
id: 14-1
title: 14-1 Hero Section Implementation
status: Done
date: 2026-09-27
parent: 14
---
## Description
As a website visitor I want to see an impactful hero section when I land on the home page So that I immediately understand what Libra offers and how to take action. - resources/views/pages/home.blade.php - Main implementation - lang/en/home.php - English translations - lang/ar/home.php - Arabic translations. Full implementation history: docs/stories/story-14.1-hero-section.md
## Acceptance Criteria
- [ ] AC1: Hero Section Container: Given a visitor lands on the home page; When the page loads; Then a full-width hero section is displayed with:
- [ ] AC2: Tagline Display: Given the hero section; When viewed in English; Then display: "Committed to Justice – Grounded in Dignity – Driven to Advocate"
- [ ] AC3: Introductory Text: Given the hero section below the tagline; When displayed; Then show a brief 1-2 sentence introduction:
- [ ] AC4: Primary CTA Button: Given the hero section; When displayed below the intro text; Then show a primary CTA button:
- [ ] AC5: Secondary CTA Button (Optional): Given the hero section; When displayed next to primary CTA; Then show a secondary CTA button:
- [ ] AC6: Responsive Layout: Given different screen sizes; When viewing the hero section:
- [ ] AC7: RTL Support: Given Arabic language is selected; When viewing the hero section; Then all text and elements align right-to-left correctly
+21
View File
@@ -0,0 +1,21 @@
---
id: 14-2
title: 14-2 About Section with Lawyer Profile
status: Done
date: 2026-09-27
parent: 14
---
## Description
As a website visitor I want to see information about the lawyer behind Libra So that I can trust the firm and understand who will be handling my case. - resources/views/pages/home.blade.php - Add about section - lang/en/home.php - Add translations - lang/ar/home.php - Add translations - public/images/huda-armouche.jpg - Lawyer photo (to be added). Full implementation history: docs/stories/story-14.2-about-section.md
## Acceptance Criteria
- [ ] AC1: Section Container: Given a visitor scrolls past the hero section; When viewing the about section; Then display a section with:
- [ ] AC2: Section Heading: Given the about section; When displayed; Then show a section heading:
- [ ] AC3: Lawyer Photo: Given the about section; When displayed; Then show Huda Armouche's professional photo:
- [ ] AC4: Lawyer Name and Title: Given the about section; When displayed; Then show:
- [ ] AC5: Bio Text: Given the about section; When displayed; Then show a professional bio:
- [ ] AC6: Layout Structure: Given different screen sizes; When viewing the about section:
- [ ] AC7: RTL Support: Given Arabic language is selected; When viewing the about section; Then layout mirrors appropriately (photo on right in RTL if it was on left in LTR)
+21
View File
@@ -0,0 +1,21 @@
---
id: 14-3
title: 14-3 Services Section
status: Done
date: 2026-09-27
parent: 14
---
## Description
As a website visitor I want to see what legal services Libra offers So that I can determine if they can help with my legal needs. - resources/views/pages/home.blade.php - Add services section - lang/en/home.php - Add translations - lang/ar/home.php - Add translations. Full implementation history: docs/stories/story-14.3-services-section.md
## Acceptance Criteria
- [ ] AC1: Section Container: Given a visitor scrolls to the services section; When viewing the section; Then display with:
- [ ] AC2: Section Heading: Given the services section; When displayed; Then show a section heading:
- [ ] AC3: Four Service Cards: Given the services section; When displayed; Then show 4 service cards:
- [ ] AC4: Service Card Design: Given each service card; When displayed; Then include:
- [ ] AC5: Service Descriptions: Given each service card; When displayed; Then show appropriate descriptions:
- [ ] AC6: Grid Layout: Given different screen sizes; When viewing the services section:
- [ ] AC7: RTL Support: Given Arabic language is selected; When viewing the services section; Then cards maintain proper alignment and text direction
+21
View File
@@ -0,0 +1,21 @@
---
id: 14-4
title: 14-4 Values Section
status: Done
date: 2026-09-27
parent: 14
---
## Description
As a website visitor I want to understand Libra's core values So that I can assess if their principles align with my expectations. - resources/views/pages/home.blade.php - Add values section - lang/en/home.php - Add translations - lang/ar/home.php - Add translations. Full implementation history: docs/stories/story-14.4-values-section.md
## Acceptance Criteria
- [ ] AC1: Section Container: Given a visitor scrolls to the values section; When viewing the section; Then display with:
- [ ] AC2: Section Heading: Given the values section; When displayed; Then show a section heading:
- [ ] AC3: Six Value Items: Given the values section; When displayed; Then show 6 values:
- [ ] AC4: Value Item Design: Given each value item; When displayed; Then include:
- [ ] AC5: Grid Layout: Given different screen sizes; When viewing the values section:
- [ ] AC6: Visual Style Options: Given the values display; When implemented; Then choose one of these styles:
- [ ] AC7: RTL Support: Given Arabic language is selected; When viewing the values section; Then items maintain proper alignment and text direction
+23
View File
@@ -0,0 +1,23 @@
---
id: 14-5
title: 14-5 Latest Posts Section
status: Done
date: 2026-09-27
parent: 14
---
## Description
As a website visitor I want to see recent legal articles and updates on the home page So that I can access valuable legal content and see that the firm is active. - resources/views/pages/home.blade.php - Add posts section with data query - lang/en/home.php - Add translations - lang/ar/home.php - Add translations. Full implementation history: docs/stories/story-14.5-latest-posts-section.md
## Acceptance Criteria
- [ ] AC1: Section Container: Given a visitor scrolls to the latest posts section; When viewing the section; Then display with:
- [ ] AC2: Section Heading: Given the latest posts section; When displayed; Then show a section heading:
- [ ] AC3: Display 3 Latest Posts: Given the posts section; When posts exist in the database; Then display the 3 most recent published posts showing:
- [ ] AC4: Post Card Design: Given each post card; When displayed; Then include:
- [ ] AC5: Empty State: Given the posts section; When no published posts exist; Then either:
- [ ] AC6: View All Link: Given the posts section; When posts are displayed; Then show a "View All Articles" / "عرض جميع المقالات" link:
- [ ] AC7: Grid Layout: Given different screen sizes; When viewing the posts section:
- [ ] AC8: RTL Support: Given Arabic language is selected; When viewing the posts section; Then cards and text align right-to-left correctly
- [ ] AC9: Dynamic Data: Given the posts section; When rendered; Then query posts from database:
+20
View File
@@ -0,0 +1,20 @@
---
id: 14-6
title: 14-6 Footer Contact Information Update
status: Done
date: 2026-09-27
parent: 14
---
## Description
As a website visitor I want to see accurate contact information in the footer So that I can reach out to Libra through the correct phone number and address. - resources/views/components/layouts/public.blade.php - Main footer location - OR resources/views/components/footer.blade.php - If footer is a separate component. Full implementation history: docs/stories/story-14.6-footer-update.md
## Acceptance Criteria
- [ ] AC1: Update Phone Number: Given the website footer; When displayed; Then show the phone number: `+970599353502`
- [ ] AC2: Update Address: Given the website footer; When displayed; Then show the address:
- [ ] AC3: Phone Display Format: Given the phone number in footer; When displayed; Then format as:
- [ ] AC4: Contact Section Layout: Given the footer contact area; When displayed; Then include:
- [ ] AC5: RTL Support: Given Arabic language is selected; When viewing the footer; Then address displays in Arabic and layout adjusts for RTL
- [ ] AC6: Consistency Check: Given the footer update; When completed; Then ensure footer displays correctly on:
+26
View File
@@ -0,0 +1,26 @@
---
id: 14
title: 14 Home Page Redesign
status: Done
date: 2026-09-27
---
## Description
Transforms the minimal home page into a full landing page: hero section, an about section featuring lawyer Huda Armouche, a services section, a values section, a latest-posts section pulling live data, and an updated footer with current contact information.
## Acceptance Criteria
- [ ] All 6 stories completed with acceptance criteria met
- [ ] Hero section displays tagline and CTAs correctly
- [ ] About section shows lawyer photo and bio
- [ ] Services section displays 4 generalized services
- [ ] Values section displays 6 values with icons
- [ ] Latest posts section pulls real data from database
- [ ] Footer shows updated phone and address
- [ ] Responsive design works on mobile, tablet, desktop
- [ ] RTL (Arabic) layout displays correctly
- [ ] LTR (English) layout displays correctly
- [ ] All text in translation files (ar/en)
- [ ] Visual consistency with brand guidelines
- [ ] Accessibility standards maintained
+19
View File
@@ -0,0 +1,19 @@
---
id: 15-1
title: 15-1 Database Schema & Model Setup
status: Done
date: 2026-09-27
parent: 15
---
## Description
As an admin I want to have a database structure for potential clients So that I can store and manage prospective client information. Full implementation history: docs/stories/story-15.1-database-model.md
## Acceptance Criteria
- [ ] AC1: Database Migration: Given the system needs to store potential clients; When the migration runs; Then a `potential_clients` table is created with:
- [ ] AC2: PotentialClientType Enum: Given potential clients have different types; When the enum is created; Then `App\Enums\PotentialClientType` contains:
- [ ] AC3: PotentialClient Model: Given the migration exists; When the model is created; Then `App\Models\PotentialClient` includes:
- [ ] AC4: Model Factory: Given tests need potential client data; When the factory is created; Then `Database\Factories\PotentialClientFactory` generates:
- [ ] AC5: Translation Keys: Given the system is bilingual; When translations are added; Then create keys in `lang/en/potential-clients.php` and `lang/ar/potential-clients.php`:
+24
View File
@@ -0,0 +1,24 @@
---
id: 15-2
title: 15-2 Potential Clients List with Type Filter
status: Done
date: 2026-09-27
parent: 15
---
## Description
As an admin I want to view a list of potential clients with filtering capabilities So that I can easily browse and find specific prospective clients. | File | Purpose | |------|---------| | resources/views/livewire/admin/potential-clients/index.blade.php | List Volt component | | routes/web.php | Add route for potential clients |. Full implementation history: docs/stories/story-15.2-list-filter.md
## Acceptance Criteria
- [ ] AC1: Admin Navigation: Given the admin is logged in; When viewing the admin sidebar; Then a "Potential Clients" menu item is visible with an appropriate icon
- [ ] AC2: List Page Header: Given the admin navigates to `/admin/potential-clients`; When the page loads; Then display:
- [ ] AC3: Type Filter: Given the potential clients list; When the filter is displayed; Then a type dropdown includes:
- [ ] AC4: Search Functionality: Given the potential clients list; When the admin types in the search box; Then filter potential clients by name, email, or phone
- [ ] AC5: List Table Display: Given potential clients exist; When viewing the list; Then display a table with columns:
- [ ] AC6: Type Badges: Given potential clients in the list; When displaying the type; Then show colored badges:
- [ ] AC7: Empty State: Given no potential clients exist; When viewing the list; Then display an empty state with:
- [ ] AC8: Pagination: Given more than 10 potential clients exist; When viewing the list; Then display pagination controls
- [ ] AC9: Clear Filters: Given search or type filter is active; When admin clicks "Clear filters"; Then reset all filters to defaults
- [ ] AC10: RTL Support: Given Arabic language is selected; When viewing the potential clients list; Then all text and layout align correctly right-to-left
+26
View File
@@ -0,0 +1,26 @@
---
id: 15-3
title: 15-3 CRUD Operations for Potential Clients
status: Done
date: 2026-09-27
parent: 15
---
## Description
As an admin I want to create, view, edit, and delete potential clients So that I can fully manage my prospective client records. | File | Purpose | |------|---------| | resources/views/livewire/admin/potential-clients/create.blade.php | Create form component | | resources/views/livewire/admin/potential-clients/show.blade.php | View page component | | resources/views/livewire/admin/potential-clients/edit.blade.php | Edit form component |. Full implementation history: docs/stories/story-15.3-crud-operations.md
## Acceptance Criteria
- [ ] AC1: Create Form Access: Given the admin is on the potential clients list; When clicking "Add Potential Client"; Then navigate to `/admin/potential-clients/create`
- [ ] AC2: Create Form Fields: Given the admin is on the create form; When the form is displayed; Then show the following fields:
- [ ] AC3: Create Submission: Given the admin fills the create form; When submitting with valid data; Then create a new potential client record
- [ ] AC4: Create Validation: Given the admin submits the create form; When type is not selected; Then show validation error: "Please select a type" / "يرجى اختيار النوع"
- [ ] AC5: View Page: Given a potential client exists; When the admin clicks the view icon from the list; Then navigate to `/admin/potential-clients/{id}`
- [ ] AC6: View Page Display: Given the admin is viewing a potential client; When the page loads; Then display:
- [ ] AC7: Edit Form Access: Given the admin is viewing a potential client; When clicking "Edit"; Then navigate to `/admin/potential-clients/{id}/edit`
- [ ] AC8: Edit Form Submission: Given the admin modifies the edit form; When submitting with valid data; Then update the potential client record
- [ ] AC9: Delete Confirmation: Given the admin is viewing a potential client; When clicking "Delete"; Then show a confirmation modal with:
- [ ] AC10: Delete Execution: Given the delete confirmation modal is shown; When the admin confirms deletion; Then delete the potential client record
- [ ] AC11: RTL Support: Given Arabic language is selected; When viewing create/edit/view pages; Then all forms and layouts align correctly right-to-left
- [ ] AC12: Cancel Actions: Given the admin is on create or edit form; When clicking "Cancel"; Then navigate back to the previous page (list or view)
+19
View File
@@ -0,0 +1,19 @@
---
id: 15
title: 15 Potential Clients Management
status: Done
date: 2026-09-27
---
## Description
Adds an admin-only lead-tracking system for prospects (individual/company/agency) who don't yet have accounts: a new standalone `PotentialClient` model/table, a filterable list view by client type, and full CRUD, following existing admin interface patterns.
## Acceptance Criteria
- [ ] All stories completed with acceptance criteria met
- [ ] Tests cover CRUD operations and filtering
- [ ] Admin can manage potential clients through new interface
- [ ] No regression in existing features
- [ ] Bilingual support (Arabic/English) for all UI elements
- [ ] Admin navigation updated with new menu item
+22
View File
@@ -0,0 +1,22 @@
---
id: 16-1
title: 16-1 About Page Layout & Hero Section
status: Done
date: 2026-09-27
parent: 16
---
## Description
As a website visitor I want to access a dedicated About Us page So that I can learn about Libra for Rights' identity and purpose. - resources/views/pages/about.blade.php - Main page - lang/en/about.php - English translations - lang/ar/about.php - Arabic translations. Full implementation history: docs/stories/story-16.1-about-page-layout-hero.md
## Acceptance Criteria
- [ ] AC1: Route & Navigation: Given a visitor on any page; When they look at the main navigation; Then an "About Us" / "من نحن" link is visible
- [ ] AC2: Page Structure: Given a visitor accesses `/about`; When the page loads; Then the page uses the public layout with:
- [ ] AC3: Hero Section Container: Given the About Us page loads; When displayed; Then show a hero section with:
- [ ] AC4: Page Title: Given the hero section; When viewed in English; Then display title: "About Us"
- [ ] AC5: Tagline Display: Given the hero section below the title; When displayed; Then show the tagline:
- [ ] AC6: Identity Statement: Given the hero section below the tagline; When displayed; Then show the identity statement:
- [ ] AC7: Responsive Layout: Given different screen sizes; When viewing the hero section:
- [ ] AC8: RTL Support: Given Arabic language is selected; When viewing the page; Then all text and elements align right-to-left correctly
+23
View File
@@ -0,0 +1,23 @@
---
id: 16-2
title: 16-2 Vision & Mission Section
status: Done
date: 2026-09-27
parent: 16
---
## Description
As a website visitor I want to read Libra's vision and mission statements So that I understand the organization's purpose and who they serve. Full implementation history: docs/stories/story-16.2-vision-mission-section.md
## Acceptance Criteria
- [ ] AC1: Vision Section Container: Given the About Us page below the hero; When displayed; Then show a vision section with:
- [ ] AC2: Vision Section Header: Given the vision section; When displayed; Then show section header:
- [ ] AC3: Vision Statement: Given the vision section; When displayed; Then show the full vision statement:
- [ ] AC4: Mission Section Container: Given the About Us page below the vision; When displayed; Then show a mission section with:
- [ ] AC5: Mission Section Header: Given the mission section; When displayed; Then show section header:
- [ ] AC6: Mission Cards - Three Categories: Given the mission section; When displayed; Then show 3 mission cards in a responsive grid:
- [ ] AC7: Mission Card Styling: Given each mission card; When displayed; Then style with:
- [ ] AC8: Responsive Grid: Given different screen sizes; When viewing mission cards:
- [ ] AC9: RTL Support: Given Arabic language is selected; When viewing both sections; Then all text and cards align right-to-left correctly
+21
View File
@@ -0,0 +1,21 @@
---
id: 16-3
title: 16-3 Values Section
status: Done
date: 2026-09-27
parent: 16
---
## Description
As a website visitor I want to see Libra's core values So that I understand the principles that guide their work. Full implementation history: docs/stories/story-16.3-values-section.md
## Acceptance Criteria
- [ ] AC1: Values Section Container: Given the About Us page below the mission section; When displayed; Then show a values section with:
- [ ] AC2: Values Section Header: Given the values section; When displayed; Then show section header:
- [ ] AC3: Values Introduction: Given the values section below the header; When displayed; Then show introductory text:
- [ ] AC4: Six Value Cards: Given the values section; When displayed; Then show 6 value cards:
- [ ] AC5: Value Card Styling: Given each value card; When displayed; Then style with:
- [ ] AC6: Responsive Grid: Given different screen sizes; When viewing value cards:
- [ ] AC7: RTL Support: Given Arabic language is selected; When viewing the values section; Then all cards and text align correctly for RTL
+21
View File
@@ -0,0 +1,21 @@
---
id: 16-4
title: 16-4 Goals Section
status: Done
date: 2026-09-27
parent: 16
---
## Description
As a website visitor I want to see Libra's organizational goals So that I understand what they are working to achieve. Full implementation history: docs/stories/story-16.4-goals-section.md
## Acceptance Criteria
- [ ] AC1: Goals Section Container: Given the About Us page below the values section; When displayed; Then show a goals section with:
- [ ] AC2: Goals Section Header: Given the goals section; When displayed; Then show section header:
- [ ] AC3: Seven Goals Display: Given the goals section; When displayed; Then show all 7 goals:
- [ ] AC4: Goals List Styling: Given the goals list; When displayed; Then style as:
- [ ] AC5: Numbered Circle Style: Given each goal number; When displayed; Then style the number with:
- [ ] AC6: Responsive Layout: Given different screen sizes; When viewing goals:
- [ ] AC7: RTL Support: Given Arabic language is selected; When viewing the goals section; Then numbers align on the right, text flows RTL
+22
View File
@@ -0,0 +1,22 @@
---
id: 16-5
title: 16-5 Legal Services Section
status: Done
date: 2026-09-27
parent: 16
---
## Description
As a website visitor I want to see Libra's comprehensive legal services So that I know what services they offer and if they can help with my legal needs. Full implementation history: docs/stories/story-16.5-legal-services-section.md
## Acceptance Criteria
- [ ] AC1: Services Section Container: Given the About Us page below the goals section; When displayed; Then show a services section with:
- [ ] AC2: Services Section Header: Given the services section; When displayed; Then show section header:
- [ ] AC3: Services Introduction: Given the services section below the header; When displayed; Then show introductory text:
- [ ] AC4: Four Service Categories: Given the services section; When displayed; Then show 4 service category cards:
- [ ] AC5: Service Card Styling: Given each service card; When displayed; Then style with:
- [ ] AC6: Responsive Grid: Given different screen sizes; When viewing service cards:
- [ ] AC7: CTA Button: Given the services section; When displayed below the cards; Then show a CTA button:
- [ ] AC8: RTL Support: Given Arabic language is selected; When viewing the services section; Then all cards, lists, and text align correctly for RTL
+29
View File
@@ -0,0 +1,29 @@
---
id: 16-6
title: 16-6 Scholarship Aspiration Section (REMOVED from production 2026-01-11 — do not re-implement)
status: Done
date: 2026-09-27
parent: 16
---
## Description
**Removed from production 2026-01-11** (commit `e8c1730`, "removed the scholarship stiff from
/about") — the section was built, then Naser had it deleted from the live `/about` page and its
language strings entirely. It does not exist in the current codebase. Kept here (rather than
deleted) for traceability only; do not re-implement without confirming with Naser first.
Original intent, for history: As a website visitor I want to learn about Libra's scholarship
aspiration So that I understand their vision for supporting Palestinian arts and law students.
Full implementation history: docs/stories/story-16.6-scholarship-section.md
## Acceptance Criteria
- [ ] AC1: Scholarship Section Container: Given the About Us page below the services section; When displayed; Then show a scholarship section with:
- [ ] AC2: Scholarship Section Header: Given the scholarship section; When displayed; Then show section header:
- [ ] AC3: Scholarship Description: Given the scholarship section; When displayed; Then show the scholarship description with two paragraphs:
- [ ] AC4: Key Aspirations List: Given the scholarship section below the description; When displayed; Then show 4 key aspirations as highlight items:
- [ ] AC5: Aspiration Item Styling: Given each aspiration item; When displayed; Then style with:
- [ ] AC6: Visual Accent: Given the scholarship section; When displayed; Then include:
- [ ] AC7: Responsive Layout: Given different screen sizes; When viewing the scholarship section:
- [ ] AC8: RTL Support: Given Arabic language is selected; When viewing the scholarship section; Then all text and items align correctly for RTL
+28
View File
@@ -0,0 +1,28 @@
---
id: 16
title: 16 About Us Page
status: Done
date: 2026-09-27
---
## Description
Builds a new public `/about` page presenting LIBRA for Rights' identity, vision, mission, values, goals, legal services, and scholarship aspiration, sourced from the organization's vision/mission/values document, across hero, vision/mission, values, goals, legal-services, and scholarship sections.
## Acceptance Criteria
- [ ] All 6 stories completed with acceptance criteria met
- [ ] About Us page accessible at `/about`
- [ ] Navigation updated with About Us link
- [ ] Hero section displays title and identity statement
- [ ] Vision section displays full vision statement
- [ ] Mission section displays all three mission categories
- [ ] Values section displays 6 values with icons
- [ ] Goals section displays 7 goals
- [ ] Legal services section displays all service categories
- [ ] Scholarship section displays aspiration content
- [ ] Responsive design works on mobile, tablet, desktop
- [ ] RTL (Arabic) layout displays correctly
- [ ] LTR (English) layout displays correctly
- [ ] All text in translation files (ar/en)
- [ ] Visual consistency with brand guidelines
+128
View File
@@ -0,0 +1,128 @@
---
id: 17-1
title: 17-1 Registration mailable and email template
status: Done
date: 2026-09-27
parent: 17
---
## Description
Create a Mailable and Arabic markdown email template that, when sent, delivers a workshop
registration submission to `info@libra.adv.ps`. This is a prerequisite for task 17-2, which will
call it from the form's submit handler.
**File to create:** `app/Mail/WorkshopRegistrationMail.php`
```php
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class WorkshopRegistrationMail extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;
/**
* Create a new message instance.
*/
public function __construct(
public string $fullName,
public string $contactNumber,
public ?string $email,
) {}
/**
* Get the message envelope.
*/
public function envelope(): Envelope
{
return new Envelope(
subject: 'تسجيل جديد - ورشة عمل ريادايات نابلس',
);
}
/**
* Get the message content definition.
*/
public function content(): Content
{
return new Content(
markdown: 'emails.workshop-registration.ar',
with: [
'fullName' => $this->fullName,
'contactNumber' => $this->contactNumber,
'email' => $this->email,
],
);
}
/**
* Get the attachments for the message.
*
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
*/
public function attachments(): array
{
return [];
}
}
```
This class deliberately does **not** extend `App\Mail\BaseMailable` — `BaseMailable::getFromName()`
switches on the app locale/from-name for the law firm's own bilingual mail, which doesn't apply
here; this mailable always sends in Arabic with a fixed subject, following the same
`ShouldQueue` + `Queueable`/`SerializesModels` pattern as `App\Mail\GuestBookingSubmittedMail`
(`app/Mail/GuestBookingSubmittedMail.php`) instead.
**File to create:** `resources/views/emails/workshop-registration/ar.blade.php`
```blade
<x-mail::message>
<div dir="rtl" style="text-align: right;">
# تسجيل جديد في ورشة عمل رياديات نابلس
تم استلام تسجيل جديد بالبيانات التالية:
- **الاسم الكامل:** {{ $fullName }}
- **رقم التواصل:** {{ $contactNumber }}
@if($email)
- **البريد الإلكتروني:** {{ $email }}
@endif
مع أطيب التحيات،<br>
{{ config('app.name') }}
</div>
</x-mail::message>
```
This follows the same `<x-mail::message>` + `dir="rtl"` wrapper pattern as
`resources/views/emails/booking/guest-submitted/ar.blade.php`.
No route or controller wiring belongs to this task — task 17-2 imports
`App\Mail\WorkshopRegistrationMail`, constructs it with the submitted field values, and sends it
with `Mail::to('info@libra.adv.ps')->send(...)`.
## Acceptance Criteria
- [x] `App\Mail\WorkshopRegistrationMail` exists, extends `Illuminate\Mail\Mailable`, implements
`Illuminate\Contracts\Queue\ShouldQueue`, and its constructor accepts `fullName` (string),
`contactNumber` (string), and `email` (nullable string)
- [x] `resources/views/emails/workshop-registration/ar.blade.php` exists, renders `$fullName` and
`$contactNumber` unconditionally, and renders `$email` only when it is not null/empty
- [x] Sending `new WorkshopRegistrationMail('Test Name', '0599123456', null)` via
`Mail::fake()` in a test produces an email with subject `تسجيل جديد - ورشة عمل ريادايات نابلس`
and body containing "Test Name" and "0599123456", with no email line rendered
- [x] Sending the same mailable with a non-null `email` value produces a body that additionally
contains that email address
## Sub-tasks
None.
+215
View File
@@ -0,0 +1,215 @@
---
id: 17-2
title: 17-2 Standalone registration page, form, and submit wiring
status: Done
date: 2026-09-27
parent: 17
---
## Description
Build the standalone, unlinked Nablus workshop registration page at `/forms/nablus-workshop`.
Depends on task 17-1 (`App\Mail\WorkshopRegistrationMail` must already exist).
### 1. Route
**File to modify:** `routes/web.php`
Add, near the other public `Volt::route` calls (after line 14, the `/booking/success` route),
outside any `auth`/`admin`/`client` middleware group:
```php
Volt::route('/forms/nablus-workshop', 'pages.forms.nablus-workshop')->name('forms.nablus-workshop');
```
Do **not** add any link to this route anywhere else in the codebase — specifically, do not touch
`resources/views/components/navigation.blade.php`, `resources/views/components/footer.blade.php`,
or any other menu/nav component. The page is reachable only by visiting the URL directly.
### 2. Standalone layout (no site nav/footer)
**File to create:** `resources/views/components/layouts/standalone.blade.php`
A minimal, self-contained HTML layout — it must NOT include `<x-navigation />` or `<x-footer />`
(unlike `resources/views/components/layouts/public.blade.php`, which this page intentionally does
not use, since the form must not carry the site's admin/login/booking navigation). Follow the
`<head>` include pattern from `resources/views/components/layouts/public.blade.php` (its
`@include('partials.head')`) but with a bare body:
```blade
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-[#F4F1EA]" style="font-family: var(--font-arabic)">
<main class="min-h-screen flex flex-col items-center px-4 py-10 sm:py-16">
<div class="w-full max-w-[640px]">
{{ $slot }}
</div>
</main>
@fluxScripts
</body>
</html>
```
### 3. Page component
**File to create:** `resources/views/livewire/pages/forms/nablus-workshop.blade.php`
Class-based Volt component (this project's convention — see `resources/views/livewire/pages/booking.blade.php`
for the pattern), using the new standalone layout, with these exact public properties, validation
rules, and submit behavior:
```php
<?php
use App\Mail\WorkshopRegistrationMail;
use Illuminate\Support\Facades\Mail;
use Livewire\Attributes\Layout;
use Livewire\Volt\Component;
new #[Layout('components.layouts.standalone')] class extends Component
{
public string $fullName = '';
public string $contactNumber = '';
public string $email = '';
public function register(): void
{
$validated = $this->validate([
'fullName' => ['required', 'string', 'max:255'],
'contactNumber' => ['required', 'string', 'max:50'],
'email' => ['nullable', 'email', 'max:255'],
], [
'fullName.required' => 'يرجى إدخال الاسم الكامل',
'contactNumber.required' => 'يرجى إدخال رقم التواصل',
'email.email' => 'يرجى إدخال بريد إلكتروني صحيح',
]);
Mail::to('info@libra.adv.ps')->send(new WorkshopRegistrationMail(
fullName: $validated['fullName'],
contactNumber: $validated['contactNumber'],
email: $validated['email'] !== '' ? $validated['email'] : null,
));
$this->redirect(route('about'), navigate: false);
}
}; ?>
<div class="flex flex-col gap-6">
<img
src="{{ asset('images/workshop-nablus-flyer.jpeg') }}"
alt="ورشة متخصصة: القانون، التسويق الرقمي، وإدارة المتاجر الإلكترونية"
class="w-full rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"
/>
<div class="bg-white rounded-lg p-6" style="box-shadow: 0 2px 8px rgba(0,0,0,0.1)">
<img src="{{ asset('images/logo.png') }}" alt="LIBRA for Rights" class="h-16 w-auto object-contain mb-4" />
<h1 class="text-2xl font-bold mb-2" style="color: #2D322A">تسجيل في ورشة عمل ريادايات نابلس</h1>
<p class="mb-4" style="color: #2D322A">تخططين لإطلاق مشروعك الخاص أو تطوير تجارتك الإلكترونية؟ 🚀</p>
<p class="text-sm leading-relaxed mb-6" style="color: #2D322A">
ندعوكم للانضمام إلينا في ورشة عمل متخصصة وشاملة تجمع بين القانون، التسويق الرقمي، وإدارة
المتاجر الإلكترونية لبناء مشروعك على أسس متينة وناجحة! 🎯📊💡
<br><br>
برنامج الورشة:
<br>
■ ١١:٠٠ – ١١:١٠ | الترحيب والافتتاحية والتعريف بالسوق الفلسطيني — أ. لينا عبد الهادي
<br>
■ ١١:١٠ – ١١:٤٠ | كيف تبدأ مشروعاً ريادياً — أ. هبة المصري
<br>
■ ١١:٤٥ – ١٢:٢٠ | أساسيات التسويق الرقمي للمشاريع الريادية عبر وسائل التواصل — أ. تالا حلوب
<br>
■ ١٢:٢٠ – ١٢:٣٠ استراحة
<br>
■ ١٢:٣٠ – ١:٠٠ | الحيثيات والإجراءات القانونية الخاصة بالتجارة الإلكترونية — أ. هدى عرموش
<br>
■ ١:٠٥ – ١:٢٥ | البيع عبر المواقع الإلكترونية مقابل منصات التواصل الاجتماعي والفرق بينهما — أ. أيسر غزال
<br><br>
📍 المكان: قاعة "ورشة" – برج رفيديا – نابلس
<br>
الوقت: من الساعة ١١:٠٠ صباحاً حتى ١:٢٥ ظهراً
<br>
✨ الدعوة عامة لجميع الرياديين/ات وأصحاب المشاريع الناشئة والمهتمين!
</p>
<form wire:submit="register" class="flex flex-col gap-4">
<flux:input
wire:model="fullName"
label="الاسم الكامل"
placeholder="أدخل اسمك الكامل"
required
/>
<flux:input
wire:model="contactNumber"
label="رقم التواصل"
placeholder="أدخل رقم جوالك"
required
/>
<flux:input
wire:model="email"
type="email"
label="ايميلك للتواصل"
placeholder="أدخل بريدك الإلكتروني"
/>
<flux:button variant="primary" type="submit" class="w-full">
إرسال
</flux:button>
</form>
</div>
</div>
```
`flux:input` renders the gold-focus-border / SemiBold-label / required-asterisk styling described
in `docs/ux-design.md` "Forms" automatically (same components already used on `pages.booking`),
so no additional CSS is required beyond the inline colors/classes above (Warm Cream `#F4F1EA` page
background from the standalone layout, Forest Green `#2D322A` text, White card, Warm Gold accents
via Flux's own primary-button styling — matching the existing site palette).
## Acceptance Criteria
- [ ] Visiting `/forms/nablus-workshop` returns HTTP 200 and does not require authentication
- [ ] The rendered page contains neither `<x-navigation` nor `<x-footer` (verify:
`curl -s http://libra.test/forms/nablus-workshop | grep -E 'x-navigation|x-footer'` returns
no match)
- [ ] `resources/views/components/navigation.blade.php` and
`resources/views/components/footer.blade.php` contain no reference to
`forms.nablus-workshop` or `/forms/nablus-workshop` (verify: `rg 'nablus-workshop'
resources/views/components/navigation.blade.php resources/views/components/footer.blade.php`
returns no match)
- [ ] Submitting the form with `fullName` and `contactNumber` filled in and `email` left blank
succeeds: no validation error is raised, `Mail::to('info@libra.adv.ps')->send(...)` is
called with a `WorkshopRegistrationMail` carrying the submitted `fullName`/`contactNumber`
and a null `email`, and the response redirects to `route('about')`
- [ ] Submitting with `fullName` blank, or `contactNumber` blank, re-renders the form with a
validation error and does not send any mail
- [ ] Submitting with a non-empty but invalid `email` (e.g. `not-an-email`) re-renders the form
with a validation error and does not send any mail
- [ ] Submitting with a valid `email` filled in sends a `WorkshopRegistrationMail` whose `email`
property equals the submitted value
## Sub-tasks
None.
## QA Notes (2026-09-27)
All 6 acceptance criteria verified: `tests/Feature/Public/NablusWorkshopRegistrationTest.php`
(7 tests, all passing) covers route reachability without auth, absence of
`x-navigation`/`x-footer` markup, absence of `nablus-workshop` references in
`navigation.blade.php`/`footer.blade.php`, valid-submission mail dispatch with null email,
validation failures for blank `fullName`/`contactNumber` and invalid `email` (no mail sent), and
valid-email pass-through. No manual tests required — all criteria are HTTP/route/grep/mail
testable. Regression check: last 5 Done tasks (16-4, 16-5, 16-6, 17-1) touch no files this task
changed; 17-1's own mailable tests re-run clean (4/4). Full-suite gate run as parent 17 rollup:
1723 passed, 69 failed, 7 skipped — all 69 failures pre-existing/unrelated (About page
scholarship section removed 2026-01-11 per 16-6, Card/Accessibility/Admin-export/Availability
tests), none reference this task's files (routes/web.php, standalone layout, nablus-workshop
page). Not fixed here per QA scope.
+32
View File
@@ -0,0 +1,32 @@
---
id: 17
title: 17 Nablus Workshop Registration Form
status: Done
date: 2026-09-27
parent: null
---
## Description
Parent container task for the standalone Nablus workshop registration form (PRD v1.3 update,
Section "Update — Version 1.3"). This task carries no independent implementation — it is done
when both subtasks below are Done.
## Acceptance Criteria
- [x] Subtask 17-1 is Done
- [x] Subtask 17-2 is Done
## Sub-tasks
- 17-1 Registration mailable and email template
- 17-2 Standalone registration page, form, and submit wiring
## Completion Note (2026-09-27)
Both subtasks Done. Full-suite regression gate run as parent rollup:
`php -d memory_limit=4G artisan test | cat` — 1723 passed, 69 failed, 7 skipped. All 69 failures
are pre-existing and unrelated to this parent's changes (About page scholarship section removed
2026-01-11 per 16-6, plus Card/Accessibility/Admin-export/Availability-calendar tests); none
reference routes/web.php, standalone.blade.php, or the nablus-workshop page. Not fixed here —
outside this task's scope.
+71
View File
@@ -0,0 +1,71 @@
---
id: 18
title: 18 Nablus Workshop Form - Image Sizing Fix
status: Done
date: 2026-09-27
parent: null
---
## Description
Naser reviewed the Nablus workshop registration page (task 17, shipped in commit `690c223`) and
found the flyer image and the logo render far too large. Fix the sizing in
`resources/views/livewire/pages/forms/nablus-workshop.blade.php` — a pure styling change, no
logic involved.
**File to modify:** `resources/views/livewire/pages/forms/nablus-workshop.blade.php`
Current flyer image markup (around line 39-43):
```blade
<img
src="{{ asset('images/workshop-nablus-flyer.jpeg') }}"
alt="ورشة متخصصة: القانون، التسويق الرقمي، وإدارة المتاجر الإلكترونية"
class="w-full rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"
/>
```
The image is 1086x1448px (portrait). `w-full` inside the page's `max-w-[640px]` container
scales it to roughly 640x853px, which dominates the page above the fold on both desktop and
mobile. The full workshop agenda text is already duplicated in the paragraph immediately below
this image (same file, further down), so the image is decorative here, not the only source of
that information — it can be shown at a much smaller, capped size without losing information.
Change the class to cap its height and center it as a modest banner rather than a full-width
hero:
```blade
class="max-h-64 w-auto mx-auto rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"
```
Current logo markup (around line 46):
```blade
<img src="{{ asset('images/logo.png') }}" alt="LIBRA for Rights" class="h-16 w-auto object-contain mb-4" />
```
`h-16` (64px) is larger than this project's own logo-size convention for a compact card header —
`resources/views/components/logo.blade.php` defines `sm` as `h-10 w-10` (40px, its own comment
says "Mobile nav") and `md` as `h-12 w-12` (48px, "Desktop nav"). Change the class to match the
`sm` convention:
```blade
<img src="{{ asset('images/logo.png') }}" alt="LIBRA for Rights" class="h-10 w-auto object-contain mb-4" />
```
No other part of the file changes. No route, layout, mailable, or validation logic is affected.
## Acceptance Criteria
- [ ] `resources/views/livewire/pages/forms/nablus-workshop.blade.php`'s flyer `<img>` tag's
class attribute contains `max-h-64` and does not contain `w-full`
- [ ] The same file's logo `<img>` tag's class attribute contains `h-10` and does not contain
`h-16`
- [ ] Visiting `/forms/nablus-workshop` still returns HTTP 200 (no markup breakage introduced)
- [ ] The existing test suite for this page (`tests/Feature/Public/NablusWorkshopRegistrationTest.php`)
still passes unchanged — this is a styling-only change, it must not alter any of that
test's assertions
## Sub-tasks
None.
+57
View File
@@ -0,0 +1,57 @@
---
id: 19
title: 19 Nablus Workshop Form - Remove Logo, Shrink Flyer Further
status: Done
date: 2026-09-28
parent: null
---
## Description
Follow-up to task 18. Naser wants the logo removed entirely from the Nablus workshop registration
page, and the flyer image made smaller still. Pure styling/markup change, no logic involved.
**File to modify:** `resources/views/livewire/pages/forms/nablus-workshop.blade.php`
Current markup (as of task 18):
```blade
<img
src="{{ asset('images/workshop-nablus-flyer.jpeg') }}"
alt="ورشة متخصصة: القانون، التسويق الرقمي، وإدارة المتاجر الإلكترونية"
class="max-h-64 w-auto mx-auto rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"
/>
<div class="bg-white rounded-lg p-6" style="box-shadow: 0 2px 8px rgba(0,0,0,0.1)">
<img src="{{ asset('images/logo.png') }}" alt="LIBRA for Rights" class="h-10 w-auto object-contain mb-4" />
<h1 class="text-2xl font-bold mb-2" style="color: #2D322A">تسجيل في ورشة عمل ريادايات نابلس</h1>
```
1. **Delete the logo `<img>` tag entirely** — the line
`<img src="{{ asset('images/logo.png') }}" alt="LIBRA for Rights" class="h-10 w-auto object-contain mb-4" />`
is removed completely, nothing replaces it. The `<h1>` immediately after becomes the first
element inside the white card div.
2. **Shrink the flyer image further** — change its class from `max-h-64 w-auto mx-auto
rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]` to `max-h-40 w-auto mx-auto rounded-lg
shadow-[0_2px_8px_rgba(0,0,0,0.1)]` (only the height cap changes, `max-h-64` → `max-h-40`;
everything else in that class string stays the same).
No other part of the file changes — routing, validation, mail-sending, and all other markup are
untouched.
## Acceptance Criteria
- [x] `resources/views/livewire/pages/forms/nablus-workshop.blade.php` contains no `<img>` tag
referencing `images/logo.png` (verify: `rg "images/logo.png" resources/views/livewire/pages/forms/nablus-workshop.blade.php` returns no match)
- [x] The flyer `<img>` tag's class attribute contains `max-h-40` and does not contain `max-h-64`
- [x] Visiting `/forms/nablus-workshop` still returns HTTP 200
- [x] The existing test suite for this page (`tests/Feature/Public/NablusWorkshopRegistrationTest.php`)
still passes unchanged — this is a styling/markup-only change, it must not alter any of that
test's assertions (none of that file's assertions reference the logo image, so removing it
should not require any test changes; confirm this is true before treating a resulting
failure as pre-existing/unrelated)
## Sub-tasks
None.
+39
View File
@@ -0,0 +1,39 @@
---
id: 2-1
title: 2-1 Individual Client Account Management
status: Done
date: 2026-09-27
parent: 2
---
## Description
As an admin, I want to create, view, edit, and search individual client accounts, So that I can manage client information and provide them platform access. Context: Integrates with: Users table, Fortify authentication; Technology: Livewire Volt, Flux UI forms; Follows pattern: Admin CRUD patterns, class-based Volt components. - **Validation failure:** Display inline field errors using Flux UI error states - **Duplicate email:** Show "Email already exists" error on email field - **Duplicate National ID:** Show "National ID already registered" error - **Empty search results:** Display "No clients found" message with clear filters option. Full implementation history: docs/stories/story-2.1-individual-client-account-management.md
## Acceptance Criteria
- [ ] Form with required fields:
- [ ] Validation for all required fields
- [ ] Duplicate email/National ID prevention with clear error message
- [ ] Password strength indicator (optional)
- [ ] Success message on creation
- [ ] Display all individual clients (user_type = 'individual')
- [ ] Columns: Name, Email, National ID, Phone, Status, Created Date
- [ ] Pagination (10/25/50 per page)
- [ ] Default sort by created date (newest first)
- [ ] Search by name, email, or National ID
- [ ] Filter by status (active/deactivated/all)
- [ ] Real-time search with debounce (300ms)
- [ ] Clear filters button
- [ ] Edit all client information
- [ ] Cannot change user_type from this form
- [ ] Validation same as create
- [ ] Success message on update
- [ ] Display all client information
- [ ] Show consultation history summary
- [ ] Show timeline history summary
- [ ] Quick links to related records
- [ ] Bilingual form labels and messages
- [ ] Proper form validation with error display
- [ ] Audit log entries for all operations
- [ ] Tests for CRUD operations
+36
View File
@@ -0,0 +1,36 @@
---
id: 2-2
title: 2-2 Company/Corporate Client Account Management
status: Done
date: 2026-09-27
parent: 2
---
## Description
As an admin, I want to create, view, edit, and manage company/corporate client accounts, So that I can serve corporate clients with their unique data requirements. Context: Integrates with: `users` table (company-specific fields), `admin_logs` table; Technology: Livewire Volt (class-based), Flux UI forms, Pest tests; Follows pattern: Same CRUD pattern as Story 2.1 Individual Clients. > **Note:** This migration is NOT part of this story. It is preserved here for future reference if multiple contact persons feature is prioritized. Full implementation history: docs/stories/story-2.2-company-client-account-management.md
## Acceptance Criteria
- [ ] Form with required fields:
- [ ] Validation for all required fields
- [ ] Duplicate email/registration number prevention
- [ ] Success message on creation
- [ ] Display all company clients (user_type = 'company')
- [ ] Columns: Company Name, Contact Person, Email, Reg #, Status, Created Date
- [ ] Pagination (10/25/50 per page)
- [ ] Default sort by created date
- [ ] Search by company name, email, or registration number
- [ ] Filter by status (active/deactivated/all)
- [ ] Real-time search with debounce
- [ ] Edit all company information
- [ ] Update contact person details
- [ ] Validation same as create
- [ ] Success message on update
- [ ] Display all company information (including contact person details)
- [ ] Show consultation history summary
- [ ] Show timeline history summary
- [ ] Bilingual form labels and messages
- [ ] Proper form validation
- [ ] Audit log entries for all operations
- [ ] Tests for CRUD operations
+33
View File
@@ -0,0 +1,33 @@
---
id: 2-3
title: 2-3 Account Type Conversion
status: Done
date: 2026-09-27
parent: 2
---
## Description
As an admin, I want to convert individual accounts to company accounts and vice versa, So that I can accommodate clients whose business structure changes. Context: Integrates with: Users table, consultations, timelines; Technology: Livewire Volt (class-based), Flux UI modals, Pest tests; Follows pattern: Admin action pattern with confirmation modal (same as Story 2.1/2.2 CRUD pattern). Full implementation history: docs/stories/story-2.3-account-type-conversion.md
## Acceptance Criteria
- [ ] "Convert to Company" action available on individual profiles
- [ ] Modal/form prompts for additional company fields:
- [ ] Preserve existing data (email, phone, password)
- [ ] Preserve all consultation history
- [ ] Preserve all timeline history
- [ ] Confirmation dialog before conversion
- [ ] Success message after conversion
- [ ] "Convert to Individual" action available on company profiles
- [ ] Modal/form prompts for individual-specific fields:
- [ ] Handle company-specific data:
- [ ] Preserve all consultation history
- [ ] Preserve all timeline history
- [ ] Confirmation dialog before conversion
- [ ] Audit log entry capturing:
- [ ] Email notification to user about account type change
- [ ] Bilingual confirmation dialogs
- [ ] Bilingual email notification
- [ ] All data preserved (verify in tests)
- [ ] No broken relationships after conversion
+38
View File
@@ -0,0 +1,38 @@
---
id: 2-4
title: 2-4 Account Lifecycle Management
status: Done
date: 2026-09-27
parent: 2
---
## Description
As an admin, I want to deactivate, reactivate, and permanently delete client accounts, So that I can manage the full lifecycle of client relationships. Context: Integrates with: Users table, consultations, timelines, notifications, sessions; Technology: Livewire Volt (class-based), Flux UI modals, Pest tests; Follows pattern: Same admin action patterns as Story 2.1/2.2, soft deactivation via status field, hard deletion with cascade. Full implementation history: docs/stories/story-2.4-account-lifecycle-management.md
## Acceptance Criteria
- [ ] "Deactivate" button on user profile and list
- [ ] Confirmation dialog explaining consequences
- [ ] Effects of deactivation:
- [ ] Visual indicator in user list (grayed out, badge)
- [ ] Audit log entry created
- [ ] "Reactivate" button on deactivated profiles
- [ ] Confirmation dialog
- [ ] Effects of reactivation:
- [ ] Email notification sent to user
- [ ] Audit log entry created
- [ ] "Delete" button (with danger styling)
- [ ] Confirmation dialog with strong warning:
- [ ] Effects of deletion:
- [ ] Audit log entry preserved (for audit trail)
- [ ] No email sent (user no longer exists)
- [ ] "Reset Password" action on user profile
- [ ] Options:
- [ ] Email new credentials to client
- [ ] Force password change on next login (optional) - Not implemented per simplified approach
- [ ] Audit log entry created
- [ ] All actions logged in admin_logs table
- [ ] Bilingual confirmation messages
- [ ] Clear visual states for account status
- [ ] Tests for all lifecycle operations
+46
View File
@@ -0,0 +1,46 @@
---
id: 2-5
title: 2-5 Account Creation Email Notification
status: Done
date: 2026-09-27
parent: 2
---
## Description
As an admin, I want welcome emails sent automatically when I create client accounts, So that clients receive their login credentials and know how to access the platform. Context: Integrates with: User creation flow, Laravel Mail; Technology: Laravel Mailable, queued jobs; Follows pattern: Laravel notification/mailable patterns. Full implementation history: docs/stories/story-2.5-account-creation-email-notification.md
## Acceptance Criteria
- [ ] Email sent automatically on account creation
- [ ] Works for both individual and company accounts
- [ ] Queued for performance (async sending)
- [ ] No email sent for admin accounts
- [ ] Personalized greeting:
- [ ] Message: "Your account has been created"
- [ ] Login credentials:
- [ ] Login URL (clickable button/link)
- [ ] Brief platform introduction
- [ ] Contact information for questions
- [ ] Professional template with Libra branding
- [ ] Colors: Navy blue (#0A1F44) and Gold (#D4AF37)
- [ ] Libra logo in header
- [ ] Footer with firm information
- [ ] Mobile-responsive layout
- [ ] From: no-reply@libra.ps
- [ ] From Name: Libra Law Firm / مكتب ليبرا للمحاماة
- [ ] Reply-To: (firm contact email)
- [ ] Email in user's preferred_language
- [ ] Arabic email for Arabic preference
- [ ] English email for English preference
- [ ] All text translated
- [ ] Plain text version generated
- [ ] All essential information included
- [ ] Readable without HTML
- [ ] Email passes spam filters
- [ ] Links work correctly
- [ ] Password visible but not overly prominent
- [ ] Tests verify email sending
- [ ] Email queued with retry on failure (Laravel default: 3 attempts)
- [ ] Failed emails logged to `failed_jobs` table
- [ ] User creation succeeds even if email fails (non-blocking)
+22
View File
@@ -0,0 +1,22 @@
---
id: 2
title: 2 User Management System
status: Done
date: 2026-09-27
---
## Description
Gives the admin full lifecycle control over client accounts: creating individual and company/corporate accounts, converting between types, deactivating or permanently deleting accounts, resetting passwords, and sending welcome-email notifications. All operations are audit-logged.
## Acceptance Criteria
- [ ] Admin can create individual client accounts
- [ ] Admin can create company/corporate client accounts
- [ ] Admin can convert between account types
- [ ] Admin can deactivate accounts (data retained)
- [ ] Admin can permanently delete accounts
- [ ] Admin can reset client passwords
- [ ] Welcome email sent with login credentials
- [ ] User search and filtering functional
- [ ] All operations logged for audit
+135
View File
@@ -0,0 +1,135 @@
---
id: 20
title: 20 Nablus Workshop Form - Match Site Background and Card Styling
status: Done
date: 2026-09-28
parent: null
---
## Description
Naser says the page currently has "no background design at all" and wants it to match the
website's coloring/design system. Fix by reusing patterns that already exist elsewhere in this
codebase (the auth pages' subtle background pattern, and the reusable card component) rather than
inventing new ones — this also avoids a real bug just hit on tasks 18/19: brand-new Tailwind
utility classes (e.g. `max-h-64`, arbitrary-value `shadow-[...]`) are not in the compiled
`public/build` CSS until `npm run build`/`npm run dev` runs, so a change can look like it "did
nothing." Every class used below is already present in the current compiled CSS (verified via
`grep` against `public/build/assets/*.css` at spec-writing time) because it's already used by
`resources/views/components/layouts/auth/split.blade.php` and
`resources/views/components/ui/card.blade.php`.
**File to modify:** `resources/views/components/layouts/standalone.blade.php`
Current:
```blade
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-[#F4F1EA]" style="font-family: var(--font-arabic)">
<main class="min-h-screen flex flex-col items-center px-4 py-10 sm:py-16">
<div class="w-full max-w-[640px]">
{{ $slot }}
</div>
</main>
@fluxScripts
</body>
</html>
```
Replace with (adds the `auth-pattern` class already defined in `resources/css/app.css` lines
974-992 — a repeating low-opacity botanical/geometric SVG background using
`public/images/auth-pattern.svg`, the same file the login page's split layout already references;
swaps the arbitrary hex background for the `bg-background` token which maps to the same Warm
Cream color via `resources/css/app.css`'s `@theme` block):
```blade
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
@include('partials.head')
</head>
<body class="min-h-screen bg-background antialiased" style="font-family: var(--font-arabic)">
<main class="auth-pattern relative min-h-screen flex flex-col items-center px-4 py-10 sm:py-16">
<div class="relative w-full max-w-[640px] z-10">
{{ $slot }}
</div>
</main>
@fluxScripts
</body>
</html>
```
(The `.auth-pattern > *` rule in `resources/css/app.css` already lifts direct children to
`z-index: 1` above the pattern — the explicit `relative z-10` on the inner div here is a belt-and-
suspenders match to how `auth/split.blade.php` structures it, since that inner div is not a direct
child of the `auth-pattern` element in this layout the way it is there.)
**File to modify:** `resources/views/livewire/pages/forms/nablus-workshop.blade.php`
Current card wrapper (lines 45, 100 in the file as of task 19):
```blade
<div class="bg-white rounded-lg p-6" style="box-shadow: 0 2px 8px rgba(0,0,0,0.1)">
...
</div>
```
Replace with the project's existing reusable card component
(`resources/views/components/ui/card.blade.php`), using its `highlight` prop for the Warm-Gold
accent border already documented in `docs/ux-design.md` ("Cards/containers... optional gold
top/left accent border for featured or important cards"):
```blade
<x-ui.card highlight>
...
</x-ui.card>
```
Current inline-colored text elements (lines 46, 47, 49 in the file as of task 19) each use
`style="color: #2D322A"` — replace each with the Tailwind class `text-body` (already compiled,
maps to the same Forest Green `#2D322A` token via `resources/css/app.css`'s `--color-body: var(--color-text)`
alias) and drop the inline `style` attribute entirely:
```blade
<h1 class="text-2xl font-bold mb-2 text-body">تسجيل في ورشة عمل ريادايات نابلس</h1>
<p class="mb-4 text-body">تخططين لإطلاق مشروعك الخاص أو تطوير تجارتك الإلكترونية؟ 🚀</p>
<p class="text-sm leading-relaxed mb-6 text-body">
```
(The long agenda paragraph's inner content — the schedule lines — is unchanged, only its opening
tag's class/style attributes change as shown above.)
No other part of either file changes — routing, validation, mail-sending, the flyer image
(already sized correctly by tasks 18/19), and the form fields are untouched.
## Acceptance Criteria
- [x] `resources/views/components/layouts/standalone.blade.php`'s `<main>` tag's class attribute
contains `auth-pattern`
- [x] The same file's `<body>` tag's class attribute contains `bg-background` and does not
contain `bg-[#F4F1EA]`
- [x] `resources/views/livewire/pages/forms/nablus-workshop.blade.php` contains `<x-ui.card
highlight>` and no longer contains `bg-white` or the inline `style="box-shadow:
0 2px 8px rgba(0,0,0,0.1)"` on the form's outer wrapper
- [x] The same file's `<h1>` and both `<p>` tags that previously had `style="color: #2D322A"` now
use the `text-body` class instead, with no `style="color:` attribute remaining anywhere in
the file (verify: `rg "style=\"color:" resources/views/livewire/pages/forms/nablus-workshop.blade.php`
returns no match)
- [x] `public/images/auth-pattern.svg` exists (it must — this task reuses it, doesn't create it;
verify: `test -f public/images/auth-pattern.svg`)
- [x] Visiting `/forms/nablus-workshop` still returns HTTP 200
- [x] The existing test suite for this page (`tests/Feature/Public/NablusWorkshopRegistrationTest.php`)
still passes unchanged
- [x] After this change, run `npm run build` (or confirm it was already run) and verify
`auth-pattern`, `bg-background`, and `text-body` all appear in the newly generated
`public/build/assets/*.css` — state this explicitly in the completion report, since tasks
18/19 shipped a visual change that silently didn't take effect for exactly this reason
## Sub-tasks
None.
+68
View File
@@ -0,0 +1,68 @@
---
id: 21
title: 21 Nablus Workshop Form - Flyer Size Adjustment
status: Done
date: 2026-09-28
parent: null
---
## Description
Follow-up to tasks 18/19. Naser says the flyer image is now a bit too small to read comfortably
(it was capped to `max-h-40`, 160px) — he wants it bumped up to a size that's still compact but
readable. Pure styling change, no logic involved.
**File to modify:** `resources/views/livewire/pages/forms/nablus-workshop.blade.php`
Current flyer image markup:
```blade
<img
src="{{ asset('images/workshop-nablus-flyer.jpeg') }}"
alt="ورشة متخصصة: القانون، التسويق الرقمي، وإدارة المتاجر الإلكترونية"
class="max-h-40 w-auto mx-auto rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"
/>
```
Change only the height cap, `max-h-40` → `max-h-56` (224px — roughly midway between the too-small
160px from task 19 and the too-large 256px from task 18). Nothing else in the class string
changes:
```blade
class="max-h-56 w-auto mx-auto rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"
```
`max-h-56` is a standard Tailwind spacing-scale utility (14rem), same family as the `max-h-40`/
`max-h-64` already used in this file's history, so it will compile the same way once the frontend
build runs (see step below — required, do not skip).
**Required build step:** after making the edit, run `npm run build` (node/npm are only reachable
via `source ~/.nvm/nvm.sh && nvm use v24.20.0` in this environment — not on the default PATH) and
grep the freshly generated `public/build/assets/*.css` file for `max-h-56` to confirm it compiled.
Tasks 18/19 shipped a class that silently never took effect because nobody rebuilt the stale
`public/build` bundle — do not repeat that.
## Acceptance Criteria
- [x] The flyer `<img>` tag's class attribute in
`resources/views/livewire/pages/forms/nablus-workshop.blade.php` contains `max-h-56` and
does not contain `max-h-40` or `max-h-64`
- [x] `npm run build` was run after the edit, and `max-h-56` is confirmed present (via grep) in
the newly generated `public/build/assets/*.css` — state the exact filename and grep result
in the completion report
- [x] Visiting `/forms/nablus-workshop` still returns HTTP 200
- [x] The existing test suite for this page (`tests/Feature/Public/NablusWorkshopRegistrationTest.php`)
still passes unchanged
## QA Verification (2026-09-28)
- Class attribute confirmed: `class="max-h-56 w-auto mx-auto rounded-lg shadow-[0_2px_8px_rgba(0,0,0,0.1)]"`
— no `max-h-40`/`max-h-64` present.
- Grepped current `public/build/assets/app-XIQ2Iam8.css` fresh (not trusting the report's
filename) — file confirmed still present with that name, `max-h-56` found in it.
- `curl http://127.0.0.1:8971/forms/nablus-workshop` → HTTP 200.
- `php artisan test tests/Feature/Public/NablusWorkshopRegistrationTest.php` → 7 passed (26 assertions).
## Sub-tasks
None.
+33
View File
@@ -0,0 +1,33 @@
---
id: 3-1
title: 3-1 Working Hours Configuration
status: Done
date: 2026-09-27
parent: 3
---
## Description
As an admin, I want to configure available working hours for each day of the week, So that clients can only book consultations during my available times. Context: Integrates with: working_hours table, availability calendar; Technology: Livewire Volt, Flux UI forms; Follows pattern: Admin settings pattern. The AdminLog model is used for audit logging (defined in Epic 1). Schema:. Full implementation history: docs/stories/story-3.1-working-hours-configuration.md
## Acceptance Criteria
- [ ] Set available days (enable/disable each day of week)
- [ ] Set start time for each enabled day
- [ ] Set end time for each enabled day
- [ ] Support different hours for different days
- [ ] 15-minute buffer automatically applied between appointments
- [ ] 12-hour time format display (AM/PM)
- [ ] Visual weekly schedule view
- [ ] Toggle for each day (Sunday-Saturday)
- [ ] Time pickers for start/end times
- [ ] Preview of available slots per day
- [ ] Save button with confirmation
- [ ] Changes take effect immediately for new bookings
- [ ] Existing approved bookings NOT affected by changes
- [ ] Warning if changing hours that have pending bookings
- [ ] Validation: end time must be after start time
- [ ] Bilingual labels and messages
- [ ] Default working hours on initial setup
- [ ] Audit log entry on changes
- [ ] Tests for configuration logic
+38
View File
@@ -0,0 +1,38 @@
---
id: 3-2
title: 3-2 Time Slot Blocking
status: Done
date: 2026-09-27
parent: 3
---
## Description
As an admin, I want to block specific dates or time ranges for personal events or holidays, So that clients cannot book during my unavailable times. Context: Integrates with: blocked_times table, availability calendar; Technology: Livewire Volt, Flux UI; Follows pattern: CRUD pattern with calendar integration. Full implementation history: docs/stories/story-3.2-time-slot-blocking.md
## Acceptance Criteria
- [ ] Block entire days (all-day events)
- [ ] Block specific time ranges within a day
- [ ] Add reason/note for blocked time
- [ ] View list of all blocked times (upcoming and past)
- [ ] Edit blocked times
- [ ] Delete blocked times
- [ ] Select date (date picker)
- [ ] Choose: All day OR specific time range
- [ ] If time range: start time and end time
- [ ] Optional reason/note field
- [ ] Confirmation on save
- [ ] Blocked times show as unavailable in calendar (Story 3.3 dependency)
- [ ] Visual distinction from "already booked" slots (Story 3.3 dependency)
- [ ] Future blocked times don't affect existing approved bookings
- [ ] Warning if blocking time with pending bookings
- [ ] Show all blocked times
- [ ] Sort by date (upcoming first)
- [ ] Filter: past/upcoming/all
- [ ] Quick actions: edit, delete
- [ ] Show reason if provided
- [ ] Bilingual support
- [ ] Audit log for create/edit/delete
- [ ] Validation: end time after start time
- [ ] Tests for blocking logic
+34
View File
@@ -0,0 +1,34 @@
---
id: 3-3
title: 3-3 Availability Calendar Display
status: Done
date: 2026-09-27
parent: 3
---
## Description
As a client, I want to see a calendar with available time slots, So that I can choose a convenient time for my consultation. Context: Integrates with: working_hours, blocked_times, consultations tables; Technology: Livewire Volt, JavaScript calendar library; Follows pattern: Real-time availability checking. Full implementation history: docs/stories/story-3.3-availability-calendar-display.md
## Acceptance Criteria
- [ ] Monthly calendar view showing available dates
- [ ] Visual distinction for date states:
- [ ] Navigate between months
- [ ] Current month shown by default
- [ ] Clicking a date shows available time slots
- [ ] 1-hour slots (45min consultation + 15min buffer)
- [ ] Clear indication of slot availability
- [ ] Unavailable reasons (optional):
- [ ] Availability checked on date selection
- [ ] Prevent double-booking (race condition handling)
- [ ] Refresh availability when navigating months
- [ ] Prevent navigating to months before current month (all dates would be "past")
- [ ] Optionally limit future navigation (e.g., max 3 months ahead) - configurable (deferred to future story)
- [ ] Mobile-friendly calendar
- [ ] Touch-friendly slot selection
- [ ] Proper RTL support for Arabic
- [ ] Fast loading (eager load data)
- [ ] Language-appropriate date formatting
- [ ] Accessible (keyboard navigation)
- [ ] Tests for availability logic
+19
View File
@@ -0,0 +1,19 @@
---
id: 3-4
title: 3-4 Booking Request Submission
status: Done
date: 2026-09-27
parent: 3
---
## Description
As a client, I want to submit a consultation booking request, so that I can schedule a meeting with the lawyer. Full implementation history: docs/stories/story-3.4-booking-request-submission.md
## Acceptance Criteria
- [ ] Booking Form (AC1-5)
- [ ] Validation & Constraints (AC6-9)
- [ ] Submission Flow (AC10-14)
- [ ] UI/UX (AC15-18)
- [ ] Quality Requirements (AC19-22)
+38
View File
@@ -0,0 +1,38 @@
---
id: 3-5
title: 3-5 Admin Booking Review & Approval
status: Done
date: 2026-09-27
parent: 3
---
## Description
As an admin, I want to review, categorize, and approve or reject booking requests, So that I can manage my consultation schedule and set appropriate consultation types. Context: Integrates with: consultations table, notifications, .ics generation; Technology: Livewire Volt, Flux UI; Follows pattern: Admin action workflow. Create these notification classes in app/Notifications/:. Full implementation history: docs/stories/story-3.5-admin-booking-review-approval.md
## Acceptance Criteria
- [ ] View all pending booking requests
- [ ] Display: client name, requested date/time, submission date
- [ ] Show problem summary preview
- [ ] Click to view full details
- [ ] Sort by date (oldest first default)
- [ ] Filter by date range
- [ ] Full client information
- [ ] Complete problem summary
- [ ] Client consultation history
- [ ] Requested date and time
- [ ] Set consultation type:
- [ ] If paid: set payment amount
- [ ] If paid: add payment instructions (optional)
- [ ] Approve button with confirmation
- [ ] On approval:
- [ ] Optional rejection reason field
- [ ] Reject button with confirmation
- [ ] On rejection:
- [ ] Quick approve (free) button on list
- [ ] Quick reject button on list
- [ ] Bulk actions (optional)
- [ ] Audit log for all decisions
- [ ] Bilingual notifications
- [ ] Tests for approval/rejection flow
+35
View File
@@ -0,0 +1,35 @@
---
id: 3-6
title: 3-6 Calendar File Generation (.ics)
status: Done
date: 2026-09-27
parent: 3
---
## Description
As a client, I want to receive a calendar file when my booking is approved, So that I can easily add the consultation to my calendar app. Context: Integrates with: Consultation model, email attachments; Technology: iCalendar format (RFC 5545); Follows pattern: Service class for generation. Full implementation history: docs/stories/story-3.6-calendar-file-generation.md
## Acceptance Criteria
- [ ] Generate valid .ics file on booking approval
- [ ] File follows iCalendar specification (RFC 5545)
- [ ] Compatible with major calendar apps:
- [ ] Event title: "Consultation with Libra Law Firm" (bilingual)
- [ ] Date and time (correct timezone)
- [ ] Duration: 45 minutes
- [ ] Location (office address or "Phone consultation")
- [ ] Description with:
- [ ] Reminder: 1 hour before
- [ ] Attach to approval email
- [ ] Available for download from client dashboard
- [ ] Proper MIME type (text/calendar)
- [ ] Correct filename (consultation-{date}.ics)
- [ ] Event title in client's preferred language
- [ ] Description in client's preferred language
- [ ] Valid iCalendar format (passes validators)
- [ ] Tests for file generation
- [ ] Tests for calendar app compatibility
- [ ] Tests for bilingual content (Arabic/English)
- [ ] Tests for download route authorization
- [ ] Tests for email attachment
+39
View File
@@ -0,0 +1,39 @@
---
id: 3-7
title: 3-7 Consultation Management
status: Done
date: 2026-09-27
parent: 3
---
## Description
As an admin, I want to manage consultations throughout their lifecycle, So that I can track completed sessions, handle no-shows, and maintain accurate records. Context: Integrates with: consultations table, notifications; Technology: Livewire Volt, Flux UI; Follows pattern: Admin management dashboard. Handle these scenarios with appropriate validation and error handling:. Full implementation history: docs/stories/story-3.7-consultation-management.md
## Acceptance Criteria
- [ ] View all consultations with filters:
- [ ] Sort by date, status, client name
- [ ] Pagination (15/25/50 per page)
- [ ] Quick status indicators
- [ ] Mark consultation as completed
- [ ] Mark consultation as no-show
- [ ] Cancel booking on behalf of client
- [ ] Status change confirmation
- [ ] Reschedule appointment to new date/time
- [ ] Validate new slot availability
- [ ] Send notification to client
- [ ] Generate new .ics file
- [ ] Mark payment as received (for paid consultations)
- [ ] Payment date recorded
- [ ] Payment status visible in list
- [ ] Add internal admin notes
- [ ] Notes not visible to client
- [ ] View notes in consultation detail
- [ ] Edit/delete notes
- [ ] View all consultations for a specific client
- [ ] Linked from user profile
- [ ] Summary statistics per client
- [ ] Audit log for all status changes
- [ ] Bilingual labels
- [ ] Tests for status transitions
+30
View File
@@ -0,0 +1,30 @@
---
id: 3-8
title: 3-8 Consultation Reminders
status: Done
date: 2026-09-27
parent: 3
---
## Description
As a client, I want to receive reminder emails before my consultation, So that I don't forget my appointment and can prepare accordingly. Context: Integrates with: consultations table, Laravel scheduler, email notifications; Technology: Laravel Queue, Scheduler, Mailable; Follows pattern: Scheduled job pattern. Full implementation history: docs/stories/story-3.8-consultation-reminders.md
## Acceptance Criteria
- [ ] Sent 24 hours before consultation
- [ ] Includes:
- [ ] Sent 2 hours before consultation
- [ ] Includes:
- [ ] Only for approved consultations
- [ ] Skip cancelled consultations
- [ ] Skip no-show consultations
- [ ] Don't send duplicate reminders
- [ ] Handle timezone correctly
- [ ] Email in client's preferred language
- [ ] Arabic template for Arabic preference
- [ ] English template for English preference
- [ ] Scheduled jobs run reliably
- [ ] Retry on failure
- [ ] Logging for debugging
- [ ] Tests for reminder logic
+40
View File
@@ -0,0 +1,40 @@
---
id: 3-9
title: 3-9 Guest Booking Request
status: Done
date: 2026-09-27
parent: 3
---
## Description
As a guest visitor, I want to submit a consultation booking request with my contact details, So that I can request legal services without needing an account first. Context: Integrates with: Availability calendar (Story 3.3), Admin booking review (Story 3.5), User creation (Epic 2); Technology: Livewire Volt, Flux UI, existing availability calendar component; Follows pattern: Client booking submission (Story 3.4), Admin approval workflow (Story 3.5). Extend the existing admin.bookings.pending component to include guest booking requests:. Full implementation history: docs/stories/story-3.9-guest-booking-request.md
## Acceptance Criteria
- [ ] **AC1:** Public `/booking` page accessible without login
- [ ] **AC2:** Display availability calendar (reuse existing component)
- [ ] **AC3:** Guest can select date and available time slot
- [ ] **AC4:** Account type toggle: Individual / Company
- [ ] **AC5:** Form fields for Individual:
- [ ] **AC6:** Additional fields for Company:
- [ ] **AC7:** Problem summary field (required, textarea, min 20 characters, max 2000)
- [ ] **AC8:** Confirmation step before submission showing all entered data
- [ ] **AC9:** Duplicate check: If email OR national_id exists in users table, show "Account already exists. Please login to book." with login link
- [ ] **AC10:** 1-per-day limit by email: Check guest_booking_requests table for same email on same booking_date
- [ ] **AC11:** Validate selected slot is still available
- [ ] **AC12:** Clear error messages for all validation failures (bilingual)
- [ ] **AC13:** On submit, create record in `guest_booking_requests` table with status 'pending'
- [ ] **AC14:** Guest sees success page: "Request received. We will contact you soon."
- [ ] **AC15:** Admin receives email notification about new guest booking request
- [ ] **AC16:** Guest receives submission confirmation email
- [ ] **AC17:** Guest booking requests appear in admin pending bookings queue with "Guest" badge
- [ ] **AC18:** Admin can view full guest details and problem summary
- [ ] **AC19:** Admin action: **Approve + Create Account**
- [ ] **AC20:** Admin action: **Reject**
- [ ] **AC21:** Admin action: **Create Account Only**
- [ ] **AC22:** All admin actions logged in audit trail
- [ ] **AC23:** Bilingual support (Arabic/English) for all UI and emails
- [ ] **AC24:** Mobile-responsive design
- [ ] **AC25:** Race condition prevention for slot availability
- [ ] **AC26:** Comprehensive test coverage
+24
View File
@@ -0,0 +1,24 @@
---
id: 3
title: 3 Booking & Consultation System
status: Done
date: 2026-09-27
---
## Description
Implements the full consultation booking workflow: admin-configured working hours and blocked time, a live availability calendar, client and guest booking submission, admin approval/rejection with free/paid assignment, consultation management, .ics calendar-file generation, and 24h/2h reminders.
## Acceptance Criteria
- [ ] Calendar displays available time slots
- [ ] Clients can submit booking requests
- [ ] 1 consultation per day per client enforced
- [ ] Admin can approve/reject bookings
- [ ] Admin assigns free/paid status
- [ ] Email notifications at each stage
- [ ] Consultation reminders (24hr, 2hr)
- [ ] Calendar file (.ics) generation
- [ ] Admin can mark as completed/no-show/cancelled
- [ ] Guests can submit booking requests from public page
- [ ] Admin can approve guest requests and create accounts
+30
View File
@@ -0,0 +1,30 @@
---
id: 4-1
title: 4-1 Timeline Creation
status: Done
date: 2026-09-27
parent: 4
---
## Description
As an admin, I want to create case timelines for clients, So that I can track and communicate progress on their legal matters. Context: Integrates with: timelines table, timeline_updates table, users table, admin_logs table; Technology: Livewire Volt, Flux UI; Follows pattern: Admin CRUD pattern (see existing admin components). Full implementation history: docs/stories/story-4.1-timeline-creation.md
## Acceptance Criteria
- [ ] Select client (search by name/email) - only users with user_type 'individual' or 'company'
- [ ] Case name/title (required)
- [ ] Case reference number (optional, unique if provided)
- [ ] Initial notes (optional)
- [ ] Timeline assigned to selected client
- [ ] Creation date automatically recorded
- [ ] Status defaults to 'active'
- [ ] Can create multiple timelines per client
- [ ] Confirmation message on successful creation
- [ ] Timeline immediately visible to client
- [ ] Case name required
- [ ] Case reference unique if provided
- [ ] Client must exist
- [ ] Audit log entry created via AdminLog model
- [ ] Bilingual labels and messages
- [ ] Tests for creation flow
+40
View File
@@ -0,0 +1,40 @@
---
id: 4-2
title: 4-2 Timeline Updates Management
status: Done
date: 2026-09-27
parent: 4
---
## Description
As an admin, I want to add and edit updates within a timeline, So that I can keep clients informed about their case progress. Context: Integrates with: timeline_updates table, timelines table; Technology: Livewire Volt, rich text editor (Trix recommended); Follows pattern: Nested CRUD pattern. Full implementation history: docs/stories/story-4.2-timeline-updates-management.md
## Acceptance Criteria
- [ ] Add new update to timeline
- [ ] Update text content (required)
- [ ] Rich text formatting supported:
- [ ] Timestamp automatically recorded
- [ ] Admin name automatically recorded
- [ ] Client notified via email on new update
- [ ] Edit existing update text
- [ ] Edit history preserved (updated_at changes)
- [ ] Cannot change timestamp or admin
- [ ] Updates displayed in chronological order
- [ ] Each update shows:
- [ ] Visual timeline representation
- [ ] HTML sanitization using `mews/purifier` package
- [ ] Audit log for add/edit operations via AdminLog
- [ ] Feature tests for all operations
- [ ] Can add update with valid text (min 10 chars)
- [ ] Cannot add update with empty text - validation error
- [ ] Cannot add update with text < 10 chars - validation error
- [ ] HTML is sanitized (script tags, XSS vectors removed)
- [ ] Client receives notification email on new update
- [ ] Audit log created when update is added
- [ ] Audit log created when update is edited (includes old/new values)
- [ ] Updates display in chronological order (oldest first)
- [ ] Admin name and timestamp automatically recorded
- [ ] Edit preserves original created_at, updates updated_at
- [ ] Cannot change timestamp or admin on edit
+29
View File
@@ -0,0 +1,29 @@
---
id: 4-3
title: 4-3 Timeline Archiving
status: Done
date: 2026-09-27
parent: 4
---
## Description
As an admin, I want to archive completed cases and unarchive if needed, So that I can organize active and completed case timelines. Context: Integrates with: timelines table (status field from Story 4.1); Technology: Livewire Volt; Follows pattern: Soft state change pattern. Add these methods to app/Models/Timeline.php:. Full implementation history: docs/stories/story-4.3-timeline-archiving.md
## Acceptance Criteria
- [ ] Archive button on timeline detail view (admin only)
- [ ] Confirmation modal before archiving ("Are you sure?")
- [ ] Status changes to 'archived'
- [ ] Timeline remains visible to client (read-only as always)
- [ ] No further updates can be added (show disabled state with tooltip)
- [ ] Visual indicator shows archived status (badge + muted styling)
- [ ] Unarchive button on archived timelines
- [ ] Status returns to 'active'
- [ ] Updates can be added again
- [ ] Archiving already-archived timeline: No-op, no error shown
- [ ] Unarchiving already-active timeline: No-op, no error shown
- [ ] Adding update to archived timeline: Prevented with error message
- [ ] Audit log for status changes (action: 'archive' or 'unarchive') - uses AdminLog `action` field
- [ ] Bilingual labels (AR/EN for buttons, messages)
- [ ] Feature tests covering all scenarios below
+34
View File
@@ -0,0 +1,34 @@
---
id: 4-4
title: 4-4 Admin Timeline Dashboard
status: Done
date: 2026-09-27
parent: 4
---
## Description
As an admin, I want a central view to manage all timelines across all clients, So that I can efficiently track and update case progress. Context: Integrates with: timelines table, users table; Technology: Livewire Volt with pagination; Follows pattern: Admin list/dashboard pattern. resources/views/livewire/admin/timelines/index.blade.php. Full implementation history: docs/stories/story-4.4-admin-timeline-dashboard.md
## Acceptance Criteria
- [ ] Display all timelines with:
- [ ] Pagination (15/25/50 per page)
- [ ] Empty state message when no timelines exist
- [ ] Filter by client (search/select)
- [ ] Filter by status (active/archived/all)
- [ ] Filter by date range (created/updated)
- [ ] Search by case name or reference
- [ ] Clear filters option
- [ ] Show "No results" message when filters return empty
- [ ] Sort by client name
- [ ] Sort by case name
- [ ] Sort by last updated
- [ ] Sort by created date
- [ ] Visual indicator for current sort column/direction
- [ ] View timeline details
- [ ] Add update (inline or link)
- [ ] Archive/unarchive toggle with confirmation
- [ ] Fast loading with eager loading
- [ ] Bilingual support
- [ ] Tests for filtering/sorting
+29
View File
@@ -0,0 +1,29 @@
---
id: 4-5
title: 4-5 Client Timeline View
status: Done
date: 2026-09-27
parent: 4
---
## Description
As a client, I want to view my case timelines and updates, So that I can track the progress of my legal matters. Context: Integrates with: timelines, timeline_updates tables; Technology: Livewire Volt (read-only); Follows pattern: Client dashboard pattern. Full implementation history: docs/stories/story-4.5-client-timeline-view.md
## Acceptance Criteria
- [ ] Display all client's timelines
- [ ] Active timelines prominently displayed
- [ ] Archived timelines clearly separated
- [ ] Visual distinction (color/icon) for status
- [ ] Show for each:
- [ ] Case name and reference
- [ ] Status indicator
- [ ] All updates in chronological order
- [ ] Each update shows:
- [ ] Read-only (no edit/comment)
- [ ] No ability to archive/delete
- [ ] Only see own timelines (403 for unauthorized access)
- [ ] Recent updates indicator (new since last view, optional)
- [ ] Responsive design for mobile
- [ ] Bilingual labels and dates
+30
View File
@@ -0,0 +1,30 @@
---
id: 4-6
title: 4-6 Timeline Update Notifications
status: Done
date: 2026-09-27
parent: 4
---
## Description
As a client, I want to receive email notifications when my timeline is updated, So that I stay informed about my case progress without checking the portal. Context: Integrates with: timeline_updates creation, email system; Technology: Laravel Notifications, queued emails; Follows pattern: Event-driven notification pattern. Full implementation history: docs/stories/story-4.6-timeline-update-notifications.md
## Acceptance Criteria
- [ ] Email sent when new update added to timeline
- [ ] Triggered automatically on TimelineUpdate creation
- [ ] Queued for performance
- [ ] Case name and reference
- [ ] Update summary or full text
- [ ] Date of update
- [ ] Link to view timeline
- [ ] Libra branding
- [ ] Email in client's preferred language
- [ ] Arabic template
- [ ] English template
- [ ] No email for archived timeline reactivation
- [ ] No email if client deactivated
- [ ] Professional email template
- [ ] Tests for notification sending
- [ ] Error handling for failed sends
+21
View File
@@ -0,0 +1,21 @@
---
id: 4
title: 4 Case Timeline System
status: Done
date: 2026-09-27
---
## Description
Lets the admin create and maintain one-way, text-only case timelines per client (multiple timelines per client, active/archived states), with clients able to view (read-only) their timelines and receive email notifications on updates.
## Acceptance Criteria
- [ ] Admin can create unlimited timelines per client
- [ ] Admin can add text updates to timelines
- [ ] Admin can edit existing updates
- [ ] Admin can archive/unarchive timelines
- [ ] Clients can view their timelines (read-only)
- [ ] Clients notified via email on updates
- [ ] Update history with timestamps preserved
- [ ] Clear visual distinction between active/archived
+33
View File
@@ -0,0 +1,33 @@
---
id: 5-1
title: 5-1 Post Creation & Editing
status: Done
date: 2026-09-27
parent: 5
---
## Description
As an admin, I want to create and edit blog posts with rich text formatting, So that I can publish professional legal content for website visitors. Context: Integrates with: posts table; Technology: Livewire Volt, TinyMCE or similar rich text editor; Follows pattern: Admin CRUD pattern. Use the mews/purifier package for HTML sanitization via the clean() helper:. Full implementation history: docs/stories/story-5.1-post-creation-editing.md
## Acceptance Criteria
- [ ] Title (required, bilingual: Arabic and English)
- [ ] Body content (required, bilingual)
- [ ] Status (draft/published)
- [ ] Bold, italic, underline
- [ ] Headings (H2, H3)
- [ ] Bullet and numbered lists
- [ ] Links
- [ ] Blockquotes
- [ ] Save as draft functionality
- [ ] Preview post before publishing
- [ ] Edit published posts
- [ ] Auto-save draft periodically (every 60 seconds)
- [ ] Immediate publishing (no scheduling)
- [ ] created_at recorded on creation
- [ ] updated_at updated on edit
- [ ] HTML sanitization for XSS prevention
- [ ] Bilingual form labels
- [ ] Audit log for create/edit
- [ ] Tests for CRUD operations
+30
View File
@@ -0,0 +1,30 @@
---
id: 5-2
title: 5-2 Post Management Dashboard
status: Done
date: 2026-09-27
parent: 5
---
## Description
As an admin, I want a dashboard to manage all blog posts, So that I can organize, publish, and maintain content efficiently. Context: Integrates with: posts table, admin_logs table; Technology: Livewire Volt with pagination; Follows pattern: Admin list pattern (see similar components in `resources/views/livewire/admin/`). Create Volt component at: resources/views/livewire/admin/posts/index.blade.php. Full implementation history: docs/stories/story-5.2-post-management-dashboard.md
## Acceptance Criteria
- [ ] Display all posts with:
- [ ] Pagination (10/25/50 per page)
- [ ] Filter by status (draft/published/all)
- [ ] Search by title or body content
- [ ] Sort by date (newest/oldest)
- [ ] Edit post
- [ ] Delete (with confirmation)
- [ ] Publish/unpublish toggle
- [ ] Bulk delete option (optional) - **OUT OF SCOPE**
- [ ] Bilingual labels
- [ ] Audit log for delete and status change actions
- [ ] Authorization check (admin only) on all actions
- [ ] Tests for list operations
- [ ] Handle post not found gracefully (race condition on delete)
- [ ] Per-page selector visible in UI (10/25/50 options)
- [ ] Bulk delete is **out of scope** for this story (marked optional)
+26
View File
@@ -0,0 +1,26 @@
---
id: 5-3
title: 5-3 Post Deletion
status: Done
date: 2026-09-27
parent: 5
---
## Description
As an admin, I want to permanently delete posts, So that I can remove outdated or incorrect content from the website. Context: Integrates with: posts table; Technology: Livewire Volt; Follows pattern: Permanent delete pattern. Add delete button to the post edit form (from Story 5.1) when editing an existing post:. Full implementation history: docs/stories/story-5.3-post-deletion.md
## Acceptance Criteria
- [ ] Delete button on post list (primary location)
- [ ] Delete button on post edit page (secondary location)
- [ ] Confirmation modal dialog before deletion
- [ ] Permanent deletion (no soft delete per PRD)
- [ ] Success message after deletion
- [ ] Redirect to post list after deletion from edit page
- [ ] Admin-only access (middleware protection)
- [ ] Audit log entry preserved
- [ ] Old values stored in log
- [ ] Clear warning in confirmation
- [ ] Bilingual messages
- [ ] Tests for deletion
+32
View File
@@ -0,0 +1,32 @@
---
id: 5-4
title: 5-4 Public Posts Display
status: Done
date: 2026-09-27
parent: 5
---
## Description
As a website visitor, I want to view published blog posts, So that I can read legal updates and articles from the firm. Context: Integrates with: posts table (published only); Technology: Livewire Volt (public routes); Follows pattern: Public content display. Full implementation history: docs/stories/story-5.4-public-posts-display.md
## Acceptance Criteria
- [ ] Public access (no login required)
- [ ] Display in reverse chronological order
- [ ] Each post card shows:
- [ ] Pagination for many posts
- [ ] Full post content displayed
- [ ] Clean, readable typography
- [ ] Publication date shown
- [ ] Back to posts list link
- [ ] Content displayed based on current site language
- [ ] Title and body in selected language
- [ ] Date formatting per locale
- [ ] Responsive design (mobile-friendly)
- [ ] Professional typography
- [ ] Consistent with brand colors
- [ ] Only published posts visible
- [ ] Fast loading
- [ ] SEO-friendly URLs (optional per PRD)
- [ ] Tests for display logic
+27
View File
@@ -0,0 +1,27 @@
---
id: 5-5
title: 5-5 Post Search
status: Done
date: 2026-09-27
parent: 5
---
## Description
As a website visitor, I want to search through blog posts, So that I can find relevant legal articles and information. Context: Integrates with: posts table, public posts listing; Technology: Livewire Volt with real-time search; Follows pattern: Search component pattern. Full implementation history: docs/stories/story-5.5-post-search.md
## Acceptance Criteria
- [ ] Search input on posts listing page
- [ ] Search by title (both languages)
- [ ] Search by body content (both languages)
- [ ] Real-time search results (debounced)
- [ ] "No results found" message when empty
- [ ] Clear search button
- [ ] Search works in both Arabic and English
- [ ] Only searches published posts
- [ ] Search highlights in results
- [ ] Search suggestions
- [ ] Debounce to reduce server load (300ms)
- [ ] Case-insensitive search
- [ ] Tests for search functionality
+21
View File
@@ -0,0 +1,21 @@
---
id: 5
title: 5 Posts/Blog System
status: Done
date: 2026-09-27
---
## Description
An admin-only publishing system for legal articles/news: rich-text creation and editing, draft saving, deletion, public bilingual display in reverse-chronological order, and simple title/body search — all without login or comments.
## Acceptance Criteria
- [ ] Admin can create, edit, delete posts
- [ ] Rich text editor for formatting
- [ ] Draft saving capability
- [ ] Posts publicly visible
- [ ] Search functionality
- [ ] Reverse chronological display
- [ ] Bilingual content support
- [ ] Responsive design
+33
View File
@@ -0,0 +1,33 @@
---
id: 6-1
title: 6-1 Dashboard Overview & Statistics
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to see real-time metrics and key statistics at a glance, So that I can understand the current state of my practice. Full implementation history: docs/stories/story-6.1-dashboard-overview-statistics.md
## Acceptance Criteria
- [ ] Total active clients (individual + company with status = active)
- [ ] Individual vs company breakdown (count each type)
- [ ] Deactivated clients count
- [ ] New clients this month (created_at in current month)
- [ ] Pending requests count (highlighted with warning color)
- [ ] Today's consultations (scheduled for today, approved status)
- [ ] This week's consultations
- [ ] This month's consultations
- [ ] Free vs paid breakdown (consultation_type field)
- [ ] No-show rate percentage (no-show / total completed * 100)
- [ ] Active case timelines (status = active)
- [ ] Archived timelines (status = archived)
- [ ] Updates added this week (timeline_updates created in last 7 days)
- [ ] Total published posts (status = published)
- [ ] Posts published this month
- [ ] Clean card-based layout using Flux UI components
- [ ] Color-coded status indicators (gold for highlights, success green, warning colors)
- [ ] Responsive grid (2 columns on tablet, 1 on mobile, 4 on desktop)
- [ ] Navy blue and gold color scheme per PRD Section 7.1
+34
View File
@@ -0,0 +1,34 @@
---
id: 6-10
title: 6-10 Audit Log Viewer
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to view admin action history, So that I can maintain accountability and track changes. - resources/views/livewire/admin/audit-logs.blade.php - Main Volt component - app/Models/AdminLog.php - Eloquent model (if not already created in Story 1.1) - routes/web.php - Add admin route (or admin routes file) - lang/ar/audit.php - Arabic translations - lang/en/audit.php - English translations. Full implementation history: docs/stories/story-6.10-audit-log-viewer.md
## Acceptance Criteria
- [ ] Paginated table of audit log entries (25 per page)
- [ ] Each row displays:
- [ ] Filter by action type (dropdown with available actions)
- [ ] Filter by target type (dropdown with available targets)
- [ ] Filter by date range (date pickers for from/to)
- [ ] Filters apply without page reload (Livewire)
- [ ] Reset filters button
- [ ] Search by target ID (exact match)
- [ ] Search updates results in real-time with debounce
- [ ] Modal displays full log entry details
- [ ] Shows old values in readable format (JSON pretty-printed)
- [ ] Shows new values in readable format
- [ ] Highlights differences between old/new for updates
- [ ] Bilingual labels
- [ ] Export current filtered results to CSV
- [ ] CSV includes all displayed columns
- [ ] CSV filename includes export date
- [ ] Bilingual column headers based on admin's language preference
- [ ] Friendly message when no logs exist
- [ ] Friendly message when filters return no results
+39
View File
@@ -0,0 +1,39 @@
---
id: 6-2
title: 6-2 Analytics Charts
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want visual charts showing trends and historical data, So that I can identify patterns in client acquisition and consultation outcomes to make informed business decisions. Full implementation history: docs/stories/story-6.2-analytics-charts.md
## Acceptance Criteria
- [ ] Display new clients per month (from `users.created_at`)
- [ ] Display consultations per month (from `consultations.scheduled_date`)
- [ ] Two data series on same chart with legend
- [ ] X-axis: Month labels (e.g., "Jan 2025", "Feb 2025")
- [ ] Y-axis: Count values with appropriate scale
- [ ] Show free vs paid consultation ratio
- [ ] Display percentage labels on segments
- [ ] Legend showing "Free" and "Paid" with counts
- [ ] Monthly no-show percentage trend
- [ ] X-axis: Month labels
- [ ] Y-axis: Percentage (0-100%)
- [ ] Visual threshold line at concerning rate (e.g., 20%)
- [ ] Preset options: Last 6 months, Last 12 months
- [ ] Custom date range picker (start/end month)
- [ ] Charts update when range changes
- [ ] Default selection: Last 6 months
- [ ] Tooltips showing exact values on hover
- [ ] Responsive sizing (charts resize with viewport)
- [ ] Bilingual labels (Arabic/English based on locale)
- [ ] Loading state while fetching data
- [ ] Empty state when no data available
- [ ] Charts section below statistics cards from Story 6.1
- [ ] Card-based layout for each chart
- [ ] Navy blue and gold color scheme per PRD Section 7.1
- [ ] Responsive grid (1 column mobile, 2 columns tablet+)
+37
View File
@@ -0,0 +1,37 @@
---
id: 6-3
title: 6-3 Quick Actions Panel
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want quick access to pending items and common tasks, So that I can efficiently manage my daily workflow without navigating away from the dashboard. Full implementation history: docs/stories/story-6.3-quick-actions-panel.md
## Acceptance Criteria
- [ ] Display count badge showing number of pending consultation requests
- [ ] Urgent indicator (red/warning styling) when pending count > 0
- [ ] Mini list showing up to 5 most recent pending bookings with:
- [ ] "View All" link navigating to booking management page (`admin.bookings.pending`)
- [ ] Empty state message when no pending bookings
- [ ] List of today's approved consultations ordered by time
- [ ] Each item displays:
- [ ] Quick status buttons for each consultation:
- [ ] Empty state message when no consultations scheduled today
- [ ] Display last 5 timeline updates across all clients
- [ ] Each item shows:
- [ ] Click navigates to the specific timeline (`admin.timelines.show`)
- [ ] Empty state message when no recent updates
- [ ] **Create Client** button - navigates to `admin.clients.individual.create`
- [ ] **Create Post** button - navigates to `admin.posts.create`
- [ ] **Block Time Slot** button - opens modal to block availability
- [ ] Bell icon in admin header/navbar
- [ ] Badge showing total pending items count (pending bookings)
- [ ] Badge hidden when count is 0
- [ ] Click navigates to pending bookings
- [ ] Widgets auto-refresh via Livewire polling every 30 seconds
- [ ] No full page reload required
- [ ] Visual indication during refresh (subtle loading state) - Using default Livewire behavior
+42
View File
@@ -0,0 +1,42 @@
---
id: 6-4
title: 6-4 Data Export - User Lists
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to export user data in CSV and PDF formats, So that I can generate reports and maintain offline records. Full implementation history: docs/stories/story-6.4-data-export-user-lists.md
## Acceptance Criteria
- [ ] Export all users (both individual and company clients)
- [ ] Export individual clients only (`user_type = 'individual'`)
- [ ] Export company clients only (`user_type = 'company'`)
- [ ] Date range filter on `created_at` field (start date, end date)
- [ ] Status filter: active, deactivated, or all
- [ ] Filters combine with export type (e.g., "active individual clients created in 2024")
- [ ] Name (`name` for individual, `company_name` for company)
- [ ] Email (`email`)
- [ ] Phone (`phone`)
- [ ] User type (`user_type`: individual/company)
- [ ] National ID / Company registration (`national_id` for individual, `company_cert_number` for company)
- [ ] Status (`status`: active/deactivated)
- [ ] Created date (`created_at` formatted per locale)
- [ ] UTF-8 BOM for proper Arabic character display in Excel
- [ ] Same data fields as CSV in tabular format
- [ ] Libra branding header (logo, firm name)
- [ ] Generation timestamp in footer
- [ ] Page numbers if multiple pages
- [ ] Professional formatting with brand colors (Navy #0A1F44, Gold #D4AF37)
- [ ] Column headers based on admin's `preferred_language` setting
- [ ] Date formatting per locale (DD/MM/YYYY for Arabic, MM/DD/YYYY for English)
- [ ] PDF title and footer text bilingual
- [ ] Export section accessible from Admin User Management page
- [ ] Filter form with: user type dropdown, status dropdown, date range picker
- [ ] "Export CSV" and "Export PDF" buttons
- [ ] Loading indicator during export generation
- [ ] Success toast on download start
- [ ] Error toast if export fails
+30
View File
@@ -0,0 +1,30 @@
---
id: 6-5
title: 6-5 Data Export - Consultation Records
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to export consultation/booking data in CSV and PDF formats, So that I can generate reports for accounting, analyze consultation patterns, and maintain offline records of client interactions. Follow the export pattern established in Story 6.4. Reuse any base export functionality created there. Full implementation history: docs/stories/story-6.5-data-export-consultation-records.md
## Acceptance Criteria
- [ ] Export all consultations
- [ ] Export filtered subset based on criteria below
- [ ] Date range (booking_date between start/end)
- [ ] Consultation type (free/paid)
- [ ] Status (pending/approved/completed/no-show/cancelled/rejected)
- [ ] Payment status (pending/received/na)
- [ ] Client name (from user relationship)
- [ ] Date and time (booking_date, booking_time)
- [ ] Consultation type (free/paid)
- [ ] Status
- [ ] Payment status
- [ ] Problem summary (truncated in PDF if > 500 chars)
- [ ] CSV format with streaming download
- [ ] PDF format with professional layout and Libra branding
- [ ] Column headers based on admin's preferred language
- [ ] Use translation keys from `lang/{locale}/export.php`
+33
View File
@@ -0,0 +1,33 @@
---
id: 6-6
title: 6-6 Data Export - Timeline Reports
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to export timeline and case data, So that I can maintain records and generate case reports. Context: Follows pattern: Story 6.4 (User Lists Export) and Story 6.5 (Consultation Export) - same UI layout, filter approach, and export mechanisms; Integrates with: Timeline model, TimelineUpdate model, User model; Technology: Livewire Volt, Flux UI, league/csv, barryvdh/laravel-dompdf. Full implementation history: docs/stories/story-6.6-data-export-timeline-reports.md
## Acceptance Criteria
- [ ] Export all timelines (across all clients)
- [ ] Export timelines for specific client (client selector/search)
- [ ] Status filter (active/archived/all)
- [ ] Date range filter (created_at)
- [ ] Client filter (search by name/email)
- [ ] Case name and reference
- [ ] Client name
- [ ] Status
- [ ] Created date
- [ ] Number of updates
- [ ] Last update date
- [ ] CSV format with bilingual headers
- [ ] PDF format with Libra branding
- [ ] Include update content toggle (full content vs summary only)
- [ ] When enabled, PDF includes all update entries per timeline
- [ ] Filter controls match Story 6.4/6.5 layout
- [ ] Export buttons clearly visible
- [ ] Loading state during export generation
- [ ] Success/error feedback messages
+52
View File
@@ -0,0 +1,52 @@
---
id: 6-7
title: 6-7 Monthly Statistics Report
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to generate comprehensive monthly PDF reports from the admin dashboard, So that I can archive business performance records, share summaries with stakeholders, and track month-over-month trends. Full implementation history: docs/stories/story-6.7-monthly-statistics-report.md
## Acceptance Criteria
- [ ] "Generate Monthly Report" button in admin dashboard (below metrics cards or in a Reports section)
- [ ] Month/year selector dropdown (default: previous month)
- [ ] Selectable range: last 12 months only (no future months)
- [ ] Libra logo and branding
- [ ] Report title: "Monthly Statistics Report"
- [ ] Period: Month and Year (e.g., "December 2025")
- [ ] Generated date and time
- [ ] List of sections with page numbers
- [ ] Non-clickable (simple text list for print compatibility)
- [ ] Key highlights (2-3 bullet points)
- [ ] Month-over-month comparison if prior month data exists
- [ ] New clients registered this month
- [ ] Total active clients (end of month)
- [ ] Individual vs company breakdown
- [ ] Client growth trend (compared to previous month)
- [ ] Total consultations this month
- [ ] Approved/Completed/Cancelled/No-show breakdown
- [ ] Free vs paid ratio
- [ ] No-show rate percentage
- [ ] Pie chart: Consultation types (rendered as image)
- [ ] Active timelines (end of month)
- [ ] New timelines created this month
- [ ] Timeline updates added this month
- [ ] Archived timelines this month
- [ ] Posts published this month
- [ ] Total published posts (cumulative)
- [ ] Line chart showing monthly consultations trend (last 6 months ending with selected month)
- [ ] Rendered as base64 PNG image
- [ ] Professional A4 portrait layout
- [ ] Libra branding: Navy Blue (#0A1F44) headers, Gold (#D4AF37) accents
- [ ] Consistent typography and spacing
- [ ] Print-friendly (no dark backgrounds, adequate margins)
- [ ] Bilingual: Arabic or English based on admin's `preferred_language` setting
- [ ] Loading indicator with "Generating report..." message during PDF creation
- [ ] Disable generate button while processing
- [ ] Auto-download PDF on completion
- [ ] Success toast notification after download starts
- [ ] Error handling with user-friendly message if generation fails
+26
View File
@@ -0,0 +1,26 @@
---
id: 6-8
title: 6-8 System Settings
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to configure system-wide settings, So that I can customize the platform to my needs. Add preferred_language column to users table:. Full implementation history: docs/stories/story-6.8-system-settings.md
## Acceptance Criteria
- [ ] Admin name
- [ ] Email
- [ ] Password change
- [ ] Preferred language
- [ ] Display current sender email from `config('mail.from.address')`
- [ ] Display current sender name from `config('mail.from.name')`
- [ ] "Send Test Email" button that sends a test email to admin's email address
- [ ] Success/error feedback after test email attempt
- [ ] Settings saved and applied immediately
- [ ] Validation for all inputs
- [ ] Flash messages for success/error states
- [ ] Password fields cleared after successful update
+30
View File
@@ -0,0 +1,30 @@
---
id: 6-9
title: 6-9 Legal Pages Editor
status: Done
date: 2026-09-27
parent: 6
---
## Description
As an admin, I want to edit Terms of Service and Privacy Policy pages, So that I can maintain legal compliance and update policies. This project uses **class-based Volt components** for interactivity. Follow existing patterns in resources/views/livewire/. Full implementation history: docs/stories/story-6.9-legal-pages-editor.md
## Acceptance Criteria
- [ ] Terms of Service (`/page/terms`)
- [ ] Privacy Policy (`/page/privacy`)
- [ ] Rich text editor using Quill.js (lightweight, RTL-friendly)
- [ ] Bilingual content with Arabic/English tabs in editor UI
- [ ] Save and publish button updates database immediately
- [ ] Preview opens modal showing rendered content in selected language
- [ ] HTML content sanitized before save (prevent XSS)
- [ ] Accessible under Admin Dashboard > Settings section
- [ ] Sidebar item: "Legal Pages" or integrate into Settings page
- [ ] List view showing both pages with "Edit" action
- [ ] Edit page shows language tabs (Arabic | English) above editor
- [ ] Pages accessible from footer links (no auth required)
- [ ] Route: `/page/{slug}` where slug is `terms` or `privacy`
- [ ] Content displayed in user's current language preference
- [ ] Last updated timestamp displayed at bottom of page
- [ ] Professional layout consistent with site design (navy/gold)
+21
View File
@@ -0,0 +1,21 @@
---
id: 6
title: 6 Admin Dashboard
status: Done
date: 2026-09-27
---
## Description
A centralized control panel for the admin: overview statistics, Chart.js analytics, a quick-actions panel, CSV/PDF data exports (users, consultations, timelines, monthly stats), system settings, a legal-pages (Terms/Privacy) editor, and an audit-log viewer.
## Acceptance Criteria
- [ ] Overview dashboard with key metrics
- [ ] Charts for trends and analytics
- [ ] Quick access to pending actions
- [ ] Data export (CSV, PDF)
- [ ] System settings management
- [ ] Legal pages editor (Terms, Privacy)
- [ ] Audit log visibility
- [ ] Responsive design for tablet use
+44
View File
@@ -0,0 +1,44 @@
---
id: 7-1
title: 7-1 Client Dashboard Overview
status: Done
date: 2026-09-27
parent: 7
---
## Description
As a client, I want a dashboard showing my key information at a glance, So that I can quickly see upcoming consultations and case updates. Full implementation history: docs/stories/story-7.1-client-dashboard-overview.md
## Acceptance Criteria
- [ ] Display "Welcome, {client name}" greeting
- [ ] Use localized greeting based on user's preferred language
- [ ] Show current date in user's locale format
- [ ] Display next approved consultation (or "No upcoming consultations" if none)
- [ ] Show consultation date/time formatted per locale (AR: DD/MM/YYYY, EN: MM/DD/YYYY)
- [ ] Show time in 12-hour format (AM/PM)
- [ ] Display type badge: "Free" (green) or "Paid" (gold)
- [ ] Display status badge with appropriate color
- [ ] "View Details" link to consultation details (Story 7.2)
- [ ] Display count of active timelines
- [ ] Show preview of most recent update (truncated to ~100 chars)
- [ ] "View All Cases" link to timelines list (Story 7.3)
- [ ] Empty state: "No active cases" with muted styling
- [ ] Display last 3 timeline updates across all user's cases
- [ ] Each update shows: case name, update date, preview text
- [ ] "View Timeline" link for each update
- [ ] Empty state: "No recent updates"
- [ ] Display count of pending booking requests
- [ ] Show booking limit indicator:
- [ ] "Book Consultation" button linking to booking page (Story 7.5)
- [ ] Disable button if daily limit reached
- [ ] Card-based layout using Flux UI components
- [ ] Color scheme: Navy (#0A1F44) background sections, Gold (#D4AF37) accents
- [ ] Mobile-first responsive (stack cards vertically on mobile)
- [ ] All text content bilingual (Arabic RTL / English LTR)
- [ ] Use consistent spacing: `gap-6` between cards, `p-6` card padding
- [ ] No consultations: Show empty state with "Book your first consultation" CTA
- [ ] No timelines: Show empty state "No cases assigned yet"
- [ ] No updates: Show empty state "No recent updates"
- [ ] Loading state: Show skeleton loaders while data fetches

Some files were not shown because too many files have changed in this diff Show More