Project SaaS Task Management Platform

A multi-tenant SaaS ticket and task management system focused on backend architecture, tenant isolation, authentication, reliability, and asynchronous processing.

Overview

Project SaaS is a B2B, multi-tenant task and ticket management system designed to simulate the kind of backend architecture used in real production environments. The project prioritises correctness, tenant safety, resilience, and maintainability over flashy UI features.

The system allows multiple organisations to use the same platform while keeping their data isolated through tenant-aware design. It also supports JWT authentication, role-based access control, optimistic concurrency, background workers, outbox-driven event processing, and notification delivery (disabled on the live app to keep it free).

Login flow

Authentication is handled through a secure login flow using JWT-based access control. The frontend submits credentials, the API validates the user within the correct tenant context, and the system returns the token and user session data needed to access protected routes.

Project SaaS login flow diagram

Login flow: user submits credentials → API validates company and user → JWT/token issued → frontend stores session → protected app access.

Post ticket flow

Ticket creation is designed around reliability. The client sends the new ticket request, the API validates the tenant and payload, stores the ticket in PostgreSQL, writes an outbox event in the same transaction, and then allows the background worker to process notifications or other side effects asynchronously.

Project SaaS post ticket flow diagram

Ticket flow: frontend submits ticket → API validates auth and tenant → database saves ticket + outbox event → worker processes event → notifications created.

Goals of the project

This project was built as a portfolio-grade backend system to demonstrate production-style engineering practices rather than only basic CRUD screens.

  • Demonstrate real-world backend architecture
  • Show multi-tenant system design and tenant isolation
  • Apply SOLID principles in a structured codebase
  • Support resilient workflows with retries and background processing
  • Use the Outbox pattern for reliable event delivery
  • Provide a strong portfolio project for backend-oriented roles

High-level architecture

The platform is split into clear system components so that each part has a focused responsibility and the architecture can grow without becoming tightly coupled.

Frontend
  Next.js / React
  Dashboards and protected application routes

Backend API
  ASP.NET Core Web API
  Authentication, tenancy, users, tickets, companies

Worker
  ASP.NET Core BackgroundService
  Outbox processing, retries, notifications, jobs

Database
  PostgreSQL
  Shared schema with OrganisationId tenant scoping

Communication between the frontend and backend uses REST over HTTP, while real-time notifications are designed around SignalR/WebSockets. Internal background side effects are handled asynchronously through the outbox pipeline.

Core architectural decisions

Multi-tenancy

Every tenant-scoped record contains an OrganisationId. This allows a single shared database schema while still enforcing strong isolation between companies. Tenant identity is derived from authenticated user context and propagated through the request pipeline.

Authentication and roles

The system uses JWT-based authentication and role-based authorisation. Admin users can manage company data, users, and ticket assignment, while regular users operate only within the permissions allowed by their role and tenant scope.

Reliability through Outbox

Ticket writes and domain events are stored atomically in the same database transaction. A background worker later processes unhandled outbox messages and performs side effects such as notification creation and downstream processing. This avoids losing events when a request succeeds but a side effect fails.

Optimistic concurrency

Ticket updates use row-version based optimistic concurrency. This prevents accidental overwrites when multiple users modify the same work item and allows the API to return a proper conflict response instead of silently replacing someone else’s changes.

Project structure

The backend follows a clean, layered structure so that domain logic, infrastructure, contracts, and background processing stay separated.

/Controllers
/Application
/Domain
/Infrastructure
/Contracts
/Common
/Background
/Docs

ProjectSaas.Api
ProjectSaas.Worker (not nunning on the live app)

Main domain model

The system is centred around tenant-scoped entities that support business workflows, reliability, and auditability.

Core entities

C# / Domain
Organisation
User
Ticket
TicketAttachment
Notification
OutboxMessage
IdempotencyKey

Indexes are applied on common query paths such as organisation + status, organisation + assignee, and organisation + created date to keep filtering and listing efficient as tenant data grows.

Ticket lifecycle

The ticket lifecycle is designed to be both safe and reliable. Business writes happen synchronously, while secondary effects are processed asynchronously.

Ticket flow

System
1. User creates or updates a ticket
2. API validates auth, tenant, role, and request rules
3. Ticket is persisted in PostgreSQL
4. Outbox message is written in the same transaction
5. API returns success immediately
6. Worker polls unprocessed outbox messages
7. Worker dispatches event handlers
8. Notifications and other side effects are executed
9. Outbox message is marked as processed

This approach improves availability because ticket creation does not depend on notification delivery or optional downstream services being available in the same request.

API surface

The system exposes a practical set of endpoints covering authentication, companies, users, tickets, and notifications.

Main endpoints

REST
Auth
POST   /api/auth/login
POST   /api/auth/refresh
POST   /api/auth/logout
GET    /api/auth/me

Companies
POST   /api/companies
GET    /api/companies/me
PATCH  /api/companies/me
DELETE /api/companies/me

Users
GET    /api/users
POST   /api/users
GET    /api/users/{userId}
PATCH  /api/users/{userId}
DELETE /api/users/{userId}

Tickets
GET    /api/tickets
POST   /api/tickets
GET    /api/tickets/{ticketId}
PATCH  /api/tickets/{ticketId}
DELETE /api/tickets/{ticketId}
POST   /api/tickets/{ticketId}/assign
POST   /api/tickets/{ticketId}/complete

Notifications
GET    /api/notifications
GET    /api/notifications/unread-count
PATCH  /api/notifications/{notificationId}/read
PATCH  /api/notifications/read-all

Reliability and resilience

Idempotency

Idempotency keys are used on write-sensitive endpoints such as ticket creation, assignment, and completion. This protects the system from duplicate writes caused by retries or repeated client requests.

Retry and failure handling

The worker processes outbox messages in batches and records retry counts and errors for failed events. This makes the asynchronous pipeline more observable and prevents silent data loss.

Graceful degradation

Core ticket operations remain available even if a background side effect fails. This is important in distributed systems where notifications, enrichment, or downstream integrations may become temporarily unavailable.

Example of the design approach

The codebase separates responsibilities so controllers stay thin, services handle business rules, and infrastructure focuses on persistence and external concerns.

Example service responsibilities

Conceptual
Controllers
  HTTP input/output, routing, status codes

Application services
  Business rules, tenant scoping, validation orchestration

Domain
  Core entities and invariants

Infrastructure
  EF Core, persistence, auth plumbing, integrations

Worker
  Outbox polling, retries, event dispatching

Why this project matters

Project SaaS is intentionally designed to show the kind of engineering decisions expected in real backend work: multi-tenant safety, authentication and session management, robust API design, reliable asynchronous processing, and maintainable separation of concerns.

Rather than focusing only on CRUD screens, the project demonstrates how production-oriented backend systems are structured, tested, and evolved over time.

Tech stack

  • ASP.NET Core Web API
  • PostgreSQL
  • Entity Framework Core
  • JWT authentication
  • SignalR for notifications
  • BackgroundService worker
  • Outbox pattern
  • Next.js frontend