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.
This commit is contained in:
2026-01-24 03:11:50 +02:00
parent 60fd99492f
commit 666bec95bb
2 changed files with 259 additions and 8 deletions

199
SETUP_GUIDE.md Normal file
View File

@@ -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

View File

@@ -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<string, unknown> = {
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;
}