A modular, multi-tenant ASP.NET Core backend for integrated enterprise management.
One secure backend for organizational administration, Agile project delivery, employee learning, internal community engagement, analytics, real-time collaboration, and AI-assisted workflows.
- About Collabrium
- The Problem and the Product Idea
- What This Repository Contains
- Platform at a Glance
- Engineering Highlights
- System Architecture
- Core Domain and Business Rules
- Tenant and Organization Model
- User and Account Rules
- Team Membership Rules
- Project Model
- Sprint Lifecycle
- Work-Item Hierarchy
- Type-Specific Workflows
- Relations, Traceability, and Collaboration
- Course and Learning Progress Rules
- Roadmap Structure and Publishing Rules
- Article Rules
- Community Post Rules
- Event Scheduling and Attendance Rules
- Announcement Targeting and Scheduling Rules
- Notification State Rules
- Functional Modules
- Authentication, Authorization, and Security
- Real-Time Communication
- Event-Driven Notifications and Email
- Background Processing
- AI Assistance
- Analytics, Reports, and PDF Export
- Persistence and Data Integrity
- API Design and Error Handling
- Technology Stack
- External Integrations
- Solution Structure
- Main API Route Groups
- Roles and Access Model
- Engineering Skills Demonstrated
- Getting Started
- Configuration Reference
- Database Migrations and Seed Data
- Using Swagger
- Development Notes
- Testing and Current Repository Status
- Deployment Notes
- Project Links
- Academic Context
- Contributors
- License
Collabrium is an Integrated Enterprise Management Platform designed to bring several organizational workflows into one connected environment.
Instead of asking an organization to use one tool for projects, another for employee learning, another for internal communication, and separate systems for administration and reporting, Collabrium combines these concerns in a unified platform.
The system supports:
- multiple independent organizations through a multi-tenant design;
- users, roles, skills, teams, and organizational administration;
- Agile projects, sprints, backlogs, boards, and structured work items;
- employee learning through courses, roadmaps, articles, assignments, and progress tracking;
- internal community interaction through posts, announcements, and events;
- dashboards, analytical reports, charts, and downloadable PDF documents;
- real-time presence, comments, notifications, and unread-count updates;
- AI-assisted suggestions, recommendations, skill-gap analysis, roadmap generation, and report insights.
This repository contains the backend that coordinates those capabilities and enforces their business, security, tenant, and data-integrity rules.
Organizations commonly depend on disconnected systems for project tracking, employee development, communication, administration, and performance monitoring. That separation can create several problems:
- information is distributed across unrelated tools;
- teams repeat or manually synchronize the same data;
- managers lack one consistent view of organizational activity;
- employees must move between different systems to complete related work;
- project, learning, communication, and performance data are difficult to analyze together.
Collabrium addresses that fragmentation by treating the organization as one connected ecosystem:
Organization
├── Users, roles, skills, and teams
├── Projects, sprints, and work items
├── Learning content and employee progress
├── Posts, announcements, and events
├── Notifications and real-time collaboration
└── Reports, analytics, and AI-assisted insights
The important idea is not simply to place unrelated screens in one application. The backend connects the modules around the same tenant, users, teams, roles, projects, and business context. For example:
- a user can be assigned to a team and then become eligible for project work;
- project and sprint activity contributes to analytical reports;
- work-item assignment can create persistent and real-time notifications;
- skill data can be used to generate learning recommendations;
- report data can be passed to the AI subsystem to produce grounded narrative insights;
- tenant boundaries remain enforced across all of those operations.
This repository is the ASP.NET Core backend API for Collabrium. It includes:
- the REST API and SignalR endpoints consumed by the frontend;
- domain models and business rules;
- application use cases implemented as commands and queries;
- SQL Server persistence through Entity Framework Core;
- ASP.NET Core Identity, JWT access tokens, and refresh tokens;
- tenant resolution and organization-level access protection;
- authorization roles, policies, and project-access requirements;
- media, email, AI, reporting, and real-time service integrations;
- database migrations and startup seeders;
- background services for scheduled notifications and reminders;
- Swagger/OpenAPI documentation.
The frontend is maintained separately. Links to the deployed application and frontend showcase are available in Project Links.
| Area | What Collabrium Provides |
|---|---|
| Multi-tenant administration | Platform-level tenant registration, activation, profiles, branding, and logical organization isolation |
| Identity and access | Secure login, email confirmation, password recovery, first-login password change, JWT access tokens, refresh-token rotation, roles, and policies |
| Users and teams | Profiles, skills, roles, account status, team creation, membership, leadership, and candidate selection |
| Project delivery | Projects, assigned teams, history, backlog, boards, Epics, User Stories, Tasks, Bugs, Test Cases, and code/work traceability |
| Sprint management | Planning, scheduling, scope assignment, start, completion, cancellation, planned dates, and actual dates |
| Learning Hub | Courses, ratings, saved and enrolled courses, team/user assignments, progress, roadmaps, articles, and learning resources |
| Community Hub | Posts, tags, images, comments, likes, pinning, announcements, events, attendance, calendars, and audience targeting |
| Real-time services | Presence, work-item comments, in-app notifications, and unread-count updates through SignalR |
| Analytics | Tenant, sprint, velocity, cycle time, quality, productivity, blocked work, overdue work, and project-health reports |
| AI assistance | Work-item field suggestions, roadmap generation, learning-resource suggestions, skill-gap analysis, and report insights |
| Documents and media | Cloudinary-backed uploads, QuestPDF documents, and ScottPlot report charts |
- Four-project Clean Architecture structure with
API,Application,Domain, andInfrastructureprojects. - CQRS with MediatR to separate write use cases from read use cases.
- Domain-centered command path that applies business rules before persistence.
- Dedicated query read models that retrieve purpose-specific DTOs instead of complete entity graphs.
- Separate domain models and persistence entities, connected through explicit mappers.
- Repository and Unit of Work patterns for transactional command operations.
- Logical multi-tenancy with authenticated-user, tenant-state, claim, and membership validation.
- ASP.NET Core Identity and JWT Bearer authentication with persistent, rotating refresh tokens.
- Layered authorization using roles, policies, project membership, tenant context, and account state.
- FluentValidation pipeline behavior for application requests, plus transport-level API validators.
- SignalR hubs for presence, comments, and targeted notification delivery.
- Application events and handlers that decouple core operations from notifications and email.
- Background services for due announcements and event reminders.
- Ollama-based AI integration with structured-output parsing, retries, normalization, and fallback behavior.
- QuestPDF and ScottPlot reporting pipeline for branded PDF exports with generated charts.
- Cloudinary abstraction for image, file, video, and attachment storage.
- Consistent Problem Details responses with validation details and trace identifiers.
- Swagger/OpenAPI documentation with JWT authentication support.
- UTC normalization for persisted date and time values.
flowchart LR
User[Platform User]
Frontend[React Frontend]
API[Collabrium ASP.NET Core API]
DB[(SQL Server)]
Cloudinary[Cloudinary]
SMTP[SMTP Server]
Ollama[Ollama / Gemma 3]
User --> Frontend
Frontend -->|HTTPS + JSON| API
Frontend <-->|SignalR| API
API --> DB
API --> Cloudinary
API --> SMTP
API --> Ollama
The frontend communicates with the backend through RESTful JSON APIs and authenticated SignalR connections. The backend owns business rules, access control, persistence, notifications, integrations, report generation, and AI orchestration.
flowchart TB
subgraph Presentation[API / Presentation]
Controllers[REST Controllers]
Contracts[Request and Response Contracts]
Validators[Transport Validators]
Middleware[Middleware]
Hubs[SignalR Hubs]
Authorization[Authorization Policies]
Startup[Composition Root and Startup]
end
subgraph ApplicationLayer[Application]
Commands[Commands and Handlers]
Queries[Queries and Handlers]
DTOs[DTOs]
Behaviors[MediatR Behaviors]
Events[Application Events and Event Handlers]
Interfaces[Repository, Read Model, and Service Interfaces]
AppServices[Application Services]
end
subgraph DomainLayer[Domain]
Models[Domain Models]
Rules[Business Rules and Guards]
ValueObjects[Value Objects]
Enums[Domain Enums]
end
subgraph InfrastructureLayer[Infrastructure]
EF[EF Core / SQL Server]
Identity[Identity and JWT]
Repositories[Command Repositories]
ReadModels[Query Read Models]
Mappers[Domain / Persistence Mappers]
SignalR[SignalR Services]
Reports[Reports and Charts]
AI[Ollama Integration]
Email[SMTP and Templates]
Storage[Cloudinary Storage]
Workers[Background Services]
end
Controllers --> Commands
Controllers --> Queries
Hubs --> AppServices
Commands --> Models
Commands --> Interfaces
Queries --> Interfaces
Events --> Interfaces
Behaviors --> Commands
Behaviors --> Queries
InfrastructureLayer -. implements .-> Interfaces
Repositories --> Mappers
Mappers --> EF
ReadModels --> EF
Identity --> EF
The Domain project contains the business meaning of the system:
- domain models such as projects, sprints, work items, tenants, teams, learning resources, and community content;
- guards and invariants;
- valid state transitions;
- value objects and enums;
- rules that should remain independent from HTTP, SQL Server, or third-party services.
The Application project expresses the use cases:
- commands and command handlers for state-changing operations;
- queries and query handlers for data retrieval;
- DTOs returned to the API;
- interfaces implemented by Infrastructure;
- validation behavior;
- application events and their handlers;
- cross-feature application services.
The Infrastructure project provides technical implementations:
- Entity Framework Core and SQL Server persistence;
- ASP.NET Core Identity and JWT services;
- repositories, read models, mappings, migrations, and seeders;
- SignalR hubs and real-time delivery services;
- SMTP email and HTML templates;
- Cloudinary storage;
- Ollama-based AI services;
- QuestPDF and ScottPlot reporting;
- background workers and tenant-context implementations.
The API project is the presentation and composition layer:
- controllers and routes;
- HTTP request and response contracts;
- AutoMapper profiles;
- API validators;
- global exception and tenant middleware;
- policy registration;
- Swagger configuration;
- dependency registration and application startup.
The project references preserve an inward dependency direction:
API ───────────────► Application ───────────────► Domain
│ ▲
└──────────────► Infrastructure
│
└────────────────────► Application
Domainhas no project dependency on the other layers.Applicationdepends onDomain.Infrastructuredepends onApplicationand implements its abstractions.APIcomposesApplicationandInfrastructureand exposes them over HTTP and SignalR.
This keeps business rules independent from storage, transport, and external service details.
Collabrium separates commands and queries because read and write operations have different responsibilities.
sequenceDiagram
participant Client
participant Controller
participant MediatR
participant Validator
participant Handler
participant Repository
participant Domain
participant UoW as Unit of Work
participant Database
participant Events as Event Handlers
Client->>Controller: State-changing HTTP request
Controller->>MediatR: Send command
MediatR->>Validator: Validate command
Validator-->>MediatR: Valid
MediatR->>Handler: Execute use case
Handler->>Repository: Load domain state
Repository->>Database: Read persistence entities
Repository-->>Handler: Mapped domain model
Handler->>Domain: Apply rule or transition
Handler->>Repository: Persist changes
Handler->>UoW: Commit transaction
UoW->>Database: Save atomically
Handler->>Events: Publish application event
Handler-->>Controller: Result DTO
Controller-->>Client: HTTP response
The command side is responsible for correctness. It loads domain state, applies guards and state-transition rules, persists changes, and coordinates transactions and resulting application events.
sequenceDiagram
participant Client
participant Controller
participant MediatR
participant Handler
participant ReadModel
participant Database
Client->>Controller: Read request with filters
Controller->>MediatR: Send query
MediatR->>Handler: Execute query
Handler->>ReadModel: Request purpose-specific data
ReadModel->>Database: Filter, sort, paginate, and project
Database-->>ReadModel: Selected fields
ReadModel-->>Handler: DTO or paged result
Handler-->>Controller: Query result
Controller-->>Client: JSON response
The query side favors efficient retrieval:
- dedicated read-model interfaces;
- direct projections to DTOs;
- server-side filtering and sorting;
- pagination or cursor-based retrieval where implemented;
- no requirement to hydrate complete domain models for read-only screens.
Each regular user operates inside one tenant. Platform-level Super Admin operations use a global platform tenant context.
flowchart TD
Request[Authenticated request]
Skip{IgnoreTenantContext endpoint?}
UserCheck{Authenticated user exists and is active?}
Super{SuperAdmin?}
Global[Resolve global platform tenant]
Claim[Read tenantId claim]
TenantCheck{Tenant exists and is active?}
Membership{User belongs to tenant?}
Context[Set scoped ITenantContext]
Endpoint[Continue to endpoint]
Reject[Reject request]
Request --> Skip
Skip -- Yes --> Endpoint
Skip -- No --> UserCheck
UserCheck -- No --> Reject
UserCheck -- Yes --> Super
Super -- Yes --> Global --> Context
Super -- No --> Claim --> TenantCheck
TenantCheck -- No --> Reject
TenantCheck -- Yes --> Membership
Membership -- No --> Reject
Membership -- Yes --> Context --> Endpoint
The repository implements logical, application-enforced tenant isolation. Tenant protection is not described as a separate physical database per organization. Instead, tenant identifiers, request context, authorization checks, and tenant-aware data access keep records associated with the correct organization and prevent unauthorized cross-tenant access.
Collabrium does not place all business decisions inside controllers. Rules are enforced at the layer that owns the relevant responsibility:
- Domain models protect entity invariants, valid state transitions, and behavior that must remain true regardless of transport or storage.
- Application handlers and services coordinate rules that require several aggregates, the current tenant, the current user, authorization context, or repository lookups.
- Database configurations reinforce referential integrity, uniqueness, required relationships, and tenant-aware persistence constraints.
This section summarizes the principal rules implemented across those layers.
A tenant represents one organization using Collabrium. Tenant-owned data includes users, teams, projects, work items, learning content, community content, reports, and notifications.
Representative rules and behaviors include:
- a tenant requires a non-empty name and domain and is active when first created;
- a tenant administrator can be assigned to the organization;
- tenant profiles support organization details, contact information, social links, and a stored profile image;
- tenants can be activated or deactivated through explicit domain behavior;
- tenant status is checked before normal tenant-scoped requests continue;
- authenticated users must belong to the tenant resolved from their security context;
- Super Admin operations use the platform-level global tenant context rather than a regular organization context;
- users, teams, projects, content, notifications, and related persistence records retain the tenant identifier required for logical data isolation;
- affected users can receive notifications when important tenant, account, role, or team operations occur.
The domain user represents the platform profile associated with the ASP.NET Core Identity account.
Implemented rules include:
- a user stores tenant association, identity details, job title, department, date of birth, account state, contact details, profile image, and last-login information;
- a newly created domain user starts with
MustChangePassword = true; - the account can be flagged again when another mandatory password change is required;
- successful login activity records
LastLoginAtin UTC; - account activation is changed through explicit domain behavior rather than direct public property assignment;
- creation rejects a date of birth in the future;
- identity-profile updates require the user to be at least 18 years old;
- contact details and social links are constructed through value objects, and profile images are represented as stored-image values;
- roles, password hashes, confirmation tokens, lockout-related identity state, JWT issuance, and refresh tokens are handled by ASP.NET Core Identity and the authentication infrastructure rather than being embedded in the domain profile model.
A team is tenant-owned and has one lead, a department, an optional capacity, an active state, and a set of member IDs.
Important rules include:
- the team lead is automatically included in the member set when the team is created or rehydrated;
- changing the team lead also ensures that the new lead is a team member;
- the current team lead cannot be removed from the team;
- members cannot be added to an inactive team;
- the same user cannot be added more than once;
- when capacity is defined, it must be at least
1; - a new member cannot be added after the configured capacity has been reached;
- removing a user who is not a member is rejected;
- team activation and deactivation are explicit operations and can trigger notifications for affected members.
Projects organize delivery work inside a tenant.
Project status values are:
NotStarted · InProgress · Completed · OnHold · Cancelled
Selected domain and application rules include:
- a project requires a name, creator, and tenant;
- a project key must contain only uppercase letters and must be between 2 and 10 characters;
- planned end date cannot be earlier than planned start date when both are supplied;
- projects maintain independent counters used to generate sequential work-item codes and sprint names;
- a team can be assigned or unassigned through authorized operations;
- changing a project to
Completedis rejected while any supplied project work-item snapshot is notDone; - when a project becomes
Completedand has no end date, the domain records the current UTC time as its end date; - project history records important project and work-item changes for traceability;
- project access is evaluated separately from general authentication and tenant membership.
Sprint statuses are:
Planned · Active · Completed · Cancelled
A sprint stores both planning and execution information:
PlannedStartDateandPlannedEndDatedescribe the schedule;StartedAtandCompletedAtrecord actual execution timestamps;IsScheduledis true only when both planned dates exist.
Important lifecycle rules include:
- a newly created sprint starts in
Plannedstatus; - only a
Plannedsprint can be started; - starting a sprint records
StartedAt, clears any previous completion timestamp, and changes the status toActive; - only an
Activesprint can be completed; - completion records
CompletedAtand changes the status toCompleted; - a completed sprint cannot be updated or cancelled;
- when the planned start date is changed, the new value must be in the future;
- planned end date must be greater than or equal to planned start date;
- the planned start date cannot be changed after an active sprint has started;
- work items cannot be assigned to a cancelled or completed sprint through the update use case;
- work-item status changes require the work item to belong to an active sprint.
The system supports five concrete work-item types:
Epic
└── User Story
├── Task
├── Bug
└── Test Case
The code enum names the Task work item TaskItem, while the user-facing concept is a Task.
Common work-item information includes:
- generated code and title;
- description and acceptance criteria;
- priority and non-negative effort points;
- assignee and creator;
- project, sprint, and optional parent;
- blocked state;
- start and completion timestamps;
- comments, attachments, code links, and relations.
Hierarchy rules include:
- a work item cannot be its own parent or relation target;
- a work item can have only one parent through the initial parent-setting operation;
- valid parent relationships are
User Story → Epic,Task → User Story,Bug → User Story, andTest Case → User Storywhen expressed from child to parent; - valid child relationships are the inverse direction:
Epic → User StoryandUser Story → Task/Bug/Test Case; - the implemented same-sprint invariant applies to a User Story and its Task, Bug, or Test Case children;
- moving a User Story to another sprint also moves its recognized Task, Bug, and Test Case children in the update workflow;
- a child Task, Bug, or Test Case with a User Story parent cannot be moved to a different sprint from that parent;
- the Epic–User Story relationship is structurally validated, but it is not included in the current same-sprint rule.
User Stories use the supported planning values:
1 · 2 · 3 · 5 · 8 · 13 story points
The shared status enum contains:
ToDo · ReadyForDev · InProgress · InReview · InTesting · ReadyForRelease · Done
The system does not apply one universal linear workflow to every work-item type. Metadata exposes a canonical state set for each type, while each concrete domain model validates the transitions it permits from the current state.
| Work-item type | Canonical states exposed by metadata | Important completion or quality behavior |
|---|---|---|
| Epic | ToDo, InProgress, Done |
An Epic cannot become Done until all linked User Stories are Done |
| User Story | all shared status values | InTesting requires linked Tasks to be done; release and completion additionally require no open Bugs and all linked Test Cases to be completed with a Passed result |
| Task | ToDo, ReadyForDev, InProgress, InReview, Done |
Supports controlled forward movement and selected backward transitions for rework |
| Bug | ToDo, ReadyForDev, InProgress, InTesting, Done |
Uses defect-oriented development, retesting, and reopening behavior |
| Test Case | ToDo, InTesting, Done |
Can return from Done to InTesting for another run; an outcome can be recorded only while it is InTesting and must be Passed, Failed, or Blocked, not NotRun |
Shared guards also prevent invalid operations. Examples include:
- status cannot be changed while the project is
NotStarted,Completed, orCancelled; - a blocked work item cannot move into
InProgress; - start time is recorded when execution begins, including when a Test Case enters
InTestingfor the first time; - returning an item to
ToDoclears its start time; - moving to
Donerecords the end time, while reopening an eligible item clears it; - completed work items reject details editing, assignment changes, sprint movement, blocking, and adding or removing code links and attachments;
- a User Story cannot pass its testing, release, or completion gates while the required child-work conditions are not satisfied.
The metadata endpoints expose workflows and allowed values so the frontend does not need to independently duplicate the canonical domain options.
Supported work-item relation types are:
Parent · Child · RelatesTo · FoundByTestCase
The backend validates relation rules across the domain and application layers:
- source and target must exist in the same requested project context;
- a work item cannot relate to itself;
- the same target and relation type cannot be added twice;
- immediate contradictory Parent/Child relationships are rejected;
- Parent and Child relations must match the supported type hierarchy;
FoundByTestCaseis valid only in the implemented directionBug → Test Case;RelatesTois non-hierarchical and does not apply the parent/child type restriction;- same-sprint validation is required for hierarchical relations between a User Story and a Task, Bug, or Test Case, but not for non-hierarchical relation types.
Additional collaboration and traceability rules include:
- comments are attached to a specific work item and can be broadcast through the comment hub;
- code-link URLs cannot be duplicated on the same work item;
- completed work items reject adding or removing code links and attachments;
- assignments, priority changes, blocked-state changes, sprint movement, relations, comments, and details changes are coordinated through authorized use cases;
- project and work-item history records significant changes;
- important assignment and collaboration actions can publish application events that create notifications and real-time updates.
Courses and user-course records separate reusable learning content from each employee's personal progress and assignment state.
Course-content rules include:
- a course requires a tenant, title, description, URL, provider, level, and language;
- course tags are trimmed, empty values are ignored, and duplicate IDs are not stored through the domain methods;
- learning points are represented as value objects, empty entries are ignored, and duplicate text is not stored;
- the thumbnail is managed as an optional stored-image value;
- course ratings must be between
1and5; - the database enforces one rating per tenant, user, and course combination.
User learning progress follows:
NotStarted → InProgress → Completed
Important progress and assignment rules include:
IsSavedandIsAssignedare independent from the progress status;- assignment records the assigning user and
AssignedAttimestamp; - unassignment clears assignment metadata without automatically discarding existing progress or saved state;
- starting a course changes the status to
InProgressand recordsStartedAtonly the first time; - a completed course cannot be started again until progress is reset;
- completing a course records
CompletedAtand createsStartedAtfirst when necessary; - resetting progress returns the record to
NotStartedand clears start and completion timestamps; - after unassignment, the user-course record is deleted only when it is not saved, is still
NotStarted, and has no start or completion timestamp; otherwise the record is retained and only the assignment state is removed.
Course-assignment use cases also apply organizational rules:
- a manager cannot directly assign a course to themselves;
- direct and team assignment exclude target roles
ProductOwner,TeamLead,TenantAdmin,BusinessAnalyst, andCEO; - team assignment requires a team with members, skips the assigning user, and skips members whose roles are blocked by the assignment rule.
A roadmap is tenant-owned learning content organized by path, level, tags, ordered nodes, subtopics, and resources.
Implemented rules include:
- a roadmap requires a title and tenant and may be visible or hidden;
- publishing records
PublishedAt, which cannot be earlier than the roadmap creation time; - a duplicate tag cannot be added to the same roadmap;
- removing a tag that is not attached is rejected;
- roadmap nodes can be Topic nodes or Reference nodes;
- node, subtopic, and resource order values must be at least
1; - a Reference node cannot reference the same roadmap that contains it;
- subtopics require a parent Topic node identifier;
- resources require a subtopic, title, URL, resource type, and valid order;
- roadmap structure changes are performed through explicit create, update, delete, and reorder use cases rather than exposing persistence collections directly.
Learning articles provide tenant-scoped long-form knowledge content.
Important rules include:
- an article requires a tenant, title, content, and creator;
- description and cover image are optional;
- articles support explicit publish and unpublish behavior;
- article tags are stored as a set, so duplicate tag IDs are not retained;
- cover images are managed as stored-image values and can be replaced or removed;
- article comments require an article ID, creator ID, and non-empty content;
- likes and comments are stored as separate records so interaction data remains traceable to the article and user.
Post types are:
General · Question · Discussion · Resource · Tip
Post behavior includes:
- a post requires a tenant, creator, title, content, and type;
- a post can contain at most five tags;
- a post can contain at most five images, and duplicate images are detected by storage public ID;
- a post can contain at most five links;
- links are allowed only when the post type is
Resource; - changing a post from
Resourceto another type clears its existing links; - duplicate links are not stored;
- pinning records
IsPinned, the user who pinned the post, and the UTC pin time; - unpinning clears the pin owner and timestamp;
- tags, links, and images are changed through controlled collection methods instead of direct mutable collection exposure.
An event is tenant-owned and contains its schedule, delivery mode, capacity, attendance records, cancellation state, reminder state, and optional banner.
Scheduling and place rules include:
- event end time must be after event start time;
- an online event requires a meeting URL;
- an in-person event requires a location;
- maximum attendance, when supplied, must be greater than
0; - a cancelled event cannot be updated;
- cancellation is idempotent;
- event state is derived as
Upcoming,Ongoing,Finished, orCancelledfrom the schedule and cancellation flag; - available seats are calculated from maximum capacity and the current attendance count and never return a negative number;
- reminder delivery records
ReminderSentandReminderSentAtand ignores repeated marking after delivery.
Attendance use cases enforce that:
- a user cannot attend a cancelled event;
- a user cannot attend an event that has already finished;
- a user cannot register for the same event twice;
- registration is rejected when the event has reached its maximum capacity;
- the database reinforces duplicate prevention with a unique index on
EventIdandUserId; - cancelling attendance requires an existing attendance record.
Announcements combine content, priority, publication timing, audience targeting, and delivery state.
Implemented rules include:
- an announcement requires a tenant, title, content, creator, priority, and publication time;
ExpiresAt, when supplied, must be later thanPublishAt;- an announcement is visible only after publication time and before expiration, when an expiration exists;
- an announcement must have at least one audience;
- supported audience types are
Everyone,Team, andRole; - an
Everyoneaudience cannot contain a team, role, or user target; - a
Teamaudience requires only a team ID; - a
Roleaudience requires only a role name; - audience records are attached to the announcement being updated before the new audience set is accepted;
- successful notification processing records
NotificationSentandNotificationSentAtand does not mark the same announcement twice; - when an announcement is updated with a future publication time, its notification state is reset so the background worker can process the revised schedule.
A notification is a persistent, tenant-owned message addressed to one user.
The notification model enforces:
- required tenant ID, recipient user ID, type, title, and message;
- optional triggering user, related entity type, related entity ID, and action URL;
- a new notification starts unread with no read timestamp;
- marking a notification as read records
ReadAtin UTC and is idempotent when already read; - marking it unread clears
ReadAtand is idempotent when already unread; - persistent notification storage is the durable record, while SignalR is used for immediate delivery and unread-count updates.
Main route group: /api/auth
The authentication module supports the complete account-access lifecycle:
- platform Super Admin registration;
- tenant employee registration by authorized users;
- secure email-and-password login;
- JWT access-token generation;
- persistent refresh-token generation and rotation;
- refresh-token revocation;
- email confirmation and confirmation-email resend;
- forgotten-password request and reset;
- authenticated password change;
- mandatory first-login password-change workflow.
Login is not based only on correct credentials. Account confirmation, activation state, tenant state, and password-change requirements are also part of the access flow.
Main route group: /api/tenants
Tenant management provides platform and organization administration:
- register a tenant together with its tenant administrator;
- list, search, filter, and inspect tenants;
- retrieve tenant details and analytical information;
- view and update the current tenant profile;
- upload or update tenant branding/logo;
- view tenant users;
- activate or deactivate tenants;
- maintain the global platform context required for Super Admin operations.
Main route group: /api/users
User operations include:
- retrieve the authenticated user's profile;
- view authorized profiles inside the tenant;
- edit personal information;
- upload a profile image;
- manage and inspect user skills;
- update roles through authorized operations;
- toggle user activation through authorized tenant-management operations;
- retrieve assignable project or team users;
- discover managers and other user selections needed by the platform;
- view tenant-scoped online users through the presence service.
Main route group: /api/teams
Team management connects employees to organizational and project work:
- create and update teams;
- browse, filter, sort, and paginate teams;
- view team details;
- retrieve candidate members;
- add and remove members;
- assign team leadership according to the request model and policies;
- activate or deactivate teams;
- retrieve teams associated with a user;
- use team membership in project assignment, notifications, and access decisions.
Main route group: /api/projects
Project capabilities include:
- create, view, edit, and delete projects according to policy;
- validate project identity information such as key and dates;
- assign or unassign an organizational team;
- retrieve projects available to the current user;
- browse projects for higher-level management;
- view project details;
- retrieve backlog, board, Epic, and User Story views;
- inspect project history;
- enforce tenant, role, and project-access requirements;
- expose project information to reports and AI insights.
Main route group: /api/projects/{projectId}/work-items
Work-item operations are organized around planning, execution, quality, collaboration, and traceability:
- create and update Epics and User Stories;
- create and update Tasks, Bugs, and Test Cases;
- browse and filter work items;
- retrieve details and board/backlog views;
- change status under type-specific domain rules;
- assign or unassign eligible project members;
- change priority and blocked state;
- add, update, retrieve, and delete comments;
- upload and remove attachments;
- manage code links;
- retrieve relation candidates;
- add and delete work-item relationships;
- connect test findings to Bugs through supported relation types;
- preserve project and work-item traceability.
Main route group: /api/projects/project/{projectId}/sprints
Sprint operations include:
- create a planned sprint;
- update the sprint schedule, name, and goal;
- browse and filter sprints;
- retrieve sprint details and assigned work;
- add eligible work items to the sprint scope;
- start a planned sprint;
- complete an active sprint;
- cancel a non-completed sprint;
- delete when the corresponding use-case conditions permit;
- retrieve sprint User Stories and work-item structures;
- use sprint data in progress, velocity, and cycle-time reports.
Main route groups:
/api/courses
/api/courses/{courseId}/ratings
/api/user-courses
/api/user-course-assignments
/api/roadmaps
/api/articles
The Learning Hub combines structured content, assignments, progress, and knowledge sharing.
- create, update, retrieve, and delete courses;
- maintain course metadata, tags, language, level, duration, and thumbnail;
- publish or expose courses according to implemented status and access rules;
- assign a course to an individual user or an entire team;
- unassign courses;
- save and unsave courses;
- start and complete learning activity;
- retrieve assigned, saved, enrolled, and personal-course views;
- submit and retrieve ratings;
- calculate summaries and course statistics.
- create and manage learning roadmaps;
- publish or hide roadmaps;
- organize roadmaps by path, level, and tags;
- create topic and reference nodes;
- manage subtopics and resources;
- order roadmap structure;
- retrieve public and management views;
- generate complete roadmap drafts or individual suggestions through AI.
- create, edit, publish, retrieve, and delete articles;
- upload cover images;
- manage tags;
- like and unlike articles;
- add and delete comments;
- support knowledge sharing inside the tenant.
Main route groups:
/api/posts
/api/events
/api/announcements
- create, edit, retrieve, and delete posts;
- upload and manage post images;
- categorize content with tags and post types;
- pin and unpin important posts;
- like and unlike posts;
- add and remove comments;
- retrieve feeds and post details.
- create and update events;
- upload event banners;
- retrieve event lists, details, and calendar views;
- attend an event or cancel attendance;
- cancel events;
- schedule reminder processing for attendees.
- create and update announcements;
- define priority and audience targeting;
- retrieve tenant-relevant announcements;
- publish due announcement notifications;
- track whether notification delivery has been processed.
Main route group: /api/notifications
Notifications are both persisted and delivered in real time.
The module supports:
- paged notification retrieval;
- read/unread state;
- unread-count retrieval;
- marking one notification as read;
- marking all notifications as read;
- optional entity type, entity ID, and action URL for navigation;
- tenant-, team-, and user-targeted delivery;
- application-event-driven notification creation;
- SignalR updates for newly created notifications and unread counts.
Main route group: /api/reports
The reporting module retrieves analytical data through dedicated read models and can return report data or generate branded PDF documents. Report results are also available to the AI insight subsystem.
The exact implemented report types are documented in Analytics, Reports, and PDF Export.
Main route groups:
/api/projects/{projectId}/work-items/ai-suggestions
/api/ai/roadmaps
/api/ai/reports
/api/Gaps/skill-gaps/me
AI supports users during normal workflows rather than replacing domain validation. Generated content is returned as a suggestion or draft, and the regular creation/update use case remains responsible for validation and persistence.
Main route groups:
/api/metadata
/api/tags
The metadata area exposes values required by the client, including domain enums, workflow information, and shared option data. This reduces duplication between backend and frontend and helps the UI present values that match the current domain implementation.
sequenceDiagram
participant User
participant API
participant Identity as ASP.NET Core Identity
participant DB as SQL Server
User->>API: Email + password
API->>Identity: Validate credentials and account state
Identity->>DB: Read user, roles, tenant, and refresh data
DB-->>Identity: Identity state
Identity-->>API: Authenticated user
API->>API: Create claims and signed access token
API->>DB: Persist refresh token
API-->>User: Access token + refresh token + user context
ASP.NET Core Identity is configured for user, password, and role management.
Password requirements include:
- at least one uppercase character;
- at least one lowercase character;
- at least one digit;
- at least one non-alphanumeric character;
- minimum length of eight characters;
- unique email addresses.
The account lifecycle also supports email confirmation and password-reset tokens.
The API validates:
- signing key and signature;
- issuer;
- audience;
- token lifetime.
Generated claims include the identifiers and context required by the application, such as:
sub
jti
fullName
username
email
lastLoginAt
tenantId
mustChangePassword
role / roles
Refresh tokens are not treated as permanent credentials:
- they are persisted in the database;
- their lifetime is seven days in the current implementation;
- a successful refresh rotates the token;
- the previous refresh token is revoked;
- an explicit revoke operation is available.
Newly registered users can be required to replace a temporary password before using the protected platform normally. The authorization configuration includes a password-changed policy, and the authentication response exposes the information needed by the client to route the user through setup.
Access is not decided by role alone. The backend combines several layers:
- Authentication — the request must carry a valid identity.
- Account state — inactive or invalid accounts are blocked.
- Tenant state and membership — the organization must be valid and the user must belong to it.
- Role-based checks — roles represent organizational responsibilities.
- Policy-based checks — named policies protect specific modules and operations.
- Project-access requirements — project-scoped resources require relevant project access.
- Command/query validation — use cases verify related records and operation rules.
- Domain rules — state transitions and invariants are enforced inside domain models.
Representative policy groups include:
PasswordChanged
Project_Access
Tenant.Read
Tenant.Manage
Local.Tenant.Manage
Projects.Read
Projects.Manage
Projects.HighLevelManage
Teams.Read
Teams.Manage
Sprints.Read
Sprints.Manage
WorkItems.*
Roadmaps.*
Tags.*
Courses.*
Posts.*
Announcements.*
Events.*
- REST endpoints use Bearer authentication where required.
- SignalR accepts the JWT through the
access_tokenquery parameter during hub negotiation. - persistence entities are not exposed directly as API contracts;
- request models and DTOs define explicit transport boundaries;
- unmapped JSON members are rejected;
- FluentValidation runs before application handlers;
- related entities are checked before commands modify state;
- tenant context is validated before tenant-scoped work;
- database relationships and constraints protect referential integrity;
- errors are returned through consistent Problem Details responses;
- development-only diagnostic detail is kept separate from production responses.
Do not commit connection strings, JWT secrets, SMTP credentials, Cloudinary credentials, or optional Ollama credentials. Use local settings, .NET user secrets, or deployment environment variables.
The backend exposes three authenticated SignalR hubs.
| Hub | Route | Responsibility |
|---|---|---|
| Presence Hub | /hubs/presence |
Tenant-scoped online state and online/offline updates |
| Comment Hub | /hubs/comments |
Real-time comments for one project work item |
| Notification Hub | /hubs/notifications |
Persistent notification delivery and unread-count updates |
The Presence Hub supports tenant-scoped presence operations such as checking whether a user is online and retrieving online users.
The tenant presence group follows this shape:
tenants:{tenantId}:presence
The current presence tracker is process-local and stored in application memory. This is suitable for the current single-process design. A multi-instance deployment would require a distributed presence store and a SignalR scale-out mechanism to keep presence state synchronized across instances.
The Comment Hub works with a specific project and work item. Connections provide projectId and workItemId as query parameters, and the hub validates access before joining the real-time comment context.
Client event names used by the implementation include:
Comments:Load
Comments:Created
Comments:Updated
Comments:Deleted
Comments:Error
Notification connections join scoped groups such as:
tenant:{tenantId}
tenant:{tenantId}:team:{teamId}
tenant:{tenantId}:user:{userId}
The client receives events including:
NotificationReceived
UnreadCountChanged
Notifications are saved before real-time delivery, so a disconnected user can still retrieve them later from the notification API.
Core use cases publish application events through MediatR. Event handlers then perform secondary work such as creating in-app notifications, sending email, or broadcasting real-time updates.
This separation prevents a command handler from becoming tightly coupled to every delivery channel.
Representative event-driven scenarios include:
- role changes;
- team-member additions and removals;
- team activation changes;
- project assignment;
- work-item assignment, unassignment, details changes, and comments;
- sprint status changes;
- course assignments;
- article and post interactions;
- announcement publication;
- event reminders;
- welcome notification after initial account access.
The in-app notification model supports:
- recipient user;
- optional triggering user;
- notification type, title, and message;
- optional entity type and entity ID;
- optional action URL;
- read state;
- creation timestamp;
- tenant ownership.
Email is sent through an SMTP implementation based on System.Net.Mail, with SSL enabled and reusable HTML templates selected through the email-template factory.
The repository contains two hosted background services built with BackgroundService and PeriodicTimer.
- checks for due reminders every minute;
- targets event attendees;
- processes reminders approximately 15 minutes before event start;
- publishes the relevant event/notification workflow;
- marks the reminder as sent to prevent duplicate processing.
- checks every minute for announcements whose scheduled time has arrived;
- publishes the notification event;
- marks announcement notification delivery as processed.
These workers demonstrate scheduled processing inside the ASP.NET Core host. For a larger distributed deployment, a persistent job scheduler or queue-based worker architecture would be a natural evolution.
The AI subsystem communicates with an Ollama-compatible chat API.
Endpoint: {OllamaSettings.BaseUrl}/api/chat
Model: gemma3:latest
Request timeout: 10 minutes
Authentication: optional HTTP Basic authentication
The service prompt instructs the model to use the supplied application data and avoid inventing unsupported context.
AI can suggest structured fields for:
- Epics;
- User Stories;
- Tasks;
- Bugs;
- Test Cases.
The response is not accepted blindly. The backend performs:
- model request construction;
- JSON extraction from the model response;
- normalization into the expected structure;
- validation of required fields and values;
- repair prompts when parsing or validation fails;
- up to three generation attempts;
- safe fallback suggestions when the model still does not return a usable result.
The generated suggestion is returned to the client for review. A normal work-item command must still validate and persist any final user-approved data.
The AI subsystem supports:
- generation of a complete roadmap draft;
- generation-and-create workflows;
- topic suggestions;
- subtopic suggestions;
- learning-resource suggestions.
Structured parsing, validation, retry, and fallback behavior is also used for roadmap output.
Endpoint:
GET /api/Gaps/skill-gaps/me
The use case analyzes the current user's role and recorded skills to return a structured result that can include:
- readiness score and level;
- identified strengths;
- missing or underdeveloped skills;
- priority information;
- development advice;
- role-related learning recommendations.
Every supported report type can be transformed into an AI prompt based on the retrieved report data. The result is structured around concepts such as:
- summary;
- key findings;
- risks or concerns;
- recommendations.
The report-data-first approach keeps the AI analysis tied to the selected tenant, project, sprint, team, user, or work-item metrics rather than requesting an unsupported general opinion.
AI is an assistive layer, not the source of business truth. Tenant security, authorization, domain validation, persistence, and state transitions remain fully controlled by the regular backend application and domain layers.
The reporting subsystem separates several responsibilities:
flowchart LR
Request[Report request]
Authorization[Scope and access checks]
ReadModel[Analytical read model]
Data[Structured report data]
JSON[JSON response]
Chart[ScottPlot chart rendering]
PDF[QuestPDF document rendering]
AI[AI report insight]
Request --> Authorization --> ReadModel --> Data
Data --> JSON
Data --> Chart --> PDF
Data --> PDF
Data --> AI
The exact ReportType enum contains ten report types:
| # | Enum value | Purpose |
|---|---|---|
| 1 | TenantInfo |
Organization-level information and summary data |
| 2 | SprintProgress |
Sprint scope and progress information |
| 3 | Velocity |
Delivery velocity across completed sprint work |
| 4 | CycleTime |
Time taken for work to move through delivery |
| 5 | BugSeverityDistribution |
Distribution of Bugs according to severity-related data |
| 6 | DeveloperProductivity |
Developer-focused work and completion metrics |
| 7 | TeamsProductivity |
Team-level productivity information |
| 8 | BlockedWorkItems |
Work currently marked as blocked |
| 9 | OverdueWorkItems |
Work whose relevant dates indicate it is overdue |
| 10 | ProjectHealth |
Combined project indicators used to evaluate project condition |
The Reports controller also exposes sprint-summary functionality in addition to the report-type workflow.
- QuestPDF generates the PDF document.
- ScottPlot renders charts used inside reports.
- a shared branding provider supplies report identity and logo assets;
- dedicated read models retrieve analytical data;
- report-specific rendering components keep data access separate from presentation;
- AI report endpoints reuse report data to generate narrative insights.
QuestPDF is configured with its Community license in the current project.
The backend uses:
- SQL Server as the relational database;
- Entity Framework Core 8;
- Code-First migrations;
AppDbContextderived fromIdentityDbContext;- explicit entity configurations;
- indexes, required fields, keys, unique constraints, and relationships;
- seeders for platform roles and the global tenant.
The domain model is not used as a direct database schema representation. Infrastructure contains persistence entities and explicit mappings between persistence and domain forms.
This design allows:
- domain behavior to remain independent from EF Core navigation requirements;
- database relationships and columns to evolve without placing persistence concerns inside the core model;
- commands to work with behavior-rich domain objects;
- queries to bypass domain hydration and project directly into DTOs.
Command operations use repositories to load and persist domain state. Related database changes are committed through the Unit of Work, which provides transaction and rollback behavior for multi-step operations.
Read operations use purpose-specific read models. Their responsibilities include:
- tenant and project scoping;
- filtering and search;
- sorting;
- pagination and cursor retrieval where implemented;
- EF Core projections;
AsNoTrackingfor appropriate read-only queries;- returning only the fields required by the requested screen or report.
EF Core configuration applies a UTC converter to DateTime and nullable DateTime properties. This reduces inconsistencies between local development, hosted environments, clients, scheduled workers, and report calculations.
Data integrity is protected through multiple mechanisms:
- request validation;
- command-handler relationship checks;
- domain guards and controlled state transitions;
- tenant identifiers and scoped access;
- SQL Server primary and foreign keys;
- required and unique constraints;
- Unit of Work transactions;
- date-range validation;
- project and work-item history;
- DTO boundaries that limit accepted and returned data.
The frontend and backend communicate through RESTful endpoints using JSON.
JSON configuration includes:
- conversion support for spaced enum values;
- an ISO 8601 date/time converter;
- rejection of unmapped JSON members.
Rejecting unsupported JSON properties helps detect outdated or incorrectly shaped client requests instead of silently ignoring accidental input.
Validation occurs at more than one boundary:
- API validators protect transport contracts;
- a MediatR validation behavior validates application requests before handlers run;
- handlers verify related records and authorization context;
- domain models enforce invariants that must hold regardless of transport.
Global exception handling converts failures into consistent ProblemDetails or ValidationProblemDetails responses.
Responses can include:
- HTTP status;
- error title and detail;
- validation-error collections;
- a trace identifier for support and debugging.
Detailed stack information is restricted to Development rather than being exposed in normal production responses.
Swagger/OpenAPI is configured with:
- generated endpoint documentation;
- XML comments;
- a Bearer-token security scheme;
- interactive request execution;
- conditional enablement through environment and configuration.
| Category | Technology | How It Is Used |
|---|---|---|
| Language | C# | Domain, application, infrastructure, and API implementation |
| Runtime | .NET 8 | Target framework for all projects |
| Web API | ASP.NET Core Web API | REST endpoints, middleware, dependency injection, hosted services, and application host |
| Architecture | Clean Architecture-based four-project design | Separates Domain, Application, Infrastructure, and API responsibilities |
| Application pattern | CQRS | Separates state-changing commands from optimized queries |
| Messaging | MediatR 13 | Commands, queries, application events, handlers, and pipeline behavior |
| ORM | Entity Framework Core 8 | SQL Server access, mappings, projections, migrations, and Identity persistence |
| Database | SQL Server | Relational storage for identity and platform data |
| Identity | ASP.NET Core Identity | Users, passwords, roles, account tokens, and identity persistence |
| Authentication | JWT Bearer + refresh tokens | Stateless API access with persisted session renewal and revocation |
| Authorization | Roles, policies, project requirements, tenant context | Fine-grained access control across platform, tenant, and project scopes |
| Validation | FluentValidation 12 | API and application-request validation |
| Mapping | AutoMapper 12 + explicit mappers | API/DTO mapping and domain/persistence conversion |
| Real time | ASP.NET Core SignalR | Presence, comments, notifications, and unread-count events |
| Media | CloudinaryDotNet | Images, files, videos, and attachments |
SMTP / System.Net.Mail |
Confirmation, password, account, notification, and reminder emails | |
| QuestPDF | Branded downloadable report documents | |
| Charts | ScottPlot | Charts embedded in report documents |
| AI | Ollama HTTP API + gemma3:latest |
Suggestions, generation, skill-gap analysis, and report insights |
| Background work | BackgroundService + PeriodicTimer |
Announcement scheduling and event reminders |
| Documentation | Swagger / OpenAPI | Interactive API discovery and testing |
| Errors | ASP.NET Core exception handler + Problem Details | Consistent API failure responses |
| Logging | ASP.NET Core ILogger abstractions |
Startup, errors, services, and worker diagnostics |
Some project files contain additional package references. This README lists technologies that are evidenced as active parts of the current source implementation rather than presenting every referenced package as a configured runtime component.
Infrastructure provides a storage factory and services for media categories such as images, files, videos, and work-item attachments. The backend stores provider results and exposes the resulting media through platform use cases.
SMTP is used for account and system email. Configuration includes host, port, username, password, and sender address. Reusable HTML templates separate email presentation from business commands.
Ollama provides the chat endpoint used by AI services. The base URL is configurable, and optional Basic authentication is sent when both username and password are configured.
These libraries run inside the backend to create PDF reports and render their charts. They are not external hosted APIs, but they are important infrastructure integrations inside the reporting pipeline.
Collabrium/
├── API/
│ ├── Common/
│ ├── Contracts/
│ ├── Controllers/
│ ├── MappingProfiles/
│ ├── Middlewares/
│ ├── Properties/
│ ├── SetupProgram/
│ ├── Validators/
│ ├── API.http
│ ├── API.csproj
│ └── Program.cs
│
├── Application/
│ ├── Common/
│ │ ├── Behaviors/
│ │ ├── DTOs/
│ │ └── Exceptions/
│ ├── Events/
│ ├── EventsHandlers/
│ ├── Features/
│ │ ├── AI/
│ │ ├── Announcements/
│ │ ├── Articles/
│ │ ├── Courses/
│ │ ├── Events/
│ │ ├── Identity/
│ │ ├── Metadata/
│ │ ├── Notifications/
│ │ ├── Posts/
│ │ ├── Projects/
│ │ ├── Reports/
│ │ ├── Roadmaps/
│ │ ├── Sprints/
│ │ ├── Tags/
│ │ ├── Teams/
│ │ ├── Tenants/
│ │ ├── Users/
│ │ └── WorkItems/
│ ├── Interfaces/
│ ├── Services/
│ ├── Application.csproj
│ └── DependencyInjection.cs
│
├── Domain/
│ ├── Core/
│ ├── Enums/
│ ├── Models/
│ ├── ValueObjects/
│ └── Domain.csproj
│
├── Infrastructure/
│ ├── AI/
│ ├── BackgroundServices/
│ ├── Email/
│ ├── FilesStorage/
│ ├── Identity/
│ ├── Migrations/
│ ├── Persistence/
│ │ ├── Configurations/
│ │ ├── Entities/
│ │ ├── Mappers/
│ │ ├── ReadModels/
│ │ ├── Repositories/
│ │ └── Seeders/
│ ├── Reports/
│ │ └── Assets/
│ ├── Security/
│ ├── Settings/
│ ├── SignalR/
│ ├── TenantContexts/
│ ├── DependencyInjection.cs
│ └── Infrastructure.csproj
│
├── .gitignore
├── Collabrium.sln
└── README.md
Domain
▲
│
Application
▲ ▲
│ │
Infrastructure
▲
│
API
More precisely:
ApplicationreferencesDomain.InfrastructurereferencesApplication.APIreferences bothApplicationandInfrastructure.
| Area | Base route |
|---|---|
| Authentication | /api/auth |
| Tenants | /api/tenants |
| Users | /api/users |
| Teams | /api/teams |
| Projects | /api/projects |
| Work items | /api/projects/{projectId}/work-items |
| Sprints | /api/projects/project/{projectId}/sprints |
| Courses | /api/courses |
| Course ratings | /api/courses/{courseId}/ratings |
| User courses | /api/user-courses |
| Course assignments | /api/user-course-assignments |
| Roadmaps | /api/roadmaps |
| Roadmap nodes | /api/roadmaps/roadmap/{roadmapId}/nodes |
| Roadmap subtopics | /api/roadmaps/roadmap/{roadmapId}/topics/{topicNodeId}/subtopics |
| Roadmap resources | /api/roadmaps/roadmap/{roadmapId}/topics/{topicNodeId}/subtopics/{subTopicId}/resources |
| Articles | /api/articles |
| Posts | /api/posts |
| Events | /api/events |
| Announcements | /api/announcements |
| Notifications | /api/notifications |
| Reports | /api/reports |
| AI report insights | /api/ai/reports |
| AI roadmap assistance | /api/ai/roadmaps |
| AI work-item suggestions | /api/projects/{projectId}/work-items/ai-suggestions |
| Current-user skill gaps | /api/Gaps/skill-gaps/me |
| Metadata | /api/metadata |
| Tags | /api/tags |
SignalR routes:
/hubs/presence
/hubs/comments
/hubs/notifications
Swagger provides the operation-level routes, parameters, request contracts, response types, and authorization requirements.
The exact role enum contains thirteen roles:
SuperAdmin
TenantAdmin
CEO
HR
ProductOwner
TeamLead
BackendDev
FrontendDev
FullStackDev
QA
BusinessAnalyst
Designer
IT
| Role | General organizational responsibility represented by the role |
|---|---|
SuperAdmin |
Platform-level tenant administration and global platform operations |
TenantAdmin |
Administration of one tenant's users, roles, teams, content, and organization settings |
CEO |
High-level organizational visibility and management use cases |
HR |
Employee, skill, learning, and workforce-related use cases where authorized |
ProductOwner |
Product direction, backlog, planning, and project-management activities |
TeamLead |
Team coordination, assignment, sprint, and execution oversight |
BackendDev |
Backend-development work and authorized project collaboration |
FrontendDev |
Frontend-development work and authorized project collaboration |
FullStackDev |
Cross-stack development work and authorized project collaboration |
QA |
test cases, Bugs, quality workflows, and project collaboration |
BusinessAnalyst |
requirements, Epics, User Stories, acceptance criteria, and planning collaboration |
Designer |
design-related team membership and assigned project work |
IT |
technical account and user-management responsibilities where policy permits |
These descriptions explain the business meaning of the roles. Effective endpoint access is determined by the actual authorization policies, tenant context, project access, and use-case checks—not by this table alone.
This repository demonstrates more than framework usage. It shows how several backend engineering concerns were combined in one coherent system.
- designing a large REST API across multiple business modules;
- defining explicit HTTP contracts and DTOs;
- clear API organization and Swagger documentation;
- consistent error contracts and validation responses;
- asynchronous request handling and cancellation-token propagation;
- real-time API design through SignalR.
- Clean Architecture dependency direction;
- CQRS separation of commands and queries;
- MediatR request and event pipelines;
- repository, read-model, and Unit of Work patterns;
- dependency inversion through interfaces;
- separation of domain objects from persistence entities;
- modular, feature-oriented application organization.
- modeling Projects, Sprints, Epics, User Stories, Tasks, Bugs, and Test Cases;
- implementing type-specific workflows rather than one generic status sequence;
- enforcing aggregate rules and state transitions;
- protecting completion rules and hierarchy constraints;
- maintaining project and work-item traceability.
- ASP.NET Core Identity configuration;
- JWT issuing and validation;
- refresh-token persistence, rotation, and revocation;
- email-confirmation and password-recovery flows;
- role- and policy-based authorization;
- tenant-context middleware;
- account, tenant, membership, and project-level access checks;
- secure SignalR authentication.
- SQL Server relational design;
- EF Core Code-First migrations;
- explicit configurations, constraints, indexes, and relationships;
- transactional command operations;
- read projections and performance-conscious query models;
- UTC date normalization;
- seed data for roles and global platform state.
- SignalR connection and group management;
- tenant-, team-, user-, project-, and work-item-scoped communication;
- persistent notification records combined with real-time delivery;
- MediatR events that decouple primary use cases from secondary effects;
- background workers for scheduled system activity.
- integrating a locally or remotely hosted language model through Ollama;
- prompt construction from application-owned data;
- structured JSON response extraction;
- normalization and validation of model output;
- repair retries and safe fallbacks;
- keeping AI suggestions separate from authoritative domain commands.
- analytical read models;
- metric and report-specific data retrieval;
- server-side chart rendering;
- PDF document generation and branding;
- reuse of report data for AI-generated narrative insight.
- Cloudinary media storage behind service abstractions;
- SMTP email behind reusable services and templates;
- interface-based integrations that can be replaced without rewriting core domain logic.
Install or prepare:
- .NET 8 SDK
- SQL Server, SQL Server Developer Edition, or another compatible SQL Server environment
- Entity Framework Core CLI tools
- Ollama and
gemma3:latestfor AI features - a Cloudinary account for upload features
- an SMTP account/server for email features
git clone https://github.com/NadaAsadk/Collabrium.git
cd Collabriumdotnet restore Collabrium.slnCreate:
API/appsettings.Development.json
The repository ignores API/appsettings*.json, which helps prevent local secrets from being committed.
{
"ConnectionStrings": {
"SqlServer": "Server=localhost;Database=CollabriumDb;Trusted_Connection=True;TrustServerCertificate=True;"
},
"JwtSettings": {
"SecretKey": "replace-with-a-long-random-development-secret",
"ExpiryMinutes": 60,
"Issuer": "Collabrium.API",
"Audience": "Collabrium.Client"
},
"IdentitySettings": {
"ConfirmationUrlBase": "http://localhost:5173/confirm-email",
"PasswordResetUrlBase": "http://localhost:5173/reset-password"
},
"WebAppSettings": {
"BaseUrl": "http://localhost:5173"
},
"CloudinarySettings": {
"CloudName": "your-cloud-name",
"ApiKey": "your-api-key",
"ApiSecret": "your-api-secret"
},
"SmtpSettings": {
"Host": "smtp.example.com",
"Port": 587,
"User": "your-smtp-user",
"Password": "your-smtp-password",
"From": "no-reply@example.com"
},
"OllamaSettings": {
"BaseUrl": "http://localhost:11434",
"Username": "",
"Password": ""
},
"DatabaseSettings": {
"ApplyMigrationsOnStartup": true,
"SeedDataOnStartup": true
},
"SwaggerSettings": {
"Enabled": true
}
}The sample values are placeholders only. Never copy production credentials into the repository.
ollama pull gemma3:latest
ollama serveAI endpoints require the configured Ollama server to be reachable. Other modules can be developed independently, but AI requests will fail while the service is unavailable.
The repository uses EF Core 8.0.19 packages. A matching CLI version can be installed with:
dotnet tool install --global dotnet-ef --version 8.0.19To update an existing installation:
dotnet tool update --global dotnet-ef --version 8.0.19If startup migration is disabled, run:
dotnet ef database update --project Infrastructure --startup-project APIHTTP profile:
dotnet run --project API --launch-profile httpDefault HTTP URL:
http://localhost:5000
HTTPS profile:
dotnet run --project API --launch-profile httpsDefault URLs in the included launch profile:
https://localhost:5000
http://localhost:5001
Swagger opens at:
/swagger
For example:
https://localhost:5000/swagger
The current CORS configuration includes local Vite origins on ports 5173 through 5177 and the deployed Azure Static Web Apps frontend:
https://wonderful-flower-040696410.7.azurestaticapps.net
ASP.NET Core environment variables use double underscores in place of nested JSON separators.
Examples:
ConnectionStrings__SqlServer
JwtSettings__SecretKey
OllamaSettings__BaseUrl
CloudinarySettings__ApiSecret
DatabaseSettings__ApplyMigrationsOnStartup
| Section | Key | Required for | Description |
|---|---|---|---|
ConnectionStrings |
SqlServer |
Core application | SQL Server connection string |
JwtSettings |
SecretKey |
Authentication | Symmetric JWT signing secret |
JwtSettings |
ExpiryMinutes |
Authentication | Access-token lifetime in minutes |
JwtSettings |
Issuer |
Authentication | Expected JWT issuer |
JwtSettings |
Audience |
Authentication | Expected JWT audience |
IdentitySettings |
ConfirmationUrlBase |
Email confirmation | Frontend route used in confirmation links |
IdentitySettings |
PasswordResetUrlBase |
Password reset | Frontend route used in reset links |
WebAppSettings |
BaseUrl |
Generated application links | Frontend base URL |
CloudinarySettings |
CloudName |
Media uploads | Cloudinary cloud identifier |
CloudinarySettings |
ApiKey |
Media uploads | Cloudinary API key |
CloudinarySettings |
ApiSecret |
Media uploads | Cloudinary API secret |
SmtpSettings |
Host |
SMTP server host | |
SmtpSettings |
Port |
SMTP server port | |
SmtpSettings |
User |
SMTP username | |
SmtpSettings |
Password |
SMTP password or application password | |
SmtpSettings |
From |
Sender address | |
OllamaSettings |
BaseUrl |
AI | Ollama-compatible service base URL |
OllamaSettings |
Username |
Optional AI auth | HTTP Basic username |
OllamaSettings |
Password |
Optional AI auth | HTTP Basic password |
DatabaseSettings |
ApplyMigrationsOnStartup |
Startup | Whether pending migrations are applied automatically |
DatabaseSettings |
SeedDataOnStartup |
Startup | Whether platform roles and the global tenant are seeded |
SwaggerSettings |
Enabled |
API documentation | Enables Swagger outside Development when true |
dotnet ef migrations add <MigrationName> \
--project Infrastructure \
--startup-project API \
--output-dir MigrationsPowerShell equivalent:
dotnet ef migrations add <MigrationName> `
--project Infrastructure `
--startup-project API `
--output-dir Migrationsdotnet ef database update \
--project Infrastructure \
--startup-project APIProgram.cs registers API and infrastructure services, then calls the startup migration and seed workflow before configuring middleware.
Depending on DatabaseSettings, startup can:
- apply pending migrations;
- seed the complete role set;
- seed the global tenant used by platform-level Super Admin operations.
For a production multi-instance deployment, migration ownership should be controlled so multiple instances do not attempt to migrate the same database concurrently.
- Start the API.
- Open
/swagger. - Use the appropriate authentication endpoint to create or access an account.
- Log in through
/api/auth/login. - Copy the returned access token.
- Select Authorize in Swagger.
- Enter the JWT as instructed by the Bearer security dialog.
- Execute authorized requests and inspect contracts and responses.
The repository also includes API/API.http, which can be used as a lightweight starting point for HTTP requests in supported editors.
Controller
→ MediatR command/query
→ FluentValidation behavior
→ Handler
→ Repository or read model
→ SQL Server / external service
→ Application event when needed
→ API response contract
A typical feature addition follows this shape:
- place core invariant changes in the Domain project;
- define a command or query in the relevant Application feature;
- define or reuse the required interface;
- implement persistence or external-service behavior in Infrastructure;
- add request/response contracts and mapping in API;
- expose the endpoint through a controller;
- add FluentValidation rules;
- apply policies and tenant/project checks;
- document the operation through Swagger/XML comments;
- add tests when a test project is introduced.
Recommended local approaches:
dotnet user-secrets init --project API
dotnet user-secrets set "JwtSettings:SecretKey" "your-local-secret" --project API
dotnet user-secrets set "ConnectionStrings:SqlServer" "your-local-connection-string" --project APIDeployment environments should supply secrets through their protected configuration mechanism.
Collabrium was completed as a graduation project in June 2026. This repository snapshot includes:
- the four backend projects;
- domain rules and application use cases;
- EF Core migrations;
- Swagger documentation;
- validators and middleware;
- the
.httprequest file; - reporting, AI, SignalR, email, storage, and background-service implementations.
An automated unit or integration test project is not present in the current repository snapshot. Therefore, this README does not claim an automated test suite or a test-coverage percentage.
Recommended future test areas are:
- domain transition and completion-rule unit tests;
- tenant-isolation integration tests;
- authentication and refresh-token tests;
- authorization-policy tests;
- command-handler transaction tests;
- query projection and pagination tests;
- SignalR hub authorization and group tests;
- notification/event-handler tests;
- report-generation verification;
- AI structured-output parsing and fallback tests;
- full API and SQL Server integration tests.
The source was reviewed statically for this documentation. A build result is not claimed here unless the repository is compiled in an environment with the .NET 8 SDK and all required configuration/services.
The repository currently does not contain:
- a Dockerfile;
- a Docker Compose configuration;
- a CI workflow file;
- an automated deployment pipeline definition.
The deployed frontend is hosted on Azure Static Web Apps, and the API CORS configuration includes that frontend origin. Backend deployment still requires:
- a .NET 8-compatible host;
- a reachable SQL Server database;
- protected application configuration;
- HTTPS;
- an SMTP service for email workflows;
- Cloudinary credentials for media workflows;
- a reachable Ollama service for AI workflows;
- a strategy for migrations and background-service ownership;
- SignalR scale-out and distributed presence storage when running multiple API instances.
| Resource | URL |
|---|---|
| Live application | https://wonderful-flower-040696410.7.azurestaticapps.net/ |
| Frontend showcase | https://github.com/NadaAsadk/Collabrium-Frontend-Showcase |
| Main project repository | https://github.com/NadaAsadk/Collabrium |
Collabrium was developed as a graduation project submitted in partial fulfillment of the requirements for the Bachelor's Degree in Computer Systems Engineering.
Palestine Technical University – Kadoorie
Faculty of Engineering and Technology
Department of Computer Systems Engineering
Tulkarm, Palestine
June 2026
The project was developed iteratively using an Agile approach with two-week sprints covering requirements, modeling, UI/UX, backend and frontend implementation, integration, testing, review, and refinement.
- Abeer Mahmoud
- Hanan Issa
- Nada Asad
- Raghad Hanon
- Dr. Thaer Sammar
Copyright © 2026 Abeer Mahmoud, Hanan Issa, Nada Asad, and Raghad Hanon. All rights reserved.
Collabrium and its source code are the exclusive intellectual property of the project team. This repository is made available for viewing, academic evaluation, and portfolio demonstration only. It is not open source.
No part of this project may be copied, modified, reproduced, distributed, sublicensed, published, sold, used commercially, or incorporated into another project without prior written permission from the project owners. Access to the repository does not grant any license or ownership rights.
For permission requests, please contact the project team.
Integrated management, collaboration, learning, analytics, and intelligent assistance in one enterprise platform.