Skip to content

feat: Add EventHub - Enterprise Event Management Platform#224

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1775826233-eventhub-application
Open

feat: Add EventHub - Enterprise Event Management Platform#224
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1775826233-eventhub-application

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 10, 2026

Summary

Adds a complete EventHub web application — an enterprise event management platform with 5 user personas (App Admin, Event Organizer, Governance Team, Speaker, Audience). The application is built as a monorepo with separate backend/ and frontend/ directories.

Backend (backend/): Express.js + TypeScript + Prisma ORM + SQLite

  • JWT authentication with role-based middleware (ADMIN, ORGANIZER, GOVERNANCE, SPEAKER, AUDIENCE)
  • REST API routes: auth, events (CRUD + proposal/approval workflow), users, groups, campaigns, notifications, calendar (iCal export), admin (config, audit logs, access grants)
  • Twilio SMS integration for notifications (graceful fallback when credentials unavailable)
  • Database seed script with 7 demo users, 5 org groups, and 5 sample events

Frontend (frontend/): React 19 + TypeScript + Material UI v9 + Vite

  • 15 pages: Login, Register, Events (discovery + detail), My Events, Propose Event, Pending Approvals, Campaigns, Notifications, Preferences, Groups, Users, Access Matrix, App Config, Audit Logs
  • Role-filtered navigation sidebar — each persona sees only their permitted pages
  • Notification polling (30s interval), calendar export, event registration/unregistration

Review & Testing Checklist for Human

  • Security: hardcoded JWT secretbackend/src/middleware/auth.ts falls back to 'eventhub-secret-key-change-in-production' when JWT_SECRET env var is missing. Verify this is acceptable for your deployment model.
  • Hardcoded localhost URLs in frontendEvents.tsx, EventDetail.tsx, and MyEvents.tsx contain hardcoded http://localhost:4000/api/calendar/... URLs for iCal downloads instead of using the configurable VITE_API_URL. These will break in any non-local deployment.
  • CORS is fully openbackend/src/index.ts uses cors() with no origin restrictions. Review whether this is appropriate.
  • No tests — There are zero unit, integration, or e2e tests. All backend routes and frontend pages are untested.
  • Silent error swallowing — Most frontend API calls use empty catch { /* ignore */ } blocks, meaning users won't see error feedback for many failure scenarios.

Recommended test plan:

  1. Run cd backend && npm install && npx prisma migrate dev && npx prisma db seed && npm run dev
  2. Run cd frontend && npm install && npm run dev
  3. Log in as each demo user (admin@eventhub.com, organizer@eventhub.com, speaker1@eventhub.com, audience1@eventhub.com — password: password123) and verify role-appropriate pages are visible
  4. Test event proposal flow: log in as speaker → propose event → log in as organizer → approve/reject
  5. Test registration, iCal download, notification list, campaign creation
  6. Verify admin-only pages (Users, Access Matrix, Config, Logs) are inaccessible to non-admin roles

Notes

  • This adds a Node.js/React app to a repo that appears to be primarily .NET/Angular microservices — confirm this is the intended location.
  • No Helm charts, Dockerfiles, or ArgoCD manifests are included (the repo's platform conformance notes mention these are required for new microservices).
  • SQLite is used as the database — suitable for development/demo but not production.

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/9d986a285a8a44a8a04b6853ece64047


Open with Devin

- Backend: Express.js + TypeScript + Prisma ORM + SQLite
- Frontend: React + TypeScript + Material UI v9 + Vite
- 5 personas: Admin, Organizer, Governance, Speaker, Audience
- JWT authentication with role-based access control
- Event discovery, proposal/approval workflow
- Campaign scheduling (MS Teams, Viva Engage)
- Calendar integration (iCal export)
- Twilio SMS notifications
- Notification preferences and customization
- Admin panel: user management, access matrix, config, audit logs
- Seed data with 7 users, 5 groups, 5 sample events
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

View 7 additional findings in Devin Review.

Open in Devin Review

Comment on lines +21 to +24
if (error.response?.status === 401) {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/login';
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Axios 401 interceptor causes page reload on failed login, preventing error message display

The global axios response interceptor redirects to /login via window.location.href on any 401 response, including the one returned by POST /auth/login for invalid credentials. When a user enters wrong credentials on the login page, the flow is: (1) api.post('/auth/login', ...) at frontend/src/context/AuthContext.tsx:35 returns 401, (2) the interceptor fires and sets window.location.href = '/login', triggering a full page reload, (3) the promise rejects and the catch in frontend/src/pages/Login.tsx:19 tries to setError(...), but the page is already reloading. The net result is the user never sees the "Invalid email or password" error — the login page just silently reloads. The same issue affects the register flow for 401 errors.

Suggested change
if (error.response?.status === 401) {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/login';
if (error.response?.status === 401 && !error.config?.url?.includes('/auth/')) {
localStorage.removeItem('token');
localStorage.removeItem('user');
window.location.href = '/login';
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +34 to +36
const notification = await prisma.notification.update({
where: { id: req.params.id },
data: { read: true },
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Missing ownership check on PATCH /notifications/:id/read allows any user to mark others' notifications as read

The PATCH /:id/read endpoint at backend/src/routes/notifications.ts:32-42 updates a notification by its ID without verifying it belongs to the authenticated user (req.user.userId). Any authenticated user who knows or guesses a notification ID can mark another user's notification as read. The Prisma update uses only where: { id: req.params.id } with no userId filter.

Suggested change
const notification = await prisma.notification.update({
where: { id: req.params.id },
data: { read: true },
const notification = await prisma.notification.findUnique({ where: { id: req.params.id } });
if (!notification || notification.userId !== req.user!.userId) {
return res.status(404).json({ error: 'Notification not found' });
}
const updated = await prisma.notification.update({
where: { id: req.params.id },
data: { read: true },
});
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

<Button variant="contained" onClick={handleRegister}>Register</Button>
)}
<Button variant="outlined" startIcon={<Download />}
onClick={() => window.open(`http://localhost:4000/api/calendar/event/${event.id}/ical`, '_blank')}>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Hardcoded localhost:4000 URLs for iCal downloads break in non-local environments

Calendar download links are hardcoded to http://localhost:4000/api/calendar/... in three frontend components (frontend/src/pages/EventDetail.tsx:113, frontend/src/pages/Events.tsx:97, frontend/src/pages/MyEvents.tsx:27) instead of using the configured VITE_API_URL base URL from frontend/src/services/api.ts:3. In any deployed environment, these window.open() calls will try to reach localhost, failing silently.

Prompt for agents
Three frontend files hardcode http://localhost:4000/api/calendar/... for iCal download URLs instead of using the configured API base URL.

Affected locations:
1. frontend/src/pages/EventDetail.tsx line 113: window.open(http://localhost:4000/api/calendar/event/${event.id}/ical)
2. frontend/src/pages/Events.tsx line 97: window.open(http://localhost:4000/api/calendar/event/${event.id}/ical)
3. frontend/src/pages/MyEvents.tsx line 27: window.open(http://localhost:4000/api/calendar/my-events/ical)

The fix is to export the API_BASE constant from frontend/src/services/api.ts (or create a utility function) and use it to construct the calendar URLs dynamically. For example, export const API_BASE from api.ts and use window.open(`${API_BASE}/calendar/event/${event.id}/ical`).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants