- Add runtime Docker socket permission detection in entrypoint - Detects socket GID and logs helpful deployment guidance - Provides three resolution options (root user, group-add, or chmod) - Non-intrusive: logs only, doesn't modify permissions - Fix notification page routing mismatch - Move notifications route from /notifications to /settings/notifications - Add notifications tab to Settings page with Bell icon - Align navigation structure with route definitions - Enhance Docker API error handling - Return 503 (not 500) when Docker daemon unavailable - Add DockerUnavailableError type for clear error distinction - Implement SSRF hardening (reject arbitrary host values) - Improve security and testability - Move ProxyHost routes to protected auth group - Refactor Docker handler tests to use mocks - Simplify useDocker hook query enablement logic Docker socket fix addresses deployment-level permission issue without code changes. The 503 error correctly signals service unavailability due to configuration, not application bugs. Closes #XX (if applicable)
13 KiB
Notification Page Trace Analysis
Date: 2025-12-22 Issue: User moved notification page in layout.tsx but can't find the rest of the code to render it correctly Status: Routing mismatch identified
Executive Summary
ROOT CAUSE: There is a routing mismatch between the navigation link and the actual React Router route definition:
| Component | Path | Status |
|---|---|---|
| Layout.tsx navigation | /settings/notifications |
✅ Points here |
| App.tsx route | /notifications |
❌ Route is defined here |
| Settings.tsx tabs | Missing notifications tab | ❌ Not integrated |
Result: Clicking "Notifications" in the sidebar navigates to /settings/notifications, but there is no route defined for that path. The route exists at /notifications (top-level), not as a nested settings route.
1. Full Workflow Mapping
Frontend Layer
A. Layout.tsx (Navigation Definition)
- File: frontend/src/components/Layout.tsx
- Navigation entry (line 81):
{ name: t('navigation.notifications'), path: '/settings/notifications', icon: '🔔' }, - Location: Nested under the "Settings" menu group
- Status: ✅ Entry exists, links to
/settings/notifications
B. App.tsx (Route Definitions)
- File: frontend/src/App.tsx
- Notifications route (line 70):
<Route path="notifications" element={<Notifications />} /> - Location: Top-level route under the authenticated layout (NOT under
/settings) - Actual path:
/notifications - Status: ⚠️ Route exists at WRONG path
C. Settings.tsx (Settings Tab Navigation)
- File: frontend/src/pages/Settings.tsx
- Tab items (lines 14-18):
const navItems = [ { path: '/settings/system', label: t('settings.system'), icon: Server }, { path: '/settings/smtp', label: t('settings.smtp'), icon: Mail }, { path: '/settings/account', label: t('settings.account'), icon: User }, ] - Status: ❌ Missing notifications tab - not integrated into Settings page
D. Notifications.tsx (Page Component)
- File: frontend/src/pages/Notifications.tsx
- Status: ✅ Fully implemented - manages notification providers, templates, tests
- Features:
- Provider CRUD (Discord, Slack, Gotify, Telegram, Generic/Custom Webhook)
- External template management
- Provider testing
- Provider preview
- Event type subscriptions (proxy hosts, remote servers, domains, certs, uptime)
E. useNotifications.ts (Hook)
- File: frontend/src/hooks/useNotifications.ts
- Purpose: Security notification settings (different from provider management)
- Hooks exported:
useSecurityNotificationSettings()- fetches security notification configuseUpdateSecurityNotificationSettings()- updates security notification config
- API endpoints used:
GET /api/v1/notifications/settings/securityPUT /api/v1/notifications/settings/security
- Note: This hook is for security-specific notifications (WAF, ACL, rate limiting), NOT the general notification providers page
F. NotificationCenter.tsx (Header Component)
- File: frontend/src/components/NotificationCenter.tsx
- Purpose: Dropdown bell icon in header showing system notifications
- API endpoints used:
GET /api/v1/notifications(fromapi/system.ts)POST /api/v1/notifications/:id/readPOST /api/v1/notifications/read-allGET /api/v1/system/updates
- Status: ✅ Working correctly, separate from the settings page
G. API Client - notifications.ts
- File: frontend/src/api/notifications.ts
- Exports:
- Provider CRUD:
getProviders,createProvider,updateProvider,deleteProvider,testProvider - Templates:
getTemplates,getExternalTemplates,createExternalTemplate,updateExternalTemplate,deleteExternalTemplate,previewExternalTemplate - Provider preview:
previewProvider - Security settings:
getSecurityNotificationSettings,updateSecurityNotificationSettings
- Provider CRUD:
- Status: ✅ Complete
Backend Layer
H. routes.go (Route Registration)
- File: backend/internal/api/routes/routes.go
- Notification endpoints registered:
| Endpoint | Handler | Line |
|---|---|---|
GET /notifications |
notificationHandler.List |
232 |
POST /notifications/:id/read |
notificationHandler.MarkAsRead |
233 |
POST /notifications/read-all |
notificationHandler.MarkAllAsRead |
234 |
GET /notifications/providers |
notificationProviderHandler.List |
269 |
POST /notifications/providers |
notificationProviderHandler.Create |
270 |
PUT /notifications/providers/:id |
notificationProviderHandler.Update |
271 |
DELETE /notifications/providers/:id |
notificationProviderHandler.Delete |
272 |
POST /notifications/providers/test |
notificationProviderHandler.Test |
273 |
POST /notifications/providers/preview |
notificationProviderHandler.Preview |
274 |
GET /notifications/templates |
notificationProviderHandler.Templates |
275 |
GET /notifications/external-templates |
notificationTemplateHandler.List |
278 |
POST /notifications/external-templates |
notificationTemplateHandler.Create |
279 |
PUT /notifications/external-templates/:id |
notificationTemplateHandler.Update |
280 |
DELETE /notifications/external-templates/:id |
notificationTemplateHandler.Delete |
281 |
POST /notifications/external-templates/preview |
notificationTemplateHandler.Preview |
282 |
GET /security/notifications/settings |
securityNotificationHandler.GetSettings |
180 |
PUT /security/notifications/settings |
securityNotificationHandler.UpdateSettings |
181 |
- Status: ✅ All backend routes exist
I. Handler Files
notification_handler.go- System notifications list/readnotification_provider_handler.go- Provider CRUDnotification_template_handler.go- External templatessecurity_notifications.go- Security-specific notification settings- Status: ✅ All handlers implemented
J. Service Files
notification_service.go- Core notification servicesecurity_notification_service.go- Security notification config- Status: ✅ All services implemented
K. Model Files
notification.go- System notification modelnotification_provider.go- Provider modelnotification_template.go- Template modelnotification_config.go- Config model- Status: ✅ All models defined
2. What's MISSING or BROKEN
Critical Issue: Route Mismatch
| Issue | Description | Impact |
|---|---|---|
| Route path mismatch | Layout links to /settings/notifications but route is at /notifications |
Page not found when clicking nav |
| Settings integration missing | Settings.tsx doesn't include notifications tab | Even if route fixed, no tab in settings UI |
| Route nesting incorrect | Route defined at top level, not under /settings/* |
Inconsistent with navigation structure |
Missing Integration
The Notifications page component exists and is fully functional, but it's not wired up correctly to the navigation:
User clicks "Notifications" in sidebar
↓
Navigation points to: /settings/notifications
↓
App.tsx has NO route for /settings/notifications
↓
React Router shows: blank content (falls through to no match)
3. Recent Git Changes
From get_changed_files, the relevant recent change to Layout.tsx:
- { name: t('navigation.notifications'), path: '/notifications', icon: '🔔' },
- // Import group moved under Tasks
+ { name: t('navigation.notifications'), path: '/settings/notifications', icon: '🔔' },
What happened: The navigation path was changed from /notifications (which matches the route) to /settings/notifications (which has no route), and the entry was moved under the Settings submenu.
The route in App.tsx was NOT updated to match this change.
4. Two Distinct Notification Features
There are actually TWO different notification features that may be causing confusion:
Feature 1: Notification Providers (Settings Page)
- Purpose: Configure external notification channels (Discord, Slack, etc.)
- Page:
Notifications.tsx - API:
/api/v1/notifications/providers/*,/api/v1/notifications/external-templates/* - This is what the settings navigation should show
Feature 2: System Notifications (Header Bell)
- Purpose: In-app notification center showing system events
- Component:
NotificationCenter.tsx - API:
/api/v1/notifications,/api/v1/notifications/:id/read - This already works correctly in the header
Feature 3: Security Notifications (Cerberus Modal)
- Purpose: Configure notifications for security events (WAF blocks, ACL denials, etc.)
- Component:
SecurityNotificationSettingsModal.tsx - Hook:
useNotifications.ts - API:
/api/v1/security/notifications/settings - Accessed from Cerberus/Security dashboard
5. Solutions
Option A: Fix Route to Match Navigation (Recommended)
Update App.tsx to add the route under settings:
{/* Settings Routes */}
<Route path="settings" element={<Settings />}>
<Route index element={<SystemSettings />} />
<Route path="system" element={<SystemSettings />} />
<Route path="notifications" element={<Notifications />} /> // ADD THIS
<Route path="smtp" element={<SMTPSettings />} />
<Route path="account" element={<Account />} />
<Route path="account-management" element={<UsersPage />} />
</Route>
Also update Settings.tsx to add the tab:
const navItems = [
{ path: '/settings/system', label: t('settings.system'), icon: Server },
{ path: '/settings/notifications', label: t('settings.notifications'), icon: Bell }, // ADD THIS
{ path: '/settings/smtp', label: t('settings.smtp'), icon: Mail },
{ path: '/settings/account', label: t('settings.account'), icon: User },
]
Option B: Revert Navigation to Match Route
Change Layout.tsx back to use the existing route:
// Move outside settings submenu, at top level
{ name: t('navigation.notifications'), path: '/notifications', icon: '🔔' },
This keeps the existing route but changes the navigation structure.
6. Test Files Review
Existing Tests (All Pass)
| Test File | Coverage |
|---|---|
useNotifications.test.tsx |
Security notification hooks ✅ |
NotificationCenter.test.tsx |
Header notification dropdown ✅ |
SecurityNotificationSettingsModal.test.tsx |
Security settings modal ✅ |
notification_handler_test.go |
System notifications API ✅ |
notification_provider_handler_test.go |
Provider API ✅ |
notification_template_handler_test.go |
Template API ✅ |
security_notifications_test.go |
Security notifications API ✅ |
No tests would prevent the routing fix - the tests cover API and component behavior, not navigation routing.
7. Summary
What EXISTS and WORKS:
- ✅
Notifications.tsxpage component (fully implemented) - ✅
notifications.tsAPI client (complete) - ✅ Backend handlers and routes (complete)
- ✅ Database models (complete)
- ✅
NotificationCenter.tsxheader component (works) - ✅ Navigation link in Layout.tsx (points to
/settings/notifications)
What's BROKEN:
- ❌ Route definition - Route is at
/notificationsbut navigation points to/settings/notifications - ❌ Settings.tsx tabs - Missing notifications tab
What NEEDS to be done:
- Add route
<Route path="notifications" element={<Notifications />} />under/settings/*in App.tsx - Add notifications tab to Settings.tsx navItems array
- Optionally remove the old
/notificationstop-level route to avoid confusion
8. Quick Fix Checklist
- In
App.tsx: Add<Route path="notifications" element={<Notifications />} />inside the<Route path="settings">block - In
Settings.tsx: Add{ path: '/settings/notifications', label: t('settings.notifications'), icon: Bell }to navItems - In
Settings.tsx: ImportBellfrom lucide-react - Optional: Remove
<Route path="notifications" element={<Notifications />} />from top level in App.tsx (line 70) - Test: Navigate to Settings → Notifications tab should appear and work