Task Manager is a web application designed to help teams organize and manage their projects efficiently. The application provides a structured approach to task management, ensuring that team members have clearly defined roles and responsibilities within each project. At its core, the system allows users to create projects, assign tasks, track progress, and collaborate through comments and file attachments. Access control is a key feature, ensuring that only authorized team members can view or modify project data. The application distinguishes between administrative roles (system-wide) and project-specific roles, enabling flexible permission management.
A built-in notification system informs users about important updates, such as new tasks, status changes, or comments on tasks they are assigned to. The default implementation uses email notifications via Gmail, but the system is designed to be easily extended to other communication platforms
Task Manager also includes cloud-based file storage integration, with Dropbox as the default provider. This allows team members to upload, retrieve, and manage attachments related to specific tasks. The file storage module is built in a way that makes it possible to add new providers or switch to an internal storage system if necessary.
The backend is implemented using Spring Boot, with authentication managed via JWT and Spring Security. Data persistence is handled through MySQL, with schema versioning managed by Liquibase. The application is fully containerized using Docker, and testing is automated with JUnit, Testcontainers, and MailHog.
โ๏ธ User authentication & authorization (JWT, Spring Security)
โ๏ธ Project Management โ Create projects accessible only to team members.
โ๏ธ Task & Project management (CRUD operations, labels, attachments, comments)
โ๏ธAttachments โ Upload and manage file attachments.
โ๏ธ Event-based notification system
- Java 17
- Spring Boot
- Maven as the build system
- MySQL 8 as the database
- Docker โ Includes
Dockerfileanddocker-compose.yml - JUnit, Testcontainers โ Integration and unit testing (running in Docker and MailHog)
- Liquibase โ Database versioning and migration
The project follows a layered architecture to ensure maintainability, scalability, and clean separation of concerns. Below is the complete project structure along with its key components.
config/โ Contains configuration files, including security, object mapping, and external integrations (e.g., Dropbox).controller/โ REST controllers responsible for handling HTTP requests.dto/โ Data Transfer Objects, ensuring a clear separation between API responses and domain models.exception/โ Custom exception handling to manage application errors gracefully.mapper/โ Converts entities to DTOs and vice versa.model/โ JPA entities representing the database structure.repository/โ Spring Data JPA repositories for database access.security/โ Security and authentication layer, including JWT handling and user authentication.service/โ Business logic layer, handling application functionalities such as tasks, projects, and notifications.validator/โ Custom validation classes, e.g., for email validation.
The application implements two levels of authorization:
- Global role-based access control (RBAC) using Spring Security
- Project-specific role management handled by the
MemberService
Each user has one of the following global roles:
ADMINโ Can manage users and edit the global set of labels.USERโ Assigned automatically upon registration. Users can create and manage their own projects.
Each project has a list of members with different levels of access:
-
Manager(automatically assigned to the project creator)- Can add/remove members and managers
- Can create, assign, and manage tasks
- Can add labels
- Can update project settings
-
Member(added by a manager)- Can comment on tasks
- Can complete assigned tasks
- Can attachted and download files
- Can comment task and edit if they are the authors
Project roles are managed by the MemberService, which ensures that only authorized users can perform specific actions within a project.
The authentication mechanism uses:
โ JWT tokens for stateless authentication
โ Spring Security for endpoint protection
All API requests requiring authentication must include a JWT token in the `Authorization
The application provides file attachment management with an integrated cloud storage solution.
Attachments can be stored using different storage providers. By default, the system supports Dropbox, but it is designed to be easily extended with additional storage services or a custom solution.
โ Dropbox Integration (default)
โ Expandable to other APIs or in-house storage systems
FileStorageProviderFactorydynamically provides the correct storage implementation.- Uses a service map approach, where services are registered using
@Component("<PROVIDER_NAME>"). - Example: Dropbox storage is registered as
@Component("DROPBOX").
Since Dropbox API requires OAuth 2.0, the application:
- Uses a refresh token to request a new access token.
- Stores the encrypted access token in the database.
- Automatically renews the token upon expiration.
โ Secure file upload & download
โ Storage provider abstraction for easy extension
โ Encrypted token storage for Dropbox authentication
โ Automatic token refresh on expiration
The notification system ensures that users are informed about important project updates while maintaining flexibility, scalability, and performance.
โ Centralized event handling โ ChangeManager serves as the main communication hub between the application and notification services.
โ Flexible event structure โ ProjectEvent follows the Builder Pattern, allowing easy modification and extension.
โ Asynchronous processing โ Notifications are sent concurrently, improving efficiency.
โ Expandable notification channels โ Designed to integrate additional services (e.g., Slack, WebSockets).
1๏ธโฃ ChangeManager acts as the central notification coordinator, receiving and dispatching project-related events.
2๏ธโฃ ProjectEvent is a dynamic event model based on the Builder Pattern, allowing flexible event definitions. Any project-related event can be constructed dynamically without requiring multiple classes.
3๏ธโฃ Extending ProjectEvent is straightforward โ just add a new field to the class and its constructor. Thanks to Lombok annotations, the builder pattern will automatically include it, simplifying modifications.
4๏ธโฃ Custom event types can be added when necessary โ while ProjectEvent covers most scenarios, separate event classes (e.g., UserRegistrationEvent) can be introduced where needed.
5๏ธโฃ Notifications are processed asynchronously โ The notification service utilizes multi-threading to handle multiple recipients in parallel. Messages are passed through a CompletableFuture pipeline, allowing easy integration of additional notification services.
ows seamless integration with other notification systems such as WebSockets, push notifications, or third-party services like Slack and Microsoft Teams.
ProjectEventโ Represents an event within the system (task updates, attachments, comments, etc.).ChangeManagerโ Manages event processing and dispatches notifications.NotificationServiceโ Sends notifications through various channels.EmailServiceโ Handles email notifications (integrated with Gmail).
By default, notifications are sent via email using Gmail SMTP, but additional notification methods (e.g., Slack, WebSockets, SMS) can be implemented.
โ Uses Spring Mail API
โ Supports email authentication & encryption
โ Easily extendable to other notification services
To enable email notifications, configure the following properties in application.properties:
spring.mail.host=smtp.gmail.com
spring.mail.port=587
spring.mail.username=your-email@gmail.com
spring.mail.password=your-email-password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.connectiontimeout=5000
spring.mail.properties.mail.smtp.timeout=5000
spring.mail.properties.mail.smtp.writetimeout=5000The application includes unit tests, integration tests, and database migration tests using:
โ JUnit 5 โ Unit and integration testing framework
โ Testcontainers โ Runs database and email tests in Docker containers
โ MailHog โ Email testing container
โ Mockito โ Mocking dependencies for unit tests
โ Liquibase โ Database migration verification
| Type | Framework | Purpose |
|---|---|---|
| Unit Tests | JUnit 5, Mockito | Testing individual components (services, validators, mappers) |
| Integration Tests | Testcontainers | Testing interaction with the database and external dependencies |
| Security Tests | Spring Security Test | Ensuring proper authentication & authorization |
| Email Tests | MailHog (Docker) | Testing email notifications |
The integration tests use a temporary MySQL instance managed by Testcontainers, avoiding the need for a real database.
spring.datasource.url=jdbc:tc:mysql:8:///testdb
spring.datasource.username=test
spring.datasource.password=test
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=true
spring.liquibase.change-log=classpath:db.testchangelog/db.changelog-master.yaml
spring.mail.host=localhost
spring.mail.port=1025
spring.mail.username=test
spring.mail.password=testThe application includes a centralized exception handling and logging system to ensure that errors are properly captured, logged, and returned to the client in a structured format.
All exceptions are handled globally in CustomGlobalExceptionHandler, so developers do not need to log errors manually in individual services or controllers.
โ Consistent error responses for API clients.
โ Automatic logging of all exceptions, including validation errors, authentication failures, and external API issues.
โ Separation of concerns, making it easy to extend exception handling without modifying business logic.
This means that whenever an exception occurs, it is automatically loggedโdevelopers donโt need to write explicit logging statements for every error scenario.
The following exceptions are handled centrally:
| Exception Type | HTTP Status | Description |
|---|---|---|
MethodArgumentNotValidException |
400 Bad Request |
Validation errors in API requests. |
RegistrationException |
400 Bad Request |
User registration failure. |
AuthenticationException |
401 Unauthorized |
Failed authentication attempts. |
EntityNotFoundException |
404 Not Found |
Requested resource not found. |
DataProcessingException |
400 Bad Request |
General data processing failure. |
DropBoxProcessingException |
500 Internal Server Error |
Dropbox API processing failure. |
The logging system captures key events and errors in separate logs to facilitate debugging and monitoring.
| Log File | Purpose |
|---|---|
logs/errors.log |
Stores all critical application errors, managed centrally in CustomGlobalExceptionHandler. |
logs/user-registrations.log |
Logs new user registration attempts, both successful and failed. |
logs/app-events.log |
Captures important application events such as project creation, task assignments, and permission changes. |
By maintaining separate log files, the system allows for better monitoring and faster issue resolution.
This approach keeps error management consistent, centralized, and scalable.
Below is a summary of the main API endpoints.
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/authentication/registration |
Register a new user | โ No |
POST |
/authentication/login |
Authenticate and get JWT token | โ No |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
GET |
/users/me |
Get own user profile | โ Yes (USER) |
PUT |
/users/me |
Update own profile | โ Yes (USER) |
GET |
/users/{userId} |
Get user by ID | โ Yes (ADMIN) |
DELETE |
/users/{userId} |
Delete user by ID | โ Yes (ADMIN) |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/projects |
Create a new project | โ Yes (USER) |
GET |
/projects |
Get all of own user's projects | โ Yes (USER) |
GET |
/projects/{id} |
Get a specific project | โ Yes (Member) |
PUT |
/projects/{id} |
Update project details | โ Yes (Manager) |
DELETE |
/projects/{id} |
Delete a project | โ Yes (Manager/Admin) |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/projects/{projectId}/tasks |
Create a new task | โ Yes (Manager) |
GET |
/projects/{projectId}/tasks |
Get all tasks in a project | โ Yes (Member) |
GET |
/projects/{projectId}/tasks/{taskId} |
Get a specific task | โ Yes (Member) |
PUT |
/projects/{projectId}/tasks/{taskId} |
Update a task | โ Yes (Manager) |
DELETE |
/projects/{projectId}/tasks/{taskId} |
Delete a task | โ Yes (Manager) |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/projects/{projectId}/tasks/{taskId}/attachments/{apiName} |
Upload file | โ Yes (Member) |
GET |
/projects/{projectId}/tasks/{taskId}/attachments/{fileId} |
Download file | โ Yes (Member) |
DELETE |
/projects/{projectId}/tasks/{taskId}/attachments/{fileId} |
Delete file | โ Yes (Manager) |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/projects/{projectId}/tasks/{taskId}/comments |
Add comment | โ Yes (Member) |
GET |
/projects/{projectId}/tasks/{taskId}/comments |
Get task comments | โ Yes (Member) |
PUT |
/projects/{projectId}/tasks/{taskId}/comments/{commentId} |
Edit comment | โ Yes (Author) |
DELETE |
/projects/{projectId}/tasks/{taskId}/comments/{commentId} |
Delete comment | โ Yes (Manager/Author) |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/labels |
Create a new label | โ Yes (Admin) |
GET |
/labels |
Get all labels | โ Yes (Admin) |
PUT |
/labels/{labelId} |
Update label | โ Yes (Admin) |
DELETE |
/labels/{labelId} |
Delete label | โ Yes (Admin) |
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
POST |
/projects/{projectId}/members/{userId} |
Add member to project | โ Yes (Manager) |
DELETE |
/projects/{projectId}/members/{userId} |
Remove member | โ Yes (Manager) |
POST |
/projects/{projectId}/members/{userId}/managers |
Promote user to manager | โ Yes (Manager) |
DELETE |
/projects/{projectId}/members/{userId}/managers |
Revoke manager role | โ Yes (Manager) |
All API endpoints require authentication via JWT tokens in the Authorization header: Authorization: Bearer <JWT_TOKEN>
Task Manager is a role-based project and task management system. The system is modular and allows for future extensions, including additional notification channels, integrations with external services, and UI enhancements.
Planned improvements and possible extensions:
1๏ธโฃ Task Dependency Chains โ Ability to link tasks into logical sequences, ensuring that one task cannot start until another is completed.
2๏ธโฃ In-App Notifications โ A notification center within the application for tracking important updates without relying on emails.
3๏ธโฃ Social Media & External Authentication โ Integration with Google, Facebook, and other OAuth providers for faster and easier login.
4๏ธโฃ Project Timeline View โ A visual timeline that helps teams track project progress over time.
5๏ธโฃ Calendar Integration โ Syncing tasks and deadlines with calendar applications like Google Calendar and Outlook.
These features would further enhance collaboration, usability, and efficiency, making the system more adaptable to various team workflows.
Author: Mateusz Seler
๐ง Email: mate.tasks.manager@gmail.com
For any questions, suggestions, or contributions, feel free to reach out! ๐