Archive roadmap and requirements to milestones/v1.0-*.
Evolve PROJECT.md with validated requirements and decisions.
Reorganize ROADMAP.md with milestone grouping.
Delete REQUIREMENTS.md (fresh for next milestone).
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
<template x-data> inside <tbody> is inert — browsers don't render its
children. Replace with per-member <tbody x-data> (multiple tbody is
valid HTML). Also replace x-collapse on <tr> with x-transition since
table rows don't support max-height/overflow-hidden.
UAT: all 7 tests passed via Playwright automation.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- Test notes index returns author name and created_at for display
- Test empty state response (empty array when no notes)
- Test Blade view renders all Alpine.js history panel directives
- Test store endpoint returns complete note data for cache sync
- All 11 tests pass (7 existing + 4 new)
- Install @alpinejs/collapse plugin for smooth expand/collapse animation
- Fix controller ordering: notes now explicitly ordered newest first via latest('created_at')
- Note count badge is now clickable button to toggle history panel
- Add expansion panel row with loading state, search filter, empty state
- Search filters notes by content or author name (client-side)
- Panel collapses cleanly, search query resets on close
- Cache sync: new notes from inline form appear in history immediately
- Display format: author name and formatted datetime (YYYY年MM月DD日 HH:mm)
- Empty state shows '尚無備註', no-results shows '找不到符合的備忘錄'
- Alpine.js inline note forms in member list with per-row badge counters
- AJAX submission, validation error display, and full dark mode support
- 5 feature tests pass, no regressions in 7 Phase 1 tests
- Duration: 2 min 17 sec
- Tasks: 2 (feat + test)
- Files: 2 (1 created, 1 modified)
- Self-check: PASSED
- Test note count badge renders with correct count from withCount
- Test Alpine.js directives present in HTML (noteFormOpen, submitNote, x-model, :disabled)
- Test 備忘錄 column header renders
- Test zero-note members show 0 count
- Test correct note store route URL embedded for each member
All 5 tests pass. No regressions in 7 Phase 1 tests.
- Add Alpine.js x-data scope to each member row with noteFormOpen, noteContent, isSubmitting, errors, noteCount
- Add submitNote() async method calling axios.post to admin.members.notes.store route
- Add note count badge with reactive x-text binding to noteCount (initialized from withCount)
- Add toggle button to expand/collapse inline note form
- Add inline form with textarea, cancel button, and submit button
- Submit button disabled when isSubmitting or noteContent is empty
- Loading state toggles between 儲存 and 儲存中...
- Validation errors display in Traditional Chinese via x-show and x-text
- Cancel button clears content, closes form, and resets errors
- Add 備忘錄 column header between 狀態 and 操作
- Update empty state colspan from 7 to 8
- Add x-cloak CSS to prevent flash of unstyled content
- All elements include dark mode classes (dark:*)
- AdminMemberController index() now includes withCount('notes')
- Created MemberNoteTest with 7 feature tests
- Tests cover: creation, retrieval, validation, audit logging, authorization, N+1 prevention, ordering
- All new tests passing (7/7)
- No regressions in existing test suite
- MemberNoteController with index() and store() methods
- StoreNoteRequest with Traditional Chinese validation messages
- Routes registered at admin.members.notes.index/store
- JSON responses for AJAX consumption in Phase 2
- DB::transaction wrapper with AuditLogger::log
- Add SUMMARY.md documenting all tasks and deviations
- Update STATE.md: plan 1 of 2 complete in phase 01
- Update performance metrics: 3 min execution time
- Document morph map decision in STATE.md
- Changed from enforceMorphMap to morphMap in AppServiceProvider
- enforceMorphMap was causing errors with Spatie Laravel Permission package
- morphMap still provides namespace protection for our custom models
- Adds comment explaining why we don't enforce strict mapping
- Add notes() morphMany relationship to Member model (ordered by created_at desc)
- Register morph map in AppServiceProvider ('member' => Member::class)
- Create NoteFactory with forMember() and byAuthor() state methods
- Add notes migration with polymorphic columns (notable_type, notable_id)
- Add foreign key to users table for author tracking
- Add indexes on composite (notable_type, notable_id) and created_at
- Create Note model with morphTo and belongsTo relationships
The related articles query was missing ->with(['categories']),
causing the frontend ArticleCard to crash on undefined categories.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changed getFeaturedImageUrlAttribute to return relative paths
(e.g., /images/blog/photo.jpg) instead of full Laravel storage URLs.
Migrated image paths updated from migrated-images/ to images/ prefix.
Images are now served from Next.js public/ directory via Vercel CDN.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>