AEW-AEC Conference Platform.
A full-stack event management system for the 11th UNESCO Africa Engineering Week and 9th African Engineering Conference 2025, covering multilingual content, registration workflows and payments.

- 1000+
- Registrations
- 90%
- Faster admin loads
- 3
- Languages
- 5
- Payment methods
Key features
Multilingual
English, French and Arabic, including RTL layout.
Payments
PesaPal gateway with multiple methods and real-time verification.
Registration
Multi-step flow with duplicate prevention and email validation.
Admin dashboard
Registration management, analytics and bulk operations.
Performance
Lazy loading and pagination for a 90% load-time improvement.
Email automation
Ticket generation, reminders and edit links.
Stack
Frontend
- Next.js 14
- TypeScript
- Tailwind CSS
- next-intl
- React Hook Form
Backend
- NestJS
- Firebase
- PesaPal API
- Nodemailer
- Vercel
Challenges & solutions
Duplicate email prevention
Block duplicate registrations while letting people finish incomplete ones.
Solution — Backend validation, real-time email verification and completion-status detection.
Payment callback handling
Reliable verification and registration completion across payment methods.
Solution — A callback system with fallbacks, proper error handling and automated ticket generation.
Performance at scale
The admin dashboard slowed down with thousands of registrations and tokens.
Solution — Pagination, lazy loading and batch operations, for a 90% improvement.
Technical highlights
Multilingual middleware
// middleware.ts
export function middleware(request: NextRequest) {
// Handle internationalization
const response = intlMiddleware(request);
// Add cache control headers
response.headers.set(
'Cache-Control',
'public, max-age=3600, s-maxage=86400'
);
return response;
}Duplicate email check
// registration.service.ts
async checkDuplicateEmail(email: string) {
const existing = await this.firestore
.collection('registrations')
.where('email', '==', email)
.get();
const completed = existing.docs.some(doc => {
const data = doc.data();
return data.paymentStatus === 'completed' ||
data.registrationDate ||
data.ticketSent;
});
if (completed) {
throw new BadRequestException(
'Email already registered'
);
}
}Need something similar?
Full-stack development, payment integration, internationalization and performance work. Let's talk about your project.
Get in touch