Backend for a Jira-style task management platform with project-based collaboration, role-based access control, and real-time activity updates.
The solution is split into two services:
TaskManagement.Auth: OAuth2/OIDC with OpenIddict + ASP.NET Identity.TaskManagement.Api: Vertical-slice ASP.NET Core API for Projects, TaskItems, and Activity feed (including SignalR notifications).
Designed for local full-stack development with Docker + Caddy and structured to evolve toward production deployment patterns.
flowchart LR
SPA["TaskManagementClient (Angular SPA)"] -->|"HTTPS"| Caddy["Caddy Reverse Proxy"]
Caddy -->|"HTTPS"| Auth["Auth Service<br/>OpenIddict + Identity"]
Caddy -->|"HTTPS"| Api["API Service<br/>Projects + TaskItems + Activity"]
Auth --> Db[("PostgreSQL")]
Api --> Db
- OAuth2 / OpenID Connect via OpenIddict.
- JWT validation in API service.
- Role and resource-based authorization checks in handlers.
- Auth user directory exposes
isActivestatus and user roles. - User management endpoints in Auth service:
GET /api/userswithsearch,isActive, androlefilters (paged).Administrator: can query all users with full filters.ProjectManager: restricted torole=Userqueries (assignable-contributor lookup).
GET /api/users/{id}/detailsfor richer admin user profile data.PATCH /api/users/{id}/statusto activate/deactivate users.
- Safety guards:
- Admins cannot deactivate themselves.
- The last active administrator cannot be deactivated.
- Rate limiting on sensitive auth/admin operations:
POST /connect/token- Admin user-management endpoints (
GET /api/users,GET /api/users/{id}/details,PATCH /api/users/{id}/status)
- Create, update, delete, and read projects.
- Partial updates via
PATCH /api/projects/{id}. - Project membership tracking (
ProjectMember) with audit fields. - Project members listing endpoint with display names.
- Inactive users are surfaced in display names as
Name (Inactive)when resolved from user directory.
- Create, update, delete, and read task items.
- Partial updates via
PATCH /api/taskitems/{id}. - Assignment support and project membership auto-add for newly assigned users.
- Filtered task queries for project, assignee, updater, status, unassigned, text search, date range, and pagination.
- Activity log for key events:
ProjectCreatedProjectRenamedProjectDeletedTaskCreatedTaskStatusChangedTaskRenamedTaskDeletedTaskAssigneeChangedTaskDueDateChanged
- Activity feed endpoint for dashboard consumption with pagination.
- Activity payload includes
oldValue/newValuefor rename/assignee/due-date changes andoldStatus/newStatusfor status transitions. - SignalR hub for real-time updates (
/hubs/activity) with project and admin group subscriptions.
- Aggregated dashboard summary endpoint:
GET /api/dashboard/summary.
- Authentication for hub requests supports bearer tokens in
Authorizationheader oraccess_tokenquery string (WebSocket-friendly). - Connections are closed on token expiration (
CloseOnAuthenticationExpiration = true) so clients can reconnect with a fresh token. - On each connection, the server auto-subscribes:
Administratorto global admin activity group.- Non-admin users to all projects they can access.
- Optional hub methods for explicit subscriptions:
JoinProject(projectId)JoinProjects(projectIds)JoinAllProjects()ResubscribeToScope()LeaveProject(projectId)
High-level role intent:
Administrator: platform-wide superuser.ProjectManager: project delivery owner with project/task management in project scope.User: day-to-day contributor with task-focused access.
For endpoint-level details, see:
Vertical slice architecture organizes by feature instead of technical layers.
Each feature typically contains:
- Commands and queries
- Handlers
- Validators
- Mappings
- Controller endpoints
Benefits:
- Better feature ownership
- Lower coupling between slices
- Cleaner incremental changes
- ASP.NET Core (.NET 8)
- EF Core (PostgreSQL)
- MediatR
- FluentValidation
- AutoMapper
- OpenIddict
- Serilog
- xUnit + integration testing
- Docker Compose + Caddy
- OpenIddict authorization server
- ASP.NET Identity user and role management
- Authorization Code + PKCE support
- Issues tokens via Authorization Code + PKCE
- Projects, TaskItems, Activity features
- Token validation and authorization enforcement
- SignalR real-time activity events
- Unit and integration tests
- Shared persistence for Auth and API domains
- Local HTTPS termination
- Routing for
auth.localhostandapi.localhost
- Docker
- Docker Compose (v2)
- Hosts file entries:
127.0.0.1 api.localhost127.0.0.1 auth.localhost
You can copy .env.example to .env and adjust values if needed.
docker compose up --buildThis starts PostgreSQL, Auth, API, and Caddy with local HTTPS routing.
macOS:
./scripts/setup-local-trust.shWindows (PowerShell as Administrator):
./scripts/setup-local-trust.ps1Run full solution tests:
dotnet test TaskManagementServer.sln -c DebugTest coverage includes:
- Authorization and role behavior
- Command/query handler rules
- API integration flows
- Persistence and mappings
TaskManagement.Auth Swagger is intentionally scoped to api/* endpoints (admin user-management APIs).
OAuth/OpenID endpoints (/connect/*) are not shown in Auth Swagger to avoid route conflicts and keep docs focused.
To call protected Auth admin endpoints from Swagger:
- Obtain an access token from the Auth service (e.g., via SPA login flow, Postman, or direct OAuth2 Authorization Code + token exchange).
- Open
https://auth.localhost/swagger. - Click Authorize and paste:
Bearer <access_token>
Notes:
- This is a development/testing workflow.
- For full OAuth2 Swagger login UX, use
TaskManagement.ApiSwagger (resource API), where OAuth2 authorization flow is the primary fit.
This project is intended as a production-minded learning and portfolio codebase for a full-stack Jira-like platform.
Backend priorities:
- Correct authorization and tenancy boundaries
- Clean feature-oriented architecture
- Observable and testable behavior
- Real-time user-facing events for SPA dashboards