Jump to [Database Documentation](#database-documentation)

# LCC Backend API Documentation

**API Version:** v1.0  
**Last Updated:** March 16, 2025

## Table of Contents

1. [Overview API](#overview-api)
2. [Authentication](#authentication)
3. [Request and Response Conventions](#request-and-response-conventions)
4. [System Configuration Endpoints](#system-configuration-endpoints)
5. [Transportation Rate Endpoints](#transportation-rate-endpoints)
6. [User Management Endpoints](#user-management-endpoints)
7. [Calculation Endpoints](#calculation-endpoints)
8. [Reporting Endpoints](#reporting-endpoints)
9. [Glossary](#glossary)

## Overview API

This document provides a comprehensive description of the LCC Backend API endpoints, their functionality, parameters, and response formats. The API is structured around several core domains: System Configuration, Transportation Rates, User Management, and Calculation.

## Authentication

### Authentication Methods 

The LCC API uses two primary authentication methods:

1. **Pre-Shared Key (PSK)** \- Required for administrative endpoints such as User Management
2. **Session-based Authentication** \- Standard user authentication for most operations

#### Pre-Shared Key Authentication

For endpoints that require PSK authentication, include the following header in your request:

```javascript
Authorization: PSK your_psk_here
```

Contact your system administrator to obtain a valid PSK.

#### Session-based Authentication

Most API endpoints require a valid session, which can be obtained by authenticating through the organization's identity provider.

## Request and Response Conventions

### Common Response Format

All API responses follow a consistent structure.

#### Success Response

- HTTP Status Code: 200 OK
- Response Body: Varies by endpoint (details provided in specific endpoint documentation)

#### Error Response

- HTTP Status Code: Varies (400, 401, 403, 404, 500, etc.)
- Response Body:

```javascript
{
  "error": {
    "code": "ERROR_CODE",
    "message": "User-friendly message",
    "details": { }
  }
}
```

### Common HTTP Status Codes

| Status Code | Description |
| :---- | :---- |
| 200 | Success |
| 400 | Bad Request (client error) |
| 401 | Unauthorized (authentication required) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Resource Not Found |
| 409 | Conflict (e.g., resource already exists) |
| 500 | Internal Server Error |

### Pagination

Endpoints that return lists of resources support pagination using the following query parameters:

- `limit`: Maximum number of items to return (default: 20, maximum: 100\)
- `offset`: Number of items to skip for pagination (default: 0\)

Example: `/api/materials?limit=20&offset=40` will return items 41-60.

Pagination metadata is included in the response header:

```javascript
X-Total-Count: 243
X-Page-Count: 13
X-Current-Page: 3
```

## System Configuration Endpoints {#system-configuration-endpoints}

### Bulk Operations

#### Upload Template Data

- **URL**: `/api/bulk/upload/{$type}`
- **Method**: POST
- **Description**: Uploads a filled-out template for batch processing
- **Path Parameters**:
    - `$type`: The type of data being uploaded (valid values: `container_rate`, `country_matrix`, `material`, `packaging`, `node`)
- **Response**: Returns a processing ID for status tracking

#### Get Template

- **URL**: `/api/bulk/templates/{$type}`
- **Method**: GET
- **Description**: Returns a template for the specified data type
- **Path Parameters**:
    - `$type`: The template type (valid values: `container_rate`, `country_matrix`, `material`, `packaging`, `node`)

#### Check Processing Status

- **URL**: `/api/bulk/status/{$processing_id}`
- **Method**: GET
- **Description**: Returns the processing status of a bulk upload
- **Path Parameters**:
    - `$processing_id`: The ID returned from a bulk upload request

### Materials Management

#### List Materials

- **URL**: `/api/materials/`
- **Method**: GET
- **Description**: Returns a list of all materials
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "part_number": "string",
    "name": "string"
  },
  ...
]
```

#### Get Material Details

- **URL**: `/api/materials/{id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific material
- **Path Parameters**:
    - `id`: Material ID
- **Response Format**:

```javascript
{
  "id": "string",
  "part_number": "string",
  "name": "string",
  "hs_code": "string",
  "handling_units": [
    {
      "id": "string",
      "supplier_name": "string",
      "parent_id": "string",
      "length": "number",
      "width": "number",
      "height": "number",
      "dimension_unit": "string",
      "weight": "number",
      "weight_unit": "string",
      "content_unit_count": "number"
    },
    ...
  ]
}
```

#### Update Material

- **URL**: `/api/materials/{id}`
- **Method**: PUT
- **Description**: Updates the material with the specified ID
- **Path Parameters**:
    - `id`: Material ID

#### Delete Material

- **URL**: `/api/materials/{id}`
- **Method**: DELETE
- **Description**: Sets the material to deprecated (soft delete)
- **Path Parameters**:
    - `id`: Material ID

### Packaging Management

#### List Packagings

- **URL**: `/api/packaging/`
- **Method**: GET
- **Description**: Returns a list of all packagings (handling units)
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
    - `supplier`: Filter by supplier ID
    - `material`: Filter by material ID
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "supplier_name": "string",
    "part_number": "string",
    "material_name": "string",
    "length": "number",
    "width": "number",
    "height": "number",
    "dimension_unit": "string",
    "weight": "number",
    "weight_unit": "string",
    "content_unit_count": "number"
  },
  ...
]
```

#### Get Packaging Details

- **URL**: `/api/packaging/{id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific packaging
- **Path Parameters**:
    - `id`: Packaging ID
- **Response Format**:

```javascript
{
  "id": "string",
  "supplier": {
    "id": "string",
    "country": {
      "id": "string",
      "iso_code": "string",
      "region_code": "string"
    },
    "name": "string",
    "address": "string"
  },
  "material": {
    "id": "string",
    "part_number": "string",
    "name": "string",
    "hs_code": "string"
  },
  "handling_unit": {
    "length": "number",
    "width": "number",
    "height": "number",
    "dimension_unit": "string",
    "weight": "number",
    "weight_unit": "string",
    "content_unit_count": "number"
  },
  "small_handling_unit": {
    "length": "number",
    "width": "number",
    "height": "number",
    "dimension_unit": "string",
    "weight": "number",
    "weight_unit": "string",
    "content_unit_count": "number"
  }
}
```

#### Update Packaging

- **URL**: `/api/packaging/{id}`
- **Method**: PUT
- **Description**: Updates the packaging with the specified ID
- **Path Parameters**:
    - `id`: Packaging ID

#### Delete Packaging

- **URL**: `/api/packaging/{id}`
- **Method**: DELETE
- **Description**: Sets the packaging to deprecated (soft delete)
- **Path Parameters**:
    - `id`: Packaging ID

### Country Management

#### List Countries

- **URL**: `/api/country/`
- **Method**: GET
- **Description**: Returns a list of all countries
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "iso_code": "string",
    "name": "string",
    "region_code": "string"
  },
  ...
]
```

#### Get Country Details

- **URL**: `/api/country/{id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific country
- **Path Parameters**:
    - `id`: Country ID
- **Response Format**:

```javascript
{
  "id": "string",
  "iso_code": "string",
  "name": "string",
  "region_code": "string",
  "properties": [
    {
      "id": "string",
      "mapping_id": "string",
      "name": "string",
      "datatype": "string",
      "current_value": "any",
      "draft_value": "any",
      "is_required": "boolean"
    },
    ...
  ]
}
```

#### Update Country

- **URL**: `/api/country/{id}`
- **Method**: PUT
- **Description**: Updates the country with the specified ID
- **Path Parameters**:
    - `id`: Country ID

#### Delete Country

- **URL**: `/api/country/{id}`
- **Method**: DELETE
- **Description**: Sets the country to deprecated (soft delete)
- **Path Parameters**:
    - `id`: Country ID

### System Properties Management

#### List System Properties

- **URL**: `/api/properties/system/`
- **Method**: GET
- **Description**: Returns property set including properties
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "mapping_id": "string",
    "name": "string",
    "data_type": "string",
    "current_value": "any",
    "draft_value": "any"
  },
  ...
]
```

#### Get System Property Details

- **URL**: `/api/properties/system/{id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific system property
- **Path Parameters**:
    - `id`: Property ID
- **Response Format**:

```javascript
{
  "id": "string",
  "mapping_id": "string",
  "name": "string",
  "data_type": "string",
  "current_value": "any",
  "draft_value": "any"
}
```

#### Update System Property

- **URL**: `/api/properties/system/{id}`
- **Method**: PUT
- **Description**: Updates the system property with the specified ID
- **Path Parameters**:
    - `id`: Property ID

#### List Property Types

- **URL**: `/api/properties/types/{$system_part}/`
- **Method**: GET
- **Description**: Returns a list of all property types for the specified system part
- **Path Parameters**:
    - `$system_part`: The system part to get properties for (valid values: `system`, `packaging`, `country`)
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "mapping_id": "string",
    "name": "string",
    "data_type": "string"
  },
  ...
]
```

#### Create Property Type

- **URL**: `/api/properties/types/{$system_part}/`
- **Method**: PUT
- **Description**: Creates a new system property type
- **Path Parameters**:
    - `$system_part`: The system part to create a property for (valid values: `system`, `packaging`, `country`)

#### Get Property Type Details

- **URL**: `/api/properties/types/{$system_part}/{id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific property type
- **Path Parameters**:
    - `$system_part`: System part (valid values: `system`, `packaging`, `country`)
    - `id`: Property type ID
- **Response Format**:

```javascript
{
  "id": "string",
  "mapping_id": "string",
  "name": "string",
  "data_type": "string"
}
```

#### Update Property Type

- **URL**: `/api/properties/types/{$system_part}/{id}`
- **Method**: PUT
- **Description**: Updates the property type with the specified ID
- **Path Parameters**:
    - `$system_part`: System part (valid values: `system`, `packaging`, `country`)
    - `id`: Property type ID

#### Check Staged Property Changes

- **URL**: `/api/properties/staged_changes/`
- **Method**: GET
- **Description**: Returns true if there are any unapproved "drafts" properties, false otherwise

#### Approve Property Changes

- **URL**: `/api/properties/staged_changes/`
- **Method**: PUT
- **Description**: Approves drafts and sets current "draft" properties to current valid properties

### Node Management

#### List Nodes

- **URL**: `/api/nodes/`
- **Method**: GET
- **Description**: Returns a list of all active nodes (with deprecated \= false)
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
    - `filter`: Search text to filter nodes
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "country": {
      "id": "string",
      "iso_code": "string",
      "region_code": "string",
      "name": "string"
    },
    "address": "string",
    "location": {
      "longitude": "number",
      "latitude": "number"
    },
    "types": ["sink", "source", "intermediate"]
  },
  ...
]
```

#### Get Node Details

- **URL**: `/api/nodes/{$id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific node
- **Path Parameters**:
    - `$id`: Node ID
- **Response Format**:

```javascript
{
  "id": "string",
  "country": {
    "id": "string",
    "iso_code": "string",
    "region_code": "string",
    "name": "string"
  },
  "name": "string",
  "address": "string",
  "location": {
    "longitude": "number",
    "latitude": "number"
  },
  "types": ["sink", "source", "intermediate"],
  "predecessors": {
    "1": {
      "id": "string",
      "country": {
        "id": "string",
        "iso_code": "string",
        "region_code": "string",
        "name": "string"
      },
      "name": "string",
      "address": "string",
      "location": {
        "longitude": "number",
        "latitude": "number"
      }
    },
    "2": { ... }
  },
  "outbound_countries": [
    {
      "id": "string",
      "iso_code": "string",
      "region_code": "string",
      "name": "string"
    },
    ...
  ]
}
```

#### Update Node

- **URL**: `/api/nodes/{$id}`
- **Method**: PUT
- **Description**: Updates the node with the specified ID
- **Path Parameters**:
    - `$id`: Node ID

#### Delete Node

- **URL**: `/api/nodes/{$id}`
- **Method**: DELETE
- **Description**: Sets the node with the specified ID to deprecated (soft delete)
- **Path Parameters**:
    - `$id`: Node ID

#### Search Nodes

- **URL**: `/api/nodes/search`
- **Method**: GET
- **Description**: Returns a list of nodes matching the search conditions
- **Query Parameters**:
    - `filter`: Search string
    - `limit`: Maximum number of items to return
    - `node_type`: Type filter (valid values: `source`, `sink`, `intermediate`)
    - `include_user_nodes`: Boolean to include user-specific nodes
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "country": {
      "id": "string",
      "iso_code": "string",
      "region_code": "string",
      "name": "string"
    },
    "name": "string",
    "address": "string",
    "location": {
      "longitude": "number",
      "latitude": "number"
    },
    "types": ["sink", "source", "intermediate"],
    "predecessors": { ... },
    "outbound_countries": [ ... ],
    "is_user_node": "boolean"
  },
  ...
]
```

## Transportation Rate Endpoints {#transportation-rate-endpoints}

### Rate Validity Periods

#### List Validity Periods

- **URL**: `/api/rates/periods`
- **Method**: GET
- **Description**: Returns a list of validity periods for transportation rates
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "start_date": "date",
    "end_date": "date",
    "state": "string"
  },
  ...
]
```

- **Note**: State can have the following values: `draft`, `valid`, `invalid`, `expired`

#### Create Validity Period

- **URL**: `/api/rates/periods`
- **Method**: PUT
- **Description**: Creates a new validity period (only possible if no validity period with state "draft" exists)

#### Invalidate Validity Period

- **URL**: `/api/rates/periods/{$id}`
- **Method**: DELETE
- **Description**: Invalidates the validity period with the specified ID (must be in state "valid" or "expired")
- **Path Parameters**:
    - `$id`: Validity period ID

### Container Rates

#### List Container Rates

- **URL**: `/api/rates/container/`
- **Method**: GET
- **Description**: Returns a list of container rates associated with a specific validity period
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
    - `valid`: Validity period filter (values: validity\_period\_id, "current", "draft")
    - `validAt`: Timestamp to find rates valid at a specific time
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "origin": {
      "id": "string",
      "country": { ... },
      "address": "string",
      "location": { ... },
      "types": ["sink", "source", "intermediate"]
    },
    "destination": {
      "id": "string",
      "country": { ... },
      "address": "string",
      "location": { ... },
      "types": ["sink", "source", "intermediate"]
    },
    "type": "string",
    "rates": {
      "40": "number",
      "20": "number",
      "40_HC": "number"
    },
    "lead_time": "number",
    "validity_period": {
      "id": "string",
      "start_date": "date",
      "end_date": "date",
      "state": "string"
    }
  },
  ...
]
```

- **Note**: Type can have the following values: `rail`, `sea`, `post-run`, `road`

#### Get Container Rate Details

- **URL**: `/api/rates/container/{$id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific container rate
- **Path Parameters**:
    - `$id`: Container rate ID
- **Response Format**: Same as list container rates

#### Update Container Rate

- **URL**: `/api/rates/container/{$id}`
- **Method**: PUT
- **Description**: Updates the container rate with the specified ID (only possible if the validity period is in state "draft")
- **Path Parameters**:
    - `$id`: Container rate ID

#### Delete Container Rate

- **URL**: `/api/rates/container/{$id}`
- **Method**: DELETE
- **Description**: Deletes the container rate with the specified ID (only possible if the validity period is in state "draft")
- **Path Parameters**:
    - `$id`: Container rate ID

### Country Matrix Rates

#### List Country Matrix Rates

- **URL**: `/api/rates/matrix/`
- **Method**: GET
- **Description**: Returns a list of country matrix rates associated with a specific validity period
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
    - `valid`: Validity period filter (values: validity\_period\_id, "current", "draft")
    - `validAt`: Timestamp to find rates valid at a specific time
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "origin": {
      "id": "string",
      "country": { ... },
      "address": "string",
      "location": { ... },
      "types": ["sink", "source", "intermediate"]
    },
    "destination": {
      "id": "string",
      "country": { ... },
      "address": "string",
      "location": { ... },
      "types": ["sink", "source", "intermediate"]
    },
    "rate": "number"
  },
  ...
]
```

#### Get Country Matrix Rate Details

- **URL**: `/api/rates/matrix/{$id}`
- **Method**: GET
- **Description**: Returns detailed information about a specific country matrix rate
- **Path Parameters**:
    - `$id`: Country matrix rate ID
- **Response Format**: Same as list country matrix rates

#### Update Country Matrix Rate

- **URL**: `/api/rates/matrix/{$id}`
- **Method**: PUT
- **Description**: Updates the country matrix rate with the specified ID (only possible if the validity period is in state "draft")
- **Path Parameters**:
    - `$id`: Country matrix rate ID

#### Delete Country Matrix Rate

- **URL**: `/api/rates/matrix/{$id}`
- **Method**: DELETE
- **Description**: Deletes the country matrix rate with the specified ID (only possible if the validity period is in state "draft")
- **Path Parameters**:
    - `$id`: Country matrix rate ID

#### Check Staged Rate Changes

- **URL**: `/api/rates/staged_changes/`
- **Method**: GET
- **Description**: Returns true if there are any unapproved "draft" rates, false otherwise

#### Approve Rate Changes

- **URL**: `/api/rates/staged_changes/`
- **Method**: PUT
- **Description**: Approves drafts and sets current "draft" validity period to current valid validity period

## User Management Endpoints

### User Operations {#user-operations}

#### List Users

- **URL**: `/api/users/`
- **Method**: GET
- **Description**: Lists all users
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
- **Authorization**: PSK (Pre-Shared Key)
- **Response Format**:

```javascript
[
  {
    "firstname": "string",
    "lastname": "string",
    "mail": "string",
    "workday_id": "string",
    "is_active": "boolean",
    "groups": ["string", ...]
  },
  ...
]
```

#### Create or Update User

- **URL**: `/api/users/`
- **Method**: PUT
- **Description**: Updates an existing user or creates a new one
- **Authorization**: PSK (Pre-Shared Key)

### Group Operations

#### List Groups

- **URL**: `/api/groups/`
- **Method**: GET
- **Description**: Lists all user groups
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
- **Authorization**: PSK (Pre-Shared Key)
- **Response Format**:

```javascript
[
  {
    "group_name": "string",
    "group_description": "string"
  },
  ...
]
```

#### Create or Update Group

- **URL**: `/api/groups/`
- **Method**: PUT
- **Description**: Updates an existing group or creates a new one
- **Authorization**: PSK (Pre-Shared Key)

## Calculation Endpoints {#calculation-endpoints}

### Calculation Operations

#### View Calculation Premises

- **URL**: `/api/calculation/view`
- **Method**: GET
- **Description**: Lists a preview of all premises for the current user (or another user with elevated rights)
- **Query Parameters**:
    - `limit`: Maximum number of items to return (default: 20\)
    - `offset`: Number of items to skip (for pagination)
    - `filter`: Search string
    - `user`: User ID filter
    - `deleted`: Boolean to include deleted premises (default: false)
    - `archived`: Boolean to include archived premises (default: false)
    - `done`: Boolean to include completed premises (default: true)
- **Response Format**:

```javascript
[
  {
    "id": "string",
    "material": {
      "id": "string",
      "part_number": "string",
      "name": "string"
    },
    "supplier": {
      "id": "string",
      "country": {
        "id": "string",
        "iso_code": "string",
        "region_code": "string"
      },
      "name": "string",
      "address": "string"
    },
    "state": "string"
  },
  ...
]
```

- **Note**: State can have the following values: `draft`, `completed`, `archived`, `deleted`

#### Search for Materials and Suppliers

- **URL**: `/api/calculation/search`
- **Method**: GET
- **Description**: Parses the given search string and returns the found materials and associated suppliers
- **Query Parameters**:
    - `material`: Search string for materials
- **Response Format**:

```javascript
{
  "materials": [
    {
      "id": "string",
      "part_number": "string",
      "name": "string"
    },
    ...
  ],
  "supplier": [
    {
      "id": "string",
      "country": {
        "id": "string",
        "iso_code": "string",
        "region_code": "string"
      },
      "name": "string",
      "address": "string"
    },
    ...
  ],
  "user_supplier": [
    {
      "id": "string",
      "country": {
        "id": "string",
        "iso_code": "string",
        "region_code": "string"
      },
      "name": "string",
      "address": "string"
    },
    ...
  ]
}
```

#### Create Calculation Premises

- **URL**: `/api/calculation/create`
- **Method**: GET
- **Description**: Returns a list of premises based on the provided parameters
- **Query Parameters**:
    - `material`: Array of material IDs
    - `supplier`: Array of supplier IDs
    - `user_supplier`: Array of user supplier IDs
    - `from_scratch`: Boolean to create empty premises
- **Response Format**: Detailed premise data including routes and transit nodes

#### Edit Calculation Premises

- **URL**: `/api/calculation/edit`
- **Method**: GET
- **Description**: Returns a list of premises based on the provided premise IDs
- **Query Parameters**:
    - `premiss_ids`: Array of premise IDs
- **Response Format**: Detailed premise data including routes and transit nodes

#### Save Calculation Premises

- **URL**: `/api/calculation/edit`
- **Method**: PUT
- **Description**: Saves the provided premises
- **Request Body**: Array of premise objects with detailed route information

## Reporting Endpoints

### Reporting Operations {#reporting-operations}

#### Download Report

- **URL**: `/api/reports/download`
- **Method**: GET
- **Description**: Returns an Excel-file based report
- **Query Parameters**:
    - `material`: Material ID
    - `sources`: Array of source IDs

#### Search Report Sources

- **URL**: `/api/reports/search`
- **Method**: GET
- **Description**: Returns a list of source groups based on the given material ID
- **Query Parameters**:
    - `material`: Material ID
- **Response Format**:

```javascript
[
  ["source_id", ...],c
  ...
]
```

#### View Report

- **URL**: `/api/reports/view`
- **Method**: GET
- **Description**: Returns a detailed cost and risk report
- **Query Parameters**:
    - `material`: Material ID
    - `sources`: Array of source IDs
- **Response Format**:

```javascript
[
  {
    "cost": {
      "material_cost": {
        "total": "number",
        "percentage": "number"
      },
      "fca_fees": {
        "total": "number",
        "percentage": "number"
      },
      "pre_run_cost": {
        "total": "number",
        "percentage": "number"
      },
      "main_run_cost": {
        "total": "number",
        "percentage": "number"
      },
      "post_run_cost": {
        "total": "number",
        "percentage": "number"
      },
      "repacking_cost": {
        "total": "number",
        "percentage": "number"
      },
      "handling_cost": {
        "total": "number",
        "percentage": "number"
      },
      "storage_cost": {
        "total": "number",
        "percentage": "number"
      },
      "captial_cost": {
        "total": "number",
        "percentage": "number"
      },
      "disposal_cost": {
        "total": "number",
        "percentage": "number"
      },
      "total_cost": {
        "total": "number",
        "percentage": "number"
      }
    },
    "risk": {
      "air_freight_cost": {
        "total": "number",
        "percentage": "number"
      },
      "best_case_cost": {
        "total": "number",
        "percentage": "number"
      },
      "worst_case_cost": {
        "total": "number",
        "percentage": "number"
      }
    },
    "premisses": {
      "quantities": [
        {
          "destination": "string",
          "quantity": "number",
          "route": [
            {
              "name": "string",
              "type": "string",
              "cost": {
                "total": "number",
                "percentage": "number"
              }
            },
            "..."
          ]
        }
      ],
      "hs_code": "string",
      "custom_rate": "number",
      "container": {
        "type": "string",
        "rate": "number",
        "unit_count": "number",
        "weight_exceeded": "boolean",
        "utilization": "number",
        "mixed": "boolean"
      },
      "packaging": {
        "width": "number",
        "height": "number",
        "length": "number",
        "weight": "number",
        "dimension_unit": "string",
        "weight_unit": "string",
        "unit_count": "number",
        "layers": "number"
      },
      "qouta_share": {
        "oversea_share": "number",
        "air_freight_share": "number",
        "transport_time": "number",
        "safety_stock": "number"
      }
    }
  },
  "..."
]
```

## Glossary {#glossary}

| Term | Definition |
| :---- | :---- |
| **API** | Application Programming Interface. A set of rules that allows programs to talk to each other. |
| **Calculation Premises** | The foundational data and assumptions used for logistics cost calculations. |
| **Container Rate** | Pricing for transportation of goods via standard shipping containers (20ft, 40ft, 40ft High Cube). |
| **Country Matrix** | A grid representing transportation rates between country pairs. |
| **Draft** | A working state for rates, properties, or other data that is not yet approved or in production. |
| **Handling Unit** | A physical package or container for materials (e.g., pallet, box). |
| **HS Code** | Harmonized System code. An international nomenclature for classifying traded products. |
| **LCC** | Logistics Cost Calculator, the primary system this API supports. |
| **Lead Time** | The time taken from ordering to delivery of materials. |
| **Material** | A product or component that is transported or managed in the system. |
| **Node** | A geographic location in the logistics network (could be source, sink, or intermediate). |
| **Packaging** | The physical container or wrapping for materials during transportation. |
| **Pre-Shared Key (PSK)** | A secret key shared between parties for authentication purposes. |
| **Property Type** | A definition of a characteristic that can be assigned to system entities. |
| **Rate** | The cost associated with transporting goods between locations. |
| **Sink** | A destination node in the logistics network (typically a manufacturing plant). |
| **Source** | An origin node in the logistics network (typically a supplier). |
| **System Property** | A configuration setting that affects the behavior of the LCC system. |
| **Transit Node** | An intermediate point in a transportation route. |
| **User Supplier** | A supplier that is specific to a particular user rather than system-wide. |
| **Validity Period** | A timeframe during which rates or other data are considered active and applicable. |

# Database Documentation

## Overview Database

This document provides a comprehensive description of the LCC Backend Database structure. It handles property management, geographical data, user management, logistics nodes, transportation rates, packaging, materials, and calculation workflows for optimizing logistics operations.

## Table Categories

The database is organized into several functional areas:

1. **Property Management** - Versioned configuration properties
2. **Geographic Data** - Countries and regions
3. **User Management** - Users, groups, and permissions
4. **Logistics Nodes** - Physical locations in the supply chain
5. **Transportation** - Distance matrices and rates
6. **Materials & Packaging** - Product and packaging information
7. **Premiss & Routes** - Supply chain scenarios and route planning
8. **Calculation** - Cost calculation jobs and results

## Detailed Table Descriptions

### Property Management

#### `property_set`
Manages versioned sets of properties with temporal validity.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `start_date` | TIMESTAMP | When this property set becomes valid |
| `end_date` | TIMESTAMP | When this property set expires (NULL = no expiration) |
| `state` | CHAR(8) | Status of property set: DRAFT, VALID, INVALID, EXPIRED |

#### `system_property_type`
Defines system-wide configuration property types.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `name` | VARCHAR(255) | Property type name |
| `external_mapping_id` | VARCHAR(16) | External system identifier |
| `data_type` | VARCHAR(16) | Data type: INT, PERCENTAGE, BOOLEAN, CURRENCY, ENUMERATION, TEXT |
| `validation_rule` | VARCHAR(64) | Optional validation rules |

#### `system_property`
Stores system-wide configuration property values.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `property_set_id` | INT | References property_set |
| `system_property_type_id` | INT | References system_property_type |
| `property_value` | VARCHAR(500) | The value of the property |

### Geographic Data

#### `country`
Master data table for country information and regional classification.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `iso_code` | CHAR(2) | ISO 3166-1 alpha-2 country code |
| `region_code` | CHAR(5) | Geographic region: EMEA/LATAM/APAC/NAM |
| `name` | VARCHAR(128) | Country name |
| `is_deprecated` | BOOLEAN | Whether the country record is deprecated |

#### `country_property_type`
Defines property types specific to countries.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `name` | VARCHAR(255) | Property type name |
| `external_mapping_id` | VARCHAR(16) | External system identifier |
| `data_type` | VARCHAR(16) | Data type: INT, PERCENTAGE, BOOLEAN, CURRENCY, ENUMERATION, TEXT |
| `validation_rule` | VARCHAR(64) | Optional validation rules |
| `is_required` | BOOLEAN | Whether the property is required |

#### `country_property`
Stores country-specific property values with versioning support.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `country_id` | INT | References country |
| `country_property_type_id` | INT | References country_property_type |
| `property_set_id` | INT | References property_set |
| `property_value` | VARCHAR(500) | The value of the property |

### User Management

#### `sys_user`
Stores basic information about system users.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `workday_id` | CHAR(32) | External HR system identifier |
| `email` | VARCHAR(254) | User email |
| `firstname` | VARCHAR(100) | User first name |
| `lastname` | VARCHAR(100) | User last name |
| `is_active` | BOOLEAN | Whether the user is active |

#### `sys_group`
Defines user groups for access management.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `group_name` | VARCHAR(64) | Group name |
| `group_description` | VARCHAR(128) | Group description |

#### `sys_user_group_mapping`
Links users with their associated groups.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `user_id` | INT | References sys_user |
| `group_id` | INT | References sys_group |

#### `sys_user_node`
Contains user-generated logistic nodes.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `user_id` | INT | References sys_user |
| `country_id` | INT | References country |
| `name` | VARCHAR(254) | Node name |
| `address` | VARCHAR(500) | Physical address |
| `geo_lat` | DECIMAL(7,4) | Latitude (-90 to 90) |
| `geo_lng` | DECIMAL(7,4) | Longitude (-180 to 180) |
| `is_deprecated` | BOOLEAN | Whether the node is deprecated |

### Logistics Nodes

#### `node`
Represents physical locations in the supply chain network.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `country_id` | INT | References country |
| `name` | VARCHAR(255) | Node name |
| `address` | VARCHAR(500) | Physical address |
| `external_mapping_id` | VARCHAR(32) | External system identifier |
| `predecessor_required` | BOOLEAN | Whether this node requires a predecessor |
| `is_sink` | BOOLEAN | Whether this node is a destination/consumption point |
| `is_source` | BOOLEAN | Whether this node is a source/production point |
| `is_intermediate` | BOOLEAN | Whether this node is a transfer point |
| `geo_lat` | DECIMAL(7,4) | Latitude (-90 to 90) |
| `geo_lng` | DECIMAL(7,4) | Longitude (-180 to 180) |
| `updated_at` | TIMESTAMP | Last update timestamp |
| `is_deprecated` | BOOLEAN | Whether the node is deprecated |

#### `node_predecessor`
Defines predecessor relationships between nodes.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `node_id` | INT | References node |
| `predecessor_node_id` | INT | References node as a predecessor |
| `sequence_number` | INT | Position in the sequence (>0) |

#### `outbound_country_mapping`
Maps nodes to countries they can serve.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `node_id` | INT | References node |
| `country_id` | INT | References country |

#### `distance_matrix`
Stores distance information between nodes.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `from_node_id` | INT | References source node |
| `to_node_id` | INT | References destination node |
| `from_geo_lat` | DECIMAL(7,4) | Source latitude |
| `from_geo_lng` | DECIMAL(7,4) | Source longitude |
| `to_geo_lat` | DECIMAL(7,4) | Destination latitude |
| `to_geo_lng` | DECIMAL(7,4) | Destination longitude |
| `distance` | DECIMAL(15,2) | Travel distance in meters |
| `updated_at` | TIMESTAMP | Last update timestamp |
| `state` | CHAR(10) | Status: VALID, STALE |

### Transportation Rates

#### `validity_period`
Defines time periods for rate validity.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `start_date` | TIMESTAMP | When the period starts |
| `end_date` | TIMESTAMP | When the period ends (NULL = no end) |
| `state` | CHAR(8) | Status: DRAFT, VALID, INVALID, EXPIRED |

#### `container_rate`
Stores rates for container transportation between nodes.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `from_node_id` | INT | References source node |
| `to_node_id` | INT | References destination node |
| `container_rate_type` | CHAR(8) | Type: RAIL, SEA, POST-RUN, ROAD |
| `rate_20` | DECIMAL(15,2) | Rate for 20ft container in EUR |
| `rate_40` | DECIMAL(15,2) | Rate for 40ft container in EUR |
| `rate_40_hc` | DECIMAL(15,2) | Rate for 40ft HQ container in EUR |
| `lead_time` | INT UNSIGNED | Lead time in days |
| `validity_period_id` | INT | References validity_period |

#### `country_matrix_rate`
Stores rates for full truck load based on country pairs.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `from_country_id` | INT | References source country |
| `to_country_id` | INT | References destination country |
| `rate` | DECIMAL(15,2) | Rate for full truck load per kilometer in EUR |
| `validity_period_id` | INT | References validity_period |

### Materials & Packaging

#### `material`
Stores information about materials.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `part_number` | CHAR(12) | Material part number |
| `normalized_part_number` | CHAR(12) | Standardized part number (unique) |
| `hs_code` | CHAR(8) | Harmonized System code for customs |
| `name` | VARCHAR(500) | Material name |
| `is_deprecated` | BOOLEAN | Whether the material is deprecated |

#### `packaging`
Defines packaging specifications.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `supplier_node_id` | INT | References node (supplier) |
| `material_id` | INT | References material |
| `parent_id` | INT | References parent packaging (hierarchical) |
| `type` | CHAR(3) | Type: SHU (small handling unit), HU (handling unit) |
| `length` | INT UNSIGNED | Length in mm |
| `width` | INT UNSIGNED | Width in mm |
| `height` | INT UNSIGNED | Height in mm |
| `displayed_dimension_unit` | CHAR(2) | Display unit: MM, CM, M |
| `weight` | INT UNSIGNED | Weight in g |
| `displayed_weight_unit` | CHAR(2) | Display unit: G, KG |
| `content_unit_count` | INT UNSIGNED | Number of units contained |
| `is_deprecated` | BOOLEAN | Whether the packaging is deprecated |

#### `packaging_property_type`
Defines property types for packaging.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `name` | VARCHAR(255) | Property type name |
| `data_type` | VARCHAR(16) | Data type |
| `validation_rule` | VARCHAR(64) | Optional validation rules |
| `is_required` | BOOLEAN | Whether the property is required |

#### `packaging_property`
Stores packaging property values.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `packaging_property_type_id` | INT | References packaging_property_type |
| `packaging_id` | INT | References packaging |
| `property_value` | VARCHAR(500) | The value of the property |

### Premiss & Routes

#### `premiss`
Core table for logistics scenario planning.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `material_id` | INT | References material |
| `supplier_node_id` | INT | References node (system supplier) |
| `user_supplier_node_id` | INT | References sys_user_node (user's supplier) |
| `packaging_id` | INT | References packaging |
| `user_id` | INT | References sys_user (creator) |
| `createdAt` | TIMESTAMP | Creation timestamp |
| `updatedAt` | TIMESTAMP | Last update timestamp |
| `material_cost` | DECIMAL(15,2) | Material cost in EUR (MEK_A) |
| `is_fca_enabled` | BOOLEAN | Free Carrier shipping terms enabled |
| `oversea_share` | DECIMAL(7,4) | Percentage of overseas transport |
| `hs_code` | CHAR(8) | Harmonized System code for customs |
| `custom_rate` | DECIMAL(7,4) | Custom duty rate |
| `state` | CHAR(10) | Status: DRAFT, COMPLETED, ARCHIVED, DELETED |
| `individual_hu_length` | INT UNSIGNED | Handling unit length in mm |
| `individual_hu_height` | INT UNSIGNED | Handling unit height in mm |
| `individual_hu_width` | INT UNSIGNED | Handling unit width in mm |
| `individual_hu_weight` | INT UNSIGNED | Handling unit weight in g |
| `hu_displayed_dimension_unit` | CHAR(2) | Display unit for dimensions |
| `hu_displayed_weight_unit` | CHAR(2) | Display unit for weight |
| `hu_unit_count` | INT UNSIGNED | Number of units per handling unit |
| `hu_stackable` | BOOLEAN | Whether the unit is stackable |
| `hu_mixable` | BOOLEAN | Whether the unit can be mixed with others |

#### `premiss_sink`
Links premiss to destination nodes with volume information.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `premiss_id` | INT | References premiss |
| `annual_amount` | INT UNSIGNED | Annual amount in pieces |
| `sink_node_id` | INT | References node (destination) |

#### `premiss_route`
Defines possible routes for a premiss_sink.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `premiss_sink_id` | INT | References premiss_sink |
| `is_fastest` | BOOLEAN | Whether this is the fastest route |
| `is_cheapest` | BOOLEAN | Whether this is the cheapest route |
| `is_selected` | BOOLEAN | Whether this route is selected/preferred |

#### `premiss_route_node`
Defines nodes in a route.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `premiss_route_id` | INT | References premiss_route |
| `node_id` | INT | References node (system node) |
| `user_node_id` | INT | References sys_user_node (user's node) |
| `name` | VARCHAR(255) | Node name |
| `address` | VARCHAR(500) | Node address |
| `is_sink` | BOOLEAN | Whether this is a destination node |
| `is_intermediate` | BOOLEAN | Whether this is a transfer node |
| `is_source` | BOOLEAN | Whether this is a source node |
| `geo_lat` | DECIMAL(7,4) | Latitude |
| `geo_lng` | DECIMAL(7,4) | Longitude |
| `is_outdated` | BOOLEAN | Whether the node data is outdated |

#### `premiss_route_section`
Defines transportation sections between route nodes.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `premiss_route_id` | INT | References premiss_route |
| `from_route_node_id` | INT | References premiss_route_node (source) |
| `to_route_node_id` | INT | References premiss_route_node (destination) |
| `list_position` | INT | Position in the route sequence |
| `transport_type` | CHAR(16) | Type: RAIL, SEA, ROAD, POST-RUN, MATRIX, D2D |
| `rate_d2d` | DECIMAL(15,2) | Door-to-door rate in EUR |
| `is_pre_run` | BOOLEAN | Whether this is a pre-run section |
| `is_main_run` | BOOLEAN | Whether this is a main-run section |
| `is_post_run` | BOOLEAN | Whether this is a post-run section |
| `is_outdated` | BOOLEAN | Whether the section data is outdated |

### Calculation System

#### `calculation_job`
Manages calculation processes.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `premiss_id` | INT | References premiss |
| `calculation_date` | TIMESTAMP | When the calculation was performed |
| `validity_period_id` | INT | References validity_period |
| `property_set_id` | INT | References property_set |
| `job_state` | CHAR(10) | Status: CREATED, SCHEDULED, VALID, INVALID, EXCEPTION |
| `user_id` | INT | References sys_user (creator) |

#### `calculation_job_sink`
Stores calculation results per sink.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_id` | INT | References calculation_job |
| `premiss_sink_id` | INT | References premiss_sink |
| `safety_stock` | INT UNSIGNED | Safety stock in pieces |
| `shipping_frequency` | INT UNSIGNED | Annual shipping frequency |
| `total_cost` | DECIMAL(15,2) | Total cost in EUR (MEK_B) |

#### `calculation_job_transportation`
Stores transportation calculation results.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_sink_id` | INT | References calculation_job_sink |
| `transportation_type` | CHAR(8) | Type: 20, 40, 40HC, TRUCK |
| `hu_per_layer` | INT UNSIGNED | Handling units per layer |
| `layer_structure` | JSON | Structure of a single layer |
| `layer_count` | INT UNSIGNED | Number of layers per container/truck |
| `transport_weight_exceeded` | BOOLEAN | Weight vs. volume limitation |
| `transports_per_year` | DECIMAL(15,2) | Number of transports per year |
| `annual_cost` | DECIMAL(15,2) | Annual transportation costs in EUR |

#### `calculation_job_route_section`
Detailed calculation results for route sections.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `premiss_route_section_id` | INT | References premiss_route_section |
| `calculation_job_transportation_id` | INT | References calculation_job_transportation |
| `used_rule` | CHAR(8) | Calculation rule: CONTAINER, MATRIX |
| `is_unmixed_price` | BOOLEAN | Whether an unmixed pricing was used |
| `is_cbm_price` | BOOLEAN | Whether cubic meter pricing was used |
| `is_weight_price` | BOOLEAN | Whether weight-based pricing was used |
| `is_stacked` | BOOLEAN | Whether stacking was considered |
| `is_pre_run` | BOOLEAN | Whether this is a pre-run calculation |
| `is_main_run` | BOOLEAN | Whether this is a main-run calculation |
| `is_post_run` | BOOLEAN | Whether this is a post-run calculation |
| `rate` | DECIMAL(15,2) | Applied rate in EUR |
| `distance` | DECIMAL(15,2) | Section distance in meters |
| `cbm_price` | DECIMAL(15,2) | Price per cubic meter |
| `weight_price` | DECIMAL(15,2) | Price per kilogram |
| `annual_cost` | DECIMAL(15,2) | Annual costs for this section |
| `transit_time` | INT UNSIGNED | Transit time |

#### `calculation_job_airfreight`
Stores air freight calculation results.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_sink_id` | INT | References calculation_job_sink |
| `air_freight_share_max` | DECIMAL(7,4) | Maximum air freight share |
| `air_freight_share` | DECIMAL(7,4) | Actual air freight share |
| `air_freight_volumetric_weight` | DECIMAL(15,2) | Volumetric weight |
| `air_freight_weight` | DECIMAL(15,2) | Actual weight |
| `annual_cost` | DECIMAL(15,2) | Annual air freight costs |

#### `calculation_job_custom`
Stores customs duty calculation results.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_sink_id` | INT | References calculation_job_sink |
| `custom_value` | DECIMAL(15,2) | Customs value |
| `custom_duties` | DECIMAL(15,2) | Customs duties |
| `custom_rate` | DECIMAL(7,4) | Applied duty rate |
| `annual_cost` | DECIMAL(15,2) | Annual customs costs |

#### `calculation_job_inventory`
Stores inventory calculation results.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_sink_id` | INT | References calculation_job_sink |
| `operational_stock` | DECIMAL(15,2) | Operational stock in pieces |
| `safety_stock` | DECIMAL(15,2) | Safety stock in pieces |
| `stocked_inventory` | DECIMAL(15,2) | Total stocked inventory |
| `in_transport_stock` | DECIMAL(15,2) | Stock in transport |
| `stock_before_payment` | DECIMAL(15,2) | Stock before payment |
| `annual_capital_cost` | DECIMAL(15,2) | Annual capital costs |
| `annual_storage_cost` | DECIMAL(15,2) | Annual storage costs |

#### `calculation_job_handling`
Stores handling cost calculation results.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_sink_id` | INT | References calculation_job_sink |
| `is_small_unit` | BOOLEAN | Whether this is a small unit (< 0.08 cbm) |
| `annual_repacking_cost` | DECIMAL(15,2) | Annual repacking costs |
| `annual_handling_cost` | DECIMAL(15,2) | Annual handling costs |
| `annual_disposal_cost` | DECIMAL(15,2) | Annual disposal costs |

#### `calculation_job_risk`
Stores risk assessment calculation results.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INT | Primary key |
| `calculation_job_sink_id` | INT | References calculation_job_sink |
| `annual_risk_cost` | DECIMAL(15,2) | Annual risk costs (worst case) |
| `annual_chance_cost` | DECIMAL(15,2) | Annual opportunity costs (best case) |

## Entity Relationship Diagram

The database has several key relationship patterns:

1. The `property_set` system provides versioned configuration for both system-wide and country-specific properties
2. The `node` system forms the backbone of the logistics network
3. The `premiss` system ties together materials, packaging, suppliers, and destinations
4. The `calculation_job` system captures results of cost calculations with various components

## Common Data Types and Conventions

- Monetary values are stored as DECIMAL(15,2) in EUR
- Geographical coordinates are stored as DECIMAL(7,4)
- Dimensions are stored in mm (millimeters)
- Weights are stored in g (grams)
- Most tables include an `is_deprecated` flag for soft-deletion
- State/status fields use CHECK constraints to limit valid values
