diff --git a/WebApp/Components/Features/Events/CareerMapping.razor b/WebApp/Components/Features/Events/CareerMapping.razor
new file mode 100644
index 0000000..108e5bf
--- /dev/null
+++ b/WebApp/Components/Features/Events/CareerMapping.razor
@@ -0,0 +1,146 @@
+@page "/events/career-mapping"
+@attribute [Authorize]
+@using Microsoft.EntityFrameworkCore
+@using WebApp.Components.Shared.Components
+@inject AppDbContext Context
+
+
+
+@if (_isLoading)
+{
+
+
+ Loading career mapping data...
+
+}
+else if (string.IsNullOrWhiteSpace(_mermaidDefinition))
+{
+
+ No Career Mappings Found
+
+ No events have related careers assigned. Edit events to add related careers.
+
+
+}
+else
+{
+
+ Event-Career Relationships
+
+ This diagram shows the connections between events and their related careers.
+ Events are shown on the left, careers on the right.
+
+
+
+
+
+}
+
+@code {
+ private string _mermaidDefinition = string.Empty;
+ private bool _isLoading = true;
+
+ protected override async Task OnInitializedAsync()
+ {
+ await LoadDataAsync();
+ }
+
+ private async Task LoadDataAsync()
+ {
+ _isLoading = true;
+
+ try
+ {
+ var events = await Context.Events
+ .Include(e => e.RelatedCareers)
+ .Where(e => e.RelatedCareers.Any())
+ .OrderBy(e => e.Name)
+ .ToListAsync();
+
+ if (events.Any())
+ {
+ _mermaidDefinition = GenerateMermaidDiagram(events);
+ }
+ }
+ finally
+ {
+ _isLoading = false;
+ }
+ }
+
+ private string GenerateMermaidDiagram(List events)
+ {
+ var builder = new System.Text.StringBuilder();
+ builder.AppendLine("graph LR");
+
+ // Dictionary to track node IDs and labels (to avoid duplicates)
+ var eventNodeIds = new Dictionary();
+ var careerNodeIds = new Dictionary();
+ var careerCounter = 1;
+ var eventCounter = 1;
+
+ // First pass: collect all unique nodes
+ foreach (var evt in events)
+ {
+ if (!eventNodeIds.ContainsKey(evt.Id))
+ {
+ var eventNodeId = $"E{eventCounter++}";
+ var eventLabel = EscapeMermaidLabel(evt.Name);
+ eventNodeIds[evt.Id] = (eventNodeId, eventLabel);
+ }
+
+ foreach (var career in evt.RelatedCareers)
+ {
+ if (!careerNodeIds.ContainsKey(career.Id))
+ {
+ var careerNodeId = $"C{careerCounter++}";
+ var careerLabel = EscapeMermaidLabel(career.Name);
+ careerNodeIds[career.Id] = (careerNodeId, careerLabel);
+ }
+ }
+ }
+
+ // Second pass: define all nodes
+ foreach (var (id, (nodeId, label)) in eventNodeIds.OrderBy(e => e.Value.Label))
+ {
+ builder.AppendLine($" {nodeId}[\"{label}\"]");
+ }
+
+ foreach (var (id, (nodeId, label)) in careerNodeIds.OrderBy(c => c.Value.Label))
+ {
+ builder.AppendLine($" {nodeId}[\"{label}\"]");
+ }
+
+ // Third pass: define all edges
+ foreach (var evt in events.OrderBy(e => e.Name))
+ {
+ var currentEventNodeId = eventNodeIds[evt.Id].Id;
+
+ foreach (var career in evt.RelatedCareers.OrderBy(c => c.Name))
+ {
+ var currentCareerNodeId = careerNodeIds[career.Id].Id;
+ builder.AppendLine($" {currentEventNodeId} --> {currentCareerNodeId}");
+ }
+ }
+
+ return builder.ToString();
+ }
+
+ private string EscapeMermaidLabel(string label)
+ {
+ if (string.IsNullOrEmpty(label))
+ return string.Empty;
+
+ // Escape quotes and other special characters for Mermaid labels
+ return label
+ .Replace("\"", """)
+ .Replace("\n", " ")
+ .Replace("\r", " ")
+ .Trim();
+ }
+}
+
diff --git a/WebApp/Components/Features/Events/Index.razor b/WebApp/Components/Features/Events/Index.razor
index 490f8b9..101ea54 100644
--- a/WebApp/Components/Features/Events/Index.razor
+++ b/WebApp/Components/Features/Events/Index.razor
@@ -11,6 +11,7 @@
Create New
Printable Descriptions
+ Career Mapping
diff --git a/WebApp/Components/_Imports.razor b/WebApp/Components/_Imports.razor
index 1e3980e..0ad4ad2 100644
--- a/WebApp/Components/_Imports.razor
+++ b/WebApp/Components/_Imports.razor
@@ -26,3 +26,4 @@
@using MudBlazor
@using Core.Entities
@using Data
+@using Blazorade.Mermaid.Components
diff --git a/WebApp/WebApp.csproj b/WebApp/WebApp.csproj
index 06e0b86..6a8184c 100644
--- a/WebApp/WebApp.csproj
+++ b/WebApp/WebApp.csproj
@@ -14,6 +14,7 @@
+