diff --git a/docs/qa/gates/5.5-post-search.yml b/docs/qa/gates/5.5-post-search.yml
new file mode 100644
index 0000000..b6b0dd1
--- /dev/null
+++ b/docs/qa/gates/5.5-post-search.yml
@@ -0,0 +1,52 @@
+# Quality Gate Decision
+schema: 1
+story: "5.5"
+story_title: "Post Search"
+gate: PASS
+status_reason: "All acceptance criteria met with comprehensive test coverage. Implementation follows coding standards with proper security measures (XSS protection, regex injection prevention)."
+reviewer: "Quinn (Test Architect)"
+updated: "2025-12-27T00:00:00Z"
+
+waiver: { active: false }
+
+top_issues: []
+
+risk_summary:
+ totals: { critical: 0, high: 0, medium: 0, low: 0 }
+ recommendations:
+ must_fix: []
+ monitor:
+ - action: "Monitor search performance at scale - LIKE on JSON columns may need optimization for large datasets"
+ refs: ["resources/views/livewire/pages/posts/index.blade.php:47-49"]
+
+quality_score: 100
+expires: "2026-01-10T00:00:00Z"
+
+evidence:
+ tests_reviewed: 9
+ risks_identified: 0
+ trace:
+ ac_covered: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ ac_gaps: []
+
+nfr_validation:
+ security:
+ status: PASS
+ notes: "XSS protection via e() escaping, regex injection prevented via preg_quote(), published-only scope"
+ performance:
+ status: PASS
+ notes: "300ms debounce, pagination at 10 items. LIKE on JSON acceptable for blog scale"
+ reliability:
+ status: PASS
+ notes: "Proper error handling, graceful empty states"
+ maintainability:
+ status: PASS
+ notes: "Clean code following Volt class-based pattern, well-structured tests"
+
+recommendations:
+ immediate: []
+ future:
+ - action: "Consider full-text search or JSON path operators if post volume grows significantly"
+ refs: ["resources/views/livewire/pages/posts/index.blade.php:47-49"]
+ - action: "Search suggestions feature (marked optional in story)"
+ refs: ["docs/stories/story-5.5-post-search.md:35"]
diff --git a/docs/stories/story-5.5-post-search.md b/docs/stories/story-5.5-post-search.md
index 76868f9..af8f3f5 100644
--- a/docs/stories/story-5.5-post-search.md
+++ b/docs/stories/story-5.5-post-search.md
@@ -19,25 +19,25 @@ So that **I can find relevant legal articles and information**.
## Acceptance Criteria
### Search Functionality
-- [ ] Search input on posts listing page
-- [ ] Search by title (both languages)
-- [ ] Search by body content (both languages)
-- [ ] Real-time search results (debounced)
+- [x] Search input on posts listing page
+- [x] Search by title (both languages)
+- [x] Search by body content (both languages)
+- [x] Real-time search results (debounced)
### User Experience
-- [ ] "No results found" message when empty
-- [ ] Clear search button
-- [ ] Search works in both Arabic and English
-- [ ] Only searches published posts
+- [x] "No results found" message when empty
+- [x] Clear search button
+- [x] Search works in both Arabic and English
+- [x] Only searches published posts
### Optional Enhancements
-- [ ] Search highlights in results
+- [x] Search highlights in results
- [ ] Search suggestions
### Quality Requirements
-- [ ] Debounce to reduce server load (300ms)
-- [ ] Case-insensitive search
-- [ ] Tests for search functionality
+- [x] Debounce to reduce server load (300ms)
+- [x] Case-insensitive search
+- [x] Tests for search functionality
## Technical Notes
@@ -254,16 +254,48 @@ it('only searches published posts', function () {
## Definition of Done
-- [ ] Search input on posts page
-- [ ] Searches title in both languages
-- [ ] Searches body in both languages
-- [ ] Real-time results with debounce
-- [ ] Clear search button works
-- [ ] "No results" message shows
-- [ ] Only published posts searched
-- [ ] Search highlighting works
-- [ ] Tests pass
-- [ ] Code formatted with Pint
+- [x] Search input on posts page
+- [x] Searches title in both languages
+- [x] Searches body in both languages
+- [x] Real-time results with debounce
+- [x] Clear search button works
+- [x] "No results" message shows
+- [x] Only published posts searched
+- [x] Search highlighting works
+- [x] Tests pass
+- [x] Code formatted with Pint
+
+## Dev Agent Record
+
+### Agent Model Used
+Claude Opus 4.5
+
+### Completion Notes
+- Implemented search functionality on the posts index page with real-time debounced search (300ms)
+- Search queries both title and body fields as JSON columns (works with SQLite for tests and MySQL/MariaDB for production)
+- Added search result highlighting with gold background on matched terms
+- Clear search button with RTL/LTR position awareness
+- Added bilingual translation strings for search UI (English and Arabic)
+- 9 new search-specific tests added to PostsTest.php covering title search, body search, Arabic search, case-insensitivity, pagination reset, and clear functionality
+- All 22 posts tests pass, full test suite passes
+
+### File List
+- `resources/views/livewire/pages/posts/index.blade.php` (modified) - Added search functionality and highlight method
+- `lang/en/posts.php` (modified) - Added search translation strings
+- `lang/ar/posts.php` (modified) - Added Arabic search translation strings
+- `tests/Feature/Public/PostsTest.php` (modified) - Added 9 search tests
+
+### Change Log
+- Added `$search` property with debounced live binding
+- Added `updatedSearch()` method to reset pagination on search change
+- Added `clearSearch()` method to clear search and reset pagination
+- Added `highlightSearch()` method for search term highlighting with HTML escaping
+- Updated `with()` query to filter posts by title and body columns using LIKE
+- Added search input with magnifying glass icon
+- Added clear search button (X) with RTL-aware positioning
+- Added search results info message showing count or "no results" message
+- Added empty state with search icon and clear button when search yields no results
+- Search highlighting applied to both title and excerpt in search results
## Dependencies
@@ -273,3 +305,125 @@ it('only searches published posts', function () {
**Complexity:** Low-Medium
**Estimated Effort:** 2-3 hours
+
+---
+
+## QA Results
+
+### Review Date: 2025-12-27
+
+### Reviewed By: Quinn (Test Architect)
+
+### Code Quality Assessment
+
+The implementation is solid and follows project conventions well. The search functionality is implemented correctly using Livewire Volt's class-based pattern with proper debouncing, pagination reset, and bilingual support. The `highlightSearch()` method is well-designed with proper XSS protection using `e()` for both input text and search term before applying regex highlighting.
+
+**Notable positives:**
+- Clean, readable code following coding standards
+- Proper use of Flux UI components
+- RTL-aware positioning for the clear search button
+- Good separation between display logic (getTitle/getExcerpt) and search logic
+
+### Refactoring Performed
+
+None required - the implementation is clean and follows best practices.
+
+### Compliance Check
+
+- Coding Standards: ✓ Uses class-based Volt pattern, Flux UI components, proper testing
+- Project Structure: ✓ Files in correct locations, naming follows conventions
+- Testing Strategy: ✓ 9 comprehensive tests with 22 assertions covering all scenarios
+- All ACs Met: ✓ All acceptance criteria verified with corresponding tests
+
+### Improvements Checklist
+
+- [x] Search functionality implemented with proper debouncing (300ms)
+- [x] Bilingual search working for both title and body
+- [x] XSS protection in highlight function
+- [x] Case-insensitive search implemented
+- [x] Clear search resets pagination
+- [x] "No results" message displays correctly
+- [x] Only published posts are searched
+- [ ] Optional: Consider JSON path operators (`->`) for more precise JSON column searches in production MySQL (current LIKE on JSON works but is less precise)
+- [ ] Optional enhancement: Search suggestions (marked as optional in story, not implemented)
+
+### Security Review
+
+✓ **XSS Protection**: The `highlightSearch()` method properly escapes HTML using `e()` before applying regex replacement, preventing XSS attacks.
+✓ **Regex Injection**: `preg_quote()` is used to escape special regex characters in the search term.
+✓ **Authorization**: Search is scoped to `published()` posts only - draft content is not accessible.
+
+### Performance Considerations
+
+✓ **Debouncing**: 300ms debounce reduces unnecessary server requests
+✓ **Pagination**: 10 items per page limits data transfer
+- Note: LIKE queries on JSON columns may become slow with very large datasets. For a blog with hundreds/thousands of posts, this is acceptable. For larger scale, consider full-text search indexes.
+
+### Files Modified During Review
+
+None - no refactoring was required.
+
+### Gate Status
+
+Gate: PASS → docs/qa/gates/5.5-post-search.yml
+
+### Recommended Status
+
+✓ Ready for Done - All acceptance criteria met, tests pass, code follows standards.
+
+---
+
+## Story DoD Checklist
+
+### 1. Requirements Met:
+- [x] All functional requirements specified in the story are implemented.
+ - Search input on posts listing page ✓
+ - Search by title (both languages) ✓
+ - Search by body content (both languages) ✓
+ - Real-time search with 300ms debounce ✓
+- [x] All acceptance criteria defined in the story are met.
+ - "No results found" message ✓
+ - Clear search button ✓
+ - Works in Arabic and English ✓
+ - Only searches published posts ✓
+ - Search highlights in results ✓
+
+### 2. Coding Standards & Project Structure:
+- [x] All new/modified code strictly adheres to `Operational Guidelines`.
+- [x] All new/modified code aligns with `Project Structure` (file locations, naming, etc.).
+- [x] Adherence to `Tech Stack` for technologies/versions used.
+- [N/A] Adherence to `Api Reference` and `Data Models` - No API or data model changes.
+- [x] Basic security best practices applied (HTML escaping in highlight function).
+- [x] No new linter errors or warnings introduced (Pint passes).
+- [x] Code is well-commented where necessary.
+
+### 3. Testing:
+- [x] All required unit tests implemented (9 new search tests).
+- [N/A] Integration tests - Component tests cover functionality adequately.
+- [x] All tests pass successfully (22 posts tests, full suite passes).
+- [x] Test coverage meets project standards.
+
+### 4. Functionality & Verification:
+- [x] Functionality verified through comprehensive test suite.
+- [x] Edge cases handled (empty search, no results, case-insensitivity, RTL support).
+
+### 5. Story Administration:
+- [x] All tasks within the story file are marked as complete.
+- [x] Decisions documented (search on raw JSON columns vs JSON path, highlight implementation).
+- [x] Story wrap up section completed with change log and file list.
+
+### 6. Dependencies, Build & Configuration:
+- [x] Project builds successfully without errors.
+- [x] Project linting passes (Pint --dirty).
+- [N/A] No new dependencies added.
+- [N/A] No new environment variables or configurations.
+
+### 7. Documentation:
+- [x] Inline code documentation adequate (method names are self-documenting).
+- [N/A] No user-facing documentation changes needed.
+- [N/A] No architectural changes made.
+
+### Final Confirmation
+- [x] I, the Developer Agent, confirm that all applicable items above have been addressed.
+
+**Status: Ready for Review**
diff --git a/lang/ar/posts.php b/lang/ar/posts.php
index 62a5964..bd5de2c 100644
--- a/lang/ar/posts.php
+++ b/lang/ar/posts.php
@@ -7,6 +7,9 @@ return [
'create_post' => 'إنشاء مقال',
'no_posts' => 'لا توجد مقالات.',
'search_placeholder' => 'البحث في المقالات...',
+ 'search_results' => 'تم العثور على :count نتيجة لـ ":query"',
+ 'no_results' => 'لم يتم العثور على نتائج لـ ":query"',
+ 'clear_search' => 'مسح البحث',
'last_updated' => 'آخر تحديث',
'created' => 'تاريخ الإنشاء',
'read_more' => 'اقرأ المزيد',
diff --git a/lang/en/posts.php b/lang/en/posts.php
index e82a3b5..348dcbc 100644
--- a/lang/en/posts.php
+++ b/lang/en/posts.php
@@ -7,6 +7,9 @@ return [
'create_post' => 'Create Post',
'no_posts' => 'No posts found.',
'search_placeholder' => 'Search posts...',
+ 'search_results' => 'Found :count results for ":query"',
+ 'no_results' => 'No results found for ":query"',
+ 'clear_search' => 'Clear search',
'last_updated' => 'Last Updated',
'created' => 'Created',
'read_more' => 'Read More',
diff --git a/resources/views/livewire/pages/posts/index.blade.php b/resources/views/livewire/pages/posts/index.blade.php
index af29a0e..fead8c7 100644
--- a/resources/views/livewire/pages/posts/index.blade.php
+++ b/resources/views/livewire/pages/posts/index.blade.php
@@ -9,10 +9,46 @@ new #[Layout('components.layouts.public')] class extends Component
{
use WithPagination;
+ public string $search = '';
+
+ public function updatedSearch(): void
+ {
+ $this->resetPage();
+ }
+
+ public function clearSearch(): void
+ {
+ $this->search = '';
+ $this->resetPage();
+ }
+
+ public function highlightSearch(string $text, string $search): string
+ {
+ if (empty($search)) {
+ return e($text);
+ }
+
+ $escapedText = e($text);
+ $escapedSearch = e($search);
+
+ return preg_replace(
+ '/('.preg_quote($escapedSearch, '/').')/iu',
+ '$1',
+ $escapedText
+ );
+ }
+
public function with(): array
{
return [
'posts' => Post::published()
+ ->when($this->search, function ($query) {
+ $search = $this->search;
+ $query->where(function ($q) use ($search) {
+ $q->where('title', 'like', "%{$search}%")
+ ->orWhere('body', 'like', "%{$search}%");
+ });
+ })
->latest()
->paginate(10),
];
@@ -22,12 +58,50 @@ new #[Layout('components.layouts.public')] class extends Component