From d58a66980753c75ef6bd3a0cc8b2c87261eb9f70 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:23:48 +0200 Subject: [PATCH 01/22] docs: `signup` swagger document --- src/docs/swagger.json | 8083 +---------------------------------------- 1 file changed, 54 insertions(+), 8029 deletions(-) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 46c2903..b4a8c31 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -59,14 +59,23 @@ "/api/auth/signup": { "post": { "tags": ["Auth"], - "summary": "Register a new user", - "description": "Creates a new user account and sends verification OTP to email", + "summary": "Creates a new user account and sends verification OTP to email", + "description": "Register a new user with email, password, and personal details. Sends verification OTP to the provided email.", + "operationId": "signup", "requestBody": { + "description": "User registration data", "required": true, "content": { "application/json": { "schema": { "type": "object", + "required": [ + "email", + "password", + "firstName", + "lastName", + "username" + ], "properties": { "email": { "type": "string", @@ -75,8 +84,9 @@ }, "password": { "type": "string", + "format": "password", "minLength": 6, - "example": "password123" + "example": "securePassword123" }, "firstName": { "type": "string", @@ -90,21 +100,14 @@ "type": "string", "example": "johndoe" } - }, - "required": [ - "email", - "password", - "firstName", - "lastName", - "username" - ] + } } } } }, "responses": { "201": { - "description": "User created successfully", + "description": "User created successfully. Verification OTP sent to email.", "content": { "application/json": { "schema": { @@ -116,7 +119,8 @@ }, "userId": { "type": "string", - "format": "uuid" + "format": "uuid", + "example": "123e4567-e89b-12d3-a456-426614174000" }, "user": { "$ref": "#/components/schemas/User" @@ -127,94 +131,23 @@ } }, "400": { - "description": "Validation error or user already exists" - } - } - } - }, - "/api/auth/resendOTP": { - "post": { - "tags": ["Auth"], - "summary": "Resend OTP code", - "description": "Resend OTP code if it expired", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "example": "user@example.com" - } - }, - "required": ["email"] - } - } - } - }, - "responses": { - "200": { - "description": "OTP resent successfully", + "description": "Validation error or user already exists", "content": { "application/json": { "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "example": true - }, "message": { "type": "string", - "example": "Code sent successfully. Please check your email" + "example": "User with this email or username already exists" } } } } } }, - "400": { - "description": "Invalid email" - }, - "404": { - "description": "User not found" - } - } - } - }, - "/api/auth/verifyEmail": { - "post": { - "tags": ["Auth"], - "summary": "Verify email address", - "description": "Verify user's email address using the OTP sent to their email", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "example": "user@example.com" - }, - "otp": { - "type": "string", - "example": "123456" - } - }, - "required": ["email", "otp"] - } - } - } - }, - "responses": { - "200": { - "description": "Email verified successfully", + "429": { + "description": "Too many requests", "content": { "application/json": { "schema": { @@ -222,7964 +155,56 @@ "properties": { "message": { "type": "string", - "example": "Email verified successfully" + "example": "Too many requests, please try again later." } } } } } - }, - "400": { - "description": "Invalid or expired OTP" - }, - "404": { - "description": "User not found" - } - } - } - }, - "/api/auth/signin": { - "post": { - "tags": ["Auth"], - "summary": "Authenticate user", - "description": "Authenticate user and return JWT tokens", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "example": "user@example.com" - }, - "password": { - "type": "string", - "example": "password123" - } - }, - "required": ["email", "password"] - } - } } }, - "responses": { - "200": { - "description": "User logged in successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "User login successfully" - }, - "accessToken": { - "type": "string", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "refreshToken": { - "type": "string", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "email": { - "type": "string" - }, - "name": { - "type": "string" - }, - "role": { - "type": "string", - "enum": ["MEMBER", "ADMIN", "SUPER_ADMIN"] - } - } - } - } - } - } - } + "security": [] + } + } + }, + + "components": { + "schemas": { + "User": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" }, - "400": { - "description": "Validation error" + "email": { + "type": "string", + "format": "email" }, - "401": { - "description": "Invalid credentials" + "username": { + "type": "string" }, - "403": { - "description": "Account not activated" - } - } - } - }, - "/api/auth/forgotPassword": { - "post": { - "tags": ["Auth"], - "summary": "Request password reset", - "description": "Initiate password reset process by sending OTP to user's email", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "example": "user@example.com" - } - }, - "required": ["email"] - } - } - } - }, - "responses": { - "200": { - "description": "Password reset OTP sent", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Password reset OTP sent" - } - } - } - } - } + "firstName": { + "type": "string" }, - "400": { - "description": "Validation error" - } - } - } - }, - "/api/auth/resetPassword": { - "post": { - "tags": ["Auth"], - "summary": "Reset password", - "description": "Reset user password using the OTP received via email", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "example": "user@example.com" - }, - "otp": { - "type": "string", - "example": "123456" - }, - "newPassword": { - "type": "string", - "minLength": 6, - "example": "newpassword123" - } - }, - "required": ["email", "otp", "newPassword"] - } - } - } - }, - "responses": { - "200": { - "description": "Password reset successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Password reset successfully" - } - } - } - } - } + "lastName": { + "type": "string" }, - "400": { - "description": "Invalid or expired OTP" + "role": { + "type": "string", + "enum": ["MEMBER", "ADMIN", "SUPER_ADMIN"], + "default": "MEMBER" }, - "404": { - "description": "User not found" - } - } - } - }, - "/api/auth/forgotPasswordWithoutEmail": { - "post": { - "tags": ["Auth"], - "summary": "Request password reset without email", - "description": "Initiate password reset using refreshToken to identify user", - "responses": { - "200": { - "description": "Password reset OTP sent", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Password reset OTP sent" - } - } - } - } - } + "isActive": { + "type": "boolean", + "default": false }, - "401": { - "description": "No token provided or invalid token" + "createdAt": { + "type": "string", + "format": "date-time" } } } - }, - "/api/auth/resetPasswordWithoutEmail": { - "post": { - "tags": ["Auth"], - "summary": "Reset password without email", - "description": "Reset user password using the OTP received via email (authenticated via refresh token)", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "otp": { - "type": "string", - "example": "123456" - }, - "newPassword": { - "type": "string", - "minLength": 6, - "example": "newpassword123" - } - }, - "required": ["otp", "newPassword"] - } - } - } - }, - "responses": { - "200": { - "description": "Password reset successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Password reset successfully" - } - } - } - } - } - }, - "400": { - "description": "Invalid or expired OTP" - }, - "401": { - "description": "No token provided or invalid token" - }, - "404": { - "description": "User not found" - } - } - } - }, - "/api/auth/refreshAccessToken": { - "post": { - "tags": ["Auth"], - "summary": "Refresh access token", - "description": "Generate new access token using refresh token", - "responses": { - "200": { - "description": "New access token generated", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "accessToken": { - "type": "string", - "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." - } - } - } - } - } - }, - "401": { - "description": "Refresh token missing" - }, - "403": { - "description": "Invalid refresh token" - } - } - } - }, - "/api/auth/firebase": { - "post": { - "tags": ["Auth"], - "summary": "Authenticate with Firebase ID token", - "description": "Authenticates a user using Firebase ID token, creates or updates user in database", - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "idToken": { - "type": "string", - "description": "Firebase ID token from client", - "example": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ij..." - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Authentication successful", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "id": { "type": "string", "format": "uuid" }, - "email": { "type": "string", "format": "email" }, - "username": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "role": { - "type": "string", - "enum": ["MEMBER", "ADMIN"] - }, - "profilePic": { "type": "string", "format": "uri" } - } - }, - "message": { "type": "string" } - }, - "example": { - "user": { - "id": "123e4567-e89b-12d3-a456-426614174000", - "email": "user@example.com", - "username": "user123", - "firstName": "John", - "lastName": "Doe", - "role": "MEMBER", - "profilePic": "https://example.com/profile.jpg" - }, - "message": "Authentication successful" - } - } - } - } - }, - "400": { - "description": "Missing or invalid ID token" - }, - "401": { - "description": "Invalid or expired Firebase token" - }, - "500": { - "description": "Internal server error" - } - } - } - }, - "/me": { - "get": { - "tags": ["User"], - "summary": "Get current user profile", - "description": "Returns the profile of the currently authenticated user", - "security": [ - { - "bearerAuth": [] - } - ], - "responses": { - "200": { - "description": "User profile retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/User" - } - } - } - }, - "401": { - "description": "Unauthorized - Missing or invalid token" - }, - "404": { - "description": "User not found in database" - } - } - } - }, - "/api/auth/logout": { - "post": { - "tags": ["Auth"], - "summary": "Log out user", - "description": "Log out user by invalidating their refresh token", - "responses": { - "200": { - "description": "Logged out successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Logged out successfully" - } - } - } - } - } - }, - "204": { - "description": "No content (no token provided)" - } - } - } - }, - "/api/organizations/{organizationId}/departments/all": { - "get": { - "tags": ["Department"], - "summary": "Get all active departments (paginated) for an organization", - "description": "Returns a paginated list of all active departments in the specified organization. Accessible by organization owners and admins only.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "default": 1 - }, - "description": "Page number for pagination" - } - ], - "responses": { - "200": { - "description": "Departments retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" }, - "data": { - "type": "object", - "properties": { - "departments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "description": { "type": "string" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "manager": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" } - } - } - } - } - }, - "pagination": { - "type": "object", - "properties": { - "page": { "type": "integer" }, - "limit": { "type": "integer" }, - "totalItems": { "type": "integer" }, - "totalPages": { "type": "integer" } - } - } - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions" - }, - "404": { - "description": "Organization not found" - } - }, - "security": [{ "bearerAuth": [] }] - } - }, - "/api/organizations/{organizationId}/departments/{departmentId}": { - "get": { - "tags": ["Department"], - "summary": "Get department by ID with related data", - "description": "Returns department details including users and teams. Accessible by organization owners, admins, or the department manager.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - }, - { - "name": "departmentId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the department" - } - ], - "responses": { - "200": { - "description": "Department retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" }, - "data": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "description": { "type": "string" }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "manager": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "jobTitle": { "type": "string" } - } - }, - "users": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "jobTitle": { "type": "string" } - } - } - }, - "teams": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "description": { "type": "string" } - } - } - } - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions" - }, - "404": { - "description": "Department not found" - } - }, - "security": [{ "bearerAuth": [] }] - }, - "put": { - "tags": ["Department"], - "summary": "Update department details", - "description": "Updates department information. Accessible by organization owners and admins only.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - }, - { - "name": "departmentId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the department to update" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "description": { "type": "string" } - }, - "required": ["name"] - } - } - } - }, - "responses": { - "200": { - "description": "Department updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" }, - "data": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "description": { "type": "string" }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "manager": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" } - } - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - invalid input data" - }, - "403": { - "description": "Forbidden - insufficient permissions" - }, - "404": { - "description": "Department not found" - }, - "409": { - "description": "Conflict - department name already exists" - } - }, - "security": [{ "bearerAuth": [] }] - } - }, - "/api/organizations/{organizationId}/departments/created": { - "get": { - "tags": ["Department"], - "summary": "Get departments managed by current user", - "description": "Returns a paginated list of departments managed by the current user in the specified organization.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "default": 1 - }, - "description": "Page number for pagination" - }, - { - "name": "limit", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "default": 10 - }, - "description": "Number of items per page" - } - ], - "responses": { - "200": { - "description": "Managed departments retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" }, - "data": { - "type": "object", - "properties": { - "departments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "description": { "type": "string" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "_count": { - "type": "object", - "properties": { - "users": { "type": "integer" }, - "teams": { "type": "integer" } - } - } - } - } - }, - "pagination": { - "type": "object", - "properties": { - "page": { "type": "integer" }, - "limit": { "type": "integer" }, - "totalItems": { "type": "integer" }, - "totalPages": { "type": "integer" } - } - } - } - } - } - } - } - } - }, - "404": { - "description": "Organization not found" - } - }, - "security": [{ "bearerAuth": [] }] - } - }, - "/api/organizations/{organizationId}/departments/create": { - "post": { - "tags": ["Department"], - "summary": "Create a new department", - "description": "Creates a new department in the specified organization. Accessible by organization owners and admins only.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "name": { "type": "string" }, - "description": { "type": "string" } - }, - "required": ["name"] - } - } - } - }, - "responses": { - "201": { - "description": "Department created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" }, - "data": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "description": { "type": "string" }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "manager": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" } - } - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - invalid input data" - }, - "403": { - "description": "Forbidden - insufficient permissions" - }, - "404": { - "description": "Organization not found" - }, - "409": { - "description": "Conflict - department name already exists" - } - }, - "security": [{ "bearerAuth": [] }] - } - }, - "/api/organizations/{organizationId}/departments/{departmentId}/delete": { - "delete": { - "tags": ["Department"], - "summary": "Soft delete a department", - "description": "Marks a department as deleted by setting its deletedAt field. Accessible by organization owners and admins only.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - }, - { - "name": "departmentId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the department to delete" - } - ], - "responses": { - "200": { - "description": "Department deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" } - } - } - } - } - }, - "400": { - "description": "Bad request - department already deleted" - }, - "403": { - "description": "Forbidden - insufficient permissions" - }, - "404": { - "description": "Department not found" - } - }, - "security": [{ "bearerAuth": [] }] - } - }, - "/api/organizations/{organizationId}/departments/{departmentId}/restore": { - "patch": { - "tags": ["Department"], - "summary": "Restore a soft-deleted department", - "description": "Restores a previously deleted department by setting its deletedAt field to null. Accessible by organization owners and admins only.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the organization" - }, - { - "name": "departmentId", - "in": "path", - "required": true, - "schema": { - "type": "string" - }, - "description": "ID of the department to restore" - } - ], - "responses": { - "200": { - "description": "Department restored successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean" }, - "message": { "type": "string" } - } - } - } - } - }, - "400": { - "description": "Bad request - department not deleted" - }, - "403": { - "description": "Forbidden - insufficient permissions" - }, - "404": { - "description": "Department not found" - } - }, - "security": [{ "bearerAuth": [] }] - } - }, - "/api/organization": { - "post": { - "tags": ["Organization"], - "summary": "Create a new organization with the current user as owner", - "description": "Creates a new organization. If created by admin, organization is automatically approved. Otherwise, it requires email verification.", - "security": [{ "bearerAuth": [] }], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["name", "contactEmail"], - "properties": { - "name": { - "type": "string", - "description": "Organization name", - "example": "Acme Inc" - }, - "description": { - "type": "string", - "description": "Organization description", - "example": "A leading tech company" - }, - "industry": { - "type": "string", - "description": "Industry sector", - "example": "Technology" - }, - "sizeRange": { - "type": "string", - "description": "Size range of the organization", - "example": "51-200" - }, - "website": { - "type": "string", - "description": "Organization website URL", - "example": "https://acme.com" - }, - "logoUrl": { - "type": "string", - "description": "URL to organization logo", - "example": "https://acme.com/logo.png" - }, - "address": { - "type": "string", - "description": "Physical address", - "example": "123 Main St, City, Country" - }, - "contactEmail": { - "type": "string", - "format": "email", - "description": "Contact email for the organization", - "example": "contact@acme.com" - }, - "contactPhone": { - "type": "string", - "description": "Contact phone number", - "example": "+1234567890" - }, - "orgOwnerId": { - "type": "string", - "description": "Optional user ID to assign as owner (admin only)", - "example": "cl1234567890" - } - } - } - } - } - }, - "responses": { - "201": { - "description": "Organization created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Organization created successfully. Please verify your org" - }, - "data": { - "type": "object", - "properties": { - "organization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "cl1234567890" - }, - "name": { - "type": "string", - "example": "Acme Inc" - }, - "status": { - "type": "string", - "example": "PENDING" - }, - "isVerified": { - "type": "boolean", - "example": false - } - } - }, - "organizationOwner": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "cl1234567891" - } - } - } - } - } - } - } - } - } - }, - "400": { - "description": "Validation error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "error": { - "type": "string", - "example": "\"name\" is required" - } - } - } - } - } - }, - "409": { - "description": "Organization with this name or email already exists", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization with this name or email already exists" - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "error": { - "type": "object" - }, - "message": { - "type": "string", - "example": "Failed to send verification email. Please try again later." - } - } - } - } - } - } - } - } - }, - "/api/organization/resendOTP/{orgId}": { - "post": { - "tags": ["Organization"], - "summary": "Resend OTP code for organization verification", - "description": "Resends the verification OTP to the organization's contact email if the previous one expired", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "name": "orgId", - "in": "path", - "required": true, - "description": "ID of the organization to resend OTP for", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OTP resent successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Code sent successfully. Please check your email" - } - } - } - } - } - }, - "400": { - "description": "Missing organization ID", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Organization ID is required" - } - } - } - } - } - }, - "404": { - "description": "Organization not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Organization not found" - } - } - } - } - } - }, - "500": { - "description": "Failed to send verification email", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "error": { - "type": "object" - }, - "message": { - "type": "string", - "example": "Failed to send verification email. Please try again later." - } - } - } - } - } - } - } - } - }, - "/api/organization/verifyOrg/{orgId}": { - "post": { - "tags": ["Organization"], - "summary": "Verify organization's contact email using OTP", - "description": "Verifies the organization's email address using the OTP sent to the contact email", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "name": "orgId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["otp"], - "properties": { - "otp": { - "type": "string", - "description": "The OTP code received via email", - "example": "123456" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Organization verified successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization verified successfully" - } - } - } - } - } - }, - "400": { - "description": "Invalid or expired OTP", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Invalid or expired OTP" - } - } - } - } - } - }, - "404": { - "$ref": "#/components/responses/OrganizationNotFound" - } - } - } - }, - "/api/organization/all": { - "get": { - "tags": ["Organization"], - "summary": "Get paginated list of organizations with filtering and sorting", - "description": "Returns a paginated list of organizations. Admins see all organizations, others see only organizations they are associated with.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "name": "page", - "in": "query", - "description": "Page number", - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "Items per page", - "schema": { - "type": "integer", - "default": 10 - } - }, - { - "name": "sortBy", - "in": "query", - "description": "Field to sort by", - "schema": { - "type": "string", - "default": "createdAt", - "enum": ["name", "createdAt", "updatedAt", "status"] - } - }, - { - "name": "sortOrder", - "in": "query", - "description": "Sort order", - "schema": { - "type": "string", - "default": "desc", - "enum": ["asc", "desc"] - } - }, - { - "name": "name", - "in": "query", - "description": "Filter by organization name (contains)", - "schema": { - "type": "string" - } - }, - { - "name": "industry", - "in": "query", - "description": "Filter by industry", - "schema": { - "type": "string" - } - }, - { - "name": "sizeRange", - "in": "query", - "description": "Filter by size range", - "schema": { - "type": "string" - } - }, - { - "name": "status", - "in": "query", - "description": "Filter by status", - "schema": { - "type": "string" - } - }, - { - "name": "isVerified", - "in": "query", - "description": "Filter by verification status", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "Organizations retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PaginatedOrganizations" - } - } - } - } - } - } - }, - "/api/organization/{organizationId}": { - "get": { - "tags": ["Organization"], - "summary": "Get detailed information about a specific organization", - "description": "Returns detailed information about an organization including owners, departments, teams and projects. Requires admin or membership access.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "$ref": "#/components/parameters/organizationId" - } - ], - "responses": { - "200": { - "description": "Organization details retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrganizationDetails" - } - } - } - }, - "400": { - "$ref": "#/components/responses/MissingOrgId" - }, - "403": { - "description": "Forbidden - No permission to view this organization", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to view this organization" - } - } - } - } - } - }, - "404": { - "$ref": "#/components/responses/OrganizationNotFound" - } - } - }, - "put": { - "tags": ["Organization"], - "summary": "Update organization details", - "description": "Updates organization information. Admins can update all fields, owners can update most fields except verification status.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "$ref": "#/components/parameters/organizationId" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateOrganization" - } - } - } - }, - "responses": { - "200": { - "description": "Organization updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Organization updated successfully" - }, - "data": { - "type": "object", - "properties": { - "id": { - "type": "string", - "example": "cl1234567890" - }, - "name": { - "type": "string", - "example": "Acme Inc" - }, - "description": { - "type": "string", - "example": "A leading tech company" - } - } - } - } - } - } - } - }, - "400": { - "$ref": "#/components/responses/ValidationError" - }, - "403": { - "description": "Forbidden - No permission to update this organization", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to update this organization" - } - } - } - } - } - }, - "404": { - "$ref": "#/components/responses/OrganizationNotFound" - }, - "409": { - "description": "Conflict - Organization name already exists", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Organization with this name already exists" - } - } - } - } - } - } - } - }, - "delete": { - "tags": ["Organization"], - "summary": "Soft delete an organization", - "description": "Marks an organization as deleted (soft delete). Requires admin or owner permissions.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "$ref": "#/components/parameters/organizationId" - } - ], - "responses": { - "200": { - "description": "Organization deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Organization deleted successfully" - } - } - } - } - } - }, - "400": { - "$ref": "#/components/responses/MissingOrgId" - }, - "403": { - "description": "Forbidden - No permission to delete this organization", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to delete this organization" - } - } - } - } - } - }, - "404": { - "description": "Organization not found or already deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Organization not found or already deleted" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/addOwner": { - "post": { - "tags": ["Organization"], - "summary": "Add one or more users as owners to an organization", - "description": "Adds users as owners to the organization. Requires admin or existing owner permissions.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "$ref": "#/components/parameters/organizationId" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["userIds"], - "properties": { - "userIds": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Array of user IDs to add as owners", - "example": ["cl1234567890", "cl0987654321"] - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Owners added successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddOwnersResponse" - } - } - } - }, - "400": { - "description": "Validation error or invalid user IDs", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "One or more specified users do not exist" - }, - "errors": { - "type": "object", - "properties": { - "invalidUserIds": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - No permission to add owners", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to add new owners to this organization" - } - } - } - } - } - }, - "404": { - "$ref": "#/components/responses/OrganizationNotFound" - } - } - } - }, - "/api/organization/{organizationId}/logo/upload": { - "post": { - "tags": ["Organization"], - "summary": "Upload organization logo", - "description": "Uploads a logo image for the organization. Requires admin or owner permissions.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "$ref": "#/components/parameters/organizationId" - } - ], - "requestBody": { - "required": true, - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "image": { - "type": "string", - "format": "binary", - "description": "Logo image file" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Logo uploaded successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization logo uploaded successfully" - }, - "logoUrl": { - "type": "string", - "example": "https://cloudinary.com/logo123.jpg" - } - } - } - } - } - }, - "400": { - "description": "No file uploaded or invalid organization ID", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "No file uploaded" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - No permission to upload logo", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to modify this organization" - } - } - } - } - } - }, - "404": { - "$ref": "#/components/responses/OrganizationNotFound" - } - } - } - }, - "/api/organization/{organizationId}/logo/delete": { - "delete": { - "tags": ["Organization"], - "summary": "Delete organization logo", - "description": "Deletes the organization's logo. Requires admin or owner permissions.", - "security": [{ "bearerAuth": [] }], - "parameters": [ - { - "$ref": "#/components/parameters/organizationId" - } - ], - "responses": { - "200": { - "description": "Logo deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization logo deleted successfully" - } - } - } - } - } - }, - "400": { - "$ref": "#/components/responses/MissingOrgId" - }, - "403": { - "description": "Forbidden - No permission to delete logo", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to modify this organization" - } - } - } - } - } - }, - "404": { - "description": "Logo not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization logo not found" - } - } - } - } - } - } - } - } - }, - "/api/users/all": { - "get": { - "tags": ["User"], - "summary": "Get all users with pagination", - "description": "Retrieves a paginated list of all users. Admin access required.", - "parameters": [ - { - "name": "page", - "in": "query", - "description": "Page number", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - } - ], - "responses": { - "200": { - "description": "Users retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Users retrieved successfully" - }, - "currentPage": { - "type": "integer", - "example": 1 - }, - "totalPages": { - "type": "integer", - "example": 5 - }, - "totalUsers": { - "type": "integer", - "example": 50 - }, - "users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBasic" - } - } - } - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin access required" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/users/{id}": { - "get": { - "tags": ["User"], - "summary": "Get full user profile by ID", - "description": "Retrieves detailed information about a specific user. User or Admin access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "User retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "User retrieved successfully" - }, - "user": { - "$ref": "#/components/schemas/UserFull" - } - } - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Access denied" - }, - "404": { - "description": "User not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - }, - "put": { - "tags": ["User"], - "summary": "Update user account", - "description": "Updates user account information. User or Admin access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateUserAccount" - } - } - } - }, - "responses": { - "200": { - "description": "User account updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "User account updated successfully" - }, - "user": { - "$ref": "#/components/schemas/UserBasic" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Invalid input data" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Account is not active" - }, - "404": { - "description": "User not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - }, - "delete": { - "tags": ["User"], - "summary": "Soft delete a user", - "description": "Marks a user as deleted (soft delete). Admin access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "User deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "User deleted successfully" - } - } - } - } - } - }, - "400": { - "description": "Bad request - User already deleted" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin access required" - }, - "404": { - "description": "User not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/users/update-password/{id}": { - "patch": { - "tags": ["User"], - "summary": "Update user password", - "description": "Updates the password for a user. User access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePassword" - } - } - } - }, - "responses": { - "200": { - "description": "Password updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Password updated successfully" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Invalid input or same as old password" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - User access required" - }, - "404": { - "description": "User not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/users/restore/{id}": { - "patch": { - "tags": ["User"], - "summary": "Restore a soft-deleted user", - "description": "Restores a previously soft-deleted user. Admin access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "User restored successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "User restored successfully" - } - } - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin access required" - }, - "404": { - "description": "User not found or not deleted" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/users/{id}/profile-picture": { - "post": { - "tags": ["User"], - "summary": "Upload a profile picture for a user", - "description": "Uploads and sets a profile picture for a user. User or Admin access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "image": { - "type": "string", - "format": "binary", - "description": "Image file to upload" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Profile picture uploaded successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Profile picture uploaded successfully" - }, - "profilePicUrl": { - "type": "string", - "example": "https://cloudinary.com/image.jpg" - }, - "user": { - "$ref": "#/components/schemas/UserBasic" - } - } - } - } - } - }, - "400": { - "description": "Bad request - No file uploaded" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Access denied" - }, - "404": { - "description": "User not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - }, - "delete": { - "tags": ["User"], - "summary": "Delete user profile picture", - "description": "Deletes the profile picture of a user. User or Admin access required.", - "parameters": [ - { - "name": "id", - "in": "path", - "description": "User ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Profile picture deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Profile picture deleted successfully" - }, - "user": { - "$ref": "#/components/schemas/UserBasic" - } - } - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Access denied" - }, - "404": { - "description": "Profile picture not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team": { - "post": { - "tags": ["Team"], - "summary": "Create a new team in a specific organization", - "description": "Creates a new team within an organization. Admin or organization owner access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTeam" - } - } - } - }, - "responses": { - "201": { - "description": "Team created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamCreatedResponse" - } - } - } - }, - "400": { - "description": "Bad request - Invalid input" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin or organization owner access required" - }, - "404": { - "description": "Organization not found" - }, - "409": { - "description": "Conflict - Team with this name already exists" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/addMember": { - "post": { - "tags": ["Team"], - "summary": "Add new team members", - "description": "Adds one or more members to an existing team. Admin or organization owner access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddTeamMembers" - } - } - } - }, - "responses": { - "200": { - "description": "Members added successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamMembersResponse" - } - } - } - }, - "400": { - "description": "Bad request - Invalid input" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin or organization owner access required" - }, - "404": { - "description": "Organization or team not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}": { - "put": { - "tags": ["Team"], - "summary": "Update a team", - "description": "Updates team information. Admin or organization owner access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTeam" - } - } - } - }, - "responses": { - "200": { - "description": "Team updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamBasic" - } - } - } - }, - "400": { - "description": "Bad request - Invalid input" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin or organization owner access required" - }, - "404": { - "description": "Organization or team not found" - }, - "409": { - "description": "Conflict - Team with this name already exists" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - }, - "delete": { - "tags": ["Team"], - "summary": "Delete team", - "description": "Soft deletes a team. Admin, organization owner or team creator access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Team deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Team deleted successfully" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Invalid input" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin, organization owner or team creator access required" - }, - "404": { - "description": "Organization or team not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/avatar/upload": { - "post": { - "tags": ["Team"], - "summary": "Upload team avatar", - "description": "Uploads an avatar image for a team. Admin or organization owner access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "image": { - "type": "string", - "format": "binary", - "description": "Image file to upload" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Team avatar uploaded successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Team avatar uploaded successfully" - }, - "team": { - "$ref": "#/components/schemas/TeamBasic" - } - } - } - } - } - }, - "400": { - "description": "Bad request - No file uploaded" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin or organization owner access required" - }, - "404": { - "description": "Organization or team not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/avatar/delete": { - "delete": { - "tags": ["Team"], - "summary": "Delete team avatar", - "description": "Deletes a team's avatar. Admin or organization owner access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Team avatar deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Team avatar deleted successfully" - }, - "team": { - "$ref": "#/components/schemas/TeamBasic" - } - } - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin or organization owner access required" - }, - "404": { - "description": "Organization, team or avatar not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/members/{memberId}": { - "delete": { - "tags": ["Team"], - "summary": "Remove member from a team", - "description": "Removes a member from a team (soft delete). Admin, organization owner or team creator access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "memberId", - "in": "path", - "description": "Team member ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Team member removed successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Team member John Doe removed successfully" - }, - "data": { - "type": "object", - "properties": { - "removedMember": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "name": { - "type": "string" - }, - "removedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - } - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - Cannot remove the only team leader" - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin, organization owner or team creator access required" - }, - "404": { - "description": "Organization, team or member not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/teams/all": { - "get": { - "tags": ["Team"], - "summary": "Get all teams", - "description": "Retrieves all teams in an organization with pagination. Admin or organization owner access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "page", - "in": "query", - "description": "Page number", - "required": false, - "schema": { - "type": "integer", - "default": 1 - } - }, - { - "name": "limit", - "in": "query", - "description": "Items per page", - "required": false, - "schema": { - "type": "integer", - "default": 10 - } - }, - { - "name": "search", - "in": "query", - "description": "Search term for team name", - "required": false, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Teams retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamsPaginatedResponse" - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin or organization owner access required" - }, - "404": { - "description": "Organization not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/teams/{teamId}": { - "get": { - "tags": ["Team"], - "summary": "Get specific team details", - "description": "Retrieves detailed information about a specific team. Admin, organization owner or team member access required.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Team details retrieved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeamFullResponse" - } - } - } - }, - "401": { - "description": "Unauthorized" - }, - "403": { - "description": "Forbidden - Admin, organization owner or team member access required" - }, - "404": { - "description": "Organization or team not found" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project": { - "post": { - "tags": ["Project"], - "summary": "Create a new project", - "description": "Creates a new project within a team. Requires appropriate permissions.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateProject" - } - } - } - }, - "responses": { - "201": { - "description": "Project created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProjectCreatedResponse" - } - } - } - }, - "400": { - "description": "Bad request - Invalid input or validation error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Validation failed" - }, - "errors": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions" - }, - "404": { - "description": "Not found - Organization or team not found" - }, - "409": { - "description": "Conflict - Project with this name already exists" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}": { - "put": { - "tags": ["Project"], - "summary": "Update a project", - "description": "Updates an existing project. Requires appropriate permissions (admin, organization owner, team manager, or project owner).", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateProject" - } - } - } - }, - "responses": { - "200": { - "description": "Project updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProjectUpdatedResponse" - } - } - } - }, - "400": { - "description": "Bad request - Invalid input or validation error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Validation failed" - }, - "errors": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions" - }, - "404": { - "description": "Not found - Organization, team or project not found" - }, - "409": { - "description": "Conflict - Project with this name already exists" - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/status": { - "patch": { - "tags": ["Project"], - "summary": "Update project status", - "description": "Updates the status of an existing project. Requires appropriate permissions (admin, organization owner, team manager, or project owner/manager).", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["status"], - "properties": { - "status": { - "type": "string", - "description": "New project status", - "enum": [ - "PLANNING", - "ACTIVE", - "ON_HOLD", - "COMPLETED", - "CANCELED" - ], - "example": "ACTIVE" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Project status updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Project status updated successfully" - }, - "data": { - "$ref": "#/components/schemas/ProjectBasic" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Invalid status or missing status field", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Status is required or must be one of: PLANNING, ACTIVE, ON_HOLD, COMPLETED, CANCELED" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to update this project's status" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team or project not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Project not found" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/priority": { - "patch": { - "tags": ["Project"], - "summary": "Update project priority", - "description": "Updates the priority of an existing project. Requires appropriate permissions (admin, organization owner, team manager, or project owner/manager).", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["priority"], - "properties": { - "priority": { - "type": "string", - "description": "New project priority", - "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"], - "example": "HIGH" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Project priority updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Project priority updated successfully" - }, - "data": { - "$ref": "#/components/schemas/ProjectBasic" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Invalid priority or missing priority field", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "You do not have permission to update this project's priority" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team or project not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Project not found" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/delete": { - "delete": { - "tags": ["Project"], - "summary": "Delete a project", - "description": "Soft deletes a project. Requires admin, organization owner, or team manager permissions.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Project deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Project deleted successfully" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Missing or invalid parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization ID is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "You don't have permission to delete projects from this team" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team or project not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/addMember": { - "post": { - "tags": ["Project"], - "summary": "Add members to a project", - "description": "Adds one or more members to an existing project. Requires admin, organization owner, or team manager permissions.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["members"], - "properties": { - "members": { - "type": "array", - "description": "Array of members to add", - "minItems": 1, - "items": { - "type": "object", - "required": ["userId"], - "properties": { - "userId": { - "type": "string", - "description": "ID of the user to add" - }, - "role": { - "type": "string", - "description": "Role to assign to the member", - "enum": [ - "MEMBER", - "CONTRIBUTOR", - "REVIEWER", - "MANAGER" - ], - "default": "MEMBER" - } - } - } - } - } - } - } - } - }, - "responses": { - "201": { - "description": "Members added successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Successfully added 3 members to the project" - }, - "data": { - "type": "object", - "properties": { - "count": { - "type": "integer", - "description": "Number of members added", - "example": 3 - }, - "skipped": { - "type": "integer", - "description": "Number of users already members", - "example": 1 - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - Invalid input", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "You don't have permission to add members to this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team, project or some users not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - }, - "userIds": { - "type": "array", - "items": { - "type": "string" - }, - "description": "IDs of users that were not found", - "example": ["user123", "user456"] - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/removeMember": { - "delete": { - "tags": ["Project"], - "summary": "Remove a member from a project", - "description": "Removes a member from a project (soft delete). Requires admin, organization owner, or team manager permissions.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["userId"], - "properties": { - "userId": { - "type": "string", - "description": "ID of the user to remove from the project" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Member removed successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Member removed from project successfully" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Missing or invalid parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "User ID is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "You don't have permission to remove members from this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team, project or user not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/restore": { - "patch": { - "tags": ["Project"], - "summary": "Restore a deleted project", - "description": "Restores a previously soft-deleted project. Requires admin, organization owner, or team manager permissions.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Project restored successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Project restored successfully" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Missing or invalid parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization ID is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "You don't have permission to restore projects" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team or project not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/all": { - "get": { - "tags": ["Project"], - "summary": "Get all projects for a team", - "description": "Retrieves all projects for a specific team. Regular users only see projects they're members of, while admins/owners/managers see all projects.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Projects retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProjectWithMemberCount" - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - Missing or invalid parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization ID is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - Insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "You don't have permission to view these projects" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization or team not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Organization or team not found" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/": { - "get": { - "tags": ["Project"], - "summary": "Get a specific project with details", - "description": "Retrieves detailed information about a specific project including members and tasks. Users must be project members or have team permissions to view.", - "parameters": [ - { - "name": "organizationId", - "in": "path", - "description": "Organization ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "description": "Team ID", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "description": "Project ID", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "Project details retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "data": { - "$ref": "#/components/schemas/ProjectDetails" - } - } - } - } - } - }, - "400": { - "description": "Bad request - Missing or invalid parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Project ID is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - User doesn't have permission to view this project", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "You do not have permission to view this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - Organization, team or project not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "example": "Project not found" - } - } - } - } - } - } - }, - "security": [ - { - "bearerAuth": [] - } - ] - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/create": { - "post": { - "tags": ["Task"], - "summary": "Create a new task", - "description": "Create a new task in a specific project within a team and organization.", - "operationId": "createTask", - "security": [ - { - "bearerAuth": [] - } - ], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["title", "priority", "dueDate"], - "properties": { - "title": { - "type": "string", - "example": "Design login page" - }, - "description": { - "type": "string", - "example": "Create a modern and user-friendly login page UI" - }, - "priority": { - "type": "string", - "example": "HIGH" - }, - "sprintId": { - "type": "string", - "example": "sprint_456" - }, - "assignedTo": { - "type": "string", - "example": "user_123" - }, - "dueDate": { - "type": "string", - "format": "date", - "example": "2025-04-30" - }, - "estimatedTime": { - "type": "integer", - "example": 8 - }, - "parentId": { - "type": "string", - "example": "parent_task_789" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "example": ["frontend", "urgent"] - } - } - } - } - } - }, - "responses": { - "201": { - "description": "Task created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Task created successfully" - }, - "task": { - "$ref": "#/components/schemas/Task" - }, - "project_members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProjectMember" - } - } - } - } - } - } - }, - "400": { - "description": "Bad request" - }, - "403": { - "description": "Forbidden" - }, - "404": { - "description": "Not Found" - }, - "500": { - "description": "Internal Server Error" - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}": { - "put": { - "tags": ["Task"], - "summary": "Update a task", - "description": "Updates an existing task within a specific project, team, and organization. Requires appropriate permissions.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "path", - "required": true, - "description": "ID of the task to update", - "schema": { "type": "string" } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "Updated title of the task", - "example": "Updated: Implement user authentication" - }, - "description": { - "type": "string", - "description": "Updated description of the task", - "example": "Updated: Implement JWT based authentication for the API" - }, - "priority": { - "type": "string", - "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"], - "description": "Updated priority level of the task", - "example": "MEDIUM" - }, - "sprintId": { - "type": "string", - "description": "Updated ID of the sprint this task belongs to", - "example": "cln3k7vxp0000v2k0q2q3k4k5" - }, - "assignedTo": { - "type": "string", - "description": "Updated ID of the user this task is assigned to", - "example": "cln3k7vxp0000v2k0q2q3k4k5" - }, - "dueDate": { - "type": "string", - "format": "date-time", - "description": "Updated due date for the task", - "example": "2024-01-15T23:59:59Z" - }, - "estimatedTime": { - "type": "number", - "description": "Updated estimated time to complete the task in hours", - "example": 12 - }, - "parentId": { - "type": "string", - "description": "Updated ID of the parent task if this is a subtask", - "example": "cln3k7vxp0000v2k0q2q3k4k5" - }, - "labels": { - "type": "array", - "items": { "type": "string" }, - "description": "Updated array of labels for the task", - "example": ["backend", "authentication", "security"] - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Task updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "message": { - "type": "string", - "example": "Task updated successfully" - }, - "task": { "$ref": "#/components/schemas/Task" } - } - } - } - } - }, - "400": { - "description": "Validation error or circular dependency detected", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "\"priority\" must be one of [LOW, MEDIUM, HIGH, CRITICAL]" - }, - { - "type": "string", - "example": "A task cannot be its own parent" - }, - { - "type": "string", - "example": "Circular dependency detected in task hierarchy" - } - ] - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "You don't have permission to update tasks in this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team, project, task, sprint or parent task not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { - "type": "string", - "example": "Task not found or does not belong to the specified project" - }, - { - "type": "string", - "example": "Sprint not found or does not belong to the specified project" - }, - { - "type": "string", - "example": "Parent task not found or does not belong to the specified project" - } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/priority": { - "patch": { - "tags": ["Task"], - "summary": "Update task priority", - "description": "Updates the priority of an existing task within a specific project, team, and organization. Requires appropriate permissions.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "path", - "required": true, - "description": "ID of the task to update", - "schema": { "type": "string" } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["priority"], - "properties": { - "priority": { - "type": "string", - "enum": ["HIGH", "MEDIUM", "LOW"], - "description": "New priority level for the task", - "example": "MEDIUM" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Task priority updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "message": { - "type": "string", - "example": "Task priority updated successfully" - }, - "task": { "$ref": "#/components/schemas/Task" } - } - } - } - } - }, - "400": { - "description": "Invalid priority value", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Valid priority (HIGH, MEDIUM, LOW) is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "You don't have permission to update task priorities in this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team, project or task not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { "type": "string", "example": "Team not found" }, - { "type": "string", "example": "Project not found" }, - { - "type": "string", - "example": "Task not found or does not belong to the specified project" - } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/status": { - "patch": { - "tags": ["Task"], - "summary": "Update task status", - "description": "Updates the status of an existing task within a specific project, team, and organization. Requires appropriate permissions.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "path", - "required": true, - "description": "ID of the task to update", - "schema": { "type": "string" } - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "type": "object", - "required": ["status"], - "properties": { - "status": { - "type": "string", - "enum": ["TODO", "IN_PROGRESS", "IN_REVIEW", "DONE"], - "description": "New status for the task", - "example": "IN_PROGRESS" - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Task status updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "message": { - "type": "string", - "example": "Task status updated successfully" - }, - "task": { "$ref": "#/components/schemas/Task" } - } - } - } - } - }, - "400": { - "description": "Invalid status value", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Valid status (TODO, IN_PROGRESS, IN_REVIEW, DONE) is required" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "You don't have permission to update task status in this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team, project or task not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { "type": "string", "example": "Team not found" }, - { "type": "string", "example": "Project not found" }, - { - "type": "string", - "example": "Task not found or does not belong to the specified project" - } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/all": { - "get": { - "tags": ["Task"], - "summary": "Get all tasks", - "description": "Retrieves all tasks for a specific project with filtering, sorting, and pagination capabilities.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "sprintId", - "in": "query", - "description": "Filter by sprint ID (use 'null' for tasks not in any sprint)", - "schema": { "type": "string" } - }, - { - "name": "priority", - "in": "query", - "description": "Filter by priority (HIGH, MEDIUM, LOW, CRITICAL)", - "schema": { "type": "string" } - }, - { - "name": "status", - "in": "query", - "description": "Filter by status (TODO, IN_PROGRESS, IN_REVIEW, DONE)", - "schema": { "type": "string" } - }, - { - "name": "assignedTo", - "in": "query", - "description": "Filter by assignee ID (use 'null' for unassigned tasks)", - "schema": { "type": "string" } - }, - { - "name": "parentId", - "in": "query", - "description": "Filter by parent task ID (use 'null' for root tasks)", - "schema": { "type": "string" } - }, - { - "name": "search", - "in": "query", - "description": "Search term to filter by task title or description", - "schema": { "type": "string" } - }, - { - "name": "page", - "in": "query", - "description": "Page number for pagination (default: 1)", - "schema": { "type": "integer", "default": 1 } - }, - { - "name": "limit", - "in": "query", - "description": "Number of items per page (default: 20)", - "schema": { "type": "integer", "default": 20 } - }, - { - "name": "sortBy", - "in": "query", - "description": "Field to sort by (default: createdAt)", - "schema": { "type": "string", "default": "createdAt" } - }, - { - "name": "sortOrder", - "in": "query", - "description": "Sort order (asc or desc, default: desc)", - "schema": { - "type": "string", - "default": "desc", - "enum": ["asc", "desc"] - } - } - ], - "responses": { - "200": { - "description": "List of tasks retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "tasks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "priority": { "type": "string" }, - "status": { "type": "string" }, - "projectId": { "type": "string" }, - "sprintId": { "type": "string" }, - "createdBy": { "type": "string" }, - "assignedTo": { "type": "string" }, - "dueDate": { - "type": "string", - "format": "date-time" - }, - "estimatedTime": { "type": "number" }, - "parentId": { "type": "string" }, - "labels": { - "type": "array", - "items": { "type": "string" } - }, - "order": { "type": "number" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "creator": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "assignee": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "sprint": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "status": { "type": "string" } - } - }, - "subtasks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "status": { "type": "string" }, - "priority": { "type": "string" } - } - } - }, - "parent": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "status": { "type": "string" } - } - }, - "_count": { - "type": "object", - "properties": { - "comments": { "type": "integer" }, - "attachments": { "type": "integer" } - } - } - } - } - }, - "pagination": { - "type": "object", - "properties": { - "total": { "type": "integer", "example": 100 }, - "page": { "type": "integer", "example": 1 }, - "limit": { "type": "integer", "example": 20 }, - "pages": { "type": "integer", "example": 5 } - } - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team or project not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { "type": "string", "example": "Team not found" }, - { "type": "string", "example": "Project not found" } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/": { - "get": { - "tags": ["Task"], - "summary": "Get a specific task", - "description": "Retrieves detailed information about a specific task including related entities like creator, assignee, subtasks, dependencies, comments, and attachments.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "path", - "required": true, - "description": "ID of the task to retrieve", - "schema": { "type": "string" } - } - ], - "responses": { - "200": { - "description": "Task details retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "task": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "priority": { "type": "string" }, - "status": { "type": "string" }, - "projectId": { "type": "string" }, - "sprintId": { "type": "string" }, - "createdBy": { "type": "string" }, - "assignedTo": { "type": "string" }, - "dueDate": { "type": "string", "format": "date-time" }, - "estimatedTime": { "type": "number" }, - "parentId": { "type": "string" }, - "labels": { - "type": "array", - "items": { "type": "string" } - }, - "order": { "type": "number" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "creator": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "modifier": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "assignee": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "sprint": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "status": { "type": "string" }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" - } - } - }, - "subtasks": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "status": { "type": "string" }, - "priority": { "type": "string" }, - "assignedTo": { "type": "string" }, - "dueDate": { - "type": "string", - "format": "date-time" - }, - "assignee": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" } - } - } - } - } - }, - "parent": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "status": { "type": "string" }, - "priority": { "type": "string" } - } - }, - "dependentOn": { - "type": "array", - "items": { - "type": "object", - "properties": { - "task": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "status": { "type": "string" } - } - } - } - } - }, - "dependencies": { - "type": "array", - "items": { - "type": "object", - "properties": { - "dependentTask": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "status": { "type": "string" } - } - } - } - } - }, - "comments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "content": { "type": "string" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "user": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "profilePic": { "type": "string" } - } - } - } - } - }, - "attachments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "url": { "type": "string" }, - "size": { "type": "number" }, - "type": { "type": "string" }, - "uploadedAt": { - "type": "string", - "format": "date-time" - }, - "uploader": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "profilePic": { "type": "string" } - } - } - } - } - } - } - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team, project or task not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { "type": "string", "example": "Team not found" }, - { "type": "string", "example": "Project not found" }, - { - "type": "string", - "example": "Task not found or does not belong to the specified project" - } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/delete": { - "delete": { - "tags": ["Task"], - "summary": "Delete a task", - "description": "Deletes a task either permanently (for admins) or via soft delete. Handles subtasks recursively.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "path", - "required": true, - "description": "ID of the task to delete", - "schema": { "type": "string" } - }, - { - "name": "permanent", - "in": "query", - "description": "Whether to permanently delete (true) or soft delete (false). Requires admin privileges.", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "responses": { - "200": { - "description": "Task deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "message": { - "type": "string", - "example": "Task permanently deleted successfully" - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "You don't have permission to delete tasks in this project" - }, - { - "type": "string", - "example": "Only administrators or organization owners can permanently delete tasks" - } - ] - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team, project or task not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { "type": "string", "example": "Team not found" }, - { "type": "string", "example": "Project not found" }, - { - "type": "string", - "example": "Task not found or does not belong to the specified project" - } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/restore": { - "patch": { - "tags": ["Task"], - "summary": "Restore a deleted task", - "description": "Restores a soft-deleted task and optionally its subtasks. Requires the parent task to be active if the task has one.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "path", - "required": true, - "description": "ID of the team", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "path", - "required": true, - "description": "ID of the project", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "path", - "required": true, - "description": "ID of the task to restore", - "schema": { "type": "string" } - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "restoreSubtasks": { - "type": "boolean", - "description": "Whether to restore all deleted subtasks (default: true)", - "default": true - } - } - } - } - } - }, - "responses": { - "200": { - "description": "Task restored successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "message": { - "type": "string", - "example": "Task restored successfully with its subtasks" - }, - "task": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "priority": { "type": "string" }, - "status": { "type": "string" }, - "projectId": { "type": "string" }, - "sprintId": { "type": "string" }, - "createdBy": { "type": "string" }, - "assignedTo": { "type": "string" }, - "dueDate": { "type": "string", "format": "date-time" }, - "estimatedTime": { "type": "number" }, - "parentId": { "type": "string" }, - "labels": { - "type": "array", - "items": { "type": "string" } - }, - "order": { "type": "number" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "deletedAt": { - "type": "string", - "format": "date-time" - }, - "creator": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "_count": { - "type": "object", - "properties": { - "subtasks": { "type": "number" } - } - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - parent task is deleted", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Cannot restore task because its parent task is deleted. Please restore the parent task first." - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "You don't have permission to restore tasks in this project" - } - } - } - } - } - }, - "404": { - "description": "Not found - organization, team, project or task not found or already active", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Task not found, already active, or does not belong to the specified project" - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/activity-logs": { - "get": { - "tags": ["Activity Logs"], - "summary": "Get activity logs with filtering", - "description": "Retrieves activity logs with various filtering, sorting, and pagination options. Requires 'view activity logs' permission.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "entityType", - "in": "query", - "description": "Filter by entity type (ORGANIZATION, DEPARTMENT, TEAM, PROJECT, SPRINT, TASK)", - "schema": { "type": "string" } - }, - { - "name": "action", - "in": "query", - "description": "Filter by action type (CREATE, UPDATE, DELETE, etc.)", - "schema": { "type": "string" } - }, - { - "name": "userId", - "in": "query", - "description": "Filter by user ID who performed the action", - "schema": { "type": "string" } - }, - { - "name": "departmentId", - "in": "query", - "description": "Filter by department ID", - "schema": { "type": "string" } - }, - { - "name": "teamId", - "in": "query", - "description": "Filter by team ID", - "schema": { "type": "string" } - }, - { - "name": "projectId", - "in": "query", - "description": "Filter by project ID", - "schema": { "type": "string" } - }, - { - "name": "sprintId", - "in": "query", - "description": "Filter by sprint ID", - "schema": { "type": "string" } - }, - { - "name": "taskId", - "in": "query", - "description": "Filter by task ID", - "schema": { "type": "string" } - }, - { - "name": "startDate", - "in": "query", - "description": "Filter logs after this date (YYYY-MM-DD or ISO format)", - "schema": { "type": "string", "format": "date-time" } - }, - { - "name": "endDate", - "in": "query", - "description": "Filter logs before this date (YYYY-MM-DD or ISO format)", - "schema": { "type": "string", "format": "date-time" } - }, - { - "name": "page", - "in": "query", - "description": "Page number for pagination (default: 1)", - "schema": { "type": "integer", "default": 1 } - }, - { - "name": "limit", - "in": "query", - "description": "Number of items per page (default: 50)", - "schema": { "type": "integer", "default": 50 } - }, - { - "name": "sortBy", - "in": "query", - "description": "Field to sort by (createdAt, entityType, action) (default: createdAt)", - "schema": { "type": "string", "default": "createdAt" } - }, - { - "name": "sortOrder", - "in": "query", - "description": "Sort order (asc or desc) (default: desc)", - "schema": { - "type": "string", - "default": "desc", - "enum": ["asc", "desc"] - } - } - ], - "responses": { - "200": { - "description": "Activity logs retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "count": { "type": "integer", "example": 25 }, - "total": { "type": "integer", "example": 125 }, - "pagination": { - "type": "object", - "properties": { - "currentPage": { "type": "integer", "example": 1 }, - "totalPages": { "type": "integer", "example": 5 }, - "hasNextPage": { "type": "boolean", "example": true }, - "hasPreviousPage": { - "type": "boolean", - "example": false - }, - "limit": { "type": "integer", "example": 25 } - } - }, - "activityLogs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "entityType": { "type": "string" }, - "entityId": { "type": "string" }, - "action": { "type": "string" }, - "oldValue": { "type": "object" }, - "newValue": { "type": "object" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "user": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "department": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "team": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "project": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "sprint": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "task": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" } - } - } - } - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "You do not have permission to view activity logs" - } - } - } - } - } - }, - "404": { - "description": "Not found - organization not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Organization not found" - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/activity-logs/{logId}": { - "get": { - "tags": ["Activity Logs"], - "summary": "Get a specific activity log by ID", - "description": "Retrieves detailed information about a specific activity log. Requires 'view activity logs' permission.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "logId", - "in": "path", - "required": true, - "description": "ID of the activity log to retrieve", - "schema": { "type": "string" } - } - ], - "responses": { - "200": { - "description": "Activity log retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "activityLog": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "entityType": { "type": "string" }, - "entityId": { "type": "string" }, - "action": { "type": "string" }, - "oldValue": { "type": "object" }, - "newValue": { "type": "object" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "user": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "email": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "organization": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "department": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "team": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "project": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "sprint": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" } - } - }, - "task": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "status": { "type": "string" }, - "priority": { "type": "string" } - } - } - } - } - } - } - } - } - }, - "403": { - "description": "Forbidden - insufficient permissions", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "You do not have permission to view activity logs" - } - } - } - } - } - }, - "404": { - "description": "Not found - organization or activity log not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { - "type": "string", - "example": "Organization not found" - }, - { - "type": "string", - "example": "Activity log not found" - } - ] - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - }, - "/api/organization/{organizationId}/activity-feed": { - "get": { - "tags": ["Activity Logs"], - "summary": "Get activity feed for an entity", - "description": "Retrieves a paginated activity feed for a specific entity (task, project, etc.) with cursor-based pagination.", - "security": [{ "BearerAuth": [] }], - "parameters": [ - { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { "type": "string" } - }, - { - "name": "entityType", - "in": "query", - "description": "Type of entity to filter by (ORGANIZATION, DEPARTMENT, TEAM, PROJECT, SPRINT, TASK, USER)", - "schema": { - "type": "string", - "enum": [ - "ORGANIZATION", - "DEPARTMENT", - "TEAM", - "PROJECT", - "SPRINT", - "TASK", - "USER" - ] - } - }, - { - "name": "entityId", - "in": "query", - "description": "ID of the entity to filter by (required if entityType is provided)", - "schema": { "type": "string" } - }, - { - "name": "limit", - "in": "query", - "description": "Number of items to return (default: 20)", - "schema": { - "type": "integer", - "default": 20 - } - }, - { - "name": "before", - "in": "query", - "description": "Cursor for pagination (ISO timestamp of the last item from previous request)", - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "Activity feed retrieved successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": true }, - "activityFeed": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "message": { "type": "string" }, - "user": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "firstName": { "type": "string" }, - "lastName": { "type": "string" }, - "profilePic": { "type": "string" } - } - }, - "entityType": { "type": "string" }, - "action": { "type": "string" }, - "details": { "type": "object" }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "entityData": { "type": "object" } - } - } - }, - "pagination": { - "type": "object", - "properties": { - "nextCursor": { - "type": "string", - "format": "date-time", - "description": "Timestamp to use for next page pagination" - }, - "hasMore": { - "type": "boolean", - "description": "Whether there are more items available" - } - } - } - } - } - } - } - }, - "400": { - "description": "Bad request - invalid parameters", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "oneOf": [ - { "type": "string", "example": "Invalid entity type" }, - { - "type": "string", - "example": "entityId is required when entityType is provided" - } - ] - } - } - } - } - } - }, - "404": { - "description": "Not found - organization not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Organization not found" - } - } - } - } - } - }, - "500": { - "description": "Internal server error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { "type": "boolean", "example": false }, - "message": { - "type": "string", - "example": "Internal server error" - } - } - } - } - } - } - } - } - } - }, - - "components": { - "parameters": { - "orgId": { - "name": "orgId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { - "type": "string" - } - }, - "organizationId": { - "name": "organizationId", - "in": "path", - "required": true, - "description": "ID of the organization", - "schema": { - "type": "string" - } - } - }, - "responses": { - "MissingOrgId": { - "description": "Missing organization ID", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Organization ID is required" - } - } - } - } - } - }, - "OrganizationNotFound": { - "description": "Organization not found", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Organization not found" - } - } - } - } - } - }, - "ValidationError": { - "description": "Validation error", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Validation error occurred" - }, - "errors": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - } - } - } - } - }, - - "schemas": { - "User": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "email": { - "type": "string", - "format": "email" - }, - "username": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "role": { - "type": "string", - "enum": ["MEMBER", "ADMIN", "SUPER_ADMIN"] - }, - "isActive": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "AddOwnersResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Owners added successfully" - }, - "addedOwners": { - "type": "array", - "items": { - "$ref": "#/components/schemas/User" - } - } - } - }, - "UpdateOrganization": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Organization name" - }, - "description": { - "type": "string", - "description": "Organization description" - }, - "industry": { - "type": "string", - "description": "Industry sector" - }, - "sizeRange": { - "type": "string", - "description": "Size range of the organization" - }, - "website": { - "type": "string", - "description": "Organization website URL" - }, - "logoUrl": { - "type": "string", - "description": "URL to organization logo" - }, - "address": { - "type": "string", - "description": "Physical address" - }, - "contactEmail": { - "type": "string", - "format": "email", - "description": "Contact email for the organization" - }, - "contactPhone": { - "type": "string", - "description": "Contact phone number" - } - } - }, - "OrganizationDetails": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "status": { - "type": "string", - "enum": ["ACTIVE", "INACTIVE", "PENDING"] - }, - "isVerified": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "owners": { - "type": "array", - "items": { - "$ref": "#/components/schemas/User" - } - }, - "departments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - } - } - } - } - }, - "PaginatedOrganizations": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Organizations retrieved successfully" - }, - "data": { - "type": "object", - "properties": { - "organizations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" }, - "name": { "type": "string" }, - "status": { "type": "string" }, - "isVerified": { "type": "boolean" } - } - } - }, - "pagination": { - "type": "object", - "properties": { - "page": { "type": "integer" }, - "limit": { "type": "integer" }, - "totalItems": { "type": "integer" }, - "totalPages": { "type": "integer" } - } - } - } - } - } - }, - "UserBasic": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "role": { - "type": "string", - "enum": ["USER", "ADMIN", "SUPER_ADMIN"] - }, - "profilePic": { - "type": "string", - "nullable": true - }, - "phoneNumber": { - "type": "string", - "nullable": true - }, - "jobTitle": { - "type": "string", - "nullable": true - }, - "timezone": { - "type": "string", - "nullable": true - }, - "bio": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "UserFull": { - "type": "object", - "allOf": [ - { - "$ref": "#/components/schemas/UserBasic" - }, - { - "type": "object", - "properties": { - "username": { - "type": "string" - }, - "preferences": { - "type": "object" - }, - "isActive": { - "type": "boolean" - }, - "isOwner": { - "type": "boolean" - }, - "lastLogin": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "lastLogout": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "department": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - } - }, - "organization": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - } - }, - "permissions": { - "type": "array", - "items": { - "type": "object", - "properties": { - "entityType": { - "type": "string" - }, - "entityId": { - "type": "string" - }, - "permissions": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - }, - "teamMemberships": { - "type": "array", - "items": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - } - } - } - } - }, - "activityLogs": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "action": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - } - } - } - } - } - ] - }, - "UpdateUserAccount": { - "type": "object", - "properties": { - "firstName": { - "type": "string", - "nullable": true - }, - "lastName": { - "type": "string", - "nullable": true - }, - "phoneNumber": { - "type": "string", - "nullable": true - }, - "jobTitle": { - "type": "string", - "nullable": true - }, - "timezone": { - "type": "string", - "nullable": true - }, - "bio": { - "type": "string", - "nullable": true - }, - "role": { - "type": "string", - "enum": ["USER", "ADMIN", "SUPER_ADMIN"], - "nullable": true, - "description": "Admin only field" - }, - "departmentId": { - "type": "string", - "nullable": true, - "description": "Admin only field" - }, - "organizationId": { - "type": "string", - "nullable": true, - "description": "Admin only field" - } - } - }, - "UpdatePassword": { - "type": "object", - "required": ["oldPassword", "newPassword"], - "properties": { - "oldPassword": { - "type": "string", - "format": "password", - "minLength": 6 - }, - "newPassword": { - "type": "string", - "format": "password", - "minLength": 6 - } - } - }, - "TeamBasic": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "avatar": { - "type": "string", - "nullable": true - }, - "createdBy": { - "type": "string" - }, - "organizationId": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "CreateTeam": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "minLength": 3, - "maxLength": 50 - }, - "description": { - "type": "string", - "nullable": true, - "maxLength": 500 - }, - "avatar": { - "type": "string", - "nullable": true - }, - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeamMemberInput" - } - } - } - }, - "TeamMemberInput": { - "type": "object", - "required": ["userId"], - "properties": { - "userId": { - "type": "string" - }, - "role": { - "type": "string", - "enum": ["MEMBER", "LEADER"], - "default": "MEMBER" - } - } - }, - "TeamCreatedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Team created successfully." - }, - "data": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - } - } - }, - "teamLeader": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "leader": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "teamId": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { - "type": "string" - }, - "isActive": { - "type": "boolean" - } - } - } - } - }, - "teamMembers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { - "type": "string" - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - } - } - } - } - } - } - } - }, - "AddTeamMembers": { - "type": "object", - "required": ["members"], - "properties": { - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeamMemberInput" - } - } - } - }, - "TeamMembersResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Members added successfully." - }, - "data": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - } - } - }, - "teamLeader": { - "type": "object", - "properties": { - "id": { - "type": "string" - } - } - }, - "teamMembers": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { - "type": "string" - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - } - } - } - } - } - } - } - }, - "UpdateTeam": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 3, - "maxLength": 50, - "nullable": true - }, - "description": { - "type": "string", - "maxLength": 500, - "nullable": true - }, - "avatar": { - "type": "string", - "nullable": true - } - } - }, - "TeamsPaginatedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "data": { - "type": "object", - "properties": { - "teams": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeamWithMembers" - } - }, - "pagination": { - "type": "object", - "properties": { - "page": { - "type": "integer", - "example": 1 - }, - "limit": { - "type": "integer", - "example": 10 - }, - "totalItems": { - "type": "integer", - "example": 25 - }, - "totalPages": { - "type": "integer", - "example": 3 - } - } - } - } - } - } - }, - "TeamWithMembers": { - "type": "object", - "allOf": [ - { - "$ref": "#/components/schemas/TeamBasic" - }, - { - "type": "object", - "properties": { - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "role": { - "type": "string" - }, - "isActive": { - "type": "boolean" - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - } - } - } - }, - "creator": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - } - } - } - ] - }, - "TeamFullResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "data": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "avatar": { - "type": "string", - "nullable": true - }, - "createdBy": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "creator": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - }, - "department": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "nullable": true - } - } - }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "role": { - "type": "string" - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - }, - "joinedAt": { - "type": "string", - "format": "date-time" - } - } - } - }, - "projects": { - "type": "array", - "items": { - "type": "object" - } - }, - "recentReports": { - "type": "array", - "items": { - "type": "object" - } - }, - "statistics": { - "type": "object", - "properties": { - "activeMembers": { - "type": "integer" - }, - "totalProjects": { - "type": "integer" - }, - "projectsInProgress": { - "type": "integer" - }, - "completedProjects": { - "type": "integer" - } - } - } - } - } - } - }, - "CreateProject": { - "type": "object", - "required": ["name", "startDate", "endDate"], - "properties": { - "name": { - "type": "string", - "description": "Project name", - "minLength": 3, - "maxLength": 100 - }, - "description": { - "type": "string", - "description": "Project description", - "nullable": true, - "maxLength": 1000 - }, - "status": { - "type": "string", - "description": "Project status", - "enum": [ - "PLANNING", - "IN_PROGRESS", - "ON_HOLD", - "COMPLETED", - "CANCELLED" - ], - "default": "PLANNING" - }, - "startDate": { - "type": "string", - "format": "date-time", - "description": "Project start date" - }, - "endDate": { - "type": "string", - "format": "date-time", - "description": "Project end date" - }, - "priority": { - "type": "string", - "description": "Project priority", - "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"], - "default": "MEDIUM" - }, - "budget": { - "type": "number", - "description": "Project budget", - "nullable": true, - "minimum": 0 - }, - "members": { - "type": "array", - "description": "Initial project members", - "items": { - "$ref": "#/components/schemas/ProjectMemberInput" - }, - "default": [] - } - } - }, - "ProjectMemberInput": { - "type": "object", - "required": ["userId"], - "properties": { - "userId": { - "type": "string", - "description": "User ID to add as project member" - }, - "role": { - "type": "string", - "description": "Member role", - "enum": ["MEMBER", "CONTRIBUTOR", "REVIEWER", "MANAGER"], - "default": "MEMBER" - } - } - }, - "ProjectCreatedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Project created successfully." - }, - "data": { - "type": "object", - "properties": { - "project": { - "$ref": "#/components/schemas/ProjectBasic" - }, - "projectOwner": { - "$ref": "#/components/schemas/ProjectMember" - }, - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProjectMember" - } - } - } - } - } - }, - "ProjectBasic": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "status": { - "type": "string" - }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" - }, - "priority": { - "type": "string" - }, - "budget": { - "type": "number", - "nullable": true - }, - "teamId": { - "type": "string" - }, - "organizationId": { - "type": "string" - }, - "progress": { - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - "createdBy": { - "type": "string" - }, - "lastModifiedBy": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "ProjectMember": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "projectId": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { - "type": "string" - }, - "isActive": { - "type": "boolean" - } - } - }, - "UpdateProject": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Project name", - "minLength": 3, - "maxLength": 100 - }, - "description": { - "type": "string", - "description": "Project description", - "nullable": true, - "maxLength": 1000 - }, - "status": { - "type": "string", - "description": "Project status", - "enum": [ - "PLANNING", - "IN_PROGRESS", - "ON_HOLD", - "COMPLETED", - "CANCELLED" - ] - }, - "startDate": { - "type": "string", - "format": "date-time", - "description": "Project start date" - }, - "endDate": { - "type": "string", - "format": "date-time", - "description": "Project end date" - }, - "priority": { - "type": "string", - "description": "Project priority", - "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"] - }, - "budget": { - "type": "number", - "description": "Project budget", - "nullable": true, - "minimum": 0 - }, - "progress": { - "type": "integer", - "description": "Project progress percentage", - "minimum": 0, - "maximum": 100 - } - } - }, - "ProjectUpdatedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Project updated successfully" - }, - "data": { - "$ref": "#/components/schemas/ProjectBasic" - } - } - }, - "ProjectWithMemberCount": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "status": { - "type": "string", - "enum": [ - "PLANNING", - "IN_PROGRESS", - "ON_HOLD", - "COMPLETED", - "CANCELLED" - ] - }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" - }, - "priority": { - "type": "string", - "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"] - }, - "budget": { - "type": "number", - "nullable": true - }, - "teamId": { - "type": "string" - }, - "organizationId": { - "type": "string" - }, - "progress": { - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "deletedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "memberCount": { - "type": "integer", - "description": "Number of active members in the project" - }, - "userRole": { - "type": "string", - "description": "Current user's role in the project (only for non-admin users)", - "nullable": true, - "enum": [ - "MEMBER", - "CONTRIBUTOR", - "REVIEWER", - "MANAGER", - "PROJECT_OWNER" - ] - } - } - }, - "ProjectDetails": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "status": { - "type": "string", - "enum": [ - "PLANNING", - "IN_PROGRESS", - "ON_HOLD", - "COMPLETED", - "CANCELLED" - ] - }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" - }, - "priority": { - "type": "string", - "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"] - }, - "budget": { - "type": "number", - "nullable": true - }, - "teamId": { - "type": "string" - }, - "organizationId": { - "type": "string" - }, - "progress": { - "type": "integer", - "minimum": 0, - "maximum": 100 - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProjectMember" - } - }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProjectTask" - } - }, - "memberCount": { - "type": "integer" - }, - "taskCount": { - "type": "integer" - }, - "userRole": { - "type": "string", - "nullable": true, - "enum": [ - "MEMBER", - "CONTRIBUTOR", - "REVIEWER", - "MANAGER", - "PROJECT_OWNER" - ] - } - } - }, - "ProjectTask": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "title": { - "type": "string" - }, - "status": { - "type": "string" - }, - "priority": { - "type": "string" - }, - "dueDate": { - "type": "string", - "format": "date-time", - "nullable": true - } - } - }, - "Task": { - "type": "object", - "properties": { - "id": { "type": "string", "example": "task_123" }, - "title": { "type": "string" }, - "description": { "type": "string" }, - "priority": { "type": "string" }, - "status": { "type": "string", "example": "TODO" }, - "projectId": { "type": "string" }, - "sprintId": { "type": "string" }, - "createdBy": { "type": "string" }, - "assignedTo": { "type": "string" }, - "dueDate": { "type": "string", "format": "date" }, - "estimatedTime": { "type": "integer" }, - "parentId": { "type": "string" }, - "order": { "type": "integer" }, - "labels": { - "type": "array", - "items": { "type": "string" } - }, - "lastModifiedBy": { "type": "string" } - } - } - }, - "securitySchemes": { - "bearerAuth": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } } } } From 745c52da88a74ee47d419965723d97947a42da01 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:25:38 +0200 Subject: [PATCH 02/22] docs: `resendOTP` swagger document --- src/docs/swagger.json | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index b4a8c31..b56688d 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -165,6 +165,135 @@ }, "security": [] } + }, + "/api/auth/resendOTP": { + "post": { + "tags": ["Auth"], + "summary": "Resend OTP code for email verification", + "description": "Generates a new OTP and sends it to the user's email if the previous one expired or wasn't received.", + "operationId": "resendOTP", + "requestBody": { + "description": "Email address to resend OTP", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["email"], + "properties": { + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "OTP resent successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Code sent successfully. Please check your email" + } + } + } + } + } + }, + "400": { + "description": "Missing or invalid email", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Please enter a valid email" + } + } + } + } + } + }, + "404": { + "description": "User not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "User not found" + } + } + } + } + } + }, + "429": { + "description": "Too many requests", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Too many requests, please try again later." + } + } + } + } + } + }, + "500": { + "description": "Failed to send email", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "error": { + "type": "object" + }, + "message": { + "type": "string", + "example": "Failed to send verification email. Please try again later." + } + } + } + } + } + } + }, + "security": [] + } } }, From 6bb5a25d545d8a21838e0a9cbe7dcfea608ec98a Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:27:06 +0200 Subject: [PATCH 03/22] docs: `verifyEmail` swagger document --- src/docs/swagger.json | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index b56688d..a357457 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -294,6 +294,105 @@ }, "security": [] } + }, + "/api/auth/verifyEmail": { + "post": { + "tags": ["Auth"], + "summary": "Verify user's email address using OTP", + "description": "Validates the OTP sent to user's email and activates their account if verification is successful.", + "operationId": "verifyEmail", + "requestBody": { + "description": "Email and OTP for verification", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["email", "otp"], + "properties": { + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + }, + "otp": { + "type": "string", + "description": "6-digit verification code", + "example": "123456" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Email verified successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Email verified successfully" + } + } + } + } + } + }, + "400": { + "description": "Validation error, invalid OTP, or email already verified", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Invalid or expired OTP" + } + } + } + } + } + }, + "404": { + "description": "User not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User not found" + } + } + } + } + } + }, + "429": { + "description": "Too many requests", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Too many requests, please try again later." + } + } + } + } + } + } + }, + "security": [] + } } }, From 6424dc411f6258db92afc49896d4e432099424fc Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:28:51 +0200 Subject: [PATCH 04/22] docs: `signin` swagger document --- src/docs/swagger.json | 154 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index a357457..2fe4979 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -393,6 +393,160 @@ }, "security": [] } + }, + "/api/auth/signin": { + "post": { + "tags": ["Auth"], + "summary": "Authenticate user and return JWT tokens", + "description": "Validates user credentials and returns access and refresh tokens if authentication is successful.", + "operationId": "signin", + "requestBody": { + "description": "User credentials", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["email", "password"], + "properties": { + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + }, + "password": { + "type": "string", + "format": "password", + "example": "yourpassword123" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Authentication successful", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User login successfully" + }, + "accessToken": { + "type": "string", + "description": "JWT access token", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "refreshToken": { + "type": "string", + "description": "JWT refresh token (also set as HTTP-only cookie)", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "email": { + "type": "string", + "format": "email" + }, + "name": { + "type": "string" + }, + "role": { + "type": "string", + "enum": ["MEMBER", "ADMIN", "SUPER_ADMIN"] + } + } + } + } + } + } + }, + "headers": { + "Set-Cookie": { + "schema": { + "type": "string", + "example": "refreshToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; HttpOnly; Secure; SameSite=Strict; Max-Age=604800" + }, + "description": "Refresh token set as HTTP-only cookie" + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "\"email\" is required" + } + } + } + } + } + }, + "401": { + "description": "Invalid credentials", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Invalid email or password" + } + } + } + } + } + }, + "403": { + "description": "Account not activated", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Account not activated. Please verify your email" + } + } + } + } + } + }, + "429": { + "description": "Too many requests", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Too many requests, please try again later." + } + } + } + } + } + } + }, + "security": [] + } } }, From 737c0752d8f65ff2b4daca62b6534b9d7b09eac4 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:30:08 +0200 Subject: [PATCH 05/22] docs: `forgotPassword` swagger document --- src/docs/swagger.json | 94 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 2fe4979..b48c96b 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -547,6 +547,100 @@ }, "security": [] } + }, + "/api/auth/forgotPassword": { + "post": { + "tags": ["Auth"], + "summary": "Initiate password reset process", + "description": "Sends a password reset OTP to the user's email address if the account exists.", + "operationId": "forgotPassword", + "requestBody": { + "description": "User's email address", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["email"], + "properties": { + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Password reset OTP sent if account exists", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Password reset OTP sent" + } + } + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "\"email\" is required" + } + } + } + } + } + }, + "429": { + "description": "Too many requests", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Too many requests, please try again later." + } + } + } + } + } + }, + "500": { + "description": "Failed to send email", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Failed to send password reset email" + } + } + } + } + } + } + }, + "security": [] + } } }, From 11b87a146ee10b981cbad9d5e1f2b45daf9e3abc Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:35:06 +0200 Subject: [PATCH 06/22] docs: `resetPassword` swagger document --- src/docs/swagger.json | 107 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index b48c96b..5656b6e 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -641,6 +641,113 @@ }, "security": [] } + }, + "/api/auth/resetPassword": { + "post": { + "tags": ["Auth"], + "summary": "Reset user password using OTP", + "description": "Allows users to reset their password by providing a valid OTP sent to their email.", + "operationId": "resetPassword", + "requestBody": { + "description": "Password reset details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "User's email address" + }, + "otp": { + "type": "string", + "description": "One-time password received via email" + }, + "newPassword": { + "type": "string", + "format": "password", + "description": "New password to set", + "minLength": 6 + } + }, + "required": ["email", "otp", "newPassword"] + } + } + } + }, + "responses": { + "200": { + "description": "Password reset successful", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Password reset successfully" + } + } + } + } + } + }, + "400": { + "description": "Invalid request", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Invalid or expired reset token" + } + } + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Validation error message" + } + } + } + ] + } + } + } + }, + "404": { + "description": "User not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User not found" + } + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + }, + "security": [], + "x-rate-limit": { + "description": "Rate limited to prevent brute force attacks" + } + } } }, From 59d79a3ffce7abb7b4f5139664442168d2bc06a2 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:38:48 +0200 Subject: [PATCH 07/22] docs: `forget/reset password` swagger document --- src/docs/swagger.json | 183 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 5656b6e..fc78ecf 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -748,10 +748,193 @@ "description": "Rate limited to prevent brute force attacks" } } + }, + "/api/auth/forgotPasswordWithoutEmail": { + "post": { + "tags": ["Auth"], + "summary": "Initiate password reset using refreshToken", + "description": "Generates and sends a password reset OTP to the user's email identified by their refreshToken. Requires valid refreshToken cookie.", + "operationId": "forgotPasswordWithoutEmail", + "responses": { + "200": { + "description": "OTP sent successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Password reset OTP sent" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "No token provided" + } + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "cookieAuth": [] + } + ], + "x-rate-limit": { + "description": "Rate limited to prevent abuse" + } + } + }, + "/api/auth/resetPasswordWithoutEmail": { + "post": { + "tags": ["Auth"], + "summary": "Reset password using OTP (refreshToken flow)", + "description": "Resets user's password using OTP received via email. Requires valid refreshToken cookie.", + "operationId": "resetPasswordWithoutEmail", + "requestBody": { + "description": "Password reset details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "otp": { + "type": "string", + "description": "One-time password received via email" + }, + "newPassword": { + "type": "string", + "format": "password", + "description": "New password to set", + "minLength": 6 + } + }, + "required": ["otp", "newPassword"] + } + } + } + }, + "responses": { + "200": { + "description": "Password reset successful", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Password reset successfully" + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Invalid or expired reset token" + } + } + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Validation error message" + } + } + } + ] + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "No token provided" + } + } + } + } + } + }, + "404": { + "description": "User not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User not found" + } + } + } + } + } + }, + "500": { + "description": "Internal server error" + } + }, + "security": [ + { + "cookieAuth": [] + } + ], + "x-rate-limit": { + "description": "Rate limited to prevent brute force attacks" + } + } } }, "components": { + "securitySchemes": { + "cookieAuth": { + "type": "apiKey", + "in": "cookie", + "name": "refreshToken", + "description": "Refresh token cookie for authentication" + } + }, "schemas": { "User": { "type": "object", From aa26df4e291c01c250c17ddf5d16157b84bae585 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:42:47 +0200 Subject: [PATCH 08/22] docs: `refreshAccessToken` swagger document --- src/docs/swagger.json | 95 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index fc78ecf..29d2f06 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -923,6 +923,101 @@ "description": "Rate limited to prevent brute force attacks" } } + }, + "/api/auth/refreshAccessToken": { + "post": { + "tags": ["Auth"], + "summary": "Generate new access token using refresh token", + "description": "Creates a new access token when provided with a valid refresh token.", + "operationId": "refreshAccessToken", + "requestBody": { + "description": "Refresh token", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["refreshToken"], + "properties": { + "refreshToken": { + "type": "string", + "description": "Valid refresh token obtained during signin", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + } + } + } + } + } + }, + "responses": { + "200": { + "description": "New access token generated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "accessToken": { + "type": "string", + "description": "New JWT access token", + "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + } + } + } + } + } + }, + "401": { + "description": "Refresh token missing", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Refresh token missing" + } + } + } + } + } + }, + "403": { + "description": "Invalid or mismatched refresh token", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Invalid refresh token" + } + } + } + } + } + }, + "429": { + "description": "Too many requests", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Too many requests, please try again later." + } + } + } + } + } + } + }, + "security": [] + } } }, From 8e97ed8e2fcdab4fb94d69d174154fc64dd8998b Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:49:19 +0200 Subject: [PATCH 09/22] docs: `getAllUsers` swagger document --- src/docs/swagger.json | 97 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 29d2f06..7827cb3 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1018,6 +1018,98 @@ }, "security": [] } + }, + "/api/users/all": { + "get": { + "tags": ["User"], + "summary": "Get all users with pagination", + "description": "Retrieves a paginated list of all users. Requires admin permission.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "query", + "name": "page", + "schema": { + "type": "integer", + "default": 1 + }, + "description": "Page number for pagination" + } + ], + "responses": { + "200": { + "description": "List of users retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Users retrieved successfully" + }, + "currentPage": { + "type": "integer", + "example": 1 + }, + "totalPages": { + "type": "integer", + "example": 5 + }, + "totalUsers": { + "type": "integer", + "example": 42 + }, + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + }, + "role": { + "type": "string", + "example": "USER" + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have admin permissions" + }, + "500": { + "description": "Internal Server Error" + } + } + } } }, @@ -1028,6 +1120,11 @@ "in": "cookie", "name": "refreshToken", "description": "Refresh token cookie for authentication" + }, + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" } }, "schemas": { From 95baaa4ef0b110f18020a2997fee301795f449d3 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:52:00 +0200 Subject: [PATCH 10/22] docs: `getUserById/updateUser` swagger document --- src/docs/swagger.json | 392 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 392 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 7827cb3..b4e0015 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1110,6 +1110,398 @@ } } } + }, + "/api/users/{id}": { + "get": { + "tags": ["User"], + "summary": "Get full user profile by ID", + "description": "Retrieves detailed information about a specific user. Requires authentication and appropriate permissions.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID" + } + ], + "responses": { + "200": { + "description": "User retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User retrieved successfully" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "email": { + "type": "string", + "format": "email", + "example": "user@example.com" + }, + "username": { + "type": "string", + "example": "johndoe" + }, + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + }, + "role": { + "type": "string", + "example": "USER" + }, + "profilePic": { + "type": "string", + "nullable": true, + "example": "https://example.com/profile.jpg" + }, + "phoneNumber": { + "type": "string", + "nullable": true, + "example": "+1234567890" + }, + "jobTitle": { + "type": "string", + "nullable": true, + "example": "Software Developer" + }, + "timezone": { + "type": "string", + "nullable": true, + "example": "America/New_York" + }, + "bio": { + "type": "string", + "nullable": true, + "example": "Software developer with 5 years of experience" + }, + "preferences": { + "type": "object", + "nullable": true + }, + "isActive": { + "type": "boolean", + "example": true + }, + "isOwner": { + "type": "boolean", + "example": false + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "lastLogin": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "lastLogout": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "department": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "organization": { + "type": "object", + "nullable": true, + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "permissions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "entityType": { + "type": "string" + }, + "entityId": { + "type": "string", + "format": "uuid" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "teamMemberships": { + "type": "array", + "items": { + "type": "object", + "properties": { + "team": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + } + } + } + }, + "activityLogs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "action": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have required permissions" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "put": { + "tags": ["User"], + "summary": "Update user account", + "description": "Updates user account information. Users can update their own basic information, while admins can modify additional fields.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "firstName": { + "type": "string", + "example": "John" + }, + "lastName": { + "type": "string", + "example": "Doe" + }, + "phoneNumber": { + "type": "string", + "example": "+1234567890" + }, + "jobTitle": { + "type": "string", + "example": "Senior Developer" + }, + "timezone": { + "type": "string", + "example": "America/New_York" + }, + "bio": { + "type": "string", + "example": "Software developer with extensive experience" + }, + "role": { + "type": "string", + "description": "Admin only field", + "example": "ADMIN" + }, + "departmentId": { + "type": "string", + "format": "uuid", + "description": "Admin only field" + }, + "organizationId": { + "type": "string", + "format": "uuid", + "description": "Admin only field" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "User account updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User account updated successfully" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "email": { + "type": "string", + "format": "email" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "role": { + "type": "string" + }, + "phoneNumber": { + "type": "string", + "nullable": true + }, + "jobTitle": { + "type": "string", + "nullable": true + }, + "timezone": { + "type": "string", + "nullable": true + }, + "bio": { + "type": "string", + "nullable": true + }, + "departmentId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "organizationId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "profilePic": { + "type": "string", + "nullable": true + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request - Invalid input or validation error" + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have required permissions or account is not active" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal Server Error" + } + } + } } }, From 1b2831b2f5ce601c970ce18b48ddea78dc67969c Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:54:24 +0200 Subject: [PATCH 11/22] docs: `updatePassword/deleteUser` swagger document --- src/docs/swagger.json | 163 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index b4e0015..03221b4 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1502,6 +1502,169 @@ } } } + }, + "/api/users/update-password/{id}": { + "patch": { + "tags": ["User"], + "summary": "Update user password", + "description": "Allows a user to update their password by providing the old and new passwords. User can only update their own password.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["oldPassword", "newPassword"], + "properties": { + "oldPassword": { + "type": "string", + "description": "User's current password", + "example": "CurrentP@ssw0rd" + }, + "newPassword": { + "type": "string", + "description": "New password to set", + "example": "NewP@ssw0rd123" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Password updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Password updated successfully" + } + } + } + } + } + }, + "400": { + "description": "Bad Request - Invalid input, validation error, incorrect old password, or new password same as old password", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Incorrect old password" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have required permissions" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/api/users/delete/{id}": { + "delete": { + "tags": ["User"], + "summary": "Soft delete a user", + "description": "Soft deletes a user by setting deletedAt to current date and making them inactive. Admin permission required.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID to delete" + } + ], + "responses": { + "200": { + "description": "User deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User deleted successfully" + } + } + } + } + } + }, + "400": { + "description": "Bad Request - User already deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User already deleted" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have admin permissions" + }, + "404": { + "description": "User not found" + }, + "500": { + "description": "Internal Server Error" + } + } + } } }, From 530030d404152e773ce15c637a5b4cbd1f84b8e3 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 11:57:32 +0200 Subject: [PATCH 12/22] docs: profilePicManagement and restore user swagger document --- src/docs/swagger.json | 298 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 03221b4..9d983c8 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1665,6 +1665,304 @@ } } } + }, + "/api/users/restore/{id}": { + "patch": { + "tags": ["User"], + "summary": "Restore a soft-deleted user", + "description": "Restores a previously soft-deleted user by clearing their deletedAt field and setting isActive to true. Requires admin permission.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID to restore" + } + ], + "responses": { + "200": { + "description": "User restored successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User restored successfully" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have admin permissions" + }, + "404": { + "description": "User not found or not deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User not found or not deleted" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/api/users/{id}/profile-picture": { + "post": { + "tags": ["User"], + "summary": "Upload a user profile picture", + "description": "Uploads and sets a profile picture for a user. Users can upload their own pictures or admins can upload for any user.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID" + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "image": { + "type": "string", + "format": "binary", + "description": "Profile picture image file" + } + }, + "required": ["image"] + } + } + } + }, + "responses": { + "200": { + "description": "Profile picture uploaded successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Profile picture uploaded successfully" + }, + "profilePicUrl": { + "type": "string", + "example": "https://cloudinary.com/example/profile_picture.jpg" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "email": { + "type": "string", + "format": "email" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "profilePic": { + "type": "string" + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request - User ID is required or no file uploaded", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "No file uploaded" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have required permissions" + }, + "404": { + "description": "User not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User not found" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + }, + "delete": { + "tags": ["User"], + "summary": "Delete user profile picture", + "description": "Removes the profile picture for a user and sets the profilePic field to null. Users can delete their own pictures or admins can delete for any user.", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "User ID" + } + ], + "responses": { + "200": { + "description": "Profile picture deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Profile picture deleted successfully" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "email": { + "type": "string", + "format": "email" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request - User ID is required", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User ID is required" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "403": { + "description": "Forbidden - User does not have required permissions" + }, + "404": { + "description": "Profile picture not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Profile picture not found" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + } } }, From b38739c8e02689e3af8eb22dd3af450fe7660ce8 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 12:22:14 +0200 Subject: [PATCH 13/22] docs: create org with verification swagger document --- src/docs/swagger.json | 380 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 9d983c8..76ce39a 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -1963,6 +1963,386 @@ } } } + }, + "/api/organization": { + "post": { + "tags": ["Organization"], + "summary": "Create a new organization", + "description": "Creates a new organization with the current user as the owner or a specified user as owner", + "security": [ + { + "bearerAuth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["name", "contactEmail"], + "properties": { + "name": { + "type": "string", + "description": "Organization name", + "example": "Acme Corporation" + }, + "description": { + "type": "string", + "description": "Organization description", + "example": "A leading provider of innovative solutions" + }, + "industry": { + "type": "string", + "description": "Industry sector", + "example": "Technology" + }, + "sizeRange": { + "type": "string", + "description": "Size range of the organization", + "example": "50-100" + }, + "website": { + "type": "string", + "format": "uri", + "description": "Organization website URL", + "example": "https://acme.example.com" + }, + "logoUrl": { + "type": "string", + "format": "uri", + "description": "URL to organization logo", + "example": "https://example.com/logo.png" + }, + "address": { + "type": "string", + "description": "Organization address", + "example": "123 Main St, Anytown, USA" + }, + "contactEmail": { + "type": "string", + "format": "email", + "description": "Organization contact email", + "example": "contact@acme.example.com" + }, + "contactPhone": { + "type": "string", + "description": "Organization contact phone", + "example": "+1-234-567-8900" + }, + "orgOwnerId": { + "type": "string", + "format": "uuid", + "description": "User ID to set as organization owner (optional, defaults to current user)", + "example": "123e4567-e89b-12d3-a456-426614174000" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Organization created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Organization created successfully." + }, + "data": { + "type": "object", + "properties": { + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string", + "example": "APPROVED" + }, + "isVerified": { + "type": "boolean", + "example": true + } + } + }, + "organizationOwner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad Request - Invalid input data", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "example": "Name is required" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "409": { + "description": "Conflict - Organization with name or email already exists", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization with this name or email already exists" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/api/organization/resendOTP/{orgId}": { + "post": { + "tags": ["Organization"], + "summary": "Resend OTP verification code", + "description": "Generates a new OTP code and sends it to the organization's contact email for verification", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "orgId", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "Organization ID" + } + ], + "responses": { + "200": { + "description": "OTP sent successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Code send successfully. Please check your email" + } + } + } + } + } + }, + "400": { + "description": "Bad Request - Missing organization ID", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Organization ID is required" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Organization not found" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error or failed to send email", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Failed to send verification email. Please try again later." + } + } + } + } + } + } + } + } + }, + "/api/organization/verifyOrg/{orgId}": { + "post": { + "tags": ["Organization"], + "summary": "Verify organization using OTP", + "description": "Verifies an organization's contact email using the provided OTP code", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "orgId", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + }, + "description": "Organization ID" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["otp"], + "properties": { + "otp": { + "type": "string", + "description": "Verification OTP code", + "example": "123456" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Organization verified successfully or already verified", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization verified successfully" + } + } + } + } + } + }, + "400": { + "description": "Bad Request - Invalid or expired OTP", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Invalid or expired OTP" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized - Invalid or missing token" + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization not found" + } + } + } + } + } + }, + "500": { + "description": "Internal Server Error" + } + } + } } }, From 1162dcf31a2b469a8c4dd6cd413946f1b2b1b4e6 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 12:34:08 +0200 Subject: [PATCH 14/22] docs: get/update org swagger document --- src/docs/swagger.json | 749 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 749 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 76ce39a..19fee39 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -2343,6 +2343,371 @@ } } } + }, + "/api/organization/all": { + "get": { + "tags": ["Organization"], + "summary": "Get paginated list of organizations", + "description": "Returns a paginated list of organizations with filtering, sorting, and permission-based access control.", + "operationId": "getAllOrganizations", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "default": 10 + } + }, + { + "name": "sortBy", + "in": "query", + "description": "Field to sort by", + "required": false, + "schema": { + "type": "string", + "default": "createdAt", + "enum": ["createdAt", "name", "industry", "sizeRange", "status"] + } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort order", + "required": false, + "schema": { + "type": "string", + "default": "desc", + "enum": ["asc", "desc"] + } + }, + { + "name": "name", + "in": "query", + "description": "Filter by organization name (contains, case-insensitive)", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "industry", + "in": "query", + "description": "Filter by industry", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "sizeRange", + "in": "query", + "description": "Filter by size range", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "isVerified", + "in": "query", + "description": "Filter by verification status", + "required": false, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Organizations retrieved successfully" + }, + "data": { + "type": "object", + "properties": { + "organizations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrganizationWithStats" + } + }, + "pagination": { + "$ref": "#/components/schemas/Pagination" + } + } + } + } + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/organization/{organizationId}": { + "get": { + "tags": ["Organization"], + "summary": "Get organization details", + "description": "Returns detailed information about a specific organization including related entities (departments, teams, projects) with permission checks.", + "operationId": "getSpecificOrganization", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Organization retrieved successfully" + }, + "data": { + "$ref": "#/components/schemas/OrganizationDetails" + } + } + } + } + } + }, + "400": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "put": { + "tags": ["Organization"], + "summary": "Update organization", + "description": "Updates organization details with validation and permission checks. Admins and organization owners can update all fields, others have restricted access.", + "operationId": "updateOrganization", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "Organization update data", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrganizationUpdate" + } + } + } + }, + "responses": { + "200": { + "description": "Successful operation", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Organization updated successfully" + }, + "note": { + "type": "string", + "example": "Please verify your organization email" + }, + "data": { + "$ref": "#/components/schemas/OrganizationBasic" + } + } + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Validation error" + }, + "errors": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "409": { + "description": "Conflict - Organization name exists", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Email verification failed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Organization updated but failed to send verification email" + } + } + } + } + } + } + } + } } }, @@ -2395,6 +2760,390 @@ "format": "date-time" } } + }, + "OrganizationWithStats": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string" + }, + "logoUrl": { + "type": "string" + }, + "status": { + "type": "string" + }, + "isVerified": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "statistics": { + "type": "object", + "properties": { + "usersCount": { + "type": "integer" + }, + "departmentsCount": { + "type": "integer" + }, + "teamsCount": { + "type": "integer" + }, + "projectsCount": { + "type": "integer" + } + } + }, + "owners": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + } + } + } + } + } + }, + "OrganizationDetails": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string" + }, + "logoUrl": { + "type": "string" + }, + "status": { + "type": "string" + }, + "isVerified": { + "type": "boolean" + }, + "contactEmail": { + "type": "string", + "format": "email" + }, + "contactPhone": { + "type": "string" + }, + "address": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "statistics": { + "type": "object", + "properties": { + "usersCount": { + "type": "integer" + }, + "departmentsCount": { + "type": "integer" + }, + "teamsCount": { + "type": "integer" + }, + "projectsCount": { + "type": "integer" + }, + "templatesCount": { + "type": "integer" + } + } + }, + "owners": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "profileImage": { + "type": "string" + } + } + } + }, + "departments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "usersCount": { + "type": "integer" + }, + "teamsCount": { + "type": "integer" + } + } + } + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "usersCount": { + "type": "integer" + }, + "projectsCount": { + "type": "integer" + } + } + } + }, + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "status": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date-time" + }, + "endDate": { + "type": "string", + "format": "date-time" + } + } + } + }, + "hasMoreDepartments": { + "type": "boolean" + }, + "hasMoreTeams": { + "type": "boolean" + }, + "hasMoreProjects": { + "type": "boolean" + } + } + }, + "OrganizationUpdate": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "industry": { + "type": "string", + "maxLength": 50 + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string", + "format": "uri", + "maxLength": 100 + }, + "logoUrl": { + "type": "string", + "format": "uri", + "maxLength": 255 + }, + "contactEmail": { + "type": "string", + "format": "email", + "maxLength": 100 + }, + "contactPhone": { + "type": "string", + "maxLength": 20 + }, + "address": { + "type": "string", + "maxLength": 255 + }, + "isVerified": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": ["ACTIVE", "PENDING", "SUSPENDED"] + } + } + }, + "OrganizationBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string" + }, + "logoUrl": { + "type": "string" + }, + "status": { + "type": "string" + }, + "isVerified": { + "type": "boolean" + }, + "contactEmail": { + "type": "string", + "format": "email" + }, + "contactPhone": { + "type": "string" + }, + "address": { + "type": "string" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "Pagination": { + "type": "object", + "properties": { + "total": { + "type": "integer" + }, + "page": { + "type": "integer" + }, + "limit": { + "type": "integer" + }, + "pages": { + "type": "integer" + } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Error message" + } + } } } } From e97166b970b63eaaa16197b9a0e97a33fa55c198 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 12:44:21 +0200 Subject: [PATCH 15/22] docs: delete/logo org swagger document --- src/docs/swagger.json | 409 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 372 insertions(+), 37 deletions(-) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 19fee39..de1392f 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -2525,10 +2525,7 @@ "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "example": true - }, + "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Organization retrieved successfully" @@ -2545,9 +2542,7 @@ "description": "Bad request", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } + "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, @@ -2555,9 +2550,7 @@ "description": "Forbidden", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } + "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } }, @@ -2565,9 +2558,7 @@ "description": "Organization not found", "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } + "schema": { "$ref": "#/components/schemas/ErrorResponse" } } } } @@ -2596,9 +2587,7 @@ "required": true, "content": { "application/json": { - "schema": { - "$ref": "#/components/schemas/OrganizationUpdate" - } + "schema": { "$ref": "#/components/schemas/OrganizationUpdate" } } } }, @@ -2610,10 +2599,7 @@ "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "example": true - }, + "success": { "type": "boolean", "example": true }, "message": { "type": "string", "example": "Organization updated successfully" @@ -2622,8 +2608,211 @@ "type": "string", "example": "Please verify your organization email" }, + "data": { "$ref": "#/components/schemas/OrganizationBasic" } + } + } + } + } + }, + "400": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Validation error" + }, + "errors": { "type": "array", "items": { "type": "string" } } + } + } + } + } + }, + "403": { + "description": "Forbidden", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "409": { + "description": "Conflict - Organization name exists", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "500": { + "description": "Email verification failed", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Organization updated but failed to send verification email" + } + } + } + } + } + } + } + }, + "delete": { + "tags": ["Organization"], + "summary": "Soft delete an organization", + "description": "Marks an organization as deleted but retains it in the database. Only accessible to admins and organization owners.", + "operationId": "deleteOrganization", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization to delete", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Organization deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "Organization deleted successfully" + } + } + } + } + } + }, + "400": { + "description": "Missing organization ID", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + }, + "404": { + "description": "Organization not found or already deleted", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" } + } + } + } + } + } + }, + "/api/organization/{organizationId}/addOwner": { + "post": { + "tags": ["Organization"], + "summary": "Add owners to an organization", + "description": "Adds one or more users as owners to an organization. Requires admin or existing owner permissions.", + "operationId": "addOwners", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "description": "User IDs to add as owners", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["userIds"], + "properties": { + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Array of user IDs to add as owners", + "example": ["123e4567-e89b-12d3-a456-426614174000"] + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Owners added successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Successfully added 2 owner(s) to the organization" + }, "data": { - "$ref": "#/components/schemas/OrganizationBasic" + "type": "object", + "properties": { + "addedOwners": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserBasic" + } + }, + "skippedOwners": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } } } } @@ -2631,7 +2820,7 @@ } }, "400": { - "description": "Validation error", + "description": "Validation error or invalid user IDs", "content": { "application/json": { "schema": { @@ -2642,13 +2831,18 @@ "example": false }, "message": { - "type": "string", - "example": "Validation error" + "type": "string" }, "errors": { - "type": "array", - "items": { - "type": "string" + "type": "object", + "properties": { + "invalidUserIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } } } } @@ -2657,7 +2851,7 @@ } }, "403": { - "description": "Forbidden", + "description": "Forbidden - insufficient permissions", "content": { "application/json": { "schema": { @@ -2675,9 +2869,71 @@ } } } + } + } + } + }, + "/api/organization/{organizationId}/logo/upload": { + "post": { + "tags": ["Organization"], + "summary": "Upload organization logo", + "description": "Uploads a logo image for the organization. Requires admin or owner permissions.", + "operationId": "uploadOrganizationLogo", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "image": { + "type": "string", + "format": "binary", + "description": "Logo image file" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Logo uploaded successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization logo uploaded successfully" + }, + "logoUrl": { + "type": "string", + "format": "uri" + }, + "organization": { + "$ref": "#/components/schemas/OrganizationBasic" + } + } + } + } + } }, - "409": { - "description": "Conflict - Organization name exists", + "400": { + "description": "No file uploaded or missing organization ID", "content": { "application/json": { "schema": { @@ -2686,25 +2942,87 @@ } } }, - "500": { - "description": "Email verification failed", + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/logo/delete": { + "delete": { + "tags": ["Organization"], + "summary": "Delete organization logo", + "description": "Deletes the organization's logo. Requires admin or owner permissions.", + "operationId": "deleteOrganizationLogo", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Logo deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "success": { - "type": "boolean", - "example": false - }, "message": { "type": "string", - "example": "Organization updated but failed to send verification email" + "example": "Organization logo deleted successfully" + }, + "organization": { + "$ref": "#/components/schemas/OrganizationBasic" } } } } } + }, + "400": { + "description": "Missing organization ID", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Organization or logo not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } } } } @@ -3144,6 +3462,23 @@ "example": "Error message" } } + }, + "UserBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string", + "description": "Combined first and last name" + }, + "email": { + "type": "string", + "format": "email" + } + } } } } From 1bc537dbb4861e2906bcb387bd91f2abb2692040 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 12:53:02 +0200 Subject: [PATCH 16/22] docs: get departmet swagger document --- src/docs/swagger.json | 427 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 427 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index de1392f..a4333e4 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -3026,6 +3026,256 @@ } } } + }, + "/api/organizations/{organizationId}/departments/all": { + "get": { + "tags": ["Department"], + "summary": "Get all active departments (paginated)", + "description": "Returns paginated list of departments for an organization. Accessible to Admin/Owner only.", + "operationId": "getAllDepartments", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + } + ], + "responses": { + "200": { + "description": "Departments retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Departments retrieved successfully" + }, + "data": { + "type": "object", + "properties": { + "departments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DepartmentBasic" + } + }, + "pagination": { + "$ref": "#/components/schemas/Pagination" + } + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/organizations/{organizationId}/departments/{departmentId}": { + "get": { + "tags": ["Department"], + "summary": "Get department by ID with related data", + "description": "Returns detailed department information including users and teams. Accessible to Owner/Admin or department manager.", + "operationId": "getDepartmentById", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "departmentId", + "in": "path", + "description": "ID of the department", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Department retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Department retrieved successfully" + }, + "data": { + "$ref": "#/components/schemas/DepartmentDetailed" + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "404": { + "description": "Department not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/api/organizations/{organizationId}/departments/created": { + "get": { + "tags": ["Department"], + "summary": "Get departments managed by current user", + "description": "Returns paginated list of departments managed by the current user in the specified organization.", + "operationId": "getCreatedDepartments", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "ID of the organization", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Managed departments retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Managed departments retrieved successfully" + }, + "data": { + "type": "object", + "properties": { + "departments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DepartmentWithCounts" + } + }, + "pagination": { + "$ref": "#/components/schemas/Pagination" + } + } + } + } + } + } + } + }, + "404": { + "description": "Organization not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } } }, @@ -3479,6 +3729,183 @@ "format": "email" } } + }, + "DepartmentBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "manager": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } + }, + "DepartmentDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "manager": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "jobTitle": { + "type": "string" + } + } + }, + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserBasic" + } + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + }, + "DepartmentWithCounts": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "_count": { + "type": "object", + "properties": { + "users": { + "type": "integer" + }, + "teams": { + "type": "integer" + } + } + } + } } } } From 6874635f417d2f460ec4e7b3acea89dc4da10b96 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 13:04:56 +0200 Subject: [PATCH 17/22] docs: finish department swagger document --- src/docs/swagger.json | 155 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index a4333e4..bdfaee7 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -3276,6 +3276,161 @@ } } } + }, + "/api/organizations/{organizationId}/departments/create": { + "post": { + "tags": ["Department"], + "summary": "Create a new department", + "description": "Creates a department within the specified organization. Requires Admin or Owner permissions.", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" } + }, + "required": ["name"] + } + } + } + }, + "responses": { + "201": { + "description": "Department created successfully" + }, + "400": { + "description": "Validation error" + }, + "403": { + "description": "Unauthorized action" + }, + "409": { + "description": "Duplicate department name" + } + } + } + }, + "/api/organizations/{organizationId}/departments/{departmentId}/": { + "put": { + "tags": ["Department"], + "summary": "Update department details", + "description": "Updates a department’s name or description. Requires Admin or Owner permissions.", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "departmentId", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "name": { "type": "string" }, + "description": { "type": "string" } + } + } + } + } + }, + "responses": { + "200": { + "description": "Department updated successfully" + }, + "400": { + "description": "Validation error" + }, + "404": { + "description": "Department or organization not found" + }, + "409": { + "description": "Duplicate department name" + } + } + } + }, + "/api/organizations/{organizationId}/departments/{departmentId}/delete": { + "delete": { + "tags": ["Department"], + "summary": "Soft delete department", + "description": "Soft deletes a department by setting deletedAt timestamp. Requires Admin or Owner permissions.", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "departmentId", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Department deleted successfully" + }, + "404": { + "description": "Department or organization not found" + } + } + } + }, + "/api/organizations/{organizationId}/departments/{departmentId}/restore": { + "patch": { + "tags": ["Department"], + "summary": "Restore department", + "description": "Restores a soft-deleted department. Requires Admin or Owner permissions.", + "security": [{ "bearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "departmentId", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Department restored successfully" + }, + "404": { + "description": "Department or organization not found" + } + } + } } }, From f7d2c73b81a50c0853fc0c8ca4097a69bf58a786 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 13:14:58 +0200 Subject: [PATCH 18/22] docs: finish team swagger document --- src/docs/swagger.json | 1344 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 1245 insertions(+), 99 deletions(-) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index bdfaee7..b281821 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -3431,6 +3431,644 @@ } } } + }, + "/api/organization/{organizationId}/team": { + "post": { + "tags": ["Team"], + "summary": "Create a new team in a specific organization", + "description": "Creates a new team within an organization. Admin or organization owner access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeam" + } + } + } + }, + "responses": { + "201": { + "description": "Team created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamCreatedResponse" + } + } + } + }, + "400": { + "description": "Bad request - Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin or organization owner access required" + }, + "404": { + "description": "Organization not found" + }, + "409": { + "description": "Conflict - Team with this name already exists" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/addMember": { + "post": { + "tags": ["Team"], + "summary": "Add new team members", + "description": "Adds one or more members to an existing team. Admin or organization owner access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddTeamMembers" + } + } + } + }, + "responses": { + "200": { + "description": "Members added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamMembersResponse" + } + } + } + }, + "400": { + "description": "Bad request - Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin or organization owner access required" + }, + "404": { + "description": "Organization or team not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}": { + "put": { + "tags": ["Team"], + "summary": "Update a team", + "description": "Updates team information. Admin or organization owner access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTeam" + } + } + } + }, + "responses": { + "200": { + "description": "Team updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamBasic" + } + } + } + }, + "400": { + "description": "Bad request - Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin or organization owner access required" + }, + "404": { + "description": "Organization or team not found" + }, + "409": { + "description": "Conflict - Team with this name already exists" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + }, + "delete": { + "tags": ["Team"], + "summary": "Delete team", + "description": "Soft deletes a team. Admin, organization owner or team creator access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Team deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Team deleted successfully" + } + } + } + } + } + }, + "400": { + "description": "Bad request - Invalid input" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin, organization owner or team creator access required" + }, + "404": { + "description": "Organization or team not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/avatar/upload": { + "post": { + "tags": ["Team"], + "summary": "Upload team avatar", + "description": "Uploads an avatar image for a team. Admin or organization owner access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "image": { + "type": "string", + "format": "binary", + "description": "Image file to upload" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Team avatar uploaded successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Team avatar uploaded successfully" + }, + "team": { + "$ref": "#/components/schemas/TeamBasic" + } + } + } + } + } + }, + "400": { + "description": "Bad request - No file uploaded" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin or organization owner access required" + }, + "404": { + "description": "Organization or team not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/avatar/delete": { + "delete": { + "tags": ["Team"], + "summary": "Delete team avatar", + "description": "Deletes a team's avatar. Admin or organization owner access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Team avatar deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Team avatar deleted successfully" + }, + "team": { + "$ref": "#/components/schemas/TeamBasic" + } + } + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin or organization owner access required" + }, + "404": { + "description": "Organization, team or avatar not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/members/{memberId}": { + "delete": { + "tags": ["Team"], + "summary": "Remove member from a team", + "description": "Removes a member from a team (soft delete). Admin, organization owner or team creator access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "memberId", + "in": "path", + "description": "Team member ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Team member removed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Team member John Doe removed successfully" + }, + "data": { + "type": "object", + "properties": { + "removedMember": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "name": { + "type": "string" + }, + "removedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad request - Cannot remove the only team leader" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin, organization owner or team creator access required" + }, + "404": { + "description": "Organization, team or member not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/teams/all": { + "get": { + "tags": ["Team"], + "summary": "Get all teams", + "description": "Retrieves all teams in an organization with pagination. Admin or organization owner access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "page", + "in": "query", + "description": "Page number", + "required": false, + "schema": { + "type": "integer", + "default": 1 + } + }, + { + "name": "limit", + "in": "query", + "description": "Items per page", + "required": false, + "schema": { + "type": "integer", + "default": 10 + } + }, + { + "name": "search", + "in": "query", + "description": "Search term for team name", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Teams retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamsPaginatedResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin or organization owner access required" + }, + "404": { + "description": "Organization not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/teams/{teamId}": { + "get": { + "tags": ["Team"], + "summary": "Get specific team details", + "description": "Retrieves detailed information about a specific team. Admin, organization owner or team member access required.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Team details retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamFullResponse" + } + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - Admin, organization owner or team member access required" + }, + "404": { + "description": "Organization or team not found" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } } }, @@ -3862,13 +4500,30 @@ "type": "boolean", "example": false }, - "message": { + "message": { + "type": "string", + "example": "Error message" + } + } + }, + "UserBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string", + "description": "Combined first and last name" + }, + "email": { "type": "string", - "example": "Error message" + "format": "email" } } }, - "UserBasic": { + "DepartmentBasic": { "type": "object", "properties": { "id": { @@ -3876,16 +4531,49 @@ "format": "uuid" }, "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { "type": "string", - "description": "Combined first and last name" + "format": "date-time" }, - "email": { + "updatedAt": { "type": "string", - "format": "email" + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "manager": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } } } }, - "DepartmentBasic": { + "DepartmentDetailed": { "type": "object", "properties": { "id": { @@ -3930,133 +4618,591 @@ }, "lastName": { "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "jobTitle": { + "type": "string" + } + } + }, + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserBasic" + } + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + }, + "DepartmentWithCounts": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "_count": { + "type": "object", + "properties": { + "users": { + "type": "integer" + }, + "teams": { + "type": "integer" + } + } + } + } + }, + "CreateTeam": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 50 + }, + "description": { + "type": "string", + "nullable": true, + "maxLength": 500 + }, + "avatar": { + "type": "string", + "nullable": true + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamMemberInput" + } + } + } + }, + "TeamMemberInput": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "string" + }, + "role": { + "type": "string", + "enum": ["MEMBER", "LEADER"], + "default": "MEMBER" + } + } + }, + "TeamCreatedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Team created successfully." + }, + "data": { + "type": "object", + "properties": { + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + } + } + }, + "teamLeader": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "leader": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "teamId": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "isActive": { + "type": "boolean" + } + } + } + } + }, + "teamMembers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } + } + } + } + } + }, + "AddTeamMembers": { + "type": "object", + "required": ["members"], + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamMemberInput" + } + } + } + }, + "TeamMembersResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Members added successfully." + }, + "data": { + "type": "object", + "properties": { + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + } + } + }, + "teamLeader": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "teamMembers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } } } } } }, - "DepartmentDetailed": { + "UpdateTeam": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid" - }, "name": { - "type": "string" + "type": "string", + "minLength": 3, + "maxLength": 50, + "nullable": true }, "description": { - "type": "string" - }, - "createdAt": { "type": "string", - "format": "date-time" + "maxLength": 500, + "nullable": true }, - "updatedAt": { + "avatar": { "type": "string", - "format": "date-time" + "nullable": true + } + } + }, + "TeamsPaginatedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true }, - "organization": { + "data": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid" + "teams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamWithMembers" + } }, - "name": { - "type": "string" + "pagination": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "example": 1 + }, + "limit": { + "type": "integer", + "example": 10 + }, + "totalItems": { + "type": "integer", + "example": 25 + }, + "totalPages": { + "type": "integer", + "example": 3 + } + } } } + } + } + }, + "TeamWithMembers": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/TeamBasic" }, - "manager": { + { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "isActive": { + "type": "boolean" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } }, - "jobTitle": { - "type": "string" - } - } - }, - "users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBasic" - } - }, - "teams": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" + "creator": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } } } } } - } + ] }, - "DepartmentWithCounts": { + "TeamFullResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" + "success": { + "type": "boolean", + "example": true }, - "organization": { + "data": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid" + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "avatar": { + "type": "string", + "nullable": true + }, + "createdBy": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + }, + "department": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "nullable": true + } + } }, - "name": { - "type": "string" - } - } - }, - "_count": { - "type": "object", - "properties": { - "users": { - "type": "integer" + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + }, + "joinedAt": { + "type": "string", + "format": "date-time" + } + } + } }, - "teams": { - "type": "integer" + "projects": { + "type": "array", + "items": { + "type": "object" + } + }, + "recentReports": { + "type": "array", + "items": { + "type": "object" + } + }, + "statistics": { + "type": "object", + "properties": { + "activeMembers": { + "type": "integer" + }, + "totalProjects": { + "type": "integer" + }, + "projectsInProgress": { + "type": "integer" + }, + "completedProjects": { + "type": "integer" + } + } } } } From 99f379fc796ef9d7fbb7b3b839901cf8c3e686ec Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 13:17:28 +0200 Subject: [PATCH 19/22] docs: add team basic schema --- src/docs/swagger.json | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index b281821..2f8e555 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -4700,6 +4700,39 @@ } } }, + "TeamBasic": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "avatar": { + "type": "string", + "nullable": true + }, + "createdBy": { + "type": "string" + }, + "organizationId": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, "CreateTeam": { "type": "object", "required": ["name"], From 87af9458b80eb6704e7182755af7a52d89e0a4b8 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 13:23:26 +0200 Subject: [PATCH 20/22] docs: finish project swagger document --- src/docs/swagger.json | 3715 +++++++++++++++++++++++++++++------------ 1 file changed, 2687 insertions(+), 1028 deletions(-) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 2f8e555..7a8203a 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -4069,1175 +4069,2834 @@ } ] } - } - }, - - "components": { - "securitySchemes": { - "cookieAuth": { - "type": "apiKey", - "in": "cookie", - "name": "refreshToken", - "description": "Refresh token cookie for authentication" - }, - "bearerAuth": { - "type": "http", - "scheme": "bearer", - "bearerFormat": "JWT" - } }, - "schemas": { - "User": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "email": { - "type": "string", - "format": "email" - }, - "username": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "role": { - "type": "string", - "enum": ["MEMBER", "ADMIN", "SUPER_ADMIN"], - "default": "MEMBER" - }, - "isActive": { - "type": "boolean", - "default": false + "/api/organization/{organizationId}/team/{teamId}/project": { + "post": { + "tags": ["Project"], + "summary": "Create a new project", + "description": "Creates a new project within a team. Requires appropriate permissions.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "createdAt": { - "type": "string", - "format": "date-time" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } } - } - }, - "OrganizationWithStats": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "industry": { - "type": "string" - }, - "sizeRange": { - "type": "array", - "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateProject" + } + } + } + }, + "responses": { + "201": { + "description": "Project created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectCreatedResponse" + } + } + } }, - "website": { - "type": "string" + "400": { + "description": "Bad request - Invalid input or validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Validation failed" + }, + "errors": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + } }, - "logoUrl": { - "type": "string" + "403": { + "description": "Forbidden - Insufficient permissions" }, - "status": { - "type": "string" + "404": { + "description": "Not found - Organization or team not found" }, - "isVerified": { - "type": "boolean" + "409": { + "description": "Conflict - Project with this name already exists" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}": { + "put": { + "tags": ["Project"], + "summary": "Update a project", + "description": "Updates an existing project. Requires appropriate permissions (admin, organization owner, team manager, or project owner).", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "createdAt": { - "type": "string", - "format": "date-time" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "statistics": { - "type": "object", - "properties": { - "usersCount": { - "type": "integer" - }, - "departmentsCount": { - "type": "integer" - }, - "teamsCount": { - "type": "integer" - }, - "projectsCount": { - "type": "integer" + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProject" + } + } + } + }, + "responses": { + "200": { + "description": "Project updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProjectUpdatedResponse" + } } } }, - "owners": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" + "400": { + "description": "Bad request - Invalid input or validation error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Validation failed" + }, + "errors": { + "type": "array", + "items": { + "type": "string" + } + } + } } } } - } - } - }, - "OrganizationDetails": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" }, - "name": { - "type": "string" + "403": { + "description": "Forbidden - Insufficient permissions" }, - "description": { - "type": "string" + "404": { + "description": "Not found - Organization, team or project not found" }, - "industry": { - "type": "string" - }, - "sizeRange": { - "type": "array", - "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] - }, - "website": { - "type": "string" - }, - "logoUrl": { - "type": "string" - }, - "status": { - "type": "string" - }, - "isVerified": { - "type": "boolean" - }, - "contactEmail": { - "type": "string", - "format": "email" - }, - "contactPhone": { - "type": "string" - }, - "address": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" + "409": { + "description": "Conflict - Project with this name already exists" + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/status": { + "patch": { + "tags": ["Project"], + "summary": "Update project status", + "description": "Updates the status of an existing project. Requires appropriate permissions (admin, organization owner, team manager, or project owner/manager).", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "updatedAt": { - "type": "string", - "format": "date-time" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "statistics": { - "type": "object", - "properties": { - "usersCount": { - "type": "integer" - }, - "departmentsCount": { - "type": "integer" - }, - "teamsCount": { - "type": "integer" - }, - "projectsCount": { - "type": "integer" - }, - "templatesCount": { - "type": "integer" + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["status"], + "properties": { + "status": { + "type": "string", + "description": "New project status", + "enum": [ + "PLANNING", + "ACTIVE", + "ON_HOLD", + "COMPLETED", + "CANCELED" + ], + "example": "ACTIVE" + } + } } } - }, - "owners": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" - }, - "profileImage": { - "type": "string" + } + }, + "responses": { + "200": { + "description": "Project status updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Project status updated successfully" + }, + "data": { + "$ref": "#/components/schemas/ProjectBasic" + } + } } } } }, - "departments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "usersCount": { - "type": "integer" - }, - "teamsCount": { - "type": "integer" + "400": { + "description": "Bad request - Invalid status or missing status field", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Status is required or must be one of: PLANNING, ACTIVE, ON_HOLD, COMPLETED, CANCELED" + } + } } } } }, - "teams": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "usersCount": { - "type": "integer" - }, - "projectsCount": { - "type": "integer" + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "You do not have permission to update this project's status" + } + } } } } }, - "projects": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "status": { - "type": "string" - }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" + "404": { + "description": "Not found - Organization, team or project not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Project not found" + } + } } } } - }, - "hasMoreDepartments": { - "type": "boolean" - }, - "hasMoreTeams": { - "type": "boolean" - }, - "hasMoreProjects": { - "type": "boolean" } - } - }, - "OrganizationUpdate": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 3, - "maxLength": 100 - }, - "description": { - "type": "string", - "maxLength": 500 - }, - "industry": { - "type": "string", - "maxLength": 50 - }, - "sizeRange": { - "type": "array", - "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] - }, - "website": { - "type": "string", - "format": "uri", - "maxLength": 100 - }, - "logoUrl": { - "type": "string", - "format": "uri", - "maxLength": 255 + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/priority": { + "patch": { + "tags": ["Project"], + "summary": "Update project priority", + "description": "Updates the priority of an existing project. Requires appropriate permissions (admin, organization owner, team manager, or project owner/manager).", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "contactEmail": { - "type": "string", - "format": "email", - "maxLength": 100 + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "contactPhone": { - "type": "string", - "maxLength": 20 + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["priority"], + "properties": { + "priority": { + "type": "string", + "description": "New project priority", + "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"], + "example": "HIGH" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Project priority updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Project priority updated successfully" + }, + "data": { + "$ref": "#/components/schemas/ProjectBasic" + } + } + } + } + } }, - "address": { - "type": "string", - "maxLength": 255 + "400": { + "description": "Bad request - Invalid priority or missing priority field", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string" + } + } + } + } + } }, - "isVerified": { - "type": "boolean" + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "You do not have permission to update this project's priority" + } + } + } + } + } }, - "status": { - "type": "string", - "enum": ["ACTIVE", "PENDING", "SUSPENDED"] + "404": { + "description": "Not found - Organization, team or project not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Project not found" + } + } + } + } + } } - } - }, - "OrganizationBasic": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/delete": { + "delete": { + "tags": ["Project"], + "summary": "Delete a project", + "description": "Soft deletes a project. Requires admin, organization owner, or team manager permissions.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "name": { - "type": "string" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "description": { - "type": "string" + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Project deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Project deleted successfully" + } + } + } + } + } }, - "industry": { - "type": "string" + "400": { + "description": "Bad request - Missing or invalid parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization ID is required" + } + } + } + } + } }, - "sizeRange": { - "type": "array", - "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "You don't have permission to delete projects from this team" + } + } + } + } + } }, - "website": { - "type": "string" - }, - "logoUrl": { - "type": "string" - }, - "status": { - "type": "string" - }, - "isVerified": { - "type": "boolean" - }, - "contactEmail": { - "type": "string", - "format": "email" - }, - "contactPhone": { - "type": "string" - }, - "address": { - "type": "string" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "Pagination": { - "type": "object", - "properties": { - "total": { - "type": "integer" - }, - "page": { - "type": "integer" - }, - "limit": { - "type": "integer" - }, - "pages": { - "type": "integer" + "404": { + "description": "Not found - Organization, team or project not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } + } } - } - }, - "ErrorResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": false - }, - "message": { - "type": "string", - "example": "Error message" + }, + "security": [ + { + "bearerAuth": [] } - } - }, - "UserBasic": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/addMember": { + "post": { + "tags": ["Project"], + "summary": "Add members to a project", + "description": "Adds one or more members to an existing project. Requires admin, organization owner, or team manager permissions.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "name": { - "type": "string", - "description": "Combined first and last name" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "email": { - "type": "string", - "format": "email" + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } } - } - }, - "DepartmentBasic": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "organization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["members"], + "properties": { + "members": { + "type": "array", + "description": "Array of members to add", + "minItems": 1, + "items": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "string", + "description": "ID of the user to add" + }, + "role": { + "type": "string", + "description": "Role to assign to the member", + "enum": [ + "MEMBER", + "CONTRIBUTOR", + "REVIEWER", + "MANAGER" + ], + "default": "MEMBER" + } + } + } + } + } } } - }, - "manager": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" + } + }, + "responses": { + "201": { + "description": "Members added successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Successfully added 3 members to the project" + }, + "data": { + "type": "object", + "properties": { + "count": { + "type": "integer", + "description": "Number of members added", + "example": 3 + }, + "skipped": { + "type": "integer", + "description": "Number of users already members", + "example": 1 + } + } + } + } + } } } - } - } - }, - "DepartmentDetailed": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" }, - "organization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" + "400": { + "description": "Bad request - Invalid input", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } } } }, - "manager": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string", - "format": "email" - }, - "jobTitle": { - "type": "string" + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "You don't have permission to add members to this project" + } + } + } } } }, - "users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBasic" - } - }, - "teams": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" + "404": { + "description": "Not found - Organization, team, project or some users not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "userIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IDs of users that were not found", + "example": ["user123", "user456"] + } + } } } } } - } - }, - "DepartmentWithCounts": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/removeMember": { + "delete": { + "tags": ["Project"], + "summary": "Remove a member from a project", + "description": "Removes a member from a project (soft delete). Requires admin, organization owner, or team manager permissions.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "description": { - "type": "string" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "createdAt": { - "type": "string", - "format": "date-time" + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "string", + "description": "ID of the user to remove from the project" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Member removed successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Member removed from project successfully" + } + } + } + } + } }, - "updatedAt": { - "type": "string", - "format": "date-time" + "400": { + "description": "Bad request - Missing or invalid parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "User ID is required" + } + } + } + } + } }, - "organization": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid" - }, - "name": { - "type": "string" + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "You don't have permission to remove members from this project" + } + } + } } } }, - "_count": { - "type": "object", - "properties": { - "users": { - "type": "integer" - }, - "teams": { - "type": "integer" + "404": { + "description": "Not found - Organization, team, project or user not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } } } } - } - }, - "TeamBasic": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "avatar": { - "type": "string", - "nullable": true - }, - "createdBy": { - "type": "string" - }, - "organizationId": { - "type": "string" + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/restore": { + "patch": { + "tags": ["Project"], + "summary": "Restore a deleted project", + "description": "Restores a previously soft-deleted project. Requires admin, organization owner, or team manager permissions.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "createdAt": { - "type": "string", - "format": "date-time" + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } }, - "updatedAt": { - "type": "string", - "format": "date-time" + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } } - } - }, - "CreateTeam": { - "type": "object", - "required": ["name"], - "properties": { - "name": { - "type": "string", - "minLength": 3, - "maxLength": 50 - }, - "description": { - "type": "string", - "nullable": true, - "maxLength": 500 - }, - "avatar": { - "type": "string", - "nullable": true - }, - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeamMemberInput" - } - } - } - }, - "TeamMemberInput": { - "type": "object", - "required": ["userId"], - "properties": { - "userId": { - "type": "string" - }, - "role": { - "type": "string", - "enum": ["MEMBER", "LEADER"], - "default": "MEMBER" - } - } - }, - "TeamCreatedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Team created successfully." - }, - "data": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - } - } - }, - "teamLeader": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "leader": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "teamId": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { - "type": "string" - }, - "isActive": { - "type": "boolean" - } - } - } - } - }, - "teamMembers": { - "type": "array", - "items": { + ], + "responses": { + "200": { + "description": "Project restored successfully", + "content": { + "application/json": { + "schema": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { - "type": "string" + "success": { + "type": "boolean", + "example": true }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } + "message": { + "type": "string", + "example": "Project restored successfully" } } } } } - } - } - }, - "AddTeamMembers": { - "type": "object", - "required": ["members"], - "properties": { - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeamMemberInput" - } - } - } - }, - "TeamMembersResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true - }, - "message": { - "type": "string", - "example": "Members added successfully." }, - "data": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true + "400": { + "description": "Bad request - Missing or invalid parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization ID is required" + } } } - }, - "teamLeader": { - "type": "object", - "properties": { - "id": { - "type": "string" + } + } + }, + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "You don't have permission to restore projects" + } } } - }, - "teamMembers": { - "type": "array", - "items": { + } + } + }, + "404": { + "description": "Not found - Organization, team or project not found", + "content": { + "application/json": { + "schema": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "userId": { - "type": "string" - }, - "role": { + "message": { "type": "string" - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } } } } } } } - } - }, - "UpdateTeam": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 3, - "maxLength": 50, - "nullable": true - }, - "description": { - "type": "string", - "maxLength": 500, - "nullable": true + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/all": { + "get": { + "tags": ["Project"], + "summary": "Get all projects for a team", + "description": "Retrieves all projects for a specific team. Regular users only see projects they're members of, while admins/owners/managers see all projects.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, - "avatar": { - "type": "string", - "nullable": true + { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } } - } - }, - "TeamsPaginatedResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true + ], + "responses": { + "200": { + "description": "Projects retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectWithMemberCount" + } + } + } + } + } + } }, - "data": { - "type": "object", - "properties": { - "teams": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeamWithMembers" + "400": { + "description": "Bad request - Missing or invalid parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization ID is required" + } + } } - }, - "pagination": { - "type": "object", - "properties": { - "page": { - "type": "integer", - "example": 1 - }, - "limit": { - "type": "integer", - "example": 10 - }, - "totalItems": { - "type": "integer", - "example": 25 - }, - "totalPages": { - "type": "integer", - "example": 3 + } + } + }, + "403": { + "description": "Forbidden - Insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "You don't have permission to view these projects" + } + } + } + } + } + }, + "404": { + "description": "Not found - Organization or team not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Organization or team not found" + } } } } } } - } - }, - "TeamWithMembers": { - "type": "object", - "allOf": [ + }, + "security": [ { - "$ref": "#/components/schemas/TeamBasic" + "bearerAuth": [] + } + ] + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/": { + "get": { + "tags": ["Project"], + "summary": "Get a specific project with details", + "description": "Retrieves detailed information about a specific project including members and tasks. Users must be project members or have team permissions to view.", + "parameters": [ + { + "name": "organizationId", + "in": "path", + "description": "Organization ID", + "required": true, + "schema": { + "type": "string" + } }, { - "type": "object", - "properties": { - "members": { - "type": "array", - "items": { + "name": "teamId", + "in": "path", + "description": "Team ID", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "path", + "description": "Project ID", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Project details retrieved successfully", + "content": { + "application/json": { + "schema": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "role": { - "type": "string" - }, - "isActive": { - "type": "boolean" + "success": { + "type": "boolean", + "example": true }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } + "data": { + "$ref": "#/components/schemas/ProjectDetails" } } } - }, - "creator": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true + } + } + }, + "400": { + "description": "Bad request - Missing or invalid parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "Project ID is required" + } } } } } - } - ] - }, - "TeamFullResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "example": true }, - "data": { - "type": "object", - "properties": { - "team": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string", - "nullable": true - }, - "avatar": { - "type": "string", - "nullable": true - }, - "createdBy": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "creator": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } + "403": { + "description": "Forbidden - User doesn't have permission to view this project", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "example": "You do not have permission to view this project" } - }, - "department": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "nullable": true } } - }, - "members": { - "type": "array", - "items": { + } + } + }, + "404": { + "description": "Not found - Organization, team or project not found", + "content": { + "application/json": { + "schema": { "type": "object", "properties": { - "id": { - "type": "string" - }, - "role": { - "type": "string" - }, - "user": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "firstName": { - "type": "string" - }, - "lastName": { - "type": "string" - }, - "email": { - "type": "string" - }, - "profilePic": { - "type": "string", - "nullable": true - } - } - }, - "joinedAt": { + "message": { "type": "string", - "format": "date-time" + "example": "Project not found" } } } + } + } + } + }, + "security": [ + { + "bearerAuth": [] + } + ] + } + } + }, + + "components": { + "securitySchemes": { + "cookieAuth": { + "type": "apiKey", + "in": "cookie", + "name": "refreshToken", + "description": "Refresh token cookie for authentication" + }, + "bearerAuth": { + "type": "http", + "scheme": "bearer", + "bearerFormat": "JWT" + } + }, + "schemas": { + "User": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "email": { + "type": "string", + "format": "email" + }, + "username": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "role": { + "type": "string", + "enum": ["MEMBER", "ADMIN", "SUPER_ADMIN"], + "default": "MEMBER" + }, + "isActive": { + "type": "boolean", + "default": false + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "OrganizationWithStats": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string" + }, + "logoUrl": { + "type": "string" + }, + "status": { + "type": "string" + }, + "isVerified": { + "type": "boolean" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "statistics": { + "type": "object", + "properties": { + "usersCount": { + "type": "integer" }, - "projects": { - "type": "array", - "items": { - "type": "object" - } + "departmentsCount": { + "type": "integer" }, - "recentReports": { - "type": "array", - "items": { - "type": "object" - } + "teamsCount": { + "type": "integer" }, - "statistics": { - "type": "object", - "properties": { - "activeMembers": { - "type": "integer" - }, - "totalProjects": { - "type": "integer" - }, - "projectsInProgress": { - "type": "integer" - }, - "completedProjects": { - "type": "integer" - } - } + "projectsCount": { + "type": "integer" } } + }, + "owners": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + } + } + } + } + } + }, + "OrganizationDetails": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string" + }, + "logoUrl": { + "type": "string" + }, + "status": { + "type": "string" + }, + "isVerified": { + "type": "boolean" + }, + "contactEmail": { + "type": "string", + "format": "email" + }, + "contactPhone": { + "type": "string" + }, + "address": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "statistics": { + "type": "object", + "properties": { + "usersCount": { + "type": "integer" + }, + "departmentsCount": { + "type": "integer" + }, + "teamsCount": { + "type": "integer" + }, + "projectsCount": { + "type": "integer" + }, + "templatesCount": { + "type": "integer" + } + } + }, + "owners": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "profileImage": { + "type": "string" + } + } + } + }, + "departments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "usersCount": { + "type": "integer" + }, + "teamsCount": { + "type": "integer" + } + } + } + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "usersCount": { + "type": "integer" + }, + "projectsCount": { + "type": "integer" + } + } + } + }, + "projects": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "status": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date-time" + }, + "endDate": { + "type": "string", + "format": "date-time" + } + } + } + }, + "hasMoreDepartments": { + "type": "boolean" + }, + "hasMoreTeams": { + "type": "boolean" + }, + "hasMoreProjects": { + "type": "boolean" + } + } + }, + "OrganizationUpdate": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 100 + }, + "description": { + "type": "string", + "maxLength": 500 + }, + "industry": { + "type": "string", + "maxLength": 50 + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string", + "format": "uri", + "maxLength": 100 + }, + "logoUrl": { + "type": "string", + "format": "uri", + "maxLength": 255 + }, + "contactEmail": { + "type": "string", + "format": "email", + "maxLength": 100 + }, + "contactPhone": { + "type": "string", + "maxLength": 20 + }, + "address": { + "type": "string", + "maxLength": 255 + }, + "isVerified": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": ["ACTIVE", "PENDING", "SUSPENDED"] + } + } + }, + "OrganizationBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "sizeRange": { + "type": "array", + "enum": ["1-10", "11-50", "51-200", "201-500", "501-1000", "1001+"] + }, + "website": { + "type": "string" + }, + "logoUrl": { + "type": "string" + }, + "status": { + "type": "string" + }, + "isVerified": { + "type": "boolean" + }, + "contactEmail": { + "type": "string", + "format": "email" + }, + "contactPhone": { + "type": "string" + }, + "address": { + "type": "string" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "Pagination": { + "type": "object", + "properties": { + "total": { + "type": "integer" + }, + "page": { + "type": "integer" + }, + "limit": { + "type": "integer" + }, + "pages": { + "type": "integer" + } + } + }, + "ErrorResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string", + "example": "Error message" + } + } + }, + "UserBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string", + "description": "Combined first and last name" + }, + "email": { + "type": "string", + "format": "email" + } + } + }, + "DepartmentBasic": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "manager": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + } + } + } + } + }, + "DepartmentDetailed": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "manager": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string", + "format": "email" + }, + "jobTitle": { + "type": "string" + } + } + }, + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserBasic" + } + }, + "teams": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + } + } + }, + "DepartmentWithCounts": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "organization": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + } + }, + "_count": { + "type": "object", + "properties": { + "users": { + "type": "integer" + }, + "teams": { + "type": "integer" + } + } + } + } + }, + "TeamBasic": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "avatar": { + "type": "string", + "nullable": true + }, + "createdBy": { + "type": "string" + }, + "organizationId": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "CreateTeam": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 50 + }, + "description": { + "type": "string", + "nullable": true, + "maxLength": 500 + }, + "avatar": { + "type": "string", + "nullable": true + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamMemberInput" + } + } + } + }, + "TeamMemberInput": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "string" + }, + "role": { + "type": "string", + "enum": ["MEMBER", "LEADER"], + "default": "MEMBER" + } + } + }, + "TeamCreatedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Team created successfully." + }, + "data": { + "type": "object", + "properties": { + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + } + } + }, + "teamLeader": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "leader": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "teamId": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "isActive": { + "type": "boolean" + } + } + } + } + }, + "teamMembers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } + } + } + } + } + }, + "AddTeamMembers": { + "type": "object", + "required": ["members"], + "properties": { + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamMemberInput" + } + } + } + }, + "TeamMembersResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Members added successfully." + }, + "data": { + "type": "object", + "properties": { + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + } + } + }, + "teamLeader": { + "type": "object", + "properties": { + "id": { + "type": "string" + } + } + }, + "teamMembers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } + } + } + } + } + }, + "UpdateTeam": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "nullable": true + }, + "description": { + "type": "string", + "maxLength": 500, + "nullable": true + }, + "avatar": { + "type": "string", + "nullable": true + } + } + }, + "TeamsPaginatedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "data": { + "type": "object", + "properties": { + "teams": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamWithMembers" + } + }, + "pagination": { + "type": "object", + "properties": { + "page": { + "type": "integer", + "example": 1 + }, + "limit": { + "type": "integer", + "example": 10 + }, + "totalItems": { + "type": "integer", + "example": 25 + }, + "totalPages": { + "type": "integer", + "example": 3 + } + } + } + } + } + } + }, + "TeamWithMembers": { + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/TeamBasic" + }, + { + "type": "object", + "properties": { + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "isActive": { + "type": "boolean" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } + }, + "creator": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + } + } + } + ] + }, + "TeamFullResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "data": { + "type": "object", + "properties": { + "team": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "avatar": { + "type": "string", + "nullable": true + }, + "createdBy": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + }, + "department": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "nullable": true + } + } + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "role": { + "type": "string" + }, + "user": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "email": { + "type": "string" + }, + "profilePic": { + "type": "string", + "nullable": true + } + } + }, + "joinedAt": { + "type": "string", + "format": "date-time" + } + } + } + }, + "projects": { + "type": "array", + "items": { + "type": "object" + } + }, + "recentReports": { + "type": "array", + "items": { + "type": "object" + } + }, + "statistics": { + "type": "object", + "properties": { + "activeMembers": { + "type": "integer" + }, + "totalProjects": { + "type": "integer" + }, + "projectsInProgress": { + "type": "integer" + }, + "completedProjects": { + "type": "integer" + } + } + } + } + } + } + }, + "CreateProject": { + "type": "object", + "required": ["name", "startDate", "endDate"], + "properties": { + "name": { + "type": "string", + "description": "Project name", + "minLength": 3, + "maxLength": 100 + }, + "description": { + "type": "string", + "description": "Project description", + "nullable": true, + "maxLength": 1000 + }, + "status": { + "type": "string", + "description": "Project status", + "enum": [ + "PLANNING", + "IN_PROGRESS", + "ON_HOLD", + "COMPLETED", + "CANCELLED" + ], + "default": "PLANNING" + }, + "startDate": { + "type": "string", + "format": "date-time", + "description": "Project start date" + }, + "endDate": { + "type": "string", + "format": "date-time", + "description": "Project end date" + }, + "priority": { + "type": "string", + "description": "Project priority", + "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"], + "default": "MEDIUM" + }, + "budget": { + "type": "number", + "description": "Project budget", + "nullable": true, + "minimum": 0 + }, + "members": { + "type": "array", + "description": "Initial project members", + "items": { + "$ref": "#/components/schemas/ProjectMemberInput" + }, + "default": [] + } + } + }, + "ProjectMemberInput": { + "type": "object", + "required": ["userId"], + "properties": { + "userId": { + "type": "string", + "description": "User ID to add as project member" + }, + "role": { + "type": "string", + "description": "Member role", + "enum": ["MEMBER", "CONTRIBUTOR", "REVIEWER", "MANAGER"], + "default": "MEMBER" + } + } + }, + "ProjectCreatedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Project created successfully." + }, + "data": { + "type": "object", + "properties": { + "project": { + "$ref": "#/components/schemas/ProjectBasic" + }, + "projectOwner": { + "$ref": "#/components/schemas/ProjectMember" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectMember" + } + } + } + } + } + }, + "ProjectBasic": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string" + }, + "startDate": { + "type": "string", + "format": "date-time" + }, + "endDate": { + "type": "string", + "format": "date-time" + }, + "priority": { + "type": "string" + }, + "budget": { + "type": "number", + "nullable": true + }, + "teamId": { + "type": "string" + }, + "organizationId": { + "type": "string" + }, + "progress": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "createdBy": { + "type": "string" + }, + "lastModifiedBy": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "ProjectMember": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "projectId": { + "type": "string" + }, + "userId": { + "type": "string" + }, + "role": { + "type": "string" + }, + "isActive": { + "type": "boolean" + } + } + }, + "UpdateProject": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Project name", + "minLength": 3, + "maxLength": 100 + }, + "description": { + "type": "string", + "description": "Project description", + "nullable": true, + "maxLength": 1000 + }, + "status": { + "type": "string", + "description": "Project status", + "enum": [ + "PLANNING", + "IN_PROGRESS", + "ON_HOLD", + "COMPLETED", + "CANCELLED" + ] + }, + "startDate": { + "type": "string", + "format": "date-time", + "description": "Project start date" + }, + "endDate": { + "type": "string", + "format": "date-time", + "description": "Project end date" + }, + "priority": { + "type": "string", + "description": "Project priority", + "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"] + }, + "budget": { + "type": "number", + "description": "Project budget", + "nullable": true, + "minimum": 0 + }, + "progress": { + "type": "integer", + "description": "Project progress percentage", + "minimum": 0, + "maximum": 100 + } + } + }, + "ProjectUpdatedResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Project updated successfully" + }, + "data": { + "$ref": "#/components/schemas/ProjectBasic" + } + } + }, + "ProjectWithMemberCount": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "PLANNING", + "IN_PROGRESS", + "ON_HOLD", + "COMPLETED", + "CANCELLED" + ] + }, + "startDate": { + "type": "string", + "format": "date-time" + }, + "endDate": { + "type": "string", + "format": "date-time" + }, + "priority": { + "type": "string", + "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"] + }, + "budget": { + "type": "number", + "nullable": true + }, + "teamId": { + "type": "string" + }, + "organizationId": { + "type": "string" + }, + "progress": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "deletedAt": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "memberCount": { + "type": "integer", + "description": "Number of active members in the project" + }, + "userRole": { + "type": "string", + "description": "Current user's role in the project (only for non-admin users)", + "nullable": true, + "enum": [ + "MEMBER", + "CONTRIBUTOR", + "REVIEWER", + "MANAGER", + "PROJECT_OWNER" + ] + } + } + }, + "ProjectDetails": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "status": { + "type": "string", + "enum": [ + "PLANNING", + "IN_PROGRESS", + "ON_HOLD", + "COMPLETED", + "CANCELLED" + ] + }, + "startDate": { + "type": "string", + "format": "date-time" + }, + "endDate": { + "type": "string", + "format": "date-time" + }, + "priority": { + "type": "string", + "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"] + }, + "budget": { + "type": "number", + "nullable": true + }, + "teamId": { + "type": "string" + }, + "organizationId": { + "type": "string" + }, + "progress": { + "type": "integer", + "minimum": 0, + "maximum": 100 + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectMember" + } + }, + "tasks": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectTask" + } + }, + "memberCount": { + "type": "integer" + }, + "taskCount": { + "type": "integer" + }, + "userRole": { + "type": "string", + "nullable": true, + "enum": [ + "MEMBER", + "CONTRIBUTOR", + "REVIEWER", + "MANAGER", + "PROJECT_OWNER" + ] + } + } + }, + "ProjectTask": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "status": { + "type": "string" + }, + "priority": { + "type": "string" + }, + "dueDate": { + "type": "string", + "format": "date-time", + "nullable": true } } } From 4a78d03fd1130fa0463cf83cdf0a20ac10db06d7 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 13:29:10 +0200 Subject: [PATCH 21/22] docs: finish task swagger document --- src/docs/swagger.json | 1547 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1547 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index 7a8203a..fa1658a 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -5281,6 +5281,1530 @@ } ] } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/create": { + "post": { + "tags": ["Task"], + "summary": "Create a new task", + "description": "Create a new task in a specific project within a team and organization.", + "operationId": "createTask", + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["title", "priority", "dueDate"], + "properties": { + "title": { + "type": "string", + "example": "Design login page" + }, + "description": { + "type": "string", + "example": "Create a modern and user-friendly login page UI" + }, + "priority": { + "type": "string", + "example": "HIGH" + }, + "sprintId": { + "type": "string", + "example": "sprint_456" + }, + "assignedTo": { + "type": "string", + "example": "user_123" + }, + "dueDate": { + "type": "string", + "format": "date", + "example": "2025-04-30" + }, + "estimatedTime": { + "type": "integer", + "example": 8 + }, + "parentId": { + "type": "string", + "example": "parent_task_789" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "example": ["frontend", "urgent"] + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Task created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": true + }, + "message": { + "type": "string", + "example": "Task created successfully" + }, + "task": { + "$ref": "#/components/schemas/Task" + }, + "project_members": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ProjectMember" + } + } + } + } + } + } + }, + "400": { + "description": "Bad request" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + }, + "500": { + "description": "Internal Server Error" + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}": { + "put": { + "tags": ["Task"], + "summary": "Update a task", + "description": "Updates an existing task within a specific project, team, and organization. Requires appropriate permissions.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "path", + "required": true, + "description": "ID of the task to update", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "Updated title of the task", + "example": "Updated: Implement user authentication" + }, + "description": { + "type": "string", + "description": "Updated description of the task", + "example": "Updated: Implement JWT based authentication for the API" + }, + "priority": { + "type": "string", + "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"], + "description": "Updated priority level of the task", + "example": "MEDIUM" + }, + "sprintId": { + "type": "string", + "description": "Updated ID of the sprint this task belongs to", + "example": "cln3k7vxp0000v2k0q2q3k4k5" + }, + "assignedTo": { + "type": "string", + "description": "Updated ID of the user this task is assigned to", + "example": "cln3k7vxp0000v2k0q2q3k4k5" + }, + "dueDate": { + "type": "string", + "format": "date-time", + "description": "Updated due date for the task", + "example": "2024-01-15T23:59:59Z" + }, + "estimatedTime": { + "type": "number", + "description": "Updated estimated time to complete the task in hours", + "example": 12 + }, + "parentId": { + "type": "string", + "description": "Updated ID of the parent task if this is a subtask", + "example": "cln3k7vxp0000v2k0q2q3k4k5" + }, + "labels": { + "type": "array", + "items": { "type": "string" }, + "description": "Updated array of labels for the task", + "example": ["backend", "authentication", "security"] + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Task updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "Task updated successfully" + }, + "task": { "$ref": "#/components/schemas/Task" } + } + } + } + } + }, + "400": { + "description": "Validation error or circular dependency detected", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "\"priority\" must be one of [LOW, MEDIUM, HIGH, CRITICAL]" + }, + { + "type": "string", + "example": "A task cannot be its own parent" + }, + { + "type": "string", + "example": "Circular dependency detected in task hierarchy" + } + ] + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "You don't have permission to update tasks in this project" + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team, project, task, sprint or parent task not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { + "type": "string", + "example": "Task not found or does not belong to the specified project" + }, + { + "type": "string", + "example": "Sprint not found or does not belong to the specified project" + }, + { + "type": "string", + "example": "Parent task not found or does not belong to the specified project" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/priority": { + "patch": { + "tags": ["Task"], + "summary": "Update task priority", + "description": "Updates the priority of an existing task within a specific project, team, and organization. Requires appropriate permissions.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "path", + "required": true, + "description": "ID of the task to update", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["priority"], + "properties": { + "priority": { + "type": "string", + "enum": ["HIGH", "MEDIUM", "LOW"], + "description": "New priority level for the task", + "example": "MEDIUM" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Task priority updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "Task priority updated successfully" + }, + "task": { "$ref": "#/components/schemas/Task" } + } + } + } + } + }, + "400": { + "description": "Invalid priority value", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Valid priority (HIGH, MEDIUM, LOW) is required" + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "You don't have permission to update task priorities in this project" + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team, project or task not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { "type": "string", "example": "Team not found" }, + { "type": "string", "example": "Project not found" }, + { + "type": "string", + "example": "Task not found or does not belong to the specified project" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/status": { + "patch": { + "tags": ["Task"], + "summary": "Update task status", + "description": "Updates the status of an existing task within a specific project, team, and organization. Requires appropriate permissions.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "path", + "required": true, + "description": "ID of the task to update", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["status"], + "properties": { + "status": { + "type": "string", + "enum": ["TODO", "IN_PROGRESS", "IN_REVIEW", "DONE"], + "description": "New status for the task", + "example": "IN_PROGRESS" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Task status updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "Task status updated successfully" + }, + "task": { "$ref": "#/components/schemas/Task" } + } + } + } + } + }, + "400": { + "description": "Invalid status value", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Valid status (TODO, IN_PROGRESS, IN_REVIEW, DONE) is required" + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "You don't have permission to update task status in this project" + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team, project or task not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { "type": "string", "example": "Team not found" }, + { "type": "string", "example": "Project not found" }, + { + "type": "string", + "example": "Task not found or does not belong to the specified project" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/all": { + "get": { + "tags": ["Task"], + "summary": "Get all tasks", + "description": "Retrieves all tasks for a specific project with filtering, sorting, and pagination capabilities.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "sprintId", + "in": "query", + "description": "Filter by sprint ID (use 'null' for tasks not in any sprint)", + "schema": { "type": "string" } + }, + { + "name": "priority", + "in": "query", + "description": "Filter by priority (HIGH, MEDIUM, LOW, CRITICAL)", + "schema": { "type": "string" } + }, + { + "name": "status", + "in": "query", + "description": "Filter by status (TODO, IN_PROGRESS, IN_REVIEW, DONE)", + "schema": { "type": "string" } + }, + { + "name": "assignedTo", + "in": "query", + "description": "Filter by assignee ID (use 'null' for unassigned tasks)", + "schema": { "type": "string" } + }, + { + "name": "parentId", + "in": "query", + "description": "Filter by parent task ID (use 'null' for root tasks)", + "schema": { "type": "string" } + }, + { + "name": "search", + "in": "query", + "description": "Search term to filter by task title or description", + "schema": { "type": "string" } + }, + { + "name": "page", + "in": "query", + "description": "Page number for pagination (default: 1)", + "schema": { "type": "integer", "default": 1 } + }, + { + "name": "limit", + "in": "query", + "description": "Number of items per page (default: 20)", + "schema": { "type": "integer", "default": 20 } + }, + { + "name": "sortBy", + "in": "query", + "description": "Field to sort by (default: createdAt)", + "schema": { "type": "string", "default": "createdAt" } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort order (asc or desc, default: desc)", + "schema": { + "type": "string", + "default": "desc", + "enum": ["asc", "desc"] + } + } + ], + "responses": { + "200": { + "description": "List of tasks retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "tasks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "priority": { "type": "string" }, + "status": { "type": "string" }, + "projectId": { "type": "string" }, + "sprintId": { "type": "string" }, + "createdBy": { "type": "string" }, + "assignedTo": { "type": "string" }, + "dueDate": { + "type": "string", + "format": "date-time" + }, + "estimatedTime": { "type": "number" }, + "parentId": { "type": "string" }, + "labels": { + "type": "array", + "items": { "type": "string" } + }, + "order": { "type": "number" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "sprint": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "status": { "type": "string" } + } + }, + "subtasks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "status": { "type": "string" }, + "priority": { "type": "string" } + } + } + }, + "parent": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "status": { "type": "string" } + } + }, + "_count": { + "type": "object", + "properties": { + "comments": { "type": "integer" }, + "attachments": { "type": "integer" } + } + } + } + } + }, + "pagination": { + "type": "object", + "properties": { + "total": { "type": "integer", "example": 100 }, + "page": { "type": "integer", "example": 1 }, + "limit": { "type": "integer", "example": 20 }, + "pages": { "type": "integer", "example": 5 } + } + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team or project not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { "type": "string", "example": "Team not found" }, + { "type": "string", "example": "Project not found" } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/": { + "get": { + "tags": ["Task"], + "summary": "Get a specific task", + "description": "Retrieves detailed information about a specific task including related entities like creator, assignee, subtasks, dependencies, comments, and attachments.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "path", + "required": true, + "description": "ID of the task to retrieve", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Task details retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "task": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "priority": { "type": "string" }, + "status": { "type": "string" }, + "projectId": { "type": "string" }, + "sprintId": { "type": "string" }, + "createdBy": { "type": "string" }, + "assignedTo": { "type": "string" }, + "dueDate": { "type": "string", "format": "date-time" }, + "estimatedTime": { "type": "number" }, + "parentId": { "type": "string" }, + "labels": { + "type": "array", + "items": { "type": "string" } + }, + "order": { "type": "number" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "modifier": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "assignee": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "sprint": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "status": { "type": "string" }, + "startDate": { + "type": "string", + "format": "date-time" + }, + "endDate": { + "type": "string", + "format": "date-time" + } + } + }, + "subtasks": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "status": { "type": "string" }, + "priority": { "type": "string" }, + "assignedTo": { "type": "string" }, + "dueDate": { + "type": "string", + "format": "date-time" + }, + "assignee": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" } + } + } + } + } + }, + "parent": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "status": { "type": "string" }, + "priority": { "type": "string" } + } + }, + "dependentOn": { + "type": "array", + "items": { + "type": "object", + "properties": { + "task": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "status": { "type": "string" } + } + } + } + } + }, + "dependencies": { + "type": "array", + "items": { + "type": "object", + "properties": { + "dependentTask": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "status": { "type": "string" } + } + } + } + } + }, + "comments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "content": { "type": "string" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "profilePic": { "type": "string" } + } + } + } + } + }, + "attachments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "url": { "type": "string" }, + "size": { "type": "number" }, + "type": { "type": "string" }, + "uploadedAt": { + "type": "string", + "format": "date-time" + }, + "uploader": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "profilePic": { "type": "string" } + } + } + } + } + } + } + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team, project or task not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { "type": "string", "example": "Team not found" }, + { "type": "string", "example": "Project not found" }, + { + "type": "string", + "example": "Task not found or does not belong to the specified project" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/delete": { + "delete": { + "tags": ["Task"], + "summary": "Delete a task", + "description": "Deletes a task either permanently (for admins) or via soft delete. Handles subtasks recursively.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "path", + "required": true, + "description": "ID of the task to delete", + "schema": { "type": "string" } + }, + { + "name": "permanent", + "in": "query", + "description": "Whether to permanently delete (true) or soft delete (false). Requires admin privileges.", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Task deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "Task permanently deleted successfully" + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "You don't have permission to delete tasks in this project" + }, + { + "type": "string", + "example": "Only administrators or organization owners can permanently delete tasks" + } + ] + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team, project or task not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { "type": "string", "example": "Team not found" }, + { "type": "string", "example": "Project not found" }, + { + "type": "string", + "example": "Task not found or does not belong to the specified project" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/team/{teamId}/project/{projectId}/task/{taskId}/restore": { + "patch": { + "tags": ["Task"], + "summary": "Restore a deleted task", + "description": "Restores a soft-deleted task and optionally its subtasks. Requires the parent task to be active if the task has one.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "path", + "required": true, + "description": "ID of the team", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "path", + "required": true, + "description": "ID of the project", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "path", + "required": true, + "description": "ID of the task to restore", + "schema": { "type": "string" } + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "restoreSubtasks": { + "type": "boolean", + "description": "Whether to restore all deleted subtasks (default: true)", + "default": true + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Task restored successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "message": { + "type": "string", + "example": "Task restored successfully with its subtasks" + }, + "task": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "priority": { "type": "string" }, + "status": { "type": "string" }, + "projectId": { "type": "string" }, + "sprintId": { "type": "string" }, + "createdBy": { "type": "string" }, + "assignedTo": { "type": "string" }, + "dueDate": { "type": "string", "format": "date-time" }, + "estimatedTime": { "type": "number" }, + "parentId": { "type": "string" }, + "labels": { + "type": "array", + "items": { "type": "string" } + }, + "order": { "type": "number" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "deletedAt": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "_count": { + "type": "object", + "properties": { + "subtasks": { "type": "number" } + } + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad request - parent task is deleted", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Cannot restore task because its parent task is deleted. Please restore the parent task first." + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "You don't have permission to restore tasks in this project" + } + } + } + } + } + }, + "404": { + "description": "Not found - organization, team, project or task not found or already active", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Task not found, already active, or does not belong to the specified project" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } } }, @@ -6899,6 +8423,29 @@ "nullable": true } } + }, + "Task": { + "type": "object", + "properties": { + "id": { "type": "string", "example": "task_123" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "priority": { "type": "string" }, + "status": { "type": "string", "example": "TODO" }, + "projectId": { "type": "string" }, + "sprintId": { "type": "string" }, + "createdBy": { "type": "string" }, + "assignedTo": { "type": "string" }, + "dueDate": { "type": "string", "format": "date" }, + "estimatedTime": { "type": "integer" }, + "parentId": { "type": "string" }, + "order": { "type": "integer" }, + "labels": { + "type": "array", + "items": { "type": "string" } + }, + "lastModifiedBy": { "type": "string" } + } } } } From ef66a96944cfc85838ff1a663849481f8ad2ded0 Mon Sep 17 00:00:00 2001 From: Mohamed Dawoud Date: Mon, 21 Apr 2025 13:32:21 +0200 Subject: [PATCH 22/22] docs: finish activity logs swagger document --- src/docs/swagger.json | 594 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 594 insertions(+) diff --git a/src/docs/swagger.json b/src/docs/swagger.json index fa1658a..ca0b4ba 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -6805,6 +6805,600 @@ } } } + }, + "/api/organization/{organizationId}/activity-logs": { + "get": { + "tags": ["Activity Logs"], + "summary": "Get activity logs with filtering", + "description": "Retrieves activity logs with various filtering, sorting, and pagination options. Requires 'view activity logs' permission.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "in": "query", + "description": "Filter by entity type (ORGANIZATION, DEPARTMENT, TEAM, PROJECT, SPRINT, TASK)", + "schema": { "type": "string" } + }, + { + "name": "action", + "in": "query", + "description": "Filter by action type (CREATE, UPDATE, DELETE, etc.)", + "schema": { "type": "string" } + }, + { + "name": "userId", + "in": "query", + "description": "Filter by user ID who performed the action", + "schema": { "type": "string" } + }, + { + "name": "departmentId", + "in": "query", + "description": "Filter by department ID", + "schema": { "type": "string" } + }, + { + "name": "teamId", + "in": "query", + "description": "Filter by team ID", + "schema": { "type": "string" } + }, + { + "name": "projectId", + "in": "query", + "description": "Filter by project ID", + "schema": { "type": "string" } + }, + { + "name": "sprintId", + "in": "query", + "description": "Filter by sprint ID", + "schema": { "type": "string" } + }, + { + "name": "taskId", + "in": "query", + "description": "Filter by task ID", + "schema": { "type": "string" } + }, + { + "name": "startDate", + "in": "query", + "description": "Filter logs after this date (YYYY-MM-DD or ISO format)", + "schema": { "type": "string", "format": "date-time" } + }, + { + "name": "endDate", + "in": "query", + "description": "Filter logs before this date (YYYY-MM-DD or ISO format)", + "schema": { "type": "string", "format": "date-time" } + }, + { + "name": "page", + "in": "query", + "description": "Page number for pagination (default: 1)", + "schema": { "type": "integer", "default": 1 } + }, + { + "name": "limit", + "in": "query", + "description": "Number of items per page (default: 50)", + "schema": { "type": "integer", "default": 50 } + }, + { + "name": "sortBy", + "in": "query", + "description": "Field to sort by (createdAt, entityType, action) (default: createdAt)", + "schema": { "type": "string", "default": "createdAt" } + }, + { + "name": "sortOrder", + "in": "query", + "description": "Sort order (asc or desc) (default: desc)", + "schema": { + "type": "string", + "default": "desc", + "enum": ["asc", "desc"] + } + } + ], + "responses": { + "200": { + "description": "Activity logs retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "count": { "type": "integer", "example": 25 }, + "total": { "type": "integer", "example": 125 }, + "pagination": { + "type": "object", + "properties": { + "currentPage": { "type": "integer", "example": 1 }, + "totalPages": { "type": "integer", "example": 5 }, + "hasNextPage": { "type": "boolean", "example": true }, + "hasPreviousPage": { + "type": "boolean", + "example": false + }, + "limit": { "type": "integer", "example": 25 } + } + }, + "activityLogs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "entityType": { "type": "string" }, + "entityId": { "type": "string" }, + "action": { "type": "string" }, + "oldValue": { "type": "object" }, + "newValue": { "type": "object" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "organization": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "department": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "team": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "project": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "sprint": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "task": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" } + } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "You do not have permission to view activity logs" + } + } + } + } + } + }, + "404": { + "description": "Not found - organization not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Organization not found" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/activity-logs/{logId}": { + "get": { + "tags": ["Activity Logs"], + "summary": "Get a specific activity log by ID", + "description": "Retrieves detailed information about a specific activity log. Requires 'view activity logs' permission.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "logId", + "in": "path", + "required": true, + "description": "ID of the activity log to retrieve", + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Activity log retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "activityLog": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "entityType": { "type": "string" }, + "entityId": { "type": "string" }, + "action": { "type": "string" }, + "oldValue": { "type": "object" }, + "newValue": { "type": "object" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "email": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "organization": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "department": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "team": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "project": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "sprint": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" } + } + }, + "task": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "description": { "type": "string" }, + "status": { "type": "string" }, + "priority": { "type": "string" } + } + } + } + } + } + } + } + } + }, + "403": { + "description": "Forbidden - insufficient permissions", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "You do not have permission to view activity logs" + } + } + } + } + } + }, + "404": { + "description": "Not found - organization or activity log not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { + "type": "string", + "example": "Organization not found" + }, + { + "type": "string", + "example": "Activity log not found" + } + ] + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } + }, + "/api/organization/{organizationId}/activity-feed": { + "get": { + "tags": ["Activity Logs"], + "summary": "Get activity feed for an entity", + "description": "Retrieves a paginated activity feed for a specific entity (task, project, etc.) with cursor-based pagination.", + "security": [{ "BearerAuth": [] }], + "parameters": [ + { + "name": "organizationId", + "in": "path", + "required": true, + "description": "ID of the organization", + "schema": { "type": "string" } + }, + { + "name": "entityType", + "in": "query", + "description": "Type of entity to filter by (ORGANIZATION, DEPARTMENT, TEAM, PROJECT, SPRINT, TASK, USER)", + "schema": { + "type": "string", + "enum": [ + "ORGANIZATION", + "DEPARTMENT", + "TEAM", + "PROJECT", + "SPRINT", + "TASK", + "USER" + ] + } + }, + { + "name": "entityId", + "in": "query", + "description": "ID of the entity to filter by (required if entityType is provided)", + "schema": { "type": "string" } + }, + { + "name": "limit", + "in": "query", + "description": "Number of items to return (default: 20)", + "schema": { + "type": "integer", + "default": 20 + } + }, + { + "name": "before", + "in": "query", + "description": "Cursor for pagination (ISO timestamp of the last item from previous request)", + "schema": { + "type": "string", + "format": "date-time" + } + } + ], + "responses": { + "200": { + "description": "Activity feed retrieved successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": true }, + "activityFeed": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "message": { "type": "string" }, + "user": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "profilePic": { "type": "string" } + } + }, + "entityType": { "type": "string" }, + "action": { "type": "string" }, + "details": { "type": "object" }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "entityData": { "type": "object" } + } + } + }, + "pagination": { + "type": "object", + "properties": { + "nextCursor": { + "type": "string", + "format": "date-time", + "description": "Timestamp to use for next page pagination" + }, + "hasMore": { + "type": "boolean", + "description": "Whether there are more items available" + } + } + } + } + } + } + } + }, + "400": { + "description": "Bad request - invalid parameters", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "oneOf": [ + { "type": "string", "example": "Invalid entity type" }, + { + "type": "string", + "example": "entityId is required when entityType is provided" + } + ] + } + } + } + } + } + }, + "404": { + "description": "Not found - organization not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Organization not found" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { "type": "boolean", "example": false }, + "message": { + "type": "string", + "example": "Internal server error" + } + } + } + } + } + } + } + } } },