Ship all P0/P1/P2 gaps + 11 AI features

P0 Critical (7):
- STOP/UNSUBSCRIBE keyword → CANCEL (PECR compliance)
- Rate limiting on pledge creation (10/IP/5min)
- Terms of Service + Privacy Policy pages
- WhatsApp onboarding gate (persistent dashboard banner)
- Demo account seeding (demo@pnpl.app)
- Footer legal links
- Basic accessibility (aria labels on donor flow)

P1 Within 2 Weeks (8):
- Pledge editing by staff (PATCH amount, name, email, phone, rail)
- Donor self-cancel page (/p/cancel) + API
- Donor 'My Pledges' lookup page (/p/my-pledges)
- Bulk QR code download (print-ready HTML)
- Public event progress bar (/e/[slug]/progress)
- Email-only donor handling (honest status + WhatsApp fallback)
- Email verification (format + disposable domain blocking)
- Organisations page rewrite (multi-campaign, not multi-org)

P2 Within First Month (10):
- Event cloning with QR sources
- Account deletion (GDPR Article 17)
- Daily digest cron via WhatsApp
- AI-6 Smart reminder timing (due date anchoring, cultural sensitivity)
- H1 Duplicate donor detection (email, phone, Jaro-Winkler name)
- H5 Bank CSV format presets (10 UK banks)
- H16 Partial payment matching (underpay, overpay, instalment)
- H10 Activity logging (audit trail for staff actions)
- AI nudge endpoint + AI column mapping + AI event setup wizard
- AI anomaly detection wired into daily digest

AI Features (11): smart reconciliation, social proof, auto column mapper,
daily digest, impact storyteller, smart timing, nudge composer, event wizard,
NLU concierge, anomaly detection, bank presets

22 new files, 15 modified files, 0 TypeScript errors, clean build.
This commit is contained in:
2026-03-04 20:10:34 +08:00
parent 59485579ec
commit fcfae1c1a4
36 changed files with 3405 additions and 46 deletions

286
ADMIN_PANEL_AUDIT.md Normal file
View File

@@ -0,0 +1,286 @@
# CharityRight Admin Panel — Full Audit & Overhaul Plan
**Date:** 4 March 2026
**Auditor:** Claude (via pi)
**Stack:** Laravel 11 + Filament v3.3.26 + PHP 8.3 + DigitalOcean
---
## 1. Current State Inventory
### Navigation Groups & Resources
| Group | Resource | Model | Records | Notes |
|-------|----------|-------|---------|-------|
| **Management** | Customers | Customer | 21,558 | Basic CRUD, no search filters |
| | Users | User | 20,189 | Hidden from Admin role, minimal form |
| | Snowdon Registrations | SnowdonRegistration | 112 | Legacy event, still in nav |
| | Campaign Registrations | CampaignRegistration | 115 | T365/Ramadan, hardcoded title |
| **Donations** | General | Donation | 30,497 | Main donation view, good filters |
| | Scheduled | ScheduledGivingDonation | 2,841 | Separate resource from general |
| | URL Builder | (page) | — | Utility page for donation links |
| **Campaigns** | Appeals | Appeal | 8,914 | Core resource, complex |
| | Approvals | ApprovalQueue | 1,934 | Queue for appeal changes |
| | Scheduled Campaigns | ScheduledGivingCampaign | 3 | Very few records |
| | Words of Hope | WOHMessage | 817 | Form submissions |
| **Allocation** | Donation Items | DonationType | 30 | Hidden from Admin role |
| | Countries | DonationCountry | 12 | Hidden from Admin role |
| | Fund Dimensions | EngageFundDimension | — | N3O Engage sync |
| | Attribution Dimensions | EngageAttributionDimension | — | N3O Engage sync |
| **Misc** | Settings | (page) | — | Global settings, hidden from Admin |
| | Event Logs | EventLog | 2,276,079 | ⚠️ 2.2M rows, no cleanup |
### Roles & Permissions
| Role | Permissions | Can See |
|------|-------------|---------|
| Superadmin | All (via Gate::before) | Everything |
| Admin | Full CRUD on customers, donations, appeals, campaigns | Most things, hidden: Users, Settings, DonationType, DonationCountry |
| Appeal Manager | view/edit/delete appeal | Appeals only |
| Finance Manager | view/edit/delete donation + donation-item | Donations only |
| User | (none) | Nothing in admin |
---
## 2. Critical Issues Found
### 🔴 A. No Dashboard — Zero At-a-Glance Intelligence
The admin panel has **no widgets, no dashboard, no KPIs**. When staff log in they see a blank page with navigation. They have no idea:
- How many donations came in today/this week/this month
- Total revenue
- Active campaigns and their progress
- Pending approvals count
- Failed/errored donations
- Scheduled giving health
### 🔴 B. No Supporter/Care View
There is **zero support workflow**. A support agent can't:
- Search for a donor by email/name/phone and see everything about them in one place
- See a donor's full history (all donations, scheduled giving, appeals, gift aid status)
- Issue refunds or resend receipts easily
- Add notes/tags to a customer record
- Merge duplicate customer records (21K customers vs 20K users = many duplicates)
- See a timeline/activity log for a customer
### 🔴 C. Customer ↔ User Confusion
Two separate models (`User` = login account, `Customer` = donation record) with no unified view. Staff must:
1. Search Users to find the login account
2. Search Customers to find donation records
3. Mentally link them (via `customer.user_id`)
4. No way to see "this person's full picture"
### 🔴 D. Event Logs — 2.2 Million Rows, No Cleanup
`EventLog` table has 2.2M rows with no pruning, no auto-archive, no summary view. This:
- Slows down the admin panel
- Makes the "Event Logs" page unusable (loads millions of rows)
- No alerting on errors
- No way to filter by severity or recent errors only
### 🔴 E. Hardcoded Emails for Export Access
```php
->visible(function () {
$authedEmail = auth()->user()->email;
return $authedEmail == 'omair.saleh@charityright.org.uk' || $authedEmail == 'development@verge.digital';
})
```
Export functionality is locked to specific email addresses instead of using the permission system.
---
## 3. UX Issues
### 🟠 F. Top Navigation is Overcrowded
`->topNavigation()` with 5 groups × 3-5 items = 15+ items in a horizontal bar. With long names like "Scheduled Giving Campaigns", this overflows on most screens. Many items are rarely used (Snowdon Registrations, Fund Dimensions, Attribution Dimensions).
### 🟠 G. Deprecated Code Patterns (Partially Fixed)
- `->reactive()` instead of `->live()` — fixed for Appeal resources, but **DonationResource, CustomerResource, ScheduledGivingDonationResource** still use `->reactive()` and `callable $get`
- `HtmlString` used extensively for simple formatting (should use Filament's native badge/formatting)
### 🟠 H. No Global Search
No `->globalSearch()` configured. Staff can't type a donor email in the search bar and find them. They must navigate to Customers, then search.
### 🟠 I. Donation Edit Form is Read-Only Placeholders
The DonationResource edit form is **entirely Placeholder components** — nothing is actually editable. The form pretends to be an edit page but is really a view page. Should use ViewAction or a proper view page.
### 🟠 J. No Inline Links Between Resources
- Viewing a Donation doesn't link to the Customer
- Viewing a Customer doesn't link to their User account
- Viewing an Appeal doesn't link to the parent appeal in a clickable way
- `view_customer` action exists but has no URL attached
### 🟠 K. Inconsistent Form Patterns
- AppealResource defines the form schema TWICE (in `AppealResource::form()` AND `EditAppeal::form()`) — 100% duplicated
- Some resources use `ViewAction`, others use `EditAction` for the same purpose
- Some tables have bulk actions, others don't
- Inconsistent use of `->collapsible()->collapsed()` vs not
### 🟠 L. Legacy/Dead Resources in Navigation
- **Snowdon Registrations** (112 records, likely a past event)
- **Campaign Registrations** with hardcoded "T365 / Ramadan Challenge" title
- Both clutter the Management group for daily users
---
## 4. Functional Gaps
### 🟡 M. No Refund Workflow
No ability to process or record refunds from the admin panel. Support staff need to go to Stripe dashboard.
### 🟡 N. No Donation Notes/Comments
No way to add internal notes to a donation (e.g., "Donor called, wants to change allocation" or "Refunded via Stripe on 2024-01-15").
### 🟡 O. No Customer Merge Tool
With 21K customers and 20K users, there are certainly duplicates. No tool to merge them.
### 🟡 P. No Scheduled Giving Management
Can't pause, cancel, or modify a scheduled giving subscription from the admin. The edit page exists but fields are placeholder-only.
### 🟡 Q. No Bulk Operations for Appeals
Can't bulk-approve, bulk-reject, or bulk-publish appeals. Approval queue exists but it's a basic list.
### 🟡 R. No Communication/Email Log
No record of emails sent to donors (receipts, confirmations). Can't tell if a receipt was sent or if it bounced.
### 🟡 S. No Gift Aid Reporting
Gift Aid is tracked per donation but there's no aggregated report view for HMRC claims.
### 🟡 T. Missing Filters on Key Resources
- **Customers**: No filters at all (no date range, no donation count, no total donated)
- **Appeals**: No status filter, no date filter, no "has donations" filter
- **Users**: No role filter, no activity filter
---
## 5. Overhaul Plan — Phases
### Phase 1: Dashboard & Navigation (High Impact, Quick Win)
1. **Build a Dashboard** with widgets:
- Today's donations (count + total £)
- This week/month revenue chart
- Pending approvals badge
- Active campaigns progress bars
- Recent errors count (from EventLog)
- Scheduled giving health (active/paused/failed)
2. **Fix Navigation Structure:**
```
Dashboard (home)
├── Supporter Care (new)
│ ├── Donors (unified Customer+User view)
│ └── Donor Lookup (global search page)
├── Donations
│ ├── All Donations
│ ├── Scheduled Giving
│ └── URL Builder
├── Campaigns
│ ├── Appeals
│ ├── Approvals (with badge count)
│ ├── Scheduled Campaigns
│ └── Registrations (merge Snowdon + Campaign)
├── Configuration (collapsible, for admins)
│ ├── Donation Items
│ ├── Countries
│ ├── Fund Dimensions
│ ├── Attribution Dimensions
│ └── Settings
├── Logs & System
│ └── Event Logs (with cleanup)
```
3. **Switch from Top Nav to Sidebar** — Too many items for top nav. Sidebar with collapsible groups is standard for admin panels this size.
4. **Enable Global Search** across Customers, Donations, Appeals.
### Phase 2: Supporter Care Hub (Highest Business Value)
1. **Unified Donor Profile Page** — Single page showing:
- Customer details + linked User account
- All donations (one-off + scheduled) in a timeline
- All appeals they've donated to
- Gift aid status across all donations
- Address history
- Internal notes (new feature)
- Communication log (new feature)
- Quick actions: Send receipt, Add note, View in Stripe
2. **Donor Search Widget** — Search by email, name, phone, donation reference, provider reference. Returns unified results.
3. **Internal Notes System** — Polymorphic `notes` table: add notes to Customers, Donations, Appeals.
### Phase 3: Operational Improvements
1. **Fix DonationResource** — Make it a proper ViewRecord page, not a fake edit page with Placeholders
2. **Add missing filters** to all key resources
3. **Replace hardcoded email checks** with proper permissions (`can-export` permission)
4. **Add cross-resource links** (Donation → Customer, Customer → User, Appeal → Parent)
5. **Deduplicate AppealResource form** (remove from `AppealResource::form()`, keep only in `EditAppeal::form()`)
6. **Archive/hide legacy resources** (Snowdon, or move to a "Legacy" group)
### Phase 4: Reporting & Data Health
1. **Gift Aid Report Page** — Aggregate view for HMRC claims
2. **Donation Summary Report** — By type, country, period
3. **EventLog Cleanup** — Auto-prune entries older than 90 days, add severity indicators
4. **Scheduled Giving Health Dashboard** — Failed payments, retries, cancellations
---
## 6. Technical Recommendations
| Item | Current | Recommended |
|------|---------|-------------|
| Navigation | `->topNavigation()` | `->sidebarCollapsibleOnDesktop()` |
| Global Search | None | Enable on Customer, Donation, Appeal |
| Dashboard | Blank | Custom widgets page |
| Form pattern | `->reactive()` + `callable $get` | `->live()` + `\Filament\Forms\Get $get` |
| Export access | Hardcoded emails | Permission-based (`can-export`) |
| EventLog | 2.2M unmanaged rows | Pruning schedule + summary widget |
| Donation form | Placeholder-only edit page | ViewRecord page |
| Customer-User | Separate resources | Unified Donor resource |
---
## 7. Priority Matrix
| Priority | Item | Effort | Impact |
|----------|------|--------|--------|
| 🔴 P0 | Dashboard widgets | Medium | Very High |
| 🔴 P0 | Fix navigation (sidebar + groups) | Low | High |
| 🔴 P0 | Global search | Low | High |
| 🔴 P0 | Supporter Care donor profile | High | Very High |
| 🟠 P1 | Internal notes system | Medium | High |
| 🟠 P1 | Fix donation view page | Low | Medium |
| 🟠 P1 | Add missing filters | Low | Medium |
| 🟠 P1 | Cross-resource links | Low | Medium |
| 🟠 P1 | Replace hardcoded email checks | Low | Medium |
| 🟡 P2 | Gift Aid report | Medium | Medium |
| 🟡 P2 | EventLog cleanup | Medium | Medium |
| 🟡 P2 | Customer merge tool | High | Medium |
| 🟡 P2 | Communication log | Medium | Medium |
| 🟡 P2 | Archive legacy resources | Low | Low |
---
## Ready to execute. Say "go" with a phase number, or "go all" to start from Phase 1.