This project is a secure, role-based task management system built within an NX monorepo. The backend is powered by NestJS and the frontend is an Angular single-page application.
This project utilizes an NX monorepo to manage the frontend and backend code in a single repository. This approach simplifies dependency management and promotes code sharing.
- apps/api: The NestJS backend application. It handles all business logic, database interactions, and authentication.
- apps/dashboard: The Angular frontend application. It provides the user interface for interacting with the task management system.
- libs/data: A shared library containing TypeScript interfaces and Data Transfer Objects (DTOs). This ensures type safety and consistency between the frontend and backend.
- libs/auth: A shared library for reusable authentication and authorization logic, such as JWT guards and role-based access control (RBAC) decorators.
- Node.js (v18 or later)
- npm, pnpm, or yarn
- An NX workspace (
npx create-nx-workspace@latest)
- Navigate to the
apps/apidirectory. - Create a
.envfile by copying.env.example. - Fill in the
JWT_SECRETwith a long, random, and secure string. - Install dependencies from the root of the monorepo:
npm install- Run the backend server:
npx nx serve apiThe API will be available at: http://localhost:3000/api.
- The frontend is part of the same monorepo, so dependencies are already installed.
- Run the Angular development server:
npx nx serve secure-task-manager- Open your browser to:
http://localhost:4200.
The system uses three core entities: Users, Organizations, and Tasks.
- Organization: Represents a top-level entity.
- User: Belongs to one Organization and has one Role (Either an
Adminwho created the Organization or anOwnerwithin the Organization who owns a Task). - Task: Created by a User and is associated with them.
+----------------+ +-------------------+
| Organization |-------| User |
|----------------| |-------------------|
| id (PK) | | id (PK) |
| name | | username |
+----------------+ | password (hash) |
| role |
| organizationId(FK)|
+-------------------+
|
| owns
|
+------------------+
| Task |
|------------------|
| id (PK) |
| title |
| description |
| status |
| category |
| userId (FK) |
+------------------+
Access control is enforced on the backend using a combination of JWT authentication and a custom Roles guard implementation in functions.
- Admin: Can modify and delete
WorkorStudytasks for anyone in their organization. Cannot see or deletePersonaltasks. - Owner: Full control over their tasks within their organization.
- Viewer: Can only view organizations they want to join or create organizations. After joining an organization, they then have
Ownerrights, but after creating an organization, they haveAdminrights.
- The user logs in via the Angular UI, sending credentials to the
/api/auth/loginendpoint. - The NestJS backend validates the credentials and, if successful, returns a JSON Web Token (JWT).
- The Angular app stores this JWT in local storage.
- For every subsequent API request, the JWT is included in the
Authorization: Bearer <token>header.
- The
JwtAuthGuardon the backend validates the token on every protected endpoint. - Instead of a
RolesGuard, I added logic to functions that require role authorizations which is gotten from the payload, enforcing role inheritance (an Admin has all permissions of an Owner). - Service-level logic performs finer-grained checks, such as verifying that a user is trying to modify a task within their own organization.
To see the full API documentation, you can visit the Base URL: /swagger
Base URL: /api
POST /auth/login
Authenticates a user.
Request Body:
{ "username": "...", "password": "..." }Response:
{ "access_token": "..." }Requires Authentication
GET /tasks
Lists tasks accessible to the current user based on their role.
Response: Array<Task>
POST /tasks (Admin, Owner only)
Creates a new task.
Request Body:
{ "title": "...", "description": "...", "category": "..." }Response: Task
GET /tasks (Owner get there own tasks, Admin sees every task in the organization)
Get tasks.
Response:
Response: [Task]
PUT /tasks/:id (Owner, Admin)
Updates a task.
Request Body:
{ "title": "...", "status": "...", ... }Response: Task
DELETE /tasks/:id (Owner only)
Deletes a task.
Response:
{ "deleted": true }GET /audit-log (Admin, Owner only)
Retrieves the system's audit log.
Response: Array<AuditLog>
- Refresh Tokens: Implement JWT refresh tokens for more robust and secure session management.
- Advanced RBAC: Allow for custom roles and permissions to be defined and assigned.
- Scalability: For large organizations, optimize permission checks to avoid numerous database lookups, possibly with a caching layer like Redis or Nginx.
- Security Hardening: Add CSRF protection, rate limiting, and other security best practices for a production environment.
- Feature: Add
invite/joinfeature on the backend forAdmin's to be able to send invites to user emails to create accounts. - Feature: Add an
Adminfeature, where theAdmincan create task for any user under theOrganization. - Feature: With more time, I would have added an
Adminfeature, where theAdmincan see the activities (Audit Log) and progress of everyUserunder theirOrganization.