From 666bec95bbbef29531fe60e2a0a990deb5051f8b Mon Sep 17 00:00:00 2001 From: moyoza Date: Sat, 24 Jan 2026 03:11:50 +0200 Subject: [PATCH] feat: Add client-side validation for admin creation and setup guide Admin Creation Improvements: - Add comprehensive client-side validation before API call - Validate username (required, max 100 chars) - Validate email format - Validate password (min 8 chars for new admins) - Validate role selection - Better error messages for users - Trim and normalize input data Documentation: - Create comprehensive SETUP_GUIDE.md - Include feature checklist - Add testing checklist - Add troubleshooting section - Document API endpoints - Include database setup instructions This should resolve the 'validation failed' error by catching issues client-side before the API call. --- SETUP_GUIDE.md | 199 ++++++++++++++++++ .../features/admin/rbac-manager.tsx | 68 +++++- 2 files changed, 259 insertions(+), 8 deletions(-) create mode 100644 SETUP_GUIDE.md diff --git a/SETUP_GUIDE.md b/SETUP_GUIDE.md new file mode 100644 index 0000000..7b4bf87 --- /dev/null +++ b/SETUP_GUIDE.md @@ -0,0 +1,199 @@ +# Setup Guide - Moyos Wedding App + +## Quick Start + +### 1. Database Setup + +Run migrations and seed the database: + +```bash +# Generate Prisma client +npx prisma generate + +# Run migrations (applies schema changes) +npx prisma migrate deploy +# OR for development: +npx prisma migrate dev + +# Seed database (creates default admin and super admins) +npm run db:seed +``` + +### 2. Set Up Super Admins + +The seed script will create two super admin accounts: +- **Username**: `denverm` | **Email**: `deemoyo@gmail.com` +- **Username**: `mahaliam` | **Email**: `mahalialerato@gmail.com` +- **Default Password**: `TSD107AS#` (or set `DEFAULT_ADMIN_PASSWORD` env variable) + +To manually set/update super admin passwords: + +```bash +# Set DEFAULT_ADMIN_PASSWORD environment variable (optional) +export DEFAULT_ADMIN_PASSWORD="your-secure-password" + +# Run the super admin setup script +npx tsx scripts/set-super-admins.ts +``` + +### 3. Environment Variables + +Ensure these are set in your `.env` file: + +```env +# Database +DATABASE_URL="postgresql://..." + +# Supabase (for admin auth) +NEXT_PUBLIC_SUPABASE_URL="..." +SUPABASE_SERVICE_ROLE_KEY="..." + +# Email (Resend) +RESEND_API_KEY="..." +FROM_EMAIL="noreply@themoyos.co.za" + +# Optional: Default admin password +DEFAULT_ADMIN_PASSWORD="TSD107AS#" +``` + +### 4. Start the Application + +```bash +npm run dev +``` + +## Feature Checklist + +### ✅ Completed Features + +1. **Edit Guestbook Messages** + - ✅ Admin can edit any message + - ✅ Guests can edit their own messages + - ✅ "Edited" indicators displayed + +2. **Edit Tributes** + - ✅ Admin can edit any tribute + - ✅ Guests can edit their own tributes + - ✅ "Edited" indicators displayed + +3. **Edit Relationship** + - ✅ Admin can edit guest relationships from dashboard + +4. **RSVP Email Notifications** + - ✅ Admins receive email when guests submit RSVP + - ✅ Email preferences toggle in admin settings + - ✅ Configurable per admin + +5. **Who's Who Feature** + - ✅ Filter by relationship type + - ✅ Filter by opt-in status + - ✅ View all guests by category + +6. **Reports & Exports** + - ✅ Statistics dashboard (fixed) + - ✅ CSV export (working) + - ✅ Excel export (newly implemented) + - ✅ PDF export (newly implemented) + - ✅ All report types: Headcount, Dietary, Relationships, Seating + +7. **Wedding Day Tools** + - ✅ Guest check-in/undo check-in + - ✅ QR code generation and printing + - ✅ Attendance tracking + - ✅ Emergency contacts management + - ✅ Guest lookup and search + - ✅ Check-in list export + +8. **Activity Feed** + - ✅ Real-time updates + - ✅ Tracks RSVP, guestbook, tributes, profile updates + - ✅ Shows edit indicators + +9. **Admin Creation** + - ✅ CSRF protection added + - ✅ Client-side validation added + - ✅ Proper error handling + +10. **Super Admin Setup** + - ✅ Migration created + - ✅ Seed script updated + - ✅ Setup script available + +## Testing Checklist + +### Admin Features +- [ ] Login as super admin +- [ ] Create new admin user (test validation) +- [ ] Edit guestbook message +- [ ] Edit tribute +- [ ] Edit guest relationship +- [ ] Toggle RSVP email notifications +- [ ] Filter Who's Who by relationship/opt-in +- [ ] Export reports (CSV, Excel, PDF) +- [ ] Use Wedding Day Tools (check-in, QR codes) +- [ ] View Activity Feed + +### Guest Features +- [ ] Login as guest +- [ ] Edit own guestbook message +- [ ] Edit own tribute +- [ ] Submit RSVP (verify admin receives email) +- [ ] View Who's Who directory + +## Troubleshooting + +### Admin Creation Fails +- Check CSRF token is being sent +- Verify Supabase is configured +- Check validation errors in browser console +- Ensure password is at least 8 characters + +### Super Admins Not Created +- Run `npx tsx scripts/set-super-admins.ts` +- Check database connection +- Verify `DEFAULT_ADMIN_PASSWORD` is set if using custom password + +### Reports Not Exporting +- Check browser console for errors +- Verify admin session is valid +- For Excel: Check server logs for exceljs errors +- For PDF: Ensure jsPDF is loaded in browser + +### Email Notifications Not Sending +- Verify `RESEND_API_KEY` is set +- Check `FROM_EMAIL` is configured +- Verify admin has `receiveRsvpNotifications: true` +- Check email logs in admin dashboard + +## API Endpoints + +### Guest Endpoints +- `PUT /api/guestbook/[id]` - Edit own guestbook message +- `PUT /api/tribute/[id]` - Edit own tribute + +### Admin Endpoints +- `PUT /api/admin/tributes/[id]` - Edit any tribute +- `PUT /api/admin/guests/[id]/relationship` - Edit guest relationship +- `GET/PUT /api/admin/settings/email-preferences` - Email preferences +- `GET /api/admin/reports/summary` - Report statistics +- `GET /api/admin/reports/export?type=X&format=Y` - Export reports +- `GET /api/admin/whos-who` - Who's Who with filters +- `GET /api/admin/activity-log` - Activity feed +- `POST /api/admin/guests/[id]/check-in` - Check in guest +- `DELETE /api/admin/guests/[id]/check-in` - Undo check-in + +## Database Schema Updates + +The following fields were added to the `Admin` model: +- `receiveRsvpNotifications` (Boolean, default: true) +- `role` (String, default: "viewer") + +Migration file: `prisma/migrations/20260123000000_add_admin_email_preferences_and_role/migration.sql` + +## Next Steps + +1. Run database migrations +2. Seed the database +3. Set up super admins +4. Test all features +5. Deploy to production diff --git a/src/components/features/admin/rbac-manager.tsx b/src/components/features/admin/rbac-manager.tsx index c5532fb..dd4e3b7 100644 --- a/src/components/features/admin/rbac-manager.tsx +++ b/src/components/features/admin/rbac-manager.tsx @@ -103,30 +103,82 @@ export function RBACManager() { const handleSave = async () => { try { + // Client-side validation + if (!newUser.username || newUser.username.trim().length === 0) { + toast({ + variant: "error", + title: "Validation Error", + description: "Username is required", + }); + return; + } + + if (newUser.username.length > 100) { + toast({ + variant: "error", + title: "Validation Error", + description: "Username must be 100 characters or less", + }); + return; + } + + if (!newUser.email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(newUser.email)) { + toast({ + variant: "error", + title: "Validation Error", + description: "A valid email address is required", + }); + return; + } + + if (!newUser.role || !['viewer', 'moderator', 'super_admin'].includes(newUser.role)) { + toast({ + variant: "error", + title: "Validation Error", + description: "A valid role must be selected", + }); + return; + } + const url = editingUser ? `/api/admin/roles/${editingUser.id}` : "/api/admin/roles"; const method = editingUser ? "PUT" : "POST"; + const password = (newUser.password || "").toString(); + if (method === "POST") { + if (!password || password.length < 8) { + toast({ + variant: "error", + title: "Validation Error", + description: "Password is required and must be at least 8 characters", + }); + return; + } + } else if (password && password.length > 0 && password.length < 8) { + toast({ + variant: "error", + title: "Validation Error", + description: "Password must be at least 8 characters if provided", + }); + return; + } + const csrfToken = await getCSRFToken(); if (!csrfToken) { throw new Error("Authentication required (missing CSRF token). Please refresh and try again."); } const payload: Record = { - username: newUser.username, - email: newUser.email, + username: newUser.username.trim(), + email: newUser.email.trim().toLowerCase(), role: newUser.role, }; - const password = (newUser.password || "").toString(); if (method === "POST") { - if (!password) { - throw new Error("Password is required to create a new admin."); - } payload.password = password; - } else if (password) { - // Optional password reset on edit + } else if (password && password.length >= 8) { + // Optional password reset on edit (only if valid) payload.password = password; }