Files
web-hosts/domains/coppertone.tech/docs/api/work-management-service.md
2025-12-26 13:38:04 +01:00

21 KiB

Work Management Service API Documentation

Base URL: /api/work (via gateway) or http://localhost:8083 (direct)

Service Port: 8083

Overview

The Work Management Service handles all project, task, and work order management for the Coppertone.tech platform. It provides:

  • Project management with approval workflow
  • Task tracking with assignments and time tracking
  • Work orders with IPFS document integration
  • Role-based access control (RBAC)

Authentication

All endpoints require a valid JWT token in the Authorization header:

Authorization: Bearer <jwt_token>

The token is validated against the auth-service and must contain:

  • user_id / userId: User identifier
  • roles: Array of user roles

Role-Based Access

Role Projects Tasks Work Orders
SUPERUSER Full access Full access Full access
ADMIN Full access Full access Full access
STAFF Full access Full access Full access
CLIENT Own projects only Tasks on own projects No access

Note: SUPERUSER role automatically grants full access to all endpoints.


Health Check

GET /healthz

Response:

200 OK
ok

Projects

List Projects

Retrieve a list of approved projects. CLIENTs see only their own projects.

GET /projects

Headers:

Authorization: Bearer <token>

Required Role: Any authenticated user

Response (200 OK):

[
  {
    "id": 1,
    "name": "Website Redesign",
    "description": "Complete redesign of corporate website",
    "status": "IN_PROGRESS",
    "clientId": 5,
    "ipfsMetadataCid": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
    "startDate": "2024-01-15",
    "endDate": "2024-03-15",
    "requestedBy": 5,
    "approvedBy": 2,
    "approvalStatus": "APPROVED",
    "approvalDate": "2024-01-10T14:30:00Z",
    "rejectionReason": null,
    "createdAt": "2024-01-05T10:00:00Z",
    "updatedAt": "2024-01-20T09:15:00Z"
  }
]

Authorization Logic:

  • STAFF/ADMIN/SUPERUSER: See all approved projects
  • CLIENT: See only projects where client_id matches their user ID

Get Project by ID

Retrieve a single project by ID.

GET /projects/{id}

Headers:

Authorization: Bearer <token>

Required Role: Any authenticated user (with access)

Path Parameters:

Parameter Type Description
id integer Project ID

Response (200 OK):

{
  "id": 1,
  "name": "Website Redesign",
  "description": "Complete redesign of corporate website",
  "status": "IN_PROGRESS",
  "clientId": 5,
  "ipfsMetadataCid": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
  "startDate": "2024-01-15",
  "endDate": "2024-03-15",
  "requestedBy": 5,
  "approvedBy": 2,
  "approvalStatus": "APPROVED",
  "approvalDate": "2024-01-10T14:30:00Z",
  "rejectionReason": null,
  "createdAt": "2024-01-05T10:00:00Z",
  "updatedAt": "2024-01-20T09:15:00Z"
}

Error Responses:

Status Condition Response
400 Invalid ID Invalid project ID
403 No access Forbidden: you do not have access to this project
404 Not found Project not found

Authorization Logic:

  • User must be: project owner (client_id), requester (requested_by), or STAFF/ADMIN/SUPERUSER

Create Project

Create a new project. Projects created by STAFF/ADMIN are auto-approved.

POST /projects

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Request Body:

{
  "name": "New Mobile App",
  "description": "iOS and Android app development",
  "status": "PLANNING",
  "clientId": 5,
  "ipfsMetadataCid": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
  "startDate": "2024-02-01",
  "endDate": "2024-06-30"
}
Field Type Required Default Description
name string Yes - Project name
description string No - Project description
status string No PLANNING Project status
clientId integer No - Assigned client user ID
ipfsMetadataCid string No - IPFS CID for metadata
startDate string No - Planned start date (YYYY-MM-DD)
endDate string No - Planned end date (YYYY-MM-DD)

Valid Status Values:

  • PLANNING
  • IN_PROGRESS
  • ON_HOLD
  • COMPLETED
  • CANCELLED

Response (201 Created):

{
  "id": 2,
  "name": "New Mobile App",
  "description": "iOS and Android app development",
  "status": "PLANNING",
  "clientId": 5,
  "ipfsMetadataCid": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
  "startDate": "2024-02-01",
  "endDate": "2024-06-30",
  "requestedBy": 2,
  "approvedBy": 2,
  "approvalStatus": "APPROVED",
  "approvalDate": "2024-01-25T12:00:00Z",
  "rejectionReason": null,
  "createdAt": "2024-01-25T12:00:00Z",
  "updatedAt": "2024-01-25T12:00:00Z"
}

Error Responses:

Status Condition Response
400 Missing name Project name is required
403 Insufficient role Insufficient permissions

Update Project

Update an existing project.

PUT /projects/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER (or project owner)

Path Parameters:

Parameter Type Description
id integer Project ID

Request Body:

{
  "name": "Updated Project Name",
  "description": "Updated description",
  "status": "IN_PROGRESS",
  "clientId": 5,
  "ipfsMetadataCid": "QmNewCid...",
  "startDate": "2024-02-01",
  "endDate": "2024-07-31"
}

Response (200 OK):

{
  "id": 1,
  "name": "Updated Project Name",
  ...
}

Error Responses:

Status Condition Response
403 No permission Forbidden: you do not have permission to update this project
404 Not found Project not found

Delete Project

Delete a project. Only STAFF/ADMIN can delete projects.

DELETE /projects/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Path Parameters:

Parameter Type Description
id integer Project ID

Response (204 No Content)

Error Responses:

Status Condition Response
403 No permission Forbidden: only STAFF or ADMIN can delete projects
404 Not found Project not found

Project Requests (Client Workflow)

CLIENTs can request new projects, which require STAFF/ADMIN approval.

List My Project Requests

Retrieve all project requests made by the current user.

GET /project-requests

Headers:

Authorization: Bearer <token>

Required Role: Any authenticated user

Response (200 OK):

[
  {
    "id": 3,
    "name": "New Feature Request",
    "description": "We need a new dashboard feature",
    "status": "PENDING_APPROVAL",
    "clientId": 5,
    "requestedBy": 5,
    "approvedBy": null,
    "approvalStatus": "PENDING",
    "approvalDate": null,
    "rejectionReason": null,
    "createdAt": "2024-01-25T10:00:00Z",
    "updatedAt": "2024-01-25T10:00:00Z"
  }
]

Create Project Request

Submit a new project request for approval.

POST /project-requests

Headers:

Authorization: Bearer <token>

Required Role: Any authenticated user

Request Body:

{
  "name": "Custom Integration Project",
  "description": "We need to integrate our CRM with the platform. This should include bidirectional sync and real-time updates."
}
Field Type Required Description
name string Yes Project name
description string Yes Detailed description of the project request

Response (201 Created):

{
  "id": 4,
  "name": "Custom Integration Project",
  "description": "We need to integrate our CRM with the platform...",
  "status": "PENDING_APPROVAL",
  "clientId": 5,
  "requestedBy": 5,
  "approvalStatus": "PENDING",
  "createdAt": "2024-01-25T14:30:00Z",
  "updatedAt": "2024-01-25T14:30:00Z"
}

Error Responses:

Status Condition Response
400 Missing name Project name is required
400 Missing description Project description is required to help us understand your needs

Get Project Request

Retrieve a specific project request.

GET /project-requests/{id}

Headers:

Authorization: Bearer <token>

Required Role: Request owner, or STAFF/ADMIN/SUPERUSER

Response (200 OK):

{
  "id": 4,
  "name": "Custom Integration Project",
  "description": "...",
  "status": "PENDING_APPROVAL",
  "approvalStatus": "PENDING",
  ...
}

Cancel Project Request

Cancel a pending project request.

DELETE /project-requests/{id}

Headers:

Authorization: Bearer <token>

Required Role: Request owner only (cannot cancel after approval)

Response (204 No Content)

Error Responses:

Status Condition Response
403 Not owner Forbidden: you can only cancel your own requests
403 Already processed Cannot cancel: request has already been processed
404 Not found Project request not found

Project Approval (Admin Workflow)

List Pending Projects

Retrieve all projects pending approval.

GET /projects/pending

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Response (200 OK):

[
  {
    "id": 4,
    "name": "Custom Integration Project",
    "description": "...",
    "status": "PENDING_APPROVAL",
    "clientId": 5,
    "requestedBy": 5,
    "approvalStatus": "PENDING",
    "createdAt": "2024-01-25T14:30:00Z",
    "updatedAt": "2024-01-25T14:30:00Z"
  }
]

Approve or Reject Project

Approve or reject a pending project request.

POST /projects/approve/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Path Parameters:

Parameter Type Description
id integer Project ID

Request Body (Approve):

{
  "action": "approve"
}

Request Body (Reject):

{
  "action": "reject",
  "reason": "The requested scope is too broad. Please break this into smaller projects."
}
Field Type Required Description
action string Yes approve or reject
reason string If rejecting Reason for rejection

Response (200 OK - Approved):

{
  "message": "Project approved successfully",
  "project": {
    "id": 4,
    "name": "Custom Integration Project",
    "status": "PLANNING",
    "approvalStatus": "APPROVED",
    "approvedBy": 2,
    "approvalDate": "2024-01-26T09:00:00Z",
    ...
  }
}

Response (200 OK - Rejected):

{
  "message": "Project rejected",
  "project": {
    "id": 4,
    "name": "Custom Integration Project",
    "status": "CANCELLED",
    "approvalStatus": "REJECTED",
    "rejectionReason": "The requested scope is too broad...",
    ...
  }
}

Error Responses:

Status Condition Response
400 Invalid action Invalid action. Must be 'approve' or 'reject'
400 Missing reason Rejection reason is required
400 Not pending Project is not pending approval
404 Not found Project not found

Tasks

List Tasks

Retrieve tasks, optionally filtered by project.

GET /tasks
GET /tasks?project_id=1

Headers:

Authorization: Bearer <token>

Required Role: Any authenticated user

Query Parameters:

Parameter Type Description
project_id integer Optional. Filter tasks by project

Response (200 OK):

[
  {
    "id": 1,
    "projectId": 1,
    "title": "Design Homepage Mockup",
    "description": "Create wireframes and visual design for homepage",
    "status": "IN_PROGRESS",
    "assigneeId": 3,
    "dueDate": "2024-02-01",
    "completedAt": null,
    "priority": 2,
    "estimatedHours": 8.0,
    "actualHours": 3.5,
    "createdAt": "2024-01-20T10:00:00Z",
    "updatedAt": "2024-01-25T14:00:00Z"
  }
]

Authorization Logic:

  • STAFF/ADMIN/SUPERUSER: See all tasks (optionally filtered)
  • CLIENT: See only tasks for projects they own

Get Task by ID

Retrieve a single task.

GET /tasks/{id}

Headers:

Authorization: Bearer <token>

Required Role: Any authenticated user (with access to parent project)

Response (200 OK):

{
  "id": 1,
  "projectId": 1,
  "title": "Design Homepage Mockup",
  "description": "Create wireframes and visual design for homepage",
  "status": "IN_PROGRESS",
  "assigneeId": 3,
  "dueDate": "2024-02-01",
  "completedAt": null,
  "priority": 2,
  "estimatedHours": 8.0,
  "actualHours": 3.5,
  "createdAt": "2024-01-20T10:00:00Z",
  "updatedAt": "2024-01-25T14:00:00Z"
}

Error Responses:

Status Condition Response
403 No access Forbidden: you do not have access to this task
404 Not found Task not found

Create Task

Create a new task for a project.

POST /tasks

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Request Body:

{
  "projectId": 1,
  "title": "Implement API Endpoints",
  "description": "Create REST endpoints for user management",
  "status": "TODO",
  "assigneeId": 3,
  "dueDate": "2024-02-15",
  "priority": 1,
  "estimatedHours": 16.0
}
Field Type Required Default Description
projectId integer Yes - Parent project ID
title string Yes - Task title
description string No - Task description
status string No TODO Task status
assigneeId integer No - Assigned user ID
dueDate string No - Due date (YYYY-MM-DD)
priority integer No 0 Priority (higher = more important)
estimatedHours float No - Estimated hours to complete

Valid Status Values:

  • TODO
  • IN_PROGRESS
  • REVIEW
  • COMPLETED
  • BLOCKED

Response (201 Created):

{
  "id": 5,
  "projectId": 1,
  "title": "Implement API Endpoints",
  "status": "TODO",
  ...
}

Error Responses:

Status Condition Response
400 Missing fields Task title and project_id are required
403 No permission Insufficient permissions

Update Task

Update an existing task.

PUT /tasks/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Request Body:

{
  "title": "Implement API Endpoints",
  "description": "Updated description",
  "status": "COMPLETED",
  "assigneeId": 3,
  "dueDate": "2024-02-15",
  "priority": 1,
  "estimatedHours": 16.0,
  "actualHours": 14.5
}

Special Behavior:

  • Setting status to COMPLETED automatically sets completedAt timestamp
  • Setting status to anything else clears completedAt

Response (200 OK):

{
  "id": 5,
  "projectId": 1,
  "title": "Implement API Endpoints",
  "status": "COMPLETED",
  "completedAt": "2024-02-14T16:30:00Z",
  ...
}

Delete Task

Delete a task.

DELETE /tasks/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Response (204 No Content)


Work Orders

Work orders are internal documents for tracking billable work. STAFF/ADMIN only.

List Work Orders

Retrieve work orders, optionally filtered by project.

GET /workorders
GET /workorders?project_id=1

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Query Parameters:

Parameter Type Description
project_id integer Optional. Filter by project

Response (200 OK):

[
  {
    "id": 1,
    "projectId": 1,
    "title": "Initial Setup and Configuration",
    "description": "Server setup, environment configuration, CI/CD pipeline",
    "orderNumber": "WO-2024-001",
    "ipfsDocumentCid": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
    "createdBy": 2,
    "createdAt": "2024-01-20T10:00:00Z",
    "updatedAt": "2024-01-20T10:00:00Z"
  }
]

Get Work Order by ID

GET /workorders/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Response (200 OK):

{
  "id": 1,
  "projectId": 1,
  "title": "Initial Setup and Configuration",
  "description": "Server setup, environment configuration, CI/CD pipeline",
  "orderNumber": "WO-2024-001",
  "ipfsDocumentCid": "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco",
  "createdBy": 2,
  "createdAt": "2024-01-20T10:00:00Z",
  "updatedAt": "2024-01-20T10:00:00Z"
}

Create Work Order

POST /workorders

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Request Body:

{
  "projectId": 1,
  "title": "Database Migration",
  "description": "Migrate from PostgreSQL 14 to 16",
  "orderNumber": "WO-2024-002",
  "ipfsDocumentCid": "QmNewCid...",
  "createdBy": 2
}
Field Type Required Description
projectId integer Yes Parent project ID
title string Yes Work order title
orderNumber string Yes Unique order number
description string No Work order description
ipfsDocumentCid string No IPFS CID for attached document
createdBy integer No User ID who created the work order

Response (201 Created):

{
  "id": 2,
  "projectId": 1,
  "title": "Database Migration",
  "orderNumber": "WO-2024-002",
  ...
}

Error Responses:

Status Condition Response
400 Missing fields Work order title, project_id, and order_number are required
409 Duplicate order number Work order number already exists

Update Work Order

PUT /workorders/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Request Body:

{
  "title": "Updated Title",
  "description": "Updated description",
  "orderNumber": "WO-2024-002",
  "ipfsDocumentCid": "QmUpdatedCid..."
}

Response (200 OK)


Delete Work Order

DELETE /workorders/{id}

Headers:

Authorization: Bearer <token>

Required Role: STAFF, ADMIN, or SUPERUSER

Response (204 No Content)


CORS Configuration

Same as auth-service:

Header Value
Access-Control-Allow-Origin Configured via CORS_ALLOW_ORIGIN env var
Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers Content-Type, Authorization
Access-Control-Allow-Credentials true

Environment Variables

Variable Required Default Description
JWT_SECRET Yes - Secret key for JWT validation (must match auth-service)
DB_HOST Yes - PostgreSQL host
DB_USER Yes - PostgreSQL user
DB_PASSWORD Yes - PostgreSQL password
DB_NAME Yes - PostgreSQL database name
DB_SSL_MODE No require SSL mode
DB_SCHEMA No public Schema: dev, testing, prod
CORS_ALLOW_ORIGIN No http://localhost:8090 Allowed CORS origin

Database Tables

projects

CREATE TABLE projects (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    status VARCHAR(50) DEFAULT 'PLANNING',
    client_id INTEGER REFERENCES users(id),
    ipfs_metadata_cid VARCHAR(100),
    start_date DATE,
    end_date DATE,
    requested_by INTEGER REFERENCES users(id),
    approved_by INTEGER REFERENCES users(id),
    approval_status VARCHAR(20) DEFAULT 'APPROVED',
    approval_date TIMESTAMP,
    rejection_reason TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

tasks

CREATE TABLE tasks (
    id SERIAL PRIMARY KEY,
    project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    status VARCHAR(50) DEFAULT 'TODO',
    assignee_id INTEGER REFERENCES users(id),
    due_date DATE,
    completed_at TIMESTAMP,
    priority INTEGER DEFAULT 0,
    estimated_hours DECIMAL(5,2),
    actual_hours DECIMAL(5,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

work_orders

CREATE TABLE work_orders (
    id SERIAL PRIMARY KEY,
    project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    order_number VARCHAR(50) NOT NULL UNIQUE,
    ipfs_document_cid VARCHAR(100),
    created_by INTEGER REFERENCES users(id),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);