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.
287 lines
12 KiB
Markdown
287 lines
12 KiB
Markdown
# 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.
|